Completed
Push — master ( fa3ca9...034150 )
by vistart
05:25
created

BlameableTrait::getContent()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 6

Importance

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

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
254
    }
255
256
    /**
257
     * Get blameable rules cache tag.
258
     * @return string cache tag
259
     */
260 84
    public function getBlameableRulesCacheTag()
261
    {
262 84
        return static::class . $this->cachePrefix . static::$cacheTagBlameableRules;
263
    }
264
265
    /**
266
     * Get the rules associated with content to be blamed.
267
     * @return array rules.
268
     */
269 84
    public function getBlameableRules()
270
    {
271 84
        $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...
272 84
        if ($cache) {
273 84
            $this->blameableLocalRules = $cache->get($this->getBlameableRulesCacheKey());
274
        }
275
        // 若当前规则不为空,且是数组,则认为是规则数组,直接返回。
276 84
        if (!empty($this->blameableLocalRules) && is_array($this->blameableLocalRules)) {
277 31
            return $this->blameableLocalRules;
278
        }
279
280
        // 父类规则与确认规则合并。
281 84
        if ($cache) {
282 84
            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...
283
        }
284 84
        $rules = array_merge(
285 84
            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...
286 84
            $this->getConfirmationRules(),
287 84
            $this->getBlameableAttributeRules(),
288 84
            $this->getDescriptionRules(),
289 84
            $this->getContentRules(),
290 84
            $this->getSelfBlameableRules()
291
        );
292 84
        $this->setBlameableRules($rules);
293 84
        return $this->blameableLocalRules;
294
    }
295
296
    /**
297
     * Get the rules associated with `createdByAttribute`, `updatedByAttribute`
298
     * and `idAttribute`-`createdByAttribute` combination unique.
299
     * @return array rules.
300
     */
301 84
    public function getBlameableAttributeRules()
302
    {
303 84
        $rules = [];
304
        // 创建者和上次修改者由 BlameableBehavior 负责,因此标记为安全。
305 84
        if (!is_string($this->createdByAttribute) || empty($this->createdByAttribute)) {
306
            throw new NotSupportedException('You must assign the creator.');
307
        }
308 84
        $rules[] = [
309 84
            [$this->createdByAttribute],
310 84
            'safe',
311
        ];
312
313 84
        if (is_string($this->updatedByAttribute) && !empty($this->updatedByAttribute)) {
314 42
            $rules[] = [
315 42
                [$this->updatedByAttribute],
316 42
                'safe',
317
            ];
318
        }
319
320 84
        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...
321 84
            $rules ['id'] = [
322 84
                [$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...
323 84
                    $this->createdByAttribute],
324 84
                'unique',
325 84
                '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...
326 84
                    $this->createdByAttribute],
327
            ];
328
        }
329 84
        return $rules;
330
    }
331
332
    /**
333
     * Get the rules associated with `description` attribute.
334
     * @return array rules.
335
     */
336 84
    public function getDescriptionRules()
337
    {
338 84
        $rules = [];
339 84
        if (is_string($this->descriptionAttribute) && !empty($this->descriptionAttribute)) {
340 42
            $rules[] = [
341 42
                [$this->descriptionAttribute],
342 42
                'string'
343
            ];
344 42
            $rules[] = [
345 42
                [$this->descriptionAttribute],
346 42
                'default',
347 42
                'value' => $this->initDescription,
348
            ];
349
        }
350 84
        return $rules;
351
    }
352
353
    /**
354
     * Get the rules associated with `content` and `contentType` attributes.
355
     * @return array rules.
356
     */
357 84
    public function getContentRules()
358
    {
359 84
        if (!$this->contentAttribute) {
360 30
            return [];
361
        }
362 54
        $rules = [];
363 54
        $rules[] = [$this->contentAttribute, 'required'];
364 54
        if ($this->contentAttributeRule) {
365 54
            if (is_string($this->contentAttributeRule)) {
366
                $this->contentAttributeRule = [$this->contentAttributeRule];
367
            }
368 54
            if (is_array($this->contentAttributeRule)) {
369 54
                $rules[] = array_merge([$this->contentAttribute], $this->contentAttributeRule);
370
            }
371
        }
372
373 54
        if (!$this->contentTypeAttribute) {
374 42
            return $rules;
375
        }
376
377 12
        if (is_array($this->contentTypes) && !empty($this->contentTypes)) {
378 12
            $rules[] = [[
379 12
                $this->contentTypeAttribute],
380 12
                'required'];
381 12
            $rules[] = [[
382 12
                $this->contentTypeAttribute],
383 12
                'in',
384 12
                'range' => array_keys($this->contentTypes)];
385
        }
386 12
        return $rules;
387
    }
388
389
    /**
390
     * Set blameable rules.
391
     * @param array $rules
392
     */
393 84
    protected function setBlameableRules($rules = [])
394
    {
395 84
        $this->blameableLocalRules = $rules;
396 84
        $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...
397 84
        if ($cache) {
398 84
            $tagDependency = new TagDependency(['tags' => [$this->getBlameableRulesCacheTag()]]);
399 84
            $cache->set($this->getBlameableRulesCacheKey(), $rules, 0, $tagDependency);
400
        }
401 84
    }
402
403
    /**
404
     * Get blameable behaviors cache key.
405
     * @return string cache key.
406
     */
407 87
    public function getBlameableBehaviorsCacheKey()
408
    {
409 87
        return static::class . $this->cachePrefix . static::$cacheKeyBlameableBehaviors;
410
    }
411
412
    /**
413
     * Get blameable behaviors cache tag.
414
     * @return string cache tag.
415
     */
416 87
    public function getBlameableBehaviorsCacheTag()
417
    {
418 87
        return static::class . $this->cachePrefix . static::$cacheTagBlameableBehaviors;
419
    }
420
421
    /**
422
     * Get blameable behaviors. If current behaviors array is empty, the init
423
     * array will be given.
424
     * @return array
425
     */
426 87
    public function getBlameableBehaviors()
427
    {
428 87
        $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...
429 87
        if ($cache) {
430 87
            $this->blameableLocalBehaviors = $cache->get($this->getBlameableBehaviorsCacheKey());
431
        }
432 87
        if (empty($this->blameableLocalBehaviors) || !is_array($this->blameableLocalBehaviors)) {
433 87
            if ($cache) {
434 87
                TagDependency::invalidate($cache, [$this->getEntityBehaviorsCacheTag()]);
0 ignored issues
show
Bug introduced by
The method getEntityBehaviorsCacheTag() does not exist on rhosocial\base\models\traits\BlameableTrait. Did you maybe mean behaviors()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
435
            }
436 87
            $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...
437 87
            $behaviors['blameable'] = [
438 87
                'class' => BlameableBehavior::class,
439 87
                'createdByAttribute' => $this->createdByAttribute,
440 87
                'updatedByAttribute' => $this->updatedByAttribute,
441 87
                'value' => [$this,
442 87
                    'onGetCurrentUserGuid'],
443
            ];
444 87
            $this->setBlameableBehaviors($behaviors);
445
        }
446 87
        return $this->blameableLocalBehaviors;
447
    }
448
449
    /**
450
     * Set blameable behaviors.
451
     * @param array $behaviors
452
     */
453 87
    protected function setBlameableBehaviors($behaviors = [])
454
    {
455 87
        $this->blameableLocalBehaviors = $behaviors;
456 87
        $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...
457 87
        if ($cache) {
458 87
            $tagDependencyConfig = ['tags' => [$this->getBlameableBehaviorsCacheTag()]];
459 87
            $tagDependency = new TagDependency($tagDependencyConfig);
460 87
            $cache->set($this->getBlameableBehaviorsCacheKey(), $behaviors, 0, $tagDependency);
461
        }
462 87
    }
463
464
    /**
465
     * Set description.
466
     * @return string description.
467
     */
468 1
    public function getDescription()
469
    {
470 1
        $descAttribute = $this->descriptionAttribute;
471 1
        return is_string($descAttribute) ? $this->$descAttribute : null;
472
    }
473
474
    /**
475
     * Get description.
476
     * @param string $desc description.
477
     * @return string|null description if enabled, or null if disabled.
478
     */
479 1
    public function setDescription($desc)
480
    {
481 1
        $descAttribute = $this->descriptionAttribute;
482 1
        return is_string($descAttribute) ? $this->$descAttribute = $desc : null;
483
    }
484
485
    /**
486
     * Get blame who owned this blameable model.
487
     * NOTICE! This method will not check whether `$userClass` exists. You should
488
     * specify it in `init()` method.
489
     * @return BaseUserQuery user.
490
     */
491 8
    public function getUser()
492
    {
493 8
        return $this->getHost();
494
    }
495
    
496
    /**
497
     * 
498
     * @return 
499
     */
500 12
    public function getHost()
501
    {
502 12
        $hostClass = $this->hostClass;
503 12
        $model = $hostClass::buildNoInitModel();
504 12
        return $this->hasOne($hostClass::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...
505
    }
506
    
507
    /**
508
     * 
509
     * @param string $host
510
     * @return type
511
     */
512 42
    public function setHost($host)
513
    {
514 42
        if ($host instanceof $this->hostClass || $host instanceof \yii\web\IdentityInterface) {
515 42
            return $this->{$this->createdByAttribute} = $host->getGUID();
516
        }
517
        if (is_string($host) && preg_match(Number::GUID_REGEX, $host)) {
518
            return $this->{$this->createdByAttribute} = Number::guid_bin($host);
519
        }
520
        if (strlen($host) == 16) {
521
            return $this->{$this->createdByAttribute} = $user;
0 ignored issues
show
Bug introduced by
The variable $user does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
522
        }
523
        return false;
524
    }
525
    
526
    /**
527
     *
528
     * @param BaseUserModel|string $user
529
     * @return boolean
530
     */
531
    public function setUser($user)
532
    {
533
        return $this->setHost($user);
534
    }
535
536
    /**
537
     * Get updater who updated this blameable model recently.
538
     * NOTICE! This method will not check whether `$userClass` exists. You should
539
     * specify it in `init()` method.
540
     * @return BaseUserQuery user.
541
     */
542 1
    public function getUpdater()
543
    {
544 1
        if (!is_string($this->updatedByAttribute) || empty($this->updatedByAttribute)) {
545
            return null;
546
        }
547 1
        $hostClass = $this->hostClass;
548 1
        $model = $hostClass::buildNoInitModel();
549
        /* @var $model BaseUserModel */
550 1
        return $this->hasOne($hostClass::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...
551
    }
552
    
553
    /**
554
     *
555
     * @param BaseUserModel|string $user
0 ignored issues
show
Bug introduced by
There is no parameter named $user. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
556
     * @return boolean
557
     */
558
    public function setUpdater($updater)
559
    {
560
        if (!is_string($this->updatedByAttribute) || empty($this->updatedByAttribute)) {
561
            return false;
562
        }
563
        if ($updater instanceof $this->hostClass || $updater instanceof \yii\web\IdentityInterface) {
564
            return $this->{$this->updatedByAttribute} = $updater->getGUID();
565
        }
566
        if (is_string($updater) && preg_match(Number::GUID_REGEX, $updater)) {
567
            return $this->{$this->updatedByAttribute} = Number::guid_bin($updater);
568
        }
569
        if (strlen($updater) == 16) {
570
            return $this->{$this->updatedByAttribute} = $updater;
571
        }
572
        return false;
573
    }
574
575
    /**
576
     * This event is triggered before the model update.
577
     * This method is ONLY used for being triggered by event. DO NOT call,
578
     * override or modify it directly, unless you know the consequences.
579
     * @param ModelEvent $event
580
     */
581 10
    public function onContentChanged($event)
582
    {
583 10
        $sender = $event->sender;
584
        /* @var $sender static */
585 10
        return $sender->resetConfirmation();
586
    }
587
588
    /**
589
     * Return the current user's GUID if current model doesn't specify the owner
590
     * yet, or return the owner's GUID if current model has been specified.
591
     * This method is ONLY used for being triggered by event. DO NOT call,
592
     * override or modify it directly, unless you know the consequences.
593
     * @param ModelEvent $event
594
     * @return string the GUID of current user or the owner.
595
     */
596 72
    public function onGetCurrentUserGuid($event)
597
    {
598 72
        $sender = $event->sender;
599
        /* @var $sender static */
600 72
        if (isset($sender->attributes[$sender->createdByAttribute])) {
601 72
            return $sender->attributes[$sender->createdByAttribute];
0 ignored issues
show
Bug introduced by
The property attributes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
602
        }
603
        $identity = \Yii::$app->user->identity;
604
        /* @var $identity BaseUserModel */
605
        if ($identity) {
606
            return $identity->getGUID();
607
        }
608
    }
609
610
    /**
611
     * Initialize type of content. the first of element[index is 0] of
612
     * $contentTypes will be used.
613
     * @param ModelEvent $event
614
     */
615 12
    public function onInitContentType($event)
616
    {
617 12
        $sender = $event->sender;
618
        /* @var $sender static */
619 12
        if (!is_string($sender->contentTypeAttribute) || empty($sender->contentTypeAttribute)) {
620
            return;
621
        }
622 12
        $contentTypeAttribute = $sender->contentTypeAttribute;
623 12
        if (!isset($sender->$contentTypeAttribute) &&
624 12
            !empty($sender->contentTypes) &&
625 12
            is_array($sender->contentTypes)) {
626 12
            $sender->$contentTypeAttribute = $sender->contentTypes[0];
627
        }
628 12
    }
629
630
    /**
631
     * Initialize description property with $initDescription.
632
     * @param ModelEvent $event
633
     */
634 45
    public function onInitDescription($event)
635
    {
636 45
        $sender = $event->sender;
637
        /* @var $sender static */
638 45
        if (!is_string($sender->descriptionAttribute) || empty($sender->descriptionAttribute)) {
639
            return;
640
        }
641 45
        $descriptionAttribute = $sender->descriptionAttribute;
642 45
        if (empty($sender->$descriptionAttribute)) {
643 45
            $sender->$descriptionAttribute = $sender->initDescription;
644
        }
645 45
    }
646
647
    /**
648
     * Attach events associated with blameable model.
649
     */
650 87
    public function initBlameableEvents()
651
    {
652 87
        $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...
653 87
        $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...
654 87
        $contentTypeAttribute = $this->contentTypeAttribute;
655 87
        if (is_string($contentTypeAttribute) && !empty($contentTypeAttribute) && !isset($this->$contentTypeAttribute)) {
656 12
            $this->on(static::$eventNewRecordCreated, [$this, "onInitContentType"]);
0 ignored issues
show
Bug introduced by
It seems like on() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
657
        }
658 87
        $descriptionAttribute = $this->descriptionAttribute;
659 87
        if (is_string($descriptionAttribute) && !empty($descriptionAttribute) && !isset($this->$descriptionAttribute)) {
660 45
            $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...
661
        }
662 87
        $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...
663 87
        $this->initSelfBlameableEvents();
664 87
    }
665
666
    /**
667
     * @inheritdoc
668
     */
669 32
    public function enabledFields()
670
    {
671 32
        $fields = parent::enabledFields();
672 32
        if (is_string($this->createdByAttribute) && !empty($this->createdByAttribute)) {
673 32
            $fields[] = $this->createdByAttribute;
674
        }
675 32
        if (is_string($this->updatedByAttribute) && !empty($this->updatedByAttribute) &&
676 32
            $this->createdByAttribute != $this->updatedByAttribute) {
677
            $fields[] = $this->updatedByAttribute;
678
        }
679 32
        if (is_string($this->contentAttribute)) {
680 32
            $fields[] = $this->contentAttribute;
681
        }
682 32
        if (is_array($this->contentAttribute)) {
683
            $fields = array_merge($fields, $this->contentAttribute);
684
        }
685 32
        if (is_string($this->descriptionAttribute)) {
686 1
            $fields[] = $this->descriptionAttribute;
687
        }
688 32
        if (is_string($this->confirmationAttribute)) {
689 1
            $fields[] = $this->confirmationAttribute;
690
        }
691 32
        if (is_string($this->parentAttribute)) {
692
            $fields[] = $this->parentAttribute;
693
        }
694 32
        return $fields;
695
    }
696
697
    /**
698
     * Find all follows by specified identity. If `$identity` is null, the logged-in
699
     * identity will be taken.
700
     * @param string|integer $pageSize If it is 'all`, then will find all follows,
701
     * the `$currentPage` parameter will be skipped. If it is integer, it will be
702
     * regarded as sum of models in one page.
703
     * @param integer $currentPage The current page number, begun with 0.
704
     * @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...
705
     * @return static[] If no follows, null will be given, or return follow array.
706
     */
707 1
    public static function findAllByIdentityInBatch($pageSize = 'all', $currentPage = 0, $identity = null)
708
    {
709 1
        if ($pageSize === 'all') {
710 1
            return static::findByIdentity($identity)->all();
711
        }
712 1
        return static::findByIdentity($identity)->page($pageSize, $currentPage)->all();
713
    }
714
715
    /**
716
     * Find one follow by specified identity. If `$identity` is null, the logged-in
717
     * identity will be taken. If $identity doesn't has the follower, null will
718
     * be given.
719
     * @param integer $id user id.
720
     * @param boolean $throwException
721
     * @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...
722
     * @return static
723
     * @throws InvalidParamException
724
     */
725 1
    public static function findOneById($id, $throwException = true, $identity = null)
726
    {
727 1
        $query = static::findByIdentity($identity);
728 1
        if (!empty($id)) {
729 1
            $query = $query->id($id);
730
        }
731 1
        $model = $query->one();
732 1
        if (!$model && $throwException) {
733 1
            throw new InvalidParamException('Model Not Found.');
734
        }
735 1
        return $model;
736
    }
737
738
    /**
739
     * Get total of follows of specified identity.
740
     * @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...
741
     * @return integer total.
742
     */
743 1
    public static function countByIdentity($identity = null)
744
    {
745 1
        return (int)(static::findByIdentity($identity)->count());
746
    }
747
748
    /**
749
     * Get pagination, used for building contents page by page.
750
     * @param integer $limit
751
     * @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...
752
     * @return Pagination
753
     */
754
    public static function getPagination($limit = 10, $identity = null)
755
    {
756
        $limit = (int) $limit;
757
        $count = static::countByIdentity($identity);
758
        if ($limit > $count) {
759
            $limit = $count;
760
        }
761
        return new Pagination(['totalCount' => $count, 'pageSize' => $limit]);
762
    }
763
}
764