Browse Source

Re-implementing Collection::insert using a special iterator class for
this job. Using Multiple iterator had too many shortcomings to actually
be useful.

Jose Lorenzo Rodriguez 12 years ago
parent
commit
f91bec12ce

+ 2 - 20
src/Collection/CollectionTrait.php

@@ -22,7 +22,7 @@ use Cake\Collection\Iterator\FilterIterator;
 use Cake\Collection\Iterator\MapReduce;
 use Cake\Collection\Iterator\ReplaceIterator;
 use Cake\Collection\Iterator\SortIterator;
-use Cake\Collection\Iterator\SyncIterator;
+use Cake\Collection\Iterator\InsertIterator;
 use LimitIterator;
 
 /**
@@ -752,25 +752,7 @@ trait CollectionTrait {
 	}
 
 	public function insert($path, $values) {
-		$iterator = new SyncIterator($this, new Collection($values));
-		$collection = new Collection($iterator);
-		$path = explode('.', $path);
-		$target = array_pop($path);
-
-		return $collection->map(function($values) use ($path, $target) {
-			list($row, $insert) = $values;
-			$pointer =& $row;
-
-			foreach ($path as $step) {
-				if (!isset($pointer[$step])) {
-					return $row;
-				}
-				$pointer =& $pointer[$step];
-			}
-
-			$pointer[$target] = $insert;
-			return $row;
-		});
+		return new InsertIterator($this, $path, $values);
 	}
 
 /**

+ 132 - 0
src/Collection/Iterator/InsertIterator.php

@@ -0,0 +1,132 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         CakePHP(tm) v 3.0.0
+ * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+namespace Cake\Collection\Iterator;
+
+use Cake\Collection\Collection;
+
+/**
+ * This iterator will insert values into a property of each of the records returned.
+ * The values to be inserted come out of another traversal object. This is useful
+ * when you have two separate collections and want to merge them toghether by placing
+ * each of the values from one collection into a property inside the other collection.
+ */
+class InsertIterator extends Collection {
+
+/**
+ * The collection from which to extract the values to be inserted
+ *
+ * @var \Cake\Collection\Collection
+ */
+	protected $_values;
+
+/**
+ * Holds whether the values colelction is still valid. (has more records)
+ *
+ * @var boolean
+ */
+	protected $_validValues = true;
+
+/**
+ * An array containing each of the properties to be traversed to reach the
+ * point where the values should be inserted.
+ *
+ * @var array
+ */
+	protected $_path;
+
+/**
+ * The property name to which values will be assigned
+ *
+ * @var string
+ */
+	protected $_target;
+
+/**
+ * Constructs a new collection that will dynamically add properties to it out of
+ * the values found in $values.
+ *
+ * @param array|\Traversable $into The target collection to which the values will
+ * be inserted at the specified path.
+ * @param string $path A dot separated list of properties that need to be traversed
+ * to insert the value into the target collection.
+ * @param array|\Traversable $values The source collection from which the values will
+ * be inserted at the specified path.
+ */
+	public function __construct($into, $path, $values) {
+		parent::__construct($into);
+
+		if (!($values instanceof Collection)) {
+			$values = new Collection($values);
+		}
+
+		$path = explode('.', $path);
+		$target = array_pop($path);
+		$this->_path = $path;
+		$this->_target = $target;
+		$this->_values = $values;
+	}
+
+/**
+ * Advances the cursor to the next record
+ *
+ * @return void
+ */
+	public function next() {
+		parent::next();
+		if ($this->_validValues) {
+			$this->_values->next();
+		}
+		$this->_validValues = $this->_values->valid();
+	}
+
+/**
+ * Returns the current element in the target collection after inserting
+ * the value from the source collection into the specified path.
+ *
+ * @return void
+ */
+
+	public function current() {
+		$row = parent::current();
+
+		if (!$this->_validValues) {
+			return $row;
+		}
+
+		$pointer =& $row;
+		foreach ($this->_path as $step) {
+			if (!isset($pointer[$step])) {
+				return $row;
+			}
+			$pointer =& $pointer[$step];
+		}
+
+		$pointer[$this->_target] = $this->_values->current();
+		return $row;
+	}
+
+/**
+ * Resets the collection pointer.
+ *
+ * @return void
+ */
+	public function rewind() {
+		parent::rewind();
+		$this->_values->rewind();
+		$this->_validValues = $this->_values->valid();
+	}
+
+}
+

+ 0 - 34
src/Collection/Iterator/SyncIterator.php

@@ -1,34 +0,0 @@
-<?php
-/**
- * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link          http://cakephp.org CakePHP(tm) Project
- * @since         CakePHP(tm) v 3.0.0
- * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-namespace Cake\Collection\Iterator;
-
-use Iterator;
-use MultipleIterator;
-
-class SyncIterator extends MultipleIterator {
-
-	public function __construct(Iterator $left, Iterator $right) {
-		$flags = static::MIT_NEED_ANY|static::MIT_KEYS_NUMERIC;
-		parent::__construct($flags);
-		$this->attachIterator($left);
-		$this->attachIterator($right);
-	}
-
-	public function key() {
-		$key = parent::key();
-		return $key[0];
-	}
-
-}