diff --git a/src/Collection/CollectionTrait.php b/src/Collection/CollectionTrait.php index 82ede510818..a7a96701557 100644 --- a/src/Collection/CollectionTrait.php +++ b/src/Collection/CollectionTrait.php @@ -21,8 +21,10 @@ use Cake\Collection\Iterator\FilterIterator; use Cake\Collection\Iterator\InsertIterator; use Cake\Collection\Iterator\MapReduce; +use Cake\Collection\Iterator\NestIterator; use Cake\Collection\Iterator\ReplaceIterator; use Cake\Collection\Iterator\SortIterator; +use Cake\Collection\Iterator\TreeIterator; use LimitIterator; /** @@ -857,4 +859,16 @@ public function compile($preserveKeys = true) { return new Collection($this->toArray($preserveKeys)); } +/** + * + * + * @return void + */ + public function listNested($nestingKey = 'children') { + return new TreeIterator( + new NestIterator($this, $nestingKey), + TreeIterator::SELF_FIRST + ); + } + } diff --git a/src/Collection/Iterator/NestIterator.php b/src/Collection/Iterator/NestIterator.php new file mode 100644 index 00000000000..575b78d66a3 --- /dev/null +++ b/src/Collection/Iterator/NestIterator.php @@ -0,0 +1,48 @@ +_nestKey = $nestKey; + } + + public function getChildren() { + $property = $this->_propertyExtractor($this->_nestKey); + return new self($property($this->current()), $this->_nestKey); + } + + public function hasChildren () { + $property = $this->_propertyExtractor($this->_nestKey); + $children = $property($this->current()); + + if (is_array($children)) { + return !empty($children); + } + + if ($children instanceof \Traversable) { + return true; + } + + return false; + } +} diff --git a/src/Collection/Iterator/TreeIterator.php b/src/Collection/Iterator/TreeIterator.php new file mode 100644 index 00000000000..f9770bcf99f --- /dev/null +++ b/src/Collection/Iterator/TreeIterator.php @@ -0,0 +1,24 @@ + 1, 'parent_id' => null], + ['id' => 2, 'parent_id' => 1], + ['id' => 3, 'parent_id' => 2], + ['id' => 4, 'parent_id' => 2], + ['id' => 5, 'parent_id' => 3], + ['id' => 6, 'parent_id' => null], + ['id' => 7, 'parent_id' => 3], + ['id' => 8, 'parent_id' => 4], + ['id' => 9, 'parent_id' => 6], + ['id' => 10, 'parent_id' => 6] + ]; + $collection = (new Collection($items))->nest('id', 'parent_id')->listNested(); + $this->assertEquals( + [1, 2, 3, 5, 7, 4, 8, 6, 9, 10], + $collection->extract('id')->toArray(false) + ); + } + +/** + * Tests using listNested with a different nesting key + * + * @return void + */ + public function testListNestedCustomKey() { + $items = [ + ['id' => 1, 'stuff' => [['id' => 2, 'stuff' => [['id' => 3]]]]], + ['id' => 4, 'stuff' => [['id' => 5]]] + ]; + $collection = (new Collection($items))->listNested('stuff'); + $this->assertEquals(range(1, 5), $collection->extract('id')->toArray(false)); + } + }