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

miaoxing / user / 5220599583

pending completion
5220599583

push

github

twinh
refactor: 校验逻辑放到 `validate` 回调中

21 of 70 branches covered (30.0%)

6 of 6 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

88 of 666 relevant lines covered (13.21%)

1.4 hits per line

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

17.73
/src/Service/UserModel.php
1
<?php
2

3
namespace Miaoxing\User\Service;
4

5
use Miaoxing\Admin\Service\GroupModel;
6
use Miaoxing\App\Service\UserModel as BaseUserModel;
7
use Miaoxing\Plugin\Service\Ret;
8
use Wei\Time;
9

10
class UserModel extends BaseUserModel
11
{
12
    public function __construct(array $options = [])
13
    {
14
        parent::__construct($options);
39✔
15
        $this->virtual = array_merge($this->virtual, [
39✔
16
            'isMobileVerified',
39✔
17
        ]);
26✔
18
    }
13✔
19

20
    public function getBackendDisplayName()
21
    {
22
        if ($this['name'] && $this['nickName']) {
×
23
            return $this['name'] . '(' . $this['nickName'] . ')';
×
24
        } elseif ($this['name']) {
×
25
            return $this['name'];
×
26
        } else {
27
            return $this['nickName'];
×
28
        }
29
    }
30

31
    /**
32
     * Repo: 根据用户编号,从缓存中获取用户名
33
     *
34
     * @param int $id
35
     * @return string
36
     */
37
    public function getDisplayNameByIdFromCache($id)
38
    {
39
        return wei()->arrayCache->remember('nickName' . $id, function () use ($id) {
40
            $user = wei()->user()->find(['id' => $id]);
×
41

42
            return $user ? $user->getNickName() : '';
×
43
        });
×
44
    }
45

46
    public function afterSave()
47
    {
48
        parent::afterSave();
27✔
49
        $this->removeModelCache();
27✔
50
    }
9✔
51

52
    public function afterDestroy()
53
    {
54
        parent::afterDestroy();
6✔
55
        $this->removeModelCache();
6✔
56
    }
2✔
57

58
    /**
59
     * Record: 移动用户分组
60
     *
61
     * @param int $groupId
62
     * @return array
63
     */
64
    public function updateGroup($groupId)
65
    {
66
        $group = GroupModel::findOrInit($groupId);
3✔
67
        $ret = wei()->event->until('groupMove', [[$this['id']], $group]);
3✔
68
        if ($ret) {
3✔
69
            return $ret;
×
70
        }
71

72
        $this->save(['groupId' => $groupId]);
3✔
73

74
        return $this->suc();
3✔
75
    }
76

77
    /**
78
     * Record: 创建一个新用户
79
     *
80
     * wei()->user()->register([
81
     *     'email' => 'xx', // 可选
82
     *     'username' => 'xx',
83
     *     'password' => 'xx',
84
     *     'passwordAgain' => 'xx,
85
     *     'source' => 1, // 来源,可选
86
     * ]);
87
     *
88
     * @param array $data
89
     * @return array
90
     * @todo 太多validate,需简化
91
     */
92
    public function register($data)
93
    {
94
        // 1. 校验额外数据
95
        if (isset($data['mobile'])) {
×
96
            $validator = wei()->validate([
×
97
                'data' => $data,
×
98
                'rules' => [
99
                    'mobile' => [
100
                        'required' => true,
101
                        'mobileCn' => true,
102
                    ],
103
                    'verifyCode' => [
104
                        'required' => true,
105
                    ],
106
                ],
107
                'names' => [
108
                    'mobile' => '手机号码',
109
                    'verifyCode' => '验证码',
110
                ],
111
                'messages' => [
112
                    'mobile' => [
113
                        'required' => '请输入手机号码',
114
                    ],
115
                    'verifyCode' => [
116
                        'required' => '请输入验证码',
117
                    ],
118
                ],
119
            ]);
120
            if (!$validator->isValid()) {
×
121
                return ['code' => -1, 'message' => $validator->getFirstMessage()];
×
122
            }
123

124
            $ret = wei()->verifyCode->check($data['mobile'], $data['verifyCode']);
×
125
            if (1 !== $ret['code']) {
×
126
                return $ret + ['verifyCodeErr' => true];
×
127
            }
128
        } else {
129
            $validator = wei()->validate([
×
130
                'data' => $data,
×
131
                'rules' => [
132
                    'email' => [
133
                        'required' => true,
134
                    ],
135
                ],
136
                'names' => [
137
                    'email' => '邮箱',
138
                ],
139
                'messages' => [
140
                    'email' => [
141
                        'required' => '请输入邮箱',
142
                    ],
143
                ],
144
            ]);
145
            if (!$validator->isValid()) {
×
146
                return ['code' => -1, 'message' => $validator->getFirstMessage()];
×
147
            }
148
        }
149

150
        // 2. 统一校验
151
        $validator = wei()->validate([
×
152
            'data' => $data,
×
153
            'rules' => [
154
                'email' => [
155
                    'required' => false,
156
                    'email' => true,
157
                    'notRecordExists' => ['user', 'email'],
158
                ],
159
                'password' => [
160
                    'minLength' => 6,
161
                ],
162
                'passwordConfirm' => [
163
                    'equalTo' => $data['password'],
×
164
                ],
165
            ],
166
            'names' => [
167
                'email' => '邮箱',
168
                'password' => '密码',
169
            ],
170
            'messages' => [
171
                'passwordConfirm' => [
172
                    'required' => '请再次输入密码',
173
                    'equalTo' => '两次输入的密码不相等',
174
                ],
175
            ],
176
        ]);
177
        if (!$validator->isValid()) {
×
178
            return ['code' => -7, 'message' => $validator->getFirstMessage()];
×
179
        }
180

181
        if ($data['mobile']) {
×
182
            $user = wei()->user()->mobileVerified()->find(['mobile' => $data['mobile']]);
×
183
            if ($user) {
×
184
                return ['code' => -8, 'message' => '手机号码已存在'];
×
185
            }
186
        }
187

188
        $ret = $this->event->until('userRegisterValidate', [$this]);
×
189
        if ($ret) {
×
190
            return $ret;
×
191
        }
192

193
        // 3. 保存到数据库
194
        $this->setPlainPassword($data['password']);
×
195

196
        if ($data['mobile']) {
×
197
            $this->setMobileVerified();
×
198
        }
199

200
        $this->save([
×
201
            'email' => (string) $data['email'],
×
202
            'mobile' => (string) $data['mobile'],
×
203
            'username' => (string) $data['username'],
×
204
            'source' => isset($data['source']) ? $data['source'] : '',
×
205
        ]);
206

207
        return ['code' => 1, 'message' => '注册成功'];
×
208
    }
209

210
    public function isMobileExists($mobile)
211
    {
212
        return (bool) wei()->userModel()
×
213
            ->where('mobile', $mobile)
×
214
            ->where('id', '!=', $this->id)
×
215
            ->fetchColumn();
×
216
    }
217

218
    /**
219
     * QueryBuilder: 查询手机号码验证过
220
     *
221
     * @return $this
222
     */
223
    public function mobileVerified()
224
    {
225
        return $this->where('mobile_verified_at', '!=', '0000-00-00 00:00:00');
9✔
226
    }
227

228
    /**
229
     * @param bool $verified
230
     * @return $this
231
     */
232
    public function setMobileVerified($verified = true)
233
    {
234
        $this->mobileVerifiedAt = $verified ? Time::now() : null;
12✔
235
        return $this;
12✔
236
    }
237

238
    public function updateMobileIfVerified($save = true, $req = null)
239
    {
240
        $req || $req = $this->req;
×
241

242
        // 未校验,或者是输入了新手机,需要校验
243
        if (
244
            !$this->isMobileVerified()
×
245
            || $this['mobile'] != $req['mobile']
×
246
        ) {
247
            $ret = $this->checkMobile($req['mobile']);
×
248
            if (1 !== $ret['code']) {
×
249
                return $ret;
×
250
            }
251

252
            if (!$req['verifyCode']) {
×
253
                return $this->err('验证码不能为空');
×
254
            }
255

256
            $ret = wei()->verifyCode->check($req['mobile'], $req['verifyCode']);
×
257
            if (1 !== $ret['code']) {
×
258
                return $ret + ['verifyCodeErr' => true];
×
259
            }
260
        }
261

262
        if ($this['mobile'] == $req['mobile']) {
×
263
            return $this->suc(['changed' => false]);
×
264
        }
265

266
        $this['mobile'] = $req['mobile'];
×
267
        $this->setMobileVerified();
×
268
        if ($save) {
×
269
            $this->save();
×
270
        }
271
        return $this->suc(['changed' => true]);
×
272
    }
273

274
    /**
275
     * Repo: 记录用户操作日志
276
     *
277
     * @param string $action
278
     * @param array $data
279
     * @return $this
280
     */
281
    public function log($action, array $data)
282
    {
283
        /** @phpstan-ignore-next-line */
284
        $user = User::cur();
×
285
        $app = wei()->app;
×
286

287
        if (isset($data['param']) && is_array($data['param'])) {
×
288
            $data['param'] = json_encode($data['param'], \JSON_UNESCAPED_UNICODE);
×
289
        }
290

291
        if (isset($data['ret']) && is_array($data['ret'])) {
×
292
            $data['ret'] = json_encode($data['ret'], \JSON_UNESCAPED_UNICODE);
×
293
        }
294

295
        wei()->db->insert('userLogs', $data + [
×
296
                'appId' => $app->getId(),
×
297
                'userId' => $user->id,
×
298
                'nickName' => $user->nickName,
×
299
                'page' => $app->getControllerAction(),
×
300
                'action' => $action,
×
301
                'createTime' => date('Y-m-d H:i:s'),
×
302
            ]);
303

304
        return $this;
×
305
    }
306

307
    public function getTags()
308
    {
309
        $userTags = wei()->userTag->getAll();
×
310
        $tags = [];
×
311
        $relations = wei()->userTagsUserModel()->asc('id')->findAll(['user_id' => $this['id']]);
×
312
        foreach ($relations as $relation) {
×
313
            $tags[] = $userTags[$relation->tagId];
×
314
        }
315
        return $tags;
×
316
    }
317

318
    public function getIsMobileVerifiedAttribute()
319
    {
320
        return (bool) $this->mobileVerifiedAt;
18✔
321
    }
322

323
    public function setIsMobileVerifiedAttribute()
324
    {
325
        // do nothing
UNCOV
326
    }
×
327

328
    public function getAvatarAttribute()
329
    {
330
        return (isset($this->attributes['avatar']) && $this->attributes['avatar']) ?
21✔
331
            $this->attributes['avatar'] : $this->user->defaultAvatar;
21✔
332
    }
333

334
    /**
335
     * QueryBuilder:
336
     *
337
     * @return \Miaoxing\Plugin\Service\UserModel
338
     */
339
    public function valid()
340
    {
341
        return $this->where(['isValid' => 1]);
×
342
    }
343

344
    /**
345
     * Record: 检查指定的手机号码能否绑定当前用户
346
     *
347
     * @param string $mobile
348
     * @return Ret
349
     * @svc
350
     */
351
    protected function checkMobile(string $mobile)
352
    {
353
        if (!$mobile) {
9✔
354
            return err('手机不能为空');
×
355
        }
356

357
        // 1. 检查是否已存在认证该手机号码的用户
358
        $mobileUser = self::new()->mobileVerified()->findBy('mobile', $mobile);
9✔
359
        if ($mobileUser && $mobileUser['id'] != $this['id']) {
9✔
360
            return err('已存在认证该手机号码的用户');
6✔
361
        }
362

363
        // 2. 提供接口供外部检查手机号
364
        $ret = $this->event->until('userCheckMobile', [$this, $mobile]);
6✔
365
        if ($ret) {
6✔
366
            return $ret;
×
367
        }
368

369
        return suc('手机号码可以绑定');
6✔
370
    }
371

372
    /**
373
     * Record: 绑定手机
374
     *
375
     * @param array|\ArrayAccess $data
376
     * @return array
377
     * @svc
378
     */
379
    protected function bindMobile($data)
380
    {
381
        // 1. 校验数据
382
        $ret = $this->checkMobile($data['mobile']);
×
383
        if (1 !== $ret['code']) {
×
384
            return $ret;
×
385
        }
386

387
        // 2. 校验验证码
388
        $ret = wei()->verifyCode->check($data['mobile'], $data['verifyCode']);
×
389
        if (1 !== $ret['code']) {
×
390
            return $ret + ['verifyCodeErr' => true];
×
391
        }
392

393
        // 3. 记录手机信息
394
        $this['mobile'] = $data['mobile'];
×
395
        $this->setMobileVerified();
×
396

397
        $this->event->trigger('preUserMobileVerify', [$data, $this]);
×
398

399
        $this->save();
×
400

401
        return $this->suc('绑定成功');
×
402
    }
403

404
    /**
405
     * Record: 更新当前用户资料
406
     *
407
     * @param array|\ArrayAccess $data
408
     * @return array
409
     * @svc
410
     */
411
    protected function updateData($data)
412
    {
413
        $isMobileVerified = $this->isMobileVerified();
×
414

415
        $validator = wei()->validate([
×
416
            'data' => $data,
×
417
            'rules' => [
418
                'mobile' => [
419
                    'required' => !$isMobileVerified,
×
420
                    'mobileCn' => true,
421
                ],
422
                'name' => [
423
                    'required' => false,
424
                ],
425
                'address' => [
426
                    'required' => false,
427
                    'minLength' => 3,
428
                ],
429
            ],
430
            'names' => [
431
                'mobile' => '手机号码',
432
                'name' => '姓名',
433
                'address' => '详细地址',
434
            ],
435
        ]);
436
        if (!$validator->isValid()) {
×
437
            return $this->err($validator->getFirstMessage());
×
438
        }
439

440
        if (!$isMobileVerified) {
×
441
            // 手机号未认证时,检查手机号,根据配置检查是否重复
442
            if (wei()->user->checkMobileUnique && $this->isMobileExists($data['mobile'])) {
×
443
                return $this->err('手机号码已存在');
×
444
            }
445
            $this['mobile'] = $data['mobile'];
×
446
        }
447

448
        $result = $this->event->until('preUserUpdate', [$data, $this]);
×
449
        if ($result) {
×
450
            return $result;
×
451
        }
452

453
        $this->save([
×
454
            'name' => $data['name'],
×
455
            'address' => $data['address'],
×
456
        ]);
457

458
        return $this->suc();
×
459
    }
460
}
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