Completed
Push — master ( 7c4bfd...7dff86 )
by vistart
06:37 queued 27s
created

BlameableTrait::getBlameableBehaviors()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5

Importance

Changes 11
Bugs 2 Features 0
Metric Value
c 11
b 2
f 0
dl 0
loc 22
ccs 19
cts 19
cp 1
rs 8.6737
cc 5
eloc 16
nc 6
nop 0
crap 5
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 42
    public function rules()
148
    {
149 42
        return $this->getBlameableRules();
150
    }
151
152
    /**
153
     * @inheritdoc
154
     */
155 42
    public function behaviors()
156
    {
157 42
        return $this->getBlameableBehaviors();
158
    }
159
160
    /**
161
     * Get total of contents which owned by their owner.
162
     * @return integer
163
     */
164 2
    public function countOfOwner()
165
    {
166 2
        $createdByAttribute = $this->createdByAttribute;
167 2
        return static::find()->where([$createdByAttribute => $this->$createdByAttribute])->count();
168
    }
169
170
    /**
171
     * Get content.
172
     * @return mixed
173
     */
174
    public function getContent()
175
    {
176
        $contentAttribute = $this->contentAttribute;
177
        if ($contentAttribute === false) {
178
            return null;
179
        }
180
        if (is_array($contentAttribute)) {
181
            $content = [];
182
            foreach ($contentAttribute as $key => $value) {
183
                $content[$key] = $this->$value;
184
            }
185
            return $content;
186
        }
187
        return $this->$contentAttribute;
188
    }
189
190
    /**
191
     * Set content.
192
     * @param mixed $content
193
     */
194
    public function setContent($content)
195
    {
196
        $contentAttribute = $this->contentAttribute;
197
        if ($contentAttribute === false) {
198
            return;
199
        }
200
        if (is_array($contentAttribute)) {
201
            foreach ($contentAttribute as $key => $value) {
202
                $this->$value = $content[$key];
203
            }
204
            return;
205
        }
206
        $this->$contentAttribute = $content;
207
    }
208
209
    /**
210
     * Determines whether content could be edited. Your should implement this
211
     * method by yourself.
212
     * @return boolean
213
     * @throws NotSupportedException
214
     */
215
    public function getContentCanBeEdited()
216
    {
217
        if ($this->contentAttribute === false) {
218
            return false;
219
        }
220
        throw new NotSupportedException("This method is not implemented.");
221
    }
222
223
    /**
224
     * Check it has been ever edited.
225
     * @return boolean Whether this content has ever been edited.
226
     */
227
    public function hasEverEdited()
228
    {
229
        $createdAtAttribute = $this->createdByAttribute;
230
        $updatedAtAttribute = $this->updatedByAttribute;
231
        if (!$createdAtAttribute || !$updatedAtAttribute) {
232
            return false;
233
        }
234
        return $this->$createdAtAttribute === $this->$updatedAtAttribute;
235
    }
236
237
    /**
238
     * Get blameable rules cache key.
239
     * @return string cache key.
240
     */
241 42
    public function getBlameableRulesCacheKey()
242
    {
243 42
        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...
244
    }
245
246
    /**
247
     * Get blameable rules cache tag.
248
     * @return string cache tag
249
     */
250 15
    public function getBlameableRulesCacheTag()
251
    {
252 15
        return static::className() . $this->cachePrefix . static::$cacheTagBlameableRules;
253
    }
254
255
    /**
256
     * Get the rules associated with content to be blamed.
257
     * @return array rules.
258
     */
259 42
    public function getBlameableRules()
260
    {
261 42
        $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...
262 42
        if ($cache) {
263 42
            $this->blameableLocalRules = $cache->get($this->getBlameableRulesCacheKey());
264 42
        }
265
        // 若当前规则不为空,且是数组,则认为是规则数组,直接返回。
266 42
        if (!empty($this->blameableLocalRules) && is_array($this->blameableLocalRules)) {
267 33
            return $this->blameableLocalRules;
268 2
        }
269
270
        // 父类规则与确认规则合并。
271 15
        if ($cache) {
272 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...
273 15
        }
274 15
        $rules = array_merge(
275 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...
276 15
            $this->getConfirmationRules(),
277 15
            $this->getBlameableAttributeRules(),
278 15
            $this->getDescriptionRules(),
279 15
            $this->getContentRules(),
280 15
            $this->getSelfBlameableRules()
281 15
        );
282 15
        $this->setBlameableRules($rules);
283 15
        return $this->blameableLocalRules;
284
    }
285
286
    /**
287
     * Get the rules associated with `createdByAttribute`, `updatedByAttribute`
288
     * and `idAttribute`-`createdByAttribute` combination unique.
289
     * @return array rules.
290
     */
291 15
    public function getBlameableAttributeRules()
292
    {
293 15
        $rules = [];
294
        // 创建者和上次修改者由 BlameableBehavior 负责,因此标记为安全。
295 15
        if (!is_string($this->createdByAttribute) || empty($this->createdByAttribute)) {
296
            throw new \yii\base\NotSupportedException('You must assign the creator.');
297
        }
298 15
        $rules[] = [
299 15
            [$this->createdByAttribute],
300 15
            'safe',
301
        ];
302
303 15
        if (is_string($this->updatedByAttribute) && !empty($this->updatedByAttribute)) {
304 3
            $rules[] = [
305 3
                [$this->updatedByAttribute],
306 3
                'safe',
307
            ];
308 3
        }
309
310 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...
311 14
            $rules [] = [
312 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...
313 14
                    $this->createdByAttribute],
314 14
                'unique',
315 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...
316 14
                    $this->createdByAttribute],
317
            ];
318 14
        }
319 15
        return $rules;
320
    }
321
322
    /**
323
     * Get the rules associated with `description` attribute.
324
     * @return array rules.
325
     */
326 15
    public function getDescriptionRules()
327
    {
328 15
        $rules = [];
329 15
        if (is_string($this->descriptionAttribute) && !empty($this->descriptionAttribute)) {
330 1
            $rules[] = [
331 1
                [$this->descriptionAttribute],
332
                'string'
333 1
            ];
334 1
            $rules[] = [
335 1
                [$this->descriptionAttribute],
336 1
                'default',
337 1
                'value' => $this->initDescription,
338
            ];
339 1
        }
340 15
        return $rules;
341
    }
342
343
    /**
344
     * Get the rules associated with `content` and `contentType` attributes.
345
     * @return array rules.
346
     */
347 15
    public function getContentRules()
348
    {
349 15
        if (!$this->contentAttribute) {
350 2
            return [];
351
        }
352 13
        $rules = [];
353 13
        $rules[] = [$this->contentAttribute, 'required'];
354 13
        if ($this->contentAttributeRule) {
355 13
            if (is_string($this->contentAttributeRule)) {
356
                $this->contentAttributeRule = [$this->contentAttributeRule];
357
            }
358 13
            if (is_array($this->contentAttributeRule)) {
359 13
                $rules[] = array_merge([$this->contentAttribute], $this->contentAttributeRule);
360 13
            }
361 13
        }
362
363 13
        if (!$this->contentTypeAttribute) {
364 11
            return $rules;
365
        }
366
367 2
        if (is_array($this->contentTypes) && !empty($this->contentTypes)) {
368 2
            $rules[] = [[
369 2
                $this->contentTypeAttribute],
370 2
                'required'];
371 2
            $rules[] = [[
372 2
                $this->contentTypeAttribute],
373 2
                'in',
374 2
                'range' => array_keys($this->contentTypes)];
375 2
        }
376 2
        return $rules;
377
    }
378
379
    /**
380
     * Set blameable rules.
381
     * @param array $rules
382
     */
383 15
    protected function setBlameableRules($rules = [])
384
    {
385 15
        $this->blameableLocalRules = $rules;
386 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...
387 15
        if ($cache) {
388 15
            $tagDependency = new TagDependency(['tags' => [$this->getBlameableRulesCacheTag()]]);
389 15
            $cache->set($this->getBlameableRulesCacheKey(), $rules, 0, $tagDependency);
390 15
        }
391 15
    }
392
393
    /**
394
     * Get blameable behaviors cache key.
395
     * @return string cache key.
396
     */
397 42
    public function getBlameableBehaviorsCacheKey()
398
    {
399 42
        return static::className() . $this->cachePrefix . static::$cacheKeyBlameableBehaviors;
400
    }
401
402
    /**
403
     * Get blameable behaviors cache tag.
404
     * @return string cache tag.
405
     */
406 15
    public function getBlameableBehaviorsCacheTag()
407
    {
408 15
        return static::className() . $this->cachePrefix . static::$cacheTagBlameableBehaviors;
409
    }
410
411
    /**
412
     * Get blameable behaviors. If current behaviors array is empty, the init
413
     * array will be given.
414
     * @return array
415
     */
416 42
    public function getBlameableBehaviors()
417
    {
418 42
        $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...
419 42
        if ($cache) {
420 42
            $this->blameableLocalBehaviors = $cache->get($this->getBlameableBehaviorsCacheKey());
421 42
        }
422 42
        if (empty($this->blameableLocalBehaviors) || !is_array($this->blameableLocalBehaviors)) {
423 15
            if ($cache) {
424 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...
425 15
            }
426 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...
427 15
            $behaviors['blameable'] = [
428 15
                'class' => BlameableBehavior::className(),
429 15
                'createdByAttribute' => $this->createdByAttribute,
430 15
                'updatedByAttribute' => $this->updatedByAttribute,
431 15
                'value' => [$this,
432 15
                    'onGetCurrentUserGuid'],
433
            ];
434 15
            $this->setBlameableBehaviors($behaviors);
435 15
        }
436 42
        return $this->blameableLocalBehaviors;
437
    }
438
439
    /**
440
     * Set blameable behaviors.
441
     * @param array $behaviors
442
     */
443 15
    protected function setBlameableBehaviors($behaviors = [])
444
    {
445 15
        $this->blameableLocalBehaviors = $behaviors;
446 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...
447 15
        if ($cache) {
448 15
            $tagDependencyConfig = ['tags' => [$this->getBlameableBehaviorsCacheTag()]];
449 15
            $tagDependency = new \yii\caching\TagDependency($tagDependencyConfig);
450 15
            $cache->set($this->getBlameableBehaviorsCacheKey(), $behaviors, 0, $tagDependency);
451 15
        }
452 15
    }
453
454
    /**
455
     * Set description.
456
     * @return string description.
457
     */
458
    public function getDescription()
459
    {
460
        $descAttribute = $this->descriptionAttribute;
461
        return is_string($descAttribute) ? $this->$descAttribute : null;
462
    }
463
464
    /**
465
     * Get description.
466
     * @param string $desc description.
467
     * @return string|null description if enabled, or null if disabled.
468
     */
469
    public function setDescription($desc)
470
    {
471
        $descAttribute = $this->descriptionAttribute;
472
        return is_string($descAttribute) ? $this->$descAttribute = $desc : null;
473
    }
474
475
    /**
476
     * Get blame who owned this blameable model.
477
     * NOTICE! This method will not check whether `$userClass` exists. You should
478
     * specify it in `init()` method.
479
     * @return BaseUserQuery user.
480
     */
481 1
    public function getUser()
482
    {
483 1
        $userClass = $this->userClass;
484 1
        $model = $userClass::buildNoInitModel();
485 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...
486
    }
487
488
    /**
489
     * Get updater who updated this blameable model recently.
490
     * NOTICE! This method will not check whether `$userClass` exists. You should
491
     * specify it in `init()` method.
492
     * @return BaseUserQuery user.
493
     */
494 1
    public function getUpdater()
495
    {
496 1
        if (!is_string($this->updatedByAttribute)) {
497 1
            return null;
498
        }
499
        $userClass = $this->userClass;
500
        $model = $userClass::buildNoInitModel();
501
        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...
502
    }
503
504
    /**
505
     * This event is triggered before the model update.
506
     * This method is ONLY used for being triggered by event. DO NOT call,
507
     * override or modify it directly, unless you know the consequences.
508
     * @param ModelEvent $event
509
     */
510 14
    public function onContentChanged($event)
511
    {
512 14
        $sender = $event->sender;
513 14
        $sender->resetConfirmation();
514 14
    }
515
516
    /**
517
     * Return the current user's GUID if current model doesn't specify the owner
518
     * yet, or return the owner's GUID if current model has been specified.
519
     * This method is ONLY used for being triggered by event. DO NOT call,
520
     * override or modify it directly, unless you know the consequences.
521
     * @param ModelEvent $event
522
     * @return string the GUID of current user or the owner.
523
     */
524 42
    public function onGetCurrentUserGuid($event)
525
    {
526 42
        $sender = $event->sender;
527 42
        if (isset($sender->attributes[$sender->createdByAttribute])) {
528 42
            return $sender->attributes[$sender->createdByAttribute];
529
        }
530
        $identity = \Yii::$app->user->identity;
531
        if ($identity) {
532
            $igAttribute = $identity->guidAttribute;
533
            return $identity->$igAttribute;
534
        }
535
    }
536
537
    /**
538
     * Initialize type of content. the first of element[index is 0] of
539
     * $contentTypes will be used.
540
     * @param ModelEvent $event
541
     */
542 41
    public function onInitContentType($event)
543
    {
544 41
        $sender = $event->sender;
545 41
        if (!isset($sender->contentTypeAttribute) || !is_string($sender->contentTypeAttribute)) {
546 34
            return;
547
        }
548 7
        $contentTypeAttribute = $sender->contentTypeAttribute;
549 7
        if (!isset($sender->$contentTypeAttribute) &&
550 7
            !empty($sender->contentTypes) &&
551 7
            is_array($sender->contentTypes)) {
552 7
            $sender->$contentTypeAttribute = $sender->contentTypes[0];
553 7
        }
554 7
    }
555
556
    /**
557
     * Initialize description property with $initDescription.
558
     * @param ModelEvent $event
559
     */
560 42
    public function onInitDescription($event)
561
    {
562 42
        $sender = $event->sender;
563 42
        if (!isset($sender->descriptionAttribute) || !is_string($sender->descriptionAttribute)) {
564 36
            return;
565
        }
566 6
        $descriptionAttribute = $sender->descriptionAttribute;
567 6
        if (empty($sender->$descriptionAttribute)) {
568 6
            $sender->$descriptionAttribute = $sender->initDescription;
569 6
        }
570 6
    }
571
572
    /**
573
     * Attach events associated with blameable model.
574
     */
575 42
    public function initBlameableEvents()
576
    {
577 42
        $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...
578 42
        $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...
579 42
        $contentTypeAttribute = $this->contentTypeAttribute;
580 42
        if (!isset($this->$contentTypeAttribute)) {
581 41
            $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...
582 41
        }
583 42
        $descriptionAttribute = $this->descriptionAttribute;
584 42
        if (!isset($this->$descriptionAttribute)) {
585 42
            $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...
586 42
        }
587 42
        $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...
588 42
        $this->initSelfBlameableEvents();
589 42
    }
590
591
    /**
592
     * @inheritdoc
593
     */
594 14
    public function enabledFields()
595
    {
596 14
        $fields = parent::enabledFields();
597 14
        if (is_string($this->createdByAttribute)) {
598 14
            $fields[] = $this->createdByAttribute;
599 14
        }
600 14
        if (is_string($this->updatedByAttribute)) {
601 2
            $fields[] = $this->updatedByAttribute;
602 2
        }
603 14
        if (is_string($this->contentAttribute)) {
604 14
            $fields[] = $this->contentAttribute;
605 14
        }
606 14
        if (is_array($this->contentAttribute)) {
607
            $fields = array_merge($fields, $this->contentAttribute);
608
        }
609 14
        if (is_string($this->descriptionAttribute)) {
610
            $fields[] = $this->descriptionAttribute;
611
        }
612 14
        if (is_string($this->confirmationAttribute)) {
613
            $fields[] = $this->confirmationAttribute;
614
        }
615 14
        if (is_string($this->parentAttribute)) {
616
            $fields[] = $this->parentAttribute;
617
        }
618 14
        return $fields;
619
    }
620
621
    /**
622
     * Find all follows by specified identity. If `$identity` is null, the logged-in
623
     * identity will be taken.
624
     * @param string|integer $pageSize If it is 'all`, then will find all follows,
625
     * the `$currentPage` parameter will be skipped. If it is integer, it will be
626
     * regarded as sum of models in one page.
627
     * @param integer $currentPage The current page number, begun with 0.
628
     * @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...
629
     * @return static[] If no follows, null will be given, or return follow array.
630
     */
631
    public static function findAllByIdentityInBatch($pageSize = 'all', $currentPage = 0, $identity = null)
632
    {
633
        if ($pageSize === 'all') {
634
            return static::findByIdentity($identity)->all();
635
        }
636
        return static::findByIdentity($identity)->page($pageSize, $currentPage)->all();
637
    }
638
639
    /**
640
     * Find one follow by specified identity. If `$identity` is null, the logged-in
641
     * identity will be taken. If $identity doesn't has the follower, null will
642
     * be given.
643
     * @param integer $id user id.
644
     * @param boolean $throwException
645
     * @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...
646
     * @return static
647
     * @throws InvalidParamException
648
     */
649
    public static function findOneById($id, $throwException = true, $identity = null)
650
    {
651
        $query = static::findByIdentity($identity);
652
        if (!empty($id)) {
653
            $query = $query->id($id);
654
        }
655
        $model = $query->one();
656
        if (!$model && $throwException) {
657
            throw new InvalidParamException('Model Not Found.');
658
        }
659
        return $model;
660
    }
661
662
    /**
663
     * Get total of follows of specified identity.
664
     * @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...
665
     * @return integer total.
666
     */
667
    public static function countByIdentity($identity = null)
668
    {
669
        return static::findByIdentity($identity)->count();
670
    }
671
672
    /**
673
     * Get pagination, used for building contents page by page.
674
     * @param integer $limit
675
     * @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...
676
     * @return Pagination
677
     */
678
    public static function getPagination($limit = 10, $identity = null)
679
    {
680
        $limit = (int) $limit;
681
        $count = static::countByIdentity($identity);
682
        if ($limit > $count) {
683
            $limit = $count;
684
        }
685
        return new Pagination(['totalCount' => $count, 'pageSize' => $limit]);
686
    }
687
}
688