Completed
Push — master ( 8b157a...24fb80 )
by vistart
10:41 queued 04:19
created

UserRelationTrait::onDeleteRelation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 11
ccs 10
cts 10
cp 1
rs 9.4285
cc 2
eloc 8
nc 2
nop 1
crap 2
1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.name/
9
 * @copyright Copyright (c) 2016 vistart
10
 * @license https://vistart.name/license/
11
 */
12
13
namespace vistart\Models\traits;
14
15
use vistart\Models\models\BaseUserModel;
16
use vistart\Models\traits\MultipleBlameableTrait as mb;
17
use yii\base\ModelEvent;
18
19
/**
20
 * Relation features.
21
 * This trait should be used in user relation model which is extended from
22
 * [[BaseBlameableModel]], and is specified `$userClass` property. And the user
23
 * class should be extended from [[BaseUserModel]], or any other classes used
24
 * [[UserTrait]].
25
 * Notice: Several methods associated with "inserting", "updating" and "removing" may
26
 * involve more DB operations, I strongly recommend those methods to be placed in
27
 * transaction execution, in order to ensure data consistency.
28
 * If you want to use group feature, the class used [[UserRelationGroupTrait]]
29
 * must be used coordinately.
30
 * @property array $groupGuids the guid array of all groups which owned by current relation.
31
 * @property-read array $allGroups
32
 * @property-read array $nonGroupMembers
33
 * @property-read integer $groupsCount
34
 * @property-read array $groupsRules
35
 * @property boolean $isFavorite
36
 * @property-read BaseUserModel $initiator
37
 * @property-read BaseUserModel $recipient
38
 * @property-read static $opposite
39
 * @version 2.0
40
 * @author vistart <[email protected]>
41
 */
42
trait UserRelationTrait
43
{
44
    use mb,
45
        MutualTrait {
46
        mb::addBlame as addGroup;
47
        mb::createBlame as createGroup;
48
        mb::addOrCreateBlame as addOrCreateGroup;
49
        mb::removeBlame as removeGroup;
50
        mb::removeAllBlames as removeAllGroups;
51
        mb::getBlame as getGroup;
52
        mb::getOrCreateBlame as getOrCreateGroup;
53
        mb::getBlameds as getGroupMembers;
54
        mb::getBlameGuids as getGroupGuids;
55
        mb::setBlameGuids as setGroupGuids;
56
        mb::getAllBlames as getAllGroups;
57
        mb::getNonBlameds as getNonGroupMembers;
58
        mb::getBlamesCount as getGroupsCount;
59
        mb::getMultipleBlameableAttributeRules as getGroupsRules;
60
        mb::getEmptyBlamesJson as getEmptyGroupJson;
61
    }
62
63
    /**
64
     * @var string
65
     */
66
    public $remarkAttribute = 'remark';
67
    public static $relationSingle = 0;
68
    public static $relationMutual = 1;
69
    public $relationType = 1;
70
    public $relationTypes = [
71
        0 => 'Single',
72
        1 => 'Mutual',
73
    ];
74
75
    /**
76
     * @var string the attribute name of which determines the relation type.
77
     */
78
    public $mutualTypeAttribute = 'type';
79
    public static $mutualTypeNormal = 0x00;
80
    public static $mutualTypeSuspend = 0x01;
81
82
    /**
83
     * @var array Mutual types.
84
     */
85
    public static $mutualTypes = [
86
        0x00 => 'Normal',
87
        0x01 => 'Suspend',
88
    ];
89
90
    /**
91
     * @var string the attribute name of which determines the `favorite` field.
92
     */
93
    public $favoriteAttribute = 'favorite';
94
95
    /**
96
     * Permit to build self relation.
97
     * @var boolean 
98
     */
99
    public $relationSelf = false;
100
101
    /**
102
     * Get whether this relation is favorite or not.
103
     * @return boolean
104
     */
105 1
    public function getIsFavorite()
106
    {
107 1
        $favoriteAttribute = $this->favoriteAttribute;
108 1
        return is_string($favoriteAttribute) ? (int) $this->$favoriteAttribute > 0 : null;
109
    }
110
111
    /**
112
     * Set favorite.
113
     * @param boolean $fav
114
     */
115 1
    public function setIsFavorite($fav)
116
    {
117 1
        $favoriteAttribute = $this->favoriteAttribute;
118 1
        return is_string($favoriteAttribute) ? $this->$favoriteAttribute = ($fav ? 1 : 0) : null;
119
    }
120
121
    /**
122
     * @inheritdoc
123
     */
124 10
    public function rules()
125
    {
126 10
        return array_merge(parent::rules(), $this->getUserRelationRules());
127
    }
128
129
    /**
130
     * Validation rules associated with user relation.
131
     * @return array rules.
132
     */
133 10
    public function getUserRelationRules()
134
    {
135 10
        $rules = [];
136 10
        if ($this->relationType == static::$relationMutual) {
137
            $rules = [
138 8
                [[$this->mutualTypeAttribute], 'in', 'range' => array_keys(static::$mutualTypes)],
139 8
                [[$this->mutualTypeAttribute], 'default', 'value' => static::$mutualTypeNormal],
140 8
            ];
141 8
        }
142 10
        return array_merge($rules, $this->getRemarkRules(), $this->getFavoriteRules(), $this->getGroupsRules(), $this->getOtherGuidRules());
0 ignored issues
show
Bug introduced by
It seems like getGroupsRules() 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...
143
    }
144
145
    /**
146
     * Get remark.
147
     * @return string remark.
148
     */
149
    public function getRemark()
150
    {
151
        $remarkAttribute = $this->remarkAttribute;
152
        return is_string($remarkAttribute) ? $this->$remarkAttribute : null;
153
    }
154
155
    /**
156
     * Set remark.
157
     * @param string $remark
158
     * @return string remark.
159
     */
160
    public function setRemark($remark)
161
    {
162
        $remarkAttribute = $this->remarkAttribute;
163
        return is_string($remarkAttribute) ? $this->$remarkAttribute = $remark : null;
164
    }
165
166
    /**
167
     * Validation rules associated with remark attribute.
168
     * @return array rules.
169
     */
170 10
    public function getRemarkRules()
171
    {
172 10
        return is_string($this->remarkAttribute) ? [
173 10
            [[$this->remarkAttribute], 'string'],
174 10
            [[$this->remarkAttribute], 'default', 'value' => ''],
175 10
            ] : [];
176
    }
177
178
    /**
179
     * Validation rules associated with favorites attribute.
180
     * @return array rules.
181
     */
182 10
    public function getFavoriteRules()
183
    {
184 10
        return is_string($this->favoriteAttribute) ? [
185 10
            [[$this->favoriteAttribute], 'boolean'],
186 10
            [[$this->favoriteAttribute], 'default', 'value' => 0],
187 10
            ] : [];
188
    }
189
190
    /**
191
     * Validation rules associated with other guid attribute.
192
     * @return array rules.
193
     */
194 10
    public function getOtherGuidRules()
195
    {
196 10
        $rules = array_merge($this->getMutualRules(), [
197 10
            [[$this->otherGuidAttribute, $this->createdByAttribute], 'unique', 'targetAttribute' => [$this->otherGuidAttribute, $this->createdByAttribute]],
0 ignored issues
show
Bug introduced by
The property createdByAttribute 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...
198 10
        ]);
199 10
        return $rules;
200
    }
201
202
    /**
203
     * Attach events associated with user relation.
204
     */
205 10
    public function initUserRelationEvents()
206
    {
207 10
        $this->on(static::EVENT_INIT, [$this, 'onInitBlamesLimit']);
0 ignored issues
show
Bug introduced by
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...
208 10
        $this->on(static::$eventNewRecordCreated, [$this, 'onInitGroups']);
0 ignored issues
show
Bug introduced by
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...
209 10
        $this->on(static::$eventNewRecordCreated, [$this, 'onInitRemark']);
0 ignored issues
show
Bug introduced by
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...
210 10
        $this->on(static::$eventMultipleBlamesChanged, [$this, 'onBlamesChanged']);
0 ignored issues
show
Bug introduced by
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...
211 10
        $this->on(static::EVENT_AFTER_INSERT, [$this, 'onInsertRelation']);
0 ignored issues
show
Bug introduced by
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...
212 10
        $this->on(static::EVENT_AFTER_UPDATE, [$this, 'onUpdateRelation']);
0 ignored issues
show
Bug introduced by
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...
213 10
        $this->on(static::EVENT_AFTER_DELETE, [$this, 'onDeleteRelation']);
0 ignored issues
show
Bug introduced by
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...
214 10
    }
215
216
    /**
217
     * Get opposite relation against self.
218
     * @return static
219
     */
220 8
    public function getOpposite()
221
    {
222 8
        if ($this->isNewRecord) {
0 ignored issues
show
Bug introduced by
The property isNewRecord 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...
223 1
            return null;
224
        }
225 8
        $createdByAttribute = $this->createdByAttribute;
226 8
        $otherGuidAttribute = $this->otherGuidAttribute;
227 8
        return static::find()->opposite($this->$createdByAttribute, $this->$otherGuidAttribute);
228
    }
229
230
    /**
231
     * Check whether the initiator is followed by recipient.
232
     * @param BaseUserModel $initiator
233
     * @param BaseUserModel $recipient
234
     * @return boolean
235
     */
236 2
    public static function isFollowed($initiator, $recipient)
237
    {
238 2
        return ((int) static::find()->initiators($recipient)->recipients($initiator)->count()) > 0;
239
    }
240
241
    /**
242
     * Check whether the initiator is following recipient.
243
     * @param BaseUserModel $initiator
244
     * @param BaseUserModel $recipient
245
     * @return boolean
246
     */
247 2
    public static function isFollowing($initiator, $recipient)
248
    {
249 2
        return ((int) static::find()->initiators($initiator)->recipients($recipient)->count()) > 0;
250
    }
251
252
    /**
253
     * Check whether the initiator is following and followed by recipient mutually (Single Relation).
254
     * Or check whether the initiator and recipient are friend whatever the mutual type is normal or suspend.
255
     * @param BaseUserModel $initiator
256
     * @param BaseUserModel $recipient
257
     * @return boolean
258
     */
259 2
    public static function isMutual($initiator, $recipient)
260
    {
261 2
        return static::isFollowed($initiator, $recipient) && static::isFollowing($initiator, $recipient);
262
    }
263
264
    /**
265
     * Check whether the initiator is following and followed by recipient mutually (Single Relation).
266
     * Or check whether the initiator and recipient are friend if the mutual type is normal.
267
     * @param BaseUserModel $initiator
268
     * @param BaseUserModel $recipient
269
     * @return boolean
270
     */
271 2
    public static function isFriend($initiator, $recipient)
272
    {
273 2
        $query = static::find();
274 2
        $model = $query->noInitModel;
275
        /* @var $model static */
276 2
        if ($model->relationType == static::$relationSingle) {
277 1
            return static::isMutual($initiator, $recipient);
278
        }
279 1
        if ($model->relationType == static::$relationMutual) {
280 1
            $relation = (int) static::find()->initiators($initiator)->recipients($recipient)->andWhere([$model->mutualTypeAttribute => static::$mutualTypeNormal])->count();
281 1
            $inverse = (int) static::find()->recipients($initiator)->initiators($recipient)->andWhere([$model->mutualTypeAttribute => static::$mutualTypeNormal])->count();
282 1
            return $relation && $inverse;
283
        }
284
        return false;
285
    }
286
287
    /**
288
     * Build new or return existed suspend mutual relation, of return null if
289
     * current type is not mutual.
290
     * @see buildRelation()
291
     * @param BaseUserModel|string $user Initiator or its GUID.
292
     * @param BaseUserModel|string $other Recipient or its GUID.
293
     * @return static The relation will be
294
     * given if exists, or return a new relation.
295
     */
296 3
    public static function buildSuspendRelation($user, $other)
297
    {
298 3
        $relation = static::buildRelation($user, $other);
299 3
        if ($relation->relationType != static::$relationMutual) {
300 1
            return null;
301
        }
302 2
        $btAttribute = $relation->mutualTypeAttribute;
303 2
        $relation->$btAttribute = static::$mutualTypeSuspend;
304 2
        return $relation;
305
    }
306
307
    /**
308
     * Build new or return existed normal relation.
309
     * The status of mutual relation will be changed to normal if it is not. 
310
     * @see buildRelation()
311
     * @param BaseUserModel|string $user Initiator or its GUID.
312
     * @param BaseUserModel|string $other Recipient or its GUID.
313
     * @return static The relation will be
314
     * given if exists, or return a new relation.
315
     */
316 10
    public static function buildNormalRelation($user, $other)
317
    {
318 10
        $relation = static::buildRelation($user, $other);
319 10
        if ($relation->relationType == static::$relationMutual) {
320 8
            $btAttribute = $relation->mutualTypeAttribute;
321 8
            $relation->$btAttribute = static::$mutualTypeNormal;
322 8
        }
323 10
        return $relation;
324
    }
325
326
    /**
327
     * Build new or return existed relation between initiator and recipient.
328
     * If relation between initiator and recipient is not found, new relation will
329
     * be built. If initiator and recipient are the same one and it is not allowed
330
     * to build self relation, null will be given.
331
     * If you want to know whether the relation exists, you can check the return
332
     * value of `getIsNewRecord()` method.
333
     * @param BaseUserModel|string $user Initiator or its GUID.
334
     * @param BaseUserModel|string $other Recipient or its GUID.
335
     * @return static The relation will be
336
     * given if exists, or return a new relation. Or return null if not allowed
337
     * to build self relation,
338
     */
339 10
    protected static function buildRelation($user, $other)
340
    {
341 10
        $relationQuery = static::find()->initiators($user)->recipients($other);
342 10
        $noInit = $relationQuery->noInitModel;
343 10
        $relation = $relationQuery->one();
344 10
        if (!$relation) {
345 10
            $createdByAttribute = $noInit->createdByAttribute;
346 10
            $otherGuidAttribute = $noInit->otherGuidAttribute;
347 10
            $userClass = $noInit->userClass;
348 10
            if ($user instanceof BaseUserModel) {
349 10
                $userClass = $userClass ? : $user->className();
350 10
                $user = $user->guid;
351 10
            }
352 10
            if ($other instanceof BaseUserModel) {
353 10
                $other = $other->guid;
354 10
            }
355 10
            if (!$noInit->relationSelf && $user == $other) {
356
                return null;
357
            }
358 10
            $relation = new static([$createdByAttribute => $user, $otherGuidAttribute => $other, 'userClass' => $userClass]);
0 ignored issues
show
Unused Code introduced by
The call to UserRelationTrait::__construct() has too many arguments starting with array($createdByAttribut...erClass' => $userClass).

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...
359 10
        }
360 10
        return $relation;
361
    }
362
363
    /**
364
     * Build opposite relation throughout the current relation. The opposite
365
     * relation will be given if existed.
366
     * @param static $relation
0 ignored issues
show
introduced by
The type UserRelationTrait for parameter $relation 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...
367
     * @return static
368
     */
369 8
    protected static function buildOppositeRelation($relation)
370
    {
371 8
        if (!$relation) {
372
            return null;
373
        }
374 8
        $createdByAttribute = $relation->createdByAttribute;
375 8
        $otherGuidAttribute = $relation->otherGuidAttribute;
376 8
        $opposite = static::buildRelation($relation->$otherGuidAttribute, $relation->$createdByAttribute);
377 8
        if ($relation->relationType == static::$relationSingle) {
378
            $opposite->relationType = static::$relationSingle;
379 8
        } elseif ($relation->relationType == static::$relationMutual) {
380 8
            $mutualTypeAttribute = $relation->mutualTypeAttribute;
381 8
            $opposite->$mutualTypeAttribute = $relation->$mutualTypeAttribute;
382 8
        }
383 8
        return $opposite;
384
    }
385
386
    /**
387
     * Remove myself.
388
     * @return integer|false The number of relations removed, or false if the remove
389
     * is unsuccessful for some reason. Note that it is possible the number of relations
390
     * removed is 0, even though the remove execution is successful.
391
     */
392 2
    public function remove()
393
    {
394 2
        return $this->delete();
0 ignored issues
show
Bug introduced by
The method delete() does not exist on vistart\Models\traits\UserRelationTrait. Did you maybe mean onDeleteRelation()?

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.

Loading history...
395
    }
396
397
    /**
398
     * Remove first relation between initiator(s) and recipient(s).
399
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
400
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
401
     * @return integer|false The number of relations removed.
402
     */
403 1
    public static function removeOneRelation($user, $other)
404
    {
405 1
        return static::find()->initiators($user)->recipients($other)->one()->delete();
406
    }
407
408
    /**
409
     * Remove all relations between initiator(s) and recipient(s).
410
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
411
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
412
     * @return integer The number of relations removed.
413
     */
414 2
    public static function removeAllRelations($user, $other)
415
    {
416 2
        $rni = static::buildNoInitModel();
417 2
        $createdByAttribute = $rni->createdByAttribute;
418 2
        $otherGuidAttribute = $rni->otherGuidAttribute;
419 2
        return static::deleteAll([$createdByAttribute => $user, $otherGuidAttribute => $other]);
420
    }
421
422
    /**
423
     * Get first relation between initiator(s) and recipient(s).
424
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
425
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
426
     * @return static
427
     */
428 1
    public static function findOneRelation($user, $other)
429
    {
430 1
        return static::find()->initiators($user)->recipients($other)->one();
431
    }
432
433
    /**
434
     * Get first opposite relation between initiator(s) and recipient(s).
435
     * @param BaseUserModel|string $user Initiator or its guid, or array of them.
436
     * @param BaseUserModel|string $other Recipient or its guid, or array of them.
437
     * @return static
438
     */
439 8
    public static function findOneOppositeRelation($user, $other)
440
    {
441 8
        return static::find()->initiators($other)->recipients($user)->one();
442
    }
443
444
    /**
445
     * Get user's or users' all relations, or by specified groups.
446
     * @param BaseUserModel|string|array $user Initiator or its GUID, or Initiators or their GUIDs.
447
     * @param BaseUserRelationGroupModel|string|array|null $groups UserRelationGroup
448
     * or its guid, or array of them. If you do not want to delimit the groups, please assign null.
449
     * @return array all eligible relations
450
     */
451
    public static function findOnesAllRelations($user, $groups = null)
452
    {
453
        return static::find()->initiators($user)->groups($groups)->all();
454
    }
455
456
    /**
457
     * Initialize groups attribute.
458
     * @param ModelEvent $event
459
     */
460 10
    public function onInitGroups($event)
461
    {
462 10
        $sender = $event->sender;
463 10
        $sender->removeAllGroups();
464 10
    }
465
466
    /**
467
     * Initialize remark attribute.
468
     * @param ModelEvent $event
469
     */
470 10
    public function onInitRemark($event)
471
    {
472 10
        $sender = $event->sender;
473 10
        $remarkAttribute = $sender->remarkAttribute;
474 10
        is_string($remarkAttribute) ? $sender->$remarkAttribute = '' : null;
475 10
    }
476
477
    /**
478
     * The event triggered after insert new relation.
479
     * The opposite relation should be inserted without triggering events
480
     * simultaneously after new relation inserted,
481
     * @param ModelEvent $event
482
     */
483 10
    public function onInsertRelation($event)
484
    {
485 10
        $sender = $event->sender;
486 10
        if ($sender->relationType == static::$relationMutual) {
487 8
            $opposite = static::buildOppositeRelation($sender);
488 8
            $opposite->off(static::EVENT_AFTER_INSERT, [$opposite, 'onInsertRelation']);
0 ignored issues
show
Bug introduced by
It seems like off() 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...
489 8
            if (!$opposite->save()) {
0 ignored issues
show
Bug introduced by
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...
490
                $opposite->recordWarnings();
0 ignored issues
show
Bug introduced by
It seems like recordWarnings() 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...
491
            }
492 8
            $opposite->on(static::EVENT_AFTER_INSERT, [$opposite, 'onInsertRelation']);
0 ignored issues
show
Bug introduced by
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...
493 8
        }
494 10
    }
495
496
    /**
497
     * The event triggered after update relation.
498
     * The opposite relation should be updated without triggering events
499
     * simultaneously after existed relation removed.
500
     * @param ModelEvent $event
501
     */
502 4
    public function onUpdateRelation($event)
503
    {
504 4
        $sender = $event->sender;
505 4
        if ($sender->relationType == static::$relationMutual) {
506 4
            $opposite = static::buildOppositeRelation($sender);
507 4
            $opposite->off(static::EVENT_AFTER_UPDATE, [$opposite, 'onUpdateRelation']);
0 ignored issues
show
Bug introduced by
It seems like off() 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...
508 4
            if (!$opposite->save()) {
0 ignored issues
show
Bug introduced by
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...
509
                $opposite->recordWarnings();
0 ignored issues
show
Bug introduced by
It seems like recordWarnings() 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
            }
511 4
            $opposite->on(static::EVENT_AFTER_UPDATE, [$opposite, 'onUpdateRelation']);
0 ignored issues
show
Bug introduced by
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...
512 4
        }
513 4
    }
514
515
    /**
516
     * The event triggered after delete relation.
517
     * The opposite relation should be deleted without triggering events
518
     * simultaneously after existed relation removed.
519
     * @param ModelEvent $event
520
     */
521 3
    public function onDeleteRelation($event)
522
    {
523 3
        $sender = $event->sender;
524 3
        if ($sender->relationType == static::$relationMutual) {
525 2
            $createdByAttribute = $sender->createdByAttribute;
526 2
            $otherGuidAttribute = $sender->otherGuidAttribute;
527 2
            $sender->off(static::EVENT_AFTER_DELETE, [$sender, 'onDeleteRelation']);
528 2
            static::removeAllRelations($sender->$otherGuidAttribute, $sender->$createdByAttribute);
529 2
            $sender->on(static::EVENT_AFTER_DELETE, [$sender, 'onDeleteRelation']);
530 2
        }
531 3
    }
532
}
533