Yii2中的遍历层次树邻接表模型 [英] Traversing Hierarchy Tree Adjacency List Model in Yii2
问题描述
我陷入一种无法理解如何完成并遍历列表的逻辑.
实际上,我正在创建一个类别列表,该列表将在创建产品时进一步使用.我希望类别列表应采用父级及其子节点(如邻接列表模型)的形式.
数据库:
id类别名称父级[id是父级的外键]1对12 b 23 24 25楼36克4
在yii2中使用Activequerry获取详细信息
$ rows = Category :: find()-> asArray()-> all();
$ rows 数组包含这种形式的数据
数组([0] =>大批([id] =>1个[类别名称] =>一种[父母] =>1个)[1] =>大批([id] =>2个[类别名称] =>b[父母] => 2)[2] =>大批([id] =>3[类别名称] =>C[父母] =>2个))等等...
我希望所需的输出应类似于此列表形式
[['id'=>1,'categoryname'=>'一种'],['id'=>2,'categoryname'=>'b'],['id'=>3,'categoryname'=>'b>C'],['id'=>4,'categoryname'=>'b> c> f']]
我尝试过
当我从表中获取行并将其存储在关联数组中时.每个分支节点的子ID存储在另一个关联数组中.
foreach($ rows作为$ row){$ id = $ row ["id"];$ parent_id = $ row ["parent"] === NULL吗?"NULL":$ row ["parent"];$ data [$ id] = $ row;$ index [$ parent_id] [] = $ id;}函数display_child_nodes($ parent_id,$ level,$ data,$ index){$ parent_id = $ parent_id === NULL吗?"NULL":$ parent_id;如果(isset($ index [$ parent_id])){foreach($ index [$ parent_id] as $ id){$ result ['id'] = $ data [$ id] ['id'];$ result ['name'] = $ data [$ id] ['categoryname'];$ result ['level'] = $ level;回声str_repeat(-",$ level).$ data [$ id] ["categoryname"]."\ n";display_child_nodes($ id,$ level + 1,$ data,$ index);}}}display_child_nodes(NULL,0,$ data,$ index);
我遵循了此参考以获得结果,但我无法获得所需的输出.
我曾经经历过堆栈溢出问题,但是没有一个对我有用.这样任何人都可以帮助进阶的人.
您可以使用迭代器.让我们扩展 RecursiveArrayIterator
并调用新的迭代器 AdjacencyListIterator
:
class AdjacencyListIterator扩展了RecursiveArrayIterator{私人$ adjacencyList;公共功能__construct(数组$ adjacencyList,数组$ array = null,$ flags = 0){$ this-> adjacencyList = $ adjacencyList;$ array =!is_null($ array)?$数组:array_filter($ adjacencyList,function($ node){返回is_null($ node ['parent']);});parent :: __ construct($ array,$ flags);}私人儿童公共函数hasChildren(){$ children = array_filter($ this-> adjacencyList,function($ node){return $ node ['parent'] === $ this-> current()['id'];});如果(!empty($ children)){$ this-> children = $ children;返回true;}返回false;}公共功能getChildren(){返回新的static($ this-> adjacencyList,$ this-> children);}}
顺便提一下,对于顶级父母, parent
应该为 null
(并且与 id
不同)./p>
有了此迭代器,您可以生成如下路径:
$ iterator = new RecursiveIteratorIterator(新的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;}
这是工作演示.
此方法可能比自定义递归函数要慢一些.但这实际上更灵活.通过仅更改遍历模式,您只能获得叶子,例如:
$ iterator = new RecursiveIteratorIterator(新的AdjacencyListIterator($ rows));foreach($ iterator为$ leaf){echo $ leaf ['categoryname'],PHP_EOL;}
这种情况与以前的情况不同,我们将 RecursiveIteratorIterator
的 $ mode
设置为默认的 RecursiveIteratorIterator :: LEAVES_ONLY
.
I was stuck in one logic i can't understand how it would be done and traverse the list.
Actually I was creating a category list that would be further used in creating the products. I wanted the category list should be in the form of parent and its sub nodes like adjacency list model.
Database:
id categoryname parent [id is the foreign key for the parent]
1 a 1
2 b 2
3 c 2
4 e 2
5 f 3
6 g 4
Fetching the details with Activequerry in yii2
$rows = Category::find() ->asArray() ->all();
$rows array contains the data like this form
Array
(
[0] => Array
(
[id] => 1
[categoryname] => a
[parent] => 1
)
[1] => Array
(
[id] => 2
[categoryname] => b
[parent] =>2
)
[2] => Array
(
[id] => 3
[categoryname] => c
[parent] => 2
)
)
And so on...
I wanted the desired output should be like this 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 I get the rows from the table and stores them in an associative array. The child-ids for each branch node are stored in another associative array.
foreach ($rows as $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] as $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 this reference for result but i cant get the desired output.
I had gone through with stack overflow question but none is useful for me . So anybody can help Appreciated in advanced.
You can use Iterators for that. Let's extend RecursiveArrayIterator
and 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 the way, take a notice, for top level parents parent
should be null
(and not the same as id
).
Having this iterator you can generate paths like that:
$iterator = new RecursiveIteratorIterator(
new AdjacencyListIterator($rows),
RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
foreach ($iterator as $node) {
$depth = $iterator->getDepth();
$path[$depth] = $node['categoryname'];
echo implode(' > ', array_slice($path, 0, $depth + 1)), PHP_EOL;
}
Here is working demo.
This approach can be a bit slower, than custom recursive function. But it is actually more flexible. By changing only the mode of traversing, you can get leafs only, for example:
$iterator = new RecursiveIteratorIterator(
new AdjacencyListIterator($rows)
);
foreach ($iterator as $leaf) {
echo $leaf['categoryname'], PHP_EOL;
}
This case differs from previous in that we set $mode
of the RecursiveIteratorIterator
to the default one RecursiveIteratorIterator::LEAVES_ONLY
.
这篇关于Yii2中的遍历层次树邻接表模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!