Completed
Push — master ( b4f9a0...781efd )
by vistart
06:17
created

BlameableTrait::getBlameableAttributeRules()   C

Complexity

Conditions 7
Paths 5

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 7.0052

Importance

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