Skip to content
Permalink
Browse files

Implementend collection nest

  • Loading branch information...
lorenzo committed Jan 18, 2014
1 parent 4de65e7 commit 41ddf1a8d53758fd890734031fab25808bc7c3ad
Showing with 152 additions and 0 deletions.
  1. +49 −0 src/Collection/CollectionTrait.php
  2. +103 −0 tests/TestCase/Collection/CollectionTest.php
@@ -15,6 +15,7 @@
namespace Cake\Collection;
use AppendIterator;
use ArrayObject;
use Cake\Collection\Collection;
use Cake\Collection\Iterator\ExtractIterator;
use Cake\Collection\Iterator\FilterIterator;
@@ -701,6 +702,54 @@ public function combine($keyPath, $valuePath, $groupPath = null) {
return new Collection(new MapReduce($this, $mapper, $reducer));
}
/**
* Returns a new collection where the values are nested in a tree-like structure
* based on an id property path and a parent id property path.
*
* @param callable|string $idPath the column name path to use for determining
* whther an element is parent of another
* @param callable|string $parentPath the column name path to use for determining
* whther an element is child of another
* @return \Cake\Collection\Collection
*/
public function nest($idPath, $parentPath) {
$parents = [];
$idPath = $this->_propertyExtractor($idPath);
$parentPath = $this->_propertyExtractor($parentPath);
$isObject = !is_array($this->first());
$mapper = function($row, $key, $mapReduce) use (&$parents, $idPath, $parentPath) {
$row['children'] = [];
$id = $idPath($row, $key);
$parentId = $parentPath($row, $key);
$parents[$id] =& $row;
$mapReduce->emitIntermediate($id, $parentId);
};
$reducer = function($values, $key, $mapReduce) use (&$parents, $isObject) {
if (empty($key) || !isset($parents[$key])) {
foreach ($values as $id) {
$parents[$id] = $isObject ? $parents[$id] : new ArrayObject($parents[$id]);
$mapReduce->emit($parents[$id]);
}
return;
}
foreach ($values as $id) {
$parents[$key]['children'][] =& $parents[$id];
}
};
$collection = new MapReduce($this, $mapper, $reducer);
if (!$isObject) {
$collection = (new Collection($collection))->map(function($value) {
return (array)$value;
});
}
return new Collection($collection);
}
/**
* Returns an array representation of the results
*
@@ -676,4 +676,107 @@ function($value, $key) {
$this->assertEquals([1 => null, 2 => null, 3 => null], $collection->toArray());
}
/**
* Tests the nest method with only one level
*
* @return void
*/
public function testNest() {
$items = [
['id' => 1, 'parent_id' => null],
['id' => 2, 'parent_id' => 1],
['id' => 3, 'parent_id' => 1],
['id' => 4, 'parent_id' => 1],
['id' => 5, 'parent_id' => 6],
['id' => 6, 'parent_id' => null],
['id' => 7, 'parent_id' => 1],
['id' => 8, 'parent_id' => 6],
['id' => 9, 'parent_id' => 6],
['id' => 10, 'parent_id' => 6]
];
$collection = (new Collection($items))->nest('id', 'parent_id');
$expected = [
[
'id' => 1,
'parent_id' => null,
'children' => [
['id' => 2, 'parent_id' => 1, 'children' => []],
['id' => 3, 'parent_id' => 1, 'children' => []],
['id' => 4, 'parent_id' => 1, 'children' => []],
['id' => 7, 'parent_id' => 1, 'children' => []]
]
],
[
'id' => 6,
'parent_id' => null,
'children' => [
['id' => 5, 'parent_id' => 6, 'children' => []],
['id' => 8, 'parent_id' => 6, 'children' => []],
['id' => 9, 'parent_id' => 6, 'children' => []],
['id' => 10, 'parent_id' => 6, 'children' => []]
]
]
];
$this->assertEquals($expected, $collection->toArray());
}
/**
* Tests the nest method with more than one level
*
* @return void
*/
public function testNestMultiLevel() {
$items = [
['id' => 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');
$expected = [
[
'id' => 1,
'parent_id' => null,
'children' => [
[
'id' => 2,
'parent_id' => 1,
'children' => [
[
'id' => 3,
'parent_id' => 2,
'children' => [
['id' => 5, 'parent_id' => 3, 'children' => []],
['id' => 7, 'parent_id' => 3, 'children' => []]
]
],
[
'id' => 4,
'parent_id' => 2,
'children' => [
['id' => 8, 'parent_id' => 4, 'children' => []]
]
]
]
]
]
],
[
'id' => 6,
'parent_id' => null,
'children' => [
['id' => 9, 'parent_id' => 6, 'children' => []],
['id' => 10, 'parent_id' => 6, 'children' => []]
]
]
];
$this->assertEquals($expected, $collection->toArray());
}
}

0 comments on commit 41ddf1a

Please sign in to comment.
You can’t perform that action at this time.