Issues (187)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

traits/SelfBlameableTrait.php (18 issues)

Upgrade to new PHP Analysis Engine

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 http://vistart.name/
9
 * @copyright Copyright (c) 2016 vistart
10
 * @license http://vistart.name/license/
11
 */
12
13
namespace vistart\Models\traits;
14
15
use yii\base\ModelEvent;
16
use yii\db\ActiveQuery;
17
use yii\db\IntegrityException;
18
19
/**
20
 * This trait is designed for the model who contains parent.
21
 * The BlameableTrait use this trait by default. If you want to use this trait
22
 * into seperate model, please call the `initSelfBlameableEvents()` method in
23
 * `init()` method, like following:
24
 * ```php
25
 * public function init()
26
 * {
27
 *     $this->initSelfBlameableEvents();  // put it before parent call.
28
 *     parent::init();
29
 * }
30
 * ```
31
 * 
32
 * @property static $parent
33
 * @property-read static[] $ancestors
34
 * @property-read string[] $ancestorChain
35
 * @property-read static $commonAncestor
36
 * @property-read static[] $children
37
 * @property-read static[] $oldChildren
38
 * @property array $selfBlameableRules
39
 * @version 2.0
40
 * @author vistart <[email protected]>
41
 */
42
trait SelfBlameableTrait
43
{
44
45
    /**
46
     * @var false|string attribute name of which store the parent's guid.
47
     */
48
    public $parentAttribute = false;
49
50
    /**
51
     * @var string|array rule name and parameters of parent attribute, as well
52
     * as self referenced ID attribute.
53
     */
54
    public $parentAttributeRule = ['string', 'max' => 36];
55
56
    /**
57
     * @var string self referenced ID attribute.
58
     */
59
    public $refIdAttribute = 'guid';
60
    public static $parentNone = 0;
61
    public static $parentParent = 1;
62
    public static $parentTypes = [
63
        0 => 'none',
64
        1 => 'parent',
65
    ];
66
    public static $onNoAction = 0;
67
    public static $onRestrict = 1;
68
    public static $onCascade = 2;
69
    public static $onSetNull = 3;
70
    public static $onUpdateTypes = [
71
        0 => 'on action',
72
        1 => 'restrict',
73
        2 => 'cascade',
74
        3 => 'set null',
75
    ];
76
77
    /**
78
     * @var integer indicates the on delete type. default to cascade.
79
     */
80
    public $onDeleteType = 2;
81
82
    /**
83
     * @var integer indicates the on update type. default to cascade.
84
     */
85
    public $onUpdateType = 2;
86
87
    /**
88
     * @var boolean indicates whether throw exception or not when restriction occured on updating or deleting operation.
89
     */
90
    public $throwRestrictException = false;
91
    private $localSelfBlameableRules = [];
92
    public static $eventParentChanged = 'parentChanged';
93
    public static $eventChildAdded = 'childAdded';
94
95
    /**
96
     * @var false|integer Set the limit of ancestor level. False is no limit.
97
     */
98
    public $ancestorLimit = false;
99
100
    /**
101
     * @var false|integer Set the limit of children. False is no limit.
102
     */
103
    public $childrenLimit = false;
104
105
    /**
106
     * Get rules associated with self blameable attribute.
107
     * @return array rules.
108
     */
109 15
    public function getSelfBlameableRules()
110
    {
111 15
        if (!is_string($this->parentAttribute)) {
112 14
            return [];
113
        }
114 1
        if (!empty($this->localSelfBlameableRules) && is_array($this->localSelfBlameableRules)) {
115 1
            return $this->localSelfBlameableRules;
116
        }
117 1
        if (is_string($this->parentAttributeRule)) {
118
            $this->parentAttributeRule = [$this->parentAttributeRule];
119
        }
120 1
        $this->localSelfBlameableRules = [
121 1
            array_merge([$this->parentAttribute], $this->parentAttributeRule),
122
        ];
123 1
        return $this->localSelfBlameableRules;
124
    }
125
126
    /**
127
     * Set rules associated with self blameable attribute.
128
     * @param array $rules rules.
129
     */
130 1
    public function setSelfBlameableRules($rules = [])
131
    {
132 1
        $this->localSelfBlameableRules = $rules;
133 1
    }
134
135
    /**
136
     * Check whether this model has reached the ancestor limit.
137
     * If $ancestorLimit is false, it will be regared as no limit(return false).
138
     * If $ancestorLimit is not false and not a number, 256 will be taken.
139
     * @return boolean
140
     */
141 10
    public function hasReachedAncestorLimit()
142
    {
143 10
        if ($this->ancestorLimit === false) {
144 10
            return false;
145
        }
146
        if (!is_numeric($this->ancestorLimit)) {
147
            $this->ancestorLimit = 256;
148
        }
149
        return count($this->getAncestorChain()) >= $this->ancestorLimit;
150
    }
151
152
    /**
153
     * Check whether this model has reached the children limit.
154
     * If $childrenLimit is false, it will be regarded as no limit(return false).
155
     * If $childrenLimist is not false and not a number, 256 will be taken.
156
     * @return boolean
157
     */
158 10
    public function hasReachedChildrenLimit()
159
    {
160 10
        if ($this->childrenLimit === false) {
161 10
            return false;
162
        }
163
        if (!is_numeric($this->childrenLimit)) {
164
            $this->childrenLimit = 256;
165
        }
166
        return ((int) $this->getChildren()->count()) >= $this->childrenLimit;
167
    }
168
169
    /**
170
     * Bear a child.
171
     * @param array $config
172
     * @return static|null Null if reached the ancestor limit or children limit.
173
     */
174 10
    public function bear($config = [])
175
    {
176 10
        if ($this->hasReachedAncestorLimit() || $this->hasReachedChildrenLimit()) {
177
            return null;
178
        }
179 10
        if (isset($config['class'])) {
180 10
            unset($config['class']);
181 10
        }
182 10
        $refIdAttribute = $this->refIdAttribute;
183 10
        $config[$this->parentAttribute] = $this->$refIdAttribute;
184 10
        return new static($config);
0 ignored issues
show
The call to SelfBlameableTrait::__construct() has too many arguments starting with $config.

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.

Loading history...
185
    }
186
187
    /**
188
     * Add a child.
189
     * @param static $child
0 ignored issues
show
The type SelfBlameableTrait for parameter $child is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
190
     * @return boolean
191
     */
192
    public function addChild($child)
193
    {
194
        return $this->hasReachedChildrenLimit() ? $child->setParent($this) : false;
195
    }
196
197
    /**
198
     * Event triggered before deleting itself.
199
     * @param ModelEvent $event
200
     * @return boolean true if parentAttribute not specified.
201
     * @throws IntegrityException throw if $throwRestrictException is true when $onDeleteType is on restrict.
202
     */
203 24
    public function onDeleteChildren($event)
204
    {
205 24
        $sender = $event->sender;
206 24
        if (!is_string($sender->parentAttribute)) {
207 20
            return true;
208
        }
209 4
        switch ($sender->onDeleteType) {
210 4
            case static::$onRestrict:
211 1
                $event->isValid = $sender->children === null;
212 1
                if ($this->throwRestrictException) {
213 1
                    throw new IntegrityException('Delete restricted.');
214
                }
215 1
                break;
216 3
            case static::$onCascade:
217 1
                $event->isValid = $sender->deleteChildren();
218 1
                break;
219 2
            case static::$onSetNull:
220 1
                $event->isValid = $sender->updateChildren(null);
221 1
                break;
222 1
            case static::$onNoAction:
223 1
            default:
224 1
                $event->isValid = true;
225 1
                break;
226 4
        }
227 4
    }
228
229
    /**
230
     * Event triggered before updating itself.
231
     * @param ModelEvent $event
232
     * @return boolean true if parentAttribute not specified.
233
     * @throws IntegrityException throw if $throwRestrictException is true when $onUpdateType is on restrict.
234
     */
235 4
    public function onUpdateChildren($event)
236
    {
237 4
        $sender = $event->sender;
238 4
        if (!is_string($sender->parentAttribute)) {
239
            return true;
240
        }
241 4
        switch ($sender->onUpdateType) {
242 4
            case static::$onRestrict:
243 1
                $event->isValid = $sender->getOldChildren() === null;
244 1
                if ($this->throwRestrictException) {
245 1
                    throw new IntegrityException('Update restricted.');
246
                }
247
                break;
248 3
            case static::$onCascade:
249 1
                $event->isValid = $sender->updateChildren();
250 1
                break;
251 2
            case static::$onSetNull:
252 1
                $event->isValid = $sender->updateChildren(null);
253 1
                break;
254 1
            case static::$onNoAction:
255 1
            default:
256 1
                $event->isValid = true;
257 1
                break;
258 3
        }
259 3
    }
260
261
    /**
262
     * Get parent query.
263
     * Or get parent instance if access by magic property.
264
     * @return ActiveQuery
265
     */
266 3
    public function getParent()
267
    {
268 3
        return $this->hasOne(static::className(), [$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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
269
    }
270
271
    /**
272
     * Set parent.
273
     * Don't forget save model after setting it.
274
     * @param static $parent
0 ignored issues
show
The type SelfBlameableTrait for parameter $parent is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
275
     * @return false|string
276
     */
277 1
    public function setParent($parent)
278
    {
279 1
        if (empty($parent) || $this->guid == $parent->guid || $parent->hasAncestor($this) || $parent->hasReachedAncestorLimit()) {
0 ignored issues
show
The property guid 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;
Loading history...
280
            return false;
281
        }
282 1
        unset($this->parent);
283 1
        unset($parent->children);
284 1
        $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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
285 1
        $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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
286 1
        return $this->{$this->parentAttribute} = $parent->guid;
287
    }
288
289
    /**
290
     * Check whether this model has parent.
291
     * @return boolean
292
     */
293 1
    public function hasParent()
294
    {
295 1
        return $this->parent !== null;
296
    }
297
298
    /**
299
     * Check whether if $ancestor is the ancestor of myself.
300
     * Note, Itself will not be regarded as the its ancestor.
301
     * @param static $ancestor
0 ignored issues
show
The type SelfBlameableTrait for parameter $ancestor is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
302
     * @return boolean
303
     */
304 1
    public function hasAncestor($ancestor)
305
    {
306 1
        if (!$this->hasParent()) {
307 1
            return false;
308
        }
309 1
        if ($this->parent->guid == $ancestor->guid) {
310
            return true;
311
        }
312 1
        return $this->parent->hasAncestor($ancestor);
313
    }
314
315
    /**
316
     * Get ancestor chain. (Ancestor GUID Only!)
317
     * If this model has ancestor, the return array consists all the ancestor in order.
318
     * The first element is parent, and the last element is root, otherwise return empty array.
319
     * If you want to get ancestor model, you can simplify instance a query and specify the 
320
     * condition with the return value. But it will not return models under the order of ancestor chain.
321
     * @param string[] $ancestor
322
     * @return string[]
323
     */
324 1
    public function getAncestorChain($ancestor = [])
325
    {
326 1
        if (!is_string($this->parentAttribute)) {
327
            return [];
328
        }
329 1
        if (!$this->hasParent()) {
330 1
            return $ancestor;
331
        }
332 1
        $ancestor[] = $this->parent->guid;
333 1
        return $this->parent->getAncestorChain($ancestor);
334
    }
335
336
    /**
337
     * Get ancestors with specified ancestor chain.
338
     * @param string[] $ancestor Ancestor chain.
339
     * @return static[]|null
340
     */
341 1
    public static function getAncestorModels($ancestor)
342
    {
343 1
        if (empty($ancestor) || !is_array($ancestor)) {
344 1
            return null;
345
        }
346 1
        $models = [];
347 1
        foreach ($ancestor as $self) {
348 1
            $models[] = static::findOne($self);
349 1
        }
350 1
        return $models;
351
    }
352
353
    /**
354
     * Get ancestors.
355
     * @return static[]|null
356
     */
357 1
    public function getAncestors()
358
    {
359 1
        return is_string($this->parentAttribute) ? $this->getAncestorModels($this->getAncestorChain()) : null;
360
    }
361
362
    /**
363
     * Check whether if this model has common ancestor with $model.
364
     * @param static $model
0 ignored issues
show
The type SelfBlameableTrait for parameter $model is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
365
     * @return boolean
366
     */
367 1
    public function hasCommonAncestor($model)
368
    {
369 1
        return is_string($this->parentAttribute) ? $this->getCommonAncestor($model) !== null : false;
370
    }
371
372
    /**
373
     * Get common ancestor. If there isn't common ancestor, null will be given.
374
     * @param static $model
0 ignored issues
show
The type SelfBlameableTrait for parameter $model is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
375
     * @return static
376
     */
377 1
    public function getCommonAncestor($model)
378
    {
379 1
        if (!is_string($this->parentAttribute) || empty($model) || !$model->hasParent()) {
380 1
            return null;
381
        }
382 1
        $ancestor = $this->getAncestorChain();
383 1
        if (in_array($model->parent->guid, $ancestor)) {
384 1
            return $model->parent;
385
        }
386 1
        return $this->getCommonAncestor($model->parent);
387
    }
388
389
    /**
390
     * Get children query.
391
     * Or get children instances if access magic property.
392
     * @return ActiveQuery
393
     */
394 4
    public function getChildren()
395
    {
396 4
        return $this->hasMany(static::className(), [$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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
397
    }
398
399
    /**
400
     * Get children which parent attribute point to the my old guid.
401
     * @return static[]
402
     */
403 4
    public function getOldChildren()
404
    {
405 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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
406
    }
407
408
    /**
409
     * Update all children, not grandchildren.
410
     * If onUpdateType is on cascade, the children will be updated automatically.
411
     * @param mixed $value set guid if false, set empty string if empty() return
412
     * true, otherwise set it to $parentAttribute.
413
     * @return IntegrityException|boolean true if all update operations
414
     * succeeded to execute, or false if anyone of them failed. If not production
415
     * environment or enable debug mode, it will return exception.
416
     * @throws IntegrityException throw if anyone update failed.
417
     */
418 3
    public function updateChildren($value = false)
419
    {
420 3
        $children = $this->getOldChildren();
421 3
        if (empty($children)) {
422
            return true;
423
        }
424 3
        $parentAttribute = $this->parentAttribute;
425 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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
426
        try {
427 3
            foreach ($children as $child) {
428 3
                if ($value === false) {
429 1
                    $refIdAttribute = $this->refIdAttribute;
430 1
                    $child->$parentAttribute = $this->$refIdAttribute;
431 3
                } elseif (empty($value)) {
432 2
                    $child->$parentAttribute = '';
433 2
                } else {
434
                    $child->$parentAttribute = $value;
435
                }
436 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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
437
                    throw new IntegrityException('Update failed:' . $child->errors);
0 ignored issues
show
The property errors 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;
Loading history...
438
                }
439 3
            }
440 3
            $transaction->commit();
441 3
        } catch (IntegrityException $ex) {
442
            $transaction->rollBack();
443
            if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) {
444
                Yii::error($ex->errorInfo, static::className() . '\update');
445
                return $ex;
446
            }
447
            Yii::warning($ex->errorInfo, static::className() . '\update');
448
            return false;
449
        }
450 3
        return true;
451
    }
452
453
    /**
454
     * Delete all children, not grandchildren.
455
     * If onDeleteType is on cascade, the children will be deleted automatically.
456
     * If onDeleteType is on restrict and contains children, the deletion will
457
     * be restricted.
458
     * @return IntegrityException|boolean true if all delete operations
459
     * succeeded to execute, or false if anyone of them failed. If not production
460
     * environment or enable debug mode, it will return exception.
461
     * @throws IntegrityException throw if anyone delete failed.
462
     */
463 1
    public function deleteChildren()
464
    {
465 1
        $children = $this->children;
466 1
        if (empty($children)) {
467 1
            return true;
468
        }
469 1
        $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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
470
        try {
471 1
            foreach ($children as $child) {
472 1
                if (!$child->delete()) {
473
                    throw new IntegrityException('Delete failed:' . $child->errors);
474
                }
475 1
            }
476 1
            $transaction->commit();
477 1
        } catch (IntegrityException $ex) {
478
            $transaction->rollBack();
479
            if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) {
480
                Yii::error($ex->errorInfo, static::className() . '\delete');
481
                return $ex;
482
            }
483
            Yii::warning($ex->errorInfo, static::className() . '\delete');
484
            return false;
485
        }
486 1
        return true;
487
    }
488
489
    /**
490
     * Update children's parent attribute.
491
     * Event triggered before updating.
492
     * @param ModelEvent $event
493
     * @return boolean
494
     */
495 19
    public function onParentRefIdChanged($event)
496
    {
497 19
        $sender = $event->sender;
498 19
        if ($sender->isAttributeChanged($sender->refIdAttribute)) {
499 4
            return $sender->onUpdateChildren($event);
500
        }
501 17
    }
502
503
    /**
504
     * Attach events associated with self blameable attribute.
505
     */
506 46
    protected function initSelfBlameableEvents()
507
    {
508 46
        $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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
509 46
        $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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
510 46
    }
511
}
512