1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace devgroup\JsTreeWidget\actions\nestedset; |
4
|
|
|
|
5
|
|
|
use devgroup\JsTreeWidget\widgets\TreeWidget; |
6
|
|
|
use yii\base\Action; |
7
|
|
|
use Yii; |
8
|
|
|
use yii\base\InvalidConfigException; |
9
|
|
|
use yii\db\ActiveRecord; |
10
|
|
|
use yii\db\Expression; |
11
|
|
|
use yii\web\Response; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Class NodeMoveAction |
15
|
|
|
* |
16
|
|
|
* @package devgroup\JsTreeWidget\actions\nestedset |
17
|
|
|
*/ |
18
|
|
|
class NodeMoveAction extends Action |
19
|
|
|
{ |
20
|
|
|
/** @var ActiveRecord */ |
21
|
|
|
public $className; |
22
|
|
|
/** @var string set root column name for multi root tree */ |
23
|
|
|
public $rootAttribute = false; |
24
|
|
|
/** @var string */ |
25
|
|
|
public $leftAttribute = 'lft'; |
26
|
|
|
/** @var string */ |
27
|
|
|
public $rightAttribute = 'rgt'; |
28
|
|
|
/** @var string */ |
29
|
|
|
public $depthAttribute = 'depth'; |
30
|
|
|
|
31
|
|
|
/** @var ActiveRecord */ |
32
|
|
|
private $node; |
33
|
|
|
/** @var ActiveRecord */ |
34
|
|
|
private $parent; |
35
|
|
|
/** @var string */ |
36
|
|
|
private $tableName; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @inheritdoc |
40
|
|
|
*/ |
41
|
|
View Code Duplication |
public function init() |
|
|
|
|
42
|
|
|
{ |
43
|
|
|
if (true === empty($this->className) || false === is_subclass_of($this->className, ActiveRecord::class)) { |
|
|
|
|
44
|
|
|
throw new InvalidConfigException('"className" param must be set and must be child of ActiveRecord'); |
45
|
|
|
} |
46
|
|
|
/** @var ActiveRecord $class */ |
47
|
|
|
$class = $this->className; |
48
|
|
|
$this->tableName = $class::tableName(); |
49
|
|
|
$scheme = Yii::$app->getDb()->getTableSchema($this->tableName); |
50
|
|
|
$columns = $scheme->columns; |
51
|
|
|
if (false !== $this->rootAttribute && false === isset($columns[$this->rootAttribute])) { |
52
|
|
|
throw new InvalidConfigException("Column '{$this->rootAttribute}' not found in the '{$this->tableName}' table"); |
|
|
|
|
53
|
|
|
} |
54
|
|
|
if (false === isset( |
55
|
|
|
$columns[$this->leftAttribute], |
56
|
|
|
$columns[$this->rightAttribute], |
57
|
|
|
$columns[$this->depthAttribute] |
58
|
|
|
) |
59
|
|
|
) { |
60
|
|
|
throw new InvalidConfigException( |
61
|
|
|
"Some of the '{$this->leftAttribute}', '{$this->rightAttribute}', '{$this->depthAttribute}', " |
62
|
|
|
. "not found in the '{$this->tableName}' columns list" |
63
|
|
|
); |
64
|
|
|
} |
65
|
|
|
TreeWidget::registerTranslations(); |
66
|
|
|
parent::init(); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @inheritdoc |
71
|
|
|
*/ |
72
|
|
|
public function run() |
73
|
|
|
{ |
74
|
|
|
Yii::$app->response->format = Response::FORMAT_JSON; |
75
|
|
|
$newParentId = Yii::$app->request->post('parent'); |
76
|
|
|
$oldParentId = Yii::$app->request->post('old_parent'); |
77
|
|
|
$position = Yii::$app->request->post('position'); |
78
|
|
|
$oldPosition = Yii::$app->request->post('old_position'); |
79
|
|
|
$nodeId = Yii::$app->request->post('node_id'); |
80
|
|
|
$siblings = Yii::$app->request->post('siblings', []); |
81
|
|
|
$class = $this->className; |
82
|
|
|
if ((int)$newParentId == 0) { |
83
|
|
|
return ['error' => Yii::t('jstw', 'Can not move node as root!')]; |
84
|
|
|
} |
85
|
|
|
if ((null === $node = $class::findOne($nodeId)) || (null === $parent = $class::findOne($newParentId))) { |
86
|
|
|
return ['error' => Yii::t('jstw', 'Invalid node id or parent id received!')]; |
87
|
|
|
} |
88
|
|
|
$this->node = $node; |
|
|
|
|
89
|
|
|
$this->parent = $parent; |
|
|
|
|
90
|
|
|
if (false !== $this->rootAttribute && ($node->{$this->rootAttribute} != $parent->{$this->rootAttribute})) { |
91
|
|
|
return $this->moveMultiRoot($position, $siblings, $oldParentId); |
92
|
|
|
} |
93
|
|
|
if ($newParentId == $oldParentId) { |
94
|
|
|
return $this->reorder($oldPosition, $position, $siblings); |
95
|
|
|
} else { |
96
|
|
|
return $this->move($position, $siblings, $oldParentId); |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Moves node inside one parent inside one root |
102
|
|
|
* |
103
|
|
|
* @param null $oldPosition |
104
|
|
|
* @param null $position |
105
|
|
|
* @param array $siblings |
106
|
|
|
* @return array|bool |
|
|
|
|
107
|
|
|
* @throws \yii\db\Exception |
108
|
|
|
*/ |
109
|
|
|
public function reorder($oldPosition = null, $position = null, $siblings = []) |
110
|
|
|
{ |
111
|
|
|
if (null === $oldPosition || null === $position || true === empty($siblings)) { |
112
|
|
|
return ['error' => Yii::t('jstw', 'Invalid data provided!')]; |
113
|
|
|
} |
114
|
|
|
$nodeId = $siblings[$position]; |
115
|
|
|
$class = $this->className; |
116
|
|
|
$lr = $workWith = []; |
|
|
|
|
117
|
|
|
$nodeOperator = $siblingsOperator = ''; |
|
|
|
|
118
|
|
|
if ($oldPosition > $position) { |
119
|
|
|
//change next |
120
|
|
|
$nodeOperator = '-'; |
121
|
|
|
$siblingsOperator = '+'; |
122
|
|
|
$workWith = array_slice($siblings, $position, $oldPosition - $position + 1); |
123
|
|
|
} else if ($oldPosition < $position) { |
124
|
|
|
//change previous |
125
|
|
|
$nodeOperator = '+'; |
126
|
|
|
$siblingsOperator = '-'; |
127
|
|
|
$workWith = array_slice($siblings, $oldPosition, $position - $oldPosition + 1); |
128
|
|
|
} else { |
129
|
|
|
return true; |
130
|
|
|
} |
131
|
|
|
if (true === empty($workWith)) { |
132
|
|
|
return ['error' => Yii::t('jstw', 'Invalid data provided!')]; |
133
|
|
|
} |
134
|
|
|
$lr = $workWithLr = $this->getLr($workWith); |
135
|
|
|
if (true === empty($lr)) { |
136
|
|
|
return ['error' => Yii::t('jstw', 'Invalid data provided!')]; |
137
|
|
|
} |
138
|
|
|
unset($workWithLr[$nodeId]); |
139
|
|
|
$lft = array_column($workWithLr, $this->leftAttribute); |
140
|
|
|
$lft = min($lft); |
141
|
|
|
$rgt = array_column($workWithLr, $this->rightAttribute); |
142
|
|
|
$rgt = max($rgt); |
143
|
|
|
$nodeCondition = [ |
144
|
|
|
'and', |
145
|
|
|
['>=', $this->leftAttribute, $lft], |
146
|
|
|
['<=', $this->rightAttribute, $rgt] |
147
|
|
|
]; |
148
|
|
|
$this->applyRootCondition($nodeCondition); |
149
|
|
|
$nodeDelta = $this->getCount($nodeCondition); |
150
|
|
|
$nodeDelta *= 2; |
151
|
|
|
$siblingsCondition = [ |
152
|
|
|
'and', |
153
|
|
|
['>=', $this->leftAttribute, $lr[$nodeId][$this->leftAttribute]], |
154
|
|
|
['<=', $this->rightAttribute, $lr[$nodeId][$this->rightAttribute]] |
155
|
|
|
]; |
156
|
|
|
$this->applyRootCondition($siblingsCondition); |
157
|
|
|
$nodeChildren = $this->getChildIds($siblingsCondition); |
158
|
|
|
$siblingsDelta = count($nodeChildren) * 2; |
159
|
|
|
$db = Yii::$app->getDb(); |
160
|
|
|
$transaction = $db->beginTransaction(); |
161
|
|
|
try { |
162
|
|
|
//updating necessary node siblings |
163
|
|
|
$db->createCommand()->update( |
164
|
|
|
$class::tableName(), |
165
|
|
|
[ |
166
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $siblingsOperator, $siblingsDelta)), |
|
|
|
|
167
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $siblingsOperator, $siblingsDelta)), |
|
|
|
|
168
|
|
|
], |
169
|
|
|
$nodeCondition |
170
|
|
|
)->execute(); |
171
|
|
|
//updating node |
172
|
|
|
$db->createCommand()->update( |
173
|
|
|
$class::tableName(), |
174
|
|
|
[ |
175
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)), |
|
|
|
|
176
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)), |
|
|
|
|
177
|
|
|
], |
178
|
|
|
['id' => $nodeChildren] |
179
|
|
|
)->execute(); |
180
|
|
|
$transaction->commit(); |
181
|
|
|
} catch (\Exception $e) { |
182
|
|
|
$transaction->rollBack(); |
183
|
|
|
return ['error' => $e->getMessage()]; |
184
|
|
|
} |
185
|
|
|
return true; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Moves node inside one root |
190
|
|
|
* |
191
|
|
|
* @param null $position |
192
|
|
|
* @param array $siblings |
193
|
|
|
* @param string | integer $oldParentId |
194
|
|
|
* @return array|bool |
|
|
|
|
195
|
|
|
* @throws \yii\db\Exception |
196
|
|
|
*/ |
197
|
|
|
private function move($position = null, $siblings = [], $oldParentId) |
|
|
|
|
198
|
|
|
{ |
199
|
|
|
$class = $this->className; |
200
|
|
View Code Duplication |
if (null === $oldParent = $class::findOne($oldParentId)) { |
|
|
|
|
201
|
|
|
return ['error' => Yii::t('jstw', "Old parent with id '{id}' not found!", ['id' => $oldParentId])]; |
202
|
|
|
} |
203
|
|
|
$nodeCountCondition = [ |
204
|
|
|
'and', |
205
|
|
|
['>=', $this->leftAttribute, $this->node{$this->leftAttribute}], |
206
|
|
|
['<=', $this->rightAttribute, $this->node{$this->rightAttribute}] |
207
|
|
|
]; |
208
|
|
|
$this->applyRootCondition($nodeCountCondition); |
209
|
|
|
$nodeChildren = $this->getChildIds($nodeCountCondition); |
210
|
|
|
$siblingsDelta = count($nodeChildren) * 2; |
211
|
|
View Code Duplication |
if ($position == 0) { |
|
|
|
|
212
|
|
|
$compareRight = $this->parent->{$this->leftAttribute} + 1; |
213
|
|
|
} else { |
214
|
|
|
if (false === isset($siblings[$position - 1])) { |
215
|
|
|
return ['error' => Yii::t('jstw', 'New previous sibling not exists')]; |
216
|
|
|
} |
217
|
|
|
$newPrevSiblingId = $siblings[$position - 1]; |
218
|
|
|
$newPrevSiblingData = $this->getLr($newPrevSiblingId); |
219
|
|
|
$compareRight = $newPrevSiblingData[$newPrevSiblingId][$this->rightAttribute]; |
220
|
|
|
} |
221
|
|
|
if ($this->node->{$this->leftAttribute} > $compareRight) { |
222
|
|
|
//move node up |
223
|
|
View Code Duplication |
if ($position == 0) { |
|
|
|
|
224
|
|
|
$leftFrom = $this->parent->{$this->leftAttribute} + 1; |
225
|
|
|
} else { |
226
|
|
|
$leftFrom = $newPrevSiblingData[$newPrevSiblingId][$this->rightAttribute] + 1; |
|
|
|
|
227
|
|
|
} |
228
|
|
|
$rightTo = $this->node->{$this->leftAttribute}; |
229
|
|
|
$nodeDelta = $this->node->{$this->leftAttribute} - $leftFrom; |
230
|
|
|
$nodeOperator = '-'; |
231
|
|
|
$parentOperator = $siblingsOperator = '+'; |
232
|
|
|
$newParentUpdateField = $this->rightAttribute; |
233
|
|
|
$oldParentUpdateField = $this->leftAttribute; |
234
|
|
|
} else if ($this->node->{$this->leftAttribute} < $compareRight) { |
235
|
|
|
//move node down |
236
|
|
|
$leftFrom = $this->node->{$this->rightAttribute}; |
237
|
|
View Code Duplication |
if ($position == 0) { |
|
|
|
|
238
|
|
|
$rightTo = $this->parent->{$this->leftAttribute}; |
239
|
|
|
} else { |
240
|
|
|
$rightTo = $newPrevSiblingData[$newPrevSiblingId][$this->rightAttribute]; |
241
|
|
|
} |
242
|
|
|
$nodeOperator = '+'; |
243
|
|
|
$parentOperator = $siblingsOperator = '-'; |
244
|
|
|
$nodeDelta = $rightTo - $siblingsDelta + 1 - $this->node->{$this->leftAttribute}; |
245
|
|
|
$newParentUpdateField = $this->leftAttribute; |
246
|
|
|
$oldParentUpdateField = $this->rightAttribute; |
247
|
|
|
} else { |
248
|
|
|
return ['error' => Yii::t('jstw', 'There are two nodes with same "left" value. This should not be.')]; |
249
|
|
|
} |
250
|
|
|
$siblingsCondition = [ |
251
|
|
|
'and', |
252
|
|
|
['>=', $this->leftAttribute, $leftFrom], |
253
|
|
|
['<=', $this->rightAttribute, $rightTo] |
254
|
|
|
]; |
255
|
|
|
$this->applyRootCondition($siblingsCondition); |
256
|
|
|
$db = Yii::$app->getDb(); |
257
|
|
|
$transaction = $db->beginTransaction(); |
258
|
|
|
$oldParentDepth = $oldParent->{$this->depthAttribute}; |
259
|
|
|
$newParentDepth = $this->parent->{$this->depthAttribute}; |
260
|
|
View Code Duplication |
if ($newParentDepth < $oldParentDepth) { |
|
|
|
|
261
|
|
|
$depthOperator = '-'; |
262
|
|
|
$depthDelta = $oldParentDepth - $newParentDepth; |
263
|
|
|
} else { |
264
|
|
|
$depthOperator = '+'; |
265
|
|
|
$depthDelta = $newParentDepth - $oldParentDepth; |
266
|
|
|
} |
267
|
|
|
$commonParentsCondition = [ |
268
|
|
|
'and', |
269
|
|
|
['<', $this->leftAttribute, $leftFrom], |
270
|
|
|
['>', $this->rightAttribute, $rightTo] |
271
|
|
|
]; |
272
|
|
|
$this->applyRootCondition($commonParentsCondition); |
273
|
|
|
$commonParentsIds = $class::find()->select('id')->where($commonParentsCondition)->column(); |
274
|
|
|
$commonCondition = [ |
275
|
|
|
['!=', $this->depthAttribute, 0], |
276
|
|
|
['not in', 'id', $commonParentsIds], |
277
|
|
|
]; |
278
|
|
|
$this->applyRootCondition($commonCondition); |
279
|
|
|
$newParentCondition = array_merge([ |
280
|
|
|
'and', |
281
|
|
|
['<=', $this->leftAttribute, $this->parent->{$this->leftAttribute}], |
282
|
|
|
['>=', $this->rightAttribute, $this->parent->{$this->rightAttribute}], |
283
|
|
|
], $commonCondition); |
284
|
|
|
$oldParentsCondition = array_merge([ |
285
|
|
|
'and', |
286
|
|
|
['<', $this->leftAttribute, $this->node->{$this->leftAttribute}], |
287
|
|
|
['>', $this->rightAttribute, $this->node->{$this->rightAttribute}], |
288
|
|
|
], $commonCondition); |
289
|
|
|
try { |
290
|
|
|
//updating necessary node siblings |
291
|
|
|
$db->createCommand()->update( |
292
|
|
|
$class::tableName(), |
293
|
|
|
[ |
294
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $siblingsOperator, $siblingsDelta)), |
|
|
|
|
295
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $siblingsOperator, $siblingsDelta)), |
|
|
|
|
296
|
|
|
], |
297
|
|
|
$siblingsCondition |
298
|
|
|
)->execute(); |
299
|
|
|
//updating old parents |
300
|
|
|
$db->createCommand()->update( |
301
|
|
|
$class::tableName(), |
302
|
|
|
[ |
303
|
|
|
//down - right |
304
|
|
|
$oldParentUpdateField => new Expression($oldParentUpdateField . sprintf('%s%d', $parentOperator, $siblingsDelta)), |
|
|
|
|
305
|
|
|
], |
306
|
|
|
$oldParentsCondition |
307
|
|
|
)->execute(); |
308
|
|
|
//updating new parents |
309
|
|
|
$db->createCommand()->update( |
310
|
|
|
$class::tableName(), |
311
|
|
|
[ |
312
|
|
|
//down - left |
313
|
|
|
$newParentUpdateField => new Expression($newParentUpdateField . sprintf('%s%d', $parentOperator, $siblingsDelta)), |
|
|
|
|
314
|
|
|
], |
315
|
|
|
$newParentCondition |
316
|
|
|
)->execute(); |
317
|
|
|
//updating node with children |
318
|
|
|
$db->createCommand()->update( |
319
|
|
|
$class::tableName(), |
320
|
|
|
[ |
321
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)), |
|
|
|
|
322
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)), |
|
|
|
|
323
|
|
|
$this->depthAttribute => new Expression($this->depthAttribute . sprintf('%s%d', $depthOperator, $depthDelta)), |
|
|
|
|
324
|
|
|
], |
325
|
|
|
['id' => $nodeChildren] |
326
|
|
|
)->execute(); |
327
|
|
|
$transaction->commit(); |
328
|
|
|
} catch (\Exception $e) { |
329
|
|
|
$transaction->rollBack(); |
330
|
|
|
return ['error' => $e->getMessage()]; |
331
|
|
|
} |
332
|
|
|
return true; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Moves node between two roots |
337
|
|
|
* |
338
|
|
|
* @param null $position |
339
|
|
|
* @param array $siblings |
340
|
|
|
* @param string | integer $oldParentId |
341
|
|
|
* @return array|bool |
|
|
|
|
342
|
|
|
* @throws \yii\db\Exception |
343
|
|
|
*/ |
344
|
|
|
private function moveMultiRoot($position = null, $siblings = [], $oldParentId) |
|
|
|
|
345
|
|
|
{ |
346
|
|
|
$class = $this->className; |
347
|
|
View Code Duplication |
if (null === $oldParent = $class::findOne($oldParentId)) { |
|
|
|
|
348
|
|
|
return ['error' => Yii::t('jstw', "Old parent with id '{id}' not found!", ['id' => $oldParentId])]; |
349
|
|
|
} |
350
|
|
|
$nodeCountCondition = [ |
351
|
|
|
'and', |
352
|
|
|
['>=', $this->leftAttribute, $this->node->{$this->leftAttribute}], |
353
|
|
|
['<=', $this->rightAttribute, $this->node->{$this->rightAttribute}], |
354
|
|
|
[$this->rootAttribute => $this->node->{$this->rootAttribute}] |
355
|
|
|
]; |
356
|
|
|
$nodeChildren = $this->getChildIds($nodeCountCondition); |
357
|
|
|
$siblingsDelta = count($nodeChildren) * 2; |
358
|
|
View Code Duplication |
if ($position == 0) { |
|
|
|
|
359
|
|
|
$leftFrom = $this->parent->{$this->leftAttribute} + 1; |
360
|
|
|
} else { |
361
|
|
|
if (false === isset($siblings[$position - 1])) { |
362
|
|
|
return ['error' => Yii::t('jstw', 'New previous sibling not exists')]; |
363
|
|
|
} |
364
|
|
|
$newPrevSiblingId = $siblings[$position - 1]; |
365
|
|
|
$newPrevSiblingData = $this->getLr($newPrevSiblingId); |
366
|
|
|
$leftFrom = $newPrevSiblingData[$newPrevSiblingId][$this->rightAttribute] + 1; |
367
|
|
|
} |
368
|
|
|
if ($this->node->{$this->leftAttribute} > $leftFrom) { |
369
|
|
|
$nodeDelta = $this->node->{$this->leftAttribute} - $leftFrom; |
370
|
|
|
$nodeOperator = '-'; |
371
|
|
|
} else { |
372
|
|
|
$nodeDelta = $leftFrom - $this->node->{$this->leftAttribute}; |
373
|
|
|
$nodeOperator = '+'; |
374
|
|
|
} |
375
|
|
|
$siblingsCondition = [ |
376
|
|
|
'and', |
377
|
|
|
['>=', $this->leftAttribute, $leftFrom], |
378
|
|
|
[$this->rootAttribute => $this->parent->{$this->rootAttribute}] |
379
|
|
|
]; |
380
|
|
|
$oldSiblingsCondition = [ |
381
|
|
|
'and', |
382
|
|
|
['>', $this->leftAttribute, $this->node->{$this->rightAttribute}], |
383
|
|
|
[$this->rootAttribute => $this->node->{$this->rootAttribute}] |
384
|
|
|
]; |
385
|
|
|
$db = Yii::$app->getDb(); |
386
|
|
|
$transaction = $db->beginTransaction(); |
387
|
|
|
$oldParentDepth = $oldParent->{$this->depthAttribute}; |
388
|
|
|
$newParentDepth = $this->parent->{$this->depthAttribute}; |
389
|
|
View Code Duplication |
if ($newParentDepth < $oldParentDepth) { |
|
|
|
|
390
|
|
|
$depthOperator = '-'; |
391
|
|
|
$depthDelta = $oldParentDepth - $newParentDepth; |
392
|
|
|
} else { |
393
|
|
|
$depthOperator = '+'; |
394
|
|
|
$depthDelta = $newParentDepth - $oldParentDepth; |
395
|
|
|
} |
396
|
|
|
$newParentCondition = [ |
397
|
|
|
'and', |
398
|
|
|
['<=', $this->leftAttribute, $this->parent->{$this->leftAttribute}], |
399
|
|
|
['>=', $this->rightAttribute, $this->parent->{$this->rightAttribute}], |
400
|
|
|
[$this->rootAttribute => $this->parent->{$this->rootAttribute}] |
401
|
|
|
]; |
402
|
|
|
$oldParentsCondition = [ |
403
|
|
|
'and', |
404
|
|
|
['<=', $this->leftAttribute, $oldParent->{$this->leftAttribute}], |
405
|
|
|
['>=', $this->rightAttribute, $oldParent->{$this->rightAttribute}], |
406
|
|
|
[$this->rootAttribute => $oldParent->{$this->rootAttribute}] |
407
|
|
|
]; |
408
|
|
|
try { |
409
|
|
|
//updating necessary node new siblings |
410
|
|
|
$db->createCommand()->update( |
411
|
|
|
$class::tableName(), |
412
|
|
|
[ |
413
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('+%d', $siblingsDelta)), |
414
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('+%d', $siblingsDelta)), |
415
|
|
|
], |
416
|
|
|
$siblingsCondition |
417
|
|
|
)->execute(); |
418
|
|
|
//updating necessary node old siblings |
419
|
|
|
$db->createCommand()->update( |
420
|
|
|
$class::tableName(), |
421
|
|
|
[ |
422
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('-%d', $siblingsDelta)), |
423
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('-%d', $siblingsDelta)), |
424
|
|
|
], |
425
|
|
|
$oldSiblingsCondition |
426
|
|
|
)->execute(); |
427
|
|
|
//updating old parents |
428
|
|
|
$db->createCommand()->update( |
429
|
|
|
$class::tableName(), |
430
|
|
|
[ |
431
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('-%d', $siblingsDelta)), |
432
|
|
|
], |
433
|
|
|
$oldParentsCondition |
434
|
|
|
)->execute(); |
435
|
|
|
//updating new parents |
436
|
|
|
$db->createCommand()->update( |
437
|
|
|
$class::tableName(), |
438
|
|
|
[ |
439
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('+%d', $siblingsDelta)), |
440
|
|
|
], |
441
|
|
|
$newParentCondition |
442
|
|
|
)->execute(); |
443
|
|
|
//updating node with children |
444
|
|
|
$db->createCommand()->update( |
445
|
|
|
$class::tableName(), |
446
|
|
|
[ |
447
|
|
|
$this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)), |
|
|
|
|
448
|
|
|
$this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)), |
|
|
|
|
449
|
|
|
$this->depthAttribute => new Expression($this->depthAttribute . sprintf('%s%d', $depthOperator, $depthDelta)), |
|
|
|
|
450
|
|
|
$this->rootAttribute => $this->parent->{$this->rootAttribute} |
451
|
|
|
], |
452
|
|
|
['id' => $nodeChildren] |
453
|
|
|
)->execute(); |
454
|
|
|
$transaction->commit(); |
455
|
|
|
} catch (\Exception $e) { |
456
|
|
|
$transaction->rollBack(); |
457
|
|
|
return ['error' => $e->getMessage()]; |
458
|
|
|
} |
459
|
|
|
return true; |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Returns field set of rows to be modified while reordering |
464
|
|
|
* |
465
|
|
|
* @param array $ids |
466
|
|
|
* @return array|\yii\db\ActiveRecord[] |
467
|
|
|
*/ |
468
|
|
|
private function getLr($ids) |
469
|
|
|
{ |
470
|
|
|
$class = $this->className; |
471
|
|
|
return $class::find() |
472
|
|
|
->select(['id', $this->leftAttribute, $this->rightAttribute]) |
473
|
|
|
->where(['id' => $ids]) |
474
|
|
|
->indexBy('id') |
475
|
|
|
->asArray(true) |
476
|
|
|
->all(); |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
/** |
480
|
|
|
* Returns count of records to be modified while reordering |
481
|
|
|
* |
482
|
|
|
* @param array $condition |
483
|
|
|
* @return int|string |
484
|
|
|
*/ |
485
|
|
|
public function getCount($condition) |
486
|
|
|
{ |
487
|
|
|
$class = $this->className; |
488
|
|
|
return $class::find() |
489
|
|
|
->select(['id', $this->leftAttribute, $this->rightAttribute, $this->rootAttribute]) |
490
|
|
|
->where($condition) |
491
|
|
|
->count(); |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
|
495
|
|
|
/** |
496
|
|
|
* Returns child ids of selected node |
497
|
|
|
* |
498
|
|
|
* @param array $condition |
499
|
|
|
* @return array |
500
|
|
|
*/ |
501
|
|
|
private function getChildIds($condition) |
502
|
|
|
{ |
503
|
|
|
$class = $this->className; |
504
|
|
|
return $class::find() |
505
|
|
|
->select('id') |
506
|
|
|
->where($condition) |
507
|
|
|
->column(); |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* Applies tree root condition if multi root |
512
|
|
|
* |
513
|
|
|
* @param $condition |
514
|
|
|
*/ |
515
|
|
|
private function applyRootCondition(&$condition) |
516
|
|
|
{ |
517
|
|
|
if (false !== $this->rootAttribute) { |
518
|
|
|
$condition[] = [$this->rootAttribute => $this->node->{$this->rootAttribute}]; |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
} |
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.