php - Traversing Hierarchy Tree Adjacency List Model in Yii2 -
i stuck in 1 logic can't understand how done , traverse list.
actually creating category list further used in creating products. wanted category list should in form of parent , sub nodes adjacency list model.
database:
id categoryname parent [id foreign key parent] 1 1 2 b 2 3 c 2 4 e 2 5 f 3 6 g 4
fetching details activequerry in yii2
$rows = category::find() ->asarray() ->all();
$rows array contains data form
array ( [0] => array ( [id] => 1 [categoryname] => [parent] => 1 ) [1] => array ( [id] => 2 [categoryname] => b [parent] =>2 ) [2] => array ( [id] => 3 [categoryname] => c [parent] => 2 ) ) , on...
i wanted desired output should form of list
[ [ 'id' => 1, 'categoryname' => 'a' ], [ 'id' => 2, 'categoryname' => 'b' ], [ 'id' => 3, 'categoryname' => 'b > c' ], [ 'id' => 4, 'categoryname' => 'b>c>f' ] ]
i had tried
when rows table , stores them in associative array. child-ids each branch node stored in associative array.
foreach ($rows $row){ $id = $row["id"]; $parent_id = $row["parent"] === null ? "null" : $row["parent"]; $data[$id] = $row; $index[$parent_id][] = $id; } function display_child_nodes($parent_id, $level,$data,$index) { $parent_id = $parent_id === null ? "null" : $parent_id; if (isset($index[$parent_id])) { foreach ($index[$parent_id] $id) { $result['id'] = $data[$id]['id']; $result['name'] = $data[$id]['categoryname']; $result['level'] = $level; echo str_repeat("-", $level) . $data[$id]["categoryname"] . "\n"; display_child_nodes($id, $level + 1,$data,$index); } } } display_child_nodes(null, 0,$data,$index);
i followed reference result cant desired output.
i had gone through stack overflow question none useful me . can appreciated in advanced.
you can use iterators that. let's extend recursivearrayiterator
, call new iterator adjacencylistiterator
:
class adjacencylistiterator extends recursivearrayiterator { private $adjacencylist; public function __construct( array $adjacencylist, array $array = null, $flags = 0 ) { $this->adjacencylist = $adjacencylist; $array = !is_null($array) ? $array : array_filter($adjacencylist, function ($node) { return is_null($node['parent']); }); parent::__construct($array, $flags); } private $children; public function haschildren() { $children = array_filter($this->adjacencylist, function ($node) { return $node['parent'] === $this->current()['id']; }); if (!empty($children)) { $this->children = $children; return true; } return false; } public function getchildren() { return new static($this->adjacencylist, $this->children); } }
by way, take notice, top level parents parent
should null
(and not same id
).
having iterator can generate paths that:
$iterator = new recursiveiteratoriterator( new adjacencylistiterator($rows), recursiveiteratoriterator::self_first ); $path = []; foreach ($iterator $node) { $depth = $iterator->getdepth(); $path[$depth] = $node['categoryname']; echo implode(' > ', array_slice($path, 0, $depth + 1)), php_eol; }
here working demo.
this approach can bit slower, custom recursive function. more flexible. changing mode of traversing, can leafs only, example:
$iterator = new recursiveiteratoriterator( new adjacencylistiterator($rows) ); foreach ($iterator $leaf) { echo $leaf['categoryname'], php_eol; }
this case differs previous in set $mode
of recursiveiteratoriterator
default 1 recursiveiteratoriterator::leaves_only
.
Comments
Post a Comment