Completed
Push — master ( 173f87...1e5a7e )
by vistart
05:11
created

User   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 7

Test Coverage

Coverage 90.28%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 24
c 2
b 0
f 1
lcom 4
cbo 7
dl 0
loc 210
ccs 65
cts 72
cp 0.9028
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getSearchModel() 0 8 3
A attributeLabels() 0 20 1
A tableName() 0 4 1
A init() 0 7 1
A getCacheTag() 0 4 1
A onInvalidTags() 0 11 2
A createProfile() 0 13 4
A hasProfile() 0 7 4
A getProfile() 0 10 2
A onGenerateId() 0 6 1
A generateIdBehavior() 0 10 1
A behaviors() 0 9 2
A getIdRules() 0 6 1
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\user;
14
15
use rhosocial\base\models\models\BaseUserModel;
16
use rhosocial\base\models\queries\BaseBlameableQuery;
17
use rhosocial\user\models\log\UserLoginTrait;
18
use rhosocial\user\security\UserPasswordHistoryTrait;
19
use Yii;
20
use yii\base\Event;
21
use yii\base\InvalidConfigException;
22
use yii\behaviors\AttributeBehavior;
23
use yii\caching\TagDependency;
24
use yii\db\ActiveRecord;
25
26
/**
27
 * Common User Model.
28
 * This model should be stored in a relational database. You can create a foreign
29
 * key constraint on other models and this model.
30
 *
31
 * If you're using MySQL, we recommend that you create a data table using the following statement:
32
 *
33
 * ```
34
 * CREATE TABLE `user` (
35
 *   `guid` varbinary(16) NOT NULL COMMENT 'GUID',
36
 *   `id` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'ID',
37
 *   `pass_hash` varchar(80) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Password Hash',
38
 *   `ip` varbinary(16) NOT NULL DEFAULT '0' COMMENT 'IP',
39
 *   `ip_type` tinyint(3) unsigned NOT NULL DEFAULT '4' COMMENT 'IP Address Type',
40
 *   `created_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Create Time',
41
 *   `updated_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Update Time',
42
 *   `auth_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Authentication Key',
43
 *   `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Access Token',
44
 *   `password_reset_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Password Reset Token',
45
 *   `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT 'Status',
46
 *   `type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Type',
47
 *   `source` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Source',
48
 *   PRIMARY KEY (`guid`),
49
 *   UNIQUE KEY `user_id_unique` (`id`),
50
 *   KEY `user_auth_key_normal` (`auth_key`),
51
 *   KEY `user_access_token_normal` (`access_token`),
52
 *   KEY `user_password_reset_token` (`password_reset_token`),
53
 *   KEY `user_create_time_normal` (`created_at`)
54
 * ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='User';
55
 * ```
56
 *
57
 * The fields of User table in database are following:
58
 * @property string $guid User's GUID. This property is used to uniquely identify a user.
59
 * This property is automatically generated when the class is created, we do not
60
 * recommend that you modify this property, unless you know the consequences of doing so.
61
 * This property is also regareded as the foreign key target of other models associated
62
 * with this model. If you have to modify this property, the foreign key constraints
63
 * should be updating and deleting on cascade.
64
 * @property string $id User Identifier No. It is a 8-digit number beginning with 4 by default.
65
 * @property string $pass_hash Password Hash.
66
 * We strongly recommend you NOT to change this property directly!
67
 * If you want to set or reset password, please use setPassword() magic property instead.
68
 * @property integer $ip IP address.
69
 * @property integer $ipType
70
 * @property string $createdAt
71
 * @property string $updatedAt
72
 * @property string $auth_key
73
 * @property string $access_token
74
 * @property string $password_reset_token
75
 * @property integer $status
76
 * @property integer $type
77
 * @property string $source
78
 *
79
 * @property-read Profile $profile Profile. This magic property is read-only.
80
 * If you want to modify anyone property of Profile model, please get it first,
81
 * then change and save it, like following:
82
 * ```php
83
 * $profile = $user->profile;
84
 * $profile->nickname = 'vistart';
85
 * $profile->save();
86
 * ```
87
 * If $profileClass is `false`, `null` returned.
88
 * @version 1.0
89
 * @author vistart <[email protected]>
90
 */
91
class User extends BaseUserModel
92
{
93
    use UserPasswordHistoryTrait, UserLoginTrait;
94
    public $searchClass = UserSearch::class;
95
    public function getSearchModel()
96
    {
97
        $class = $this->searchClass;
98
        if (empty($class) || !class_exists($class)) {
99
            return null;
100
        }
101
        return new $class;
102
    }
103
104
    /**
105
     * @inheritdoc
106
     */
107 1
    public function attributeLabels()
108
    {
109
        return [
110 1
            $this->guidAttribute => Yii::t('user', 'GUID'),
111 1
            $this->idAttribute => Yii::t('user', 'ID'),
112 1
            $this->passwordHashAttribute => Yii::t('user', 'Password Hash'),
113 1
            $this->ipAttribute => Yii::t('user', 'IP Address'),
114 1
            $this->ipTypeAttribute => Yii::t('user', 'IP Address Type'),
115 1
            $this->createdAtAttribute => Yii::t('user', 'Creation Time'),
116 1
            $this->updatedAtAttribute => Yii::t('user', 'Last Updated Time'),
117 1
            $this->authKeyAttribute => Yii::t('user', 'Authentication Key'),
118 1
            $this->accessTokenAttribute => Yii::t('user', 'Access Token'),
119 1
            $this->passwordResetTokenAttribute => Yii::t('user', 'Password Reset Token'),
120 1
            $this->statusAttribute => Yii::t('user', 'Status'),
121 1
            'type' => Yii::t('user', 'Type'),
122 1
            $this->sourceAttribute => Yii::t('user', 'Source'),
123 1
            'createdAt' => Yii::t('user', 'Registration Time'),
124 1
            'updatedAt' => Yii::t('user', 'Last Updated Time'),
125
        ];
126
    }
127
128
    /**
129
     * @inheritdoc
130
     */
131
    public $idAttributeType = 1;
132
133
    /**
134
     * @inheritdoc
135
     */
136
    public $idAttributeLength = 8;
137
138
    /**
139
     * @inheritdoc
140
     */
141
    public $idAttributePrefix = '4';
142
143
    /**
144
     * @var bool
145
     */
146
    public $idPreassigned = true;
147
148
    /**
149
     * @inheritdoc
150
     */
151 41
    public static function tableName()
152
    {
153 41
        return '{{%user}}';
154
    }
155
156
    /**
157
     * @var string|false Profile class name. If you do not need profile model,
158
     * please set it false.
159
     */
160
    public $profileClass = false;
161
162
    /**
163
     * @inheritdoc
164
     */
165 41
    public function init()
166
    {
167 41
        $this->on(static::$eventAfterRegister, [$this, 'onAddPasswordToHistory']);
168 41
        $this->on(static::$eventAfterResetPassword, [$this, 'onAddPasswordToHistory']);
169 41
        $this->on(static::EVENT_AFTER_UPDATE, [$this, 'onInvalidTags']);
170 41
        parent::init();
171 41
    }
172
173
    /**
174
     * @var string
175
     */
176
    public $cacheTagPrefix = 'tag_user_';
177
178
    /**
179
     * @return string
180
     */
181 3
    public function getCacheTag()
182
    {
183 3
        return $this->cacheTagPrefix . $this->getID();
184
    }
185
186
    /**
187
     * @param Event $event
188
     * @return bool|string|array
189
     */
190 3
    public function onInvalidTags($event)
191
    {
192
        try {
193 3
            $cache = Yii::$app->get('cache');
194
        } catch (InvalidConfigException $ex) {
195
            return true;
196
        }
197 3
        $sender = $event->sender;
198
        /*@var $sender static */
199 3
        return TagDependency::invalidate($cache, $sender->getCacheTag());
200
    }
201
202
    /**
203
     * Create profile.
204
     * If profile of this user exists, it will be returned instead of creating it.
205
     * Meanwhile, the $config parameter will be skipped.
206
     * @param array $config Profile configuration. Skipped if it exists.
207
     * @return Profile
208
     */
209 19
    public function createProfile($config = [])
210
    {
211 19
        $profileClass = $this->profileClass;
212 19
        if (empty($profileClass) || !is_string($this->profileClass)) {
213 1
            return null;
214
        }
215 18
        $profile = $profileClass::findOne($this->getGUID());
216 18
        if (!$profile) {
217 18
            $profile = $this->create($profileClass, $config);
218 18
            $profile->setGUID($this->getGUID());
219
        }
220 18
        return $profile;
221
    }
222
223
    /**
224
     * 
225
     * @return boolean
226
     */
227 4
    public function hasProfile()
228
    {
229 4
        if ($this->profileClass === false || !is_string($this->profileClass) || !class_exists($this->profileClass)) {
230 2
            return false;
231
        }
232 2
        return true;
233
    }
234
235
    /**
236
     * Get Profile query.
237
     * If you want to get profile model, please access this method in magic property way,
238
     * like following:
239
     *
240
     * ```php
241
     * $user->profile;
242
     * ```
243
     *
244
     * @return BaseBlameableQuery
245
     */
246 4
    public function getProfile()
247
    {
248 4
        if (!$this->hasProfile()) {
249 2
            return null;
250
        }
251 2
        $profileClass = $this->profileClass;
252 2
        $profileModel = $profileClass::buildNoInitModel();
253 2
        return $this->hasOne($profileClass,
254 2
                [$profileModel->createdByAttribute => $this->guidAttribute])->inverseOf('user');
255
    }
256
257 36
    public function onGenerateId($event)
258
    {
259 36
        $sender = $event->sender;
260
        /* @var $sender static */
261 36
        return $sender->generateId();
262
    }
263
264
    /**
265
     * @return array
266
     */
267 41
    public function generateIdBehavior()
268
    {
269
        return [
270 41
            'class' => AttributeBehavior::class,
271
            'attributes' => [
272 41
                ActiveRecord::EVENT_BEFORE_INSERT => $this->idAttribute,
273
            ],
274 41
            'value' => [$this, 'onGenerateId'],
275
        ];
276
    }
277
278
    /**
279
     * @return array
280
     */
281 41
    public function behaviors()
282
    {
283 41
        $behaviors = parent::behaviors();
284 41
        $behavior = $this->generateIdBehavior();
285 41
        if (!empty($behavior)) {
286 41
            $behaviors[] = $behavior;
287
        }
288 41
        return $behaviors;
289
    }
290
291
    /**
292
     * @return array
293
     */
294 2
    public function getIdRules()
295
    {
296
        return [
297 2
            [$this->idAttribute, 'safe'],
298
        ];
299
    }
300
}
301