Add tests for product deletion in LookupDataStoreTest.
This commit is contained in:
parent
0192ed0b93
commit
48c44a6128
|
@ -9,6 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore;
|
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore;
|
||||||
|
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
|
||||||
|
@ -298,18 +299,18 @@ class WC_Post_Data {
|
||||||
* @param mixed $id ID of post being deleted.
|
* @param mixed $id ID of post being deleted.
|
||||||
*/
|
*/
|
||||||
public static function delete_post( $id ) {
|
public static function delete_post( $id ) {
|
||||||
if ( ! current_user_can( 'delete_posts' ) || ! $id ) {
|
$container = wc_get_container();
|
||||||
|
if ( ! $container->get( LegacyProxy::class )->call_function( 'current_user_can', 'delete_posts' ) || ! $id ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$post_type = get_post_type( $id );
|
$post_type = self::get_post_type( $id );
|
||||||
|
|
||||||
switch ( $post_type ) {
|
switch ( $post_type ) {
|
||||||
case 'product':
|
case 'product':
|
||||||
$data_store = WC_Data_Store::load( 'product-variable' );
|
$data_store = WC_Data_Store::load( 'product-variable' );
|
||||||
$data_store->delete_variations( $id, true );
|
$data_store->delete_variations( $id, true );
|
||||||
$data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
|
$data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
|
||||||
wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
|
$container->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
|
||||||
|
|
||||||
$parent_id = wp_get_post_parent_id( $id );
|
$parent_id = wp_get_post_parent_id( $id );
|
||||||
if ( $parent_id ) {
|
if ( $parent_id ) {
|
||||||
|
@ -321,7 +322,7 @@ class WC_Post_Data {
|
||||||
$data_store = WC_Data_Store::load( 'product' );
|
$data_store = WC_Data_Store::load( 'product' );
|
||||||
$data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
|
$data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
|
||||||
wc_delete_product_transients( wp_get_post_parent_id( $id ) );
|
wc_delete_product_transients( wp_get_post_parent_id( $id ) );
|
||||||
wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
|
$container->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'shop_order':
|
case 'shop_order':
|
||||||
|
@ -348,7 +349,7 @@ class WC_Post_Data {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$post_type = get_post_type( $id );
|
$post_type = self::get_post_type( $id );
|
||||||
|
|
||||||
// If this is an order, trash any refunds too.
|
// If this is an order, trash any refunds too.
|
||||||
if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
|
if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
|
||||||
|
@ -382,7 +383,7 @@ class WC_Post_Data {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$post_type = get_post_type( $id );
|
$post_type = self::get_post_type( $id );
|
||||||
|
|
||||||
if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
|
if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
@ -407,6 +408,16 @@ class WC_Post_Data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the post type for a given post.
|
||||||
|
*
|
||||||
|
* @param int $id The post id.
|
||||||
|
* @return string The post type.
|
||||||
|
*/
|
||||||
|
private static function get_post_type( $id ) {
|
||||||
|
return wc_get_container()->get( LegacyProxy::class )->call_function( 'get_post_type', $id );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Before deleting an order, do some cleanup.
|
* Before deleting an order, do some cleanup.
|
||||||
*
|
*
|
||||||
|
|
|
@ -238,17 +238,20 @@ AND table_name = %s;',
|
||||||
}
|
}
|
||||||
|
|
||||||
$product = WC()->call_function( 'wc_get_product', $product_id );
|
$product = WC()->call_function( 'wc_get_product', $product_id );
|
||||||
|
if ( ! $product ) {
|
||||||
|
$action = self::ACTION_DELETE;
|
||||||
|
}
|
||||||
|
|
||||||
switch ( $action ) {
|
switch ( $action ) {
|
||||||
case self::ACTION_INSERT:
|
case self::ACTION_INSERT:
|
||||||
$this->delete_data_for( $product->get_id() );
|
$this->delete_data_for( $product_id );
|
||||||
$this->create_data_for( $product );
|
$this->create_data_for( $product );
|
||||||
break;
|
break;
|
||||||
case self::ACTION_UPDATE_STOCK:
|
case self::ACTION_UPDATE_STOCK:
|
||||||
$this->update_stock_status_for( $product );
|
$this->update_stock_status_for( $product );
|
||||||
break;
|
break;
|
||||||
case self::ACTION_DELETE:
|
case self::ACTION_DELETE:
|
||||||
$this->delete_data_for( $product->get_id() );
|
$this->delete_data_for( $product_id );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,13 @@ class FakeQueue implements \WC_Queue_Interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function search( $args = array(), $return_format = OBJECT ) {
|
public function search( $args = array(), $return_format = OBJECT ) {
|
||||||
// TODO: Implement search() method.
|
$result = array();
|
||||||
|
foreach ( $this->methods_called as $method_called ) {
|
||||||
|
if ( $method_called['args'] === $args['args'] && $method_called['hook'] === $args['hook'] ) {
|
||||||
|
$result[] = $method_called;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// phpcs:enable Squiz.Commenting.FunctionComment.Missing
|
// phpcs:enable Squiz.Commenting.FunctionComment.Missing
|
||||||
|
|
|
@ -9,6 +9,7 @@ use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
|
||||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
|
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
|
||||||
use Automattic\WooCommerce\Testing\Tools\FakeQueue;
|
use Automattic\WooCommerce\Testing\Tools\FakeQueue;
|
||||||
use Automattic\WooCommerce\Utilities\ArrayUtil;
|
use Automattic\WooCommerce\Utilities\ArrayUtil;
|
||||||
|
use Automattic\WooCommerce\Testing\Tools\CodeHacking\Hacks\FunctionsMockerHack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the LookupDataStore class.
|
* Tests for the LookupDataStore class.
|
||||||
|
@ -23,13 +24,21 @@ class LookupDataStoreTest extends \WC_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
private $sut;
|
private $sut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lookup table name.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $lookup_table_name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs before each test.
|
* Runs before each test.
|
||||||
*/
|
*/
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
$this->sut = new LookupDataStore();
|
$this->lookup_table_name = $wpdb->prefix . 'wc_product_attributes_lookup';
|
||||||
|
$this->sut = new LookupDataStore();
|
||||||
|
|
||||||
// Initiating regeneration with a fake queue will just create the lookup table in the database.
|
// Initiating regeneration with a fake queue will just create the lookup table in the database.
|
||||||
add_filter(
|
add_filter(
|
||||||
|
@ -39,6 +48,11 @@ class LookupDataStoreTest extends \WC_Unit_Test_Case {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$this->get_instance_of( DataRegenerator::class )->initiate_regeneration();
|
$this->get_instance_of( DataRegenerator::class )->initiate_regeneration();
|
||||||
|
|
||||||
|
$queue = WC()->get_instance_of( \WC_Queue::class );
|
||||||
|
$queue->methods_called = array();
|
||||||
|
|
||||||
|
$this->reset_legacy_proxy_mocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -331,6 +345,329 @@ class LookupDataStoreTest extends \WC_Unit_Test_Case {
|
||||||
$this->assertEquals( sort( $expected ), sort( $actual ) );
|
$this->assertEquals( sort( $expected ), sort( $actual ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Deleting a simple product schedules deletion of lookup table entries when the "direct updates" option is off.
|
||||||
|
*
|
||||||
|
* @testWith ["wp_trash_post"]
|
||||||
|
* ["delete_post"]
|
||||||
|
* ["delete_method_in_product"]
|
||||||
|
* ["force_delete_method_in_product"]
|
||||||
|
*
|
||||||
|
* @param string $deletion_mechanism The mechanism used for deletion, one of: 'wp_trash_post', 'delete_post', 'delete_method_in_product', 'force_delete_method_in_product'.
|
||||||
|
*/
|
||||||
|
public function test_deleting_simple_product_schedules_deletion( $deletion_mechanism ) {
|
||||||
|
$this->set_direct_update_option( false );
|
||||||
|
|
||||||
|
$product = new \WC_Product_Simple();
|
||||||
|
$product_id = 10;
|
||||||
|
$product->set_id( $product_id );
|
||||||
|
$this->save( $product );
|
||||||
|
|
||||||
|
$this->register_legacy_proxy_function_mocks(
|
||||||
|
array(
|
||||||
|
'get_post_type' => function( $id ) use ( $product ) {
|
||||||
|
if ( $id === $product->get_id() || $id === $product ) {
|
||||||
|
return 'product';
|
||||||
|
} else {
|
||||||
|
return get_post_type( $id );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'time' => function() {
|
||||||
|
return 100;
|
||||||
|
},
|
||||||
|
'current_user_can' => function( $capability, ...$args ) {
|
||||||
|
if ( 'delete_posts' === $capability ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return current_user_can( $capability, $args );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->delete_product( $product, $deletion_mechanism );
|
||||||
|
|
||||||
|
$queue_calls = WC()->get_instance_of( \WC_Queue::class )->methods_called;
|
||||||
|
|
||||||
|
$this->assertEquals( 1, count( $queue_calls ) );
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'method' => 'schedule_single',
|
||||||
|
'args' =>
|
||||||
|
array(
|
||||||
|
$product_id,
|
||||||
|
LookupDataStore::ACTION_DELETE,
|
||||||
|
),
|
||||||
|
'group' => 'woocommerce-db-updates',
|
||||||
|
'timestamp' => 101,
|
||||||
|
'hook' => 'woocommerce_run_product_attribute_lookup_update_callback',
|
||||||
|
);
|
||||||
|
$this->assertEquals( $expected, $queue_calls[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a product or variation.
|
||||||
|
*
|
||||||
|
* @param \WC_Product $product The product to delete.
|
||||||
|
* @param string $deletion_mechanism The mechanism used for deletion, one of: 'wp_trash_post', 'delete_post', 'delete_method_in_product', 'force_delete_method_in_product'.
|
||||||
|
*/
|
||||||
|
private function delete_product( \WC_Product $product, string $deletion_mechanism ) {
|
||||||
|
// We can't use the 'wp_trash_post' and 'delete_post' functions directly
|
||||||
|
// because these invoke 'get_post', which fails because tests runs within an
|
||||||
|
// uncommitted database transaction. Being WP core functions they can't be mocked or hacked.
|
||||||
|
// So instead, we trigger the actions that the tested functionality captures.
|
||||||
|
|
||||||
|
switch ( $deletion_mechanism ) {
|
||||||
|
case 'wp_trash_post':
|
||||||
|
do_action( 'wp_trash_post', $product );
|
||||||
|
break;
|
||||||
|
case 'delete_post':
|
||||||
|
do_action( 'delete_post', $product->get_id() );
|
||||||
|
break;
|
||||||
|
case 'delete_method_in_product':
|
||||||
|
$product->delete( false );
|
||||||
|
break;
|
||||||
|
case 'force_delete_method_in_product':
|
||||||
|
$product->delete( true );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Deleting a variable product schedules deletion of lookup table entries when the "direct updates" option is off.
|
||||||
|
*
|
||||||
|
* @testWith ["wp_trash_post"]
|
||||||
|
* ["delete_post"]
|
||||||
|
* ["delete_method_in_product"]
|
||||||
|
* ["force_delete_method_in_product"]
|
||||||
|
*
|
||||||
|
* @param string $deletion_mechanism The mechanism used for deletion, one of: 'wp_trash_post', 'delete_post', 'delete_method_in_product', 'force_delete_method_in_product'.
|
||||||
|
*/
|
||||||
|
public function test_deleting_variable_product_schedules_deletion( $deletion_mechanism ) {
|
||||||
|
$this->set_direct_update_option( false );
|
||||||
|
|
||||||
|
$product = new \WC_Product_Variable();
|
||||||
|
$product->set_id( 1000 );
|
||||||
|
|
||||||
|
$variation = new \WC_Product_Variation();
|
||||||
|
$variation->set_id( 1001 );
|
||||||
|
|
||||||
|
$product->set_children( array( 1001 ) );
|
||||||
|
$this->save( $product );
|
||||||
|
|
||||||
|
$product_id = $product->get_id();
|
||||||
|
|
||||||
|
$this->register_legacy_proxy_function_mocks(
|
||||||
|
array(
|
||||||
|
'get_post_type' => function( $id ) use ( $product, $variation ) {
|
||||||
|
if ( $id === $product->get_id() || $id === $product ) {
|
||||||
|
return 'product';
|
||||||
|
} elseif ( $id === $variation->get_id() || $id === $variation ) {
|
||||||
|
return 'product_variation';
|
||||||
|
} else {
|
||||||
|
return get_post_type( $id );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'time' => function() {
|
||||||
|
return 100;
|
||||||
|
},
|
||||||
|
'current_user_can' => function( $capability, ...$args ) {
|
||||||
|
if ( 'delete_posts' === $capability ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return current_user_can( $capability, $args );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->delete_product( $product, $deletion_mechanism );
|
||||||
|
|
||||||
|
$queue_calls = WC()->get_instance_of( \WC_Queue::class )->methods_called;
|
||||||
|
|
||||||
|
$this->assertEquals( 1, count( $queue_calls ) );
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'method' => 'schedule_single',
|
||||||
|
'args' =>
|
||||||
|
array(
|
||||||
|
$product_id,
|
||||||
|
LookupDataStore::ACTION_DELETE,
|
||||||
|
),
|
||||||
|
'group' => 'woocommerce-db-updates',
|
||||||
|
'timestamp' => 101,
|
||||||
|
'hook' => 'woocommerce_run_product_attribute_lookup_update_callback',
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( $expected, $queue_calls[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Deleting a variation schedules deletion of lookup table entries when the "direct updates" option is off.
|
||||||
|
*
|
||||||
|
* @testWith ["wp_trash_post"]
|
||||||
|
* ["delete_post"]
|
||||||
|
* ["delete_method_in_product"]
|
||||||
|
* ["force_delete_method_in_product"]
|
||||||
|
*
|
||||||
|
* @param string $deletion_mechanism The mechanism used for deletion, one of: 'wp_trash_post', 'delete_post', 'delete_method_in_product', 'force_delete_method_in_product'.
|
||||||
|
*/
|
||||||
|
public function test_deleting_variation_schedules_deletion( $deletion_mechanism ) {
|
||||||
|
$this->set_direct_update_option( false );
|
||||||
|
|
||||||
|
$product = new \WC_Product_Variable();
|
||||||
|
$product->set_id( 1000 );
|
||||||
|
|
||||||
|
$variation = new \WC_Product_Variation();
|
||||||
|
$variation->set_id( 1001 );
|
||||||
|
|
||||||
|
$product->set_children( array( 1001 ) );
|
||||||
|
$this->save( $product );
|
||||||
|
|
||||||
|
$variation_id = $product->get_id();
|
||||||
|
|
||||||
|
$this->register_legacy_proxy_function_mocks(
|
||||||
|
array(
|
||||||
|
'get_post_type' => function( $id ) use ( $product, $variation ) {
|
||||||
|
if ( $id === $product->get_id() || $id === $product ) {
|
||||||
|
return 'product';
|
||||||
|
} elseif ( $id === $variation->get_id() || $id === $variation ) {
|
||||||
|
return 'product_variation';
|
||||||
|
} else {
|
||||||
|
return get_post_type( $id );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'time' => function() {
|
||||||
|
return 100;
|
||||||
|
},
|
||||||
|
'current_user_can' => function( $capability, ...$args ) {
|
||||||
|
if ( 'delete_posts' === $capability ) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return current_user_can( $capability, $args );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->delete_product( $product, $deletion_mechanism );
|
||||||
|
|
||||||
|
$queue_calls = WC()->get_instance_of( \WC_Queue::class )->methods_called;
|
||||||
|
|
||||||
|
$this->assertEquals( 1, count( $queue_calls ) );
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'method' => 'schedule_single',
|
||||||
|
'args' =>
|
||||||
|
array(
|
||||||
|
$variation_id,
|
||||||
|
LookupDataStore::ACTION_DELETE,
|
||||||
|
),
|
||||||
|
'group' => 'woocommerce-db-updates',
|
||||||
|
'timestamp' => 101,
|
||||||
|
'hook' => 'woocommerce_run_product_attribute_lookup_update_callback',
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( $expected, $queue_calls[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox 'on_product_deleted' doesn't schedule duplicate deletions (for the same product).
|
||||||
|
*/
|
||||||
|
public function test_no_duplicate_deletions_are_scheduled() {
|
||||||
|
$this->set_direct_update_option( false );
|
||||||
|
|
||||||
|
$this->register_legacy_proxy_function_mocks(
|
||||||
|
array(
|
||||||
|
'time' => function() {
|
||||||
|
return 100;
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->sut->on_product_deleted( 1 );
|
||||||
|
$this->sut->on_product_deleted( 1 );
|
||||||
|
$this->sut->on_product_deleted( 2 );
|
||||||
|
|
||||||
|
$queue_calls = WC()->get_instance_of( \WC_Queue::class )->methods_called;
|
||||||
|
|
||||||
|
$this->assertEquals( 2, count( $queue_calls ) );
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
array(
|
||||||
|
'method' => 'schedule_single',
|
||||||
|
'args' =>
|
||||||
|
array(
|
||||||
|
1,
|
||||||
|
LookupDataStore::ACTION_DELETE,
|
||||||
|
),
|
||||||
|
'group' => 'woocommerce-db-updates',
|
||||||
|
'timestamp' => 101,
|
||||||
|
'hook' => 'woocommerce_run_product_attribute_lookup_update_callback',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'method' => 'schedule_single',
|
||||||
|
'args' =>
|
||||||
|
array(
|
||||||
|
2,
|
||||||
|
LookupDataStore::ACTION_DELETE,
|
||||||
|
),
|
||||||
|
'group' => 'woocommerce-db-updates',
|
||||||
|
'timestamp' => 101,
|
||||||
|
'hook' => 'woocommerce_run_product_attribute_lookup_update_callback',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( $expected, $queue_calls );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox 'on_product_deleted' deletes the data for a variation when the "direct updates" option is on.
|
||||||
|
*/
|
||||||
|
public function test_direct_deletion_of_variation() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$this->set_direct_update_option( true );
|
||||||
|
|
||||||
|
$variation = new \WC_Product_Variation();
|
||||||
|
$variation->set_id( 2 );
|
||||||
|
$this->save( $variation );
|
||||||
|
|
||||||
|
$this->insert_lookup_table_data( 1, 1, 'pa_foo', 10, false, true );
|
||||||
|
$this->insert_lookup_table_data( 2, 1, 'pa_bar', 20, true, true );
|
||||||
|
|
||||||
|
$this->sut->on_product_deleted( $variation );
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$rows = $wpdb->get_results( 'SELECT DISTINCT product_id FROM ' . $this->lookup_table_name, ARRAY_N );
|
||||||
|
|
||||||
|
$this->assertEquals( array( 1 ), $rows[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox 'on_product_deleted' deletes the data for a product and its variations when the "direct updates" option is on.
|
||||||
|
*/
|
||||||
|
public function test_direct_deletion_of_product() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$this->set_direct_update_option( true );
|
||||||
|
|
||||||
|
$product = new \WC_Product();
|
||||||
|
$product->set_id( 1 );
|
||||||
|
$this->save( $product );
|
||||||
|
|
||||||
|
$this->insert_lookup_table_data( 1, 1, 'pa_foo', 10, false, true );
|
||||||
|
$this->insert_lookup_table_data( 2, 1, 'pa_bar', 20, true, true );
|
||||||
|
$this->insert_lookup_table_data( 3, 3, 'pa_foo', 10, false, true );
|
||||||
|
|
||||||
|
$this->sut->on_product_deleted( $product );
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$rows = $wpdb->get_results( 'SELECT DISTINCT product_id FROM ' . $this->lookup_table_name, ARRAY_N );
|
||||||
|
|
||||||
|
$this->assertEquals( array( 3 ), $rows[0] );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the product attributes from an array with this format:
|
* Set the product attributes from an array with this format:
|
||||||
*
|
*
|
||||||
|
@ -380,4 +717,73 @@ class LookupDataStoreTest extends \WC_Unit_Test_Case {
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of the option for direct lookup table updates.
|
||||||
|
*
|
||||||
|
* @param bool $value True to set the option to 'yes', false for 'no'.
|
||||||
|
*/
|
||||||
|
private function set_direct_update_option( bool $value ) {
|
||||||
|
update_option( 'woocommerce_attribute_lookup__direct_updates', $value ? 'yes' : 'no' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a product and delete any lookup table data that may have been automatically inserted
|
||||||
|
* (for the purposes of unit testing we want to insert this data manually)
|
||||||
|
*
|
||||||
|
* @param \WC_Product $product The product to save and delete lookup table data for.
|
||||||
|
*/
|
||||||
|
private function save( \WC_Product $product ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$product->save();
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$wpdb->query(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"DELETE FROM {$wpdb->prefix}wc_product_attributes_lookup WHERE product_id = %d",
|
||||||
|
$product->get_id()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
|
||||||
|
$queue = WC()->get_instance_of( \WC_Queue::class );
|
||||||
|
$queue->methods_called = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert one entry in the lookup table.
|
||||||
|
*
|
||||||
|
* @param int $product_id The product id.
|
||||||
|
* @param int $product_or_parent_id The product id for non-variable products, the main/parent product id for variations.
|
||||||
|
* @param string $taxonomy Taxonomy name.
|
||||||
|
* @param int $term_id Term id.
|
||||||
|
* @param bool $is_variation_attribute True if the taxonomy corresponds to an attribute used to define variations.
|
||||||
|
* @param bool $has_stock True if the product is in stock.
|
||||||
|
*/
|
||||||
|
private function insert_lookup_table_data( int $product_id, int $product_or_parent_id, string $taxonomy, int $term_id, bool $is_variation_attribute, bool $has_stock ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$wpdb->query(
|
||||||
|
$wpdb->prepare(
|
||||||
|
'INSERT INTO ' . $this->lookup_table_name . ' (
|
||||||
|
product_id,
|
||||||
|
product_or_parent_id,
|
||||||
|
taxonomy,
|
||||||
|
term_id,
|
||||||
|
is_variation_attribute,
|
||||||
|
in_stock)
|
||||||
|
VALUES
|
||||||
|
( %d, %d, %s, %d, %d, %d )',
|
||||||
|
$product_id,
|
||||||
|
$product_or_parent_id,
|
||||||
|
$taxonomy,
|
||||||
|
$term_id,
|
||||||
|
$is_variation_attribute ? 1 : 0,
|
||||||
|
$has_stock ? 1 : 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue