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 | /** |
||
4 | * _ __ __ _____ _____ ___ ____ _____ |
||
5 | * | | / // // ___//_ _// || __||_ _| |
||
6 | * | |/ // /(__ ) / / / /| || | | | |
||
7 | * |___//_//____/ /_/ /_/ |_||_| |_| |
||
8 | * @link https://vistart.me/ |
||
9 | * @copyright Copyright (c) 2016 - 2017 vistart |
||
10 | * @license https://vistart.me/license/ |
||
11 | */ |
||
12 | |||
13 | namespace rhosocial\base\models\traits; |
||
14 | |||
15 | use Yii; |
||
16 | use yii\base\ModelEvent; |
||
17 | use yii\base\InvalidConfigException; |
||
18 | use yii\base\InvalidParamException; |
||
19 | use yii\db\ActiveQuery; |
||
20 | use yii\db\IntegrityException; |
||
21 | |||
22 | /** |
||
23 | * This trait is designed for the model who contains parent. |
||
24 | * |
||
25 | * The BlameableTrait use this trait by default. If you want to use this trait |
||
26 | * into seperate model, please call the `initSelfBlameableEvents()` method in |
||
27 | * `init()` method, like following: |
||
28 | * ```php |
||
29 | * public function init() |
||
30 | * { |
||
31 | * $this->initSelfBlameableEvents(); // put it before parent call. |
||
32 | * parent::init(); |
||
33 | * } |
||
34 | * ``` |
||
35 | * |
||
36 | * The default reference ID attribute is `guid`. You can specify another attribute |
||
37 | * in [[__construct()]] method. |
||
38 | * |
||
39 | * We strongly recommend you to set ancestor limit and children limit, and they |
||
40 | * should not be too large. |
||
41 | * The ancestor limit is preferably no more than 256, and children limit is no |
||
42 | * more than 1024. |
||
43 | * Too large number may seriously slow down the database response speed, especially |
||
44 | * in updating operation. |
||
45 | * |
||
46 | * The data consistency between reference ID attribute and parent attribute can |
||
47 | * only be ensured by my own. And update and delete operations should be placed |
||
48 | * in the transaction to avoid data inconsistencies. |
||
49 | * Even so, we cannot fully guarantee data consistency. Therefore, we provide a |
||
50 | * method [[clearInvalidParent()]] for clearing non-existing parent node. |
||
51 | * |
||
52 | * @property static $parent |
||
53 | * @property-read static[] $ancestors |
||
54 | * @property-read string[] $ancestorChain |
||
55 | * @property-read array $ancestorModels |
||
56 | * @property-read static $commonAncestor |
||
57 | * @property-read static[] $children |
||
58 | * @property-read static[] $oldChildren |
||
59 | * @property array $selfBlameableRules |
||
60 | * @version 1.0 |
||
61 | * @author vistart <[email protected]> |
||
62 | */ |
||
63 | trait SelfBlameableTrait |
||
64 | { |
||
65 | |||
66 | /** |
||
67 | * @var false|string attribute name of which store the parent's guid. |
||
68 | * If you do not want to use self-blameable features, please set it false. |
||
69 | * Or if you access any features of this trait when this parameter is false, |
||
70 | * exception may be thrown. |
||
71 | */ |
||
72 | public $parentAttribute = false; |
||
73 | |||
74 | /** |
||
75 | * @var string|array rule name and parameters of parent attribute, as well |
||
76 | * as self referenced ID attribute. |
||
77 | */ |
||
78 | public $parentAttributeRule = ['string', 'max' => 16]; |
||
79 | |||
80 | /** |
||
81 | * @var string self referenced ID attribute. |
||
82 | * If you enable self-blameable features, this parameter should be specified, |
||
83 | * otherwise, exception will be thrown. |
||
84 | */ |
||
85 | public $refIdAttribute = 'guid'; |
||
86 | public static $parentNone = 0; |
||
87 | public static $parentParent = 1; |
||
88 | public static $parentTypes = [ |
||
89 | 0 => 'none', |
||
90 | 1 => 'parent', |
||
91 | ]; |
||
92 | |||
93 | /** |
||
94 | * @var string The constant determines the null parent. |
||
95 | */ |
||
96 | public static $nullParent = ''; |
||
97 | public static $onNoAction = 0; |
||
98 | public static $onRestrict = 1; |
||
99 | public static $onCascade = 2; |
||
100 | public static $onSetNull = 3; |
||
101 | public static $onUpdateTypes = [ |
||
102 | 0 => 'on action', |
||
103 | 1 => 'restrict', |
||
104 | 2 => 'cascade', |
||
105 | 3 => 'set null', |
||
106 | ]; |
||
107 | |||
108 | /** |
||
109 | * @var integer indicates the on delete type. default to cascade. |
||
110 | */ |
||
111 | public $onDeleteType = 2; |
||
112 | |||
113 | /** |
||
114 | * @var integer indicates the on update type. default to cascade. |
||
115 | */ |
||
116 | public $onUpdateType = 2; |
||
117 | |||
118 | /** |
||
119 | * @var boolean indicates whether throw exception or not when restriction occured on updating or deleting operation. |
||
120 | */ |
||
121 | public $throwRestrictException = false; |
||
122 | |||
123 | /** |
||
124 | * @var array store the attribute validation rules. |
||
125 | * If this field is a non-empty array, then it will be given. |
||
126 | */ |
||
127 | private $localSelfBlameableRules = []; |
||
128 | public static $eventParentChanged = 'parentChanged'; |
||
129 | public static $eventChildAdded = 'childAdded'; |
||
130 | |||
131 | /** |
||
132 | * @var false|integer Set the limit of ancestor level. False is no limit. |
||
133 | * We strongly recommend you set an unsigned integer which is less than 256. |
||
134 | */ |
||
135 | public $ancestorLimit = false; |
||
136 | |||
137 | /** |
||
138 | * @var false|integer Set the limit of children (not descendants). False is no limit. |
||
139 | * We strongly recommend you set an unsigned integer which is less than 1024. |
||
140 | */ |
||
141 | public $childrenLimit = false; |
||
142 | |||
143 | /** |
||
144 | * Get rules associated with self blameable attribute. |
||
145 | * If self-blameable rules has been stored locally, then it will be given, |
||
146 | * or return the parent attribute rule. |
||
147 | * @return array rules. |
||
148 | */ |
||
149 | 199 | public function getSelfBlameableRules() |
|
150 | { |
||
151 | 199 | if (!is_string($this->parentAttribute)) { |
|
152 | 199 | return []; |
|
153 | } |
||
154 | 46 | if (!empty($this->localSelfBlameableRules) && is_array($this->localSelfBlameableRules)) { |
|
155 | 2 | return $this->localSelfBlameableRules; |
|
156 | } |
||
157 | 46 | if (is_string($this->parentAttributeRule)) { |
|
158 | $this->parentAttributeRule = [$this->parentAttributeRule]; |
||
159 | } |
||
160 | 46 | $this->localSelfBlameableRules = [ |
|
161 | 46 | array_merge([$this->parentAttribute], $this->parentAttributeRule), |
|
162 | ]; |
||
163 | 46 | return $this->localSelfBlameableRules; |
|
164 | } |
||
165 | |||
166 | /** |
||
167 | * Set rules associated with self blameable attribute. |
||
168 | * @param array $rules rules. |
||
169 | */ |
||
170 | 1 | public function setSelfBlameableRules($rules = []) |
|
171 | { |
||
172 | 1 | $this->localSelfBlameableRules = $rules; |
|
173 | 1 | } |
|
174 | |||
175 | /** |
||
176 | * Check whether this model has reached the ancestor limit. |
||
177 | * If $ancestorLimit is false, it will be regared as no limit(return false). |
||
178 | * If $ancestorLimit is not false and not an unsigned integer, 256 will be taken. |
||
179 | * @return boolean |
||
180 | */ |
||
181 | 61 | public function hasReachedAncestorLimit() |
|
182 | { |
||
183 | 61 | if ($this->ancestorLimit === false) { |
|
184 | 61 | return false; |
|
185 | } |
||
186 | 4 | if (!is_numeric($this->ancestorLimit) || $this->ancestorLimit < 0) { |
|
187 | 1 | $this->ancestorLimit = 256; |
|
188 | } |
||
189 | 4 | return count($this->getAncestorChain()) >= $this->ancestorLimit; |
|
190 | } |
||
191 | |||
192 | /** |
||
193 | * Check whether this model has reached the children limit. |
||
194 | * If $childrenLimit is false, it will be regarded as no limit(return false). |
||
195 | * If $childrenLimit is not false and not an unsigned integer, 1024 will be taken. |
||
196 | * @return boolean |
||
197 | */ |
||
198 | 8 | public function hasReachedChildrenLimit() |
|
199 | { |
||
200 | 8 | if ($this->childrenLimit === false) { |
|
201 | 7 | return false; |
|
202 | } |
||
203 | 2 | if (!is_numeric($this->childrenLimit) || $this->childrenLimit < 0) { |
|
204 | 1 | $this->childrenLimit = 1024; |
|
205 | } |
||
206 | 2 | return ((int) $this->getChildren()->count()) >= $this->childrenLimit; |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * Bear a child. |
||
211 | * The creator of this child is not necessarily the creator of current one. |
||
212 | * For example: Someone commit a comment on another user's comment, these |
||
213 | * two comments are father and son, but do not belong to the same owner. |
||
214 | * Therefore, you need to specify the creator of current model. |
||
215 | * @param array $config |
||
216 | * @return static|null Null if reached the ancestor limit or children limit. |
||
217 | * @throws InvalidConfigException Self reference ID attribute or |
||
218 | * parent attribute not determined. |
||
219 | * @throws InvalidParamException ancestor or children limit reached. |
||
220 | */ |
||
221 | 8 | public function bear($config = []) |
|
222 | { |
||
223 | 8 | if (!$this->parentAttribute) { |
|
224 | 1 | throw new InvalidConfigException("Parent Attribute Not Determined."); |
|
225 | } |
||
226 | 7 | if (!$this->refIdAttribute) { |
|
227 | throw new InvalidConfigException("Self Reference ID Attribute Not Determined."); |
||
228 | } |
||
229 | 7 | if ($this->hasReachedAncestorLimit()) { |
|
230 | 1 | throw new InvalidParamException("Reached Ancestor Limit: " . $this->ancestorLimit); |
|
231 | } |
||
232 | 7 | if ($this->hasReachedChildrenLimit()) { |
|
233 | 1 | throw new InvalidParamException("Reached Children Limit: ". $this->childrenLimit); |
|
234 | } |
||
235 | 6 | if (isset($config['class'])) { |
|
236 | 1 | unset($config['class']); |
|
237 | } |
||
238 | 6 | $model = new static($config); |
|
0 ignored issues
–
show
|
|||
239 | 6 | if ($this->addChild($model) === false) { |
|
240 | return false; |
||
241 | } |
||
242 | 6 | return $model; |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * Add a child. |
||
247 | * But if children limit reached, false will be given. |
||
248 | * @param static $child |
||
0 ignored issues
–
show
|
|||
249 | * @return boolean Whether adding child succeeded or not. |
||
250 | */ |
||
251 | 6 | public function addChild($child) |
|
252 | { |
||
253 | 6 | return $this->hasReachedChildrenLimit() ? false : $child->setParent($this); |
|
254 | } |
||
255 | |||
256 | /** |
||
257 | * Event triggered before deleting itself. |
||
258 | * Note: DO NOT call it directly unless you know the consequences. |
||
259 | * @param ModelEvent $event |
||
260 | * @return boolean true if parentAttribute not specified. |
||
261 | * @throws IntegrityException throw if $throwRestrictException is true when $onDeleteType is on restrict. |
||
262 | */ |
||
263 | 98 | public function onDeleteChildren($event) |
|
264 | { |
||
265 | 98 | $sender = $event->sender; |
|
266 | /* @var $sender static */ |
||
267 | 98 | if (empty($sender->parentAttribute) || !is_string($sender->parentAttribute)) { |
|
268 | 98 | return true; |
|
269 | } |
||
270 | 30 | switch ($sender->onDeleteType) { |
|
271 | 30 | case static::$onRestrict: |
|
272 | 1 | $event->isValid = $sender->children === null; |
|
273 | 1 | if ($sender->throwRestrictException) { |
|
274 | 1 | throw new IntegrityException('Delete restricted.'); |
|
275 | } |
||
276 | 1 | break; |
|
277 | 30 | case static::$onCascade: |
|
278 | 30 | $event->isValid = $sender->deleteChildren(); |
|
0 ignored issues
–
show
It seems like
$sender->deleteChildren() can also be of type object<yii\db\IntegrityException> . However, the property $isValid is declared as type boolean . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
279 | 30 | break; |
|
280 | 2 | case static::$onSetNull: |
|
281 | 1 | $event->isValid = $sender->updateChildren(null); |
|
0 ignored issues
–
show
It seems like
$sender->updateChildren(null) can also be of type object<yii\db\IntegrityException> . However, the property $isValid is declared as type boolean . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
282 | 1 | break; |
|
283 | 1 | case static::$onNoAction: |
|
284 | default: |
||
285 | 1 | $event->isValid = true; |
|
286 | 1 | break; |
|
287 | } |
||
288 | 30 | } |
|
289 | |||
290 | /** |
||
291 | * Event triggered before updating itself. |
||
292 | * Note: DO NOT call it directly unless you know the consequences. |
||
293 | * @param ModelEvent $event |
||
294 | * @return boolean true if parentAttribute not specified. |
||
295 | * @throws IntegrityException throw if $throwRestrictException is true when $onUpdateType is on restrict. |
||
296 | */ |
||
297 | 4 | public function onUpdateChildren($event) |
|
298 | { |
||
299 | 4 | $sender = $event->sender; |
|
300 | /* @var $sender static */ |
||
301 | 4 | if (empty($sender->parentAttribute) || !is_string($sender->parentAttribute)) { |
|
302 | return true; |
||
303 | } |
||
304 | 4 | switch ($sender->onUpdateType) { |
|
305 | 4 | case static::$onRestrict: |
|
306 | 1 | $event->isValid = $sender->getOldChildren() === null; |
|
307 | 1 | if ($sender->throwRestrictException) { |
|
308 | 1 | throw new IntegrityException('Update restricted.'); |
|
309 | } |
||
310 | 1 | break; |
|
311 | 3 | case static::$onCascade: |
|
312 | 1 | $event->isValid = $sender->updateChildren(); |
|
0 ignored issues
–
show
It seems like
$sender->updateChildren() can also be of type object<yii\db\IntegrityException> . However, the property $isValid is declared as type boolean . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
313 | 1 | break; |
|
314 | 2 | case static::$onSetNull: |
|
315 | 1 | $event->isValid = $sender->updateChildren(null); |
|
0 ignored issues
–
show
It seems like
$sender->updateChildren(null) can also be of type object<yii\db\IntegrityException> . However, the property $isValid is declared as type boolean . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
316 | 1 | break; |
|
317 | 1 | case static::$onNoAction: |
|
318 | default: |
||
319 | 1 | $event->isValid = true; |
|
320 | 1 | break; |
|
321 | } |
||
322 | 4 | } |
|
323 | |||
324 | /** |
||
325 | * Get parent query. |
||
326 | * Or get parent instance if access by magic property. |
||
327 | * @return ActiveQuery |
||
328 | */ |
||
329 | 61 | public function getParent() |
|
330 | { |
||
331 | 61 | return $this->hasOne(static::class, [$this->refIdAttribute => $this->parentAttribute]); |
|
0 ignored issues
–
show
It seems like
hasOne() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
332 | } |
||
333 | |||
334 | /** |
||
335 | * Get parent ID. |
||
336 | * @return string|null null if parent attribute isn't enabled. |
||
337 | */ |
||
338 | 4 | public function getParentId() |
|
339 | { |
||
340 | 4 | return (is_string($this->parentAttribute) && !empty($this->parentAttribute)) ? |
|
341 | 4 | $this->{$this->parentAttribute} : null; |
|
342 | } |
||
343 | |||
344 | /** |
||
345 | * Set parent ID. |
||
346 | * @param string $parentId |
||
347 | * @return string|null null if parent attribute isn't enabled. |
||
348 | */ |
||
349 | 4 | public function setParentId($parentId) |
|
350 | { |
||
351 | 4 | return (is_string($this->parentAttribute) && !empty($this->parentAttribute)) ? |
|
352 | 4 | $this->{$this->parentAttribute} = $parentId : null; |
|
353 | } |
||
354 | |||
355 | /** |
||
356 | * Get reference ID. |
||
357 | * @return string |
||
358 | */ |
||
359 | 61 | public function getRefId() |
|
360 | { |
||
361 | 61 | if ($this->refIdAttribute == $this->guidAttribute) { |
|
0 ignored issues
–
show
The property
guidAttribute does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
362 | 61 | return $this->getGUID(); |
|
0 ignored issues
–
show
It seems like
getGUID() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
363 | } |
||
364 | if ($this->refIdAttribute == $this->idAttribute) { |
||
0 ignored issues
–
show
The property
idAttribute does not seem to exist. Did you mean refIdAttribute ?
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
365 | return $this->getID(); |
||
0 ignored issues
–
show
It seems like
getID() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
366 | } |
||
367 | return $this->{$this->refIdAttribute}; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * Set reference ID. |
||
372 | * @param string $refId |
||
373 | * @return string |
||
374 | */ |
||
375 | public function setRefId($refId) |
||
376 | { |
||
377 | if ($this->refIdAttribute == $this->guidAttribute) { |
||
378 | return $this->setGUID($refId); |
||
0 ignored issues
–
show
It seems like
setGUID() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
379 | } |
||
380 | if ($this->refIdAttribute == $this->idAttribute) { |
||
0 ignored issues
–
show
The property
idAttribute does not seem to exist. Did you mean refIdAttribute ?
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
381 | return $this->setID($refId); |
||
0 ignored issues
–
show
It seems like
setID() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
382 | } |
||
383 | return $this->{$this->refIdAttribute} = $refId; |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * Set parent. |
||
388 | * Don't forget save model after setting it. |
||
389 | * @param static $parent |
||
0 ignored issues
–
show
|
|||
390 | * @return false|string False if restriction reached. Otherwise parent's GUID given. |
||
391 | */ |
||
392 | 61 | public function setParent($parent) |
|
393 | { |
||
394 | 61 | if (empty($parent) || $this->getRefId() == $parent->getRefId() || |
|
395 | 61 | $parent->hasAncestor($this) || $this->hasReachedAncestorLimit()) { |
|
396 | 1 | return false; |
|
397 | } |
||
398 | 61 | unset($this->parent); |
|
399 | 61 | unset($parent->children); |
|
400 | 61 | $this->trigger(static::$eventParentChanged); |
|
0 ignored issues
–
show
It seems like
trigger() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
401 | 61 | $parent->trigger(static::$eventChildAdded); |
|
0 ignored issues
–
show
It seems like
trigger() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
402 | 61 | return $this->{$this->parentAttribute} = $parent->getRefId(); |
|
403 | } |
||
404 | |||
405 | /** |
||
406 | * Set null parent. |
||
407 | * This method would unset the lazy loading records before setting it. |
||
408 | * Don't forget save model after setting it. |
||
409 | */ |
||
410 | 4 | public function setNullParent() |
|
411 | { |
||
412 | 4 | if ($this->hasParent()) { |
|
413 | 2 | unset($this->parent->children); |
|
414 | } |
||
415 | 4 | unset($this->parent); |
|
416 | 4 | $this->setParentId(static::$nullParent); |
|
417 | 4 | } |
|
418 | |||
419 | /** |
||
420 | * Check whether this model has parent. |
||
421 | * @return boolean |
||
422 | */ |
||
423 | 61 | public function hasParent() |
|
424 | { |
||
425 | 61 | return $this->parent !== null; |
|
426 | } |
||
427 | |||
428 | /** |
||
429 | * Check whether if $ancestor is the ancestor of myself. |
||
430 | * Note: Itself will not be regarded as the its ancestor. |
||
431 | * @param static $ancestor |
||
0 ignored issues
–
show
|
|||
432 | * @return boolean |
||
433 | */ |
||
434 | 61 | public function hasAncestor($ancestor) |
|
435 | { |
||
436 | 61 | if (!$this->hasParent()) { |
|
437 | 61 | return false; |
|
438 | } |
||
439 | 9 | if ($this->parent->getRefId() == $ancestor->getRefId()) { |
|
440 | 2 | return true; |
|
441 | } |
||
442 | 9 | return $this->parent->hasAncestor($ancestor); |
|
443 | } |
||
444 | |||
445 | /** |
||
446 | * Get ancestor chain. (Ancestors' GUID Only!) |
||
447 | * If this model has ancestor, the return array consists all the ancestor in order. |
||
448 | * The first element is parent, and the last element is root, otherwise return empty array. |
||
449 | * If you want to get ancestor model, you can simplify instance a query and specify the |
||
450 | * condition with the return value. But it will not return models under the order of ancestor chain. |
||
451 | * @param string[] $ancestor |
||
452 | * @return string[] |
||
453 | */ |
||
454 | 9 | public function getAncestorChain($ancestor = []) |
|
455 | { |
||
456 | 9 | if (!is_string($this->parentAttribute) || empty($this->parentAttribute)) { |
|
457 | 1 | return []; |
|
458 | } |
||
459 | 8 | if (!$this->hasParent()) { |
|
460 | 8 | return $ancestor; |
|
461 | } |
||
462 | 8 | $ancestor[] = $this->parent->getRefId(); |
|
463 | 8 | return $this->parent->getAncestorChain($ancestor); |
|
464 | } |
||
465 | |||
466 | /** |
||
467 | * Get ancestors with specified ancestor chain. |
||
468 | * @param string[] $ancestor Ancestor chain. |
||
469 | * @return static[]|null |
||
470 | */ |
||
471 | 2 | public static function getAncestorModels($ancestor) |
|
472 | { |
||
473 | 2 | if (empty($ancestor) || !is_array($ancestor)) { |
|
474 | 1 | return []; |
|
475 | } |
||
476 | 2 | $models = []; |
|
477 | 2 | foreach ($ancestor as $self) { |
|
478 | 2 | $models[] = static::findOne($self); |
|
479 | } |
||
480 | 2 | return $models; |
|
481 | } |
||
482 | |||
483 | /** |
||
484 | * Get ancestors. |
||
485 | * @return static[] |
||
486 | */ |
||
487 | 1 | public function getAncestors() |
|
488 | { |
||
489 | 1 | return static::getAncestorModels($this->getAncestorChain()); |
|
490 | } |
||
491 | |||
492 | /** |
||
493 | * Check whether if this model has common ancestor with $model. |
||
494 | * @param static $model |
||
0 ignored issues
–
show
|
|||
495 | * @return boolean |
||
496 | */ |
||
497 | 2 | public function hasCommonAncestor($model) |
|
498 | { |
||
499 | 2 | return $this->getCommonAncestor($model) !== null; |
|
500 | } |
||
501 | |||
502 | /** |
||
503 | * Get common ancestor. If there isn't common ancestor, null will be given. |
||
504 | * @param static $model |
||
0 ignored issues
–
show
|
|||
505 | * @return static |
||
506 | */ |
||
507 | 3 | public function getCommonAncestor($model) |
|
508 | { |
||
509 | 3 | if (empty($this->parentAttribute) || !is_string($this->parentAttribute) || |
|
510 | 2 | empty($model) || !$model->hasParent()) { |
|
511 | 1 | return null; |
|
512 | } |
||
513 | 2 | $ancestors = $this->getAncestorChain(); |
|
514 | 2 | if (in_array($model->parent->getRefId(), $ancestors)) { |
|
515 | 2 | return $model->parent; |
|
516 | } |
||
517 | 1 | return $this->getCommonAncestor($model->parent); |
|
518 | } |
||
519 | |||
520 | /** |
||
521 | * Get children query. |
||
522 | * Or get children instances if access magic property. |
||
523 | * @return ActiveQuery |
||
524 | */ |
||
525 | 61 | public function getChildren() |
|
526 | { |
||
527 | 61 | return $this->hasMany(static::class, [$this->parentAttribute => $this->refIdAttribute])->inverseOf('parent'); |
|
0 ignored issues
–
show
It seems like
hasMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
528 | } |
||
529 | |||
530 | /** |
||
531 | * Get children which parent attribute point to old guid. |
||
532 | * @return static[] |
||
533 | */ |
||
534 | 4 | public function getOldChildren() |
|
535 | { |
||
536 | 4 | return static::find()->where([$this->parentAttribute => $this->getOldAttribute($this->refIdAttribute)])->all(); |
|
0 ignored issues
–
show
It seems like
getOldAttribute() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
537 | } |
||
538 | |||
539 | /** |
||
540 | * Update all children, not grandchildren (descendants). |
||
541 | * If onUpdateType is on cascade, the children will be updated automatically. |
||
542 | * @param mixed $value set guid if false, set empty string if empty() return |
||
543 | * true, otherwise set it to $parentAttribute. |
||
544 | * @return IntegrityException|boolean true if all update operations |
||
545 | * succeeded to execute, or false if anyone of them failed. If not production |
||
546 | * environment or enable debug mode, it will return exception. |
||
547 | * @throws IntegrityException throw if anyone update failed. |
||
548 | * The exception message only contains the first error. |
||
549 | */ |
||
550 | 3 | public function updateChildren($value = false) |
|
551 | { |
||
552 | 3 | $children = $this->getOldChildren(); |
|
553 | 3 | if (empty($children)) { |
|
554 | 1 | return true; |
|
555 | } |
||
556 | 3 | $transaction = $this->getDb()->beginTransaction(); |
|
0 ignored issues
–
show
It seems like
getDb() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
557 | try { |
||
558 | 3 | foreach ($children as $child) { |
|
559 | /* @var $child static */ |
||
560 | 3 | if ($value === false) { |
|
561 | 1 | $child->setParent($this); |
|
562 | } elseif (empty($value)) { |
||
563 | 2 | $child->setNullParent(); |
|
564 | } else { |
||
565 | $child->setParentId($value); |
||
566 | } |
||
567 | 3 | if (!$child->save()) { |
|
0 ignored issues
–
show
It seems like
save() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
568 | throw new IntegrityException('Update failed:', $child->getErrors()); |
||
0 ignored issues
–
show
It seems like
getErrors() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
569 | } |
||
570 | } |
||
571 | 3 | $transaction->commit(); |
|
572 | } catch (IntegrityException $ex) { |
||
573 | $transaction->rollBack(); |
||
574 | if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) { |
||
575 | Yii::error($ex->getMessage(), __METHOD__); |
||
576 | return $ex; |
||
577 | } |
||
578 | Yii::warning($ex->getMessage(), __METHOD__); |
||
579 | return false; |
||
580 | } |
||
581 | 3 | return true; |
|
582 | } |
||
583 | |||
584 | /** |
||
585 | * Delete all children, not grandchildren (descendants). |
||
586 | * If onDeleteType is `on cascade`, the children will be deleted automatically. |
||
587 | * If onDeleteType is `on restrict` and contains children, the deletion will |
||
588 | * be restricted. |
||
589 | * @return IntegrityException|boolean true if all delete operations |
||
590 | * succeeded to execute, or false if anyone of them failed. If not production |
||
591 | * environment or enable debug mode, it will return exception. |
||
592 | * @throws IntegrityException throw if anyone delete failed. |
||
593 | * The exception message only contains the first error. |
||
594 | */ |
||
595 | 30 | public function deleteChildren() |
|
596 | { |
||
597 | 30 | $children = $this->children; |
|
598 | 30 | if (empty($children)) { |
|
599 | 30 | return true; |
|
600 | } |
||
601 | 30 | $transaction = $this->getDb()->beginTransaction(); |
|
0 ignored issues
–
show
It seems like
getDb() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
602 | try { |
||
603 | 30 | foreach ($children as $child) { |
|
604 | /* @var $child static */ |
||
605 | 30 | if (!$child->delete()) { |
|
0 ignored issues
–
show
The method
delete() does not exist on rhosocial\base\models\traits\SelfBlameableTrait . Did you maybe mean onDeleteChildren() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
606 | 9 | throw new IntegrityException('Delete failed:', $child->getErrors()); |
|
0 ignored issues
–
show
It seems like
getErrors() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
607 | } |
||
608 | } |
||
609 | 30 | $transaction->commit(); |
|
610 | 9 | } catch (IntegrityException $ex) { |
|
611 | 9 | $transaction->rollBack(); |
|
612 | 9 | if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) { |
|
613 | 9 | Yii::error($ex->getMessage(), __METHOD__); |
|
614 | 9 | return $ex; |
|
615 | } |
||
616 | Yii::warning($ex->getMessage(), __METHOD__); |
||
617 | return false; |
||
618 | } |
||
619 | 30 | return true; |
|
620 | } |
||
621 | |||
622 | /** |
||
623 | * Update children's parent attribute. |
||
624 | * Event triggered before updating. |
||
625 | * @param ModelEvent $event |
||
626 | * @return boolean |
||
627 | */ |
||
628 | 62 | public function onParentRefIdChanged($event) |
|
629 | { |
||
630 | 62 | $sender = $event->sender; |
|
631 | /* @var $sender static */ |
||
632 | 62 | if ($sender->isAttributeChanged($sender->refIdAttribute)) { |
|
0 ignored issues
–
show
It seems like
isAttributeChanged() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
633 | 4 | return $sender->onUpdateChildren($event); |
|
634 | } |
||
635 | 61 | } |
|
636 | |||
637 | /** |
||
638 | * Attach events associated with self blameable attribute. |
||
639 | */ |
||
640 | 209 | protected function initSelfBlameableEvents() |
|
641 | { |
||
642 | 209 | $this->on(static::EVENT_BEFORE_UPDATE, [$this, 'onParentRefIdChanged']); |
|
0 ignored issues
–
show
It seems like
on() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
643 | 209 | $this->on(static::EVENT_BEFORE_DELETE, [$this, 'onDeleteChildren']); |
|
0 ignored issues
–
show
It seems like
on() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
644 | 209 | } |
|
645 | |||
646 | /** |
||
647 | * Clear invalid parent. |
||
648 | * The invalid state depends on which if parent id exists but it's corresponding |
||
649 | * parent cannot be found. |
||
650 | * @return boolean True if parent attribute is set null, False if parent valid. |
||
651 | */ |
||
652 | 4 | public function clearInvalidParent() |
|
653 | { |
||
654 | 4 | if ($this->getParentId() !== static::$nullParent && !$this->hasParent()) { |
|
655 | 2 | $this->setNullParent(); |
|
656 | 2 | return true; |
|
657 | } |
||
658 | 2 | return false; |
|
659 | } |
||
660 | } |
||
661 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.