User   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 257
Duplicated Lines 0 %

Test Coverage

Coverage 11.36%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 32
eloc 90
c 1
b 0
f 0
dl 0
loc 257
ccs 10
cts 88
cp 0.1136
rs 9.84

22 Methods

Rating   Name   Duplication   Size   Complexity  
A generatePasswordResetToken() 0 3 1
A logout() 0 7 2
A findByVerificationToken() 0 5 1
A validatePassword() 0 3 1
A findByUsername() 0 3 1
A removePasswordResetToken() 0 3 1
A findIdentity() 0 3 1
A fields() 0 14 1
A generateAuthKey() 0 3 1
A getName() 0 5 1
A behaviors() 0 4 1
A getAuthKey() 0 3 1
A setPassword() 0 9 2
B findIdentityByAccessToken() 0 32 7
A findByPasswordResetToken() 0 9 2
A rules() 0 23 1
A tableName() 0 3 1
A validateAuthKey() 0 3 1
A getLanguage() 0 3 1
A isPasswordResetTokenValid() 0 9 2
A generateEmailVerificationToken() 0 3 1
A getId() 0 3 1
1
<?php
2
namespace App\Model;
3
4
use App\Behavior\TimestampBehavior;
5
use App\Http\Filter\LanguagePickerInterface;
6
use App\Http\User\LogoutInterface;
7
use Yii;
8
use yii\web\IdentityInterface;
9
10
/**
11
 * User model
12
 *
13
 * @property integer $id
14
 * @property string $username
15
 * @property string $name
16
 * @property string $first_name
17
 * @property string $last_name
18
 * @property string $avatar
19
 * @property string $password_hash
20
 * @property string $password_reset_token
21
 * @property string $verification_token
22
 * @property string $email
23
 * @property string $auth_key
24
 * @property integer $status
25
 * @property integer $is_deleted
26
 * @property integer $create_time
27
 * @property integer $update_time
28
 * @property string $password write-only password
29
 */
30
class User extends ActiveRecord implements
31
    IdentityInterface,
32
    LogoutInterface,
33
    LanguagePickerInterface,
34
    StatusInterface,
35
    SoftDeleteInterface
36
{
37
    use StatusTrait, SoftDeleteTrait;
38
39 3
    public static function tableName()
40
    {
41 3
        return '{{%user}}';
42
    }
43
44 2
    public function behaviors()
45
    {
46
        return [
47 2
            TimestampBehavior::class,
48
        ];
49
    }
50
51
    public function rules()
52
    {
53
        return [
54
            [
55
                [
56
                    'username', 'email', 'first_name', 'last_name', 'avatar', 'language',
57
                    'avatar',
58
                ],
59
                'string'
60
            ],
61
            ['status', 'default', 'value' => StatusInterface::STATUS_INACTIVE],
62
            [['avatar', 'auth_key'], 'default', 'value' => ''],
63
            [['language'], 'default', 'value' => Yii::$app->language],
64
            [
65
                [
66
                    'username', 'email', 'first_name', 'last_name',
67
                    'language', 'status', 'password_hash'
68
                ],
69
                'required'
70
            ],
71
            ['status', 'in', 'range' => [StatusInterface::STATUS_ACTIVE, StatusInterface::STATUS_INACTIVE]],
72
            [['password'], 'safe'],
73
            [['email', 'username'], 'unique'],
74
        ];
75
    }
76
77
    public static function findIdentity($id)
78
    {
79
        return static::findOne(['id' => $id, 'status' => StatusInterface::STATUS_ACTIVE]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::findOne(a...erface::STATUS_ACTIVE)) returns the type yii\db\ActiveRecord which is incompatible with the return type mandated by yii\web\IdentityInterface::findIdentity() of null|yii\web\IdentityInterface.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
80
    }
81
82
    /**
83
     * @var Session $session
84
     */
85
    public $session;
86
87
    public static function findIdentityByAccessToken($token, $type = null)
88
    {
89
        $token = trim(strval($token));
90
        if ($token === '') {
91
            return null;
92
        }
93
94
        $session = Session::findByToken($token);
95
        if (!$session) {
0 ignored issues
show
introduced by
$session is of type App\Model\Session, thus it always evaluated to true.
Loading history...
96
            Yii::error(sprintf('Session "%s" does not exists', $token), __METHOD__);
97
            return null;
98
        }
99
        if ($session->isExpired()) {
100
            Yii::error(sprintf('Session "%s" is expired', $token), __METHOD__);
101
            return null;
102
        }
103
        
104
        if (!$session->user) {
105
            Yii::error(sprintf('User #%s does not exists', $session->user_id), __METHOD__);
106
            return null;
107
        }
108
        if (!$session->user->isActive()) {
109
            Yii::error(sprintf('User #%s is inactive', $session->user_id), __METHOD__);
110
            return null;
111
        }
112
        if ($session->user->isDeleted()) {
113
            Yii::error(sprintf('User #%s was deleted', $session->user_id), __METHOD__);
114
            return null;
115
        }
116
        
117
        $session->user->session = $session;
118
        return $session->user;
119
    }
120
121
    public function logout(): bool
122
    {
123
        if ($this->session) {
124
            $this->session->delete();
125
        }
126
127
        return Yii::$app->getUser()->logout();
128
    }
129
130
    /**
131
     * Finds user by username
132
     *
133
     * @param string $username
134
     * @return static|null
135
     */
136 3
    public static function findByUsername($username)
137
    {
138 3
        return static::findOne(['username' => $username]);
139
    }
140
141
    /**
142
     * Finds user by password reset token
143
     *
144
     * @param string $token password reset token
145
     * @return static|null
146
     */
147
    public static function findByPasswordResetToken($token)
148
    {
149
        if (!static::isPasswordResetTokenValid($token)) {
150
            return null;
151
        }
152
153
        return static::findOne([
154
            'password_reset_token' => $token,
155
            'status' => StatusInterface::STATUS_ACTIVE,
156
        ]);
157
    }
158
159
    /**
160
     * Finds user by verification email token
161
     *
162
     * @param string $token verify email token
163
     * @return static|null
164
     */
165
    public static function findByVerificationToken($token)
166
    {
167
        return static::findOne([
168
            'verification_token' => $token,
169
            'status' => StatusInterface::STATUS_INACTIVE
170
        ]);
171
    }
172
173
    /**
174
     * Finds out if password reset token is valid
175
     *
176
     * @param string $token password reset token
177
     * @return bool
178
     */
179
    public static function isPasswordResetTokenValid($token)
180
    {
181
        if (empty($token)) {
182
            return false;
183
        }
184
185
        $timestamp = (int) substr($token, strrpos($token, '_') + 1);
186
        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
187
        return $timestamp + $expire >= time();
188
    }
189
190 1
    public function getId()
191
    {
192 1
        return $this->getPrimaryKey();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getPrimaryKey() also could return the type array which is incompatible with the return type mandated by yii\web\IdentityInterface::getId() of integer|string.
Loading history...
193
    }
194
195
    public function getAuthKey()
196
    {
197
        return $this->auth_key;
198
    }
199
200
    public function validateAuthKey($authKey)
201
    {
202
        return $this->getAuthKey() === $authKey;
203
    }
204
205
    /**
206
     * Validates password
207
     *
208
     * @param string $password password to validate
209
     * @return bool if password provided is valid for current user
210
     */
211 2
    public function validatePassword($password)
212
    {
213 2
        return Yii::$app->security->validatePassword($password, $this->password_hash);
214
    }
215
216
    /**
217
     * Generates password hash from password and sets it to the model
218
     *
219
     * @param string $password
220
     */
221
    public function setPassword($password)
222
    {
223
        $password = trim($password);
224
        // ignore empty password
225
        if ($password === '') {
226
            return;
227
        }
228
229
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
230
    }
231
232
    /**
233
     * Generates "remember me" authentication key
234
     */
235
    public function generateAuthKey()
236
    {
237
        $this->auth_key = Yii::$app->security->generateRandomString();
238
    }
239
240
    /**
241
     * Generates new password reset token
242
     */
243
    public function generatePasswordResetToken()
244
    {
245
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
246
    }
247
248
    public function generateEmailVerificationToken()
249
    {
250
        $this->verification_token = Yii::$app->security->generateRandomString() . '_' . time();
251
    }
252
253
    /**
254
     * Removes password reset token
255
     */
256
    public function removePasswordResetToken()
257
    {
258
        $this->password_reset_token = null;
259
    }
260
261
    public function getLanguage()
262
    {
263
        return $this->language;
0 ignored issues
show
Bug Best Practice introduced by
The property language does not exist on App\Model\User. Since you implemented __get, consider adding a @property annotation.
Loading history...
264
    }
265
266
    public function getName(): string
267
    {
268
        $parts = [$this->first_name, $this->last_name];
269
270
        return implode(' ', array_filter($parts));
271
    }
272
273
    public function fields()
274
    {
275
        return [
276
            'id',
277
            'username',
278
            'name',
279
            'first_name',
280
            'last_name',
281
            'avatar',
282
            'email',
283
            'language',
284
            'status',
285
            'create_time',
286
            'update_time',
287
        ];
288
    }
289
}
290