Skip to content

Commit

Permalink
Added parent entry to traverse() when visiting tree nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
aimeos committed Feb 13, 2024
1 parent 541b3c6 commit b67052d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 12 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5344,7 +5344,7 @@ Traverses trees of nested items passing each item to the callback.
public function traverse( \Closure $callback = null, string $nestKey = 'children' ) : self
```

* @param **\Closure|null** `$callback` Callback with (entry, key, level) arguments, returns the entry added to result
* @param **\Closure|null** `$callback` Callback with (entry, key, level, $parent) arguments, returns the entry added to result
* @param **string** `$nestKey` Key to the children of each item
* @return **self<int|string,mixed>** New map with all items as flat list

Expand Down Expand Up @@ -5379,6 +5379,23 @@ Map::from( [[
} );
// ['- n1', '-- n2', '-- n3']

Map::from( [[
'id' => 1, 'pid' => null, 'name' => 'n1', 'children' => [
['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => []],
['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => []]
]
]] )->traverse( function( &$entry, $key, $level, $parent ) {
$entry['path'] = isset( $parent['path'] ) ? $parent['path'] . '/' . $entry['name'] : $entry['name'];
return $entry;
} );
/*
[
['id' => 1, 'pid' => null, 'name' => 'n1', 'children' => [...], 'path' => 'n1'],
['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => [], 'path' => 'n1/n2'],
['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => [], 'path' => 'n1/n3'],
]
*/

Map::from( [[
'id' => 1, 'pid' => null, 'name' => 'n1', 'nodes' => [
['id' => 2, 'pid' => 1, 'name' => 'n2', 'nodes' => []]
Expand Down
25 changes: 14 additions & 11 deletions src/Map.php
Original file line number Diff line number Diff line change
Expand Up @@ -4871,7 +4871,7 @@ public function transpose() : self
* ['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => []],
* ['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => []]
* ]
* ]] )->traverse( function( $entry, $key, $level ) {
* ]] )->traverse( function( $entry, $key, $level, $parent ) {
* return str_repeat( '-', $level ) . '- ' . $entry['name'];
* } );
*
Expand All @@ -4880,9 +4880,10 @@ public function transpose() : self
* ['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => []],
* ['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => []]
* ]
* ]] )->traverse( function( $entry, $key, $level ) {
* return !isset( $entry['children'] ) ? $entry : null;
* } )->filter();
* ]] )->traverse( function( &$entry, $key, $level, $parent ) {
* $entry['path'] = isset( $parent['path'] ) ? $parent['path'] . '/' . $entry['name'] : $entry['name'];
* return $entry;
* } );
*
* Map::from( [[
* 'id' => 1, 'pid' => null, 'name' => 'n1', 'nodes' => [
Expand All @@ -4900,16 +4901,17 @@ public function transpose() : self
* ['- n1', '-- n2', '-- n3']
*
* [
* ['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => []],
* ['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => []],
* ['id' => 1, 'pid' => null, 'name' => 'n1', 'children' => [...], 'path' => 'n1'],
* ['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => [], 'path' => 'n1/n2'],
* ['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => [], 'path' => 'n1/n3'],
* ]
*
* [
* ['id' => 1, 'pid' => null, 'name' => 'n1', 'nodes' => [...]],
* ['id' => 2, 'pid' => 1, 'name' => 'n2', 'nodes' => []],
* ]
*
* @param \Closure|null $callback Callback with (entry, key, level) arguments, returns the entry added to result
* @param \Closure|null $callback Callback with (entry, key, level, $parent) arguments, returns the entry added to result
* @param string $nestKey Key to the children of each item
* @return self<int|string,mixed> New map with all items as flat list
*/
Expand Down Expand Up @@ -5527,17 +5529,18 @@ protected function val( $entry, array $parts )
* @param int $level Current depth of the nodes in the tree
* @param \Closure|null $callback Callback with ($entry, $key, $level) arguments, returns the entry added to result
* @param string $nestKey Key to the children of each entry
* @param array<mixed>|object|null $parent Parent entry
*/
protected function visit( iterable $entries, array &$result, int $level, ?\Closure $callback, string $nestKey ) : void
protected function visit( iterable $entries, array &$result, int $level, ?\Closure $callback, string $nestKey, $parent = null ) : void
{
foreach( $entries as $key => $entry )
{
$result[] = $callback ? $callback( $entry, $key, $level ) : $entry;
$result[] = $callback ? $callback( $entry, $key, $level, $parent ) : $entry;

if( ( is_array( $entry ) || $entry instanceof \ArrayAccess ) && isset( $entry[$nestKey] ) ) {
$this->visit( $entry[$nestKey], $result, $level + 1, $callback, $nestKey );
$this->visit( $entry[$nestKey], $result, $level + 1, $callback, $nestKey, $entry );
} elseif( is_object( $entry ) && isset( $entry->{$nestKey} ) ) {
$this->visit( $entry->{$nestKey}, $result, $level + 1, $callback, $nestKey );
$this->visit( $entry->{$nestKey}, $result, $level + 1, $callback, $nestKey, $entry );
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions tests/MapTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3241,6 +3241,31 @@ public function testTraverseCallbackObject()
}


public function testTraverseCallbackParent()
{
$expected = [
['id' => 1, 'pid' => null, 'name' => 'n1', 'children' => [
['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => []],
['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => []]
], 'path' => 'n1'],
['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => [], 'path' => 'n1/n2'],
['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => [], 'path' => 'n1/n3'],
];

$r = Map::from( [[
'id' => 1, 'pid' => null, 'name' => 'n1', 'children' => [
['id' => 2, 'pid' => 1, 'name' => 'n2', 'children' => []],
['id' => 3, 'pid' => 1, 'name' => 'n3', 'children' => []]
]
]] )->traverse( function( &$entry, $key, $level, $parent ) {
$entry['path'] = isset( $parent['path'] ) ? $parent['path'] . '/' . $entry['name'] : $entry['name'];
return $entry;
} );

$this->assertSame( $expected, $r->toArray() );
}


public function testTraverseNestkey()
{
$expected = [
Expand Down

0 comments on commit b67052d

Please sign in to comment.