From d212c2ed83de75cbce4ad06c7ee44528759f6bb5 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 26 Jun 2023 22:12:13 +0200 Subject: [PATCH 01/26] Add `RecursiveDataStructureTraverser` helper to manipulate nested data --- src/Cache/NonExistentKeyException.php | 24 +++ src/Cache/RecursiveDataStructureTraverser.php | 182 ++++++++++++++++++ src/Cache/Utils.php | 22 +++ 3 files changed, 228 insertions(+) create mode 100644 src/Cache/NonExistentKeyException.php create mode 100644 src/Cache/RecursiveDataStructureTraverser.php create mode 100644 src/Cache/Utils.php diff --git a/src/Cache/NonExistentKeyException.php b/src/Cache/NonExistentKeyException.php new file mode 100644 index 00000000..ecc38d8c --- /dev/null +++ b/src/Cache/NonExistentKeyException.php @@ -0,0 +1,24 @@ +traverser = $traverser; + } + + /** + * @return RecursiveDataStructureTraverser + */ + public function get_traverser() { + return $this->traverser; + } +} diff --git a/src/Cache/RecursiveDataStructureTraverser.php b/src/Cache/RecursiveDataStructureTraverser.php new file mode 100644 index 00000000..e7e21ee1 --- /dev/null +++ b/src/Cache/RecursiveDataStructureTraverser.php @@ -0,0 +1,182 @@ +data =& $data; + $this->key = $key; + $this->parent = $parent; + } + + /** + * Get the nested value at the given key path. + * + * @param string|int|array $key_path + * + * @return static + */ + public function get( $key_path ) { + return $this->traverse_to( (array) $key_path )->value(); + } + + /** + * Get the current data. + * + * @return mixed + */ + public function value() { + return $this->data; + } + + /** + * Update a nested value at the given key path. + * + * @param string|int|array $key_path + * @param mixed $value + */ + public function update( $key_path, $value ) { + $this->traverse_to( (array) $key_path )->set_value( $value ); + } + + /** + * Update the current data with the given value. + * + * This will mutate the variable which was passed into the constructor + * as the data is set and traversed by reference. + * + * @param mixed $value + */ + public function set_value( $value ) { + $this->data = $value; + } + + /** + * Unset the value at the given key path. + * + * @param $key_path + */ + public function delete( $key_path ) { + $this->traverse_to( (array) $key_path )->unset_on_parent(); + } + + /** + * Define a nested value while creating keys if they do not exist. + * + * @param array $key_path + * @param mixed $value + */ + public function insert( $key_path, $value ) { + try { + $this->update( $key_path, $value ); + } catch ( NonExistentKeyException $exception ) { + $exception->get_traverser()->create_key(); + $this->insert( $key_path, $value ); + } + } + + /** + * Delete the key on the parent's data that references this data. + */ + public function unset_on_parent() { + $this->parent->delete_by_key( $this->key ); + } + + /** + * Delete the given key from the data. + * + * @param $key + */ + public function delete_by_key( $key ) { + if ( is_array( $this->data ) ) { + unset( $this->data[ $key ] ); + } else { + unset( $this->data->$key ); + } + } + + /** + * Get an instance of the traverser for the given hierarchical key. + * + * @param array $key_path Hierarchical key path within the current data to traverse to. + * + * @throws NonExistentKeyException + * + * @return static + */ + public function traverse_to( array $key_path ) { + $current = array_shift( $key_path ); + + if ( null === $current ) { + return $this; + } + + if ( ! $this->exists( $current ) ) { + $exception = new NonExistentKeyException( "No data exists for key \"{$current}\"" ); + $exception->set_traverser( new static( $this->data, $current, $this->parent ) ); + throw $exception; + } + + foreach ( $this->data as $key => &$key_data ) { + if ( $key === $current ) { + $traverser = new static( $key_data, $key, $this ); + return $traverser->traverse_to( $key_path ); + } + } + } + + /** + * Create the key on the current data. + * + * @throws UnexpectedValueException + */ + protected function create_key() { + if ( is_array( $this->data ) ) { + $this->data[ $this->key ] = null; + } elseif ( is_object( $this->data ) ) { + $this->data->{$this->key} = null; + } else { + $type = gettype( $this->data ); + throw new UnexpectedValueException( + "Cannot create key \"{$this->key}\" on data type {$type}" + ); + } + } + + /** + * Check if the given key exists on the current data. + * + * @param string $key + * + * @return bool + */ + public function exists( $key ) { + return ( is_array( $this->data ) && array_key_exists( $key, $this->data ) ) || + ( is_object( $this->data ) && property_exists( $this->data, $key ) ); + } +} diff --git a/src/Cache/Utils.php b/src/Cache/Utils.php new file mode 100644 index 00000000..d43be2bb --- /dev/null +++ b/src/Cache/Utils.php @@ -0,0 +1,22 @@ + Date: Mon, 26 Jun 2023 22:48:11 +0200 Subject: [PATCH 02/26] add pluck command to cache --- features/cache.feature | 32 +++++++++++++++++++++++ src/Cache_Command.php | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/features/cache.feature b/features/cache.feature index 8e21a820..6014773c 100644 --- a/features/cache.feature +++ b/features/cache.feature @@ -210,3 +210,35 @@ Feature: Managed the WordPress object cache When I run `wp cache supports set_multiple` Then the return code should be 0 + + Scenario: Nested values can be retrieved at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 'bar'] ); + wp_cache_set( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + wp_cache_set( 'my_key_custom', ['foo_custom' => ['bar_custom' => 'baz_custom']], 'my_custom_group' ); + }; + + WP_CLI::add_hook( 'before_invoke:cache pluck', $set_foo ); + """ + + When I try `wp cache pluck my_key foo` + Then STDOUT should be: + """ + bar + """ + + When I try `wp cache pluck my_key_2 foo bar` + Then STDOUT should be: + """ + baz + """ + + When I try `wp cache pluck my_key_custom foo_custom bar_custom --group=my_custom_group` + Then STDOUT should be: + """ + baz_custom + """ diff --git a/src/Cache_Command.php b/src/Cache_Command.php index b25ba1d7..790cd25e 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -1,5 +1,8 @@ + * : Cache key. + * + * ... + * : The name(s) of the keys within the value to locate the value to pluck. + * + * [--group=] + * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- + * + * [--format=] + * : The output format of the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * - yaml + * --- + */ + public function pluck( $args, $assoc_args ) { + list($key) = $args; + $group = Utils\get_flag_value($assoc_args, 'group'); + + $value = wp_cache_get( $key, $group ); + + if ( false === $value ) { + WP_CLI::halt( 1 ); + } + + $key_path = array_map( function( $key ) { + if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { + return (int) $key; + } + return $key; + }, array_slice( $args, 1 ) ); + + $traverser = new RecursiveDataStructureTraverser( $value ); + + try { + $value = $traverser->get( $key_path ); + } catch ( \Exception $e ) { + die( 1 ); + } + + WP_CLI::print_value( $value, $assoc_args ); + } } From 8e1b63dcd0166e74085b2376255c43c8445613a5 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 26 Jun 2023 23:02:30 +0200 Subject: [PATCH 03/26] add pluck command to transient --- features/transient.feature | 50 ++++++++++++++++++++++++++++++++++ src/Transient_Command.php | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/features/transient.feature b/features/transient.feature index 3902da95..a049d39e 100644 --- a/features/transient.feature +++ b/features/transient.feature @@ -604,3 +604,53 @@ Feature: Manage WordPress transient cache name foo4 """ + + Scenario: Nested values from transient can be retrieved at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 'bar'] ); + set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); + """ + + When I try `wp transient pluck my_key foo` + Then STDOUT should be: + """ + bar + """ + + When I try `wp transient pluck my_key_2 foo bar` + Then STDOUT should be: + """ + baz + """ + + Scenario: Nested values from site transient can be retrieved at any depth. + Given a WP multisite install + And I run `wp site create --slug=foo` + And a wp-content/mu-plugins/test-harness.php file: + """ + 'bar'] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); + """ + + When I try `wp transient pluck my_key foo --network` + Then STDOUT should be: + """ + bar + """ + + When I try `wp transient pluck my_key foo` + Then STDERR should be: + """ + Warning: Transient with key "my_key" is not set. + """ diff --git a/src/Transient_Command.php b/src/Transient_Command.php index 3d21ab21..2c7b8cef 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -1,5 +1,6 @@ display_items( $results ); } + /** + * Get a nested value from a transient. + * + * ## OPTIONS + * + * + * : Key for the transient. + * + * ... + * : The name(s) of the keys within the value to locate the value to pluck. + * + * [--format=] + * : The output format of the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * - yaml + * --- + * + * [--network] + * : Get the value of a network|site transient. On single site, this is + * a specially-named cache key. On multisite, this is a global cache + * (instead of local to the site). + */ + public function pluck( $args, $assoc_args ) { + list( $key ) = $args; + + $func = Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; + $value = $func( $key ); + + if ( false === $value ) { + WP_CLI::warning( 'Transient with key "' . $key . '" is not set.' ); + exit; + } + + $key_path = array_map( function( $key ) { + if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { + return (int) $key; + } + return $key; + }, array_slice( $args, 1 ) ); + + $traverser = new RecursiveDataStructureTraverser( $value ); + + try { + $value = $traverser->get( $key_path ); + } catch ( \Exception $e ) { + die( 1 ); + } + + WP_CLI::print_value( $value, $assoc_args ); + } + /** * Retrieves the expiration time. * From 6e286afa362e4d30373b994809ad2b1c53992799 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Sat, 1 Jul 2023 11:40:27 +0200 Subject: [PATCH 04/26] add patch command to cache --- features/cache.feature | 96 ++++++++++++++++++++++++++++++++++++++++-- src/Cache_Command.php | 88 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 4 deletions(-) diff --git a/features/cache.feature b/features/cache.feature index 6014773c..e92dee70 100644 --- a/features/cache.feature +++ b/features/cache.feature @@ -211,7 +211,7 @@ Feature: Managed the WordPress object cache When I run `wp cache supports set_multiple` Then the return code should be 0 - Scenario: Nested values can be retrieved at any depth. + Scenario: Nested values from cache can be retrieved at any depth. Given a WP install And a wp-content/mu-plugins/test-harness.php file: """ @@ -219,7 +219,7 @@ Feature: Managed the WordPress object cache $set_foo = function(){ wp_cache_set( 'my_key', ['foo' => 'bar'] ); wp_cache_set( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - wp_cache_set( 'my_key_custom', ['foo_custom' => ['bar_custom' => 'baz_custom']], 'my_custom_group' ); + wp_cache_set( 'my_key_3', ['foo' => 'bar_custom'], 'my_custom_group' ); }; WP_CLI::add_hook( 'before_invoke:cache pluck', $set_foo ); @@ -237,8 +237,96 @@ Feature: Managed the WordPress object cache baz """ - When I try `wp cache pluck my_key_custom foo_custom bar_custom --group=my_custom_group` + When I try `wp cache pluck my_key_3 foo --group=my_custom_group` Then STDOUT should be: """ - baz_custom + bar_custom + """ + + Scenario: Nested values from cache can be updated at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 'bar'] ); + wp_cache_set( 'other_key', ['fuz' => 'biz'] ); + + $complex_key = (object) [ + 'foo' => (object) [ + 'bar' => (object) [ + 'baz' => 2, + ], + ], + ]; + wp_cache_set( 'complex_key', $complex_key ); + }; + + WP_CLI::add_hook( 'before_invoke:cache patch', $set_foo ); + """ + + When I try `wp cache patch insert my_key fuz baz` + Then STDOUT should be: + """ + Success: Updated cache key 'my_key'. + """ + + When I try `wp cache patch insert complex_key foo bar fuz 34` + Then STDOUT should be: + """ + Success: Updated cache key 'complex_key'. + """ + + When I try `wp cache patch insert unknown_key foo bar` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + + When I try `wp cache patch update my_key foo test` + Then STDOUT should be: + """ + Success: Updated cache key 'my_key'. + """ + + When I try `wp cache patch update other_key fuz biz` + Then STDOUT should be: + """ + Success: Value passed for cache key 'other_key' is unchanged. + """ + + When I try `wp cache patch update complex_key foo bar baz 34` + Then STDOUT should be: + """ + Success: Updated cache key 'complex_key'. + """ + + When I try `wp cache patch update unknown_key foo test` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I try `wp cache patch update my_key bar test` + Then STDERR should be: + """ + Error: No data exists for key "bar" + """ + + When I try `wp cache patch delete my_key foo` + Then STDOUT should be: + """ + Success: Updated cache key 'my_key'. + """ + + When I try `wp cache patch delete unknown_key foo` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I try `wp cache patch delete my_key bar` + Then STDERR should be: + """ + Error: No data exists for key "bar" """ diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 790cd25e..3618c134 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -464,4 +464,92 @@ public function pluck( $args, $assoc_args ) { WP_CLI::print_value( $value, $assoc_args ); } + + /** + * Update a nested value from the cache. + * + * ## OPTIONS + * + * + * : Patch action to perform. + * --- + * options: + * - insert + * - update + * - delete + * --- + * + * + * : Cache key. + * + * ... + * : The name(s) of the keys within the value to locate the value to pluck. + * + * [] + * : The new value. If omitted, the value is read from STDIN. + * + * [--group=] + * : Method for grouping data within the cache which allows the same key to be used across groups. + * --- + * default: default + * --- + * + * [--format=] + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- + */ + public function patch( $args, $assoc_args ) { + list( $action, $key ) = $args; + $group = Utils\get_flag_value( $assoc_args, 'group' ); + + $key_path = array_map( function ( $key ) { + if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { + return (int) $key; + } + + return $key; + }, array_slice( $args, 2 ) ); + + if ( 'delete' === $action ) { + $patch_value = null; + } elseif ( \WP_CLI\Entity\Utils::has_stdin() ) { + $stdin_value = WP_CLI::get_value_from_arg_or_stdin( $args, - 1 ); + $patch_value = WP_CLI::read_value( trim( $stdin_value ), $assoc_args ); + } else { + // Take the patch value as the last positional argument. Mutates $key_path to be 1 element shorter! + $patch_value = WP_CLI::read_value( array_pop( $key_path ), $assoc_args ); + } + + /* Need to make a copy of $current_value here as it is modified by reference */ + $old_value = wp_cache_get($key, $group); + $current_value = $old_value; + if (is_object($old_value)) { + $current_value = clone $old_value; + } + + $traverser = new RecursiveDataStructureTraverser( $current_value ); + + try { + $traverser->$action( $key_path, $patch_value ); + } catch ( \Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + $patched_value = $traverser->value(); + + if ( $patched_value === $old_value ) { + WP_CLI::success( "Value passed for cache key '$key' is unchanged." ); + } else { + if ( wp_cache_set( $key, $patched_value, $group ) ) { + WP_CLI::success( "Updated cache key '$key'." ); + } else { + WP_CLI::error( "Could not update cache key '$key'." ); + } + } + } } From bd13459cb0f563ae41bb52256e6cfcd50962cefb Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Thu, 24 Aug 2023 00:01:57 +0200 Subject: [PATCH 05/26] add patch command to transient --- features/transient.feature | 158 +++++++++++++++++++++++++++++++++++++ src/Transient_Command.php | 93 ++++++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/features/transient.feature b/features/transient.feature index a049d39e..5fc852f4 100644 --- a/features/transient.feature +++ b/features/transient.feature @@ -654,3 +654,161 @@ Feature: Manage WordPress transient cache """ Warning: Transient with key "my_key" is not set. """ + + Scenario: Nested values from transient can be updated at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 'bar'] ); + set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); + """ + + When I try `wp transient patch insert my_key fuz baz` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I try `wp transient patch insert my_key_2 foo fuz bar` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch insert unknown_key foo bar` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + + When I try `wp transient patch insert my_key foo bar` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I try `wp transient patch update my_key foo biz` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I try `wp transient patch update my_key_2 foo bar biz` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch update unknown_key foo bar` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I try `wp transient patch update my_key foo bar` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I try `wp transient patch delete my_key foo` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I try `wp transient patch delete my_key_2 foo bar` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch delete unknown_key foo` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + Scenario: Nested values from site transient can be updated at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 'bar'] ); + set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); + """ + + When I try `wp transient patch insert my_key fuz baz --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I try `wp transient patch insert my_key_2 foo fuz bar --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch insert unknown_key foo bar --network` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + + When I try `wp transient patch insert my_key foo bar --network` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I try `wp transient patch update my_key foo biz --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I try `wp transient patch update my_key_2 foo bar biz --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch update unknown_key foo bar --network` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I try `wp transient patch update my_key foo bar --network` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I try `wp transient patch delete my_key foo --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I try `wp transient patch delete my_key_2 foo bar --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch delete unknown_key foo --network` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ diff --git a/src/Transient_Command.php b/src/Transient_Command.php index 2c7b8cef..6ac6929d 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -460,6 +460,99 @@ public function pluck( $args, $assoc_args ) { WP_CLI::print_value( $value, $assoc_args ); } + /** + * Update a nested value from a transient. + * + * ## OPTIONS + * + * + * : Patch action to perform. + * --- + * options: + * - insert + * - update + * - delete + * --- + * + * + * : Key for the transient. + * + * ... + * : The name(s) of the keys within the value to locate the value to pluck. + * + * [] + * : The new value. If omitted, the value is read from STDIN. + * + * [--format=] + * : The serialization format for the value. + * --- + * default: plaintext + * options: + * - plaintext + * - json + * --- + * + * [--expiration=] + * : Time until expiration, in seconds. + * + * [--network] + * : Get the value of a network|site transient. On single site, this is + * a specially-named cache key. On multisite, this is a global cache + * (instead of local to the site). + */ + public function patch( $args, $assoc_args ) { + list( $action, $key ) = $args; + $expiration = (int) Utils\get_flag_value($assoc_args, 'expiration', 0); + + $read_func = Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; + $write_func = Utils\get_flag_value( $assoc_args, 'network' ) ? 'set_site_transient' : 'set_transient'; + + $key_path = array_map( function ( $key ) { + if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { + return (int) $key; + } + + return $key; + }, array_slice( $args, 2 ) ); + + if ( 'delete' === $action ) { + $patch_value = null; + } elseif ( \WP_CLI\Entity\Utils::has_stdin() ) { + $stdin_value = WP_CLI::get_value_from_arg_or_stdin( $args, - 1 ); + $patch_value = WP_CLI::read_value( trim( $stdin_value ), $assoc_args ); + } else { + // Take the patch value as the last positional argument. Mutates $key_path to be 1 element shorter! + $patch_value = WP_CLI::read_value( array_pop( $key_path ), $assoc_args ); + } + + /* Need to make a copy of $current_value here as it is modified by reference */ + $old_value = $read_func( $key ); + $current_value = $old_value; + if ( is_object($old_value) ) { + $current_value = clone $old_value; + } + + $traverser = new RecursiveDataStructureTraverser( $current_value ); + + try { + $traverser->$action( $key_path, $patch_value ); + } catch ( \Exception $e ) { + WP_CLI::error( $e->getMessage() ); + } + + $patched_value = $traverser->value(); + + if ( $patched_value === $old_value ) { + WP_CLI::success( "Value passed for transient '$key' is unchanged." ); + } else { + if ( $write_func( $key, $patched_value, $expiration ) ) { + WP_CLI::success( "Updated transient '$key'." ); + } else { + WP_CLI::error( "Could not update transient '$key'." ); + } + } + } + /** * Retrieves the expiration time. * From 05424ececdc946dba4baaca120bcc7d9360bcd86 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Thu, 24 Aug 2023 00:17:00 +0200 Subject: [PATCH 06/26] Add missing `expiration` option for patch cache command --- src/Cache_Command.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 3618c134..571db78c 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -494,6 +494,12 @@ public function pluck( $args, $assoc_args ) { * default: default * --- * + * [--expiration=] + * : Define how long to keep the value, in seconds. `0` means as long as possible. + * --- + * default: 0 + * --- + * * [--format=] * : The serialization format for the value. * --- @@ -506,6 +512,7 @@ public function pluck( $args, $assoc_args ) { public function patch( $args, $assoc_args ) { list( $action, $key ) = $args; $group = Utils\get_flag_value( $assoc_args, 'group' ); + $expiration = Utils\get_flag_value( $assoc_args, 'expiration' ); $key_path = array_map( function ( $key ) { if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { @@ -545,7 +552,7 @@ public function patch( $args, $assoc_args ) { if ( $patched_value === $old_value ) { WP_CLI::success( "Value passed for cache key '$key' is unchanged." ); } else { - if ( wp_cache_set( $key, $patched_value, $group ) ) { + if ( wp_cache_set( $key, $patched_value, $group, $expiration ) ) { WP_CLI::success( "Updated cache key '$key'." ); } else { WP_CLI::error( "Could not update cache key '$key'." ); From ca02d28fea13114664b93d5cce1a72bf29358b6d Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 28 Aug 2023 14:43:01 +0200 Subject: [PATCH 07/26] Fix cs --- src/Cache_Command.php | 40 ++++++++++++++++++++++----------------- src/Transient_Command.php | 38 +++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 571db78c..fb5c4be4 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -439,7 +439,7 @@ public function flush_group( $args, $assoc_args ) { */ public function pluck( $args, $assoc_args ) { list($key) = $args; - $group = Utils\get_flag_value($assoc_args, 'group'); + $group = Utils\get_flag_value( $assoc_args, 'group' ); $value = wp_cache_get( $key, $group ); @@ -447,12 +447,15 @@ public function pluck( $args, $assoc_args ) { WP_CLI::halt( 1 ); } - $key_path = array_map( function( $key ) { - if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { - return (int) $key; - } - return $key; - }, array_slice( $args, 1 ) ); + $key_path = array_map( + function( $key ) { + if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) { + return (int) $key; + } + return $key; + }, + array_slice( $args, 1 ) + ); $traverser = new RecursiveDataStructureTraverser( $value ); @@ -511,16 +514,19 @@ public function pluck( $args, $assoc_args ) { */ public function patch( $args, $assoc_args ) { list( $action, $key ) = $args; - $group = Utils\get_flag_value( $assoc_args, 'group' ); - $expiration = Utils\get_flag_value( $assoc_args, 'expiration' ); + $group = Utils\get_flag_value( $assoc_args, 'group' ); + $expiration = Utils\get_flag_value( $assoc_args, 'expiration' ); - $key_path = array_map( function ( $key ) { - if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { - return (int) $key; - } + $key_path = array_map( + function ( $key ) { + if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) { + return (int) $key; + } - return $key; - }, array_slice( $args, 2 ) ); + return $key; + }, + array_slice( $args, 2 ) + ); if ( 'delete' === $action ) { $patch_value = null; @@ -533,9 +539,9 @@ public function patch( $args, $assoc_args ) { } /* Need to make a copy of $current_value here as it is modified by reference */ - $old_value = wp_cache_get($key, $group); + $old_value = wp_cache_get( $key, $group ); $current_value = $old_value; - if (is_object($old_value)) { + if ( is_object( $old_value ) ) { $current_value = clone $old_value; } diff --git a/src/Transient_Command.php b/src/Transient_Command.php index 6ac6929d..c5733e65 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -442,12 +442,15 @@ public function pluck( $args, $assoc_args ) { exit; } - $key_path = array_map( function( $key ) { - if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { - return (int) $key; - } - return $key; - }, array_slice( $args, 1 ) ); + $key_path = array_map( + function( $key ) { + if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) { + return (int) $key; + } + return $key; + }, + array_slice( $args, 1 ) + ); $traverser = new RecursiveDataStructureTraverser( $value ); @@ -502,18 +505,21 @@ public function pluck( $args, $assoc_args ) { */ public function patch( $args, $assoc_args ) { list( $action, $key ) = $args; - $expiration = (int) Utils\get_flag_value($assoc_args, 'expiration', 0); + $expiration = (int) Utils\get_flag_value( $assoc_args, 'expiration', 0 ); $read_func = Utils\get_flag_value( $assoc_args, 'network' ) ? 'get_site_transient' : 'get_transient'; - $write_func = Utils\get_flag_value( $assoc_args, 'network' ) ? 'set_site_transient' : 'set_transient'; + $write_func = Utils\get_flag_value( $assoc_args, 'network' ) ? 'set_site_transient' : 'set_transient'; - $key_path = array_map( function ( $key ) { - if ( is_numeric( $key ) && ( $key === (string) intval( $key ) ) ) { - return (int) $key; - } + $key_path = array_map( + function ( $key ) { + if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) { + return (int) $key; + } - return $key; - }, array_slice( $args, 2 ) ); + return $key; + }, + array_slice( $args, 2 ) + ); if ( 'delete' === $action ) { $patch_value = null; @@ -526,9 +532,9 @@ public function patch( $args, $assoc_args ) { } /* Need to make a copy of $current_value here as it is modified by reference */ - $old_value = $read_func( $key ); + $old_value = $read_func( $key ); $current_value = $old_value; - if ( is_object($old_value) ) { + if ( is_object( $old_value ) ) { $current_value = clone $old_value; } From 15ad011f51a5791680dab07052a794cf3d9664ea Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Thu, 31 Aug 2023 17:19:46 +0200 Subject: [PATCH 08/26] Update Behat features tests Split features for patch/pluck commands into their own file and use `When I run` for commands when they have a successful outcome. --- features/cache-patch.feature | 89 +++++++++++++ features/cache-pluck.feature | 33 +++++ features/cache.feature | 120 ------------------ features/transient-patch.feature | 159 +++++++++++++++++++++++ features/transient-pluck.feature | 51 ++++++++ features/transient.feature | 208 ------------------------------- 6 files changed, 332 insertions(+), 328 deletions(-) create mode 100644 features/cache-patch.feature create mode 100644 features/cache-pluck.feature create mode 100644 features/transient-patch.feature create mode 100644 features/transient-pluck.feature diff --git a/features/cache-patch.feature b/features/cache-patch.feature new file mode 100644 index 00000000..770cb14a --- /dev/null +++ b/features/cache-patch.feature @@ -0,0 +1,89 @@ +Feature: Patch command available for the object cache + + Scenario: Nested values from cache can be updated at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """php + 'bar'] ); + wp_cache_set( 'other_key', ['fuz' => 'biz'] ); + + $complex_key = (object) [ + 'foo' => (object) [ + 'bar' => (object) [ + 'baz' => 2, + ], + ], + ]; + wp_cache_set( 'complex_key', $complex_key ); + }; + + WP_CLI::add_hook( 'before_invoke:cache patch', $set_foo ); + """ + + When I run `wp cache patch insert my_key fuz baz` + Then STDOUT should be: + """ + Success: Updated cache key 'my_key'. + """ + + When I run `wp cache patch insert complex_key foo bar fuz 34` + Then STDOUT should be: + """ + Success: Updated cache key 'complex_key'. + """ + + When I try `wp cache patch insert unknown_key foo bar` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + + When I run `wp cache patch update my_key foo test` + Then STDOUT should be: + """ + Success: Updated cache key 'my_key'. + """ + + When I run `wp cache patch update other_key fuz biz` + Then STDOUT should be: + """ + Success: Value passed for cache key 'other_key' is unchanged. + """ + + When I run `wp cache patch update complex_key foo bar baz 34` + Then STDOUT should be: + """ + Success: Updated cache key 'complex_key'. + """ + + When I try `wp cache patch update unknown_key foo test` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I try `wp cache patch update my_key bar test` + Then STDERR should be: + """ + Error: No data exists for key "bar" + """ + + When I run `wp cache patch delete my_key foo` + Then STDOUT should be: + """ + Success: Updated cache key 'my_key'. + """ + + When I try `wp cache patch delete unknown_key foo` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I try `wp cache patch delete my_key bar` + Then STDERR should be: + """ + Error: No data exists for key "bar" + """ diff --git a/features/cache-pluck.feature b/features/cache-pluck.feature new file mode 100644 index 00000000..82583ee5 --- /dev/null +++ b/features/cache-pluck.feature @@ -0,0 +1,33 @@ +Feature: Pluck command available for the object cache + + Scenario: Nested values from cache can be retrieved at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """php + 'bar'] ); + wp_cache_set( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + wp_cache_set( 'my_key_3', ['foo' => 'bar_custom'], 'my_custom_group' ); + }; + + WP_CLI::add_hook( 'before_invoke:cache pluck', $set_foo ); + """ + + When I run `wp cache pluck my_key foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp cache pluck my_key_2 foo bar` + Then STDOUT should be: + """ + baz + """ + + When I run `wp cache pluck my_key_3 foo --group=my_custom_group` + Then STDOUT should be: + """ + bar_custom + """ diff --git a/features/cache.feature b/features/cache.feature index e92dee70..8e21a820 100644 --- a/features/cache.feature +++ b/features/cache.feature @@ -210,123 +210,3 @@ Feature: Managed the WordPress object cache When I run `wp cache supports set_multiple` Then the return code should be 0 - - Scenario: Nested values from cache can be retrieved at any depth. - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """ - 'bar'] ); - wp_cache_set( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - wp_cache_set( 'my_key_3', ['foo' => 'bar_custom'], 'my_custom_group' ); - }; - - WP_CLI::add_hook( 'before_invoke:cache pluck', $set_foo ); - """ - - When I try `wp cache pluck my_key foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp cache pluck my_key_2 foo bar` - Then STDOUT should be: - """ - baz - """ - - When I try `wp cache pluck my_key_3 foo --group=my_custom_group` - Then STDOUT should be: - """ - bar_custom - """ - - Scenario: Nested values from cache can be updated at any depth. - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """ - 'bar'] ); - wp_cache_set( 'other_key', ['fuz' => 'biz'] ); - - $complex_key = (object) [ - 'foo' => (object) [ - 'bar' => (object) [ - 'baz' => 2, - ], - ], - ]; - wp_cache_set( 'complex_key', $complex_key ); - }; - - WP_CLI::add_hook( 'before_invoke:cache patch', $set_foo ); - """ - - When I try `wp cache patch insert my_key fuz baz` - Then STDOUT should be: - """ - Success: Updated cache key 'my_key'. - """ - - When I try `wp cache patch insert complex_key foo bar fuz 34` - Then STDOUT should be: - """ - Success: Updated cache key 'complex_key'. - """ - - When I try `wp cache patch insert unknown_key foo bar` - Then STDERR should be: - """ - Error: Cannot create key "foo" on data type boolean - """ - - When I try `wp cache patch update my_key foo test` - Then STDOUT should be: - """ - Success: Updated cache key 'my_key'. - """ - - When I try `wp cache patch update other_key fuz biz` - Then STDOUT should be: - """ - Success: Value passed for cache key 'other_key' is unchanged. - """ - - When I try `wp cache patch update complex_key foo bar baz 34` - Then STDOUT should be: - """ - Success: Updated cache key 'complex_key'. - """ - - When I try `wp cache patch update unknown_key foo test` - Then STDERR should be: - """ - Error: No data exists for key "foo" - """ - - When I try `wp cache patch update my_key bar test` - Then STDERR should be: - """ - Error: No data exists for key "bar" - """ - - When I try `wp cache patch delete my_key foo` - Then STDOUT should be: - """ - Success: Updated cache key 'my_key'. - """ - - When I try `wp cache patch delete unknown_key foo` - Then STDERR should be: - """ - Error: No data exists for key "foo" - """ - - When I try `wp cache patch delete my_key bar` - Then STDERR should be: - """ - Error: No data exists for key "bar" - """ diff --git a/features/transient-patch.feature b/features/transient-patch.feature new file mode 100644 index 00000000..58efe6e7 --- /dev/null +++ b/features/transient-patch.feature @@ -0,0 +1,159 @@ +Feature: Patch command available for the transient cache + + Scenario: Nested values from transient can be updated at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """php + 'bar'] ); + set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); + """ + + When I run `wp transient patch insert my_key fuz baz` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I run `wp transient patch insert my_key_2 foo fuz bar` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch insert unknown_key foo bar` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + + When I run `wp transient patch insert my_key foo bar` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient patch update my_key foo biz` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I run `wp transient patch update my_key_2 foo bar biz` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch update unknown_key foo bar` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I run `wp transient patch update my_key foo bar` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient patch delete my_key foo` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I run `wp transient patch delete my_key_2 foo bar` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch delete unknown_key foo` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + Scenario: Nested values from site transient can be updated at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """php + 'bar'] ); + set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); + """ + + When I run `wp transient patch insert my_key fuz baz --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I run `wp transient patch insert my_key_2 foo fuz bar --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch insert unknown_key foo bar --network` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + + When I run `wp transient patch insert my_key foo bar --network` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient patch update my_key foo biz --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I run `wp transient patch update my_key_2 foo bar biz --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch update unknown_key foo bar --network` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + + When I run `wp transient patch update my_key foo bar --network` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient patch delete my_key foo --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key'. + """ + + When I run `wp transient patch delete my_key_2 foo bar --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I try `wp transient patch delete unknown_key foo --network` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ diff --git a/features/transient-pluck.feature b/features/transient-pluck.feature new file mode 100644 index 00000000..b10787d5 --- /dev/null +++ b/features/transient-pluck.feature @@ -0,0 +1,51 @@ +Feature: Pluck command available for the transient cache + + Scenario: Nested values from transient can be retrieved at any depth. + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """php + 'bar'] ); + set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); + """ + + When I run `wp transient pluck my_key foo` + Then STDOUT should be: + """ + bar + """ + + When I run `wp transient pluck my_key_2 foo bar` + Then STDOUT should be: + """ + baz + """ + + Scenario: Nested values from site transient can be retrieved at any depth. + Given a WP multisite install + And I run `wp site create --slug=foo` + And a wp-content/mu-plugins/test-harness.php file: + """php + 'bar'] ); + }; + + WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); + """ + + When I run `wp transient pluck my_key foo --network` + Then STDOUT should be: + """ + bar + """ + + When I try `wp transient pluck my_key foo` + Then STDERR should be: + """ + Warning: Transient with key "my_key" is not set. + """ diff --git a/features/transient.feature b/features/transient.feature index 5fc852f4..3902da95 100644 --- a/features/transient.feature +++ b/features/transient.feature @@ -604,211 +604,3 @@ Feature: Manage WordPress transient cache name foo4 """ - - Scenario: Nested values from transient can be retrieved at any depth. - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """ - 'bar'] ); - set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); - """ - - When I try `wp transient pluck my_key foo` - Then STDOUT should be: - """ - bar - """ - - When I try `wp transient pluck my_key_2 foo bar` - Then STDOUT should be: - """ - baz - """ - - Scenario: Nested values from site transient can be retrieved at any depth. - Given a WP multisite install - And I run `wp site create --slug=foo` - And a wp-content/mu-plugins/test-harness.php file: - """ - 'bar'] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); - """ - - When I try `wp transient pluck my_key foo --network` - Then STDOUT should be: - """ - bar - """ - - When I try `wp transient pluck my_key foo` - Then STDERR should be: - """ - Warning: Transient with key "my_key" is not set. - """ - - Scenario: Nested values from transient can be updated at any depth. - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """ - 'bar'] ); - set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); - """ - - When I try `wp transient patch insert my_key fuz baz` - Then STDOUT should be: - """ - Success: Updated transient 'my_key'. - """ - - When I try `wp transient patch insert my_key_2 foo fuz bar` - Then STDOUT should be: - """ - Success: Updated transient 'my_key_2'. - """ - - When I try `wp transient patch insert unknown_key foo bar` - Then STDERR should be: - """ - Error: Cannot create key "foo" on data type boolean - """ - - When I try `wp transient patch insert my_key foo bar` - Then STDOUT should be: - """ - Success: Value passed for transient 'my_key' is unchanged. - """ - - When I try `wp transient patch update my_key foo biz` - Then STDOUT should be: - """ - Success: Updated transient 'my_key'. - """ - - When I try `wp transient patch update my_key_2 foo bar biz` - Then STDOUT should be: - """ - Success: Updated transient 'my_key_2'. - """ - - When I try `wp transient patch update unknown_key foo bar` - Then STDERR should be: - """ - Error: No data exists for key "foo" - """ - - When I try `wp transient patch update my_key foo bar` - Then STDOUT should be: - """ - Success: Value passed for transient 'my_key' is unchanged. - """ - - When I try `wp transient patch delete my_key foo` - Then STDOUT should be: - """ - Success: Updated transient 'my_key'. - """ - - When I try `wp transient patch delete my_key_2 foo bar` - Then STDOUT should be: - """ - Success: Updated transient 'my_key_2'. - """ - - When I try `wp transient patch delete unknown_key foo` - Then STDERR should be: - """ - Error: No data exists for key "foo" - """ - - Scenario: Nested values from site transient can be updated at any depth. - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """ - 'bar'] ); - set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); - """ - - When I try `wp transient patch insert my_key fuz baz --network` - Then STDOUT should be: - """ - Success: Updated transient 'my_key'. - """ - - When I try `wp transient patch insert my_key_2 foo fuz bar --network` - Then STDOUT should be: - """ - Success: Updated transient 'my_key_2'. - """ - - When I try `wp transient patch insert unknown_key foo bar --network` - Then STDERR should be: - """ - Error: Cannot create key "foo" on data type boolean - """ - - When I try `wp transient patch insert my_key foo bar --network` - Then STDOUT should be: - """ - Success: Value passed for transient 'my_key' is unchanged. - """ - - When I try `wp transient patch update my_key foo biz --network` - Then STDOUT should be: - """ - Success: Updated transient 'my_key'. - """ - - When I try `wp transient patch update my_key_2 foo bar biz --network` - Then STDOUT should be: - """ - Success: Updated transient 'my_key_2'. - """ - - When I try `wp transient patch update unknown_key foo bar --network` - Then STDERR should be: - """ - Error: No data exists for key "foo" - """ - - When I try `wp transient patch update my_key foo bar --network` - Then STDOUT should be: - """ - Success: Value passed for transient 'my_key' is unchanged. - """ - - When I try `wp transient patch delete my_key foo --network` - Then STDOUT should be: - """ - Success: Updated transient 'my_key'. - """ - - When I try `wp transient patch delete my_key_2 foo bar --network` - Then STDOUT should be: - """ - Success: Updated transient 'my_key_2'. - """ - - When I try `wp transient patch delete unknown_key foo --network` - Then STDERR should be: - """ - Error: No data exists for key "foo" - """ From ba1f610e99e789a2cfd5034eb0ab65a64c680f35 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Thu, 31 Aug 2023 17:54:48 +0200 Subject: [PATCH 09/26] Add temporary log to debug failing tests in github action --- features/cache-patch.feature | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/cache-patch.feature b/features/cache-patch.feature index 770cb14a..f79e9386 100644 --- a/features/cache-patch.feature +++ b/features/cache-patch.feature @@ -6,8 +6,9 @@ Feature: Patch command available for the object cache """php 'bar'] ); - wp_cache_set( 'other_key', ['fuz' => 'biz'] ); + //TODO: DEBUG, remove before merging branch. + WP_CLI::log( var_export( wp_cache_set( 'my_key', ['foo' => 'bar'] ), true ) ); + WP_CLI::log( var_export( wp_cache_set( 'other_key', ['fuz' => 'biz'] ), true ) ); $complex_key = (object) [ 'foo' => (object) [ From 6b8d91c0a63810be3deae996a563846d0567febe Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Thu, 7 Sep 2023 10:06:39 +0200 Subject: [PATCH 10/26] Small CS fixes for WPCS v3 --- src/Cache/RecursiveDataStructureTraverser.php | 6 +++--- src/Cache_Command.php | 10 ++++------ src/Transient_Command.php | 10 ++++------ 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/Cache/RecursiveDataStructureTraverser.php b/src/Cache/RecursiveDataStructureTraverser.php index e7e21ee1..289902e4 100644 --- a/src/Cache/RecursiveDataStructureTraverser.php +++ b/src/Cache/RecursiveDataStructureTraverser.php @@ -26,12 +26,12 @@ class RecursiveDataStructureTraverser { * * @param mixed $data The data to read/manipulate by reference. * @param string|int $key The key/property the data belongs to. - * @param static $parent + * @param static $parent_instance */ - public function __construct( &$data, $key = null, $parent = null ) { + public function __construct( &$data, $key = null, $parent_instance = null ) { $this->data =& $data; $this->key = $key; - $this->parent = $parent; + $this->parent = $parent_instance; } /** diff --git a/src/Cache_Command.php b/src/Cache_Command.php index fb5c4be4..4f2540fd 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -448,7 +448,7 @@ public function pluck( $args, $assoc_args ) { } $key_path = array_map( - function( $key ) { + function ( $key ) { if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) { return (int) $key; } @@ -557,12 +557,10 @@ function ( $key ) { if ( $patched_value === $old_value ) { WP_CLI::success( "Value passed for cache key '$key' is unchanged." ); - } else { - if ( wp_cache_set( $key, $patched_value, $group, $expiration ) ) { + } elseif ( wp_cache_set( $key, $patched_value, $group, $expiration ) ) { WP_CLI::success( "Updated cache key '$key'." ); - } else { - WP_CLI::error( "Could not update cache key '$key'." ); - } + } else { + WP_CLI::error( "Could not update cache key '$key'." ); } } } diff --git a/src/Transient_Command.php b/src/Transient_Command.php index c5733e65..5d55b1d2 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -443,7 +443,7 @@ public function pluck( $args, $assoc_args ) { } $key_path = array_map( - function( $key ) { + function ( $key ) { if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) { return (int) $key; } @@ -550,12 +550,10 @@ function ( $key ) { if ( $patched_value === $old_value ) { WP_CLI::success( "Value passed for transient '$key' is unchanged." ); - } else { - if ( $write_func( $key, $patched_value, $expiration ) ) { + } elseif ( $write_func( $key, $patched_value, $expiration ) ) { WP_CLI::success( "Updated transient '$key'." ); - } else { - WP_CLI::error( "Could not update transient '$key'." ); - } + } else { + WP_CLI::error( "Could not update transient '$key'." ); } } From a70e2d7ebb11b7dcef3dd5dc981cf5cabd79eaed Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Fri, 15 Sep 2023 16:20:00 +0200 Subject: [PATCH 11/26] Fix failing functional tests --- features/cache-patch.feature | 5 ++--- src/Cache_Command.php | 20 +++++++++++++++----- src/Transient_Command.php | 20 +++++++++++++++----- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/features/cache-patch.feature b/features/cache-patch.feature index f79e9386..770cb14a 100644 --- a/features/cache-patch.feature +++ b/features/cache-patch.feature @@ -6,9 +6,8 @@ Feature: Patch command available for the object cache """php 'bar'] ), true ) ); - WP_CLI::log( var_export( wp_cache_set( 'other_key', ['fuz' => 'biz'] ), true ) ); + wp_cache_set( 'my_key', ['foo' => 'bar'] ); + wp_cache_set( 'other_key', ['fuz' => 'biz'] ); $complex_key = (object) [ 'foo' => (object) [ diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 4f2540fd..df5394b1 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -530,12 +530,22 @@ function ( $key ) { if ( 'delete' === $action ) { $patch_value = null; - } elseif ( \WP_CLI\Entity\Utils::has_stdin() ) { - $stdin_value = WP_CLI::get_value_from_arg_or_stdin( $args, - 1 ); - $patch_value = WP_CLI::read_value( trim( $stdin_value ), $assoc_args ); } else { - // Take the patch value as the last positional argument. Mutates $key_path to be 1 element shorter! - $patch_value = WP_CLI::read_value( array_pop( $key_path ), $assoc_args ); + $stdin_value = WP_CLI\Cache\Utils::has_stdin() + ? trim( WP_CLI::get_value_from_arg_or_stdin( $args, -1 ) ) + : null; + + if ( ! empty( $stdin_value ) ) { + $patch_value = WP_CLI::read_value( $stdin_value, $assoc_args ); + } elseif ( count( $key_path ) > 1 ) { + $patch_value = WP_CLI::read_value( array_pop( $key_path ), $assoc_args ); + } else { + $patch_value = null; + } + + if ( null === $patch_value ) { + WP_CLI::error( 'Please provide value to update.' ); + } } /* Need to make a copy of $current_value here as it is modified by reference */ diff --git a/src/Transient_Command.php b/src/Transient_Command.php index 5d55b1d2..1d465d7d 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -523,12 +523,22 @@ function ( $key ) { if ( 'delete' === $action ) { $patch_value = null; - } elseif ( \WP_CLI\Entity\Utils::has_stdin() ) { - $stdin_value = WP_CLI::get_value_from_arg_or_stdin( $args, - 1 ); - $patch_value = WP_CLI::read_value( trim( $stdin_value ), $assoc_args ); } else { - // Take the patch value as the last positional argument. Mutates $key_path to be 1 element shorter! - $patch_value = WP_CLI::read_value( array_pop( $key_path ), $assoc_args ); + $stdin_value = WP_CLI\Cache\Utils::has_stdin() + ? trim( WP_CLI::get_value_from_arg_or_stdin( $args, -1 ) ) + : null; + + if ( ! empty( $stdin_value ) ) { + $patch_value = WP_CLI::read_value( $stdin_value, $assoc_args ); + } elseif ( count( $key_path ) > 1 ) { + $patch_value = WP_CLI::read_value( array_pop( $key_path ), $assoc_args ); + } else { + $patch_value = null; + } + + if ( null === $patch_value ) { + WP_CLI::error( 'Please provide value to update.' ); + } } /* Need to make a copy of $current_value here as it is modified by reference */ From 5d0e6df3853aeb6d670a727328e9e7164d3e58ce Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 18 Sep 2023 21:44:44 +0200 Subject: [PATCH 12/26] Add tests for RecursiveDataStructureTraverser.php --- phpunit.xml.dist | 21 +++ src/Cache/RecursiveDataStructureTraverser.php | 6 +- tests/RecursiveDataStructureTraverserTest.php | 162 ++++++++++++++++++ 3 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 phpunit.xml.dist create mode 100644 tests/RecursiveDataStructureTraverserTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..131826c9 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,21 @@ + + + + tests + + + + + src + + + diff --git a/src/Cache/RecursiveDataStructureTraverser.php b/src/Cache/RecursiveDataStructureTraverser.php index 289902e4..c6f06e39 100644 --- a/src/Cache/RecursiveDataStructureTraverser.php +++ b/src/Cache/RecursiveDataStructureTraverser.php @@ -24,9 +24,9 @@ class RecursiveDataStructureTraverser { /** * RecursiveDataStructureTraverser constructor. * - * @param mixed $data The data to read/manipulate by reference. - * @param string|int $key The key/property the data belongs to. - * @param static $parent_instance + * @param mixed $data The data to read/manipulate by reference. + * @param string|int $key The key/property the data belongs to. + * @param static|null $parent_instance The parent instance of the traverser. */ public function __construct( &$data, $key = null, $parent_instance = null ) { $this->data =& $data; diff --git a/tests/RecursiveDataStructureTraverserTest.php b/tests/RecursiveDataStructureTraverserTest.php new file mode 100644 index 00000000..6acab84e --- /dev/null +++ b/tests/RecursiveDataStructureTraverserTest.php @@ -0,0 +1,162 @@ + 'bar', + ); + + $traverser = new RecursiveDataStructureTraverser( $array ); + + $this->assertEquals( 'bar', $traverser->get( 'foo' ) ); + } + + /** @test */ + public function it_can_get_a_top_level_object_value() { + $object = (object) array( + 'foo' => 'bar', + ); + + $traverser = new RecursiveDataStructureTraverser( $object ); + + $this->assertEquals( 'bar', $traverser->get( 'foo' ) ); + } + + /** @test */ + public function it_can_get_a_nested_array_value() { + $array = array( + 'foo' => array( + 'bar' => array( + 'baz' => 'value', + ), + ), + ); + + $traverser = new RecursiveDataStructureTraverser( $array ); + + $this->assertEquals( 'value', $traverser->get( array( 'foo', 'bar', 'baz' ) ) ); + } + + /** @test */ + public function it_can_get_a_nested_object_value() { + $object = (object) array( + 'foo' => (object) array( + 'bar' => 'baz', + ), + ); + + $traverser = new RecursiveDataStructureTraverser( $object ); + + $this->assertEquals( 'baz', $traverser->get( array( 'foo', 'bar' ) ) ); + } + + /** @test */ + public function it_can_set_a_nested_array_value() { + $array = array( + 'foo' => array( + 'bar' => 'baz', + ), + ); + $this->assertEquals( 'baz', $array['foo']['bar'] ); + + $traverser = new RecursiveDataStructureTraverser( $array ); + $traverser->update( array( 'foo', 'bar' ), 'new' ); + + $this->assertEquals( 'new', $array['foo']['bar'] ); + } + + /** @test */ + public function it_can_set_a_nested_object_value() { + $object = (object) array( + 'foo' => (object) array( + 'bar' => 'baz', + ), + ); + $this->assertEquals( 'baz', $object->foo->bar ); + + $traverser = new RecursiveDataStructureTraverser( $object ); + $traverser->update( array( 'foo', 'bar' ), 'new' ); + + $this->assertEquals( 'new', $object->foo->bar ); + } + + /** @test */ + public function it_can_update_an_integer_object_value() { + $object = (object) array( + 'test_mode' => 0, + ); + $this->assertEquals( 0, $object->test_mode ); + + $traverser = new RecursiveDataStructureTraverser( $object ); + $traverser->update( array( 'test_mode' ), 1 ); + + $this->assertEquals( 1, $object->test_mode ); + } + + /** @test */ + public function it_can_delete_a_nested_array_value() { + $array = array( + 'foo' => array( + 'bar' => 'baz', + ), + ); + $this->assertArrayHasKey( 'bar', $array['foo'] ); + + $traverser = new RecursiveDataStructureTraverser( $array ); + $traverser->delete( array( 'foo', 'bar' ) ); + + $this->assertArrayNotHasKey( 'bar', $array['foo'] ); + } + + /** @test */ + public function it_can_delete_a_nested_object_value() { + $object = (object) array( + 'foo' => (object) array( + 'bar' => 'baz', + ), + ); + $this->assertObjectHasAttribute( 'bar', $object->foo ); + + $traverser = new RecursiveDataStructureTraverser( $object ); + $traverser->delete( array( 'foo', 'bar' ) ); + + $this->assertObjectNotHasAttribute( 'bar', $object->foo ); + } + + /** @test */ + public function it_can_insert_a_key_into_a_nested_array() { + $array = array( + 'foo' => array( + 'bar' => 'baz', + ), + ); + + $traverser = new RecursiveDataStructureTraverser( $array ); + $traverser->insert( array( 'foo', 'new' ), 'new value' ); + + $this->assertArrayHasKey( 'new', $array['foo'] ); + $this->assertEquals( 'new value', $array['foo']['new'] ); + } + + /** @test */ + public function it_throws_an_exception_when_attempting_to_create_a_key_on_an_invalid_type() { + $data = 'a string'; + $traverser = new RecursiveDataStructureTraverser( $data ); + + try { + $traverser->insert( array( 'key' ), 'value' ); + } catch ( \Exception $e ) { + $this->assertSame( 'a string', $data ); + return; + } + + $this->fail( 'Failed to assert that an exception was thrown when inserting a key into a string.' ); + } +} From dd9eec306110bb27c513e26d1690c5504bd5a8c3 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Tue, 19 Sep 2023 20:44:41 +0200 Subject: [PATCH 13/26] Fix wrong command in docblock Co-authored-by: Daniel Bachhuber --- src/Cache_Command.php | 2 +- src/Transient_Command.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index df5394b1..9d42b370 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -486,7 +486,7 @@ function ( $key ) { * : Cache key. * * ... - * : The name(s) of the keys within the value to locate the value to pluck. + * : The name(s) of the keys within the value to locate the value to patch. * * [] * : The new value. If omitted, the value is read from STDIN. diff --git a/src/Transient_Command.php b/src/Transient_Command.php index 1d465d7d..4faf31cd 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -481,7 +481,7 @@ function ( $key ) { * : Key for the transient. * * ... - * : The name(s) of the keys within the value to locate the value to pluck. + * : The name(s) of the keys within the value to locate the value to patch. * * [] * : The new value. If omitted, the value is read from STDIN. From d17471730679a0acd6ab7b2475d3fd351c716194 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Tue, 19 Sep 2023 22:00:16 +0200 Subject: [PATCH 14/26] Fix CS issue Co-authored-by: Daniel Bachhuber --- src/Cache_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 9d42b370..63cff8b3 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -438,7 +438,7 @@ public function flush_group( $args, $assoc_args ) { * --- */ public function pluck( $args, $assoc_args ) { - list($key) = $args; + list( $key ) = $args; $group = Utils\get_flag_value( $assoc_args, 'group' ); $value = wp_cache_get( $key, $group ); From ae6d0a6862e1ee6de63c8a9e805587e19ec8a981 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Tue, 14 Nov 2023 12:33:36 +0000 Subject: [PATCH 15/26] Reuse has_stdin() from framework --- composer.json | 2 +- phpunit.xml.dist | 21 -- src/Cache/NonExistentKeyException.php | 24 --- src/Cache/RecursiveDataStructureTraverser.php | 182 ------------------ src/Cache/Utils.php | 22 --- src/Cache_Command.php | 4 +- src/Transient_Command.php | 4 +- tests/RecursiveDataStructureTraverserTest.php | 162 ---------------- 8 files changed, 5 insertions(+), 416 deletions(-) delete mode 100644 phpunit.xml.dist delete mode 100644 src/Cache/NonExistentKeyException.php delete mode 100644 src/Cache/RecursiveDataStructureTraverser.php delete mode 100644 src/Cache/Utils.php delete mode 100644 tests/RecursiveDataStructureTraverserTest.php diff --git a/composer.json b/composer.json index b68ac7ff..13878246 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "wp-cli/wp-cli": "^2.5" + "wp-cli/wp-cli": "^2.10" }, "require-dev": { "wp-cli/entity-command": "^1.3 || ^2", diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index 131826c9..00000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,21 +0,0 @@ - - - - tests - - - - - src - - - diff --git a/src/Cache/NonExistentKeyException.php b/src/Cache/NonExistentKeyException.php deleted file mode 100644 index ecc38d8c..00000000 --- a/src/Cache/NonExistentKeyException.php +++ /dev/null @@ -1,24 +0,0 @@ -traverser = $traverser; - } - - /** - * @return RecursiveDataStructureTraverser - */ - public function get_traverser() { - return $this->traverser; - } -} diff --git a/src/Cache/RecursiveDataStructureTraverser.php b/src/Cache/RecursiveDataStructureTraverser.php deleted file mode 100644 index c6f06e39..00000000 --- a/src/Cache/RecursiveDataStructureTraverser.php +++ /dev/null @@ -1,182 +0,0 @@ -data =& $data; - $this->key = $key; - $this->parent = $parent_instance; - } - - /** - * Get the nested value at the given key path. - * - * @param string|int|array $key_path - * - * @return static - */ - public function get( $key_path ) { - return $this->traverse_to( (array) $key_path )->value(); - } - - /** - * Get the current data. - * - * @return mixed - */ - public function value() { - return $this->data; - } - - /** - * Update a nested value at the given key path. - * - * @param string|int|array $key_path - * @param mixed $value - */ - public function update( $key_path, $value ) { - $this->traverse_to( (array) $key_path )->set_value( $value ); - } - - /** - * Update the current data with the given value. - * - * This will mutate the variable which was passed into the constructor - * as the data is set and traversed by reference. - * - * @param mixed $value - */ - public function set_value( $value ) { - $this->data = $value; - } - - /** - * Unset the value at the given key path. - * - * @param $key_path - */ - public function delete( $key_path ) { - $this->traverse_to( (array) $key_path )->unset_on_parent(); - } - - /** - * Define a nested value while creating keys if they do not exist. - * - * @param array $key_path - * @param mixed $value - */ - public function insert( $key_path, $value ) { - try { - $this->update( $key_path, $value ); - } catch ( NonExistentKeyException $exception ) { - $exception->get_traverser()->create_key(); - $this->insert( $key_path, $value ); - } - } - - /** - * Delete the key on the parent's data that references this data. - */ - public function unset_on_parent() { - $this->parent->delete_by_key( $this->key ); - } - - /** - * Delete the given key from the data. - * - * @param $key - */ - public function delete_by_key( $key ) { - if ( is_array( $this->data ) ) { - unset( $this->data[ $key ] ); - } else { - unset( $this->data->$key ); - } - } - - /** - * Get an instance of the traverser for the given hierarchical key. - * - * @param array $key_path Hierarchical key path within the current data to traverse to. - * - * @throws NonExistentKeyException - * - * @return static - */ - public function traverse_to( array $key_path ) { - $current = array_shift( $key_path ); - - if ( null === $current ) { - return $this; - } - - if ( ! $this->exists( $current ) ) { - $exception = new NonExistentKeyException( "No data exists for key \"{$current}\"" ); - $exception->set_traverser( new static( $this->data, $current, $this->parent ) ); - throw $exception; - } - - foreach ( $this->data as $key => &$key_data ) { - if ( $key === $current ) { - $traverser = new static( $key_data, $key, $this ); - return $traverser->traverse_to( $key_path ); - } - } - } - - /** - * Create the key on the current data. - * - * @throws UnexpectedValueException - */ - protected function create_key() { - if ( is_array( $this->data ) ) { - $this->data[ $this->key ] = null; - } elseif ( is_object( $this->data ) ) { - $this->data->{$this->key} = null; - } else { - $type = gettype( $this->data ); - throw new UnexpectedValueException( - "Cannot create key \"{$this->key}\" on data type {$type}" - ); - } - } - - /** - * Check if the given key exists on the current data. - * - * @param string $key - * - * @return bool - */ - public function exists( $key ) { - return ( is_array( $this->data ) && array_key_exists( $key, $this->data ) ) || - ( is_object( $this->data ) && property_exists( $this->data, $key ) ); - } -} diff --git a/src/Cache/Utils.php b/src/Cache/Utils.php deleted file mode 100644 index d43be2bb..00000000 --- a/src/Cache/Utils.php +++ /dev/null @@ -1,22 +0,0 @@ - 'bar', - ); - - $traverser = new RecursiveDataStructureTraverser( $array ); - - $this->assertEquals( 'bar', $traverser->get( 'foo' ) ); - } - - /** @test */ - public function it_can_get_a_top_level_object_value() { - $object = (object) array( - 'foo' => 'bar', - ); - - $traverser = new RecursiveDataStructureTraverser( $object ); - - $this->assertEquals( 'bar', $traverser->get( 'foo' ) ); - } - - /** @test */ - public function it_can_get_a_nested_array_value() { - $array = array( - 'foo' => array( - 'bar' => array( - 'baz' => 'value', - ), - ), - ); - - $traverser = new RecursiveDataStructureTraverser( $array ); - - $this->assertEquals( 'value', $traverser->get( array( 'foo', 'bar', 'baz' ) ) ); - } - - /** @test */ - public function it_can_get_a_nested_object_value() { - $object = (object) array( - 'foo' => (object) array( - 'bar' => 'baz', - ), - ); - - $traverser = new RecursiveDataStructureTraverser( $object ); - - $this->assertEquals( 'baz', $traverser->get( array( 'foo', 'bar' ) ) ); - } - - /** @test */ - public function it_can_set_a_nested_array_value() { - $array = array( - 'foo' => array( - 'bar' => 'baz', - ), - ); - $this->assertEquals( 'baz', $array['foo']['bar'] ); - - $traverser = new RecursiveDataStructureTraverser( $array ); - $traverser->update( array( 'foo', 'bar' ), 'new' ); - - $this->assertEquals( 'new', $array['foo']['bar'] ); - } - - /** @test */ - public function it_can_set_a_nested_object_value() { - $object = (object) array( - 'foo' => (object) array( - 'bar' => 'baz', - ), - ); - $this->assertEquals( 'baz', $object->foo->bar ); - - $traverser = new RecursiveDataStructureTraverser( $object ); - $traverser->update( array( 'foo', 'bar' ), 'new' ); - - $this->assertEquals( 'new', $object->foo->bar ); - } - - /** @test */ - public function it_can_update_an_integer_object_value() { - $object = (object) array( - 'test_mode' => 0, - ); - $this->assertEquals( 0, $object->test_mode ); - - $traverser = new RecursiveDataStructureTraverser( $object ); - $traverser->update( array( 'test_mode' ), 1 ); - - $this->assertEquals( 1, $object->test_mode ); - } - - /** @test */ - public function it_can_delete_a_nested_array_value() { - $array = array( - 'foo' => array( - 'bar' => 'baz', - ), - ); - $this->assertArrayHasKey( 'bar', $array['foo'] ); - - $traverser = new RecursiveDataStructureTraverser( $array ); - $traverser->delete( array( 'foo', 'bar' ) ); - - $this->assertArrayNotHasKey( 'bar', $array['foo'] ); - } - - /** @test */ - public function it_can_delete_a_nested_object_value() { - $object = (object) array( - 'foo' => (object) array( - 'bar' => 'baz', - ), - ); - $this->assertObjectHasAttribute( 'bar', $object->foo ); - - $traverser = new RecursiveDataStructureTraverser( $object ); - $traverser->delete( array( 'foo', 'bar' ) ); - - $this->assertObjectNotHasAttribute( 'bar', $object->foo ); - } - - /** @test */ - public function it_can_insert_a_key_into_a_nested_array() { - $array = array( - 'foo' => array( - 'bar' => 'baz', - ), - ); - - $traverser = new RecursiveDataStructureTraverser( $array ); - $traverser->insert( array( 'foo', 'new' ), 'new value' ); - - $this->assertArrayHasKey( 'new', $array['foo'] ); - $this->assertEquals( 'new value', $array['foo']['new'] ); - } - - /** @test */ - public function it_throws_an_exception_when_attempting_to_create_a_key_on_an_invalid_type() { - $data = 'a string'; - $traverser = new RecursiveDataStructureTraverser( $data ); - - try { - $traverser->insert( array( 'key' ), 'value' ); - } catch ( \Exception $e ) { - $this->assertSame( 'a string', $data ); - return; - } - - $this->fail( 'Failed to assert that an exception was thrown when inserting a key into a string.' ); - } -} From b74bc477bcb335cbf01304c5568f374eac6c5f08 Mon Sep 17 00:00:00 2001 From: Alain Schlesser Date: Tue, 14 Nov 2023 12:40:59 +0000 Subject: [PATCH 16/26] Fix PHPCS issues --- src/Cache_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index fef67b93..751258bb 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -439,7 +439,7 @@ public function flush_group( $args, $assoc_args ) { */ public function pluck( $args, $assoc_args ) { list( $key ) = $args; - $group = Utils\get_flag_value( $assoc_args, 'group' ); + $group = Utils\get_flag_value( $assoc_args, 'group' ); $value = wp_cache_get( $key, $group ); From d28445fa9bd39e4a4fb342e48490b9d3e907cb76 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 4 Dec 2023 10:11:17 +0100 Subject: [PATCH 17/26] Use `wp eval` to set the transient --- features/transient-patch.feature | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/features/transient-patch.feature b/features/transient-patch.feature index 58efe6e7..b44186d0 100644 --- a/features/transient-patch.feature +++ b/features/transient-patch.feature @@ -2,16 +2,8 @@ Feature: Patch command available for the transient cache Scenario: Nested values from transient can be updated at any depth. Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """php - 'bar'] ); - set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); - """ + And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` When I run `wp transient patch insert my_key fuz baz` Then STDOUT should be: From b1afe2e9bda21944ef7f1f4d7255ba600cb3b254 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Fri, 8 Dec 2023 17:08:10 +0100 Subject: [PATCH 18/26] split `patch` feature tests and add additionnal checks with `transient get` --- features/transient-patch.feature | 108 ++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 16 deletions(-) diff --git a/features/transient-patch.feature b/features/transient-patch.feature index b44186d0..336784a2 100644 --- a/features/transient-patch.feature +++ b/features/transient-patch.feature @@ -1,6 +1,6 @@ Feature: Patch command available for the transient cache - Scenario: Nested values from transient can be updated at any depth. + Scenario: Nested values from transient can be inserted at any depth. Given a WP install And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` And I run `wp eval "set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` @@ -11,64 +11,140 @@ Feature: Patch command available for the transient cache Success: Updated transient 'my_key'. """ - When I run `wp transient patch insert my_key_2 foo fuz bar` + When I run `wp transient get my_key --format=json` + Then STDOUT should be: + """ + {"foo":"bar","fuz":"baz"} + """ + + When I run `wp transient patch insert my_key foo bar` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient get my_key --format=json` + Then STDOUT should be: + """ + {"foo":"bar","fuz":"baz"} + """ + + When I run `wp transient patch insert my_key_2 foo fuz biz` Then STDOUT should be: """ Success: Updated transient 'my_key_2'. """ - When I try `wp transient patch insert unknown_key foo bar` - Then STDERR should be: + When I run `wp transient get my_key_2 --format=json` + Then STDOUT should be: """ - Error: Cannot create key "foo" on data type boolean + {"foo":{"bar":"baz","fuz":"biz"}} """ - When I run `wp transient patch insert my_key foo bar` + When I run `wp transient patch insert my_key_2 foo bar baz` Then STDOUT should be: """ - Success: Value passed for transient 'my_key' is unchanged. + Success: Value passed for transient 'my_key_2' is unchanged. + """ + + When I run `wp transient get my_key_2 --format=json` + Then STDOUT should be: """ + {"foo":{"bar":"baz","fuz":"biz"}} + """ + + Scenario: Nested values from transient can be updated at any depth. + Given a WP install + And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` - When I run `wp transient patch update my_key foo biz` + When I run `wp transient patch update my_key foo baz` Then STDOUT should be: """ Success: Updated transient 'my_key'. """ + When I run `wp transient get my_key --format=json` + Then STDOUT should be: + """ + {"foo":"baz"} + """ + + When I run `wp transient patch update my_key foo baz` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient get my_key --format=json` + Then STDOUT should be: + """ + {"foo":"baz"} + """ + When I run `wp transient patch update my_key_2 foo bar biz` Then STDOUT should be: """ Success: Updated transient 'my_key_2'. """ - When I try `wp transient patch update unknown_key foo bar` - Then STDERR should be: + When I run `wp transient get my_key_2 --format=json` + Then STDOUT should be: """ - Error: No data exists for key "foo" + {"foo":{"bar":"biz"}} """ - When I run `wp transient patch update my_key foo bar` + When I run `wp transient patch update my_key_2 foo bar biz` Then STDOUT should be: """ - Success: Value passed for transient 'my_key' is unchanged. + Success: Value passed for transient 'my_key_2' is unchanged. """ + When I run `wp transient get my_key_2 --format=json` + Then STDOUT should be: + """ + {"foo":{"bar":"biz"}} + """ + + Scenario: Nested values from transient can be deleted at any depth. + Given a WP install + And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` + When I run `wp transient patch delete my_key foo` Then STDOUT should be: """ Success: Updated transient 'my_key'. """ + When I run `wp transient get my_key --format=json` + Then STDOUT should be: + """ + [] + """ + When I run `wp transient patch delete my_key_2 foo bar` Then STDOUT should be: """ Success: Updated transient 'my_key_2'. """ - When I try `wp transient patch delete unknown_key foo` - Then STDERR should be: + When I run `wp transient get my_key_2 --format=json` + Then STDOUT should be: """ - Error: No data exists for key "foo" + {"foo":[]} + """ + + When I run `wp transient patch delete my_key_2 foo` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I run `wp transient get my_key_2 --format=json` + Then STDOUT should be: + """ + [] """ Scenario: Nested values from site transient can be updated at any depth. From 8d9ba42f76d282ae606672d3579d2766e24b3e20 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 11 Dec 2023 11:26:20 +0100 Subject: [PATCH 19/26] split `patch` feature tests for site transient and add additionnal checks --- features/transient-patch.feature | 122 ++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/features/transient-patch.feature b/features/transient-patch.feature index 336784a2..4d1f3f76 100644 --- a/features/transient-patch.feature +++ b/features/transient-patch.feature @@ -147,18 +147,10 @@ Feature: Patch command available for the transient cache [] """ - Scenario: Nested values from site transient can be updated at any depth. - Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """php - 'bar'] ); - set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient patch', $set_foo ); - """ + Scenario: Nested values from site transient can be inserted at any depth. + Given a WP multisite install + And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` When I run `wp transient patch insert my_key fuz baz --network` Then STDOUT should be: @@ -166,62 +158,138 @@ Feature: Patch command available for the transient cache Success: Updated transient 'my_key'. """ - When I run `wp transient patch insert my_key_2 foo fuz bar --network` + When I run `wp transient get my_key --format=json --network` + Then STDOUT should be: + """ + {"foo":"bar","fuz":"baz"} + """ + + When I run `wp transient patch insert my_key foo bar --network` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient get my_key --format=json --network` + Then STDOUT should be: + """ + {"foo":"bar","fuz":"baz"} + """ + + When I run `wp transient patch insert my_key_2 foo fuz biz --network` Then STDOUT should be: """ Success: Updated transient 'my_key_2'. """ - When I try `wp transient patch insert unknown_key foo bar --network` - Then STDERR should be: + When I run `wp transient get my_key_2 --format=json --network` + Then STDOUT should be: """ - Error: Cannot create key "foo" on data type boolean + {"foo":{"bar":"baz","fuz":"biz"}} """ - When I run `wp transient patch insert my_key foo bar --network` + When I run `wp transient patch insert my_key_2 foo bar baz --network` Then STDOUT should be: """ - Success: Value passed for transient 'my_key' is unchanged. + Success: Value passed for transient 'my_key_2' is unchanged. """ - When I run `wp transient patch update my_key foo biz --network` + When I run `wp transient get my_key_2 --format=json --network` + Then STDOUT should be: + """ + {"foo":{"bar":"baz","fuz":"biz"}} + """ + + Scenario: Nested values from site transient can be updated at any depth. + Given a WP multisite install + And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` + + When I run `wp transient patch update my_key foo baz --network` Then STDOUT should be: """ Success: Updated transient 'my_key'. """ + When I run `wp transient get my_key --format=json --network` + Then STDOUT should be: + """ + {"foo":"baz"} + """ + + When I run `wp transient patch update my_key foo baz --network` + Then STDOUT should be: + """ + Success: Value passed for transient 'my_key' is unchanged. + """ + + When I run `wp transient get my_key --format=json --network` + Then STDOUT should be: + """ + {"foo":"baz"} + """ + When I run `wp transient patch update my_key_2 foo bar biz --network` Then STDOUT should be: """ Success: Updated transient 'my_key_2'. """ - When I try `wp transient patch update unknown_key foo bar --network` - Then STDERR should be: + When I run `wp transient get my_key_2 --format=json --network` + Then STDOUT should be: """ - Error: No data exists for key "foo" + {"foo":{"bar":"biz"}} """ - When I run `wp transient patch update my_key foo bar --network` + When I run `wp transient patch update my_key_2 foo bar biz --network` Then STDOUT should be: """ - Success: Value passed for transient 'my_key' is unchanged. + Success: Value passed for transient 'my_key_2' is unchanged. + """ + + When I run `wp transient get my_key_2 --format=json --network` + Then STDOUT should be: + """ + {"foo":{"bar":"biz"}} """ + Scenario: Nested values from site transient can be deleted at any depth. + Given a WP multisite install + And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` + When I run `wp transient patch delete my_key foo --network` Then STDOUT should be: """ Success: Updated transient 'my_key'. """ + When I run `wp transient get my_key --format=json --network` + Then STDOUT should be: + """ + [] + """ + When I run `wp transient patch delete my_key_2 foo bar --network` Then STDOUT should be: """ Success: Updated transient 'my_key_2'. """ - When I try `wp transient patch delete unknown_key foo --network` - Then STDERR should be: + When I run `wp transient get my_key_2 --format=json --network` + Then STDOUT should be: + """ + {"foo":[]} + """ + + When I run `wp transient patch delete my_key_2 foo --network` + Then STDOUT should be: + """ + Success: Updated transient 'my_key_2'. + """ + + When I run `wp transient get my_key_2 --format=json --network` + Then STDOUT should be: """ - Error: No data exists for key "foo" + [] """ From 7d3a483902406961b7a169410fdd6dbd2e30c68b Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 11 Dec 2023 12:20:26 +0100 Subject: [PATCH 20/26] Add test cases for invalid keys --- features/transient-patch.feature | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/features/transient-patch.feature b/features/transient-patch.feature index 4d1f3f76..f44628db 100644 --- a/features/transient-patch.feature +++ b/features/transient-patch.feature @@ -53,6 +53,12 @@ Feature: Patch command available for the transient cache {"foo":{"bar":"baz","fuz":"biz"}} """ + When I try `wp transient patch insert unknown_key foo bar` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + Scenario: Nested values from transient can be updated at any depth. Given a WP install And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` @@ -106,6 +112,12 @@ Feature: Patch command available for the transient cache {"foo":{"bar":"biz"}} """ + When I try `wp transient patch update unknown_key foo bar` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + Scenario: Nested values from transient can be deleted at any depth. Given a WP install And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` @@ -147,6 +159,12 @@ Feature: Patch command available for the transient cache [] """ + When I try `wp transient patch delete unknown_key foo` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + Scenario: Nested values from site transient can be inserted at any depth. Given a WP multisite install And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` @@ -200,6 +218,12 @@ Feature: Patch command available for the transient cache {"foo":{"bar":"baz","fuz":"biz"}} """ + When I try `wp transient patch insert unknown_key foo bar --network` + Then STDERR should be: + """ + Error: Cannot create key "foo" on data type boolean + """ + Scenario: Nested values from site transient can be updated at any depth. Given a WP multisite install And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` @@ -253,6 +277,12 @@ Feature: Patch command available for the transient cache {"foo":{"bar":"biz"}} """ + When I try `wp transient patch update unknown_key foo bar --network` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ + Scenario: Nested values from site transient can be deleted at any depth. Given a WP multisite install And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` @@ -293,3 +323,9 @@ Feature: Patch command available for the transient cache """ [] """ + + When I try `wp transient patch delete unknown_key foo --network` + Then STDERR should be: + """ + Error: No data exists for key "foo" + """ From d061301b7d0cc8aef6647b11ea2389d1aae0934a Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 11 Dec 2023 12:23:56 +0100 Subject: [PATCH 21/26] Refactor `pluck` feature tests to use `wp eval` to set the transient --- features/transient-pluck.feature | 48 +++++++++++++++----------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/features/transient-pluck.feature b/features/transient-pluck.feature index b10787d5..61be9ade 100644 --- a/features/transient-pluck.feature +++ b/features/transient-pluck.feature @@ -2,16 +2,8 @@ Feature: Pluck command available for the transient cache Scenario: Nested values from transient can be retrieved at any depth. Given a WP install - And a wp-content/mu-plugins/test-harness.php file: - """php - 'bar'] ); - set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] ); - }; - - WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); - """ + And I run `wp eval "set_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` When I run `wp transient pluck my_key foo` Then STDOUT should be: @@ -25,27 +17,31 @@ Feature: Pluck command available for the transient cache baz """ + When I try `wp transient pluck unknown_key foo` + Then STDERR should be: + """ + Warning: Transient with key "unknown_key" is not set. + """ + Scenario: Nested values from site transient can be retrieved at any depth. Given a WP multisite install - And I run `wp site create --slug=foo` - And a wp-content/mu-plugins/test-harness.php file: - """php - 'bar'] ); - }; + And I run `wp eval "set_site_transient( 'my_key', ['foo' => 'bar'] );"` + And I run `wp eval "set_site_transient( 'my_key_2', ['foo' => ['bar' => 'baz']] );"` - WP_CLI::add_hook( 'before_invoke:transient pluck', $set_foo ); + When I run `wp transient pluck my_key foo --network` + Then STDOUT should be: + """ + bar """ - When I run `wp transient pluck my_key foo --network` + When I run `wp transient pluck my_key_2 foo bar --network` Then STDOUT should be: - """ - bar - """ + """ + baz + """ - When I try `wp transient pluck my_key foo` + When I try `wp transient pluck unknown_key foo --network` Then STDERR should be: - """ - Warning: Transient with key "my_key" is not set. - """ + """ + Warning: Transient with key "unknown_key" is not set. + """ From cf568fb4f3b5d8fcd1216e4edfc67b7b1492da3e Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Tue, 12 Dec 2023 09:21:44 +0100 Subject: [PATCH 22/26] new feature test for calling cache pluck command with invalid key --- features/cache-pluck.feature | 7 +++++++ src/Cache_Command.php | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/features/cache-pluck.feature b/features/cache-pluck.feature index 82583ee5..c5d08288 100644 --- a/features/cache-pluck.feature +++ b/features/cache-pluck.feature @@ -31,3 +31,10 @@ Feature: Pluck command available for the object cache """ bar_custom """ + + When I try `wp cache pluck unknown_key test` + Then STDERR should be: + """ + Warning: No object found for the key "unknown_key" in group "default" + """ + diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 751258bb..6205959b 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -444,7 +444,8 @@ public function pluck( $args, $assoc_args ) { $value = wp_cache_get( $key, $group ); if ( false === $value ) { - WP_CLI::halt( 1 ); + WP_CLI::warning( 'No object found for the key "' . $key . '" in group "' . $group . '"' ); + exit; } $key_path = array_map( From 3fa7fe1c34851ca458167d877812757d8496fd3b Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Fri, 26 Apr 2024 16:59:36 +0200 Subject: [PATCH 23/26] add the new commands to the `composer.json` --- composer.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 13878246..289ac5bc 100644 --- a/composer.json +++ b/composer.json @@ -40,6 +40,8 @@ "cache flush-group", "cache get", "cache incr", + "cache patch", + "cache pluck", "cache replace", "cache set", "cache supports", @@ -47,9 +49,11 @@ "transient", "transient delete", "transient get", + "transient list", + "transient patch", + "transient pluck", "transient set", - "transient type", - "transient list" + "transient type" ] }, "autoload": { From 119c9911c7c6207a1ea7c029ffa6eb9d46c7fb96 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 29 Apr 2024 14:36:00 +0200 Subject: [PATCH 24/26] use string interpolation for building message Co-authored-by: Pascal Birchler --- src/Cache_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 6205959b..ca245cff 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -444,7 +444,7 @@ public function pluck( $args, $assoc_args ) { $value = wp_cache_get( $key, $group ); if ( false === $value ) { - WP_CLI::warning( 'No object found for the key "' . $key . '" in group "' . $group . '"' ); + WP_CLI::warning( "No object found for the key '$key' in group '$group'" ); exit; } From 2d171850344729ae92d9ac1c62a73d194e6831f2 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 29 Apr 2024 14:29:33 +0200 Subject: [PATCH 25/26] explicitly call update methods for clearer code Co-authored-by: Pascal Birchler --- src/Cache_Command.php | 9 ++++++--- src/Transient_Command.php | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index ca245cff..b56eda0f 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -568,10 +568,13 @@ function ( $key ) { if ( $patched_value === $old_value ) { WP_CLI::success( "Value passed for cache key '$key' is unchanged." ); - } elseif ( wp_cache_set( $key, $patched_value, $group, $expiration ) ) { - WP_CLI::success( "Updated cache key '$key'." ); } else { - WP_CLI::error( "Could not update cache key '$key'." ); + $success = wp_cache_set( $key, $patched_value, $group, $expiration ); + if ( $success ) { + WP_CLI::success( "Updated cache key '$key'." ); + } else { + WP_CLI::error( "Could not update cache key '$key'." ); + } } } } diff --git a/src/Transient_Command.php b/src/Transient_Command.php index 474c1b19..9166935a 100644 --- a/src/Transient_Command.php +++ b/src/Transient_Command.php @@ -560,10 +560,13 @@ function ( $key ) { if ( $patched_value === $old_value ) { WP_CLI::success( "Value passed for transient '$key' is unchanged." ); - } elseif ( $write_func( $key, $patched_value, $expiration ) ) { - WP_CLI::success( "Updated transient '$key'." ); } else { - WP_CLI::error( "Could not update transient '$key'." ); + $success = $write_func( $key, $patched_value, $expiration ); + if ( $success ) { + WP_CLI::success( "Updated transient '$key'." ); + } else { + WP_CLI::error( "Could not update transient '$key'." ); + } } } From 9eca4d917e88c9b5a210d17c6ad178a8a08d0193 Mon Sep 17 00:00:00 2001 From: Clement Boirie Date: Mon, 29 Apr 2024 20:34:24 +0200 Subject: [PATCH 26/26] fix tests --- features/cache-pluck.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/cache-pluck.feature b/features/cache-pluck.feature index c5d08288..bec68e34 100644 --- a/features/cache-pluck.feature +++ b/features/cache-pluck.feature @@ -35,6 +35,6 @@ Feature: Pluck command available for the object cache When I try `wp cache pluck unknown_key test` Then STDERR should be: """ - Warning: No object found for the key "unknown_key" in group "default" + Warning: No object found for the key 'unknown_key' in group 'default' """