[Product CRUD] Getter setter proxy methods (#12236)

* Started on variation changes

* Stock functions

* Variation class

* Bulk change ->id to get_id() to fix variation form display

* Missing status

* Fix add to cart

* Start on stored data save

* save variation

* Save_variations

* Variation edit panel

* Save variations code works.

* Remove stored data code and fix save

* Improve legacy class

* wc_bool_to_string

* prepare_set_attributes

* Use wc_get_products

* More feedback fixes

* get_prop implementation in abstract and data classes

* Implement set_prop

* Change handling

* Array key exists

* set_object_read
This commit is contained in:
Mike Jolley 2016-11-03 12:03:19 +00:00 committed by GitHub
parent 392d5503e2
commit ad37a68ffb
8 changed files with 418 additions and 231 deletions

View File

@ -27,6 +27,18 @@ abstract class WC_Data {
*/ */
protected $data = array(); protected $data = array();
/**
* Core data changes for this object.
* @var array
*/
protected $changes = array();
/**
* This is false until the object is read from the DB.
* @var bool
*/
protected $object_read = false;
/** /**
* Set to _data on construct so we can track and reset data if needed. * Set to _data on construct so we can track and reset data if needed.
* @var array * @var array
@ -106,8 +118,18 @@ abstract class WC_Data {
/** /**
* Save should create or update based on object existance. * Save should create or update based on object existance.
*
* @return int
*/ */
public function save() {} public function save() {
if ( $this->get_id() ) {
$this->update();
} else {
$this->create();
}
$this->apply_changes();
return $this->get_id();
}
/** /**
* Change data to JSON format. * Change data to JSON format.
@ -401,7 +423,17 @@ abstract class WC_Data {
* Set all props to default values. * Set all props to default values.
*/ */
protected function set_defaults() { protected function set_defaults() {
$this->data = $this->default_data; $this->data = $this->default_data;
$this->changes = array();
$this->set_object_read( false );
}
/**
* Set object read property.
* @param boolean $read
*/
public function set_object_read( $read = true ) {
$this->object_read = (bool) $read;
} }
/** /**
@ -410,7 +442,7 @@ abstract class WC_Data {
* @param array $props Key value pairs to set. Key is the prop and should map to a setter function name. * @param array $props Key value pairs to set. Key is the prop and should map to a setter function name.
* @return WP_Error|bool * @return WP_Error|bool
*/ */
public function set_props( $props ) { public function set_props( $props, $context = 'set' ) {
$errors = new WP_Error(); $errors = new WP_Error();
foreach ( $props as $prop => $value ) { foreach ( $props as $prop => $value ) {
@ -434,6 +466,80 @@ abstract class WC_Data {
return sizeof( $errors->get_error_codes() ) ? $errors : true; return sizeof( $errors->get_error_codes() ) ? $errors : true;
} }
/**
* Sets a prop for a setter method.
*
* This stores changes in a special array so we can track what needs saving
* the the DB later.
*
* @since 2.7.0
* @param string $prop Name of prop to set.
* @param mixed $value Value of the prop.
*/
protected function set_prop( $prop, $value ) {
if ( array_key_exists( $prop, $this->data ) ) {
if ( true === $this->object_read ) {
$this->changes[ $prop ] = $value;
} else {
$this->data[ $prop ] = $value;
}
}
}
/**
* Return data changes only.
*
* @since 2.7.0
* @return array
*/
protected function get_changes() {
return $this->changes;
}
/**
* Merge changes with data and clear.
*
* @since 2.7.0
*/
protected function apply_changes() {
$this->data = array_merge( $this->data, $this->changes );
$this->changes = array();
}
/**
* Prefix for action and filter hooks on data.
*
* @since 2.7.0
* @return string
*/
protected function get_hook_prefix() {
return 'woocommerce_get_';
}
/**
* Gets a prop for a getter method.
*
* Gets the value from either current pending changes, or the data itself.
* Context controls what happens to the value before it's returned.
*
* @since 2.7.0
* @param string $prop Name of prop to get.
* @param string $context What the value is for. Valid values are view and edit.
* @return mixed
*/
public function get_prop( $prop, $context = 'view' ) {
$value = null;
if ( array_key_exists( $prop, $this->data ) ) {
$value = isset( $this->changes[ $prop ] ) ? $this->changes[ $prop ] : $this->data[ $prop ];
if ( 'view' === $context ) {
$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
}
}
return $value;
}
/** /**
* When invalid data is found, throw an exception unless reading from the DB. * When invalid data is found, throw an exception unless reading from the DB.
* @param string $error_code Error code. * @param string $error_code Error code.

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,14 @@ class WC_Product_External extends WC_Product {
parent::__construct( $product ); parent::__construct( $product );
} }
/**
* Get internal type.
* @return string
*/
public function get_type() {
return 'external';
}
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Getters | Getters
@ -43,30 +51,24 @@ class WC_Product_External extends WC_Product {
| Methods for getting data from the product object. | Methods for getting data from the product object.
*/ */
/**
* Get internal type.
* @return string
*/
public function get_type() {
return 'external';
}
/** /**
* Get product url. * Get product url.
* *
* @param string $context
* @return string * @return string
*/ */
public function get_product_url() { public function get_product_url( $context = 'view' ) {
return esc_url( $this->data['product_url'] ); return esc_url( $this->get_prop( 'product_url', $context ) );
} }
/** /**
* Get button text. * Get button text.
* *
* @param string $context
* @return string * @return string
*/ */
public function get_button_text() { public function get_button_text( $context = 'view' ) {
return $this->data['button_text'] ? $this->data['button_text'] : __( 'Buy product', 'woocommerce' ); return $this->get_prop( 'button_text', $context );
} }
/* /*
@ -86,7 +88,7 @@ class WC_Product_External extends WC_Product {
* @param string $product_url Product URL. * @param string $product_url Product URL.
*/ */
public function set_product_url( $product_url ) { public function set_product_url( $product_url ) {
$this->data['product_url'] = $product_url; $this->set_prop( 'product_url', $product_url );
} }
/** /**
@ -96,7 +98,7 @@ class WC_Product_External extends WC_Product {
* @param string $button_text Button text. * @param string $button_text Button text.
*/ */
public function set_button_text( $button_text ) { public function set_button_text( $button_text ) {
$this->data['button_text'] = $button_text; $this->set_prop( 'button_text', $button_text );
} }
/** /**
@ -106,7 +108,7 @@ class WC_Product_External extends WC_Product {
* @param bool * @param bool
*/ */
public function set_manage_stock( $manage_stock ) { public function set_manage_stock( $manage_stock ) {
$this->data['manage_stock'] = false; $this->set_prop( 'manage_stock', false );
if ( true === $manage_stock ) { if ( true === $manage_stock ) {
$this->error( 'product_external_invalid_manage_stock', __( 'External products cannot be stock managed.', 'woocommerce' ) ); $this->error( 'product_external_invalid_manage_stock', __( 'External products cannot be stock managed.', 'woocommerce' ) );
@ -120,7 +122,7 @@ class WC_Product_External extends WC_Product {
* @param bool * @param bool
*/ */
public function set_stock_status( $stock_status ) { public function set_stock_status( $stock_status ) {
$this->data['stock_status'] = 'instock'; $this->set_prop( 'stock_status', 'instock' );
if ( 'instock' !== $stock_status ) { if ( 'instock' !== $stock_status ) {
$this->error( 'product_external_invalid_stock_status', __( 'External products cannot be stock managed.', 'woocommerce' ) ); $this->error( 'product_external_invalid_stock_status', __( 'External products cannot be stock managed.', 'woocommerce' ) );
@ -134,7 +136,7 @@ class WC_Product_External extends WC_Product {
* @param string $backorders Options: 'yes', 'no' or 'notify'. * @param string $backorders Options: 'yes', 'no' or 'notify'.
*/ */
public function set_backorders( $backorders ) { public function set_backorders( $backorders ) {
$this->data['backorders'] = 'no'; $this->set_prop( 'backorders', 'no' );
if ( 'no' !== $backorders ) { if ( 'no' !== $backorders ) {
$this->error( 'product_external_invalid_backorders', __( 'External products cannot be backordered.', 'woocommerce' ) ); $this->error( 'product_external_invalid_backorders', __( 'External products cannot be backordered.', 'woocommerce' ) );
@ -194,19 +196,17 @@ class WC_Product_External extends WC_Product {
*/ */
/** /**
* Reads a product from the database and sets its data to the class. * Read post data.
* *
* @since 2.7.0 * @since 2.7.0
* @param int $id Product ID.
*/ */
public function read( $id ) { protected function read_product_data() {
parent::read( $id ); parent::read_product_data();
$this->set_props( array( $this->set_props( array(
'product_url' => get_post_meta( $id, '_product_url', true ), 'product_url' => get_post_meta( $this->get_id(), '_product_url', true ),
'button_text' => get_post_meta( $id, '_button_text', true ), 'button_text' => get_post_meta( $this->get_id(), '_button_text', true ) ? get_post_meta( $this->get_id(), '_button_text', true ) : __( 'Buy product', 'woocommerce' ),
) ); ) );
do_action( 'woocommerce_product_loaded', $this );
do_action( 'woocommerce_product_' . $this->get_type() . '_loaded', $this );
} }
/** /**

View File

@ -34,14 +34,6 @@ class WC_Product_Grouped extends WC_Product {
parent::__construct( $product ); parent::__construct( $product );
} }
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
|
| Methods for getting data from the product object.
*/
/** /**
* Get internal type. * Get internal type.
* @return string * @return string
@ -50,15 +42,6 @@ class WC_Product_Grouped extends WC_Product {
return 'grouped'; return 'grouped';
} }
/**
* Return the children of this product.
*
* @return array
*/
public function get_children() {
return $this->data['children'];
}
/** /**
* Get the add to cart button text. * Get the add to cart button text.
* *
@ -131,6 +114,24 @@ class WC_Product_Grouped extends WC_Product {
return apply_filters( 'woocommerce_get_price_html', $price, $this ); return apply_filters( 'woocommerce_get_price_html', $price, $this );
} }
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
|
| Methods for getting data from the product object.
*/
/**
* Return the children of this product.
*
* @param string $context
* @return array
*/
public function get_children( $context = 'view' ) {
return $this->get_prop( 'children', $context );
}
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Setters | Setters
@ -145,7 +146,7 @@ class WC_Product_Grouped extends WC_Product {
* @param array $children * @param array $children
*/ */
public function set_children( $children ) { public function set_children( $children ) {
$this->data['children'] = array_filter( wp_parse_id_list( (array) $children ) ); $this->set_prop( 'children', array_filter( wp_parse_id_list( (array) $children ) ) );
} }
/* /*
@ -155,19 +156,16 @@ class WC_Product_Grouped extends WC_Product {
*/ */
/** /**
* Reads a product from the database and sets its data to the class. * Read post data.
* *
* @since 2.7.0 * @since 2.7.0
* @param int $id Product ID.
*/ */
public function read( $id ) { protected function read_product_data() {
parent::read( $id ); parent::read_product_data();
$this->set_props( array( $this->set_props( array(
'children' => wp_parse_id_list( get_post_meta( $id, '_children', true ) ), 'children' => wp_parse_id_list( get_post_meta( $this->get_id(), '_children', true ) ),
) ); ) );
do_action( 'woocommerce_product_loaded', $this );
do_action( 'woocommerce_product_' . $this->get_type() . '_loaded', $this );
} }
/** /**

View File

@ -57,7 +57,7 @@ class WC_Product_Simple extends WC_Product {
} }
/** /**
* Get the title of the post. * Get the title of the post. @todo should this be deprecated or not? It's in deprecated class and needs review.
* *
* @return string * @return string
*/ */

View File

@ -4,7 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) {
} }
/** /**
* Variable Product Class. * Variable Product Class. @todo needs new getters/setters/changes code
* *
* The WooCommerce product class handles individual product data. * The WooCommerce product class handles individual product data.
* *

View File

@ -4,7 +4,14 @@ if ( ! defined( 'ABSPATH' ) ) {
} }
/** /**
* Product Variation Class. * Product Variation Class. @todo needs new getters/setters/changes code
*
* @todo removed filters need to be mapped via add_action to the product actions of similar naming.
* woocommerce_variation_is_in_stock
* woocommerce_variation_sale_price_html
* woocommerce_variation_price_html
* woocommerce_variation_free_price_html
* woocommerce_get_variation_price_html
* *
* @todo removed filters need to be mapped via add_action to the product actions of similar naming. * @todo removed filters need to be mapped via add_action to the product actions of similar naming.
* woocommerce_variation_is_in_stock * woocommerce_variation_is_in_stock

View File

@ -508,12 +508,20 @@ function woocommerce_list_pages( $pages ) {
global $wc_map_deprecated_filters; global $wc_map_deprecated_filters;
$wc_map_deprecated_filters = array( $wc_map_deprecated_filters = array(
'woocommerce_add_to_cart_fragments' => 'add_to_cart_fragments', 'woocommerce_add_to_cart_fragments' => 'add_to_cart_fragments',
'woocommerce_add_to_cart_redirect' => 'add_to_cart_redirect', 'woocommerce_add_to_cart_redirect' => 'add_to_cart_redirect',
'woocommerce_product_get_width' => 'woocommerce_product_width', 'woocommerce_product_get_width' => 'woocommerce_product_width',
'woocommerce_product_get_height' => 'woocommerce_product_height', 'woocommerce_product_get_height' => 'woocommerce_product_height',
'woocommerce_product_get_length' => 'woocommerce_product_length', 'woocommerce_product_get_length' => 'woocommerce_product_length',
'woocommerce_product_get_weight' => 'woocommerce_product_weight', 'woocommerce_product_get_weight' => 'woocommerce_product_weight',
'woocommerce_product_get_sku' => 'woocommerce_get_sku',
'woocommerce_product_get_price' => 'woocommerce_get_price',
'woocommerce_product_get_regular_price' => 'woocommerce_get_regular_price',
'woocommerce_product_get_sale_price' => 'woocommerce_get_sale_price',
'woocommerce_product_get_tax_class' => 'woocommerce_product_tax_class',
'woocommerce_product_get_stock_quantity' => 'woocommerce_get_stock_quantity',
'woocommerce_product_get_attributes' => 'woocommerce_get_product_attributes',
'woocommerce_product_get_gallery_image_ids' => 'woocommerce_product_gallery_attachment_ids',
); );
foreach ( $wc_map_deprecated_filters as $new => $old ) { foreach ( $wc_map_deprecated_filters as $new => $old ) {