Completed
Push — master ( e9f632...e6bbe5 )
by Alexey
11:02
created

User::getStatusLabelName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
namespace modules\users\models;
4
5
use Yii;
6
use yii\base\NotSupportedException;
7
use yii\behaviors\TimestampBehavior;
8
use yii\db\ActiveRecord;
9
use yii\web\IdentityInterface;
10
use yii\helpers\ArrayHelper;
11
use yii\helpers\Html;
12
use yii\helpers\Url;
13
use modules\users\Module;
14
15
/**
16
 * User model
17
 *
18
 * @property integer $id
19
 * @property string $username
20
 * @property string $password_hash
21
 * @property string $password_reset_token
22
 * @property string $email
23
 * @property string $auth_key
24
 * @property integer $status
25
 * @property integer $created_at
26
 * @property integer $updated_at
27
 * @property string $password write-only password
28
 * @property integer $last_visit
29
 * @property string $email_confirm_token
30
 * @property string $avatar
31
 * @property string $first_name
32
 * @property string $last_name
33
 * @property string $registration_type
34
 */
35
class User extends ActiveRecord implements IdentityInterface
36
{
37
    const STATUS_BLOCKED = 0;
38
    const STATUS_ACTIVE = 1;
39
    const STATUS_WAIT = 2;
40
    const STATUS_DELETED = 3;
41
42
    const LENGTH_STRING_PASSWORD_MIN = 6;
43
    const LENGTH_STRING_PASSWORD_MAX = 16;
44
45
    const RBAC_DEFAULT_ROLE = \modules\rbac\models\Role::ROLE_DEFAULT;
46
47
    public $role;
48
    public $imageFile;
49
    public $isDel;
50
51
    /**
52
     * @inheritdoc
53
     */
54
    public static function tableName()
55
    {
56
        return '{{%user}}';
57
    }
58
59
    /**
60
     * @inheritdoc
61
     */
62
    public function behaviors()
63
    {
64
        return [
65
            'timestamp' => [
66
                'class' => TimestampBehavior::className(),
67
            ],
68
        ];
69
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74
    public function rules()
75
    {
76
        return [
77
            ['username', 'required'],
78
            ['username', 'match', 'pattern' => '#^[\w_-]+$#i'],
79
            ['username', 'unique', 'targetClass' => self::className(), 'message' => Module::t('module', 'This username is already taken.')],
80
            ['username', 'string', 'min' => 2, 'max' => 255],
81
82
            ['email', 'required'],
83
            ['email', 'email'],
84
            ['email', 'unique', 'targetClass' => self::className(), 'message' => Module::t('module', 'This email is already taken.')],
85
            ['email', 'string', 'max' => 255],
86
87
            ['status', 'integer'],
88
            ['status', 'default', 'value' => self::STATUS_WAIT],
89
            ['status', 'in', 'range' => array_keys(self::getStatusesArray())],
90
91
            [['first_name', 'last_name'], 'string', 'max' => 45],
92
93
            [['role', 'registration_type'], 'safe'],
94
        ];
95
    }
96
97
    /**
98
     * @inheritdoc
99
     */
100
    public function attributeLabels()
101
    {
102
        return [
103
            'id' => 'ID',
104
            'created_at' => Module::t('module', 'Created'),
105
            'updated_at' => Module::t('module', 'Updated'),
106
            'last_visit' => Module::t('module', 'Last Visit'),
107
            'username' => Module::t('module', 'Username'),
108
            'email' => Module::t('module', 'Email'),
109
            'auth_key' => Module::t('module', 'Auth Key'),
110
            'status' => Module::t('module', 'Status'),
111
            'role' => Module::t('module', 'Role'),
112
            'userRoleName' => Module::t('module', 'Role'),
113
            'avatar' => Module::t('module', 'Avatar'),
114
            'first_name' => Module::t('module', 'First Name'),
115
            'last_name' => Module::t('module', 'Last Name'),
116
            'registration_type' => Module::t('module', 'Registration Type'),
117
            'imageFile' => Module::t('module', 'Avatar'),
118
            'isDel' => Module::t('module', 'Delete Avatar'),
119
        ];
120
    }
121
122
    /**
123
     * @return string
124
     */
125
    public function getAvatarPath()
126
    {
127
        if ($this->avatar != null) {
128
            $upload = Yii::$app->getModule('users')->uploads;
129
            $path = Yii::$app->params['domainFrontend'] . '/' . $upload . '/' . $this->id . '/' . $this->avatar;
130
            return $path;
131
        }
132
        return null;
133
    }
134
135
    /**
136
     * @return array
137
     */
138
    public static function getStatusesArray()
139
    {
140
        return [
141
            self::STATUS_BLOCKED => Module::t('module', 'Blocked'),
142
            self::STATUS_ACTIVE => Module::t('module', 'Active'),
143
            self::STATUS_WAIT => Module::t('module', 'Wait'),
144
            self::STATUS_DELETED => Module::t('module', 'Deleted'),
145
        ];
146
    }
147
148
    /**
149
     * @return string
150
     */
151
    public function getRegistrationType()
152
    {
153
        if ($this->registration_type > 0) {
154
            if (($model = User::findOne($this->registration_type)) !== null) {
155
                return $model->username;
156
            }
157
        }
158
        return Module::t('module', 'System');
159
    }
160
161
    /**
162
     * @return array
163
     */
164
    public static function getLabelsArray()
165
    {
166
        return [
167
            self::STATUS_BLOCKED => 'default',
168
            self::STATUS_ACTIVE => 'success',
169
            self::STATUS_WAIT => 'warning',
170
            self::STATUS_DELETED => 'danger',
171
        ];
172
    }
173
174
    /**
175
     * @return mixed
176
     */
177
    public function getStatusName()
178
    {
179
        return ArrayHelper::getValue(self::getStatusesArray(), $this->status);
180
    }
181
182
    /**
183
     * Return <span class="label label-success">Active</span>
184
     * @return string
185
     */
186
    public function getStatusLabelName()
187
    {
188
        $name = ArrayHelper::getValue(self::getLabelsArray(), $this->status);
189
        return Html::tag('span', self::getStatusName(), ['class' => 'label label-' . $name]);
190
    }
191
192
    /**
193
     * @return array
194
     */
195
    public function getRolesArray()
196
    {
197
        return ArrayHelper::map(Yii::$app->authManager->getRoles(), 'name', 'description');
198
    }
199
200
    /**
201
     * @return mixed|null
202
     */
203
    public function getUserRoleName()
204
    {
205
        if ($role = Yii::$app->authManager->getRolesByUser($this->id))
206
            return ArrayHelper::getValue($role, function ($role, $defaultValue) {
0 ignored issues
show
Unused Code introduced by
The parameter $defaultValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
207
                foreach ($role as $key => $value) {
208
                    return $value->description;
209
                }
210
                return null;
211
            });
212
        return null;
213
    }
214
215
    /**
216
     * @return mixed
217
     */
218
    public function getRoleName()
219
    {
220
        $auth = Yii::$app->authManager;
221
        $roles = $auth->getRolesByUser($this->id);
222
        $role = '';
223
        foreach ($roles as $item) {
224
            $role .= $item->description ? $item->description . ', ' : $item->name . ', ';
225
        }
226
        return chop($role, ' ,');
227
    }
228
229
    /**
230
     * Получаем роль пользователя
231
     */
232
    public function getRoleUser()
233
    {
234
        if ($role = Yii::$app->authManager->getRolesByUser($this->id))
235
            return ArrayHelper::getValue($role, function ($role, $defaultValue) {
0 ignored issues
show
Unused Code introduced by
The parameter $defaultValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
236
                foreach ($role as $key => $value) {
237
                    return $value->name;
238
                }
239
                return null;
240
            });
241
        return null;
242
    }
243
244
    /**
245
     * @param null $user_id
246
     * @return mixed|null
247
     */
248
    public function getUserRoleValue($user_id = null)
249
    {
250
        if ($user_id) {
251
            if ($role = Yii::$app->authManager->getRolesByUser($user_id))
252
                return ArrayHelper::getValue($role, function ($role) {
253
                    foreach ($role as $key => $value) {
254
                        return $value->name;
255
                    }
256
                    return null;
257
                });
258
        } else {
259
            if ($role = Yii::$app->authManager->getRolesByUser($this->id))
260
                return ArrayHelper::getValue($role, function ($role) {
261
                    foreach ($role as $key => $value) {
262
                        return $value->name;
263
                    }
264
                    return null;
265
                });
266
        }
267
        return null;
268
    }
269
270
    /**
271
     * @return string
272
     */
273
    public function getUserFullName()
274
    {
275
        if (Yii::$app->user) {
276
            if ($this->first_name && $this->last_name) {
277
                $fullName = $this->first_name . ' ' . $this->last_name;
278
            } else if ($this->first_name) {
279
                $fullName = $this->first_name;
280
            } else if ($this->last_name) {
281
                $fullName = $this->last_name;
282
            } else {
283
                $fullName = $this->username;
284
            }
285
            return Html::encode($fullName);
286
        }
287
        return false;
288
    }
289
290
    /**
291
     * @inheritdoc
292
     */
293
    public static function findIdentity($id)
294
    {
295
        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...
296
    }
297
298
    /**
299
     * @param mixed $token
300
     * @param null $type
301
     * @return null|static
302
     */
303
    public static function findIdentityByAccessToken($token, $type = null)
304
    {
305
        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...
306
    }
307
308
    /**
309
     * Finds user by username
310
     *
311
     * @param string $username
312
     * @return static|null
313
     */
314
    public static function findByUsername($username)
315
    {
316
        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
317
    }
318
319
    /**
320
     * Finds user by email
321
     *
322
     * @param string $email
323
     * @return static|null
324
     */
325
    public static function findByUsernameEmail($email)
326
    {
327
        return static::findOne(['email' => $email, 'status' => self::STATUS_ACTIVE]);
328
    }
329
330
    /**
331
     * Finds user by username or email
332
     *
333
     * @param string $string
334
     * @return static|null
335
     */
336
    public static function findByUsernameOrEmail($string)
337
    {
338
        return static::find()
339
            ->where(['or', ['username' => $string], ['email' => $string]])
340
            ->andWhere(['status' => self::STATUS_ACTIVE])
341
            ->one();
342
    }
343
344
    /**
345
     * Finds user by password reset token
346
     *
347
     * @param string $token password reset token
348
     * @return static|null
349
     */
350
    public static function findByPasswordResetToken($token)
351
    {
352
        if (!static::isPasswordResetTokenValid($token)) {
353
            return null;
354
        }
355
356
        return static::findOne([
357
            'password_reset_token' => $token,
358
            'status' => self::STATUS_ACTIVE,
359
        ]);
360
    }
361
362
    /**
363
     * Finds out if password reset token is valid
364
     *
365
     * @param string $token password reset token
366
     * @return boolean
367
     */
368
    public static function isPasswordResetTokenValid($token)
369
    {
370
        if (empty($token)) {
371
            return false;
372
        }
373
374
        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
375
        $parts = explode('_', $token);
376
        $timestamp = (int)end($parts);
377
        return $timestamp + $expire >= time();
378
    }
379
380
    /**
381
     * @inheritdoc
382
     */
383
    public function getId()
384
    {
385
        return $this->getPrimaryKey();
386
    }
387
388
    /**
389
     * @inheritdoc
390
     */
391
    public function getAuthKey()
392
    {
393
        return $this->auth_key;
394
    }
395
396
    /**
397
     * @inheritdoc
398
     */
399
    public function validateAuthKey($authKey)
400
    {
401
        return $this->getAuthKey() === $authKey;
402
    }
403
404
    /**
405
     * Validates password
406
     *
407
     * @param string $password password to validate
408
     * @return boolean if password provided is valid for current user
409
     */
410
    public function validatePassword($password)
411
    {
412
        return Yii::$app->security->validatePassword($password, $this->password_hash);
413
    }
414
415
    /**
416
     * Generates password hash from password and sets it to the model
417
     *
418
     * @param string $password
419
     */
420
    public function setPassword($password)
421
    {
422
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
423
    }
424
425
    /**
426
     * Generates "remember me" authentication key
427
     */
428
    public function generateAuthKey()
429
    {
430
        $this->auth_key = Yii::$app->security->generateRandomString();
431
    }
432
433
    /**
434
     * Generates new password reset token
435
     */
436
    public function generatePasswordResetToken()
437
    {
438
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
439
    }
440
441
    /**
442
     * Removes password reset token
443
     */
444
    public function removePasswordResetToken()
445
    {
446
        $this->password_reset_token = null;
447
    }
448
449
    /**
450
     * @param string $email_confirm_token
451
     * @return static|null
452
     */
453
    public static function findByEmailConfirmToken($email_confirm_token)
454
    {
455
        return static::findOne(['email_confirm_token' => $email_confirm_token, 'status' => self::STATUS_WAIT]);
456
    }
457
458
    /**
459
     * Generates email confirmation token
460
     */
461
    public function generateEmailConfirmToken()
462
    {
463
        $this->email_confirm_token = Yii::$app->security->generateRandomString();
464
    }
465
466
    /**
467
     * Removes email confirmation token
468
     */
469
    public function removeEmailConfirmToken()
470
    {
471
        $this->email_confirm_token = null;
472
    }
473
474
    /**
475
     * @return bool
476
     */
477
    public function isDeleted()
478
    {
479
        return $this->status === self::STATUS_DELETED;
480
    }
481
482
    /**
483
     * Gravatar Service
484
     * @url https://www.gravatar.com
485
     *
486
     * @param $email
487
     * @param int $s
488
     * @param string $d
489
     * @param string $r
490
     * @param bool $img
491
     * @param array $attr
492
     * @return string
493
     */
494
    public function getGravatar($email = null, $s = 80, $d = 'mm', $r = 'g', $img = false, $attr = [])
495
    {
496
        $email = empty($email) ? $this->email : $email;
497
498
        $url = 'https://www.gravatar.com/avatar/';
499
        $url .= md5(strtolower(trim($email))) . '?';
500
        $url .= http_build_query([
501
            's' => $s,
502
            'd' => $d,
503
            'r' => $r,
504
        ]);
505
506
        return $img ? Html::img($url, $attr) : $url;
507
    }
508
509
    /**
510
     * Действия перед сохранением
511
     * @inheritdoc
512
     */
513
    public function beforeSave($insert)
514
    {
515
        if (parent::beforeSave($insert)) {
516
            if ($insert) {
517
                $this->generateAuthKey();
518
            }
519
            return true;
520
        }
521
        return false;
522
    }
523
524
    /**
525
     * Действия после сохранения
526
     * @param bool $insert
527
     * @param array $changedAttributes
528
     */
529
    /*public function afterSave($insert, $changedAttributes)
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
530
    {
531
        parent::afterSave($insert, $changedAttributes);
532
        if ($insert) {
533
534
        }
535
    }*/
536
537
    /**
538
     * Действия перед удалением
539
     * @return bool
540
     */
541
    public function beforeDelete()
542
    {
543
        parent::beforeDelete();
544
        $this->revokeRoles();
545
        $this->removeAvatar();
546
        return true;
547
    }
548
549
    /**
550
     * Отвязываем пользователя от всех ролей
551
     */
552
    public function revokeRoles()
553
    {
554
        $authManager = Yii::$app->getAuthManager();
555
        if ($authManager->getRolesByUser($this->id)) {
556
            $authManager->revokeAll($this->id);
557
        }
558
    }
559
560
    /**
561
     * Удаляем аватарку
562
     */
563
    public function removeAvatar()
564
    {
565
        if ($this->avatar) {
566
            $upload = Yii::$app->getModule('users')->uploads;
567
            $path = str_replace('\\', '/', Url::to('@upload') . DIRECTORY_SEPARATOR . $upload . DIRECTORY_SEPARATOR . $this->id);
568
            $file = $path . DIRECTORY_SEPARATOR . $this->avatar;
569
            if (file_exists($file)) {
570
                unlink($file);
571
            }
572
            // удаляем папку пользователя
573
            if (is_dir($path)) {
574
                @rmdir($path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
575
            }
576
        }
577
    }
578
}
579