BlameableTrait::getBlameableRulesCacheTag()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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\queries\BaseUserQuery;
16
use yii\base\InvalidParamException;
17
use yii\base\ModelEvent;
18
use yii\base\NotSupportedException;
19
use yii\behaviors\BlameableBehavior;
20
use yii\caching\TagDependency;
21
use yii\data\Pagination;
22
23
/**
24
 * This trait is used for building blameable model. It contains following features:
25
 * 1.单列内容;多列内容待定;
26
 * 2.内容类型;具体类型应当自定义;
27
 * 3.内容规则;自动生成;
28
 * 4.归属用户 GUID;
29
 * 5.创建用户 GUID;
30
 * 6.上次更新用户 GUID;
31
 * 7.Confirmation features, provided by [[ConfirmationTrait]];
32
 * @property-read array $blameableAttributeRules Get all rules associated with
33
 * blameable.
34
 * @property array $blameableRules Get or set all the rules associated with
35
 * creator, updater, content and its ID, as well as all the inherited rules.
36
 * @property array $blameableBehaviors Get or set all the behaviors assoriated
37
 * with creator and updater, as well as all the inherited behaviors.
38
 * @property-read array $descriptionRules Get description property rules.
39
 * @property-read mixed $content Content.
40
 * @property-read boolean $contentCanBeEdited Whether this content could be edited.
41
 * @property-read array $contentRules Get content rules.
42
 * @property-read BaseUserModel $user
43
 * @property-read BaseUserModel $updater
44
 * @version 2.0
45
 * @author vistart <[email protected]>
46
 */
47
trait BlameableTrait
48
{
49
    use ConfirmationTrait,
50
        SelfBlameableTrait;
51
52
    private $blameableLocalRules = [];
53
    private $blameableLocalBehaviors = [];
54
55
    /**
56
     * @var boolean|string|array Specify the attribute(s) name of content(s). If
57
     * there is only one content attribute, you can assign its name. Or there
58
     * is multiple attributes associated with contents, you can assign their
59
     * names in array. If you don't want to use this feature, please assign
60
     * false.
61
     * For example:
62
     * ```php
63
     * public $contentAttribute = 'comment'; // only one field named as 'comment'.
64
     * ```
65
     * or
66
     * ```php
67
     * public $contentAttribute = ['year', 'month', 'day']; // multiple fields.
68
     * ```
69
     * or
70
     * ```php
71
     * public $contentAttribute = false; // no need of this feature.
72
     * ```
73
     * If you don't need this feature, you should add rules corresponding with
74
     * `content` in `rules()` method of your user model by yourself.
75
     */
76
    public $contentAttribute = 'content';
77
78
    /**
79
     * @var array built-in validator name or validatation method name and
80
     * additional parameters.
81
     */
82
    public $contentAttributeRule = ['string', 'max' => 255];
83
84
    /**
85
     * @var boolean|string Specify the field which stores the type of content.
86
     */
87
    public $contentTypeAttribute = false;
88
89
    /**
90
     * @var boolean|array Specify the logic type of content, not data type. If
91
     * your content doesn't need this feature. please specify false. If the
92
     * $contentAttribute is specified to false, this attribute will be skipped.
93
     * ```php
94
     * public $contentTypes = [
95
     *     'public',
96
     *     'private',
97
     *     'friend',
98
     * ];
99
     * ```
100
     */
101
    public $contentTypes = false;
102
103
    /**
104
     * @var boolean|string This attribute speicfy the name of description
105
     * attribute. If this attribute is assigned to false, this feature will be
106
     * skipped.
107
     */
108
    public $descriptionAttribute = false;
109
110
    /**
111
     * @var string
112
     */
113
    public $initDescription = '';
114
115
    /**
116
     * @var string the attribute that will receive current user ID value. This
117
     * attribute must be assigned.
118
     */
119
    public $createdByAttribute = "user_guid";
120
121
    /**
122
     * @var string the attribute that will receive current user ID value.
123
     * Set this property to false if you do not want to record the updater ID.
124
     */
125
    public $updatedByAttribute = "user_guid";
126
127
    /**
128
     * @var boolean Add combinated unique rule if assigned to true.
129
     */
130
    public $idCreatorCombinatedUnique = true;
131
132
    /**
133
     * @var boolean|string The name of user class which own the current entity.
134
     * If this attribute is assigned to false, this feature will be skipped, and
135
     * when you use create() method of UserTrait, it will be assigned with
136
     * current user class.
137
     */
138
    public $userClass;
139
    public static $cacheKeyBlameableRules = 'blameable_rules';
140
    public static $cacheTagBlameableRules = 'tag_blameable_rules';
141
    public static $cacheKeyBlameableBehaviors = 'blameable_behaviors';
142
    public static $cacheTagBlameableBehaviors = 'tag_blameable_behaviors';
143
144
    /**
145
     * @inheritdoc
146
     * ------------
147
     * The classical rules is like following:
148
     * [
149
     *     ['guid', 'required'],
150
     *     ['guid', 'unique'],
151
     *     ['guid', 'string', 'max' => 36],
152
     * 
153
     *     ['id', 'required'],
154
     *     ['id', 'unique'],
155
     *     ['id', 'string', 'max' => 4],
156
     * 
157
     *     ['create_time', 'safe'],
158
     *     ['update_time', 'safe'],
159
     * 
160
     *     ['ip_type', 'in', 'range' => [4, 6]],
161
     *     ['ip_1', 'number', 'integerOnly' => true, 'min' => 0],
162
     *     ['ip_2', 'number', 'integerOnly' => true, 'min' => 0],
163
     *     ['ip_3', 'number', 'integerOnly' => true, 'min' => 0],
164
     *     ['ip_4', 'number', 'integerOnly' => true, 'min' => 0],
165
     * 
166
     * 
167
     * ]
168
     * @return array
169
     */
170 45
    public function rules()
171
    {
172 45
        return $this->getBlameableRules();
173
    }
174
175
    /**
176
     * @inheritdoc
177
     */
178 46
    public function behaviors()
179
    {
180 46
        return $this->getBlameableBehaviors();
181
    }
182
183
    /**
184
     * Get total of contents which owned by their owner.
185
     * @return integer
186
     */
187 2
    public function countOfOwner()
188
    {
189 2
        $createdByAttribute = $this->createdByAttribute;
190 2
        return static::find()->where([$createdByAttribute => $this->$createdByAttribute])->count();
191
    }
192
193
    /**
194
     * Get content.
195
     * @return mixed
196
     */
197
    public function getContent()
198
    {
199
        $contentAttribute = $this->contentAttribute;
200
        if ($contentAttribute === false) {
201
            return null;
202
        }
203
        if (is_array($contentAttribute)) {
204
            $content = [];
205
            foreach ($contentAttribute as $key => $value) {
206
                $content[$key] = $this->$value;
207
            }
208
            return $content;
209
        }
210
        return $this->$contentAttribute;
211
    }
212
213
    /**
214
     * Set content.
215
     * @param mixed $content
216
     */
217
    public function setContent($content)
218
    {
219
        $contentAttribute = $this->contentAttribute;
220
        if ($contentAttribute === false) {
221
            return;
222
        }
223
        if (is_array($contentAttribute)) {
224
            foreach ($contentAttribute as $key => $value) {
225
                $this->$value = $content[$key];
226
            }
227
            return;
228
        }
229
        $this->$contentAttribute = $content;
230
    }
231
232
    /**
233
     * Determines whether content could be edited. Your should implement this
234
     * method by yourself.
235
     * @return boolean
236
     * @throws NotSupportedException
237
     */
238
    public function getContentCanBeEdited()
239
    {
240
        if ($this->contentAttribute === false) {
241
            return false;
242
        }
243
        throw new NotSupportedException("This method is not implemented.");
244
    }
245
246
    /**
247
     * Check it has been ever edited.
248
     * @return boolean Whether this content has ever been edited.
249
     */
250
    public function hasEverEdited()
251
    {
252
        $createdAtAttribute = $this->createdByAttribute;
253
        $updatedAtAttribute = $this->updatedByAttribute;
254
        if (!$createdAtAttribute || !$updatedAtAttribute) {
255
            return false;
256
        }
257
        return $this->$createdAtAttribute === $this->$updatedAtAttribute;
258
    }
259
260
    /**
261
     * Get blameable rules cache key.
262
     * @return string cache key.
263
     */
264 45
    public function getBlameableRulesCacheKey()
265
    {
266 45
        return static::className() . $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...
267
    }
268
269
    /**
270
     * Get blameable rules cache tag.
271
     * @return string cache tag
272
     */
273 15
    public function getBlameableRulesCacheTag()
274
    {
275 15
        return static::className() . $this->cachePrefix . static::$cacheTagBlameableRules;
276
    }
277
278
    /**
279
     * Get the rules associated with content to be blamed.
280
     * @return array rules.
281
     */
282 45
    public function getBlameableRules()
283
    {
284 45
        $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...
285 45
        if ($cache) {
286 45
            $this->blameableLocalRules = $cache->get($this->getBlameableRulesCacheKey());
287 45
        }
288
        // 若当前规则不为空,且是数组,则认为是规则数组,直接返回。
289 45
        if (!empty($this->blameableLocalRules) && is_array($this->blameableLocalRules)) {
290 36
            return $this->blameableLocalRules;
291
        }
292
293
        // 父类规则与确认规则合并。
294 15
        if ($cache) {
295 15
            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...
296 15
        }
297 15
        $rules = array_merge(
298 15
            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...
299 15
            $this->getConfirmationRules(),
300 15
            $this->getBlameableAttributeRules(),
301 15
            $this->getDescriptionRules(),
302 15
            $this->getContentRules(),
303 15
            $this->getSelfBlameableRules()
304 15
        );
305 15
        $this->setBlameableRules($rules);
306 15
        return $this->blameableLocalRules;
307
    }
308
309
    /**
310
     * Get the rules associated with `createdByAttribute`, `updatedByAttribute`
311
     * and `idAttribute`-`createdByAttribute` combination unique.
312
     * @return array rules.
313
     */
314 15
    public function getBlameableAttributeRules()
315
    {
316 15
        $rules = [];
317
        // 创建者和上次修改者由 BlameableBehavior 负责,因此标记为安全。
318 15
        if (!is_string($this->createdByAttribute) || empty($this->createdByAttribute)) {
319
            throw new NotSupportedException('You must assign the creator.');
320
        }
321 15
        $rules[] = [
322 15
            [$this->createdByAttribute],
323 15
            'safe',
324
        ];
325
326 15
        if (is_string($this->updatedByAttribute) && !empty($this->updatedByAttribute)) {
327 3
            $rules[] = [
328 3
                [$this->updatedByAttribute],
329 3
                'safe',
330
            ];
331 3
        }
332
333 15
        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...
334 14
            $rules ['id'] = [
335 14
                [$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...
336 14
                    $this->createdByAttribute],
337 14
                'unique',
338 14
                '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...
339 14
                    $this->createdByAttribute],
340
            ];
341 14
        }
342 15
        return $rules;
343
    }
344
345
    /**
346
     * Get the rules associated with `description` attribute.
347
     * @return array rules.
348
     */
349 15
    public function getDescriptionRules()
350
    {
351 15
        $rules = [];
352 15
        if (is_string($this->descriptionAttribute) && !empty($this->descriptionAttribute)) {
353 1
            $rules[] = [
354 1
                [$this->descriptionAttribute],
355
                'string'
356 1
            ];
357 1
            $rules[] = [
358 1
                [$this->descriptionAttribute],
359 1
                'default',
360 1
                'value' => $this->initDescription,
361
            ];
362 1
        }
363 15
        return $rules;
364
    }
365
366
    /**
367
     * Get the rules associated with `content` and `contentType` attributes.
368
     * @return array rules.
369
     */
370 15
    public function getContentRules()
371
    {
372 15
        if (!$this->contentAttribute) {
373 2
            return [];
374
        }
375 13
        $rules = [];
376 13
        $rules[] = [$this->contentAttribute, 'required'];
377 13
        if ($this->contentAttributeRule) {
378 13
            if (is_string($this->contentAttributeRule)) {
379
                $this->contentAttributeRule = [$this->contentAttributeRule];
380
            }
381 13
            if (is_array($this->contentAttributeRule)) {
382 13
                $rules[] = array_merge([$this->contentAttribute], $this->contentAttributeRule);
383 13
            }
384 13
        }
385
386 13
        if (!$this->contentTypeAttribute) {
387 11
            return $rules;
388
        }
389
390 2
        if (is_array($this->contentTypes) && !empty($this->contentTypes)) {
391 2
            $rules[] = [[
392 2
                $this->contentTypeAttribute],
393 2
                'required'];
394 2
            $rules[] = [[
395 2
                $this->contentTypeAttribute],
396 2
                'in',
397 2
                'range' => array_keys($this->contentTypes)];
398 2
        }
399 2
        return $rules;
400
    }
401
402
    /**
403
     * Set blameable rules.
404
     * @param array $rules
405
     */
406 15
    protected function setBlameableRules($rules = [])
407
    {
408 15
        $this->blameableLocalRules = $rules;
409 15
        $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...
410 15
        if ($cache) {
411 15
            $tagDependency = new TagDependency(['tags' => [$this->getBlameableRulesCacheTag()]]);
412 15
            $cache->set($this->getBlameableRulesCacheKey(), $rules, 0, $tagDependency);
413 15
        }
414 15
    }
415
416
    /**
417
     * Get blameable behaviors cache key.
418
     * @return string cache key.
419
     */
420 46
    public function getBlameableBehaviorsCacheKey()
421
    {
422 46
        return static::className() . $this->cachePrefix . static::$cacheKeyBlameableBehaviors;
423
    }
424
425
    /**
426
     * Get blameable behaviors cache tag.
427
     * @return string cache tag.
428
     */
429 15
    public function getBlameableBehaviorsCacheTag()
430
    {
431 15
        return static::className() . $this->cachePrefix . static::$cacheTagBlameableBehaviors;
432
    }
433
434
    /**
435
     * Get blameable behaviors. If current behaviors array is empty, the init
436
     * array will be given.
437
     * @return array
438
     */
439 46
    public function getBlameableBehaviors()
440
    {
441 46
        $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...
442 46
        if ($cache) {
443 46
            $this->blameableLocalBehaviors = $cache->get($this->getBlameableBehaviorsCacheKey());
444 46
        }
445 46
        if (empty($this->blameableLocalBehaviors) || !is_array($this->blameableLocalBehaviors)) {
446 15
            if ($cache) {
447 15
                TagDependency::invalidate($cache, [$this->getEntityBehaviorsCacheTag()]);
0 ignored issues
show
Bug introduced by
The method getEntityBehaviorsCacheTag() does not exist on vistart\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...
448 15
            }
449 15
            $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...
450 15
            $behaviors['blameable'] = [
451 15
                'class' => BlameableBehavior::className(),
452 15
                'createdByAttribute' => $this->createdByAttribute,
453 15
                'updatedByAttribute' => $this->updatedByAttribute,
454 15
                'value' => [$this,
455 15
                    'onGetCurrentUserGuid'],
456
            ];
457 15
            $this->setBlameableBehaviors($behaviors);
458 15
        }
459 46
        return $this->blameableLocalBehaviors;
460
    }
461
462
    /**
463
     * Set blameable behaviors.
464
     * @param array $behaviors
465
     */
466 15
    protected function setBlameableBehaviors($behaviors = [])
467
    {
468 15
        $this->blameableLocalBehaviors = $behaviors;
469 15
        $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...
470 15
        if ($cache) {
471 15
            $tagDependencyConfig = ['tags' => [$this->getBlameableBehaviorsCacheTag()]];
472 15
            $tagDependency = new TagDependency($tagDependencyConfig);
473 15
            $cache->set($this->getBlameableBehaviorsCacheKey(), $behaviors, 0, $tagDependency);
474 15
        }
475 15
    }
476
477
    /**
478
     * Set description.
479
     * @return string description.
480
     */
481
    public function getDescription()
482
    {
483
        $descAttribute = $this->descriptionAttribute;
484
        return is_string($descAttribute) ? $this->$descAttribute : null;
485
    }
486
487
    /**
488
     * Get description.
489
     * @param string $desc description.
490
     * @return string|null description if enabled, or null if disabled.
491
     */
492
    public function setDescription($desc)
493
    {
494
        $descAttribute = $this->descriptionAttribute;
495
        return is_string($descAttribute) ? $this->$descAttribute = $desc : null;
496
    }
497
498
    /**
499
     * Get blame who owned this blameable model.
500
     * NOTICE! This method will not check whether `$userClass` exists. You should
501
     * specify it in `init()` method.
502
     * @return BaseUserQuery user.
503
     */
504 1
    public function getUser()
505
    {
506 1
        $userClass = $this->userClass;
507 1
        $model = $userClass::buildNoInitModel();
508 1
        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...
509
    }
510
511
    /**
512
     * Get updater who updated this blameable model recently.
513
     * NOTICE! This method will not check whether `$userClass` exists. You should
514
     * specify it in `init()` method.
515
     * @return BaseUserQuery user.
516
     */
517 1
    public function getUpdater()
518
    {
519 1
        if (!is_string($this->updatedByAttribute)) {
520 1
            return null;
521
        }
522
        $userClass = $this->userClass;
523
        $model = $userClass::buildNoInitModel();
524
        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...
525
    }
526
527
    /**
528
     * This event is triggered before the model update.
529
     * This method is ONLY used for being triggered by event. DO NOT call,
530
     * override or modify it directly, unless you know the consequences.
531
     * @param ModelEvent $event
532
     */
533 15
    public function onContentChanged($event)
534
    {
535 15
        $sender = $event->sender;
536 15
        $sender->resetConfirmation();
537 15
    }
538
539
    /**
540
     * Return the current user's GUID if current model doesn't specify the owner
541
     * yet, or return the owner's GUID if current model has been specified.
542
     * This method is ONLY used for being triggered by event. DO NOT call,
543
     * override or modify it directly, unless you know the consequences.
544
     * @param ModelEvent $event
545
     * @return string the GUID of current user or the owner.
546
     */
547 45
    public function onGetCurrentUserGuid($event)
548
    {
549 45
        $sender = $event->sender;
550 45
        if (isset($sender->attributes[$sender->createdByAttribute])) {
551 45
            return $sender->attributes[$sender->createdByAttribute];
552
        }
553
        $identity = \Yii::$app->user->identity;
554
        if ($identity) {
555
            $igAttribute = $identity->guidAttribute;
556
            return $identity->$igAttribute;
557
        }
558
    }
559
560
    /**
561
     * Initialize type of content. the first of element[index is 0] of
562
     * $contentTypes will be used.
563
     * @param ModelEvent $event
564
     */
565 45
    public function onInitContentType($event)
566
    {
567 45
        $sender = $event->sender;
568 45
        if (!isset($sender->contentTypeAttribute) || !is_string($sender->contentTypeAttribute)) {
569 38
            return;
570
        }
571 7
        $contentTypeAttribute = $sender->contentTypeAttribute;
572 7
        if (!isset($sender->$contentTypeAttribute) &&
573 7
            !empty($sender->contentTypes) &&
574 7
            is_array($sender->contentTypes)) {
575 7
            $sender->$contentTypeAttribute = $sender->contentTypes[0];
576 7
        }
577 7
    }
578
579
    /**
580
     * Initialize description property with $initDescription.
581
     * @param ModelEvent $event
582
     */
583 46
    public function onInitDescription($event)
584
    {
585 46
        $sender = $event->sender;
586 46
        if (!isset($sender->descriptionAttribute) || !is_string($sender->descriptionAttribute)) {
587 40
            return;
588
        }
589 6
        $descriptionAttribute = $sender->descriptionAttribute;
590 6
        if (empty($sender->$descriptionAttribute)) {
591 6
            $sender->$descriptionAttribute = $sender->initDescription;
592 6
        }
593 6
    }
594
595
    /**
596
     * Attach events associated with blameable model.
597
     */
598 46
    public function initBlameableEvents()
599
    {
600 46
        $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...
601 46
        $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...
602 46
        $contentTypeAttribute = $this->contentTypeAttribute;
603 46
        if (!isset($this->$contentTypeAttribute)) {
604 45
            $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...
605 45
        }
606 46
        $descriptionAttribute = $this->descriptionAttribute;
607 46
        if (!isset($this->$descriptionAttribute)) {
608 46
            $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...
609 46
        }
610 46
        $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...
611 46
        $this->initSelfBlameableEvents();
612 46
    }
613
614
    /**
615
     * @inheritdoc
616
     */
617 14
    public function enabledFields()
618
    {
619 14
        $fields = parent::enabledFields();
620 14
        if (is_string($this->createdByAttribute)) {
621 14
            $fields[] = $this->createdByAttribute;
622 14
        }
623 14
        if (is_string($this->updatedByAttribute)) {
624 2
            $fields[] = $this->updatedByAttribute;
625 2
        }
626 14
        if (is_string($this->contentAttribute)) {
627 14
            $fields[] = $this->contentAttribute;
628 14
        }
629 14
        if (is_array($this->contentAttribute)) {
630
            $fields = array_merge($fields, $this->contentAttribute);
631
        }
632 14
        if (is_string($this->descriptionAttribute)) {
633
            $fields[] = $this->descriptionAttribute;
634
        }
635 14
        if (is_string($this->confirmationAttribute)) {
636
            $fields[] = $this->confirmationAttribute;
637
        }
638 14
        if (is_string($this->parentAttribute)) {
639
            $fields[] = $this->parentAttribute;
640
        }
641 14
        return $fields;
642
    }
643
644
    /**
645
     * Find all follows by specified identity. If `$identity` is null, the logged-in
646
     * identity will be taken.
647
     * @param string|integer $pageSize If it is 'all`, then will find all follows,
648
     * the `$currentPage` parameter will be skipped. If it is integer, it will be
649
     * regarded as sum of models in one page.
650
     * @param integer $currentPage The current page number, begun with 0.
651
     * @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...
652
     * @return static[] If no follows, null will be given, or return follow array.
653
     */
654
    public static function findAllByIdentityInBatch($pageSize = 'all', $currentPage = 0, $identity = null)
655
    {
656
        if ($pageSize === 'all') {
657
            return static::findByIdentity($identity)->all();
658
        }
659
        return static::findByIdentity($identity)->page($pageSize, $currentPage)->all();
660
    }
661
662
    /**
663
     * Find one follow by specified identity. If `$identity` is null, the logged-in
664
     * identity will be taken. If $identity doesn't has the follower, null will
665
     * be given.
666
     * @param integer $id user id.
667
     * @param boolean $throwException
668
     * @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...
669
     * @return static
670
     * @throws InvalidParamException
671
     */
672
    public static function findOneById($id, $throwException = true, $identity = null)
673
    {
674
        $query = static::findByIdentity($identity);
675
        if (!empty($id)) {
676
            $query = $query->id($id);
677
        }
678
        $model = $query->one();
679
        if (!$model && $throwException) {
680
            throw new InvalidParamException('Model Not Found.');
681
        }
682
        return $model;
683
    }
684
685
    /**
686
     * Get total of follows of specified identity.
687
     * @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...
688
     * @return integer total.
689
     */
690
    public static function countByIdentity($identity = null)
691
    {
692
        return static::findByIdentity($identity)->count();
693
    }
694
695
    /**
696
     * Get pagination, used for building contents page by page.
697
     * @param integer $limit
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 Pagination
700
     */
701
    public static function getPagination($limit = 10, $identity = null)
702
    {
703
        $limit = (int) $limit;
704
        $count = static::countByIdentity($identity);
705
        if ($limit > $count) {
706
            $limit = $count;
707
        }
708
        return new Pagination(['totalCount' => $count, 'pageSize' => $limit]);
709
    }
710
}
711