OSDN Git Service

Move recursive search-replace function to Utils and add unit tests
authorWill Anderson <will@itsananderson.com>
Sat, 11 Jan 2014 07:01:50 +0000 (23:01 -0800)
committerWill Anderson <will@itsananderson.com>
Sat, 11 Jan 2014 07:01:50 +0000 (23:01 -0800)
php/commands/search-replace.php
php/utils.php
tests/test-search-replace.php [new file with mode: 0644]

index 61615ef..b8d219d 100644 (file)
@@ -127,7 +127,7 @@ class Search_Replace_Command extends WP_CLI_Command {
                        if ( '' === $row->$col )
                                continue;
 
-                       $value = self::recursive_unserialize_replace( $old, $new, $row->$col, false, $recurse_objects );
+                       $value = WP_CLI\Utils\recursive_unserialize_replace( $old, $new, $row->$col, false, $recurse_objects );
 
                        if ( $dry_run ) {
                                if ( $value != $row->$col )
@@ -143,84 +143,6 @@ class Search_Replace_Command extends WP_CLI_Command {
                return $count;
        }
 
-       /**
-        * Take a serialised array and unserialise it replacing elements as needed and
-        * unserialising any subordinate arrays and performing the replace on those too.
-        * Ignores any serialized objects unless $recurse_objects is set to true.
-        *
-        * Initial code from https://github.com/interconnectit/Search-Replace-DB
-        *
-        * @param string       $from            String we're looking to replace.
-        * @param string       $to              What we want it to be replaced with
-        * @param array|string $data            Used to pass any subordinate arrays back to in.
-        * @param bool         $serialised      Does the array passed via $data need serialising.
-        * @param bool         $recurse_objects Should objects be recursively replaced.
-        * @param int          $max_recursion   How many levels to recurse into the data, if $recurse_objects is set to true.
-        * @param int          $recursion_level Current recursion depth within the original data.
-        * @param array        $visited_data    Data that has been seen in previous recursion iterations.
-        *
-        * @return array    The original array with all elements replaced as needed.
-        */
-       private static function recursive_unserialize_replace( $from = '', $to = '', &$data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) {
-
-               // some unseriliased data cannot be re-serialised eg. SimpleXMLElements
-               try {
-
-                       if ( $recurse_objects ) {
-
-                               // If no maximum recursion level is set, use the XDebug limit if it exists
-                               if ( -1 == $max_recursion ) {
-                                       // Get the XDebug nesting level. Will be zero (no limit) if no value is set
-                                       $max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) );
-                               }
-
-                               // If we've reached the maximum recursion level, short circuit
-                               if ( $max_recursion != 0 && $recursion_level >= $max_recursion ) {
-                                       WP_CLI::warning("Maximum recursion level of $max_recursion reached");
-                                       return $data;
-                               }
-
-                               if ( ( is_array( $data ) || is_object( $data ) ) ) {
-                                       // If we've seen this exact object or array before, short circuit
-                                       if ( in_array( $data, $visited_data, true ) ) {
-                                               return $data; // Avoid infinite loops when there's a cycle
-                                       }
-                                       // Add this data to the list of
-                                       $visited_data[] = $data;
-                               }
-                       }
-
-                       if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
-                               $data = self::recursive_unserialize_replace( $from, $to, $unserialized, true, $recurse_objects, $max_recursion, $recursion_level + 1 );
-                       }
-
-                       elseif ( is_array( $data ) ) {
-                               $keys = array_keys( $data );
-                               foreach ( $keys as $key ) {
-                                       $data[ $key ]= self::recursive_unserialize_replace( $from, $to, $data[$key], false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data );
-                               }
-                       }
-
-                       elseif ( $recurse_objects && is_object( $data ) ) {
-                               foreach ( $data as $key => $value ) {
-                                       $data->$key = self::recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data );
-                               }
-                       }
-
-                       else if ( is_string( $data ) ) {
-                               $data = str_replace( $from, $to, $data );
-                       }
-
-                       if ( $serialised )
-                               return serialize( $data );
-
-               } catch( Exception $error ) {
-
-               }
-
-               return $data;
-       }
-
        private static function get_columns( $table ) {
                global $wpdb;
 
index 1972c25..eba6a39 100644 (file)
@@ -375,3 +375,81 @@ function parse_url( $url ) {
        return $url_parts;
 }
 
+
+/**
+ * Take a serialised array and unserialise it replacing elements as needed and
+ * unserialising any subordinate arrays and performing the replace on those too.
+ * Ignores any serialized objects unless $recurse_objects is set to true.
+ *
+ * Initial code from https://github.com/interconnectit/Search-Replace-DB
+ *
+ * @param string       $from            String we're looking to replace.
+ * @param string       $to              What we want it to be replaced with
+ * @param array|string $data            Used to pass any subordinate arrays back to in.
+ * @param bool         $serialised      Does the array passed via $data need serialising.
+ * @param bool         $recurse_objects Should objects be recursively replaced.
+ * @param int          $max_recursion   How many levels to recurse into the data, if $recurse_objects is set to true.
+ * @param int          $recursion_level Current recursion depth within the original data.
+ * @param array        $visited_data    Data that has been seen in previous recursion iterations.
+ *
+ * @return array    The original array with all elements replaced as needed.
+ */
+function recursive_unserialize_replace( $from = '', $to = '', &$data = '', $serialised = false, $recurse_objects = false, $max_recursion = -1, $recursion_level = 0, &$visited_data = array() ) {
+
+       // some unseriliased data cannot be re-serialised eg. SimpleXMLElements
+       try {
+
+               if ( $recurse_objects ) {
+
+                       // If no maximum recursion level is set, use the XDebug limit if it exists
+                       if ( -1 == $max_recursion ) {
+                               // Get the XDebug nesting level. Will be zero (no limit) if no value is set
+                               $max_recursion = intval( ini_get( 'xdebug.max_nesting_level' ) );
+                       }
+
+                       // If we've reached the maximum recursion level, short circuit
+                       if ( $max_recursion != 0 && $recursion_level >= $max_recursion ) {
+                               return $data;
+                       }
+
+                       if ( ( is_array( $data ) || is_object( $data ) ) ) {
+                               // If we've seen this exact object or array before, short circuit
+                               if ( in_array( $data, $visited_data, true ) ) {
+                                       return $data; // Avoid infinite loops when there's a cycle
+                               }
+                               // Add this data to the list of
+                               $visited_data[] = $data;
+                       }
+               }
+
+               if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
+                       $data = recursive_unserialize_replace( $from, $to, $unserialized, true, $recurse_objects, $max_recursion, $recursion_level + 1 );
+               }
+
+               elseif ( is_array( $data ) ) {
+                       $keys = array_keys( $data );
+                       foreach ( $keys as $key ) {
+                               $data[ $key ]= recursive_unserialize_replace( $from, $to, $data[$key], false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data );
+                       }
+               }
+
+               elseif ( $recurse_objects && is_object( $data ) ) {
+                       foreach ( $data as $key => $value ) {
+                               $data->$key = recursive_unserialize_replace( $from, $to, $value, false, $recurse_objects, $max_recursion, $recursion_level + 1, $visited_data );
+                       }
+               }
+
+               else if ( is_string( $data ) ) {
+                       $data = str_replace( $from, $to, $data );
+               }
+
+               if ( $serialised )
+                       return serialize( $data );
+
+       } catch( Exception $error ) {
+
+       }
+
+       return $data;
+}
+
diff --git a/tests/test-search-replace.php b/tests/test-search-replace.php
new file mode 100644 (file)
index 0000000..696d487
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+
+require_once getcwd() . '/php/class-wp-cli.php';
+require_once getcwd() . '/php/class-wp-cli-command.php';
+require_once getcwd() . '/php/commands/search-replace.php';
+
+class UnserializeReplaceTest extends PHPUnit_Framework_TestCase {
+
+       function testReplaceString() {
+               $orig = 'foo';
+               $replacement = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $orig );
+               $this->assertEquals( 'bar', $replacement );
+       }
+
+       function testPrivateConstructor() {
+               $old_obj = ClassWithPrivateConstructor::get_instance();
+
+               $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_obj, false, true );
+               $this->assertEquals( 'bar', $new_obj->prop );
+       }
+
+       function testObjectLoop() {
+               $old_object = new stdClass();
+               $old_object->prop = 'foo';
+               $old_object->self = $old_object;
+
+               $new_obj = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true );
+               $this->assertEquals( 'bar', $new_obj->prop );
+       }
+
+       function testArrayLoop() {
+               $old_array = array( 'prop' => 'foo' );
+               $old_array['self'] = &$old_array;
+
+               $new_array = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true );
+               $this->assertEquals( 'bar', $new_array['prop'] );
+       }
+
+       function testMixedObjectArrayLoop() {
+               $old_object = new stdClass();
+               $old_object->prop = 'foo';
+               $old_object->array = array('prop' => 'foo');
+               $old_object->array['object'] = $old_object;
+
+               $new_object = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_object, false, true );
+               $this->assertEquals( 'bar', $new_object->prop );
+               $this->assertEquals( 'bar', $new_object->array['prop']);
+       }
+
+       function testMixedArrayObjectLoop() {
+               $old_array = array( 'prop' => 'foo', 'object' => new stdClass() );
+               $old_array['object']->prop = 'foo';
+               $old_array['object']->array = &$old_array;
+
+               $new_array = WP_CLI\Utils\recursive_unserialize_replace( 'foo', 'bar', $old_array, false, true );
+               $this->assertEquals( 'bar', $new_array['prop'] );
+               $this->assertEquals( 'bar', $new_array['object']->prop);
+       }
+}
+
+
+class ClassWithPrivateConstructor {
+
+       public $prop = 'foo';
+
+       private function __construct() {}
+
+       public static function get_instance() {
+               return new self;
+       }
+}