-
Notifications
You must be signed in to change notification settings - Fork 0
/
TreeBehavior.php
128 lines (111 loc) · 3.95 KB
/
TreeBehavior.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php
/**
* @author terrasoff
* @desc категория в рубрикаторе
*/
class TreeBehavior extends CActiveRecordBehavior
{
public $criteria = null;
public $idAttribute = 'id';
public $parentIdAttribute = 'parent_id';
public $orderAttribute = 'weight';
/**
* Составляем путь до выбранной категории от корня с учетом вложенности
* @return array
* @throws TException
*/
public function getPath() {
// пока путь не определены
$path = array();
// выбранная категория
if ($node = $this->getOwner())
{
// первый элемент
$path[] = $node;
// остальные элементы
$parent_id = (int)$node->{$this->parentIdAttribute};
if ($parent_id) {
while ($parent_id) {
// очерденой родитель
$node = Category::model()->findByPk($parent_id);
$path[] = $node;
if (!$node)
throw new TException('Не удалось найти путь до заданной категории');
$parent_id = (int)$node->{$this->parentIdAttribute};
}
}
}
return $path;
}
public function getBreadcrumbs() {
$breadcrumbs = array();
$items = $this->getPath();
if ($items) {
foreach ($items as $i=>$item) {
$breadcrumbs[] = $item->toArray();
}
}
return array_reverse($breadcrumbs);
}
public function getNodeCriteria($id = null) {
$criteria = new CDbCriteria();
$node = $this->getOwner();
if ($id) {
$criteria->addCondition($this->parentIdAttribute.'=:id');
$criteria->order = $this->orderAttribute;
$criteria->params = array(':id'=>$id);
} else {
$criteria->addCondition($this->parentIdAttribute.'=0');
}
return $criteria;
}
/**
* Получаем идентификаторы узлов из вложенного дерева узлов
*/
public function flattern($items = null, &$list = array()) {
// дочерние узлы
$items = $items
? $items
: $this->getTree();
foreach ($items as $i=>$item) {
$list[] = (int)$item[$this->idAttribute];
if (is_array($item['children'])) {
$this->flattern($item['children'],$list);
}
}
return $list;
}
/**
* Обходим дерево с заданной глубиной от определенного корня
* @param int $depth глубина
* @param null $root корень
* @return array
*/
public function getTree($depth = 4) {
return (array)$this->walkTree($depth);
}
/**
* Рекурсивный обход дерева с заданной глубиной по текущей глубине
* @param int $depth глубина
* @param null $current_depth текущая глубина
* @return array
*/
public function walkTree($depth = 4,$current_depth = 0) {
$node = $this->getOwner();
// глубже, чем надо не лезем
if ($current_depth++ > $depth) return;
// завершили обход?
if ($this->criteria)
$node->getDbCriteria()->mergeWith($this->criteria);
$children = $node->findAll($this->getNodeCriteria($node->{$this->idAttribute}));
if (!$children)
return;
$items = array();
// продолжаем обход
foreach($children as $n) {
$item = $n->walkTree($depth,$current_depth);
$items[] = $n->toArray($item);
}
return $items;
}
}