1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace devgroup\JsTreeWidget\actions\nestedset; |
4
|
|
|
|
5
|
|
|
use devgroup\JsTreeWidget\widgets\TreeWidget; |
6
|
|
|
use yii\base\Action; |
7
|
|
|
use yii\base\InvalidConfigException; |
8
|
|
|
use yii\db\ActiveRecord; |
9
|
|
|
use Yii; |
10
|
|
|
use yii\db\Query; |
11
|
|
|
use yii\web\Response; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Class FullTreeDataAction |
15
|
|
|
* |
16
|
|
|
* @package devgroup\JsTreeWidget\actions\nestedset |
17
|
|
|
*/ |
18
|
|
|
class FullTreeDataAction extends Action |
19
|
|
|
{ |
20
|
|
|
/** @var string */ |
21
|
|
|
public $leftAttribute = 'lft'; |
22
|
|
|
/** @var string */ |
23
|
|
|
public $rightAttribute = 'rgt'; |
24
|
|
|
/** @var string set root column name for multi root tree */ |
25
|
|
|
public $rootAttribute = false; |
26
|
|
|
/** @var ActiveRecord */ |
27
|
|
|
public $className; |
28
|
|
|
/** @var string */ |
29
|
|
|
public $modelLabelAttribute = 'name'; |
30
|
|
|
/** @var string */ |
31
|
|
|
private $tableName; |
32
|
|
|
|
33
|
|
|
private $selectedNodes = []; |
34
|
|
|
/** |
35
|
|
|
* @inheritdoc |
36
|
|
|
*/ |
37
|
|
View Code Duplication |
public function init() |
|
|
|
|
38
|
|
|
{ |
39
|
|
|
if (true === empty($this->className) || false === is_subclass_of($this->className, ActiveRecord::class)) { |
|
|
|
|
40
|
|
|
throw new InvalidConfigException('"className" param must be set and must be child of ActiveRecord'); |
41
|
|
|
} |
42
|
|
|
/** @var ActiveRecord $class */ |
43
|
|
|
$class = $this->className; |
44
|
|
|
$this->tableName = $class::tableName(); |
45
|
|
|
$scheme = Yii::$app->getDb()->getTableSchema($this->tableName); |
46
|
|
|
$columns = $scheme->columns; |
47
|
|
|
if (false !== $this->rootAttribute && false === isset($columns[$this->rootAttribute])) { |
48
|
|
|
throw new InvalidConfigException("Column '{$this->rootAttribute}' not found in the '{$this->tableName}' table"); |
|
|
|
|
49
|
|
|
} |
50
|
|
|
if (false === isset( |
51
|
|
|
$columns[$this->leftAttribute], |
52
|
|
|
$columns[$this->rightAttribute], |
53
|
|
|
$columns[$this->modelLabelAttribute] |
54
|
|
|
) |
55
|
|
|
) { |
56
|
|
|
throw new InvalidConfigException( |
57
|
|
|
"Some of the '{$this->leftAttribute}', '{$this->rightAttribute}', '{$this->modelLabelAttribute}', " |
58
|
|
|
. "not found in the '{$this->tableName}' columns list" |
59
|
|
|
); |
60
|
|
|
} |
61
|
|
|
TreeWidget::registerTranslations(); |
62
|
|
|
parent::init(); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @inheritdoc |
67
|
|
|
*/ |
68
|
|
|
public function run() |
69
|
|
|
{ |
70
|
|
|
$selectArray = [ |
71
|
|
|
'id', |
72
|
|
|
$this->leftAttribute, |
73
|
|
|
$this->rightAttribute, |
74
|
|
|
$this->modelLabelAttribute, |
75
|
|
|
]; |
76
|
|
|
$orderBy = []; |
77
|
|
|
if (false !== $this->rootAttribute) { |
78
|
|
|
$selectArray[] = $this->rootAttribute; |
79
|
|
|
$orderBy[$this->rootAttribute] = SORT_ASC; |
80
|
|
|
} |
81
|
|
|
$orderBy[$this->leftAttribute] = SORT_ASC; |
82
|
|
|
Yii::$app->response->format = Response::FORMAT_JSON; |
83
|
|
|
$data = (new Query()) |
84
|
|
|
->from($this->tableName) |
85
|
|
|
->select($selectArray) |
86
|
|
|
->orderBy($orderBy) |
87
|
|
|
->all(); |
88
|
|
|
|
89
|
|
|
$this->selectedNodes = explode(',', Yii::$app->request->get('selected', '')); |
90
|
|
|
|
91
|
|
|
return $this->prepareNestedData($data); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Converts single or multi root Nested Set database data into multidimensional array for using in the |
96
|
|
|
* jsTree widget |
97
|
|
|
* |
98
|
|
|
* @param array $data |
99
|
|
|
* @param int $lft |
100
|
|
|
* @param null $rgt |
101
|
|
|
* @param int $root |
102
|
|
|
* @return array |
103
|
|
|
*/ |
104
|
|
|
public function prepareNestedData($data, $lft = 0, $rgt = null, $root = 0) |
105
|
|
|
{ |
106
|
|
|
$res = []; |
107
|
|
|
foreach ($data as $row) { |
108
|
|
|
$currentRoot = isset($row[$this->rootAttribute]) ? $row[$this->rootAttribute] : 0; |
109
|
|
|
if (is_null($rgt) || $row[$this->rightAttribute] < $rgt && $root == $currentRoot) { |
110
|
|
|
if ($lft + 1 == $row[$this->leftAttribute]) { |
111
|
|
|
if ($row[$this->leftAttribute] + 1 !== $row[$this->rightAttribute]) { |
112
|
|
|
$res[] = [ |
113
|
|
|
'id' => $row['id'], |
114
|
|
|
'text' => $row[$this->modelLabelAttribute], |
115
|
|
|
'a_attr' => [ |
116
|
|
|
'data-id' => $row['id'], |
117
|
|
|
], |
118
|
|
|
'children' => self::prepareNestedData( |
119
|
|
|
$data, |
120
|
|
|
$row[$this->leftAttribute], |
121
|
|
|
$row[$this->rightAttribute], |
122
|
|
|
$currentRoot |
123
|
|
|
), |
124
|
|
|
'state' => [ |
125
|
|
|
'selected' => in_array($row['id'], $this->selectedNodes), |
126
|
|
|
], |
127
|
|
|
]; |
128
|
|
|
} else { |
129
|
|
|
$res[] = [ |
130
|
|
|
'id' => $row['id'], |
131
|
|
|
'text' => $row[$this->modelLabelAttribute], |
132
|
|
|
'a_attr' => [ |
133
|
|
|
'data-id' => $row['id'], |
134
|
|
|
], |
135
|
|
|
'children' => [], |
136
|
|
|
'state' => [ |
137
|
|
|
'selected' => in_array($row['id'], $this->selectedNodes), |
138
|
|
|
], |
139
|
|
|
]; |
140
|
|
|
} |
141
|
|
|
$lft = $row[$this->rightAttribute]; |
142
|
|
|
} else if ($row[$this->leftAttribute] == 1 && $root !== $currentRoot) { |
143
|
|
|
$res[] = [ |
144
|
|
|
'id' => $row['id'], |
145
|
|
|
'text' => $row[$this->modelLabelAttribute], |
146
|
|
|
'a_attr' => [ |
147
|
|
|
'data-id' => $row['id'], |
148
|
|
|
], |
149
|
|
|
'children' => self::prepareNestedData( |
150
|
|
|
$data, |
151
|
|
|
$row[$this->leftAttribute], |
152
|
|
|
$row[$this->rightAttribute], |
153
|
|
|
$currentRoot |
154
|
|
|
), |
155
|
|
|
'state' => [ |
156
|
|
|
'selected' => in_array($row['id'], $this->selectedNodes), |
157
|
|
|
], |
158
|
|
|
]; |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
return $res; |
163
|
|
|
} |
164
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.