Set reading to prevent exceptions during DB load

This commit is contained in:
Mike Jolley 2016-08-24 14:37:19 +01:00
parent 7e30e8dda3
commit d9798f7226
12 changed files with 88 additions and 84 deletions

View File

@ -27,6 +27,12 @@ abstract class WC_Data {
*/
protected $_data = array();
/**
* True when reading from the database.
* @var bool
*/
protected $_reading = false;
/**
* Stores meta in cache for future reads.
* A group must be set to to enable caching.
@ -377,33 +383,17 @@ abstract class WC_Data {
* @return mixed
*/
protected function get_prop() {
$args = func_get_args();
$target = &$this->_data;
$args = func_get_args();
$prop = &$this->_data;
foreach ( $args as $arg ) {
if ( ! isset( $target[ $arg ] ) ) {
if ( ! isset( $prop[ $arg ] ) ) {
return false;
}
$target = &$target[ $arg ];
$prop = &$prop[ $arg ];
}
return $target;
}
/**
* Set all props to passed key value pairs using setters and ignoring invalid
* values with the try/catch.
* @param array $values
*/
protected function set_props( $values = array() ) {
foreach ( $values as $prop => $value ) {
try {
$this->{"set_$prop"}( $value );
} catch ( WC_Data_Exception $e ) {
// Default value will be left as-is.
unset( $e );
}
}
return $prop;
}
/**
@ -413,7 +403,7 @@ abstract class WC_Data {
*/
protected function set_prop() {
if ( func_num_args() < 2 ) {
$this->throw_exception( 'invalid_value', 'set_prop requires at least 2 parameters' );
$this->invalid_data( 'invalid_value', 'set_prop requires at least 2 parameters' );
}
$args = func_get_args();
@ -428,12 +418,14 @@ abstract class WC_Data {
}
/**
* Returns an invalid data WP_Error object.
* When invalid data is found, throw an exception unless reading from the DB.
* @param string $message Error Message.
* @param mixed $data Data the user tried to set.
* @throws WC_Data_Exception
*/
protected function throw_exception( $error_code, $error_message, $http_status_code = 400 ) {
throw new WC_Data_Exception( $error_code, $error_message, $http_status_code );
protected function invalid_data( $error_code, $error_message, $http_status_code = 400 ) {
if ( ! $this->_reading ) {
throw new WC_Data_Exception( $error_code, $error_message, $http_status_code );
}
}
}

View File

@ -108,6 +108,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* @param int|object|WC_Order $order Order to init.
*/
public function __construct( $order = 0 ) {
$this->set_defaults();
if ( is_numeric( $order ) && $order > 0 ) {
$this->read( $order );
} elseif ( $order instanceof self ) {
@ -199,6 +201,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
return;
}
$this->_reading = true;
// Map standard post data
$this->set_id( $post_object->ID );
$this->set_parent_id( $post_object->post_parent );
@ -219,6 +222,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
// Load meta data
$this->read_meta_data();
$this->_reading = false;
}
/**
@ -605,7 +609,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
*/
public function set_parent_id( $value ) {
if ( $value && ! get_post( $value ) ) {
$this->throw_exception( 'order_invalid_parent_id', __( 'Invalid parent ID', 'woocommerce' ) );
$this->invalid_data( 'order_invalid_parent_id', __( 'Invalid parent ID', 'woocommerce' ) );
}
$this->set_prop( 'parent_id', absint( $value ) );
}
@ -654,7 +658,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
*/
public function set_currency( $value ) {
if ( $value && ! in_array( $value, array_keys( get_woocommerce_currencies() ) ) ) {
$this->throw_exception( 'order_invalid_currency', __( 'Invalid currency code', 'woocommerce' ) );
$this->invalid_data( 'order_invalid_currency', __( 'Invalid currency code', 'woocommerce' ) );
}
$this->set_prop( 'currency', $value );
}

View File

@ -434,6 +434,8 @@ class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
}
return $order->get_id();
} catch ( WC_Data_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
} catch ( WC_REST_Exception $e ) {
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
}

View File

@ -74,8 +74,10 @@ class WC_Order_Item_Coupon extends WC_Order_Item {
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->_reading = true;
$this->set_discount( get_metadata( 'order_item', $this->get_id(), 'discount_amount', true ) );
$this->set_discount_tax( get_metadata( 'order_item', $this->get_id(), 'discount_amount_tax', true ) );
$this->_reading = false;
}
}

View File

@ -83,11 +83,13 @@ class WC_Order_Item_Fee extends WC_Order_Item {
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->_reading = true;
$this->set_tax_class( get_metadata( 'order_item', $this->get_id(), '_tax_class', true ) );
$this->set_tax_status( get_metadata( 'order_item', $this->get_id(), '_tax_status', true ) );
$this->set_total( get_metadata( 'order_item', $this->get_id(), '_line_total', true ) );
$this->set_total_tax( get_metadata( 'order_item', $this->get_id(), '_line_tax', true ) );
$this->set_taxes( get_metadata( 'order_item', $this->get_id(), '_line_tax_data', true ) );
$this->_reading = false;
}
}
@ -129,7 +131,7 @@ class WC_Order_Item_Fee extends WC_Order_Item {
*/
public function set_tax_class( $value ) {
if ( $value && ! in_array( $value, WC_Tax::get_tax_classes() ) ) {
$this->throw_exception( 'order_item_fee_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
$this->invalid_data( 'order_item_fee_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
}
$this->set_prop( 'tax_class', $value );
}

View File

@ -96,6 +96,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->_reading = true;
$this->set_product_id( get_metadata( 'order_item', $this->get_id(), '_product_id', true ) );
$this->set_variation_id( get_metadata( 'order_item', $this->get_id(), '_variation_id', true ) );
$this->set_quantity( get_metadata( 'order_item', $this->get_id(), '_qty', true ) );
@ -105,6 +106,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
$this->set_total( get_metadata( 'order_item', $this->get_id(), '_line_total', true ) );
$this->set_total_tax( get_metadata( 'order_item', $this->get_id(), '_line_tax', true ) );
$this->set_taxes( get_metadata( 'order_item', $this->get_id(), '_line_tax_data', true ) );
$this->_reading = false;
}
}
@ -235,7 +237,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
*/
public function set_quantity( $value ) {
if ( 0 >= $value ) {
$this->throw_exception( 'order_item_product_invalid_quantity', __( 'Quantity must be positive', 'woocommerce' ) );
$this->invalid_data( 'order_item_product_invalid_quantity', __( 'Quantity must be positive', 'woocommerce' ) );
}
$this->set_prop( 'quantity', wc_stock_amount( $value ) );
}
@ -247,7 +249,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
*/
public function set_tax_class( $value ) {
if ( $value && ! in_array( $value, WC_Tax::get_tax_classes() ) ) {
$this->throw_exception( 'order_item_product_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
$this->invalid_data( 'order_item_product_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
}
$this->set_prop( 'tax_class', $value );
}
@ -258,8 +260,8 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @throws WC_Data_Exception
*/
public function set_product_id( $value ) {
if ( 0 >= $value || 'product' !== get_post_type( absint( $value ) ) ) {
$this->throw_exception( 'order_item_product_invalid_product_id', __( 'Invalid product ID', 'woocommerce' ) );
if ( $value > 0 && 'product' !== get_post_type( absint( $value ) ) ) {
$this->invalid_data( 'order_item_product_invalid_product_id', __( 'Invalid product ID', 'woocommerce' ) );
}
$this->set_prop( 'product_id', absint( $value ) );
}
@ -270,8 +272,8 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @throws WC_Data_Exception
*/
public function set_variation_id( $value ) {
if ( 0 >= $value || 'product_variation' !== get_post_type( $value ) ) {
$this->throw_exception( 'order_item_product_invalid_variation_id', __( 'Invalid variation ID', 'woocommerce' ) );
if ( $value > 0 && 'product_variation' !== get_post_type( $value ) ) {
$this->invalid_data( 'order_item_product_invalid_variation_id', __( 'Invalid variation ID', 'woocommerce' ) );
}
$this->set_prop( 'variation_id', absint( $value ) );
}
@ -349,7 +351,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
*/
public function set_product( $product ) {
if ( ! is_a( $product, 'WC_Product' ) ) {
$this->throw_exception( 'order_item_product_invalid_product', __( 'Invalid product', 'woocommerce' ) );
$this->invalid_data( 'order_item_product_invalid_product', __( 'Invalid product', 'woocommerce' ) );
}
$this->set_product_id( $product->get_id() );
$this->set_name( $product->get_title() );

View File

@ -74,10 +74,12 @@ class WC_Order_Item_Shipping extends WC_Order_Item {
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->_reading = true;
$this->set_method_id( get_metadata( 'order_item', $this->get_id(), 'method_id', true ) );
$this->set_total( get_metadata( 'order_item', $this->get_id(), 'cost', true ) );
$this->set_total_tax( get_metadata( 'order_item', $this->get_id(), 'total_tax', true ) );
$this->set_taxes( get_metadata( 'order_item', $this->get_id(), 'taxes', true ) );
$this->_reading = false;
}
}

View File

@ -35,11 +35,13 @@ class WC_Order_Item_Tax extends WC_Order_Item {
public function read( $id ) {
parent::read( $id );
if ( $this->get_id() ) {
$this->_reading = true;
$this->set_rate_id( get_metadata( 'order_item', $this->get_id(), 'rate_id', true ) );
$this->set_label( get_metadata( 'order_item', $this->get_id(), 'label', true ) );
$this->set_compound( get_metadata( 'order_item', $this->get_id(), 'compound', true ) );
$this->set_tax_total( get_metadata( 'order_item', $this->get_id(), 'tax_amount', true ) );
$this->set_shipping_tax_total( get_metadata( 'order_item', $this->get_id(), 'shipping_tax_amount', true ) );
$this->_reading = false;
}
}

View File

@ -70,11 +70,13 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
* @access private
*/
public function set_all( $data ) {
$this->_reading = true;
foreach ( $data as $key => $value ) {
if ( is_callable( array( $this, "set_$key" ) ) ) {
$this->{"set_$key"}( $value );
}
}
$this->_reading = false;
}
/**
@ -244,11 +246,13 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
}
if ( $data ) {
$this->_reading = true;
$this->set_order_id( $data->order_id );
$this->set_id( $data->order_item_id );
$this->set_name( $data->order_item_name );
$this->set_type( $data->order_item_type );
$this->read_meta_data();
$this->_reading = false;
}
}

View File

@ -65,6 +65,7 @@ class WC_Order_Refund extends WC_Abstract_Order {
// Read additonal order data
if ( $this->get_id() ) {
$this->_reading = true;
$post_object = get_post( $id );
$this->set_amount( get_post_meta( $this->get_id(), '_refund_amount', true ) );
@ -73,6 +74,7 @@ class WC_Order_Refund extends WC_Abstract_Order {
// post_excerpt was used before refund_reason meta.
$this->set_reason( metadata_exists( 'post', $this->get_id(), '_refund_reason' ) ? get_post_meta( $this->get_id(), '_refund_reason', true ) : absint( $post_object->post_excerpt ) );
$this->_reading = false;
}
}

View File

@ -36,45 +36,6 @@ class WC_Order extends WC_Abstract_Order {
'_customer_note', '_date_completed', '_date_paid', '_payment_tokens',
);
/**
* Map of meta data keys to internal prop keys.
* @var array
*/
protected $prop_to_meta_key = array(
'order_key' => '_order_key',
'customer_id' => '_customer_user',
'billing_first_name' => '_billing_first_name',
'billing_last_name' => '_billing_last_name',
'billing_company' => '_billing_company',
'billing_address_1' => '_billing_address_1',
'billing_address_2' => '_billing_address_2',
'billing_city' => '_billing_city',
'billing_state' => '_billing_state',
'billing_postcode' => '_billing_postcode',
'billing_country' => '_billing_country',
'billing_email' => '_billing_email',
'billing_phone' => '_billing_phone',
'shipping_first_name' => '_shipping_first_name',
'shipping_last_name' => '_shipping_last_name',
'shipping_company' => '_shipping_company',
'shipping_address_1' => '_shipping_address_1',
'shipping_address_2' => '_shipping_address_2',
'shipping_city' => '_shipping_city',
'shipping_state' => '_shipping_state',
'shipping_postcode' => '_shipping_postcode',
'shipping_country' => '_shipping_country',
'payment_method' => '_payment_method',
'payment_method_title' => '_payment_method_title',
'transaction_id' => '_transaction_id',
'customer_ip_address' => '_customer_ip_address',
'customer_user_agent' => '_customer_user_agent',
'created_via' => '_created_via',
'customer_note' => '_customer_note',
'date_completed' => '_completed_date',
'date_paid' => '_paid_date',
'cart_hash' => '_cart_hash',
);
/**
* Stores data about status changes so relevant hooks can be fired.
* @var bool|array
@ -308,17 +269,45 @@ class WC_Order extends WC_Abstract_Order {
return;
}
$post_object = get_post( $this->get_id() );
$values = array(
'customer_note' => $post_object->post_excerpt,
);
$this->_reading = true;
$post_object = get_post( $this->get_id() );
foreach ( $this->prop_to_meta_key as $prop => $meta_key ) {
$values[ $prop ] = get_post_meta( $this->get_id(), $meta_key, true );
}
$this->set_props( $values );
// Read additonal order data
$this->set_order_key( get_post_meta( $this->get_id(), '_order_key', true ) );
$this->set_customer_id( get_post_meta( $this->get_id(), '_customer_user', true ) );
$this->set_billing_first_name( get_post_meta( $this->get_id(), '_billing_first_name', true ) );
$this->set_billing_last_name( get_post_meta( $this->get_id(), '_billing_last_name', true ) );
$this->set_billing_company( get_post_meta( $this->get_id(), '_billing_company', true ) );
$this->set_billing_address_1( get_post_meta( $this->get_id(), '_billing_address_1', true ) );
$this->set_billing_address_2( get_post_meta( $this->get_id(), '_billing_address_2', true ) );
$this->set_billing_city( get_post_meta( $this->get_id(), '_billing_city', true ) );
$this->set_billing_state( get_post_meta( $this->get_id(), '_billing_state', true ) );
$this->set_billing_postcode( get_post_meta( $this->get_id(), '_billing_postcode', true ) );
$this->set_billing_country( get_post_meta( $this->get_id(), '_billing_country', true ) );
$this->set_billing_email( get_post_meta( $this->get_id(), '_billing_email', true ) );
$this->set_billing_phone( get_post_meta( $this->get_id(), '_billing_phone', true ) );
$this->set_shipping_first_name( get_post_meta( $this->get_id(), '_shipping_first_name', true ) );
$this->set_shipping_last_name( get_post_meta( $this->get_id(), '_shipping_last_name', true ) );
$this->set_shipping_company( get_post_meta( $this->get_id(), '_shipping_company', true ) );
$this->set_shipping_address_1( get_post_meta( $this->get_id(), '_shipping_address_1', true ) );
$this->set_shipping_address_2( get_post_meta( $this->get_id(), '_shipping_address_2', true ) );
$this->set_shipping_city( get_post_meta( $this->get_id(), '_shipping_city', true ) );
$this->set_shipping_state( get_post_meta( $this->get_id(), '_shipping_state', true ) );
$this->set_shipping_postcode( get_post_meta( $this->get_id(), '_shipping_postcode', true ) );
$this->set_shipping_country( get_post_meta( $this->get_id(), '_shipping_country', true ) );
$this->set_payment_method( get_post_meta( $this->get_id(), '_payment_method', true ) );
$this->set_payment_method_title( get_post_meta( $this->get_id(), '_payment_method_title', true ) );
$this->set_transaction_id( get_post_meta( $this->get_id(), '_transaction_id', true ) );
$this->set_customer_ip_address( get_post_meta( $this->get_id(), '_customer_ip_address', true ) );
$this->set_customer_user_agent( get_post_meta( $this->get_id(), '_customer_user_agent', true ) );
$this->set_created_via( get_post_meta( $this->get_id(), '_created_via', true ) );
$this->set_customer_note( get_post_meta( $this->get_id(), '_customer_note', true ) );
$this->set_date_completed( get_post_meta( $this->get_id(), '_completed_date', true ) );
$this->set_date_paid( get_post_meta( $this->get_id(), '_paid_date', true ) );
$this->set_cart_hash( get_post_meta( $this->get_id(), '_cart_hash', true ) );
$this->set_customer_note( $post_object->post_excerpt );
$this->maybe_set_user_billing_email();
$this->_reading = false;
}
/**
@ -957,7 +946,7 @@ class WC_Order extends WC_Abstract_Order {
*/
public function set_billing_email( $value ) {
if ( $value && ! is_email( $value ) ) {
$this->throw_exception( 'order_invalid_billing_email', __( 'Invalid order billing email address', 'woocommerce' ) );
$this->invalid_data( 'order_invalid_billing_email', __( 'Invalid order billing email address', 'woocommerce' ) );
}
$this->set_prop( 'billing', 'email', sanitize_email( $value ) );
}

View File

@ -799,6 +799,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case {
$this->assertEquals( $set_to, $object->get_billing_email() );
$set_to = 'not an email';
$this->setExpectedException( 'WC_Data_Exception' );
$object->set_billing_email( $set_to );
$this->assertEquals( 'test@test.com', $object->get_billing_email() );
}