Completed
Push — master ( 82df8e...bcf569 )
by vistart
74:36 queued 71:28
created
Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\invitation\registration\UserInvitationRegistrationTrait;
18
use rhosocial\user\models\log\UserLoginTrait;
19
use rhosocial\user\models\UserUsernameTrait;
20
use rhosocial\user\security\UserPasswordHistoryTrait;
21
use Yii;
22
use yii\base\Event;
23
use yii\base\InvalidConfigException;
24
use yii\behaviors\AttributeBehavior;
25
use yii\caching\TagDependency;
26
use yii\db\ActiveRecord;
27
use yii\widgets\ActiveForm;
28
29
/**
30
 * Common User Model.
31
 * This model should be stored in a relational database. You can create a foreign
32
 * key constraint on other models and this model.
33
 *
34
 * If you're using MySQL, we recommend that you create a data table using the following statement:
35
 *
36
 * ```
37
 * CREATE TABLE `user` (
38
 *   `guid` varbinary(16) NOT NULL COMMENT 'GUID',
39
 *   `id` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'ID',
40
 *   `pass_hash` varchar(80) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Password Hash',
41
 *   `ip` varbinary(16) NOT NULL DEFAULT '0' COMMENT 'IP',
42
 *   `ip_type` tinyint(3) unsigned NOT NULL DEFAULT '4' COMMENT 'IP Address Type',
43
 *   `created_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Create Time',
44
 *   `updated_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Update Time',
45
 *   `auth_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Authentication Key',
46
 *   `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Access Token',
47
 *   `password_reset_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Password Reset Token',
48
 *   `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT 'Status',
49
 *   `type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Type',
50
 *   `source` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Source',
51
 *   PRIMARY KEY (`guid`),
52
 *   UNIQUE KEY `user_id_unique` (`id`),
53
 *   UNIQUE KEY `user_username_unique` (`username`),
54
 *   KEY `user_auth_key_normal` (`auth_key`),
55
 *   KEY `user_access_token_normal` (`access_token`),
56
 *   KEY `user_password_reset_token` (`password_reset_token`),
57
 *   KEY `user_create_time_normal` (`created_at`)
58
 * ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='User';
59
 * ```
60
 *
61
 * The fields of User table in database are following:
62
 * @property string $guid User's GUID. This property is used to uniquely identify a user.
63
 * This property is automatically generated when the class is created, we do not
64
 * recommend that you modify this property, unless you know the consequences of doing so.
65
 * This property is also regareded as the foreign key target of other models associated
66
 * with this model. If you have to modify this property, the foreign key constraints
67
 * should be updating and deleting on cascade.
68
 * @property string $id User Identifier No. It is a 8-digit number beginning with 4 by default.
69
 * @property string $pass_hash Password Hash.
70
 * We strongly recommend you NOT to change this property directly!
71
 * If you want to set or reset password, please use setPassword() magic property instead.
72
 * @property integer $ip IP address.
73
 * @property integer $ipType
74
 * @property string $createdAt
75
 * @property string $updatedAt
76
 * @property string $auth_key
77
 * @property string $access_token
78
 * @property string $password_reset_token
79
 * @property integer $status
80
 * @property integer $type
81
 * @property string $source
82
 *
83
 * @property-read Profile $profile Profile. This magic property is read-only.
84
 * If you want to modify anyone property of Profile model, please get it first,
85
 * then change and save it, like following:
86
 * ```php
87
 * $profile = $user->profile;
88
 * $profile->nickname = 'vistart';
89
 * $profile->save();
90
 * ```
91
 * If $profileClass is `false`, `null` returned.
92
 * @version 1.0
93
 * @author vistart <[email protected]>
94
 */
95
class User extends BaseUserModel
96
{
97
    use UserPasswordHistoryTrait, UserLoginTrait, UserUsernameTrait, UserInvitationRegistrationTrait;
98
99
    /**
100
     * @var string
101
     */
102
    public $searchClass = UserSearch::class;
103
104
    /**
105
     * @return null
106
     */
107
    public function getSearchModel()
108
    {
109
        $class = $this->searchClass;
110
        if (empty($class) || !class_exists($class)) {
111
            return null;
112
        }
113
        return new $class;
114
    }
115
116
    /**
117
     * @inheritdoc
118
     */
119 1
    public function attributeLabels()
120
    {
121
        $labels = [
122 1
            $this->guidAttribute => Yii::t('user', 'GUID'),
123 1
            $this->idAttribute => Yii::t('user', 'ID'),
124 1
            $this->passwordHashAttribute => Yii::t('user', 'Password Hash'),
125 1
            $this->ipAttribute => Yii::t('user', 'IP Address'),
126 1
            $this->ipTypeAttribute => Yii::t('user', 'IP Address Type'),
127 1
            $this->createdAtAttribute => Yii::t('user', 'Creation Time'),
128 1
            $this->updatedAtAttribute => Yii::t('user', 'Last Updated Time'),
129 1
            $this->authKeyAttribute => Yii::t('user', 'Authentication Key'),
130 1
            $this->accessTokenAttribute => Yii::t('user', 'Access Token'),
131 1
            $this->passwordResetTokenAttribute => Yii::t('user', 'Password Reset Token'),
132 1
            $this->statusAttribute => Yii::t('user', 'Status'),
133 1
            'type' => Yii::t('user', 'Type'),
134 1
            $this->sourceAttribute => Yii::t('user', 'Source'),
135 1
            'createdAt' => Yii::t('user', 'Registration Time'),
136 1
            'updatedAt' => Yii::t('user', 'Last Updated Time'),
137
        ];
138 1
        return $labels;
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144
    public $idAttributeType = 1;
145
146
    /**
147
     * @inheritdoc
148
     */
149
    public $idAttributeLength = 8;
150
151
    /**
152
     * @inheritdoc
153
     */
154
    public $idAttributePrefix = '4';
155
156
    /**
157
     * @var bool
158
     */
159
    public $idPreassigned = true;
160
161
    /**
162
     * @inheritdoc
163
     */
164 53
    public static function tableName()
165
    {
166 53
        return '{{%user}}';
167
    }
168
169
    /**
170
     * @var string|false Profile class name. If you do not need profile model,
171
     * please set it false.
172
     */
173
    public $profileClass = false;
174
175
    /**
176
     * @inheritdoc
177
     * -----------
178
     * When the user is updated or deleted, the cache contents tagged with the corresponding user tag will be invalidated.
179
     */
180 53
    public function init()
181
    {
182 53
        $this->on(static::$eventAfterRegister, [$this, 'onAddPasswordToHistory']);
183 53
        $this->on(static::$eventAfterResetPassword, [$this, 'onAddPasswordToHistory']);
184 53
        $this->on(static::EVENT_AFTER_UPDATE, [$this, 'onInvalidTags']);
185 53
        $this->on(static::EVENT_AFTER_DELETE, [$this, 'onInvalidTags']);
186 53
        parent::init();
187 53
    }
188
189
    /**
190
     * @var string
191
     */
192
    public $cacheTagPrefix = 'tag_user_';
193
194
    /**
195
     * Get cache tag.
196
     * The cache tag ends with the user ID, but after the user ID is modified, the old ID will prevail.
197
     * @return string
198
     */
199 44
    public function getCacheTag()
200
    {
201 44
        return $this->cacheTagPrefix .
202 44
            ($this->isAttributeChanged($this->idAttribute) ? $this->getOldAttribute($this->idAttribute) : $this->getID());
203
    }
204
205
    /**
206
     * @param Event $event
207
     * @return bool|string|array
208
     */
209 44
    public function onInvalidTags($event)
210
    {
211
        try {
212 44
            $cache = Yii::$app->get('cache');
213
        } catch (InvalidConfigException $ex) {
0 ignored issues
show
The class yii\base\InvalidConfigException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
214
            return true;
215
        }
216 44
        $sender = $event->sender;
217
        /*@var $sender static */
218 44
        return TagDependency::invalidate($cache, $sender->getCacheTag());
219
    }
220
221
    /**
222
     * Create profile.
223
     * If profile of this user exists, it will be returned instead of creating it.
224
     * Meanwhile, the $config parameter will be skipped.
225
     * @param array $config Profile configuration. Skipped if it exists.
226
     * @return Profile
227
     */
228 19
    public function createProfile($config = [])
229
    {
230 19
        $profileClass = $this->profileClass;
231 19
        if (empty($profileClass) || !is_string($this->profileClass)) {
232 1
            return null;
233
        }
234 18
        $profile = $profileClass::findOne($this->getGUID());
235 18
        if (!$profile) {
236 18
            $profile = $this->create($profileClass, $config);
237 18
            $profile->setGUID($this->getGUID());
238
        }
239 18
        return $profile;
240
    }
241
242
    /**
243
     * 
244
     * @return boolean
245
     */
246 4
    public function hasProfile()
247
    {
248 4
        if ($this->profileClass === false || !is_string($this->profileClass) || !class_exists($this->profileClass)) {
249 2
            return false;
250
        }
251 2
        return true;
252
    }
253
254
    /**
255
     * Get Profile query.
256
     * If you want to get profile model, please access this method in magic property way,
257
     * like following:
258
     *
259
     * ```php
260
     * $user->profile;
261
     * ```
262
     *
263
     * @return BaseBlameableQuery
264
     */
265 4
    public function getProfile()
266
    {
267 4
        if (!$this->hasProfile()) {
268 2
            return null;
269
        }
270 2
        $profileClass = $this->profileClass;
271 2
        $profileModel = $profileClass::buildNoInitModel();
272 2
        return $this->hasOne($profileClass,
273 2
                [$profileModel->createdByAttribute => $this->guidAttribute])->inverseOf('user');
274
    }
275
276
    /**
277
     * @param $event
278
     * @return mixed
279
     */
280 48
    public function onGenerateId($event)
281
    {
282 48
        $sender = $event->sender;
283
        /* @var $sender static */
284 48
        return $sender->generateId();
285
    }
286
287
    /**
288
     * @return array
289
     */
290 53
    public function generateIdBehavior()
291
    {
292
        return [
293 53
            'class' => AttributeBehavior::class,
294
            'attributes' => [
295 53
                ActiveRecord::EVENT_BEFORE_INSERT => $this->idAttribute,
296
            ],
297 53
            'value' => [$this, 'onGenerateId'],
298
        ];
299
    }
300
301
    /**
302
     * @return array
303
     */
304 53
    public function behaviors()
305
    {
306 53
        $behaviors = parent::behaviors();
307 53
        $behavior = $this->generateIdBehavior();
308 53
        if (!empty($behavior)) {
309 53
            $behaviors[] = $behavior;
310
        }
311 53
        return $behaviors;
312
    }
313
314
    /**
315
     * @var string
316
     */
317
    public static $idRegex = '/^\d{5,8}$/';
318
319
    /**
320
     * @return array
321
     */
322 2
    public function getIdRules()
323
    {
324
        return [
325 2
            [$this->idAttribute, 'safe'],
326
        ];
327
    }
328
329
    /**
330
     * Friendly to IDE.
331
     * @return UserQuery
332
     */
333 48
    public static function find()
334
    {
335 48
        return parent::find();
336
    }
337
}
338