Completed
Push — master ( 2d4ece...81b65f )
by vistart
07:57
created

BaseMongoBlameableModel   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 89.66%

Importance

Changes 0
Metric Value
wmc 37
lcom 1
cbo 5
dl 0
loc 167
ccs 52
cts 58
cp 0.8966
rs 8.6
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 11 4
A findByIdentity() 0 4 1
A attributes() 0 4 1
A getHost() 0 7 1
A getCreatedBy() 0 5 3
A getUpdater() 0 10 3
A getUpdatedBy() 0 5 3
A onGetCurrentUserGuid() 0 13 3
B setHost() 0 16 8
B setUpdater() 0 19 10
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\models;
14
15
use MongoDB\BSON\Binary;
16
use rhosocial\base\helpers\Number;
17
use rhosocial\base\models\models\BaseUserModel;
18
use rhosocial\base\models\queries\BaseMongoBlameableQuery;
19
use rhosocial\base\models\traits\BlameableTrait;
20
use yii\web\IdentityInterface;
21
22
/**
23
 * Description of BaseMongoBlameableModel
24
 *
25
 * @version 1.0
26
 * @author vistart <[email protected]>
27
 */
28
abstract class BaseMongoBlameableModel extends BaseMongoEntityModel
29
{
30
    use BlameableTrait;
31
32
    /**
33
     * Initialize the blameable model.
34
     * If query class is not specified, [[BaseMongoBlameableQuery]] will be taken.
35
     */
36 42
    public function init()
37
    {
38 42
        if (!is_string($this->queryClass) || empty($this->queryClass)) {
39 42
            $this->queryClass = BaseMongoBlameableQuery::class;
40
        }
41 42
        if ($this->skipInit) {
42 42
            return;
43
        }
44 42
        $this->initBlameableEvents();
45 42
        parent::init();
46 42
    }
47
48
    /**
49
     * Get the query class with specified identity.
50
     * @param BaseUserModel $identity
51
     * @return BaseMongoBlameableQuery
52
     */
53 3
    public static function findByIdentity($identity = null)
54
    {
55 3
        return static::find()->byIdentity($identity);
56
    }
57
58
    /**
59
     * Because every document has a `MongoId" class, this class no longer needs GUID feature.
60
     * @var boolean determines whether enable the GUID features.
61
     */
62
    public $guidAttribute = false;
63
    public $idAttribute = '_id';
64
65
    /**
66
     * @inheritdoc
67
     * You can override this method if enabled fields cannot meet your requirements.
68
     * @return array
69
     */
70 42
    public function attributes()
71
    {
72 42
        return $this->enabledFields();
73
    }
74
75
    /**
76
     * Get blame who owned this blameable model.
77
     * NOTICE! This method will not check whether `$userClass` exists. You should
78
     * specify it in `init()` method.
79
     * @return BaseUserQuery user.
80
     */
81 15
    public function getHost()
82
    {
83 15
        $hostClass = $this->hostClass;
84 15
        $user = $hostClass::buildNoInitModel();
85
        /* @var BaseUserModel $user */
86 15
        return $this->hasOne($hostClass::className(), [$user->guidAttribute => 'createdBy']);
87
    }
88
    
89
    /**
90
     * Get created_by attribute.
91
     * @return string|null
92
     */
93 15
    public function getCreatedBy()
94
    {
95 15
        $createdByAttribute = $this->createdByAttribute;
96 15
        return (!is_string($createdByAttribute) || empty($createdByAttribute)) ? null : $this->$createdByAttribute->getData();
97
    }
98
    
99
    /**
100
     * Set host.
101
     * @param Binary|IdentityInterface|string $host
102
     * @return Binary|false
103
     */
104 42
    public function setHost($host)
105
    {
106 42
        if ($host instanceof Binary && $host->getType() == Binary::TYPE_UUID) {
0 ignored issues
show
Bug introduced by
The class MongoDB\BSON\Binary does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
107 3
            return $this->{$this->createdByAttribute} = $host;
108
        }
109 42
        if ($host instanceof $this->hostClass || $host instanceof IdentityInterface) {
110 42
            return $this->{$this->createdByAttribute} = new Binary($host->getGUID(), Binary::TYPE_UUID);
111
        }
112 9
        if (is_string($host) && preg_match(Number::GUID_REGEX, $host)) {
113 3
            return $this->{$this->createdByAttribute} = new Binary(Number::guid_bin($host), Binary::TYPE_UUID);
114
        }
115 6
        if (strlen($host) == 16) {
116 3
            return $this->{$this->createdByAttribute} = new Binary($host, Binary::TYPE_UUID);
117
        }
118 3
        return false;
119
    }
120
121
    /**
122
     * Get updater who updated this blameable model recently.
123
     * NOTICE! This method will not check whether `$userClass` exists. You should
124
     * specify it in `init()` method.
125
     * @return BaseUserQuery user.
126
     */
127 18
    public function getUpdater()
128
    {
129 18
        if (!is_string($this->updatedByAttribute) || empty($this->updatedByAttribute)) {
130
            return null;
131
        }
132 18
        $hostClass = $this->hostClass;
133 18
        $host = $hostClass::buildNoInitModel();
134
        /* @var $user BaseUserModel */
135 18
        return $this->hasOne($hostClass::className(), [$host->guidAttribute => 'updatedBy']);
136
    }
137
    
138
    /**
139
     * Get updated_by attribute.
140
     * @return string|null
141
     */
142 18
    public function getUpdatedBy()
143
    {
144 18
        $updatedByAttribute = $this->updatedByAttribute;
145 18
        return (!is_string($updatedByAttribute) || empty($updatedByAttribute)) ? null : $this->$updatedByAttribute->getData();
146
    }
147
    
148
    /**
149
     * Set updater.
150
     * @param Binary|IdentityInterface|string $updater
151
     * @return Binary|false
152
     */
153 15
    public function setUpdater($updater)
154
    {
155 15
        if (!is_string($this->updatedByAttribute) || empty($this->updatedByAttribute)) {
156
            return false;
157
        }
158 15
        if ($updater instanceof Binary && $updater->getType() == Binary::TYPE_UUID) {
0 ignored issues
show
Bug introduced by
The class MongoDB\BSON\Binary does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
159 3
            return $this->{$this->updatedByAttribute} = $updater;
160
        }
161 12
        if ($updater instanceof $this->hostClass || $updater instanceof IdentityInterface) {
162 3
            return $this->{$this->updatedByAttribute} = new Binary($updater->getGUID(), Binary::TYPE_UUID);
163
        }
164 9
        if (is_string($updater) && preg_match(Number::GUID_REGEX, $updater)) {
165 3
            return $this->{$this->updatedByAttribute} = new Binary(Number::guid_bin($updater), Binary::TYPE_UUID);
166
        }
167 6
        if (strlen($updater) == 16) {
168 3
            return $this->{$this->updatedByAttribute} = new Binary($updater, Binary::TYPE_UUID);
169
        }
170 3
        return false;
171
    }
172
173
    /**
174
     * Return the current user's GUID if current model doesn't specify the owner
175
     * yet, or return the owner's GUID if current model has been specified.
176
     * This method is ONLY used for being triggered by event. DO NOT call,
177
     * override or modify it directly, unless you know the consequences.
178
     * @param ModelEvent $event
179
     * @return string the GUID of current user or the owner.
180
     */
181 42
    public function onGetCurrentUserGuid($event)
182
    {
183 42
        $sender = $event->sender;
184
        /* @var $sender static */
185 42
        if (isset($sender->attributes[$sender->createdByAttribute])) {
186 42
            return $sender->attributes[$sender->createdByAttribute];
187
        }
188
        $identity = \Yii::$app->user->identity;
189
        /* @var BaseUserModel $identity */
190
        if ($identity) {
191
            return new Binary($identity->getGUID(), Binary::TYPE_UUID);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \MongoDB\BSON...SON\Binary::TYPE_UUID); (MongoDB\BSON\Binary) is incompatible with the return type documented by rhosocial\base\models\mo...l::onGetCurrentUserGuid of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
192
        }
193
    }
194
}
195