diff --git a/Cake/ORM/BufferedResultSet.php b/Cake/ORM/BufferedResultSet.php index 25aec18459c..3ac6f58f4ea 100644 --- a/Cake/ORM/BufferedResultSet.php +++ b/Cake/ORM/BufferedResultSet.php @@ -1,7 +1,5 @@ assertFalse($collection->contains('2')); } +/** + * Tests map + * + * @return void + */ + public function testMap() { + $items = ['a' => 1, 'b' => 2, 'c' => 3]; + $collection = new Collection($items); + $map = $collection->map(function($v, $k, $it) use ($collection) { + $this->assertSame($collection, $it); + return $v * $v; + }); + $this->assertInstanceOf('\Cake\Utility\Iterator\ReplaceIterator', $map); + $this->assertEquals(['a' => 1, 'b' => 4, 'c' => 9], iterator_to_array($map)); + } } diff --git a/Cake/Test/TestCase/Utility/Iterator/ReplaceIteratorTest.php b/Cake/Test/TestCase/Utility/Iterator/ReplaceIteratorTest.php new file mode 100644 index 00000000000..05dfb7e3336 --- /dev/null +++ b/Cake/Test/TestCase/Utility/Iterator/ReplaceIteratorTest.php @@ -0,0 +1,51 @@ +getMock('stdClass', ['__invoke']); + $callable->expects($this->at(0)) + ->method('__invoke') + ->with(1, 0, $items) + ->will($this->returnValue(1)); + $callable->expects($this->at(1)) + ->method('__invoke') + ->with(2, 1, $items) + ->will($this->returnValue(4)); + $callable->expects($this->at(2)) + ->method('__invoke') + ->with(3, 2, $items) + ->will($this->returnValue(9)); + + $map = new ReplaceIterator($items, $callable); + $this->assertEquals([1, 4, 9], iterator_to_array($map)); + } + +} diff --git a/Cake/Utility/Collection.php b/Cake/Utility/Collection.php index 6ec80466b7e..8e8df90a4a1 100644 --- a/Cake/Utility/Collection.php +++ b/Cake/Utility/Collection.php @@ -16,6 +16,7 @@ use ArrayIterator; use Cake\Utility\Iterator\FilterIterator; +use Cake\Utility\Iterator\ReplaceIterator; use InvalidArgumentException; use IteratorIterator; @@ -191,10 +192,43 @@ public function contains($value) { return false; } +/** + * Creates an iterator from another iterator that will modify each of the values + * by converting them using a callback function. + */ + +/** + * Returns another collection after modifying each of the values in this one using + * the provided callable. + * + * Each time the callback is executed it will receive the value of the element + * in the current iteration, the key of the element and this collection as + * arguments, in that order. + * + * ##Example: + * + * Getting a collection of booleans where true indicates if a person is female: + * + * {{{ + * $collection = (new Collection($people))->filter(function($person, $key) { + * return $person->sex === 'female'; + * }); + * }}} + * + * @param callable $c the method that will receive each of the elements and + * returns the new value for the key that is being iterated + * @return \Cake\Utility\Iterator\ReplaceIterator + */ + public function map(callable $c) { + return new ReplaceIterator($this, $c); + } + public function mapReduce(callable $map, callable $reduce) { } + public function extract($property) { + } public function max() { diff --git a/Cake/Utility/Iterator/FilterIterator.php b/Cake/Utility/Iterator/FilterIterator.php index 6ee1dc6f5c9..b9ed4484636 100644 --- a/Cake/Utility/Iterator/FilterIterator.php +++ b/Cake/Utility/Iterator/FilterIterator.php @@ -19,7 +19,7 @@ use Iterator; /** - * Create a filtered iterator from another iterator. The filtering is done by + * Creates a filtered iterator from another iterator. The filtering is done by * passing a callback function to each of the elements and taking them out if * it does not return true. */ @@ -33,6 +33,8 @@ class FilterIterator extends Collection { * in the current iteration, the key of the element and the passed $items iterator * as arguments, in that order. * + * @param Iterator $items the items to be filtered + * @param callable $callback * @return void */ public function __construct(Iterator $items, callable $callback) { diff --git a/Cake/Utility/Iterator/ReplaceIterator.php b/Cake/Utility/Iterator/ReplaceIterator.php new file mode 100644 index 00000000000..582e06f6776 --- /dev/null +++ b/Cake/Utility/Iterator/ReplaceIterator.php @@ -0,0 +1,60 @@ +_callback = $callback; + parent::__construct($items); + } + +/** + * Returns the value returned by the callback after passing the current value in + * the iteration + * + * @return mixed + */ + public function current() { + $callback = $this->_callback; + return $callback(parent::current(), $this->key(), $this->getInnerIterator()); + } + +}