Completed
Push — master ( 55e0f0...d0f882 )
by Alexey
11:22
created

BaseUser::getUserFullName()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 12
nc 5
nop 0
1
<?php
2
namespace modules\users\models;
3
4
use Yii;
5
use yii\behaviors\TimestampBehavior;
6
use yii\db\ActiveRecord;
7
use yii\web\IdentityInterface;
8
use yii\helpers\ArrayHelper;
9
use yii\helpers\Html;
10
use modules\users\Module;
11
12
/**
13
 * This is the model class for table "{{%user}}".
14
 *
15
 * @property int $id ID
16
 * @property string $username Username
17
 * @property string $auth_key Authorization Key
18
 * @property string $password_hash Hash Password
19
 * @property string $password_reset_token Password Token
20
 * @property string $email_confirm_token Email Confirm Token
21
 * @property string $email Email
22
 * @property int $status Status
23
 * @property int $last_visit Last Visit
24
 * @property int $created_at Created
25
 * @property int $updated_at Updated
26
 * @property string $first_name First Name
27
 * @property string $last_name Last Name
28
 * @property int $registration_type Type Registration
29
 */
30
class BaseUser extends ActiveRecord implements IdentityInterface
31
{
32
    // Status
33
    const STATUS_BLOCKED = 0;
34
    const STATUS_ACTIVE = 1;
35
    const STATUS_WAIT = 2;
36
    const STATUS_DELETED = 3;
37
38
    // Type of registration
39
    const TYPE_REGISTRATION_SYSTEM = 0;
40
41
    /**
42
     * @inheritdoc
43
     */
44
    public static function tableName()
45
    {
46
        return '{{%user}}';
47
    }
48
49
    /**
50
     * @inheritdoc
51
     */
52
    public function behaviors()
53
    {
54
        return [
55
            'timestamp' => [
56
                'class' => TimestampBehavior::className(),
57
            ],
58
        ];
59
    }
60
61
    /**
62
     * @inheritdoc
63
     */
64
    public function rules()
65
    {
66
        return [
67
            ['username', 'required'],
68
            ['username', 'match', 'pattern' => '#^[\w_-]+$#i'],
69
            ['username', 'unique', 'targetClass' => self::className(), 'message' => Module::t('module', 'This username is already taken.')],
70
            ['username', 'string', 'min' => 2, 'max' => 255],
71
72
            ['email', 'required'],
73
            ['email', 'email'],
74
            ['email', 'unique', 'targetClass' => self::className(), 'message' => Module::t('module', 'This email is already taken.')],
75
            ['email', 'string', 'max' => 255],
76
77
            ['status', 'integer'],
78
            ['status', 'default', 'value' => self::STATUS_WAIT],
79
            ['status', 'in', 'range' => array_keys(self::getStatusesArray())],
80
81
            [['first_name', 'last_name'], 'string', 'max' => 45],
82
            [['registration_type'], 'safe'],
83
        ];
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89
    public function attributeLabels()
90
    {
91
        return [
92
            'id' => 'ID',
93
            'created_at' => Module::t('module', 'Created'),
94
            'updated_at' => Module::t('module', 'Updated'),
95
            'last_visit' => Module::t('module', 'Last Visit'),
96
            'username' => Module::t('module', 'Username'),
97
            'email' => Module::t('module', 'Email'),
98
            'auth_key' => Module::t('module', 'Auth Key'),
99
            'status' => Module::t('module', 'Status'),
100
            'first_name' => Module::t('module', 'First Name'),
101
            'last_name' => Module::t('module', 'Last Name'),
102
            'registration_type' => Module::t('module', 'Registration Type'),
103
        ];
104
    }
105
106
    /**
107
     * @inheritdoc
108
     */
109
    public static function findIdentity($id)
110
    {
111
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return static::findOne(a... self::STATUS_ACTIVE)); (yii\db\ActiveRecordInterface|array|null) is incompatible with the return type declared by the interface yii\web\IdentityInterface::findIdentity of type yii\web\IdentityInterface.

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...
112
    }
113
114
    /**
115
     * @param mixed $token
116
     * @param null $type
117
     * @return null|static
118
     */
119
    public static function findIdentityByAccessToken($token, $type = null)
120
    {
121
        return static::findOne(['auth_key' => $token, 'status' => self::STATUS_ACTIVE]);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return static::findOne(a... self::STATUS_ACTIVE)); (yii\db\ActiveRecordInterface|array|null) is incompatible with the return type declared by the interface yii\web\IdentityInterfac...ndIdentityByAccessToken of type yii\web\IdentityInterface.

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...
122
    }
123
124
    /**
125
     * Finds user by username
126
     *
127
     * @param string $username
128
     * @return static|null
129
     */
130
    public static function findByUsername($username)
131
    {
132
        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
133
    }
134
135
    /**
136
     * Finds user by email
137
     *
138
     * @param string $email
139
     * @return static|null
140
     */
141
    public static function findByUsernameEmail($email)
142
    {
143
        return static::findOne(['email' => $email, 'status' => self::STATUS_ACTIVE]);
144
    }
145
146
    /**
147
     * Finds user by username or email
148
     *
149
     * @param string $string
150
     * @return static|null
151
     */
152
    public static function findByUsernameOrEmail($string)
153
    {
154
        return static::find()
155
            ->where(['or', ['username' => $string], ['email' => $string]])
156
            ->andWhere(['status' => self::STATUS_ACTIVE])
157
            ->one();
158
    }
159
160
    /**
161
     * Finds user by password reset token
162
     *
163
     * @param string $token password reset token
164
     * @return static|null
165
     */
166
    public static function findByPasswordResetToken($token)
167
    {
168
        if (!static::isPasswordResetTokenValid($token)) {
169
            return null;
170
        }
171
        return static::findOne([
172
            'password_reset_token' => $token,
173
            'status' => self::STATUS_ACTIVE,
174
        ]);
175
    }
176
177
    /**
178
     * Finds out if password reset token is valid
179
     *
180
     * @param string $token password reset token
181
     * @return boolean
182
     */
183
    public static function isPasswordResetTokenValid($token)
184
    {
185
        if (empty($token)) {
186
            return false;
187
        }
188
        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
189
        $parts = explode('_', $token);
190
        $timestamp = (int)end($parts);
191
        return $timestamp + $expire >= time();
192
    }
193
194
    /**
195
     * @inheritdoc
196
     */
197
    public function getId()
198
    {
199
        return $this->getPrimaryKey();
200
    }
201
202
    /**
203
     * @inheritdoc
204
     */
205
    public function getAuthKey()
206
    {
207
        return $this->auth_key;
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213
    public function validateAuthKey($authKey)
214
    {
215
        return $this->getAuthKey() === $authKey;
216
    }
217
218
    /**
219
     * Validates password
220
     *
221
     * @param string $password password to validate
222
     * @return boolean if password provided is valid for current user
223
     */
224
    public function validatePassword($password)
225
    {
226
        return Yii::$app->security->validatePassword($password, $this->password_hash);
227
    }
228
229
    /**
230
     * Generates password hash from password and sets it to the model
231
     *
232
     * @param string $password
233
     */
234
    public function setPassword($password)
235
    {
236
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
237
    }
238
239
    /**
240
     * Generates "remember me" authentication key
241
     */
242
    public function generateAuthKey()
243
    {
244
        $this->auth_key = Yii::$app->security->generateRandomString();
245
    }
246
247
    /**
248
     * Generates new password reset token
249
     */
250
    public function generatePasswordResetToken()
251
    {
252
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
253
    }
254
255
    /**
256
     * Removes password reset token
257
     */
258
    public function removePasswordResetToken()
259
    {
260
        $this->password_reset_token = null;
261
    }
262
263
    /**
264
     * @param string $email_confirm_token
265
     * @return static|null
266
     */
267
    public static function findByEmailConfirmToken($email_confirm_token)
268
    {
269
        return static::findOne(['email_confirm_token' => $email_confirm_token, 'status' => self::STATUS_WAIT]);
270
    }
271
272
    /**
273
     * Generates email confirmation token
274
     */
275
    public function generateEmailConfirmToken()
276
    {
277
        $this->email_confirm_token = Yii::$app->security->generateRandomString();
278
    }
279
280
    /**
281
     * Removes email confirmation token
282
     */
283
    public function removeEmailConfirmToken()
284
    {
285
        $this->email_confirm_token = null;
286
    }
287
288
    /**
289
     * @return bool
290
     */
291
    public function isDeleted()
292
    {
293
        return $this->status === self::STATUS_DELETED;
294
    }
295
296
    /**
297
     * Actions before saving
298
     *
299
     * @param bool $insert
300
     * @return bool
301
     */
302
    public function beforeSave($insert)
303
    {
304
        if (parent::beforeSave($insert)) {
305
            if ($insert) {
306
                $this->generateAuthKey();
307
            }
308
            return true;
309
        }
310
        return false;
311
    }
312
313
    /**
314
     * @return array
315
     */
316
    public static function getStatusesArray()
317
    {
318
        return [
319
            self::STATUS_BLOCKED => Module::t('module', 'Blocked'),
320
            self::STATUS_ACTIVE => Module::t('module', 'Active'),
321
            self::STATUS_WAIT => Module::t('module', 'Wait'),
322
            self::STATUS_DELETED => Module::t('module', 'Deleted'),
323
        ];
324
    }
325
326
    /**
327
     * @return mixed
328
     */
329
    public function getStatusName()
330
    {
331
        return ArrayHelper::getValue(self::getStatusesArray(), $this->status);
332
    }
333
334
    /**
335
     * Return <span class="label label-success">Active</span>
336
     * @return string
337
     */
338
    public function getStatusLabelName()
339
    {
340
        $name = ArrayHelper::getValue(self::getLabelsArray(), $this->status);
341
        return Html::tag('span', self::getStatusName(), ['class' => 'label label-' . $name]);
342
    }
343
344
    /**
345
     * @return array
346
     */
347
    public static function getLabelsArray()
348
    {
349
        return [
350
            self::STATUS_BLOCKED => 'default',
351
            self::STATUS_ACTIVE => 'success',
352
            self::STATUS_WAIT => 'warning',
353
            self::STATUS_DELETED => 'danger',
354
        ];
355
    }
356
357
    /**
358
     * Type of registration
359
     * How the user is created
360
     * If the system registration type is registered by itself,
361
     * if it is created from the admin area,
362
     * then the login type that created the account
363
     *
364
     * @return mixed|string
365
     */
366
    public function getRegistrationType()
367
    {
368
        if ($this->registration_type > 0) {
369
            if (($model = User::findOne($this->registration_type)) !== null) {
370
                return $model->username;
371
            }
372
        }
373
        return $this->getRegistrationTypeName();
374
    }
375
376
    /**
377
     * Returns the registration type string
378
     * @return mixed
379
     */
380
    public function getRegistrationTypeName()
381
    {
382
        return ArrayHelper::getValue(self::getRegistrationTypesArray(), $this->registration_type);
383
    }
384
385
    /**
386
     * Returns an array of log types
387
     * @return array
388
     */
389
    public static function getRegistrationTypesArray()
390
    {
391
        return [
392
            self::TYPE_REGISTRATION_SYSTEM => Module::t('module', 'System'),
393
        ];
394
    }
395
396
    /**
397
     * @return string
398
     */
399
    public function getUserFullName()
400
    {
401
        if (Yii::$app->user) {
402
            if ($this->first_name && $this->last_name) {
403
                $fullName = $this->first_name . ' ' . $this->last_name;
404
            } else if ($this->first_name) {
405
                $fullName = $this->first_name;
406
            } else if ($this->last_name) {
407
                $fullName = $this->last_name;
408
            } else {
409
                $fullName = $this->username;
410
            }
411
            return Html::encode($fullName);
412
        }
413
        return false;
414
    }
415
}
416