Skip to content
This repository
Browse code

Add remove() and insert()

Also add support for multi insert and multi remove.
  • Loading branch information...
commit 3d8a955043936e3604e381b728c0aa1deec84b02 1 parent 6b69ed2
Mark Story authored January 26, 2012
98  lib/Cake/Test/Case/Utility/Set2Test.php
@@ -974,21 +974,107 @@ public function testSortWithOutOfOrderKeys() {
974 974
 		$this->assertEquals($expected, $result);
975 975
 	}
976 976
 
  977
+/**
  978
+ * Test insert()
  979
+ *
  980
+ * @return void
  981
+ */
  982
+	public function testInsertSimple() {
  983
+		$a = array(
  984
+			'pages' => array('name' => 'page')
  985
+		);
  986
+		$result = Set2::insert($a, 'files', array('name' => 'files'));
  987
+		$expected = array(
  988
+			'pages' => array('name' => 'page'),
  989
+			'files' => array('name' => 'files')
  990
+		);
  991
+		$this->assertEquals($expected, $result);
  992
+
  993
+		$a = array(
  994
+			'pages' => array('name' => 'page')
  995
+		);
  996
+		$result = Set2::insert($a, 'pages.name', array());
  997
+		$expected = array(
  998
+			'pages' => array('name' => array()),
  999
+		);
  1000
+		$this->assertEquals($expected, $result);
  1001
+	}
977 1002
 
978 1003
 /**
979  
- * Test remove()
  1004
+ * Test inserting with multiple values.
  1005
+ *
  1006
+ * @return void
  1007
+ */
  1008
+	public function testInsertMulti() {
  1009
+		$data = self::articleData();
  1010
+
  1011
+		$result = Set2::insert($data, '{n}.Article.insert', 'value');
  1012
+		$this->assertEquals('value', $result[0]['Article']['insert']);
  1013
+		$this->assertEquals('value', $result[1]['Article']['insert']);
  1014
+
  1015
+		$result = Set2::insert($data, '{n}.Comment.{n}.insert', 'value');
  1016
+		$this->assertEquals('value', $result[0]['Comment'][0]['insert']);
  1017
+		$this->assertEquals('value', $result[0]['Comment'][1]['insert']);
  1018
+	}
  1019
+
  1020
+/**
  1021
+ * Test remove() method.
980 1022
  *
981 1023
  * @return void
982 1024
  */
983 1025
 	public function testRemove() {
  1026
+		$a = array(
  1027
+			'pages' => array('name' => 'page'),
  1028
+			'files' => array('name' => 'files')
  1029
+		);
  1030
+
  1031
+		$result = Set2::remove($a, 'files');
  1032
+		$expected = array(
  1033
+			'pages' => array('name' => 'page')
  1034
+		);
  1035
+		$this->assertEquals($expected, $result);
  1036
+
  1037
+		$a = array(
  1038
+			'pages' => array(
  1039
+				0 => array('name' => 'main'),
  1040
+				1 => array(
  1041
+					'name' => 'about',
  1042
+					'vars' => array('title' => 'page title')
  1043
+				)
  1044
+			)
  1045
+		);
  1046
+
  1047
+		$result = Set2::remove($a, 'pages.1.vars');
  1048
+		$expected = array(
  1049
+			'pages' => array(
  1050
+				0 => array('name' => 'main'),
  1051
+				1 => array('name' => 'about')
  1052
+			)
  1053
+		);
  1054
+		$this->assertEquals($expected, $result);
  1055
+
  1056
+		$result = Set2::remove($a, 'pages.2.vars');
  1057
+		$expected = $a;
  1058
+		$this->assertEquals($expected, $result);
  1059
+	}
  1060
+
  1061
+/**
  1062
+ * Test removing multiple values.
  1063
+ *
  1064
+ * @return void
  1065
+ */
  1066
+	public function testRemoveMulti() {
984 1067
 		$data = self::articleData();
985 1068
 
986  
-		$result = Set2::insert($data, '{n}.Article', array('test'));
987  
-		debug($result);
  1069
+		$result = Set2::remove($data, '{n}.Article.title');
  1070
+		$this->assertFalse(isset($result[0]['Article']['title']));
  1071
+		$this->assertFalse(isset($result[1]['Article']['title']));
988 1072
 
989  
-		$result = Set2::remove($data, '{n}.Article');
990  
-		debug($result);
991  
-		$this->assertFalse(isset($data[0]['Article']));
  1073
+		$result = Set2::remove($data, '{n}.Article.{s}');
  1074
+		$this->assertFalse(isset($result[0]['Article']['id']));
  1075
+		$this->assertFalse(isset($result[0]['Article']['user_id']));
  1076
+		$this->assertFalse(isset($result[0]['Article']['title']));
  1077
+		$this->assertFalse(isset($result[0]['Article']['body']));
992 1078
 	}
993 1079
 
994 1080
 }
122  lib/Cake/Utility/Set2.php
@@ -94,23 +94,6 @@ public static function extract(array $data, $path) {
94 94
 			return (array) self::get($data, $path);
95 95
 		}
96 96
 
97  
-		return self::_traverse($data, $path, function ($value) {
98  
-			return $value;
99  
-		});
100  
-	}
101  
-
102  
-/**
103  
- * Traverses $data for $path.  $callback is called for each terminal element.
104  
- * The results of all the callbacks are returned.
105  
- *
106  
- * @param array $data The data to traverse.
107  
- * @param string $path The set path to walk.
108  
- * @param callable $callback to call on the result set.
109  
- * @return array Results of the callback mapped over the leaf nodes of the path expression.
110  
- */
111  
-	protected static function _traverse(array &$data, $path, $callback) {
112  
-		$result = array();
113  
-
114 97
 		if (strpos('[', $path) === false) {
115 98
 			$tokens = explode('.', $path);
116 99
 		} else {
@@ -150,12 +133,10 @@ protected static function _traverse(array &$data, $path, $callback) {
150 133
 				}
151 134
 				$next = $filter;
152 135
 			}
153  
-
154 136
 			$context = array($_key => $next);
155 137
 
156 138
 		} while (!empty($tokens));
157  
-
158  
-		return array_map($callback, $context[$_key]);
  139
+		return $context[$_key];
159 140
 	}
160 141
 
161 142
 /**
@@ -234,16 +215,58 @@ protected static function _matches(array $data, $selector) {
234 215
 		return true;
235 216
 	}
236 217
 
  218
+/**
  219
+ * Insert $values into an array with the given $path.
  220
+ *
  221
+ * @param array $data The data to insert into.
  222
+ * @param string $path The path to insert at.
  223
+ * @param mixed $values The values to insert.
  224
+ * @return array The data with $values inserted.
  225
+ */
237 226
 	public static function insert(array $data, $path, $values = null) {
238  
-		if (empty($path)) {
239  
-			return $data;
  227
+		$tokens = explode('.', $path);
  228
+		if (strpos($path, '{') === false) {
  229
+			return self::_simpleInsert($data, $tokens, $values);
  230
+		}
  231
+
  232
+		$token = array_shift($tokens);
  233
+		$nextPath = implode('.', $tokens);
  234
+		foreach ($data as $k => $v) {
  235
+			if (self::_matchToken($k, $token)) {
  236
+				$data[$k] = self::insert($v, $nextPath, $values);
  237
+			}
240 238
 		}
  239
+		return $data;
  240
+	}
241 241
 
242  
-		$result = self::_traverse($data, $path, function (&$value) use ($values) {
243  
-			$value['test'] = $values;
244  
-			return $value;
245  
-		});
  242
+/**
  243
+ * Inserts values into simple paths.
  244
+ *
  245
+ * @param array $data Data to insert into.
  246
+ * @param string $path The path to insert into.
  247
+ * @param mixed $values The values to insert.
  248
+ * @return array Data with values inserted at $path.
  249
+ */
  250
+	protected static function _simpleInsert($data, $path, $values) {
  251
+		$_list =& $data;
246 252
 
  253
+		$count = count($path);
  254
+		foreach ($path as $i => $key) {
  255
+			if (is_numeric($key) && intval($key) > 0 || $key === '0') {
  256
+				$key = intval($key);
  257
+			}
  258
+			if ($i === $count - 1 && is_array($_list)) {
  259
+				$_list[$key] = $values;
  260
+			} else {
  261
+				if (!isset($_list[$key])) {
  262
+					$_list[$key] = array();
  263
+				}
  264
+				$_list =& $_list[$key];
  265
+			}
  266
+			if (!is_array($_list)) {
  267
+				return array();
  268
+			}
  269
+		}
247 270
 		return $data;
248 271
 	}
249 272
 
@@ -255,13 +278,54 @@ public static function insert(array $data, $path, $values = null) {
255 278
  * @return array The modified array.
256 279
  */
257 280
 	public static function remove(array $data, $path) {
  281
+		$tokens = explode('.', $path);
  282
+		if (strpos($path, '{') === false) {
  283
+			return self::_simpleRemove($data, $path);
  284
+		}
  285
+
  286
+		$token = array_shift($tokens);
  287
+		$nextPath = implode('.', $tokens);
  288
+		foreach ($data as $k => $v) {
  289
+			$match = self::_matchToken($k, $token);
  290
+			if ($match && is_array($v)) {
  291
+				$data[$k] = self::remove($v, $nextPath);
  292
+			} elseif ($match) {
  293
+				unset($data[$k]);
  294
+			}
  295
+		}
  296
+		return $data;
  297
+	}
  298
+
  299
+/**
  300
+ * Remove values along a simple path.
  301
+ * 
  302
+ * @param array $data Array to operate on.
  303
+ * @param string $path The path to remove.
  304
+ * @return array Data with value removed.
  305
+ */
  306
+	protected static function _simpleRemove($data, $path) {
258 307
 		if (empty($path)) {
259 308
 			return $data;
260 309
 		}
  310
+		if (!is_array($path)) {
  311
+			$path = explode('.', $path);
  312
+		}
  313
+		$_list =& $data;
261 314
 
262  
-		return self::_traverse($data, $path, function ($value) {
263  
-			return $value;
264  
-		});
  315
+		foreach ($path as $i => $key) {
  316
+			if (is_numeric($key) && intval($key) > 0 || $key === '0') {
  317
+				$key = intval($key);
  318
+			}
  319
+			if ($i === count($path) - 1) {
  320
+				unset($_list[$key]);
  321
+			} else {
  322
+				if (!isset($_list[$key])) {
  323
+					return $data;
  324
+				}
  325
+				$_list =& $_list[$key];
  326
+			}
  327
+		}
  328
+		return $data;
265 329
 	}
266 330
 
267 331
 	public static function combine(array $data, $keyPath, $valuePath = null) {

0 notes on commit 3d8a955

Please sign in to comment.
Something went wrong with that request. Please try again.