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

BlameableTrait::onGetCurrentUserGuid()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 4.125

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
ccs 4
cts 8
cp 0.5
rs 9.4285
cc 3
eloc 7
nc 3
nop 1
crap 4.125
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\helpers\Number;
16
use rhosocial\base\models\queries\BaseUserQuery;
17
use yii\base\InvalidParamException;
18
use yii\base\ModelEvent;
19
use yii\base\NotSupportedException;
20
use yii\behaviors\BlameableBehavior;
21
use yii\caching\TagDependency;
22
use yii\data\Pagination;
23
24
/**
25
 * This trait is used for building blameable model. It contains following features:
26
 * 1.单列内容;多列内容待定;
27
 * 2.内容类型;具体类型应当自定义;
28
 * 3.内容规则;自动生成;
29
 * 4.归属用户 GUID;
30
 * 5.创建用户 GUID;
31
 * 6.上次更新用户 GUID;
32
 * 7.Confirmation features, provided by [[ConfirmationTrait]];
33
 * @property-read array $blameableAttributeRules Get all rules associated with
34
 * blameable.
35
 * @property array $blameableRules Get or set all the rules associated with
36
 * creator, updater, content and its ID, as well as all the inherited rules.
37
 * @property array $blameableBehaviors Get or set all the behaviors assoriated
38
 * with creator and updater, as well as all the inherited behaviors.
39
 * @property-read array $descriptionRules Get description property rules.
40
 * @property-read mixed $content Content.
41
 * @property-read boolean $contentCanBeEdited Whether this content could be edited.
42
 * @property-read array $contentRules Get content rules.
43
 * @property BaseUserModel $user
44
 * @property BaseUserModel $updater
45
 * @version 1.0
46
 * @author vistart <[email protected]>
47
 */
48
trait BlameableTrait
49
{
50
    use ConfirmationTrait,
51
        SelfBlameableTrait;
52
53
    private $blameableLocalRules = [];
54
    private $blameableLocalBehaviors = [];
55
56
    /**
57
     * @var boolean|string|array Specify the attribute(s) name of content(s). If
58
     * there is only one content attribute, you can assign its name. Or there
59
     * is multiple attributes associated with contents, you can assign their
60
     * names in array. If you don't want to use this feature, please assign
61
     * false.
62
     * For example:
63
     * ```php
64
     * public $contentAttribute = 'comment'; // only one field named as 'comment'.
65
     * ```
66
     * or
67
     * ```php
68
     * public $contentAttribute = ['year', 'month', 'day']; // multiple fields.
69
     * ```
70
     * or
71
     * ```php
72
     * public $contentAttribute = false; // no need of this feature.
73
     * ```
74
     * If you don't need this feature, you should add rules corresponding with
75
     * `content` in `rules()` method of your user model by yourself.
76
     */
77
    public $contentAttribute = 'content';
78
79
    /**
80
     * @var array built-in validator name or validatation method name and
81
     * additional parameters.
82
     */
83
    public $contentAttributeRule = ['string', 'max' => 255];
84
85
    /**
86
     * @var boolean|string Specify the field which stores the type of content.
87
     */
88
    public $contentTypeAttribute = false;
89
90
    /**
91
     * @var boolean|array Specify the logic type of content, not data type. If
92
     * your content doesn't need this feature. please specify false. If the
93
     * $contentAttribute is specified to false, this attribute will be skipped.
94
     * ```php
95
     * public $contentTypes = [
96
     *     'public',
97
     *     'private',
98
     *     'friend',
99
     * ];
100
     * ```
101
     */
102
    public $contentTypes = false;
103
104
    /**
105
     * @var boolean|string This attribute speicfy the name of description
106
     * attribute. If this attribute is assigned to false, this feature will be
107
     * skipped.
108
     */
109
    public $descriptionAttribute = false;
110
111
    /**
112
     * @var string
113
     */
114
    public $initDescription = '';
115
116
    /**
117
     * @var string the attribute that will receive current user ID value. This
118
     * attribute must be assigned.
119
     */
120
    public $createdByAttribute = "user_guid";
121
122
    /**
123
     * @var string the attribute that will receive current user ID value.
124
     * Set this property to false if you do not want to record the updater ID.
125
     */
126
    public $updatedByAttribute = "user_guid";
127
128
    /**
129
     * @var boolean Add combinated unique rule if assigned to true.
130
     */
131
    public $idCreatorCombinatedUnique = true;
132
133
    /**
134
     * @var boolean|string The name of user class which own the current entity.
135
     * If this attribute is assigned to false, this feature will be skipped, and
136
     * when you use create() method of UserTrait, it will be assigned with
137
     * current user class.
138
     */
139
    public $userClass;
140
    public static $cacheKeyBlameableRules = 'blameable_rules';
141
    public static $cacheTagBlameableRules = 'tag_blameable_rules';
142
    public static $cacheKeyBlameableBehaviors = 'blameable_behaviors';
143
    public static $cacheTagBlameableBehaviors = 'tag_blameable_behaviors';
144
145
    /**
146
     * @inheritdoc
147
     * ------------
148
     * The classical rules is like following:
149
     * [
150
     *     ['guid', 'required'],
151
     *     ['guid', 'unique'],
152
     *     ['guid', 'string', 'max' => 36],
153
     *
154
     *     ['id', 'required'],
155
     *     ['id', 'unique'],
156
     *     ['id', 'string', 'max' => 4],
157
     *
158
     *     ['created_at', 'safe'],
159
     *     ['updated_at', 'safe'],
160
     *
161
     *     ['ip_type', 'in', 'range' => [4, 6]],
162
     *     ['ip', 'number', 'integerOnly' => true, 'min' => 0],
163
     * ]
164
     * @return array
165
     */
166 69
    public function rules()
167
    {
168 69
        return $this->getBlameableRules();
169
    }
170
171
    /**
172
     * @inheritdoc
173
     */
174 70
    public function behaviors()
175
    {
176 70
        return $this->getBlameableBehaviors();
177
    }
178
179
    /**
180
     * Get total of contents which owned by their owner.
181
     * @return integer
182
     */
183 1
    public function countOfOwner()
184
    {
185 1
        $createdByAttribute = $this->createdByAttribute;
186 1
        return static::find()->where([$createdByAttribute => $this->$createdByAttribute])->count();
187
    }
188
189
    /**
190
     * Get content.
191
     * @return mixed
192
     */
193 4
    public function getContent()
194
    {
195 4
        $contentAttribute = $this->contentAttribute;
196 4
        if ($contentAttribute === false) {
197
            return null;
198
        }
199 4
        if (is_array($contentAttribute)) {
200
            $content = [];
201
            foreach ($contentAttribute as $key => $value) {
202
                $content[$key] = $this->$value;
203
            }
204
            return $content;
205
        }
206 4
        return $this->$contentAttribute;
207
    }
208
209
    /**
210
     * Set content.
211
     * @param mixed $content
212
     */
213 24
    public function setContent($content)
214
    {
215 24
        $contentAttribute = $this->contentAttribute;
216 24
        if ($contentAttribute === false) {
217
            return;
218
        }
219 24
        if (is_array($contentAttribute)) {
220
            foreach ($contentAttribute as $key => $value) {
221
                $this->$value = $content[$key];
222
            }
223
            return;
224
        }
225 24
        $this->$contentAttribute = $content;
226 24
    }
227
228
    /**
229
     * Determines whether content could be edited. Your should implement this
230
     * method by yourself.
231
     * @return boolean
232
     * @throws NotSupportedException
233
     */
234
    public function getContentCanBeEdited()
235
    {
236
        if ($this->contentAttribute === false) {
237
            return false;
238
        }
239
        throw new NotSupportedException("This method is not implemented.");
240
    }
241
242
    /**
243
     * Get blameable rules cache key.
244
     * @return string cache key.
245
     */
246 69
    public function getBlameableRulesCacheKey()
247
    {
248 69
        return static::class . $this->cachePrefix . static::$cacheKeyBlameableRules;
0 ignored issues
show
Bug introduced by
The property cachePrefix 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...
249
    }
250
251
    /**
252
     * Get blameable rules cache tag.
253
     * @return string cache tag
254
     */
255 69
    public function getBlameableRulesCacheTag()
256
    {
257 69
        return static::class . $this->cachePrefix . static::$cacheTagBlameableRules;
258
    }
259
260
    /**
261
     * Get the rules associated with content to be blamed.
262
     * @return array rules.
263
     */
264 69
    public function getBlameableRules()
265
    {
266 69
        $cache = $this->getCache();
0 ignored issues
show
Bug introduced by
It seems like getCache() 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...
267 69
        if ($cache) {
268 69
            $this->blameableLocalRules = $cache->get($this->getBlameableRulesCacheKey());
269
        }
270
        // 若当前规则不为空,且是数组,则认为是规则数组,直接返回。
271 69
        if (!empty($this->blameableLocalRules) && is_array($this->blameableLocalRules)) {
272 16
            return $this->blameableLocalRules;
273
        }
274
275
        // 父类规则与确认规则合并。
276 69
        if ($cache) {
277 69
            TagDependency::invalidate($cache, [$this->getEntityRulesCacheTag()]);
0 ignored issues
show
Bug introduced by
It seems like getEntityRulesCacheTag() 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...
278
        }
279 69
        $rules = array_merge(
280 69
            parent::rules(),
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (rules() instead of getBlameableRules()). Are you sure this is correct? If so, you might want to change this to $this->rules().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
281 69
            $this->getConfirmationRules(),
282 69
            $this->getBlameableAttributeRules(),
283 69
            $this->getDescriptionRules(),
284 69
            $this->getContentRules(),
285 69
            $this->getSelfBlameableRules()
286
        );
287 69
        $this->setBlameableRules($rules);
288 69
        return $this->blameableLocalRules;
289
    }
290
291
    /**
292
     * Get the rules associated with `createdByAttribute`, `updatedByAttribute`
293
     * and `idAttribute`-`createdByAttribute` combination unique.
294
     * @return array rules.
295
     */
296 69
    public function getBlameableAttributeRules()
297
    {
298 69
        $rules = [];
299
        // 创建者和上次修改者由 BlameableBehavior 负责,因此标记为安全。
300 69
        if (!is_string($this->createdByAttribute) || empty($this->createdByAttribute)) {
301
            throw new NotSupportedException('You must assign the creator.');
302
        }
303 69
        $rules[] = [
304 69
            [$this->createdByAttribute],
305 69
            'safe',
306
        ];
307
308 69
        if (is_string($this->updatedByAttribute) && !empty($this->updatedByAttribute)) {
309 42
            $rules[] = [
310 42
                [$this->updatedByAttribute],
311 42
                'safe',
312
            ];
313
        }
314
315 69
        if ($this->idCreatorCombinatedUnique && is_string($this->idAttribute)) {
0 ignored issues
show
Bug introduced by
The property idAttribute does not seem to exist. Did you mean refIdAttribute?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
316 69
            $rules ['id'] = [
317 69
                [$this->idAttribute,
0 ignored issues
show
Bug introduced by
The property idAttribute does not seem to exist. Did you mean refIdAttribute?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
318 69
                    $this->createdByAttribute],
319 69
                'unique',
320 69
                'targetAttribute' => [$this->idAttribute,
0 ignored issues
show
Bug introduced by
The property idAttribute does not seem to exist. Did you mean refIdAttribute?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
321 69
                    $this->createdByAttribute],
322
            ];
323
        }
324 69
        return $rules;
325
    }
326
327
    /**
328
     * Get the rules associated with `description` attribute.
329
     * @return array rules.
330
     */
331 69
    public function getDescriptionRules()
332
    {
333 69
        $rules = [];
334 69
        if (is_string($this->descriptionAttribute) && !empty($this->descriptionAttribute)) {
335 27
            $rules[] = [
336 27
                [$this->descriptionAttribute],
337 27
                'string'
338
            ];
339 27
            $rules[] = [
340 27
                [$this->descriptionAttribute],
341 27
                'default',
342 27
                'value' => $this->initDescription,
343
            ];
344
        }
345 69
        return $rules;
346
    }
347
348
    /**
349
     * Get the rules associated with `content` and `contentType` attributes.
350
     * @return array rules.
351
     */
352 69
    public function getContentRules()
353
    {
354 69
        if (!$this->contentAttribute) {
355 15
            return [];
356
        }
357 54
        $rules = [];
358 54
        $rules[] = [$this->contentAttribute, 'required'];
359 54
        if ($this->contentAttributeRule) {
360 54
            if (is_string($this->contentAttributeRule)) {
361
                $this->contentAttributeRule = [$this->contentAttributeRule];
362
            }
363 54
            if (is_array($this->contentAttributeRule)) {
364 54
                $rules[] = array_merge([$this->contentAttribute], $this->contentAttributeRule);
365
            }
366
        }
367
368 54
        if (!$this->contentTypeAttribute) {
369 42
            return $rules;
370
        }
371
372 12
        if (is_array($this->contentTypes) && !empty($this->contentTypes)) {
373 12
            $rules[] = [[
374 12
                $this->contentTypeAttribute],
375 12
                'required'];
376 12
            $rules[] = [[
377 12
                $this->contentTypeAttribute],
378 12
                'in',
379 12
                'range' => array_keys($this->contentTypes)];
380
        }
381 12
        return $rules;
382
    }
383
384
    /**
385
     * Set blameable rules.
386
     * @param array $rules
387
     */
388 69
    protected function setBlameableRules($rules = [])
389
    {
390 69
        $this->blameableLocalRules = $rules;
391 69
        $cache = $this->getCache();
0 ignored issues
show
Bug introduced by
It seems like getCache() 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...
392 69
        if ($cache) {
393 69
            $tagDependency = new TagDependency(['tags' => [$this->getBlameableRulesCacheTag()]]);
394 69
            $cache->set($this->getBlameableRulesCacheKey(), $rules, 0, $tagDependency);
395
        }
396 69
    }
397
398
    /**
399
     * Get blameable behaviors cache key.
400
     * @return string cache key.
401
     */
402 70
    public function getBlameableBehaviorsCacheKey()
403
    {
404 70
        return static::class . $this->cachePrefix . static::$cacheKeyBlameableBehaviors;
405
    }
406
407
    /**
408
     * Get blameable behaviors cache tag.
409
     * @return string cache tag.
410
     */
411 70
    public function getBlameableBehaviorsCacheTag()
412
    {
413 70
        return static::class . $this->cachePrefix . static::$cacheTagBlameableBehaviors;
414
    }
415
416
    /**
417
     * Get blameable behaviors. If current behaviors array is empty, the init
418
     * array will be given.
419
     * @return array
420
     */
421 70
    public function getBlameableBehaviors()
422
    {
423 70
        $cache = $this->getCache();
0 ignored issues
show
Bug introduced by
It seems like getCache() 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...
424 70
        if ($cache) {
425 70
            $this->blameableLocalBehaviors = $cache->get($this->getBlameableBehaviorsCacheKey());
426
        }
427 70
        if (empty($this->blameableLocalBehaviors) || !is_array($this->blameableLocalBehaviors)) {
428 70
            if ($cache) {
429 70
                TagDependency::invalidate($cache, [$this->getEntityBehaviorsCacheTag()]);
0 ignored issues
show
Bug introduced by
The method getEntityBehaviorsCacheTag() does not exist on rhosocial\base\models\traits\BlameableTrait. Did you maybe mean behaviors()?

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...
430
            }
431 70
            $behaviors = parent::behaviors();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (behaviors() instead of getBlameableBehaviors()). Are you sure this is correct? If so, you might want to change this to $this->behaviors().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
432 70
            $behaviors['blameable'] = [
433 70
                'class' => BlameableBehavior::class,
434 70
                'createdByAttribute' => $this->createdByAttribute,
435 70
                'updatedByAttribute' => $this->updatedByAttribute,
436 70
                'value' => [$this,
437 70
                    'onGetCurrentUserGuid'],
438
            ];
439 70
            $this->setBlameableBehaviors($behaviors);
440
        }
441 70
        return $this->blameableLocalBehaviors;
442
    }
443
444
    /**
445
     * Set blameable behaviors.
446
     * @param array $behaviors
447
     */
448 70
    protected function setBlameableBehaviors($behaviors = [])
449
    {
450 70
        $this->blameableLocalBehaviors = $behaviors;
451 70
        $cache = $this->getCache();
0 ignored issues
show
Bug introduced by
It seems like getCache() 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...
452 70
        if ($cache) {
453 70
            $tagDependencyConfig = ['tags' => [$this->getBlameableBehaviorsCacheTag()]];
454 70
            $tagDependency = new TagDependency($tagDependencyConfig);
455 70
            $cache->set($this->getBlameableBehaviorsCacheKey(), $behaviors, 0, $tagDependency);
456
        }
457 70
    }
458
459
    /**
460
     * Set description.
461
     * @return string description.
462
     */
463 1
    public function getDescription()
464
    {
465 1
        $descAttribute = $this->descriptionAttribute;
466 1
        return is_string($descAttribute) ? $this->$descAttribute : null;
467
    }
468
469
    /**
470
     * Get description.
471
     * @param string $desc description.
472
     * @return string|null description if enabled, or null if disabled.
473
     */
474 1
    public function setDescription($desc)
475
    {
476 1
        $descAttribute = $this->descriptionAttribute;
477 1
        return is_string($descAttribute) ? $this->$descAttribute = $desc : null;
478
    }
479
480
    /**
481
     * Get blame who owned this blameable model.
482
     * NOTICE! This method will not check whether `$userClass` exists. You should
483
     * specify it in `init()` method.
484
     * @return BaseUserQuery user.
485
     */
486 11
    public function getUser()
487
    {
488 11
        $userClass = $this->userClass;
489 11
        $model = $userClass::buildNoInitModel();
490
        /* @var $model BaseUserModel */
491 11
        return $this->hasOne($userClass::className(), [$model->guidAttribute => $this->createdByAttribute]);
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...
492
    }
493
    
494
    /**
495
     *
496
     * @param BaseUserModel|string $user
497
     * @return boolean
498
     */
499 42
    public function setUser($user)
500
    {
501 42
        if ($user instanceof $this->userClass || $user instanceof \yii\web\IdentityInterface) {
502 42
            return $this->{$this->createdByAttribute} = $user->getGUID();
503
        }
504
        if (is_string($user) && preg_match(Number::GUID_REGEX, $user)) {
505
            return $this->{$this->createdByAttribute} = Number::guid_bin($user);
506
        }
507
        if (strlen($user) == 16) {
508
            return $this->{$this->createdByAttribute} = $user;
509
        }
510
        return false;
511
    }
512
513
    /**
514
     * Get updater who updated this blameable model recently.
515
     * NOTICE! This method will not check whether `$userClass` exists. You should
516
     * specify it in `init()` method.
517
     * @return BaseUserQuery user.
518
     */
519 1
    public function getUpdater()
520
    {
521 1
        if (!is_string($this->updatedByAttribute) || empty($this->updatedByAttribute)) {
522
            return null;
523
        }
524 1
        $userClass = $this->userClass;
525 1
        $model = $userClass::buildNoInitModel();
526
        /* @var $model BaseUserModel */
527 1
        return $this->hasOne($userClass::className(), [$model->guidAttribute => $this->updatedByAttribute]);
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...
528
    }
529
    
530
    /**
531
     *
532
     * @param BaseUserModel|string $user
533
     * @return boolean
534
     */
535
    public function setUpdater($user)
536
    {
537
        if (!is_string($this->updatedByAttribute) || empty($this->updatedByAttribute)) {
538
            return false;
539
        }
540
        if ($user instanceof $this->userClass || $user instanceof \yii\web\IdentityInterface) {
541
            return $this->{$this->updatedByAttribute} = $user->getGUID();
542
        }
543
        if (is_string($user) && preg_match(Number::GUID_REGEX, $user)) {
544
            return $this->{$this->updatedByAttribute} = Number::guid_bin($user);
545
        }
546
        if (strlen($user) == 16) {
547
            return $this->{$this->updatedByAttribute} = $user;
548
        }
549
        return false;
550
    }
551
552
    /**
553
     * This event is triggered before the model update.
554
     * This method is ONLY used for being triggered by event. DO NOT call,
555
     * override or modify it directly, unless you know the consequences.
556
     * @param ModelEvent $event
557
     */
558 8
    public function onContentChanged($event)
559
    {
560 8
        $sender = $event->sender;
561
        /* @var $sender static */
562 8
        return $sender->resetConfirmation();
563
    }
564
565
    /**
566
     * Return the current user's GUID if current model doesn't specify the owner
567
     * yet, or return the owner's GUID if current model has been specified.
568
     * This method is ONLY used for being triggered by event. DO NOT call,
569
     * override or modify it directly, unless you know the consequences.
570
     * @param ModelEvent $event
571
     * @return string the GUID of current user or the owner.
572
     */
573 57
    public function onGetCurrentUserGuid($event)
574
    {
575 57
        $sender = $event->sender;
576
        /* @var $sender static */
577 57
        if (isset($sender->attributes[$sender->createdByAttribute])) {
578 57
            return $sender->attributes[$sender->createdByAttribute];
0 ignored issues
show
Bug introduced by
The property attributes 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...
579
        }
580
        $identity = \Yii::$app->user->identity;
581
        /* @var $identity BaseUserModel */
582
        if ($identity) {
583
            return $identity->getGUID();
584
        }
585
    }
586
587
    /**
588
     * Initialize type of content. the first of element[index is 0] of
589
     * $contentTypes will be used.
590
     * @param ModelEvent $event
591
     */
592 12
    public function onInitContentType($event)
593
    {
594 12
        $sender = $event->sender;
595
        /* @var $sender static */
596 12
        if (!is_string($sender->contentTypeAttribute) || empty($sender->contentTypeAttribute)) {
597
            return;
598
        }
599 12
        $contentTypeAttribute = $sender->contentTypeAttribute;
600 12
        if (!isset($sender->$contentTypeAttribute) &&
601 12
            !empty($sender->contentTypes) &&
602 12
            is_array($sender->contentTypes)) {
603 12
            $sender->$contentTypeAttribute = $sender->contentTypes[0];
604
        }
605 12
    }
606
607
    /**
608
     * Initialize description property with $initDescription.
609
     * @param ModelEvent $event
610
     */
611 28
    public function onInitDescription($event)
612
    {
613 28
        $sender = $event->sender;
614
        /* @var $sender static */
615 28
        if (!is_string($sender->descriptionAttribute) || empty($sender->descriptionAttribute)) {
616
            return;
617
        }
618 28
        $descriptionAttribute = $sender->descriptionAttribute;
619 28
        if (empty($sender->$descriptionAttribute)) {
620 28
            $sender->$descriptionAttribute = $sender->initDescription;
621
        }
622 28
    }
623
624
    /**
625
     * Attach events associated with blameable model.
626
     */
627 70
    public function initBlameableEvents()
628
    {
629 70
        $this->on(static::$eventConfirmationChanged, [$this, "onConfirmationChanged"]);
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...
630 70
        $this->on(static::$eventNewRecordCreated, [$this, "onInitConfirmation"]);
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...
631 70
        $contentTypeAttribute = $this->contentTypeAttribute;
632 70
        if (is_string($contentTypeAttribute) && !empty($contentTypeAttribute) && !isset($this->$contentTypeAttribute)) {
633 12
            $this->on(static::$eventNewRecordCreated, [$this, "onInitContentType"]);
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...
634
        }
635 70
        $descriptionAttribute = $this->descriptionAttribute;
636 70
        if (is_string($descriptionAttribute) && !empty($descriptionAttribute) && !isset($this->$descriptionAttribute)) {
637 28
            $this->on(static::$eventNewRecordCreated, [$this, 'onInitDescription']);
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...
638
        }
639 70
        $this->on(static::EVENT_BEFORE_UPDATE, [$this, "onContentChanged"]);
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...
640 70
        $this->initSelfBlameableEvents();
641 70
    }
642
643
    /**
644
     * @inheritdoc
645
     */
646 32
    public function enabledFields()
647
    {
648 32
        $fields = parent::enabledFields();
649 32
        if (is_string($this->createdByAttribute) && !empty($this->createdByAttribute)) {
650 32
            $fields[] = $this->createdByAttribute;
651
        }
652 32
        if (is_string($this->updatedByAttribute) && !empty($this->updatedByAttribute) &&
653 32
            $this->createdByAttribute != $this->updatedByAttribute) {
654
            $fields[] = $this->updatedByAttribute;
655
        }
656 32
        if (is_string($this->contentAttribute)) {
657 32
            $fields[] = $this->contentAttribute;
658
        }
659 32
        if (is_array($this->contentAttribute)) {
660
            $fields = array_merge($fields, $this->contentAttribute);
661
        }
662 32
        if (is_string($this->descriptionAttribute)) {
663 1
            $fields[] = $this->descriptionAttribute;
664
        }
665 32
        if (is_string($this->confirmationAttribute)) {
666 1
            $fields[] = $this->confirmationAttribute;
667
        }
668 32
        if (is_string($this->parentAttribute)) {
669
            $fields[] = $this->parentAttribute;
670
        }
671 32
        return $fields;
672
    }
673
674
    /**
675
     * Find all follows by specified identity. If `$identity` is null, the logged-in
676
     * identity will be taken.
677
     * @param string|integer $pageSize If it is 'all`, then will find all follows,
678
     * the `$currentPage` parameter will be skipped. If it is integer, it will be
679
     * regarded as sum of models in one page.
680
     * @param integer $currentPage The current page number, begun with 0.
681
     * @param {$this->userClass} $identity
0 ignored issues
show
Documentation introduced by
The doc-type {$this->userClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
682
     * @return static[] If no follows, null will be given, or return follow array.
683
     */
684 1
    public static function findAllByIdentityInBatch($pageSize = 'all', $currentPage = 0, $identity = null)
685
    {
686 1
        if ($pageSize === 'all') {
687 1
            return static::findByIdentity($identity)->all();
688
        }
689 1
        return static::findByIdentity($identity)->page($pageSize, $currentPage)->all();
690
    }
691
692
    /**
693
     * Find one follow by specified identity. If `$identity` is null, the logged-in
694
     * identity will be taken. If $identity doesn't has the follower, null will
695
     * be given.
696
     * @param integer $id user id.
697
     * @param boolean $throwException
698
     * @param {$this->userClass} $identity
0 ignored issues
show
Documentation introduced by
The doc-type {$this->userClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
699
     * @return static
700
     * @throws InvalidParamException
701
     */
702 1
    public static function findOneById($id, $throwException = true, $identity = null)
703
    {
704 1
        $query = static::findByIdentity($identity);
705 1
        if (!empty($id)) {
706 1
            $query = $query->id($id);
707
        }
708 1
        $model = $query->one();
709 1
        if (!$model && $throwException) {
710 1
            throw new InvalidParamException('Model Not Found.');
711
        }
712 1
        return $model;
713
    }
714
715
    /**
716
     * Get total of follows of specified identity.
717
     * @param {$this->userClass} $identity
0 ignored issues
show
Documentation introduced by
The doc-type {$this->userClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
718
     * @return integer total.
719
     */
720 1
    public static function countByIdentity($identity = null)
721
    {
722 1
        return (int)(static::findByIdentity($identity)->count());
723
    }
724
725
    /**
726
     * Get pagination, used for building contents page by page.
727
     * @param integer $limit
728
     * @param {$this->userClass} $identity
0 ignored issues
show
Documentation introduced by
The doc-type {$this->userClass} could not be parsed: Unknown type name "{$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
729
     * @return Pagination
730
     */
731
    public static function getPagination($limit = 10, $identity = null)
732
    {
733
        $limit = (int) $limit;
734
        $count = static::countByIdentity($identity);
735
        if ($limit > $count) {
736
            $limit = $count;
737
        }
738
        return new Pagination(['totalCount' => $count, 'pageSize' => $limit]);
739
    }
740
}
741