• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

miaoxing / plugin / 12451994687

22 Dec 2024 06:32AM UTC coverage: 42.441%. Remained the same
12451994687

push

github

twinh
fix(plugin): `GAutoCompletion` 增加 AsCommand 属性以兼容 sf console 6,7

1238 of 2917 relevant lines covered (42.44%)

37.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.04
/src/Service/User.php
1
<?php
2

3
namespace Miaoxing\Plugin\Service;
4

5
use Miaoxing\Plugin\Auth\BaseAuth;
6
use Miaoxing\Plugin\Auth\JwtAuth;
7
use Miaoxing\Plugin\BaseService;
8
use Miaoxing\Plugin\ConfigTrait;
9
use Wei\Ret;
10
use Wei\Time;
11

12
/**
13
 * 用户
14
 *
15
 * @property bool $enableRegister
16
 * @property string $disableRegisterTips
17
 * @property bool $enableLoginCaptcha
18
 * @property int $defaultGroupId
19
 * @property bool $enablePasswordRest
20
 * @property bool $enableMobileVerify
21
 * @property bool $enableLogin
22
 * @property string $disableLoginTips
23
 * @property string $bgImage
24
 * @property int $defaultTagId
25
 * @property int $agreementArticleId
26
 * @property bool $enableExport
27
 * @property bool $enableCreate
28
 * @property string $defaultAvatar
29
 * @property bool $enablePinCode
30
 * @mixin \EventMixin
31
 * @mixin \ReqMixin
32
 */
33
class User extends BaseService
34
{
35
    use ConfigTrait {
36
        __get as getConfig;
37
    }
38

39
    /**
40
     * 用户服务是唯一的
41
     *
42
     * @var bool
43
     */
44
    protected static $createNewInstance = false;
45

46
    /**
47
     * @var UserModel|null
48
     */
49
    protected $cur;
50

51
    /**
52
     * @experimental expected to change
53
     */
54
    protected $configs = [
55
        'enablePinCode' => [
56
            'default' => false,
57
        ],
58
        'checkMobileUnique' => [
59
            'default' => false,
60
        ],
61
        'defaultAvatar' => [
62
            'default' => '',
63
        ],
64
        'enableLogin' => [
65
            'default' => true,
66
        ],
67
        'enableRegister' => [
68
            'default' => true,
69
        ],
70
        'disableRegisterTips' => [
71
            'default' => '注册功能未启用',
72
        ],
73
        'enableLoginCaptcha' => [
74
            'default' => false,
75
        ],
76
        'defaultGroupId' => [
77
            'default' => 0,
78
        ],
79
        'enablePasswordRest' => [
80
            'default' => false,
81
        ],
82
        'enableMobileVerify' => [
83
            'default' => false,
84
        ],
85
        'disableLoginTips' => [
86
            'default' => '登录功能未启用',
87
        ],
88
        'bgImage' => [
89
            'default' => '',
90
        ],
91
        'defaultTagId' => [],
92
        'agreementArticleId' => [],
93
        'enableExport' => [
94
            'default' => false,
95
        ],
96
        'enableCreate' => [
97
            'default' => false,
98
        ],
99
    ];
100

101
    /**
102
     * @var string
103
     */
104
    protected $authClass = JwtAuth::class;
105

106
    /**
107
     * @var BaseAuth|null
108
     */
109
    protected $auth;
110

111
    /**
112
     * @var array
113
     * @internal
114
     */
115
    protected $columns = [];
116

117
    /**
118
     * @param string $name
119
     * @return mixed
120
     */
121
    public function __get($name)
122
    {
123
        if (!$this->columns) {
425✔
124
            $this->columns = UserModel::getColumns();
15✔
125
        }
126
        if (isset($this->columns[$name])) {
425✔
127
            return $this->get($name);
420✔
128
        }
129

130
        return $this->getConfig($name);
10✔
131
    }
132

133
    /**
134
     * @param array|callable $returnFields
135
     * @param callable|null $prepend
136
     * @return array
137
     * @experimental may be remove
138
     * @svc
139
     */
140
    protected function toArray($returnFields = [], ?callable $prepend = null): array
141
    {
142
        return $this->cur()->toArray($returnFields, $prepend);
5✔
143
    }
144

145
    /**
146
     * @param iterable $attributes
147
     * @return UserModel
148
     * @experimental may be remove
149
     * @svc
150
     */
151
    protected function save(iterable $attributes = []): UserModel
152
    {
153
        return $this->cur()->save($attributes);
5✔
154
    }
155

156
    /**
157
     * 获取用户资料,优先从认证服务中获取
158
     *
159
     * @param string $name
160
     * @return mixed
161
     * @svc
162
     */
163
    protected function get(string $name)
164
    {
165
        $data = $this->getAuth()->getData();
445✔
166
        if (isset($data[$name])) {
445✔
167
            return $data[$name];
435✔
168
        }
169

170
        $user = $this->cur();
35✔
171
        if ($user) {
35✔
172
            return $user->get($name);
10✔
173
        }
174

175
        return null;
30✔
176
    }
177

178
    /**
179
     * Return the current user id
180
     *
181
     * @return int|string|null
182
     * @svc
183
     */
184
    protected function id()
185
    {
186
        return $this->get('id');
35✔
187
    }
188

189
    /**
190
     * Return the current user model
191
     *
192
     * @return UserModel
193
     * @svc
194
     */
195
    protected function cur(): ?UserModel
196
    {
197
        if (!$this->cur) {
50✔
198
            $this->loadDbUser();
40✔
199
        }
200
        return $this->cur;
50✔
201
    }
202

203
    /**
204
     * 判断用户是否登录
205
     *
206
     * @return bool
207
     * @svc
208
     */
209
    protected function isLogin(): bool
210
    {
211
        return $this->getAuth()->isLogin();
40✔
212
    }
213

214
    /**
215
     * 检查用户是否登录
216
     *
217
     * @return Ret
218
     * @svc
219
     */
220
    protected function checkLogin(): Ret
221
    {
222
        return $this->getAuth()->checkLogin();
×
223
    }
224

225
    /**
226
     * 根据用户账号密码,登录用户
227
     *
228
     * @param mixed $data
229
     * @return Ret
230
     * @svc
231
     */
232
    protected function login($data): Ret
233
    {
234
        // 1. 校验用户账号密码是否符合规则
235
        $validator = wei()->validate([
×
236
            'data' => $data,
×
237
            'rules' => [
×
238
                'username' => [
×
239
                    'required' => true,
×
240
                ],
×
241
                'password' => [
×
242
                    'required' => true,
×
243
                ],
×
244
            ],
×
245
            'names' => [
×
246
                'username' => '帐号',
×
247
                'password' => '密码',
×
248
            ],
×
249
        ]);
×
250

251
        if (!$validator->isValid()) {
×
252
            return err($validator->getFirstMessage());
×
253
        }
254

255
        // 2. 检查手机/邮箱/用户名是否存在
256
        $user = UserModel::new();
×
257
        switch (true) {
258
            case wei()->isMobileCn($data['username']):
×
259
                $column = 'mobile';
×
260
                $user->whereNotNULL('mobile_verified_at');
×
261
                break;
×
262

263
            case wei()->isEmail($data['username']):
×
264
                $column = 'email';
×
265
                break;
×
266

267
            default:
268
                $column = 'username';
×
269
        }
270

271
        $user = $user->findBy($column, $data['username']);
×
272

273
        if (!$user) {
×
274
            return $this->loginFailed('用户名不存在或密码错误', $user, $data);
×
275
        }
276

277
        // 3. 检查用户是否有效
278
        if (!$user->isEnabled) {
×
279
            return $this->loginFailed('用户未启用,无法登录', $user, $data);
×
280
        }
281

282
        // 4. 验证密码是否正确
283
        if (!$user->verifyPassword($data['password'])) {
×
284
            return $this->loginFailed('用户不存在或密码错误', $user, $data);
×
285
        }
286

287
        // 5. 验证通过,登录用户
288
        $ret = $this->loginByModel($user);
×
289
        if ($ret->isErr()) {
×
290
            return $this->loginFailed($ret, $user, $data);
×
291
        }
292

293
        $user->lastLoginAt = Time::now();
×
294
        $user->save();
×
295
        return $ret;
×
296
    }
297

298
    /**
299
     * 根据用户ID直接登录用户
300
     *
301
     * @param string|int $id
302
     * @return Ret
303
     * @svc
304
     */
305
    protected function loginById($id): Ret
306
    {
307
        $user = UserModel::find($id);
60✔
308
        if (!$user) {
60✔
309
            return err('用户不存在');
×
310
        } else {
311
            return $this->loginByModel($user);
60✔
312
        }
313
    }
314

315
    /**
316
     * 根据条件查找或创建用户,并登录
317
     *
318
     * @param array $conditions
319
     * @param array|object $data
320
     * @return $this
321
     * @svc
322
     */
323
    protected function loginBy(array $conditions, $data = []): self
324
    {
325
        $user = UserModel::findOrInitBy($conditions, $data);
×
326
        $this->loginByModel($user);
×
327

328
        return $this;
×
329
    }
330

331
    /**
332
     * 根据用户对象登录用户
333
     *
334
     * @param UserModel $user
335
     * @return Ret
336
     * @svc
337
     */
338
    protected function loginByModel(UserModel $user): Ret
339
    {
340
        $ret = $this->getAuth()->login($user);
90✔
341
        if ($ret->isSuc()) {
90✔
342
            $this->setCur($user);
90✔
343
            $this->event->trigger('login', [$user]);
90✔
344
            // @deprecated
345
            $this->event->trigger('userLogin', [$user]);
90✔
346
        }
347

348
        return $ret;
90✔
349
    }
350

351
    /**
352
     * 销毁用户会话,退出登录
353
     *
354
     * @return Ret
355
     * @svc
356
     */
357
    protected function logout(): Ret
358
    {
359
        if (!$this->isLogin()) {
20✔
360
            return err('用户未登录');
10✔
361
        }
362

363
        $this->getAuth()->logout();
10✔
364
        $this->event->trigger('logout', [$this->cur()]);
10✔
365
        // @@deprecated
366
        $this->event->trigger('beforeUserLogout', [$this->cur()]);
10✔
367
        $this->setCur(null);
10✔
368

369
        return suc();
10✔
370
    }
371

372
    /**
373
     * 当用户信息更改后,可以主动调用该方法,刷新会话中的数据
374
     *
375
     * @param UserModel $user
376
     * @return $this
377
     * @svc
378
     */
379
    protected function refresh(UserModel $user): self
380
    {
381
        if ($user->id === ($this->getAuth()->getData()['id'] ?? null)) {
45✔
382
            $this->loginByModel($user);
15✔
383
        }
384

385
        return $this;
45✔
386
    }
387

388
    /**
389
     * @return BaseAuth
390
     */
391
    protected function getAuth(): BaseAuth
392
    {
393
        if (!$this->auth) {
480✔
394
            $this->auth = new $this->authClass();
15✔
395
        }
396
        return $this->auth;
480✔
397
    }
398

399
    /**
400
     * Set the current user model
401
     *
402
     * @param UserModel|null $user
403
     * @return $this
404
     */
405
    protected function setCur(?UserModel $user): self
406
    {
407
        $this->cur = $user;
100✔
408
        return $this;
100✔
409
    }
410

411
    /**
412
     * 从数据库中查找用户加载到当前记录中
413
     *
414
     * @internal
415
     */
416
    protected function loadDbUser()
417
    {
418
        if (!$this->isLogin()) {
40✔
419
            return;
30✔
420
        }
421

422
        $id = $this->getAuth()->getData()['id'] ?? null;
15✔
423
        $user = UserModel::new();
15✔
424
        $user->setCacheKey($user->getModelCacheKey($id))->findOrInit($id);
15✔
425
        $this->setCur($user);
15✔
426
    }
427

428
    /**
429
     * Trigger the `loginFailed` event and return error result
430
     *
431
     * @param string|Ret $messageOrRet
432
     * @param UserModel|null $user
433
     * @param mixed $data
434
     * @return Ret
435
     * @internal
436
     */
437
    protected function loginFailed($messageOrRet, ?UserModel $user = null, $data = []): Ret
438
    {
439
        $ret = $messageOrRet instanceof Ret ? $messageOrRet : err($messageOrRet);
×
440
        $this->event->trigger('loginFailed', [$user, $ret, $data]);
×
441
        return $ret;
×
442
    }
443
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc