Completed
Push — master ( e765e7...0b5840 )
by vistart
05:28
created

UserRelationTrait::getRemark()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 5
ccs 0
cts 3
cp 0
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
crap 6
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
18
/**
19
 * Relation features.
20
 * This trait should be used in user relation model which is extended from
21
 * [[BaseBlameableModel]], and is specified `$userClass` property. And the user
22
 * class should be extended from [[BaseUserModel]], or any other classes used
23
 * [[UserTrait]].
24
 * Notice: Several methods associated with "inserting", "updating" and "removing" may
25
 * involve more DB operations, I strongly recommend those methods to be placed in
26
 * transaction execution, in order to ensure data consistency.
27
 * If you want to use group feature, the class used [[UserRelationGroupTrait]]
28
 * must be used coordinately.
29
 * @property array $groupGuids the guid array of all groups which owned by current relation.
30
 * @property-read array $allGroups
31
 * @property-read array $nonGroupMembers
32
 * @property-read integer $groupsCount
33
 * @property-read array $groupsRules
34
 * @property boolean $isFavorite
35
 * @property-read \vistart\Models\models\BaseUserModel $initiator
36
 * @property-read \vistart\Models\models\BaseUserModel $recipient
37
 * @property-read \vistart\Models\models\BaseUserRelationModel $opposite
38
 * @version 2.0
39
 * @author vistart <[email protected]>
40
 */
41
trait UserRelationTrait
42
{
43
    use mb {
44
        mb::addBlame as addGroup;
45
        mb::createBlame as createGroup;
46
        mb::addOrCreateBlame as addOrCreateGroup;
47
        mb::removeBlame as removeGroup;
48
        mb::removeAllBlames as removeAllGroups;
49
        mb::getBlame as getGroup;
50
        mb::getOrCreateBlame as getOrCreateGroup;
51
        mb::getBlameds as getGroupMembers;
52
        mb::getBlameGuids as getGroupGuids;
53
        mb::setBlameGuids as setGroupGuids;
54
        mb::getAllBlames as getAllGroups;
55
        mb::getNonBlameds as getNonGroupMembers;
56
        mb::getBlamesCount as getGroupsCount;
57
        mb::getMultipleBlameableAttributeRules as getGroupsRules;
58
        mb::getEmptyBlamesJson as getEmptyGroupJson;
59
    }
60
61
    /**
62
     * @var string the another party of the relation.
63
     */
64
    public $otherGuidAttribute = 'other_guid';
65
66
    /**
67
     * @var string
68
     */
69
    public $remarkAttribute = 'remark';
70
    public static $relationSingle = 0;
71
    public static $relationMutual = 1;
72
    public $relationType = 1;
73
    public $relationTypes = [
74
        0 => 'Single',
75
        1 => 'Mutual',
76
    ];
77
78
    /**
79
     * @var string the attribute name of which determines the relation type.
80
     */
81
    public $mutualTypeAttribute = 'type';
82
    public static $mutualTypeNormal = 0x00;
83
    public static $mutualTypeSuspend = 0x01;
84
85
    /**
86
     * @var array Mutual types.
87
     */
88
    public static $mutualTypes = [
89
        0x00 => 'Normal',
90
        0x01 => 'Suspend',
91
    ];
92
93
    /**
94
     * @var string the attribute name of which determines the `favorite` field.
95
     */
96
    public $favoriteAttribute = 'favorite';
97
98
    /**
99
     * Permit to build self relation.
100
     * @var boolean 
101
     */
102
    public $relationSelf = false;
103
104
    /**
105
     * Get whether this relation is favorite or not.
106
     * @return boolean
107
     */
108 1
    public function getIsFavorite()
109
    {
110 1
        $favoriteAttribute = $this->favoriteAttribute;
111 1
        return is_string($favoriteAttribute) ? (int) $this->$favoriteAttribute > 0 : null;
112
    }
113
114
    /**
115
     * Set favorite.
116
     * @param boolean $fav
117
     */
118 1
    public function setIsFavorite($fav)
119
    {
120 1
        $favoriteAttribute = $this->favoriteAttribute;
121 1
        return is_string($favoriteAttribute) ? $this->$favoriteAttribute = ($fav ? 1 : 0) : null;
122
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127 8
    public function rules()
128
    {
129 8
        return array_merge(parent::rules(), $this->getUserRelationRules());
130
    }
131
132
    /**
133
     * Get initiator.
134
     * @return \vistart\Models\queries\BaseUserQuery
135
     */
136
    public function getInitiator()
137
    {
138
        return $this->getUser();
0 ignored issues
show
Bug introduced by
The method getUser() does not exist on vistart\Models\traits\UserRelationTrait. Did you maybe mean getUserRelationRules()?

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...
139
    }
140
141
    /**
142
     * Get recipient.
143
     * @return \vistart\Models\queries\BaseUserQuery
144
     */
145
    public function getRecipient()
146
    {
147
        if (!is_string($this->otherGuidAttribute)) {
148
            return null;
149
        }
150
        $userClass = $this->userClass;
0 ignored issues
show
Bug introduced by
The property userClass 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...
151
        $model = $userClass::buildNoInitModel();
152
        return $this->hasOne($userClass::className(), [$model->guidAttribute => $this->otherGuidAttribute]);
0 ignored issues
show
Bug introduced by
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...
153
    }
154
155
    /**
156
     * Validation rules associated with user relation.
157
     * @return array rules.
158
     */
159 8
    public function getUserRelationRules()
160
    {
161 8
        $rules = [];
162 8
        if ($this->relationType == static::$relationMutual) {
163
            $rules = [
164 7
                [[$this->mutualTypeAttribute], 'in', 'range' => array_keys(static::$mutualTypes)],
165 7
                [[$this->mutualTypeAttribute], 'default', 'value' => static::$mutualTypeNormal],
166 7
            ];
167 7
        }
168 8
        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...
169
    }
170
171
    /**
172
     * Get remark.
173
     * @return string remark.
174
     */
175
    public function getRemark()
176
    {
177
        $remarkAttribute = $this->remarkAttribute;
178
        return is_string($remarkAttribute) ? $this->$remarkAttribute : null;
179
    }
180
181
    /**
182
     * Set remark.
183
     * @param string $remark
184
     * @return string remark.
185
     */
186
    public function setRemark($remark)
187
    {
188
        $remarkAttribute = $this->remarkAttribute;
189
        return is_string($remarkAttribute) ? $this->$remarkAttribute = $remark : null;
190
    }
191
192
    /**
193
     * Validation rules associated with remark attribute.
194
     * @return array rules.
195
     */
196 8
    public function getRemarkRules()
197
    {
198 8
        return is_string($this->remarkAttribute) ? [
199 8
            [[$this->remarkAttribute], 'string'],
200 8
            [[$this->remarkAttribute], 'default', 'value' => ''],
201 8
            ] : [];
202
    }
203
204
    /**
205
     * Validation rules associated with favorites attribute.
206
     * @return array rules.
207
     */
208 8
    public function getFavoriteRules()
209
    {
210 8
        return is_string($this->favoriteAttribute) ? [
211 8
            [[$this->favoriteAttribute], 'boolean'],
212 8
            [[$this->favoriteAttribute], 'default', 'value' => 0],
213 8
            ] : [];
214
    }
215
216
    /**
217
     * Validation rules associated with other guid attribute.
218
     * @return array rules.
219
     */
220 8
    public function getOtherGuidRules()
221
    {
222
        $rules = [
223 8
            [[$this->otherGuidAttribute], 'required'],
224 8
            [[$this->otherGuidAttribute], 'string', 'max' => 36],
225 8
            [[$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...
226 8
        ];
227 8
        return $rules;
228
    }
229
230
    /**
231
     * Attach events associated with user relation.
232
     */
233 8
    public function initUserRelationEvents()
234
    {
235 8
        $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...
236 8
        $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...
237 8
        $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...
238 8
        $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...
239 8
        $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...
240 8
        $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...
241 8
        $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...
242 8
    }
243
244
    /**
245
     * Get opposite relation against self.
246
     * @return \vistart\Models\models\BaseUserRelationModel
247
     */
248 7
    public function getOpposite()
249
    {
250 7
        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...
251 1
            return null;
252
        }
253 7
        $createdByAttribute = $this->createdByAttribute;
254 7
        $otherGuidAttribute = $this->otherGuidAttribute;
255 7
        return static::find()->opposite($this->$createdByAttribute, $this->$otherGuidAttribute);
256
    }
257
258
    /**
259
     * Build new or return existed suspend mutual relation, of return null if
260
     * current type is not mutual.
261
     * @see buildRelation()
262
     * @param BaseUserModel|string $user Initiator or its GUID.
263
     * @param BaseUserModel|string $other Recipient or its GUID.
264
     * @return \vistart\Models\models\BaseUserRelationModel The relation will be
265
     * given if exists, or return a new relation.
266
     */
267 1
    public static function buildSuspendRelation($user, $other)
268
    {
269 1
        $relation = static::buildRelation($user, $other);
270 1
        if ($relation->relationType != static::$relationMutual) {
271
            return null;
272
        }
273 1
        $btAttribute = $relation->mutualTypeAttribute;
274 1
        $relation->$btAttribute = static::$mutualTypeSuspend;
275 1
        return $relation;
276
    }
277
278
    /**
279
     * Build new or return existed normal relation.
280
     * The status of mutual relation will be changed to normal if it is not. 
281
     * @see buildRelation()
282
     * @param BaseUserModel|string $user Initiator or its GUID.
283
     * @param BaseUserModel|string $other Recipient or its GUID.
284
     * @return \vistart\Models\models\BaseUserRelationModel The relation will be
285
     * given if exists, or return a new relation.
286
     */
287 8
    public static function buildNormalRelation($user, $other)
288
    {
289 8
        $relation = static::buildRelation($user, $other);
290 8
        if ($relation->relationType == static::$relationMutual) {
291 7
            $btAttribute = $relation->mutualTypeAttribute;
292 7
            $relation->$btAttribute = static::$mutualTypeNormal;
293 7
        }
294 8
        return $relation;
295
    }
296
297
    /**
298
     * Build new or return existed relation between initiator and recipient.
299
     * If relation between initiator and recipient is not found, new relation will
300
     * be built. If initiator and recipient are the same one and it is not allowed
301
     * to build self relation, null will be given.
302
     * If you want to know whether the relation exists, you can check the return
303
     * value of `getIsNewRecord()` method.
304
     * @param BaseUserModel|string $user Initiator or its GUID.
305
     * @param BaseUserModel|string $other Recipient or its GUID.
306
     * @return \vistart\Models\models\BaseUserRelationModel The relation will be
307
     * given if exists, or return a new relation. Or return null if not allowed
308
     * to build self relation,
309
     */
310 8
    protected static function buildRelation($user, $other)
311
    {
312 8
        $relationQuery = static::find()->initiators($user)->recipients($other);
313 8
        $noInit = $relationQuery->noInitModel;
314 8
        $relation = $relationQuery->one();
315 8
        if (!$relation) {
316 8
            $createdByAttribute = $noInit->createdByAttribute;
317 8
            $otherGuidAttribute = $noInit->otherGuidAttribute;
318 8
            $userClass = $noInit->userClass;
319 8
            if ($user instanceof BaseUserModel) {
320 8
                $userClass = $userClass ? : $user->className();
321 8
                $user = $user->guid;
322 8
            }
323 8
            if ($other instanceof BaseUserModel) {
324 8
                $other = $other->guid;
325 8
            }
326 8
            if (!$noInit->relationSelf && $user == $other) {
327
                return null;
328
            }
329 8
            $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...
330 8
        }
331 8
        return $relation;
332
    }
333
334
    /**
335
     * Build opposite relation throughout the current relation. The opposite
336
     * relation will be given if existed.
337
     * @param \vistart\Models\models\BaseUserRelationModel $relation
338
     * @return \vistart\Models\models\BaseUserRelationModel
339
     */
340 7
    protected static function buildOppositeRelation($relation)
341
    {
342 7
        if (!$relation) {
343
            return null;
344
        }
345 7
        $createdByAttribute = $relation->createdByAttribute;
346 7
        $otherGuidAttribute = $relation->otherGuidAttribute;
347 7
        $opposite = static::buildRelation($relation->$otherGuidAttribute, $relation->$createdByAttribute);
348 7
        if ($relation->relationType == static::$relationSingle) {
349
            $opposite->relationType = static::$relationSingle;
350 7
        } elseif ($relation->relationType == static::$relationMutual) {
351 7
            $mutualTypeAttribute = $relation->mutualTypeAttribute;
352 7
            $opposite->$mutualTypeAttribute = $relation->$mutualTypeAttribute;
353 7
        }
354 7
        return $opposite;
355
    }
356
357
    /**
358
     * Remove myself.
359
     * @return integer|false The number of relations removed, or false if the remove
360
     * is unsuccessful for some reason. Note that it is possible the number of relations
361
     * removed is 0, even though the remove execution is successful.
362
     */
363 2
    public function remove()
364
    {
365 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...
366
    }
367
368
    /**
369
     * Remove first relation between initiator(s) and recipient(s).
370
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
371
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
372
     * @return integer|false The number of relations removed.
373
     */
374 1
    public static function removeOneRelation($user, $other)
375
    {
376 1
        return static::find()->initiators($user)->recipients($other)->one()->delete();
377
    }
378
379
    /**
380
     * Remove all relations between initiator(s) and recipient(s).
381
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
382
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
383
     * @return integer The number of relations removed.
384
     */
385 2
    public static function removeAllRelations($user, $other)
386
    {
387 2
        $rni = static::buildNoInitModel();
388 2
        $createdByAttribute = $rni->createdByAttribute;
389 2
        $otherGuidAttribute = $rni->otherGuidAttribute;
390 2
        return static::deleteAll([$createdByAttribute => $user, $otherGuidAttribute => $other]);
391
    }
392
393
    /**
394
     * Get first relation between initiator(s) and recipient(s).
395
     * @param BaseUserModel|string|array $user Initiator or its guid, or array of them.
396
     * @param BaseUserModel|string|array $other Recipient or its guid, or array of them.
397
     * @return \vistart\Models\models\BaseUserRelationModel
398
     */
399 1
    public static function findOneRelation($user, $other)
400
    {
401 1
        return static::find()->initiators($user)->recipients($other)->one();
402
    }
403
404
    /**
405
     * Get first opposite relation between initiator(s) and recipient(s).
406
     * @param BaseUserModel|string $user Initiator or its guid, or array of them.
407
     * @param BaseUserModel|string $other Recipient or its guid, or array of them.
408
     * @return \vistart\Models\models\BaseUserRelationModel
409
     */
410 7
    public static function findOneOppositeRelation($user, $other)
411
    {
412 7
        return static::find()->initiators($other)->recipients($user)->one();
413
    }
414
415
    /**
416
     * Get user's or users' all relations, or by specified groups.
417
     * @param BaseUserModel|string|array $user Initiator or its GUID, or Initiators or their GUIDs.
418
     * @param BaseUserRelationGroupModel|string|array|null $groups UserRelationGroup
419
     * or its guid, or array of them. If you do not want to delimit the groups, please assign null.
420
     * @return array all eligible relations
421
     */
422
    public static function findOnesAllRelations($user, $groups = null)
423
    {
424
        return static::find()->initiators($user)->groups($groups)->all();
425
    }
426
427
    /**
428
     * Initialize groups attribute.
429
     * @param \yii\base\Event $event
430
     */
431 8
    public function onInitGroups($event)
432
    {
433 8
        $sender = $event->sender;
434 8
        $sender->removeAllGroups();
435 8
    }
436
437
    /**
438
     * Initialize remark attribute.
439
     * @param \yii\base\Event $event
440
     */
441 8
    public function onInitRemark($event)
442
    {
443 8
        $sender = $event->sender;
444 8
        $remarkAttribute = $sender->remarkAttribute;
445 8
        is_string($remarkAttribute) ? $sender->$remarkAttribute = '' : null;
446 8
    }
447
448
    /**
449
     * The event triggered after insert new relation.
450
     * The opposite relation should be inserted without triggering events
451
     * simultaneously after new relation inserted,
452
     * @param \yii\base\Event $event
453
     */
454 8
    public function onInsertRelation($event)
455
    {
456 8
        $sender = $event->sender;
457 8
        if ($sender->relationType == static::$relationMutual) {
458 7
            $opposite = static::buildOppositeRelation($sender);
459 7
            $opposite->off(static::EVENT_AFTER_INSERT, [$opposite, 'onInsertRelation']);
460 7
            if (!$opposite->save()) {
461
                $opposite->recordWarnings();
462
            }
463 7
            $opposite->on(static::EVENT_AFTER_INSERT, [$opposite, 'onInsertRelation']);
464 7
        }
465 8
    }
466
467
    /**
468
     * The event triggered after update relation.
469
     * The opposite relation should be updated without triggering events
470
     * simultaneously after existed relation removed.
471
     * @param \yii\base\Event $event
472
     */
473 3
    public function onUpdateRelation($event)
474
    {
475 3
        $sender = $event->sender;
476 3
        if ($sender->relationType == static::$relationMutual) {
477 3
            $opposite = static::buildOppositeRelation($sender);
478 3
            $opposite->off(static::EVENT_AFTER_UPDATE, [$opposite, 'onUpdateRelation']);
479 3
            if (!$opposite->save()) {
480
                $opposite->recordWarnings();
481
            }
482 3
            $opposite->on(static::EVENT_AFTER_UPDATE, [$opposite, 'onUpdateRelation']);
483 3
        }
484 3
    }
485
486
    /**
487
     * The event triggered after delete relation.
488
     * The opposite relation should be deleted without triggering events
489
     * simultaneously after existed relation removed.
490
     * @param \yii\base\Event $event
491
     */
492 2
    public function onDeleteRelation($event)
493
    {
494 2
        $sender = $event->sender;
495 2
        if ($sender->relationType == static::$relationMutual) {
496 2
            $createdByAttribute = $sender->createdByAttribute;
497 2
            $otherGuidAttribute = $sender->otherGuidAttribute;
498 2
            $sender->off(static::EVENT_AFTER_DELETE, [$sender, 'onDeleteRelation']);
499 2
            static::removeAllRelations($sender->$otherGuidAttribute, $sender->$createdByAttribute);
500 2
            $sender->on(static::EVENT_AFTER_DELETE, [$sender, 'onDeleteRelation']);
501 2
        }
502 2
    }
503
}
504