Completed
Push — master ( bf148f...113cf9 )
by vistart
07:06
created

UserRelationTrait::isMutual()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 2
crap 2
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 rhosocial\base\models\models\BaseUserModel;
16
use rhosocial\base\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 $favoriteRules
32
 * @property boolean $isFavorite
33
 * @property-read static $opposite
34
 * @property-read array $otherGuidRules
35
 * @property string $remark
36
 * @property-read array $remarkRules
37
 * @property-read array $userRelationRules
38
 * @property-read mixed $group
39
 * @property-read array $groupMembers
40
 * @property array $groupGuids
41
 * @property-read array $allGroups
42
 * @property-read array $nonGroupMembers
43
 * @property-read integer $groupsCount
44
 * @property-read array $groupsRules
45
 * @version 1.0
46
 * @author vistart <[email protected]>
47
 */
48
trait UserRelationTrait
49
{
50
    use mb,
51
        MutualTrait {
52
        mb::addBlame as addGroup;
53
        mb::createBlame as createGroup;
54
        mb::addOrCreateBlame as addOrCreateGroup;
55
        mb::removeBlame as removeGroup;
56
        mb::removeAllBlames as removeAllGroups;
57
        mb::getBlame as getGroup;
58
        mb::getOrCreateBlame as getOrCreateGroup;
59
        mb::getBlameds as getGroupMembers;
60
        mb::getBlameGuids as getGroupGuids;
61
        mb::setBlameGuids as setGroupGuids;
62
        mb::getAllBlames as getAllGroups;
63
        mb::getNonBlameds as getNonGroupMembers;
64
        mb::getBlamesCount as getGroupsCount;
65
        mb::getMultipleBlameableAttributeRules as getGroupsRules;
66
    }
67
68
    /**
69
     * @var string
70
     */
71
    public $remarkAttribute = 'remark';
72
    public static $relationSingle = 0;
73
    public static $relationMutual = 1;
74
    public $relationType = 1;
75
    public $relationTypes = [
76
        0 => 'Single',
77
        1 => 'Mutual',
78
    ];
79
80
    /**
81
     * @var string the attribute name of which determines the relation type.
82
     */
83
    public $mutualTypeAttribute = 'type';
84
    public static $mutualTypeNormal = 0x00;
85
    public static $mutualTypeSuspend = 0x01;
86
87
    /**
88
     * @var array Mutual types.
89
     */
90
    public static $mutualTypes = [
91
        0x00 => 'Normal',
92
        0x01 => 'Suspend',
93
    ];
94
95
    /**
96
     * @var string the attribute name of which determines the `favorite` field.
97
     */
98
    public $favoriteAttribute = 'favorite';
99
100
    /**
101
     * Permit to build self relation.
102
     * @var boolean 
103
     */
104
    public $relationSelf = false;
105
106
    /**
107
     * Get whether this relation is favorite or not.
108
     * @return boolean
109
     */
110 1
    public function getIsFavorite()
111
    {
112 1
        $favoriteAttribute = $this->favoriteAttribute;
113 1
        return (is_string($favoriteAttribute) && !empty($favoriteAttribute)) ? (int) $this->$favoriteAttribute > 0 : null;
114
    }
115
116
    /**
117
     * Set favorite.
118
     * @param boolean $fav
119
     */
120 1
    public function setIsFavorite($fav)
121
    {
122 1
        $favoriteAttribute = $this->favoriteAttribute;
123 1
        return (is_string($favoriteAttribute) && !empty($favoriteAttribute)) ? $this->$favoriteAttribute = ($fav ? 1 : 0) : null;
124
    }
125
126
    /**
127
     * @inheritdoc
128
     */
129 15
    public function rules()
130
    {
131 15
        return array_merge(parent::rules(), $this->getUserRelationRules());
132
    }
133
134
    /**
135
     * Validation rules associated with user relation.
136
     * @return array rules.
137
     */
138 15
    public function getUserRelationRules()
139
    {
140 15
        $rules = [];
141 15
        if ($this->relationType == static::$relationMutual) {
142
            $rules = [
143
                [[$this->mutualTypeAttribute], 'in', 'range' => array_keys(static::$mutualTypes)],
144
                [[$this->mutualTypeAttribute], 'default', 'value' => static::$mutualTypeNormal],
145
            ];
146
        }
147 15
        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...
148
    }
149
150
    /**
151
     * Get remark.
152
     * @return string remark.
153
     */
154 1
    public function getRemark()
155
    {
156 1
        $remarkAttribute = $this->remarkAttribute;
157 1
        return is_string($remarkAttribute) ? $this->$remarkAttribute : null;
158
    }
159
160
    /**
161
     * Set remark.
162
     * @param string $remark
163
     * @return string remark.
164
     */
165 1
    public function setRemark($remark)
166
    {
167 1
        $remarkAttribute = $this->remarkAttribute;
168 1
        return is_string($remarkAttribute) ? $this->$remarkAttribute = $remark : null;
169
    }
170
171
    /**
172
     * Validation rules associated with remark attribute.
173
     * @return array rules.
174
     */
175 15
    public function getRemarkRules()
176
    {
177 15
        return is_string($this->remarkAttribute) ? [
178 15
            [[$this->remarkAttribute], 'string'],
179 15
            [[$this->remarkAttribute], 'default', 'value' => ''],
180 15
            ] : [];
181
    }
182
183
    /**
184
     * Validation rules associated with favorites attribute.
185
     * @return array rules.
186
     */
187 15
    public function getFavoriteRules()
188
    {
189 15
        return is_string($this->favoriteAttribute) ? [
190 15
            [[$this->favoriteAttribute], 'boolean'],
191 15
            [[$this->favoriteAttribute], 'default', 'value' => 0],
192 15
            ] : [];
193
    }
194
195
    /**
196
     * Validation rules associated with other guid attribute.
197
     * @return array rules.
198
     */
199 15
    public function getOtherGuidRules()
200
    {
201 15
        $rules = array_merge($this->getMutualRules(), [
202 15
            [[$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...
203
        ]);
204 15
        return $rules;
205
    }
206
207
    /**
208
     * Attach events associated with user relation.
209
     */
210 16
    public function initUserRelationEvents()
211
    {
212 16
        $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...
213 16
        $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...
214 16
        $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...
215 16
        $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...
216 16
        $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...
217 16
        $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...
218 16
        $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...
219 16
    }
220
221
    /**
222
     * Get opposite relation against self.
223
     * @return static
224
     */
225 1
    public function getOpposite()
226
    {
227 1
        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...
228 1
            return null;
229
        }
230 1
        $createdByAttribute = $this->createdByAttribute;
231 1
        $otherGuidAttribute = $this->otherGuidAttribute;
232 1
        return static::find()->opposite($this->$createdByAttribute, $this->$otherGuidAttribute);
233
    }
234
235
    /**
236
     * Check whether the initiator is followed by recipient.
237
     * @param BaseUserModel $initiator
238
     * @param BaseUserModel $recipient
239
     * @return boolean
240
     */
241 3
    public static function isFollowed($initiator, $recipient)
242
    {
243 3
        return static::find()->initiators($recipient)->recipients($initiator)->exists();
244
    }
245
246
    /**
247
     * Check whether the initiator is following recipient.
248
     * @param BaseUserModel $initiator
249
     * @param BaseUserModel $recipient
250
     * @return boolean
251
     */
252 3
    public static function isFollowing($initiator, $recipient)
253
    {
254 3
        return static::find()->initiators($initiator)->recipients($recipient)->exists();
255
    }
256
257
    /**
258
     * Check whether the initiator is following and followed by recipient mutually (Single Relation).
259
     * Or check whether the initiator and recipient are friend whatever the mutual type is normal or suspend.
260
     * @param BaseUserModel $initiator
261
     * @param BaseUserModel $recipient
262
     * @return boolean
263
     */
264 2
    public static function isMutual($initiator, $recipient)
265
    {
266 2
        return static::isFollowed($initiator, $recipient) && static::isFollowing($initiator, $recipient);
267
    }
268
269
    /**
270
     * Check whether the initiator is following and followed by recipient mutually (Single Relation).
271
     * Or check whether the initiator and recipient are friend if the mutual type is normal.
272
     * @param BaseUserModel $initiator
273
     * @param BaseUserModel $recipient
274
     * @return boolean
275
     */
276 1
    public static function isFriend($initiator, $recipient)
277
    {
278 1
        $query = static::find();
279 1
        $model = $query->noInitModel;
280
        /* @var $model static */
281 1
        if ($model->relationType == static::$relationSingle) {
282 1
            return static::isMutual($initiator, $recipient);
283
        }
284
        if ($model->relationType == static::$relationMutual) {
285
            $relation = static::find()->initiators($initiator)->recipients($recipient)->andWhere([$model->mutualTypeAttribute => static::$mutualTypeNormal])->exists();
286
            $inverse = static::find()->recipients($initiator)->initiators($recipient)->andWhere([$model->mutualTypeAttribute => static::$mutualTypeNormal])->exists();
287
            return $relation && $inverse;
288
        }
289
        return false;
290
    }
291
292
    /**
293
     * Build new or return existed suspend mutual relation, or return null if
294
     * current type is not mutual.
295
     * @see buildRelation()
296
     * @param BaseUserModel|string $user Initiator or its GUID.
297
     * @param BaseUserModel|string $other Recipient or its GUID.
298
     * @return static The relation will be
299
     * given if exists, or return a new relation.
300
     */
301 1
    public static function buildSuspendRelation($user, $other)
302
    {
303 1
        $relation = static::buildRelation($user, $other);
304 1
        if (!$relation || $relation->relationType != static::$relationMutual) {
305 1
            return null;
306
        }
307
        $btAttribute = $relation->mutualTypeAttribute;
308
        $relation->$btAttribute = static::$mutualTypeSuspend;
309
        return $relation;
310
    }
311
312
    /**
313
     * Build new or return existed normal relation.
314
     * The status of mutual relation will be changed to normal if it is not. 
315
     * @see buildRelation()
316
     * @param BaseUserModel|string $user Initiator or its GUID.
317
     * @param BaseUserModel|string $other Recipient or its GUID.
318
     * @return static The relation will be
319
     * given if exists, or return a new relation.
320
     */
321 16
    public static function buildNormalRelation($user, $other)
322
    {
323 16
        $relation = static::buildRelation($user, $other);
324 16
        if (!$relation) {
325 1
            return null;
326
        }
327 16
        if ($relation->relationType == static::$relationMutual) {
328
            $btAttribute = $relation->mutualTypeAttribute;
329
            $relation->$btAttribute = static::$mutualTypeNormal;
330
        }
331 16
        return $relation;
332
    }
333
334
    /**
335
     * Build new or return existed relation between initiator and recipient.
336
     * If relation between initiator and recipient is not found, new relation will
337
     * be built. If initiator and recipient are the same one and it is not allowed
338
     * to build self relation, null will be given.
339
     * If you want to know whether the relation exists, you can check the return
340
     * value of `getIsNewRecord()` method.
341
     * @param BaseUserModel|string $user Initiator or its GUID.
342
     * @param BaseUserModel|string $other Recipient or its GUID.
343
     * @return static The relation will be
344
     * given if exists, or return a new relation. Or return null if not allowed
345
     * to build self relation,
346
     */
347 16
    protected static function buildRelation($user, $other)
348
    {
349 16
        $relationQuery = static::find()->initiators($user)->recipients($other);
350 16
        $noInit = $relationQuery->noInitModel;
351 16
        $relation = $relationQuery->one();
352 16
        if (!$relation) {
353 16
            $createdByAttribute = $noInit->createdByAttribute;
354 16
            $otherGuidAttribute = $noInit->otherGuidAttribute;
355 16
            $userClass = $noInit->userClass;
356 16
            if ($user instanceof BaseUserModel) {
357 16
                $userClass = $userClass ? : $user->className();
358 16
                $user = $user->getGUID();
359
            }
360 16
            if ($other instanceof BaseUserModel) {
361 16
                $other = $other->getGUID();
362
            }
363 16
            if (!$noInit->relationSelf && $user == $other) {
364 1
                return null;
365
            }
366 16
            $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...
367
        }
368 16
        return $relation;
369
    }
370
371
    /**
372
     * Build opposite relation throughout the current relation. The opposite
373
     * relation will be given if existed.
374
     * @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...
375
     * @return static
376
     */
377
    protected static function buildOppositeRelation($relation)
378
    {
379
        if (!$relation) {
380
            return null;
381
        }
382
        $createdByAttribute = $relation->createdByAttribute;
383
        $otherGuidAttribute = $relation->otherGuidAttribute;
384
        $opposite = static::buildRelation($relation->$otherGuidAttribute, $relation->$createdByAttribute);
385
        if ($relation->relationType == static::$relationSingle) {
386
            $opposite->relationType = static::$relationSingle;
387
        } elseif ($relation->relationType == static::$relationMutual) {
388
            $mutualTypeAttribute = $relation->mutualTypeAttribute;
389
            $opposite->$mutualTypeAttribute = $relation->$mutualTypeAttribute;
390
        }
391
        return $opposite;
392
    }
393
394
    /**
395
     * Remove myself.
396
     * @return integer|false The number of relations removed, or false if the remove
397
     * is unsuccessful for some reason. Note that it is possible the number of relations
398
     * removed is 0, even though the remove execution is successful.
399
     */
400 16
    public function remove()
401
    {
402 16
        return $this->delete();
0 ignored issues
show
Bug introduced by
The method delete() does not exist on rhosocial\base\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...
403
    }
404
405
    /**
406
     * Remove first relation between initiator(s) and recipient(s).
407
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
408
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
409
     * @return integer|false The number of relations removed.
410
     */
411 1
    public static function removeOneRelation($user, $other)
412
    {
413 1
        return static::find()->initiators($user)->recipients($other)->one()->remove();
414
    }
415
416
    /**
417
     * Remove all relations between initiator(s) and recipient(s).
418
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
419
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
420
     * @return integer The number of relations removed.
421
     */
422 1
    public static function removeAllRelations($user, $other)
423
    {
424 1
        $rni = static::buildNoInitModel();
425 1
        $createdByAttribute = $rni->createdByAttribute;
426 1
        $otherGuidAttribute = $rni->otherGuidAttribute;
427 1
        return static::deleteAll([$createdByAttribute => $user, $otherGuidAttribute => $other]);
428
    }
429
430
    /**
431
     * Get first relation between initiator(s) and recipient(s).
432
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
433
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
434
     * @return static
435
     */
436 4
    public static function findOneRelation($user, $other)
437
    {
438 4
        return static::find()->initiators($user)->recipients($other)->one();
439
    }
440
441
    /**
442
     * Get first opposite relation between initiator(s) and recipient(s).
443
     * @param BaseUserModel|string $user Initiator or its guid, or array of them.
444
     * @param BaseUserModel|string $other Recipient or its guid, or array of them.
445
     * @return static
446
     */
447 1
    public static function findOneOppositeRelation($user, $other)
448
    {
449 1
        return static::find()->initiators($other)->recipients($user)->one();
450
    }
451
452
    /**
453
     * Get user's or users' all relations, or by specified groups.
454
     * @param BaseUserModel|string|array $user Initiator or its GUID, or Initiators or their GUIDs.
455
     * @param BaseUserRelationGroupModel|string|array|null $groups UserRelationGroup
456
     * or its guid, or array of them. If you do not want to delimit the groups, please assign null.
457
     * @return array all eligible relations
458
     */
459 1
    public static function findOnesAllRelations($user, $groups = null)
460
    {
461 1
        return static::find()->initiators($user)->groups($groups)->all();
462
    }
463
464
    /**
465
     * Initialize groups attribute.
466
     * @param ModelEvent $event
467
     */
468 16
    public function onInitGroups($event)
469
    {
470 16
        $sender = $event->sender;
471 16
        $sender->removeAllGroups();
472 16
    }
473
474
    /**
475
     * Initialize remark attribute.
476
     * @param ModelEvent $event
477
     */
478 16
    public function onInitRemark($event)
479
    {
480 16
        $sender = $event->sender;
481 16
        $remarkAttribute = $sender->remarkAttribute;
482 16
        is_string($remarkAttribute) ? $sender->$remarkAttribute = '' : null;
483 16
    }
484
485
    /**
486
     * The event triggered after insert new relation.
487
     * The opposite relation should be inserted without triggering events
488
     * simultaneously after new relation inserted,
489
     * @param ModelEvent $event
490
     */
491 15
    public function onInsertRelation($event)
492
    {
493 15
        $sender = $event->sender;
494 15
        if ($sender->relationType == static::$relationMutual) {
495
            $opposite = static::buildOppositeRelation($sender);
496
            $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...
497
            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...
498
                $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...
499
            }
500
            $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...
501
        }
502 15
    }
503
504
    /**
505
     * The event triggered after update relation.
506
     * The opposite relation should be updated without triggering events
507
     * simultaneously after existed relation removed.
508
     * @param ModelEvent $event
509
     */
510 2
    public function onUpdateRelation($event)
511
    {
512 2
        $sender = $event->sender;
513 2
        if ($sender->relationType == static::$relationMutual) {
514
            $opposite = static::buildOppositeRelation($sender);
515
            $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...
516
            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...
517
                $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...
518
            }
519
            $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...
520
        }
521 2
    }
522
523
    /**
524
     * The event triggered after delete relation.
525
     * The opposite relation should be deleted without triggering events
526
     * simultaneously after existed relation removed.
527
     * @param ModelEvent $event
528
     */
529 16
    public function onDeleteRelation($event)
530
    {
531 16
        $sender = $event->sender;
532 16
        if ($sender->relationType == static::$relationMutual) {
533
            $createdByAttribute = $sender->createdByAttribute;
534
            $otherGuidAttribute = $sender->otherGuidAttribute;
535
            $sender->off(static::EVENT_AFTER_DELETE, [$sender, 'onDeleteRelation']);
536
            static::removeAllRelations($sender->$otherGuidAttribute, $sender->$createdByAttribute);
537
            $sender->on(static::EVENT_AFTER_DELETE, [$sender, 'onDeleteRelation']);
538
        }
539 16
    }
540
}
541