Browse Source

Initial code for implementing Collection::unfold()

Unfolding can be used to yield more items in a collection than those
originally set into it.
Jose Lorenzo Rodriguez 11 years ago
parent
commit
4a2a76c5f2

+ 9 - 0
src/Collection/CollectionTrait.php

@@ -27,7 +27,9 @@ use Cake\Collection\Iterator\ReplaceIterator;
 use Cake\Collection\Iterator\SortIterator;
 use Cake\Collection\Iterator\StoppableIterator;
 use Cake\Collection\Iterator\TreeIterator;
+use Cake\Collection\Iterator\UnfoldIterator;
 use LimitIterator;
+use RecursiveIteratorIterator;
 
 /**
  * Offers a handful of method to manipulate iterators
@@ -439,4 +441,11 @@ trait CollectionTrait {
 		return new StoppableIterator($this, $condition);
 	}
 
+	public function unfold(callable $unfolder) {
+		return new Collection(
+			new RecursiveIteratorIterator(
+				new UnfoldIterator($this, $unfolder), RecursiveIteratorIterator::LEAVES_ONLY
+			)
+		);
+	}
 }

+ 67 - 0
src/Collection/Iterator/UnfoldIterator.php

@@ -0,0 +1,67 @@
+<?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         3.0.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Collection\Iterator;
+
+use Cake\Collection\Collection;
+use IteratorIterator;
+use RecursiveIterator;
+
+/**
+ * 
+ */
+class UnfoldIterator extends IteratorIterator implements RecursiveIterator {
+
+/**
+ * 
+ *
+ * @var callable
+ */
+	protected $_unfolder;
+
+/**
+ *
+ * @param array|\Traversable $items The list of values to iterate
+ * @param callable $unfolder
+ */
+	public function __construct($items, callable $unfolder) {
+		$this->_unfolder = $unfolder;
+		parent::__construct($items);
+	}
+
+	public function hasChildren() {
+		return true;
+	}
+
+	public function getChildren() {
+		$current = $this->current();
+		$key = $this->key();
+		$unfolder = $this->_unfolder;
+
+		return new NoChildrenIterator($unfolder($current, $key, $this));
+	}
+
+}
+
+class NoChildrenIterator extends Collection implements RecursiveIterator {
+
+	public function hasChildren() {
+		return false;
+	}
+
+	public function getChildren() {
+		return null;
+	}
+
+}

+ 16 - 0
tests/TestCase/Collection/CollectionTest.php

@@ -995,4 +995,20 @@ class CollectionTest extends TestCase {
 		$this->assertEquals([['foo' => 'bar']], $collection->toArray());
 	}
 
+	public function testUnfold() {
+		$items = [
+			[1, 2, 3, 4],
+			[5, 6],
+			[7, 8]
+		];
+
+		$collection = (new Collection($items))->unfold(function ($item) {
+			return $item;
+		});
+
+		$this->assertEquals(range(1, 8), $collection->toArray(false));
+
+
+	}
+
 }