Implement WC_Data_Store and related code & tests.
This commit is contained in:
parent
cd2a4e89b2
commit
1797c76a14
|
@ -27,12 +27,26 @@ abstract class WC_Data {
|
|||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Extra data for this object. Name value pairs (name + default value).
|
||||
* Used as a standard way for sub classes (like product types) to add
|
||||
* additional information to an inherited class.
|
||||
* @var array
|
||||
*/
|
||||
protected $extra_data = array();
|
||||
|
||||
/**
|
||||
* Set to _data on construct so we can track and reset data if needed.
|
||||
* @var array
|
||||
*/
|
||||
protected $default_data = array();
|
||||
|
||||
/**
|
||||
* Contains a reference to the data store for this class.
|
||||
* @var object
|
||||
*/
|
||||
protected $data_store;
|
||||
|
||||
/**
|
||||
* Stores meta in cache for future reads.
|
||||
* A group must be set to to enable caching.
|
||||
|
@ -83,31 +97,28 @@ abstract class WC_Data {
|
|||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new object in the database.
|
||||
*/
|
||||
public function create() {}
|
||||
|
||||
/**
|
||||
* Read object from the database.
|
||||
* @param int ID of the object to load.
|
||||
*/
|
||||
public function read( $id ) {}
|
||||
|
||||
/**
|
||||
* Updates object data in the database.
|
||||
*/
|
||||
public function update() {}
|
||||
|
||||
/**
|
||||
* Updates object data in the database.
|
||||
*/
|
||||
public function delete() {}
|
||||
public function delete( $force_delete = false ) {
|
||||
if ( $this->data_store ) {
|
||||
$this->data_store->delete( $this, $force_delete );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save should create or update based on object existance.
|
||||
*/
|
||||
public function save() {}
|
||||
public function save() {
|
||||
if ( $this->data_store ) {
|
||||
if ( $this->get_id() ) {
|
||||
$this->data_store->update( $this );
|
||||
} else {
|
||||
$this->data_store->create( $this );
|
||||
}
|
||||
return $this->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change data to JSON format.
|
||||
|
@ -125,6 +136,26 @@ abstract class WC_Data {
|
|||
return array_merge( array( 'id' => $this->get_id() ), $this->data, array( 'meta_data' => $this->get_meta_data() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of expected data keys for this object.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @return array
|
||||
*/
|
||||
public function get_data_keys() {
|
||||
return array_keys( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all "extra" data keys for an object (for sub objects like product types).
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @return array
|
||||
*/
|
||||
public function get_extra_data_keys() {
|
||||
return array_keys( $this->extra_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter null meta values from array.
|
||||
* @return bool
|
||||
|
@ -400,7 +431,7 @@ abstract class WC_Data {
|
|||
/**
|
||||
* Set all props to default values.
|
||||
*/
|
||||
protected function set_defaults() {
|
||||
public function set_defaults() {
|
||||
$this->data = $this->default_data;
|
||||
}
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
* Delete data from the database.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
wp_delete_post( $this->get_id() );
|
||||
}
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
* Remove a payment token from the database.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
global $wpdb;
|
||||
$this->read( $this->get_id() ); // Make sure we have a token to return after deletion
|
||||
$wpdb->delete( $wpdb->prefix . 'woocommerce_payment_tokens', array( 'token_id' => $this->get_id() ), array( '%d' ) );
|
||||
|
|
|
@ -752,7 +752,7 @@ class WC_Coupon extends WC_Legacy_Coupon {
|
|||
* Delete coupon from the database.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
wp_delete_post( $this->get_id() );
|
||||
do_action( 'woocommerce_delete_coupon', $this->get_id() );
|
||||
$this->set_id( 0 );
|
||||
|
|
|
@ -1176,7 +1176,7 @@ class WC_Customer extends WC_Legacy_Customer {
|
|||
* Delete a customer.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
if ( ! $this->get_id() ) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC Data Store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @version 2.7.0
|
||||
* @category Class
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Data_Store {
|
||||
|
||||
/**
|
||||
* Contains an instance of the data store class that we are working with.
|
||||
*/
|
||||
private $instance = null;
|
||||
|
||||
/**
|
||||
* Contains an array of default WC supported data stores.
|
||||
* Format of object name => class name.
|
||||
* Example: 'product' => 'WC_Product_Data_Store_CPT'
|
||||
* You can aso pass something like product_<type> for product stores and
|
||||
* that type will be used first when avaiable, if a store is requested like
|
||||
* this and doesn't exist, then the store would fall back to 'product'.
|
||||
* Ran through `woocommerce_data_stores`.
|
||||
*/
|
||||
private $stores = array(
|
||||
);
|
||||
|
||||
/**
|
||||
* Contains the name of the current data store's class name.
|
||||
*/
|
||||
private $current_class_name = '';
|
||||
|
||||
/**
|
||||
* Tells WC_Data_Store which object (coupon, product, order, etc)
|
||||
* store we want to work with.
|
||||
*
|
||||
* @param string $object_type Name of object.
|
||||
*/
|
||||
public function __construct( $object_type ) {
|
||||
$this->stores = apply_filters( 'woocommerce_data_stores', $this->stores );
|
||||
|
||||
// If this object type can't be found, check to see if we can load one
|
||||
// level up (so if product_type isn't found, we try product).
|
||||
if ( ! array_key_exists( $object_type, $this->stores ) ) {
|
||||
$pieces = explode( '_', $object_type );
|
||||
$object_type = $pieces[0];
|
||||
}
|
||||
|
||||
if ( array_key_exists( $object_type, $this->stores ) ) {
|
||||
$store = apply_filters( 'woocommerce_' . $object_type . '_data_store', $this->stores[ $object_type ] );
|
||||
if ( ! class_exists( $store ) ) {
|
||||
throw new Exception( __( 'Invalid data store.', 'woocommerce' ) );
|
||||
}
|
||||
$this->current_class_name = $store;
|
||||
$this->instance = new $store;
|
||||
} else {
|
||||
throw new Exception( __( 'Invalid data store.', 'woocommerce' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a data store for us or returns null if an invalid store.
|
||||
*
|
||||
* @param string $object_type Name of object.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public static function load( $object_type ) {
|
||||
try {
|
||||
return new WC_Data_Store( $object_type );
|
||||
} catch ( Exception $e ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name of the current data store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_current_class_name() {
|
||||
return $this->current_class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an object from the data store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @param WC_Data
|
||||
*/
|
||||
public function read( &$data ) {
|
||||
$this->instance->read( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an object in the data store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @param WC_Data
|
||||
*/
|
||||
public function create( &$data ) {
|
||||
$this->instance->create( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an object in the data store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @param WC_Data
|
||||
*/
|
||||
public function update( &$data ) {
|
||||
$this->instance->update( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an object from the data store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @param WC_Data
|
||||
* @param bool $force_delete True to permently delete, false to trash.
|
||||
*/
|
||||
public function delete( &$data, $force_delete = false ) {
|
||||
$this->instance->delete( $data, $force_delete );
|
||||
}
|
||||
|
||||
}
|
|
@ -249,7 +249,7 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
|
|||
* Delete data from the database.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
if ( $this->get_id() ) {
|
||||
global $wpdb;
|
||||
do_action( 'woocommerce_before_delete_order_item', $this->get_id() );
|
||||
|
|
|
@ -102,7 +102,7 @@ class WC_Order_Refund extends WC_Abstract_Order {
|
|||
* Delete data from the database.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
wp_delete_post( $this->get_id(), true );
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class WC_Shipping_Zone extends WC_Data {
|
|||
* Delete a zone.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
if ( $this->get_id() ) {
|
||||
global $wpdb;
|
||||
$wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_methods', array( 'zone_id' => $this->get_id() ) );
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared logic for post/CPT data stores.
|
||||
*
|
||||
* @version 2.7.0
|
||||
* @category Class
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Data_Store_CPT {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC Data Store Interface
|
||||
*
|
||||
* @version 2.7.0
|
||||
* @category Interface
|
||||
* @author WooThemes
|
||||
*/
|
||||
interface WC_Object_Data_Store {
|
||||
/**
|
||||
* Method to create a new record of a WC_Data based object.
|
||||
* @param WC_Data
|
||||
*/
|
||||
public function create( &$data );
|
||||
|
||||
/**
|
||||
* Method to read a record. Creates a new WC_Data based object.
|
||||
* @param WC_Data
|
||||
*/
|
||||
public function read( &$data );
|
||||
|
||||
/**
|
||||
* Updates a record in the database.
|
||||
* @param WC_Data
|
||||
*/
|
||||
public function update( &$data );
|
||||
|
||||
/**
|
||||
* Deletes a record from the database.
|
||||
* @param WC_Data
|
||||
* @param bool $force_delete True to permently delete, false to trash.
|
||||
*/
|
||||
public function delete( &$data, $force_delete );
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC Dummy Data Store: CPT.
|
||||
*
|
||||
* Used to test swapping out data stores.
|
||||
*
|
||||
* @version 2.7.0
|
||||
* @category Class
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Dummy_Data_Store_CPT implements WC_Object_Data_Store {
|
||||
public function create( &$data ) { }
|
||||
public function read( &$data ) { }
|
||||
public function update( &$data ) { }
|
||||
public function delete( &$data, $force_delete = false ) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* WC Dummy Data Store: Custom Table.
|
||||
*
|
||||
* Used to test swapping out data stores.
|
||||
*
|
||||
* @version 2.7.0
|
||||
* @category Class
|
||||
* @author WooThemes
|
||||
*/
|
||||
class WC_Dummy_Data_Store_Custom_Table implements WC_Object_Data_Store {
|
||||
public function create( &$data ) { }
|
||||
public function read( &$data ) { }
|
||||
public function update( &$data ) { }
|
||||
public function delete( &$data, $force_delete = false ) { }
|
||||
}
|
|
@ -164,7 +164,7 @@ class WC_Mock_WC_Data extends WC_Data {
|
|||
/**
|
||||
* Simple delete.
|
||||
*/
|
||||
public function delete() {
|
||||
public function delete( $force_delete = false ) {
|
||||
if ( 'user' === $this->meta_type ) {
|
||||
wp_delete_user( $this->get_id() );
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
/**
|
||||
* Data Store Tests
|
||||
* @package WooCommerce\Tests\Product
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class WC_Tests_Data_Store extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Make sure WC_Data_Store returns an exception if we try to load a data
|
||||
* store that doesn't exist.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_invalid_store_throws_exception() {
|
||||
try {
|
||||
$product_store = new WC_Data_Store( 'bogus' );
|
||||
} catch ( Exception $e ) {
|
||||
$this->assertEquals( $e->getMessage(), 'Invalid data store.' );
|
||||
return;
|
||||
}
|
||||
$this->fail( 'Invalid data store exception not correctly raised.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure ::load returns null if an invalid store is found.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_invalid_store_load_returns_null() {
|
||||
$product_store = WC_Data_Store::load( 'product-test' );
|
||||
$this->assertNull( $product_store );
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we can swap out stores.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_store_swap() {
|
||||
$this->load_dummy_store();
|
||||
|
||||
$store = new WC_Data_Store( 'dummy' );
|
||||
$this->assertEquals( 'WC_Dummy_Data_Store_CPT', $store->get_current_class_name() );
|
||||
|
||||
add_filter( 'woocommerce_dummy_data_store', array( $this, 'set_dummy_store' ) );
|
||||
|
||||
$store = new WC_Data_Store( 'dummy' );
|
||||
$this->assertEquals( 'WC_Dummy_Data_Store_Custom_Table', $store->get_current_class_name() );
|
||||
|
||||
add_filter( 'woocommerce_dummy_data_store', array( $this, 'set_default_dummy_store' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if `first_second ``-> returns to `first` if unregistered.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function test_store_sub_type() {
|
||||
$this->load_dummy_store();
|
||||
$store = WC_Data_Store::load( 'dummy_sub' );
|
||||
$this->assertEquals( 'WC_Dummy_Data_Store_CPT', $store->get_current_class_name() );
|
||||
}
|
||||
|
||||
// Helper Functions
|
||||
|
||||
/**
|
||||
* Loads two dummy data store classes that can be swapt out for each other. Adds to the `woocommerce_data_stores` filter.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function load_dummy_store() {
|
||||
include_once( dirname( dirname( dirname( __FILE__ ) ) ) . '/framework/class-wc-dummy-data-store.php' );
|
||||
add_filter( 'woocommerce_data_stores', array( $this, 'add_dummy_data_store' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a default class for the 'dummy' data store.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function add_dummy_data_store( $stores ) {
|
||||
$stores['dummy'] = 'WC_Dummy_Data_Store_CPT';
|
||||
return $stores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function/filter to swap out the default dummy store for a different one.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function set_dummy_store( $store ) {
|
||||
return 'WC_Dummy_Data_Store_Custom_Table';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function/filter to swap out the 'dummy' store for the default one.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
function set_default_product_store( $store ) {
|
||||
return 'WC_Dummy_Data_Store_CPT';
|
||||
}
|
||||
}
|
|
@ -268,7 +268,6 @@ final class WooCommerce {
|
|||
include_once( WC_ABSPATH . 'includes/class-wc-api.php' ); // API Class
|
||||
include_once( WC_ABSPATH . 'includes/class-wc-auth.php' ); // Auth Class
|
||||
include_once( WC_ABSPATH . 'includes/class-wc-post-types.php' ); // Registers post types
|
||||
include_once( WC_ABSPATH . 'includes/abstracts/abstract-wc-data.php' ); // WC_Data for CRUD
|
||||
include_once( WC_ABSPATH . 'includes/abstracts/abstract-wc-payment-token.php' ); // Payment Tokens
|
||||
include_once( WC_ABSPATH . 'includes/abstracts/abstract-wc-product.php' ); // Products
|
||||
include_once( WC_ABSPATH . 'includes/abstracts/abstract-wc-order.php' ); // Orders
|
||||
|
@ -285,6 +284,10 @@ final class WooCommerce {
|
|||
include_once( WC_ABSPATH . 'includes/class-wc-cache-helper.php' ); // Cache Helper
|
||||
include_once( WC_ABSPATH . 'includes/class-wc-https.php' ); // https Helper
|
||||
|
||||
include_once( WC_ABSPATH . 'includes/class-wc-data-store.php' ); // WC_Data_Store for CRUD
|
||||
include_once( WC_ABSPATH . 'includes/data-stores/interface-wc-object-data-store.php' );
|
||||
include_once( WC_ABSPATH . 'includes/data-stores/class-wc-data-store-cpt.php' );
|
||||
|
||||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||||
include_once( WC_ABSPATH . 'includes/class-wc-cli.php' );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue