Admin::tableName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
namespace zacksleo\yii2\backend\models;
4
5
use yii;
6
use yii\base\NotSupportedException;
7
use yii\db\ActiveRecord;
8
use yii\web\IdentityInterface;
9
use yii\web\UploadedFile;
10
use yii\helpers\Url;
11
use yii\behaviors\TimestampBehavior;
12
use zacksleo\yii2\backend\models\queries\AdminQuery;
13
use zacksleo\yii2\backend\Module;
14
15
/**
16
 * User model
17
 *
18
 * @property integer $id
19
 * @property string $username
20
 * @property string $email
21
 * @property integer $role
22
 * @property integer $status
23
 * @property string $created_at
24
 * @property string $updated_at
25
 * @property string $password_hash write-only password
26
 * @property string $avatar
27
 * @property string $auth_key
28
 * @property string $name
29
 * @property string $password_rest_token
30
 * @property string $email_confirmation_token
31
 * @property UploadedFile $imageFile
32
 */
33
class Admin extends ActiveRecord implements IdentityInterface
34
{
35
    const STATUS_INACTIVE = 0;
36
    const STATUS_ACTIVE = 10;
37
38
    public $imageFile;
39
40
    public $isAdmin = true;
41
42
    /**
43
     * @var string|null the current password value from form input
44
     */
45
    protected $_password;
46
47
    /**
48
     * @inheritdoc
49
     */
50 16
    public static function tableName()
51
    {
52 16
        return '{{%admin}}';
53
    }
54
55
    /**
56
     * @return AdminQuery custom query class with user scopes
57
     */
58 14
    public static function find()
59
    {
60 14
        return new AdminQuery(get_called_class());
61
    }
62
63
    /**
64
     * @inheritdoc
65
     */
66 7
    public function scenarios()
67
    {
68 7
        return array_merge(parent::scenarios(), [
69 7
            'reset' => ['username', 'email', 'password_hash'],
70
        ]);
71
    }
72
73
    /**
74
     * @inheritdoc
75
     */
76 7
    public function rules()
77
    {
78
        return [
79 7
            [['username', 'email', 'mobilephone', 'password_hash'], 'required', 'on' => 'reset'],
80
            ['username', 'match', 'pattern' => '/^[a-z]\w*$/i', 'on' => 'reset'],
81
            ['password_hash', 'match', 'pattern' => '/\d/', 'message' => '密码至少包含一位数字', 'on' => 'reset'],
82
            ['password_hash', 'match', 'pattern' => '/[a-zA-Z]/', 'message' => '密码至少包含一个字母', 'on' => 'reset'],
83
84 7
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
85 7
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE]],
86
87
            ['username', 'filter', 'filter' => 'trim'],
88
            ['username', 'unique', 'on' => 'reset'],
89
            ['username', 'string', 'min' => 2, 'max' => 255],
90
            ['name', 'string', 'max' => '20'],
91
92
            ['email', 'filter', 'filter' => 'trim'],
93
            ['email', 'email'],
94
            ['email', 'unique', 'on' => 'reset'],
95
            ['avatar', 'safe'],
96
            [
97
                ['imageFile'],
98
                'file',
99
                'skipOnEmpty' => true,
100
                'extensions' => 'png, jpg',
101
                'maxFiles' => 1,
102
                'maxSize' => 300000
103
            ],
104
        ];
105
    }
106
107
    /**
108
     * @inheritdoc
109
     */
110 2
    public function attributeLabels()
111
    {
112
        return [
113 2
            'avatar' => Module::t('backend', 'avatar'),
114 2
            'id' => Module::t('backend', 'id'),
115 2
            'username' => Module::t('backend', 'username'),
116 2
            'email' => Module::t('backend', 'email'),
117 2
            'is_email_verified' => Module::t('backend', 'is email verified'),
118 2
            'password_hash' => Module::t('backend', 'password'),
119 2
            'status' => Module::t('backend', 'status'),
120 2
            'created_at' => Module::t('backend', 'create time'),
121 2
            'updated_at' => Module::t('backend', 'update time'),
122 2
            'imageFile' => '上传头像',
123 2
            'name' => '姓名'
124
        ];
125
    }
126
127
    /**
128
     * @inheritdoc
129
     */
130 17
    public function behaviors()
131
    {
132
        return [
133
            'timestamp' => [
134 17
                'class' => TimestampBehavior::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
135
            ],
136
        ];
137
    }
138
139
    /**
140
     * @inheritdoc
141
     */
142 6
    public function beforeSave($insert)
143
    {
144 6
        if ($this->isNewRecord) {
145
            $this->setPassword($this->password_hash);
146
        }
147 6
        if (Yii::$app->request->isPost && isset($_POST['Admin']['imageFile'])) {
148
            $this->imageFile = UploadedFile::getInstance($this, 'imageFile');
149
            if (!empty($this->imageFile) && !$this->upload()) {
150
                $this->addError('avatar', $this->imageFile->getHasError());
0 ignored issues
show
Documentation introduced by
$this->imageFile->getHasError() is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
151
                return false;
152
            }
153
        }
154 6
        return parent::beforeSave($insert);
155
    }
156
157
    /**
158
     * @inheritdoc
159
     */
160 5
    public static function findIdentity($id)
161
    {
162 5
        return static::findOne($id);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return static::findOne($id); (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...
163
    }
164
165
    /**
166
     * @inheritdoc
167
     */
168 1
    public static function findIdentityByAccessToken($token, $type = null)
169
    {
170 1
        throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
171
    }
172
173
    /**
174
     * @inheritdoc
175
     */
176 3
    public function getId()
177
    {
178 3
        return $this->getPrimaryKey();
179
    }
180
181
    /**
182
     * @inheritdoc
183
     */
184 1
    public function getAuthKey()
185
    {
186 1
        return $this->auth_key;
187
    }
188
189
    /**
190
     * @inheritdoc
191
     */
192 1
    public function validateAuthKey($authKey)
193
    {
194 1
        return $this->getAuthKey() === $authKey;
195
    }
196
197
    /**
198
     * Validates password
199
     *
200
     * @param  string $password password to validate
201
     * @return boolean if password provided is valid for current user
202
     */
203 4
    public function validatePassword($password)
204
    {
205 4
        return Yii::$app->security->validatePassword($password, $this->password_hash);
206
    }
207
208
    /**
209
     * Generates password hash from password and sets it to the model
210
     *
211
     * @param string $password
212
     */
213 3
    public function setPassword($password)
214
    {
215 3
        $this->_password = $password;
216 3
        if (!empty($password)) {
217 3
            $this->password_hash = Yii::$app->security->generatePasswordHash($password);
218
        }
219 3
    }
220
221
    /**
222
     * @return string|null the current password value, if set from form. Null otherwise.
223
     */
224
    public function getPassword()
225
    {
226
        return $this->_password;
227
    }
228
229
    /**
230
     * Generates "remember me" authentication key
231
     */
232 1
    public function generateAuthKey()
233
    {
234 1
        $this->auth_key = Yii::$app->security->generateRandomString();
235 1
    }
236
237
    /**
238
     * Generates new email confirmation token
239
     * @param bool $save whether to save the record. Default is `false`.
240
     * @return bool|null whether the save was successful or null if $save was false.
241
     */
242
    public function generateEmailConfirmationToken($save = false)
243
    {
244
        $this->email_confirmation_token = Yii::$app->security->generateRandomString() . '_' . time();
245
        if ($save) {
246
            return $this->save();
247
        }
248
    }
249
250
    /**
251
     * Generates new password reset token
252
     * @param bool $save whether to save the record. Default is `false`.
253
     * @return bool|null whether the save was successful or null if $save was false.
254
     */
255 3
    public function generatePasswordResetToken($save = false)
256
    {
257 3
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
0 ignored issues
show
Bug introduced by
The property password_reset_token does not seem to exist. Did you mean password_rest_token?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
258 3
        if ($save) {
259 3
            return $this->save();
260
        }
261
    }
262
263
    /**
264
     * Resets to a new password and deletes the password reset token.
265
     * @param string $password the new password for this user.
266
     * @return bool whether the record was updated successfully
267
     */
268 3
    public function resetPassword($password)
269
    {
270 3
        $this->setPassword($password);
271 3
        $this->password_reset_token = null;
0 ignored issues
show
Bug introduced by
The property password_reset_token does not seem to exist. Did you mean password_rest_token?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
272 3
        return $this->save();
273
    }
274
275
    public static function getStatusList()
276
    {
277
        return [
278
            self::STATUS_ACTIVE => '激活',
279
            self::STATUS_INACTIVE => '禁用',
280
        ];
281
    }
282
283
    /**
284
     * 上传头像
285
     * @return bool
286
     */
287 1
    public function upload()
288
    {
289 1
        if ($this->validate()) {
290 1
            $path = date('Ymd') . '/';
291 1
            $fullpath = \Yii::getAlias('@app') . '/web/uploads/' . $path;
292 1
            if (!file_exists($fullpath)) {
293 1
                mkdir($fullpath);
294
            }
295 1
            $filename = uniqid() . '.' . $this->imageFile->extension;
296 1
            $this->imageFile->saveAs($fullpath . $filename);
297 1
            $this->avatar = $path . $filename;
298 1
            return true;
299
        } else {
300 1
            return false;
301
        }
302
    }
303
304
    /**
305
     * 获取头像地址
306
     * @return string
307
     */
308 1
    public function getImageUrl()
309
    {
310 1
        if (empty($this->avatar)) {
311
            return Url::to('/images/avatar.jpg');
312
        }
313 1
        return Url::to('@web/uploads/' . $this->avatar, true);
314
    }
315
}
316