This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @link https://github.com/paulzi/yii2-materialized-path |
||
4 | * @copyright Copyright (c) 2015 PaulZi <[email protected]> |
||
5 | * @license MIT (https://github.com/paulzi/yii2-materialized-path/blob/master/LICENSE) |
||
6 | */ |
||
7 | |||
8 | namespace paulzi\materializedPath; |
||
9 | |||
10 | use paulzi\sortable\SortableBehavior; |
||
11 | use Yii; |
||
12 | use yii\base\Behavior; |
||
13 | use yii\base\Exception; |
||
14 | use yii\base\NotSupportedException; |
||
15 | use yii\db\ActiveRecord; |
||
16 | use yii\db\Expression; |
||
17 | |||
18 | /** |
||
19 | * Materialized Path Behavior for Yii2 |
||
20 | * @author PaulZi <[email protected]> |
||
21 | * |
||
22 | * @property ActiveRecord $owner |
||
23 | */ |
||
24 | class MaterializedPathBehavior extends Behavior |
||
25 | { |
||
26 | const OPERATION_MAKE_ROOT = 1; |
||
27 | const OPERATION_PREPEND_TO = 2; |
||
28 | const OPERATION_APPEND_TO = 3; |
||
29 | const OPERATION_INSERT_BEFORE = 4; |
||
30 | const OPERATION_INSERT_AFTER = 5; |
||
31 | const OPERATION_DELETE_ALL = 6; |
||
32 | |||
33 | |||
34 | /** |
||
35 | * @var string |
||
36 | */ |
||
37 | public $pathAttribute = 'path'; |
||
38 | |||
39 | /** |
||
40 | * @var string |
||
41 | */ |
||
42 | public $depthAttribute = 'depth'; |
||
43 | |||
44 | /** |
||
45 | * @var string |
||
46 | */ |
||
47 | public $itemAttribute; |
||
48 | |||
49 | /** |
||
50 | * @var string|null |
||
51 | */ |
||
52 | public $treeAttribute; |
||
53 | |||
54 | /** |
||
55 | * @var array|false SortableBehavior config |
||
56 | */ |
||
57 | public $sortable = []; |
||
58 | |||
59 | /** |
||
60 | * @var string |
||
61 | */ |
||
62 | public $delimiter = '/'; |
||
63 | |||
64 | /** |
||
65 | * @var int Value of $depthAttribute for root node. |
||
66 | */ |
||
67 | public $rootDepthValue = 0; |
||
68 | |||
69 | /** |
||
70 | * @var int|null |
||
71 | */ |
||
72 | protected $operation; |
||
73 | |||
74 | /** |
||
75 | * @var ActiveRecord|self|null |
||
76 | */ |
||
77 | protected $node; |
||
78 | |||
79 | /** |
||
80 | * @var SortableBehavior |
||
81 | */ |
||
82 | protected $behavior; |
||
83 | |||
84 | /** |
||
85 | * @var bool |
||
86 | */ |
||
87 | protected $primaryKeyMode = false; |
||
88 | |||
89 | |||
90 | /** |
||
91 | * @inheritdoc |
||
92 | */ |
||
93 | 201 | public function events() |
|
94 | { |
||
95 | return [ |
||
96 | 201 | ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave', |
|
97 | ActiveRecord::EVENT_AFTER_INSERT => 'afterInsert', |
||
98 | ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave', |
||
99 | ActiveRecord::EVENT_AFTER_UPDATE => 'afterUpdate', |
||
100 | ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete', |
||
101 | ActiveRecord::EVENT_AFTER_DELETE => 'afterDelete', |
||
102 | ]; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * @param ActiveRecord $owner |
||
107 | * @throws Exception |
||
108 | */ |
||
109 | 201 | public function attach($owner) |
|
110 | { |
||
111 | 201 | parent::attach($owner); |
|
112 | 201 | if ($this->itemAttribute === null) { |
|
113 | 201 | $primaryKey = $owner->primaryKey(); |
|
114 | 201 | if (!isset($primaryKey[0])) { |
|
115 | throw new Exception('"' . $owner->className() . '" must have a primary key.'); |
||
116 | } |
||
117 | 201 | $this->itemAttribute = $primaryKey[0]; |
|
118 | 201 | $this->primaryKeyMode = true; |
|
119 | } |
||
120 | 201 | if ($this->sortable !== false) { |
|
121 | 201 | $this->behavior = Yii::createObject(array_merge( |
|
122 | [ |
||
123 | 201 | 'class' => SortableBehavior::className(), |
|
124 | 'query' => function () { |
||
125 | 87 | return $this->getSortableQuery(); |
|
126 | 201 | }, |
|
127 | ], |
||
128 | 201 | $this->sortable |
|
129 | )); |
||
130 | 201 | $owner->attachBehavior('materialized-path-sortable', $this->behavior); |
|
131 | } |
||
132 | 201 | } |
|
133 | |||
134 | /** |
||
135 | * @param int|null $depth |
||
136 | * @return \yii\db\ActiveQuery |
||
137 | */ |
||
138 | 9 | public function getParents($depth = null) |
|
139 | { |
||
140 | 9 | $path = $this->getParentPath(); |
|
141 | 9 | if ($path !== null) { |
|
142 | 9 | $paths = explode($this->delimiter, $path); |
|
143 | 9 | if (!$this->primaryKeyMode) { |
|
144 | 9 | $path = null; |
|
145 | 9 | $paths = array_map( |
|
146 | 9 | function ($value) use (&$path) { |
|
147 | 9 | return $path = ($path !== null ? $path . $this->delimiter : '') . $value; |
|
148 | 9 | }, |
|
149 | 9 | $paths |
|
150 | ); |
||
151 | } |
||
152 | 9 | if ($depth !== null) { |
|
153 | 9 | $paths = array_slice($paths, -$depth); |
|
154 | } |
||
155 | } else { |
||
156 | 3 | $paths = []; |
|
157 | } |
||
158 | |||
159 | 9 | $tableName = $this->owner->tableName(); |
|
160 | 9 | $condition = ['and']; |
|
161 | 9 | if ($this->primaryKeyMode) { |
|
162 | 6 | $condition[] = ["{$tableName}.[[{$this->itemAttribute}]]" => $paths]; |
|
163 | } else { |
||
164 | 9 | $condition[] = ["{$tableName}.[[{$this->pathAttribute}]]" => $paths]; |
|
165 | } |
||
166 | |||
167 | 9 | $query = $this->owner->find() |
|
168 | 9 | ->andWhere($condition) |
|
169 | 9 | ->andWhere($this->treeCondition()) |
|
170 | 9 | ->addOrderBy(["{$tableName}.[[{$this->pathAttribute}]]" => SORT_ASC]); |
|
171 | 9 | $query->multiple = true; |
|
172 | |||
173 | 9 | return $query; |
|
174 | } |
||
175 | |||
176 | /** |
||
177 | * @return \yii\db\ActiveQuery |
||
178 | */ |
||
179 | 6 | public function getParent() |
|
180 | { |
||
181 | 6 | $query = $this->getParents(1)->limit(1); |
|
182 | 6 | $query->multiple = false; |
|
183 | 6 | return $query; |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * @return \yii\db\ActiveQuery |
||
188 | */ |
||
189 | 3 | public function getRoot() |
|
190 | { |
||
191 | 3 | $path = explode($this->delimiter, $this->owner->getAttribute($this->pathAttribute)); |
|
192 | 3 | $path = array_shift($path); |
|
193 | 3 | $tableName = $this->owner->tableName(); |
|
194 | 3 | $query = $this->owner->find() |
|
195 | 3 | ->andWhere(["{$tableName}.[[{$this->pathAttribute}]]" => $path]) |
|
196 | 3 | ->andWhere($this->treeCondition()) |
|
197 | 3 | ->limit(1); |
|
198 | 3 | $query->multiple = false; |
|
199 | 3 | return $query; |
|
200 | } |
||
201 | |||
202 | /** |
||
203 | * @param int|null $depth |
||
204 | * @param bool $andSelf |
||
205 | * @return \yii\db\ActiveQuery |
||
206 | */ |
||
207 | 27 | public function getDescendants($depth = null, $andSelf = false) |
|
208 | { |
||
209 | 27 | $tableName = $this->owner->tableName(); |
|
210 | 27 | $path = $this->owner->getAttribute($this->pathAttribute); |
|
211 | 27 | $query = $this->owner->find() |
|
212 | 27 | ->andWhere(['like', "{$tableName}.[[{$this->pathAttribute}]]", $this->getLike($path), false]); |
|
213 | |||
214 | 27 | if ($andSelf) { |
|
215 | 9 | $query->orWhere(["{$tableName}.[[{$this->pathAttribute}]]" => $path]); |
|
216 | } |
||
217 | |||
218 | 27 | if ($depth !== null) { |
|
219 | 21 | $query->andWhere(['<=', "{$tableName}.[[{$this->depthAttribute}]]", $this->owner->getAttribute($this->depthAttribute) + $depth]); |
|
220 | } |
||
221 | |||
222 | 27 | $orderBy = []; |
|
223 | 27 | $orderBy["{$tableName}.[[{$this->depthAttribute}]]"] = SORT_ASC; |
|
224 | 27 | View Code Duplication | if ($this->sortable !== false) { |
0 ignored issues
–
show
|
|||
225 | 27 | $orderBy["{$tableName}.[[{$this->behavior->sortAttribute}]]"] = SORT_ASC; |
|
226 | } |
||
227 | 27 | $orderBy["{$tableName}.[[{$this->itemAttribute}]]"] = SORT_ASC; |
|
228 | |||
229 | $query |
||
230 | 27 | ->andWhere($this->treeCondition()) |
|
231 | 27 | ->addOrderBy($orderBy); |
|
232 | 27 | $query->multiple = true; |
|
233 | |||
234 | 27 | return $query; |
|
235 | } |
||
236 | |||
237 | /** |
||
238 | * @return \yii\db\ActiveQuery |
||
239 | */ |
||
240 | 12 | public function getChildren() |
|
241 | { |
||
242 | 12 | return $this->getDescendants(1); |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * @param int|null $depth |
||
247 | * @return \yii\db\ActiveQuery |
||
248 | */ |
||
249 | 3 | public function getLeaves($depth = null) |
|
250 | { |
||
251 | 3 | $tableName = $this->owner->tableName(); |
|
252 | $condition = [ |
||
253 | 3 | 'and', |
|
254 | 3 | ['like', "leaves.[[{$this->pathAttribute}]]", new Expression($this->concatExpression(["{$tableName}.[[{$this->pathAttribute}]]", ':delimiter']), [':delimiter' => $this->delimiter . '%'])], |
|
255 | ]; |
||
256 | |||
257 | 3 | if ($this->treeAttribute !== null) { |
|
258 | 3 | $condition[] = ["leaves.[[{$this->treeAttribute}]]" => new Expression("{$tableName}.[[{$this->treeAttribute}]]")]; |
|
259 | } |
||
260 | |||
261 | 3 | $query = $this->getDescendants($depth) |
|
262 | 3 | ->leftJoin("{$tableName} leaves", $condition) |
|
263 | 3 | ->andWhere(["leaves.[[{$this->pathAttribute}]]" => null]); |
|
264 | 3 | $query->multiple = true; |
|
265 | 3 | return $query; |
|
266 | } |
||
267 | |||
268 | /** |
||
269 | * @return \yii\db\ActiveQuery |
||
270 | * @throws NotSupportedException |
||
271 | */ |
||
272 | 3 | View Code Duplication | public function getPrev() |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
273 | { |
||
274 | 3 | if ($this->sortable === false) { |
|
275 | throw new NotSupportedException('prev() not allow if not set sortable'); |
||
276 | } |
||
277 | 3 | $tableName = $this->owner->tableName(); |
|
278 | 3 | $query = $this->owner->find() |
|
279 | 3 | ->andWhere(['like', "{$tableName}.[[{$this->pathAttribute}]]", $this->getLike($this->getParentPath()), false]) |
|
0 ignored issues
–
show
It seems like
$this->getParentPath() targeting paulzi\materializedPath\...havior::getParentPath() can also be of type array or null ; however, paulzi\materializedPath\...PathBehavior::getLike() does only seem to accept string , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
280 | 3 | ->andWhere(["{$tableName}.[[{$this->depthAttribute}]]" => $this->owner->getAttribute($this->depthAttribute)]) |
|
281 | 3 | ->andWhere(['<', "{$tableName}.[[{$this->behavior->sortAttribute}]]", $this->owner->getSortablePosition()]) |
|
282 | 3 | ->andWhere($this->treeCondition()) |
|
283 | 3 | ->orderBy(["{$tableName}.[[{$this->behavior->sortAttribute}]]" => SORT_DESC]) |
|
284 | 3 | ->limit(1); |
|
285 | 3 | $query->multiple = false; |
|
286 | 3 | return $query; |
|
287 | } |
||
288 | |||
289 | /** |
||
290 | * @return \yii\db\ActiveQuery |
||
291 | * @throws NotSupportedException |
||
292 | */ |
||
293 | 6 | View Code Duplication | public function getNext() |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
294 | { |
||
295 | 6 | if ($this->sortable === false) { |
|
296 | throw new NotSupportedException('prev() not allow if not set sortable'); |
||
297 | } |
||
298 | 6 | $tableName = $this->owner->tableName(); |
|
299 | 6 | $query = $this->owner->find() |
|
300 | 6 | ->andWhere(['like', "{$tableName}.[[{$this->pathAttribute}]]", $this->getLike($this->getParentPath()), false]) |
|
0 ignored issues
–
show
It seems like
$this->getParentPath() targeting paulzi\materializedPath\...havior::getParentPath() can also be of type array or null ; however, paulzi\materializedPath\...PathBehavior::getLike() does only seem to accept string , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
301 | 6 | ->andWhere(["{$tableName}.[[{$this->depthAttribute}]]" => $this->owner->getAttribute($this->depthAttribute)]) |
|
302 | 6 | ->andWhere(['>', "{$tableName}.[[{$this->behavior->sortAttribute}]]", $this->owner->getSortablePosition()]) |
|
303 | 6 | ->andWhere($this->treeCondition()) |
|
304 | 6 | ->orderBy(["{$tableName}.[[{$this->behavior->sortAttribute}]]" => SORT_ASC]) |
|
305 | 6 | ->limit(1); |
|
306 | 6 | $query->multiple = false; |
|
307 | 6 | return $query; |
|
308 | } |
||
309 | |||
310 | /** |
||
311 | * Returns all sibilings of node. |
||
312 | * |
||
313 | * @param bool $andSelf = false Include self node into result. |
||
314 | * @return \yii\db\ActiveQuery |
||
315 | */ |
||
316 | public function getSiblings($andSelf = false) |
||
317 | { |
||
318 | $tableName = $this->owner->tableName(); |
||
319 | $path = $this->getParentPath(); |
||
320 | $like = strtr($path . $this->delimiter, ['%' => '\%', '_' => '\_', '\\' => '\\\\']); |
||
321 | |||
322 | $query = $this->owner->find() |
||
323 | ->andWhere(['like', "{$tableName}.[[{$this->pathAttribute}]]", $like . '%', false]) |
||
324 | ->andWhere(['<=', "{$tableName}.[[{$this->depthAttribute}]]", $this->owner->{$this->depthAttribute}]); |
||
325 | |||
326 | if (!$andSelf) { |
||
327 | $query->andWhere(["!=", "{$tableName}.[[{$this->itemAttribute}]]", $this->owner->{$this->itemAttribute}]); |
||
328 | } |
||
329 | |||
330 | $orderBy = []; |
||
331 | $orderBy["{$tableName}.[[{$this->depthAttribute}]]"] = SORT_ASC; |
||
332 | View Code Duplication | if ($this->sortable !== false) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
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. ![]() |
|||
333 | $orderBy["{$tableName}.[[{$this->behavior->sortAttribute}]]"] = SORT_ASC; |
||
334 | } |
||
335 | $orderBy["{$tableName}.[[{$this->itemAttribute}]]"] = SORT_ASC; |
||
336 | |||
337 | $query |
||
338 | ->andWhere($this->treeCondition()) |
||
339 | ->addOrderBy($orderBy); |
||
340 | $query->multiple = true; |
||
341 | return $query; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * @param bool $asArray = false |
||
346 | * @return null|string|array |
||
347 | */ |
||
348 | 66 | public function getParentPath($asArray = false) |
|
349 | { |
||
350 | 66 | return static::getParentPathInternal($this->owner->getAttribute($this->pathAttribute), $this->delimiter, $asArray); |
|
351 | } |
||
352 | |||
353 | /** |
||
354 | * Populate children relations for self and all descendants |
||
355 | * |
||
356 | * @param int $depth = null |
||
357 | * @param string|array $with = null |
||
358 | * @return static |
||
359 | */ |
||
360 | 3 | public function populateTree($depth = null, $with = null) |
|
361 | { |
||
362 | /** @var ActiveRecord[]|static[] $nodes */ |
||
363 | 3 | $query = $this->getDescendants($depth); |
|
364 | 3 | if ($with) { |
|
365 | $query->with($with); |
||
366 | } |
||
367 | 3 | $nodes = $query->all(); |
|
368 | |||
369 | 3 | $relates = []; |
|
370 | 3 | foreach ($nodes as $node) { |
|
371 | 3 | $path = $node->getParentPath(true); |
|
372 | 3 | $key = array_pop($path); |
|
373 | 3 | if (!isset($relates[$key])) { |
|
374 | 3 | $relates[$key] = []; |
|
375 | } |
||
376 | 3 | $relates[$key][] = $node; |
|
377 | } |
||
378 | |||
379 | 3 | $ownerDepth = $this->owner->getAttribute($this->depthAttribute); |
|
380 | 3 | $nodes[] = $this->owner; |
|
381 | 3 | foreach ($nodes as $node) { |
|
382 | 3 | $key = $node->getAttribute($this->itemAttribute); |
|
383 | 3 | if (isset($relates[$key])) { |
|
384 | 3 | $node->populateRelation('children', $relates[$key]); |
|
385 | 3 | } elseif ($depth === null || $ownerDepth + $depth > $node->getAttribute($this->depthAttribute)) { |
|
386 | 3 | $node->populateRelation('children', []); |
|
387 | } |
||
388 | } |
||
389 | |||
390 | 3 | return $this->owner; |
|
391 | } |
||
392 | |||
393 | /** |
||
394 | * @return bool |
||
395 | */ |
||
396 | 72 | public function isRoot() |
|
397 | { |
||
398 | 72 | return count(explode($this->delimiter, $this->owner->getAttribute($this->pathAttribute))) === 1; |
|
399 | } |
||
400 | |||
401 | /** |
||
402 | * @param ActiveRecord $node |
||
403 | * @return bool |
||
404 | */ |
||
405 | 96 | public function isChildOf($node) |
|
406 | { |
||
407 | 96 | if ($node->getIsNewRecord()) { |
|
408 | 30 | return false; |
|
409 | } |
||
410 | 66 | $nodePath = $node->getAttribute($this->pathAttribute) . $this->delimiter; |
|
411 | 66 | $result = substr($this->owner->getAttribute($this->pathAttribute), 0, strlen($nodePath)) === $nodePath; |
|
412 | |||
413 | 66 | if ($result && $this->treeAttribute !== null) { |
|
414 | 9 | $result = $this->owner->getAttribute($this->treeAttribute) === $node->getAttribute($this->treeAttribute); |
|
415 | } |
||
416 | |||
417 | 66 | return $result; |
|
418 | } |
||
419 | |||
420 | /** |
||
421 | * @return bool |
||
422 | */ |
||
423 | 3 | public function isLeaf() |
|
424 | { |
||
425 | 3 | return count($this->owner->children) === 0; |
|
426 | } |
||
427 | |||
428 | /** |
||
429 | * @return ActiveRecord |
||
430 | */ |
||
431 | 6 | public function makeRoot() |
|
432 | { |
||
433 | 6 | $this->operation = self::OPERATION_MAKE_ROOT; |
|
434 | 6 | return $this->owner; |
|
435 | } |
||
436 | |||
437 | /** |
||
438 | * @param ActiveRecord $node |
||
439 | * @return ActiveRecord |
||
440 | */ |
||
441 | 33 | public function prependTo($node) |
|
442 | { |
||
443 | 33 | $this->operation = self::OPERATION_PREPEND_TO; |
|
444 | 33 | $this->node = $node; |
|
445 | 33 | return $this->owner; |
|
446 | } |
||
447 | |||
448 | /** |
||
449 | * @param ActiveRecord $node |
||
450 | * @return ActiveRecord |
||
451 | */ |
||
452 | 33 | public function appendTo($node) |
|
453 | { |
||
454 | 33 | $this->operation = self::OPERATION_APPEND_TO; |
|
455 | 33 | $this->node = $node; |
|
456 | 33 | return $this->owner; |
|
457 | } |
||
458 | |||
459 | /** |
||
460 | * @param ActiveRecord $node |
||
461 | * @return ActiveRecord |
||
462 | */ |
||
463 | 30 | public function insertBefore($node) |
|
464 | { |
||
465 | 30 | $this->operation = self::OPERATION_INSERT_BEFORE; |
|
466 | 30 | $this->node = $node; |
|
467 | 30 | return $this->owner; |
|
468 | } |
||
469 | |||
470 | /** |
||
471 | * @param ActiveRecord $node |
||
472 | * @return ActiveRecord |
||
473 | */ |
||
474 | 30 | public function insertAfter($node) |
|
475 | { |
||
476 | 30 | $this->operation = self::OPERATION_INSERT_AFTER; |
|
477 | 30 | $this->node = $node; |
|
478 | 30 | return $this->owner; |
|
479 | } |
||
480 | |||
481 | /** |
||
482 | * Need for paulzi/auto-tree |
||
483 | */ |
||
484 | public function preDeleteWithChildren() |
||
485 | { |
||
486 | $this->operation = self::OPERATION_DELETE_ALL; |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * @return bool|int |
||
491 | * @throws \Exception |
||
492 | * @throws \yii\db\Exception |
||
493 | */ |
||
494 | 9 | public function deleteWithChildren() |
|
495 | { |
||
496 | 9 | $this->operation = self::OPERATION_DELETE_ALL; |
|
497 | 9 | if (!$this->owner->isTransactional(ActiveRecord::OP_DELETE)) { |
|
498 | $transaction = $this->owner->getDb()->beginTransaction(); |
||
499 | try { |
||
500 | $result = $this->deleteWithChildrenInternal(); |
||
501 | if ($result === false) { |
||
502 | $transaction->rollBack(); |
||
503 | } else { |
||
504 | $transaction->commit(); |
||
505 | } |
||
506 | return $result; |
||
507 | } catch (\Exception $e) { |
||
508 | $transaction->rollBack(); |
||
509 | throw $e; |
||
510 | } |
||
511 | } else { |
||
512 | 9 | $result = $this->deleteWithChildrenInternal(); |
|
513 | } |
||
514 | 6 | return $result; |
|
515 | } |
||
516 | |||
517 | /** |
||
518 | * @param bool $middle |
||
519 | * @return int |
||
520 | */ |
||
521 | 3 | public function reorderChildren($middle = true) |
|
522 | { |
||
523 | /** @var ActiveRecord|SortableBehavior $item */ |
||
524 | 3 | $item = count($this->owner->children) > 0 ? $this->owner->children[0] : null; |
|
525 | 3 | if ($item) { |
|
526 | 3 | return $item->reorder($middle); |
|
0 ignored issues
–
show
The method
reorder does only exist in paulzi\sortable\SortableBehavior , but not in yii\db\ActiveRecord .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
527 | } else { |
||
528 | return 0; |
||
529 | } |
||
530 | } |
||
531 | |||
532 | /** |
||
533 | * @throws Exception |
||
534 | * @throws NotSupportedException |
||
535 | */ |
||
536 | 138 | public function beforeSave() |
|
537 | { |
||
538 | 138 | if ($this->node !== null && !$this->node->getIsNewRecord()) { |
|
0 ignored issues
–
show
The method
getIsNewRecord does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
539 | 108 | $this->node->refresh(); |
|
0 ignored issues
–
show
The method
refresh does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
540 | } |
||
541 | |||
542 | 138 | switch ($this->operation) { |
|
543 | 138 | case self::OPERATION_MAKE_ROOT: |
|
544 | 6 | $this->makeRootInternal(); |
|
545 | |||
546 | 6 | break; |
|
547 | 132 | case self::OPERATION_PREPEND_TO: |
|
548 | 33 | $this->insertIntoInternal(false); |
|
549 | |||
550 | 21 | break; |
|
551 | 99 | case self::OPERATION_APPEND_TO: |
|
552 | 33 | $this->insertIntoInternal(true); |
|
553 | |||
554 | 21 | break; |
|
555 | 66 | case self::OPERATION_INSERT_BEFORE: |
|
556 | 30 | $this->insertNearInternal(false); |
|
557 | |||
558 | 21 | break; |
|
559 | |||
560 | 36 | case self::OPERATION_INSERT_AFTER: |
|
561 | 30 | $this->insertNearInternal(true); |
|
562 | |||
563 | 18 | break; |
|
564 | |||
565 | default: |
||
566 | 6 | if ($this->owner->getIsNewRecord()) { |
|
567 | 3 | throw new NotSupportedException('Method "' . $this->owner->className() . '::insert" is not supported for inserting new nodes.'); |
|
568 | } |
||
569 | |||
570 | 3 | $item = $this->owner->getAttribute($this->itemAttribute); |
|
571 | 3 | $path = $this->getParentPath(); |
|
572 | 3 | $this->owner->setAttribute($this->pathAttribute, ($path !== null ? $path . $this->delimiter : null) . $item); |
|
573 | } |
||
574 | 90 | } |
|
575 | |||
576 | /** |
||
577 | * @throws Exception |
||
578 | */ |
||
579 | 33 | public function afterInsert() |
|
580 | { |
||
581 | 33 | if ($this->operation === self::OPERATION_MAKE_ROOT && $this->treeAttribute !== null && $this->owner->getAttribute($this->treeAttribute) === null) { |
|
582 | 3 | $id = $this->getPrimaryKeyValue(); |
|
583 | 3 | $this->owner->setAttribute($this->treeAttribute, $id); |
|
584 | |||
585 | 3 | $primaryKey = $this->owner->primaryKey(); |
|
586 | 3 | View Code Duplication | if (!isset($primaryKey[0])) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
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. ![]() |
|||
587 | throw new Exception('"' . $this->owner->className() . '" must have a primary key.'); |
||
588 | } |
||
589 | |||
590 | 3 | $this->owner->updateAll([$this->treeAttribute => $id], [$primaryKey[0] => $id]); |
|
591 | } |
||
592 | 33 | if ($this->owner->getAttribute($this->pathAttribute) === null) { |
|
593 | 33 | $primaryKey = $this->owner->primaryKey(); |
|
594 | 33 | View Code Duplication | if (!isset($primaryKey[0])) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
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. ![]() |
|||
595 | throw new Exception('"' . $this->owner->className() . '" must have a primary key.'); |
||
596 | } |
||
597 | 33 | $id = $this->getPrimaryKeyValue(); |
|
598 | 33 | if ($this->operation === self::OPERATION_MAKE_ROOT) { |
|
599 | 3 | $path = $id; |
|
600 | } else { |
||
601 | 30 | if ($this->operation === self::OPERATION_INSERT_BEFORE || $this->operation === self::OPERATION_INSERT_AFTER) { |
|
602 | 18 | $path = $this->node->getParentPath(); |
|
0 ignored issues
–
show
The method
getParentPath does only exist in paulzi\materializedPath\MaterializedPathBehavior , but not in yii\db\ActiveRecord .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
603 | } else { |
||
604 | 12 | $path = $this->node->getAttribute($this->pathAttribute); |
|
0 ignored issues
–
show
The method
getAttribute does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
605 | } |
||
606 | 30 | $path = $path . $this->delimiter . $id; |
|
607 | } |
||
608 | 33 | $this->owner->setAttribute($this->pathAttribute, $path); |
|
609 | 33 | $this->owner->updateAll([$this->pathAttribute => $path], [$primaryKey[0] => $id]); |
|
610 | } |
||
611 | 33 | $this->operation = null; |
|
612 | 33 | $this->node = null; |
|
613 | 33 | } |
|
614 | |||
615 | /** |
||
616 | * @param \yii\db\AfterSaveEvent $event |
||
617 | */ |
||
618 | 57 | public function afterUpdate($event) |
|
619 | { |
||
620 | 57 | $this->moveNode($event->changedAttributes); |
|
621 | 57 | $this->operation = null; |
|
622 | 57 | $this->node = null; |
|
623 | 57 | } |
|
624 | |||
625 | /** |
||
626 | * @param \yii\base\ModelEvent $event |
||
627 | * @throws Exception |
||
628 | */ |
||
629 | 18 | public function beforeDelete($event) |
|
630 | { |
||
631 | 18 | if ($this->owner->getIsNewRecord()) { |
|
632 | 6 | throw new Exception('Can not delete a node when it is new record.'); |
|
633 | } |
||
634 | 12 | if ($this->isRoot() && $this->operation !== self::OPERATION_DELETE_ALL) { |
|
635 | 3 | throw new Exception('Method "'. $this->owner->className() . '::delete" is not supported for deleting root nodes.'); |
|
636 | } |
||
637 | 9 | $this->owner->refresh(); |
|
638 | 9 | if ($this->operation !== static::OPERATION_DELETE_ALL && !$this->primaryKeyMode) { |
|
639 | /** @var self $parent */ |
||
640 | 3 | $parent =$this->getParent()->one(); |
|
641 | 3 | $slugs1 = $parent->getChildren() |
|
642 | 3 | ->andWhere(['<>', $this->itemAttribute, $this->owner->getAttribute($this->itemAttribute)]) |
|
643 | 3 | ->select([$this->itemAttribute]) |
|
644 | 3 | ->column(); |
|
645 | 3 | $slugs2 = $this->getChildren() |
|
646 | 3 | ->select([$this->itemAttribute]) |
|
647 | 3 | ->column(); |
|
648 | 3 | if (array_intersect($slugs1, $slugs2)) { |
|
649 | $event->isValid = false; |
||
650 | } |
||
651 | } |
||
652 | 9 | } |
|
653 | |||
654 | /** |
||
655 | * |
||
656 | */ |
||
657 | 9 | public function afterDelete() |
|
658 | { |
||
659 | 9 | if ($this->operation !== static::OPERATION_DELETE_ALL) { |
|
660 | 3 | foreach ($this->owner->children as $child) { |
|
661 | /** @var self $child */ |
||
662 | 3 | if ($this->owner->next === null) { |
|
663 | $child->appendTo($this->owner->parent)->save(); |
||
664 | } else { |
||
665 | 3 | $child->insertBefore($this->owner->next)->save(); |
|
666 | } |
||
667 | } |
||
668 | } |
||
669 | 9 | $this->operation = null; |
|
670 | 9 | $this->node = null; |
|
671 | 9 | } |
|
672 | |||
673 | |||
674 | /** |
||
675 | * @return string |
||
676 | */ |
||
677 | 36 | protected function getPrimaryKeyValue() |
|
678 | { |
||
679 | 36 | $result = $this->owner->getPrimaryKey(true); |
|
680 | 36 | return reset($result); |
|
681 | } |
||
682 | |||
683 | /** |
||
684 | * @param bool $forInsertNear |
||
685 | * @throws Exception |
||
686 | */ |
||
687 | 126 | protected function checkNode($forInsertNear = false) |
|
688 | { |
||
689 | 126 | if ($forInsertNear && $this->node->isRoot()) { |
|
0 ignored issues
–
show
The method
isRoot does only exist in paulzi\materializedPath\MaterializedPathBehavior , but not in yii\db\ActiveRecord .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
690 | 9 | throw new Exception('Can not move a node before/after root.'); |
|
691 | } |
||
692 | 117 | if ($this->node->getIsNewRecord()) { |
|
0 ignored issues
–
show
The method
getIsNewRecord does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
693 | 12 | throw new Exception('Can not move a node when the target node is new record.'); |
|
694 | } |
||
695 | |||
696 | 105 | if ($this->owner->equals($this->node)) { |
|
0 ignored issues
–
show
It seems like
$this->node can also be of type null or object<paulzi\materializ...terializedPathBehavior> ; however, yii\db\ActiveRecord::equals() does only seem to accept object<yii\db\ActiveRecord> , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
697 | 12 | throw new Exception('Can not move a node when the target node is same.'); |
|
698 | } |
||
699 | |||
700 | 93 | if ($this->node->isChildOf($this->owner)) { |
|
0 ignored issues
–
show
The method
isChildOf does only exist in paulzi\materializedPath\MaterializedPathBehavior , but not in yii\db\ActiveRecord .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
701 | 12 | throw new Exception('Can not move a node when the target node is child.'); |
|
702 | } |
||
703 | 81 | } |
|
704 | |||
705 | /** |
||
706 | * Make root operation internal handler |
||
707 | */ |
||
708 | 6 | protected function makeRootInternal() |
|
709 | { |
||
710 | 6 | $item = $this->owner->getAttribute($this->itemAttribute); |
|
711 | |||
712 | 6 | if ($item !== null) { |
|
713 | 6 | $this->owner->setAttribute($this->pathAttribute, $item); |
|
714 | } |
||
715 | |||
716 | 6 | if ($this->sortable !== false) { |
|
717 | 6 | $this->owner->setAttribute($this->behavior->sortAttribute, 0); |
|
718 | } |
||
719 | |||
720 | 6 | if ($this->treeAttribute !== null && !$this->owner->getDirtyAttributes([$this->treeAttribute]) && !$this->owner->getIsNewRecord()) { |
|
721 | 3 | $this->owner->setAttribute($this->treeAttribute, $this->getPrimaryKeyValue()); |
|
722 | } |
||
723 | |||
724 | 6 | $this->owner->setAttribute($this->depthAttribute, $this->rootDepthValue); |
|
725 | 6 | } |
|
726 | |||
727 | /** |
||
728 | * Append to operation internal handler |
||
729 | * @param bool $append |
||
730 | * @throws Exception |
||
731 | */ |
||
732 | 66 | View Code Duplication | protected function insertIntoInternal($append) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
733 | { |
||
734 | 66 | $this->checkNode(false); |
|
735 | 42 | $item = $this->owner->getAttribute($this->itemAttribute); |
|
736 | |||
737 | 42 | if ($item !== null) { |
|
738 | 42 | $path = $this->node->getAttribute($this->pathAttribute); |
|
0 ignored issues
–
show
The method
getAttribute does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
739 | 42 | $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item); |
|
740 | } |
||
741 | |||
742 | 42 | $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute) + 1); |
|
743 | |||
744 | 42 | if ($this->treeAttribute !== null) { |
|
745 | 42 | $this->owner->setAttribute($this->treeAttribute, $this->node->getAttribute($this->treeAttribute)); |
|
746 | } |
||
747 | |||
748 | 42 | if ($this->sortable !== false) { |
|
749 | 42 | if ($append) { |
|
750 | 21 | $this->behavior->moveLast(); |
|
751 | } else { |
||
752 | 21 | $this->behavior->moveFirst(); |
|
753 | } |
||
754 | } |
||
755 | 42 | } |
|
756 | |||
757 | /** |
||
758 | * Insert operation internal handler |
||
759 | * @param bool $forward |
||
760 | * @throws Exception |
||
761 | */ |
||
762 | 60 | View Code Duplication | protected function insertNearInternal($forward) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
763 | { |
||
764 | 60 | $this->checkNode(true); |
|
765 | 39 | $item = $this->owner->getAttribute($this->itemAttribute); |
|
766 | |||
767 | 39 | if ($item !== null) { |
|
768 | 39 | $path = $this->node->getParentPath(); |
|
0 ignored issues
–
show
The method
getParentPath does only exist in paulzi\materializedPath\MaterializedPathBehavior , but not in yii\db\ActiveRecord .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
769 | 39 | $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item); |
|
770 | } |
||
771 | |||
772 | 39 | $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute)); |
|
0 ignored issues
–
show
The method
getAttribute does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
773 | |||
774 | 39 | if ($this->treeAttribute !== null) { |
|
775 | 39 | $this->owner->setAttribute($this->treeAttribute, $this->node->getAttribute($this->treeAttribute)); |
|
776 | } |
||
777 | |||
778 | 39 | if ($this->sortable !== false) { |
|
779 | 39 | if ($forward) { |
|
780 | 18 | $this->behavior->moveAfter($this->node); |
|
0 ignored issues
–
show
It seems like
$this->node can also be of type null or object<paulzi\materializ...terializedPathBehavior> ; however, paulzi\sortable\SortableBehavior::moveAfter() does only seem to accept object<yii\db\ActiveRecord> , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
781 | } else { |
||
782 | 21 | $this->behavior->moveBefore($this->node); |
|
0 ignored issues
–
show
It seems like
$this->node can also be of type null or object<paulzi\materializ...terializedPathBehavior> ; however, paulzi\sortable\SortableBehavior::moveBefore() does only seem to accept object<yii\db\ActiveRecord> , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
783 | } |
||
784 | } |
||
785 | 39 | } |
|
786 | |||
787 | /** |
||
788 | * @return int |
||
789 | */ |
||
790 | 9 | protected function deleteWithChildrenInternal() |
|
791 | { |
||
792 | 9 | if (!$this->owner->beforeDelete()) { |
|
793 | return false; |
||
794 | } |
||
795 | 6 | $result = $this->owner->deleteAll($this->getDescendants(null, true)->where); |
|
796 | 6 | $this->owner->setOldAttributes(null); |
|
797 | 6 | $this->owner->afterDelete(); |
|
798 | 6 | return $result; |
|
799 | } |
||
800 | |||
801 | /** |
||
802 | * @param array $changedAttributes |
||
803 | * @throws Exception |
||
804 | */ |
||
805 | 57 | protected function moveNode($changedAttributes) |
|
806 | { |
||
807 | 57 | $path = isset($changedAttributes[$this->pathAttribute]) ? $changedAttributes[$this->pathAttribute] : $this->owner->getAttribute($this->pathAttribute); |
|
808 | 57 | $update = []; |
|
809 | $condition = [ |
||
810 | 57 | 'and', |
|
811 | 57 | ['like', "[[{$this->pathAttribute}]]", $this->getLike($path), false], |
|
812 | ]; |
||
813 | 57 | if ($this->treeAttribute !== null) { |
|
814 | 54 | $tree = isset($changedAttributes[$this->treeAttribute]) ? $changedAttributes[$this->treeAttribute] : $this->owner->getAttribute($this->treeAttribute); |
|
815 | 54 | $condition[] = [$this->treeAttribute => $tree]; |
|
816 | } |
||
817 | 57 | $params = []; |
|
818 | |||
819 | 57 | if (isset($changedAttributes[$this->pathAttribute])) { |
|
820 | 30 | $substringExpr = $this->substringExpression( |
|
821 | 30 | "[[{$this->pathAttribute}]]", |
|
822 | 30 | 'LENGTH(:pathOld) + 1', |
|
823 | 30 | "LENGTH([[{$this->pathAttribute}]]) - LENGTH(:pathOld)" |
|
824 | ); |
||
825 | 30 | $update[$this->pathAttribute] = new Expression($this->concatExpression([':pathNew', $substringExpr])); |
|
826 | 30 | $params[':pathOld'] = $path; |
|
827 | 30 | $params[':pathNew'] = $this->owner->getAttribute($this->pathAttribute); |
|
828 | } |
||
829 | |||
830 | 57 | if ($this->treeAttribute !== null && isset($changedAttributes[$this->treeAttribute])) { |
|
831 | 15 | $update[$this->treeAttribute] = $this->owner->getAttribute($this->treeAttribute); |
|
832 | } |
||
833 | |||
834 | 57 | if ($this->depthAttribute !== null && isset($changedAttributes[$this->depthAttribute])) { |
|
835 | 30 | $delta = $this->owner->getAttribute($this->depthAttribute) - $changedAttributes[$this->depthAttribute]; |
|
836 | 30 | $update[$this->depthAttribute] = new Expression("[[{$this->depthAttribute}]]" . sprintf('%+d', $delta)); |
|
837 | } |
||
838 | |||
839 | 57 | if (!empty($update)) { |
|
840 | 30 | $this->owner->updateAll($update, $condition, $params); |
|
841 | } |
||
842 | 57 | } |
|
843 | |||
844 | /** |
||
845 | * @param string $path |
||
846 | * @param string $delimiter |
||
847 | * @param bool $asArray = false |
||
848 | * @return null|string|array |
||
849 | */ |
||
850 | 66 | protected static function getParentPathInternal($path, $delimiter, $asArray = false) |
|
851 | { |
||
852 | 66 | $path = explode($delimiter, $path); |
|
853 | 66 | array_pop($path); |
|
854 | 66 | if ($asArray) { |
|
855 | 6 | return $path; |
|
856 | } |
||
857 | 63 | return count($path) > 0 ? implode($delimiter, $path) : null; |
|
858 | } |
||
859 | |||
860 | /** |
||
861 | * @return array |
||
862 | */ |
||
863 | 123 | protected function treeCondition() |
|
864 | { |
||
865 | 123 | $tableName = $this->owner->tableName(); |
|
866 | 123 | if ($this->treeAttribute === null) { |
|
867 | 123 | return []; |
|
868 | } else { |
||
869 | 123 | return ["{$tableName}.[[{$this->treeAttribute}]]" => $this->owner->getAttribute($this->treeAttribute)]; |
|
870 | } |
||
871 | } |
||
872 | |||
873 | /** |
||
874 | * @return \yii\db\ActiveQuery |
||
875 | */ |
||
876 | 87 | protected function getSortableQuery() |
|
877 | { |
||
878 | 87 | switch ($this->operation) { |
|
879 | 87 | case self::OPERATION_PREPEND_TO: |
|
880 | 66 | case self::OPERATION_APPEND_TO: |
|
881 | 42 | $path = $this->node->getAttribute($this->pathAttribute); |
|
0 ignored issues
–
show
The method
getAttribute does only exist in yii\db\ActiveRecord , but not in paulzi\materializedPath\MaterializedPathBehavior .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
882 | 42 | $depth = $this->node->getAttribute($this->depthAttribute) + 1; |
|
883 | 42 | break; |
|
884 | |||
885 | 45 | case self::OPERATION_INSERT_BEFORE: |
|
886 | 24 | case self::OPERATION_INSERT_AFTER: |
|
887 | 39 | $path = $this->node->getParentPath(); |
|
0 ignored issues
–
show
The method
getParentPath does only exist in paulzi\materializedPath\MaterializedPathBehavior , but not in yii\db\ActiveRecord .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
888 | 39 | $depth = $this->node->getAttribute($this->depthAttribute); |
|
889 | 39 | break; |
|
890 | |||
891 | default: |
||
892 | 6 | $path = $this->getParentPath(); |
|
893 | 6 | $depth = $this->owner->getAttribute($this->depthAttribute); |
|
894 | } |
||
895 | 87 | $tableName = $this->owner->tableName(); |
|
896 | |||
897 | 87 | return $this->owner->find() |
|
898 | 87 | ->andWhere($this->treeCondition()) |
|
899 | 87 | ->andWhere($path !== null ? ['like', "{$tableName}.[[{$this->pathAttribute}]]", $this->getLike($path), false] : '1=0') |
|
900 | 87 | ->andWhere(["{$tableName}.[[{$this->depthAttribute}]]" => $depth]); |
|
901 | } |
||
902 | |||
903 | /** |
||
904 | * @param string $path |
||
905 | * @return string |
||
906 | */ |
||
907 | 117 | protected function getLike($path) |
|
908 | { |
||
909 | 117 | return strtr($path . $this->delimiter, ['%' => '\%', '_' => '\_', '\\' => '\\\\']) . '%'; |
|
910 | } |
||
911 | |||
912 | /** |
||
913 | * @param array $items |
||
914 | * @return string |
||
915 | */ |
||
916 | 33 | protected function concatExpression($items) |
|
917 | { |
||
918 | 33 | if ($this->owner->getDb()->driverName === 'sqlite' || $this->owner->getDb()->driverName === 'pgsql') { |
|
919 | 22 | return implode(' || ', $items); |
|
920 | } |
||
921 | 11 | return 'CONCAT(' . implode(',', $items) . ')'; |
|
922 | } |
||
923 | |||
924 | 30 | protected function substringExpression($string, $from, $length) |
|
925 | { |
||
926 | 30 | if ($this->owner->getDb()->driverName === 'sqlite') { |
|
927 | 10 | return "SUBSTR({$string}, {$from}, {$length})"; |
|
928 | } |
||
929 | 20 | return "SUBSTRING({$string}, {$from}, {$length})"; |
|
930 | } |
||
931 | } |
||
932 |
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.