Passed
Push — master ( 07b7c5...d13f2e )
by Alexey
05:08
created

BaseUser   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 387
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 43
c 3
b 0
f 0
dl 0
loc 387
rs 8.3157

32 Methods

Rating   Name   Duplication   Size   Complexity  
A findIdentity() 0 3 1
A removeEmailConfirmToken() 0 3 1
A validatePassword() 0 3 1
A behaviors() 0 5 1
A generateAuthKey() 0 3 1
A findByUsernameEmail() 0 3 1
A validateAuthKey() 0 3 1
A getId() 0 3 1
A tableName() 0 3 1
A getRegistrationTypesArray() 0 4 1
A getLabelsArray() 0 7 1
A getRegistrationTypeName() 0 3 1
A setPassword() 0 3 1
A getRegistrationType() 0 8 3
A findByUsernameOrEmail() 0 6 1
A getStatusesArray() 0 7 1
A attributeLabels() 0 14 1
A findIdentityByAccessToken() 0 3 1
A findByUsername() 0 3 1
A removePasswordResetToken() 0 3 1
A generateEmailConfirmToken() 0 3 1
A findByPasswordResetToken() 0 8 2
A isPasswordResetTokenValid() 0 9 2
B getUserFullName() 0 15 6
A isDeleted() 0 3 1
A getStatusLabelName() 0 4 1
A generatePasswordResetToken() 0 3 1
A beforeSave() 0 9 3
A findByEmailConfirmToken() 0 5 1
A getAuthKey() 0 3 1
A rules() 0 19 1
A getStatusName() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like BaseUser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseUser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace modules\users\models;
4
5
use Yii;
6
use yii\behaviors\TimestampBehavior;
7
use yii\db\ActiveRecord;
8
use yii\web\IdentityInterface;
9
use yii\helpers\ArrayHelper;
10
use yii\helpers\Html;
11
use modules\users\Module;
12
13
/**
14
 * Class BaseUser
15
 * @package modules\users\models
16
 *
17
 * This is the model class for table "{{%user}}".
18
 *
19
 * @property int $id ID
20
 * @property string $username Username
21
 * @property string $auth_key Authorization Key
22
 * @property string $password_hash Hash Password
23
 * @property string $password_reset_token Password Token
24
 * @property string $email_confirm_token Email Confirm Token
25
 * @property string $email Email
26
 * @property int $status Status
27
 * @property int $last_visit Last Visit
28
 * @property int $created_at Created
29
 * @property int $updated_at Updated
30
 * @property string $first_name First Name
31
 * @property string $last_name Last Name
32
 * @property int $registration_type Type Registration
33
 */
34
class BaseUser extends ActiveRecord implements IdentityInterface
35
{
36
    // Status
37
    const STATUS_BLOCKED = 0;
38
    const STATUS_ACTIVE = 1;
39
    const STATUS_WAIT = 2;
40
    const STATUS_DELETED = 3;
41
42
    // Type of registration
43
    const TYPE_REGISTRATION_SYSTEM = 0;
44
45
    /**
46
     * @inheritdoc
47
     */
48
    public static function tableName()
49
    {
50
        return '{{%user}}';
51
    }
52
53
    /**
54
     * @inheritdoc
55
     */
56
    public function behaviors()
57
    {
58
        return [
59
            'timestamp' => [
60
                'class' => TimestampBehavior::className(),
61
            ],
62
        ];
63
    }
64
65
    /**
66
     * @inheritdoc
67
     */
68
    public function rules()
69
    {
70
        return [
71
            ['username', 'required'],
72
            ['username', 'match', 'pattern' => '#^[\w_-]+$#i'],
73
            ['username', 'unique', 'targetClass' => self::className(), 'message' => Module::t('module', 'This username is already taken.')],
74
            ['username', 'string', 'min' => 2, 'max' => 255],
75
76
            ['email', 'required'],
77
            ['email', 'email'],
78
            ['email', 'unique', 'targetClass' => self::className(), 'message' => Module::t('module', 'This email is already taken.')],
79
            ['email', 'string', 'max' => 255],
80
81
            ['status', 'integer'],
82
            ['status', 'default', 'value' => self::STATUS_WAIT],
83
            ['status', 'in', 'range' => array_keys(self::getStatusesArray())],
84
85
            [['first_name', 'last_name'], 'string', 'max' => 45],
86
            [['registration_type'], 'safe'],
87
        ];
88
    }
89
90
    /**
91
     * @inheritdoc
92
     */
93
    public function attributeLabels()
94
    {
95
        return [
96
            'id' => 'ID',
97
            'created_at' => Module::t('module', 'Created'),
98
            'updated_at' => Module::t('module', 'Updated'),
99
            'last_visit' => Module::t('module', 'Last Visit'),
100
            'username' => Module::t('module', 'Username'),
101
            'email' => Module::t('module', 'Email'),
102
            'auth_key' => Module::t('module', 'Auth Key'),
103
            'status' => Module::t('module', 'Status'),
104
            'first_name' => Module::t('module', 'First Name'),
105
            'last_name' => Module::t('module', 'Last Name'),
106
            'registration_type' => Module::t('module', 'Registration Type'),
107
        ];
108
    }
109
110
    /**
111
     * @inheritdoc
112
     */
113
    public static function findIdentity($id = null)
114
    {
115
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::findOne(a...> self::STATUS_ACTIVE)) also could return the type yii\db\BaseActiveRecord which is incompatible with the return type mandated by yii\web\IdentityInterface::findIdentity() of yii\web\IdentityInterface.
Loading history...
116
    }
117
118
    /**
119
     * @param mixed $token
120
     * @param null $type
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $type is correct as it would always require null to be passed?
Loading history...
121
     * @return null|static|ActiveRecord
122
     */
123
    public static function findIdentityByAccessToken($token = '', $type = null)
124
    {
125
        return static::findOne(['auth_key' => $token, 'status' => self::STATUS_ACTIVE]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::findOne(a...> self::STATUS_ACTIVE)) also could return the type yii\db\BaseActiveRecord which is incompatible with the return type mandated by yii\web\IdentityInterfac...IdentityByAccessToken() of yii\web\IdentityInterface.
Loading history...
126
    }
127
128
    /**
129
     * Finds user by username
130
     *
131
     * @param string $username
132
     * @return static|null|ActiveRecord
133
     */
134
    public static function findByUsername($username = '')
135
    {
136
        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
137
    }
138
139
    /**
140
     * Finds user by email
141
     *
142
     * @param string $email
143
     * @return array|null|ActiveRecord
144
     */
145
    public static function findByUsernameEmail($email = '')
146
    {
147
        return static::findOne(['email' => $email, 'status' => self::STATUS_ACTIVE]);
148
    }
149
150
    /**
151
     * Finds user by username or email
152
     *
153
     * @param string $string
154
     * @return array|null|ActiveRecord
155
     */
156
    public static function findByUsernameOrEmail($string = '')
157
    {
158
        return static::find()
159
            ->where(['or', ['username' => $string], ['email' => $string]])
160
            ->andWhere(['status' => self::STATUS_ACTIVE])
161
            ->one();
162
    }
163
164
    /**
165
     * Finds user by password reset token
166
     *
167
     * @param string $token password reset token
168
     * @return static|null
169
     */
170
    public static function findByPasswordResetToken($token = '')
171
    {
172
        if (!static::isPasswordResetTokenValid($token)) {
173
            return null;
174
        }
175
        return static::findOne([
176
            'password_reset_token' => $token,
177
            'status' => self::STATUS_ACTIVE,
178
        ]);
179
    }
180
181
    /**
182
     * Finds out if password reset token is valid
183
     *
184
     * @param string $token password reset token
185
     * @return boolean
186
     */
187
    public static function isPasswordResetTokenValid($token = '')
188
    {
189
        if (empty($token)) {
190
            return false;
191
        }
192
        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
193
        $parts = explode('_', $token);
194
        $timestamp = (int)end($parts);
195
        return $timestamp + $expire >= time();
196
    }
197
198
    /**
199
     * @inheritdoc
200
     */
201
    public function getId()
202
    {
203
        return $this->getPrimaryKey();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getPrimaryKey() also could return the type array|array<mixed,null|mixed> which is incompatible with the return type mandated by yii\web\IdentityInterface::getId() of integer|string.
Loading history...
204
    }
205
206
    /**
207
     * @inheritdoc
208
     */
209
    public function getAuthKey()
210
    {
211
        return $this->auth_key;
212
    }
213
214
    /**
215
     * @inheritdoc
216
     */
217
    public function validateAuthKey($authKey = '')
218
    {
219
        return $this->getAuthKey() === $authKey;
220
    }
221
222
    /**
223
     * Validates password
224
     *
225
     * @param string $password password to validate
226
     * @return boolean if password provided is valid for current user
227
     */
228
    public function validatePassword($password = '')
229
    {
230
        return Yii::$app->security->validatePassword($password, $this->password_hash);
231
    }
232
233
    /**
234
     * Generates password hash from password and sets it to the model
235
     *
236
     * @param string $password
237
     */
238
    public function setPassword($password = '')
239
    {
240
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
241
    }
242
243
    /**
244
     * Generates "remember me" authentication key
245
     */
246
    public function generateAuthKey()
247
    {
248
        $this->auth_key = Yii::$app->security->generateRandomString();
249
    }
250
251
    /**
252
     * Generates new password reset token
253
     */
254
    public function generatePasswordResetToken()
255
    {
256
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
257
    }
258
259
    /**
260
     * Removes password reset token
261
     */
262
    public function removePasswordResetToken()
263
    {
264
        $this->password_reset_token = null;
265
    }
266
267
    /**
268
     * @param $email_confirm_token
269
     * @return bool|null|static
270
     */
271
    public static function findByEmailConfirmToken($email_confirm_token = '')
272
    {
273
        return static::findOne([
274
            'email_confirm_token' => $email_confirm_token,
275
            'status' => self::STATUS_WAIT
276
        ]);
277
    }
278
279
    /**
280
     * Generates email confirmation token
281
     */
282
    public function generateEmailConfirmToken()
283
    {
284
        $this->email_confirm_token = Yii::$app->security->generateRandomString();
285
    }
286
287
    /**
288
     * Removes email confirmation token
289
     */
290
    public function removeEmailConfirmToken()
291
    {
292
        $this->email_confirm_token = null;
293
    }
294
295
    /**
296
     * @return bool
297
     */
298
    public function isDeleted()
299
    {
300
        return $this->status === self::STATUS_DELETED;
301
    }
302
303
    /**
304
     * Actions before saving
305
     *
306
     * @param bool $insert
307
     * @return bool
308
     */
309
    public function beforeSave($insert)
310
    {
311
        if (parent::beforeSave($insert)) {
312
            if ($insert) {
313
                $this->generateAuthKey();
314
            }
315
            return true;
316
        }
317
        return false;
318
    }
319
320
    /**
321
     * @return array
322
     */
323
    public static function getStatusesArray()
324
    {
325
        return [
326
            self::STATUS_BLOCKED => Module::t('module', 'Blocked'),
327
            self::STATUS_ACTIVE => Module::t('module', 'Active'),
328
            self::STATUS_WAIT => Module::t('module', 'Wait'),
329
            self::STATUS_DELETED => Module::t('module', 'Deleted'),
330
        ];
331
    }
332
333
    /**
334
     * @return mixed
335
     */
336
    public function getStatusName()
337
    {
338
        return ArrayHelper::getValue(self::getStatusesArray(), $this->status);
339
    }
340
341
    /**
342
     * Return <span class="label label-success">Active</span>
343
     * @return string
344
     */
345
    public function getStatusLabelName()
346
    {
347
        $name = ArrayHelper::getValue(self::getLabelsArray(), $this->status);
348
        return Html::tag('span', self::getStatusName(), ['class' => 'label label-' . $name]);
0 ignored issues
show
Bug Best Practice introduced by
The method modules\users\models\BaseUser::getStatusName() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

348
        return Html::tag('span', self::/** @scrutinizer ignore-call */ getStatusName(), ['class' => 'label label-' . $name]);
Loading history...
349
    }
350
351
    /**
352
     * @return array
353
     */
354
    public static function getLabelsArray()
355
    {
356
        return [
357
            self::STATUS_BLOCKED => 'default',
358
            self::STATUS_ACTIVE => 'success',
359
            self::STATUS_WAIT => 'warning',
360
            self::STATUS_DELETED => 'danger',
361
        ];
362
    }
363
364
    /**
365
     * Type of registration
366
     * How the user is created
367
     * If the system registration type is registered by itself,
368
     * if it is created from the admin area,
369
     * then the login type that created the account
370
     *
371
     * @return mixed|string
372
     */
373
    public function getRegistrationType()
374
    {
375
        if ($this->registration_type > 0) {
376
            if (($model = User::findOne($this->registration_type)) !== null) {
377
                return $model->username;
378
            }
379
        }
380
        return $this->getRegistrationTypeName();
381
    }
382
383
    /**
384
     * Returns the registration type string
385
     * @return mixed
386
     */
387
    public function getRegistrationTypeName()
388
    {
389
        return ArrayHelper::getValue(self::getRegistrationTypesArray(), $this->registration_type);
390
    }
391
392
    /**
393
     * Returns an array of log types
394
     * @return array
395
     */
396
    public static function getRegistrationTypesArray()
397
    {
398
        return [
399
            self::TYPE_REGISTRATION_SYSTEM => Module::t('module', 'System'),
400
        ];
401
    }
402
403
    /**
404
     * @return string
405
     */
406
    public function getUserFullName()
407
    {
408
        if (Yii::$app->user) {
409
            if ($this->first_name && $this->last_name) {
410
                $fullName = $this->first_name . ' ' . $this->last_name;
411
            } else if ($this->first_name) {
412
                $fullName = $this->first_name;
413
            } else if ($this->last_name) {
414
                $fullName = $this->last_name;
415
            } else {
416
                $fullName = $this->username;
417
            }
418
            return Html::encode($fullName);
419
        }
420
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
421
    }
422
}
423