Completed
Push — 6.0 ( 41214e...845f81 )
by liu
06:11 queued 01:15
created

Model   F

Complexity

Total Complexity 130

Size/Duplication

Total Lines 983
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 278
dl 0
loc 983
ccs 0
cts 314
cp 0
rs 2
c 0
b 0
f 0
wmc 130

51 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 28 6
A getName() 0 3 1
A maker() 0 3 1
A newInstance() 0 12 2
A setDb() 0 3 1
A getConnection() 0 3 1
A setConnection() 0 3 1
A setEvent() 0 3 1
A setUpdateWhere() 0 3 1
A setQuery() 0 9 2
A isForce() 0 3 1
A offsetSet() 0 3 1
A __destruct() 0 4 2
A save() 0 24 5
A setSuffix() 0 4 1
A __unset() 0 3 1
A isExists() 0 3 1
A __callStatic() 0 5 1
B saveAll() 0 28 8
A force() 0 4 1
A db() 0 32 6
A isEmpty() 0 3 1
A withoutGlobalScope() 0 5 1
A suffix() 0 6 1
A exists() 0 4 1
C updateData() 0 69 13
A initialize() 0 5 2
A __isset() 0 3 1
A __wakeup() 0 3 1
A getSuffix() 0 3 2
A getQuery() 0 3 1
A offsetGet() 0 3 1
A refresh() 0 12 3
B destroy() 0 25 7
A replace() 0 4 1
A checkResult() 0 2 1
A __debugInfo() 0 9 2
A delete() 0 32 6
C insertData() 0 57 14
A __get() 0 3 1
A create() 0 11 2
A __set() 0 3 1
A offsetExists() 0 3 1
A init() 0 2 1
A checkData() 0 2 1
A lazySave() 0 10 3
A __call() 0 7 2
A checkAllowFields() 0 28 6
A offsetUnset() 0 3 1
A getWhere() 0 13 4
A update() 0 15 3

How to fix   Complexity   

Complex Class

Complex classes like Model often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Model, and based on these observations, apply Extract Interface, too.

1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use ArrayAccess;
16
use Closure;
17
use JsonSerializable;
18
use think\db\Query;
19
20
/**
21
 * Class Model
22
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
23
 * @mixin Query
1 ignored issue
show
Coding Style introduced by
Tag value for @mixin tag indented incorrectly; expected 3 spaces but found 1
Loading history...
24
 * @method void onAfterRead(Model $model) static after_read事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
25
 * @method mixed onBeforeInsert(Model $model) static before_insert事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
26
 * @method void onAfterInsert(Model $model) static after_insert事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
27
 * @method mixed onBeforeUpdate(Model $model) static before_update事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
28
 * @method void onAfterUpdate(Model $model) static after_update事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
29
 * @method mixed onBeforeWrite(Model $model) static before_write事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
30
 * @method void onAfterWrite(Model $model) static after_write事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
31
 * @method mixed onBeforeDelete(Model $model) static before_write事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
32
 * @method void onAfterDelete(Model $model) static after_delete事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
33
 * @method void onBeforeRestore(Model $model) static before_restore事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
34
 * @method void onAfterRestore(Model $model) static after_restore事件定义
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
35
 */
4 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
36
abstract class Model implements JsonSerializable, ArrayAccess
37
{
38
    use model\concern\Attribute;
39
    use model\concern\RelationShip;
40
    use model\concern\ModelEvent;
41
    use model\concern\TimeStamp;
42
    use model\concern\Conversion;
43
44
    /**
45
     * 数据是否存在
46
     * @var bool
47
     */
48
    private $exists = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "exists" must be prefixed with an underscore
Loading history...
49
50
    /**
51
     * 是否强制更新所有数据
52
     * @var bool
53
     */
54
    private $force = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "force" must be prefixed with an underscore
Loading history...
55
56
    /**
57
     * 是否Replace
58
     * @var bool
59
     */
60
    private $replace = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "replace" must be prefixed with an underscore
Loading history...
61
62
    /**
63
     * 数据表后缀
64
     * @var string
65
     */
66
    protected $suffix;
67
68
    /**
69
     * 更新条件
70
     * @var array
71
     */
72
    private $updateWhere;
0 ignored issues
show
Coding Style introduced by
Private member variable "updateWhere" must be prefixed with an underscore
Loading history...
73
74
    /**
75
     * 数据库配置
76
     * @var string
77
     */
78
    protected $connection;
79
80
    /**
81
     * 模型名称
82
     * @var string
83
     */
84
    protected $name;
85
86
    /**
87
     * 数据表名称
88
     * @var string
89
     */
90
    protected $table;
91
92
    /**
93
     * 初始化过的模型.
94
     * @var array
95
     */
96
    protected static $initialized = [];
97
98
    /**
99
     * 查询对象实例
100
     * @var Query
101
     */
102
    protected $queryInstance;
103
104
    /**
105
     * 软删除字段默认值
106
     * @var mixed
107
     */
108
    protected $defaultSoftDelete;
109
110
    /**
111
     * 全局查询范围
112
     * @var array
113
     */
114
    protected $globalScope = [];
115
116
    /**
117
     * 延迟保存信息
118
     * @var bool
119
     */
120
    private $lazySave = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "lazySave" must be prefixed with an underscore
Loading history...
121
122
    /**
123
     * Db对象
124
     * @var Db
125
     */
126
    protected $db;
127
128
    /**
129
     * Event对象
130
     * @var Event
131
     */
132
    protected $event;
133
134
    /**
135
     * 服务注入
136
     * @var Closure
137
     */
138
    protected static $maker;
139
140
    /**
141
     * 设置服务注入
142
     * @access public
143
     * @param Closure $maker
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
144
     * @return void
145
     */
146
    public static function maker(Closure $maker)
147
    {
148
        static::$maker = $maker;
149
    }
150
151
    /**
152
     * 设置Db对象
153
     * @access public
154
     * @param Db $db Db对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
155
     * @return void
156
     */
157
    public function setDb(Db $db)
158
    {
159
        $this->db = $db;
160
    }
161
162
    /**
163
     * 设置Event对象
164
     * @access public
165
     * @param Event $event Event对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
166
     * @return void
167
     */
168
    public function setEvent(Event $event)
169
    {
170
        $this->event = $event;
171
    }
172
173
    /**
174
     * 设置Connection信息
175
     * @access public
176
     * @param mixed $connection 数据库配置
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
177
     * @return void
178
     */
179
    public function setConnection($connection)
180
    {
181
        $this->connection = $connection;
182
    }
183
184
    /**
185
     * 获取Connection信息
186
     * @access public
187
     * @return string|array
188
     */
189
    public function getConnection()
190
    {
191
        return $this->connection;
192
    }
193
194
    /**
195
     * 架构函数
196
     * @access public
197
     * @param array $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
198
     */
199
    public function __construct(array $data = [])
200
    {
201
        $this->data = $data;
202
203
        if (!empty($this->data)) {
204
            // 废弃字段
205
            foreach ((array) $this->disuse as $key) {
206
                if (array_key_exists($key, $this->data)) {
207
                    unset($this->data[$key]);
208
                }
209
            }
210
        }
211
212
        // 记录原始数据
213
        $this->origin = $this->data;
214
215
        if (empty($this->name)) {
216
            // 当前模型名
217
            $name       = str_replace('\\', '/', static::class);
218
            $this->name = basename($name);
219
        }
220
221
        if (static::$maker) {
222
            call_user_func(static::$maker, $this);
223
        }
224
225
        // 执行初始化操作
226
        $this->initialize();
227
    }
228
229
    /**
230
     * 获取当前模型名称
231
     * @access public
232
     * @return string
233
     */
234
    public function getName(): string
235
    {
236
        return $this->name;
237
    }
238
239
    /**
240
     * 创建新的模型实例
241
     * @access public
242
     * @param array $data  数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
243
     * @param mixed $where 更新条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
244
     * @return Model
245
     */
246
    public function newInstance(array $data = [], $where = null): Model
247
    {
248
        if (empty($data)) {
249
            return new static();
250
        }
251
252
        $model = (new static($data))->exists(true);
253
        $model->setUpdateWhere($where);
254
255
        $model->trigger('AfterRead');
256
257
        return $model;
258
    }
259
260
    /**
261
     * 设置模型的更新条件
262
     * @access protected
263
     * @param mixed $where 更新条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
264
     * @return void
265
     */
266
    protected function setUpdateWhere($where): void
267
    {
268
        $this->updateWhere = $where;
269
    }
270
271
    /**
272
     * 设置当前模型的数据库查询对象
273
     * @access public
274
     * @param Query $query 查询对象实例
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
275
     * @param bool  $clear 是否需要清空查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
276
     * @return $this
277
     */
278
    public function setQuery(Query $query, bool $clear = true)
279
    {
280
        $this->queryInstance = clone $query;
281
282
        if ($clear) {
283
            $this->queryInstance->removeOption();
284
        }
285
286
        return $this;
287
    }
288
289
    /**
290
     * 获取当前模型的数据库查询对象
291
     * @access public
292
     * @return Query|null
293
     */
294
    public function getQuery()
295
    {
296
        return $this->queryInstance;
297
    }
298
299
    /**
300
     * 设置当前模型数据表的后缀
301
     * @access public
302
     * @param string $suffix 数据表后缀
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
303
     * @return $this
304
     */
305
    public function setSuffix(string $suffix)
306
    {
307
        $this->suffix = $suffix;
308
        return $this;
309
    }
310
311
    /**
312
     * 获取当前模型的数据表后缀
313
     * @access public
314
     * @return string
315
     */
316
    public function getSuffix(): string
317
    {
318
        return $this->suffix ?: '';
319
    }
320
321
    /**
322
     * 获取当前模型的数据库查询对象
323
     * @access public
324
     * @param array $scope 设置不使用的全局查询范围
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
325
     * @return Query
326
     */
327
    public function db($scope = []): Query
328
    {
329
        /** @var Query $query */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
330
        if ($this->queryInstance) {
331
            $query = $this->queryInstance;
332
        } else {
333
            $query = $this->db->buildQuery($this->connection)
334
                ->name($this->name . $this->suffix)
335
                ->pk($this->pk);
336
337
            if (!empty($this->table)) {
338
                $query->table($this->table . $this->suffix);
339
            }
340
        }
341
342
        $query->model($this)
343
            ->json($this->json, $this->jsonAssoc)
344
            ->setFieldType(array_merge($this->schema, $this->jsonType));
345
346
        // 软删除
347
        if (property_exists($this, 'withTrashed') && !$this->withTrashed) {
0 ignored issues
show
Bug Best Practice introduced by
The property withTrashed does not exist on think\Model. Since you implemented __get, consider adding a @property annotation.
Loading history...
348
            $this->withNoTrashed($query);
0 ignored issues
show
Bug introduced by
The method withNoTrashed() does not exist on think\Model. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

348
            $this->/** @scrutinizer ignore-call */ 
349
                   withNoTrashed($query);
Loading history...
349
        }
350
351
        // 全局作用域
352
        if (is_array($scope)) {
0 ignored issues
show
introduced by
The condition is_array($scope) is always true.
Loading history...
353
            $globalScope = array_diff($this->globalScope, $scope);
354
            $query->scope($globalScope);
355
        }
356
357
        // 返回当前模型的数据库查询对象
358
        return $query;
359
    }
360
361
    /**
362
     *  初始化模型
363
     * @access private
364
     * @return void
365
     */
366
    private function initialize(): void
0 ignored issues
show
Coding Style introduced by
Private method name "Model::initialize" must be prefixed with an underscore
Loading history...
367
    {
368
        if (!isset(static::$initialized[static::class])) {
369
            static::$initialized[static::class] = true;
370
            static::init();
371
        }
372
    }
373
374
    /**
375
     * 初始化处理
376
     * @access protected
377
     * @return void
378
     */
379
    protected static function init()
380
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
381
382
    protected function checkData(): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function checkData()
Loading history...
383
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
384
385
    protected function checkResult($result): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function checkResult()
Loading history...
386
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
387
388
    /**
389
     * 更新是否强制写入数据 而不做比较
390
     * @access public
391
     * @param bool $force
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
392
     * @return $this
393
     */
394
    public function force(bool $force = true)
395
    {
396
        $this->force = $force;
397
        return $this;
398
    }
399
400
    /**
401
     * 判断force
402
     * @access public
403
     * @return bool
404
     */
405
    public function isForce(): bool
406
    {
407
        return $this->force;
408
    }
409
410
    /**
411
     * 新增数据是否使用Replace
412
     * @access public
413
     * @param bool $replace
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
414
     * @return $this
415
     */
416
    public function replace(bool $replace = true)
417
    {
418
        $this->replace = $replace;
419
        return $this;
420
    }
421
422
    /**
423
     * 刷新模型数据
424
     * @access public
425
     * @param bool $relation 是否刷新关联数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
426
     * @return $this
427
     */
428
    public function refresh(bool $relation = false)
429
    {
430
        if ($this->exists) {
431
            $this->data   = $this->db()->fetchArray()->find($this->getKey());
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db()->fetchArray()->find($this->getKey()) of type think\Model is incompatible with the declared type array of property $data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
432
            $this->origin = $this->data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->data of type think\Model is incompatible with the declared type array of property $origin.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
433
434
            if ($relation) {
435
                $this->relation = [];
436
            }
437
        }
438
439
        return $this;
440
    }
441
442
    /**
443
     * 设置数据是否存在
444
     * @access public
445
     * @param bool $exists
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
446
     * @return $this
447
     */
448
    public function exists(bool $exists = true)
449
    {
450
        $this->exists = $exists;
451
        return $this;
452
    }
453
454
    /**
455
     * 判断数据是否存在数据库
456
     * @access public
457
     * @return bool
458
     */
459
    public function isExists(): bool
460
    {
461
        return $this->exists;
462
    }
463
464
    /**
465
     * 判断模型是否为空
466
     * @access public
467
     * @return bool
468
     */
469
    public function isEmpty(): bool
470
    {
471
        return empty($this->data);
472
    }
473
474
    /**
475
     * 延迟保存当前数据对象
476
     * @access public
477
     * @param array|bool $data 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
478
     * @return void
479
     */
480
    public function lazySave($data = []): void
481
    {
482
        if (false === $data) {
483
            $this->lazySave = false;
484
        } else {
485
            if (is_array($data)) {
486
                $this->setAttrs($data);
487
            }
488
489
            $this->lazySave = true;
490
        }
491
    }
492
493
    /**
494
     * 保存当前数据对象
495
     * @access public
496
     * @param array  $data     数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
497
     * @param string $sequence 自增序列名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
498
     * @return bool
499
     */
500
    public function save(array $data = [], string $sequence = null): bool
501
    {
502
        // 数据对象赋值
503
        $this->setAttrs($data);
504
505
        if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {
506
            return false;
507
        }
508
509
        $result = $this->exists ? $this->updateData() : $this->insertData($sequence);
510
511
        if (false === $result) {
512
            return false;
513
        }
514
515
        // 写入回调
516
        $this->trigger('AfterWrite');
517
518
        // 重新记录原始数据
519
        $this->origin   = $this->data;
520
        $this->set      = [];
521
        $this->lazySave = false;
522
523
        return true;
524
    }
525
526
    /**
527
     * 检查数据是否允许写入
528
     * @access protected
529
     * @return array
530
     */
531
    protected function checkAllowFields(): array
532
    {
533
        // 检测字段
534
        if (empty($this->field)) {
535
            if (!empty($this->schema)) {
536
                $this->field = array_keys(array_merge($this->schema, $this->jsonType));
537
            } else {
538
                $query = $this->db();
539
                $table = $this->table ? $this->table . $this->suffix : $query->getTable();
540
541
                $this->field = $query->getConnection()->getTableFields($table);
542
            }
543
544
            return $this->field;
545
        }
546
547
        $field = $this->field;
548
549
        if ($this->autoWriteTimestamp) {
550
            array_push($field, $this->createTime, $this->updateTime);
551
        }
552
553
        if (!empty($this->disuse)) {
554
            // 废弃字段
555
            $field = array_diff($field, $this->disuse);
556
        }
557
558
        return $field;
559
    }
560
561
    /**
562
     * 保存写入数据
563
     * @access protected
564
     * @return bool
565
     */
566
    protected function updateData(): bool
567
    {
568
        // 事件回调
569
        if (false === $this->trigger('BeforeUpdate')) {
570
            return false;
571
        }
572
573
        $this->checkData();
574
575
        // 获取有更新的数据
576
        $data = $this->getChangedData();
577
578
        if (empty($data)) {
579
            // 关联更新
580
            if (!empty($this->relationWrite)) {
581
                $this->autoRelationUpdate();
582
            }
583
584
            return true;
585
        }
586
587
        if ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
588
            // 自动写入更新时间
589
            $data[$this->updateTime]       = $this->autoWriteTimestamp($this->updateTime);
0 ignored issues
show
Bug introduced by
It seems like $this->updateTime can also be of type true; however, parameter $name of think\Model::autoWriteTimestamp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

589
            $data[$this->updateTime]       = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->updateTime);
Loading history...
590
            $this->data[$this->updateTime] = $data[$this->updateTime];
591
        }
592
593
        // 检查允许字段
594
        $allowFields = $this->checkAllowFields();
595
596
        foreach ($this->relationWrite as $name => $val) {
597
            if (!is_array($val)) {
598
                continue;
599
            }
600
601
            foreach ($val as $key) {
602
                if (isset($data[$key])) {
603
                    unset($data[$key]);
604
                }
605
            }
606
        }
607
608
        // 模型更新
609
        $db = $this->db();
610
        $db->startTrans();
611
612
        try {
613
            $where  = $this->getWhere();
614
            $result = $db->where($where)
615
                ->strict(false)
616
                ->field($allowFields)
617
                ->update($data);
618
619
            $this->checkResult($result);
620
621
            // 关联更新
622
            if (!empty($this->relationWrite)) {
623
                $this->autoRelationUpdate();
624
            }
625
626
            $db->commit();
627
628
            // 更新回调
629
            $this->trigger('AfterUpdate');
630
631
            return true;
632
        } catch (\Exception $e) {
633
            $db->rollback();
634
            throw $e;
635
        }
636
    }
637
638
    /**
639
     * 新增写入数据
640
     * @access protected
641
     * @param string $sequence 自增名
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
642
     * @return bool
643
     */
644
    protected function insertData(string $sequence = null): bool
645
    {
646
        // 时间戳自动写入
647
        if ($this->autoWriteTimestamp) {
648
            if ($this->createTime && !isset($this->data[$this->createTime])) {
649
                $this->data[$this->createTime] = $this->autoWriteTimestamp($this->createTime);
0 ignored issues
show
Bug introduced by
It seems like $this->createTime can also be of type true; however, parameter $name of think\Model::autoWriteTimestamp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

649
                $this->data[$this->createTime] = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->createTime);
Loading history...
650
            }
651
652
            if ($this->updateTime && !isset($this->data[$this->updateTime])) {
653
                $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
654
            }
655
        }
656
657
        if (false === $this->trigger('BeforeInsert')) {
658
            return false;
659
        }
660
661
        $this->checkData();
662
663
        // 检查允许字段
664
        $allowFields = $this->checkAllowFields();
665
666
        $db = $this->db();
667
        $db->startTrans();
668
669
        try {
670
            $result = $db->strict(false)
671
                ->field($allowFields)
672
                ->replace($this->replace)
673
                ->insert($this->data, false, $sequence);
0 ignored issues
show
Unused Code introduced by
The call to think\db\Query::insert() has too many arguments starting with $sequence. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

673
                ->/** @scrutinizer ignore-call */ insert($this->data, false, $sequence);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
674
675
            // 获取自动增长主键
676
            if ($result && $insertId = $db->getLastInsID($sequence)) {
677
                $pk = $this->getPk();
678
679
                if (is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {
680
                    $this->data[$pk] = $insertId;
681
                }
682
            }
683
684
            // 关联写入
685
            if (!empty($this->relationWrite)) {
686
                $this->autoRelationInsert();
687
            }
688
689
            $db->commit();
690
691
            // 标记数据已经存在
692
            $this->exists = true;
693
694
            // 新增回调
695
            $this->trigger('AfterInsert');
696
697
            return true;
698
        } catch (\Exception $e) {
699
            $db->rollback();
700
            throw $e;
701
        }
702
    }
703
704
    /**
705
     * 获取当前的更新条件
706
     * @access public
707
     * @return mixed
708
     */
709
    public function getWhere()
710
    {
711
        $pk = $this->getPk();
712
713
        if (is_string($pk) && isset($this->data[$pk])) {
714
            $where = [[$pk, '=', $this->data[$pk]]];
715
        } elseif (!empty($this->updateWhere)) {
716
            $where = $this->updateWhere;
717
        } else {
718
            $where = null;
719
        }
720
721
        return $where;
722
    }
723
724
    /**
725
     * 保存多个数据到当前数据对象
726
     * @access public
727
     * @param iterable $dataSet 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
728
     * @param boolean  $replace 是否自动识别更新和写入
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
729
     * @return Collection
730
     * @throws \Exception
731
     */
732
    public function saveAll(iterable $dataSet, bool $replace = true): Collection
733
    {
734
        $db = $this->db();
735
        $db->startTrans();
736
737
        try {
738
            $pk = $this->getPk();
739
740
            if (is_string($pk) && $replace) {
741
                $auto = true;
742
            }
743
744
            $result = [];
745
746
            foreach ($dataSet as $key => $data) {
747
                if ($this->exists || (!empty($auto) && isset($data[$pk]))) {
748
                    $result[$key] = self::update($data);
749
                } else {
750
                    $result[$key] = self::create($data, $this->field, $this->replace);
751
                }
752
            }
753
754
            $db->commit();
755
756
            return $this->toCollection($result);
757
        } catch (\Exception $e) {
758
            $db->rollback();
759
            throw $e;
760
        }
761
    }
762
763
    /**
764
     * 删除当前的记录
765
     * @access public
766
     * @return bool
767
     */
768
    public function delete(): bool
769
    {
770
        if (!$this->exists || $this->isEmpty() || false === $this->trigger('BeforeDelete')) {
771
            return false;
772
        }
773
774
        // 读取更新条件
775
        $where = $this->getWhere();
776
777
        $db = $this->db();
778
        $db->startTrans();
779
780
        try {
781
            // 删除当前模型数据
782
            $db->where($where)->delete();
783
784
            // 关联删除
785
            if (!empty($this->relationWrite)) {
786
                $this->autoRelationDelete();
787
            }
788
789
            $db->commit();
790
791
            $this->trigger('AfterDelete');
792
793
            $this->exists   = false;
794
            $this->lazySave = false;
795
796
            return true;
797
        } catch (\Exception $e) {
798
            $db->rollback();
799
            throw $e;
800
        }
801
    }
802
803
    /**
804
     * 写入数据
805
     * @access public
806
     * @param array $data       数据数组
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
807
     * @param array $allowField 允许字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
808
     * @param bool  $replace    使用Replace
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
809
     * @return static
810
     */
811
    public static function create(array $data, array $allowField = [], bool $replace = false): Model
812
    {
813
        $model = new static();
814
815
        if (!empty($allowField)) {
816
            $model->allowField($allowField);
817
        }
818
819
        $model->replace($replace)->save($data);
820
821
        return $model;
822
    }
823
824
    /**
825
     * 更新数据
826
     * @access public
827
     * @param array $data       数据数组
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
828
     * @param mixed $where      更新条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
829
     * @param array $allowField 允许字段
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
830
     * @return static
831
     */
832
    public static function update(array $data, $where = [], array $allowField = [])
833
    {
834
        $model = new static();
835
836
        if (!empty($allowField)) {
837
            $model->allowField($allowField);
838
        }
839
840
        if (!empty($where)) {
841
            $model->setUpdateWhere($where);
842
        }
843
844
        $model->exists(true)->save($data);
845
846
        return $model;
847
    }
848
849
    /**
850
     * 删除记录
851
     * @access public
852
     * @param mixed $data  主键列表 支持闭包查询条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
853
     * @param bool  $force 是否强制删除
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
854
     * @return bool
855
     */
856
    public static function destroy($data, bool $force = false): bool
857
    {
858
        if (empty($data) && 0 !== $data) {
859
            return false;
860
        }
861
862
        $model = new static();
863
864
        $query = $model->db();
865
866
        if (is_array($data) && key($data) !== 0) {
867
            $query->where($data);
868
            $data = null;
869
        } elseif ($data instanceof \Closure) {
870
            $data($query);
871
            $data = null;
872
        }
873
874
        $resultSet = $query->select($data);
875
876
        foreach ($resultSet as $result) {
877
            $result->force($force)->delete();
878
        }
879
880
        return true;
881
    }
882
883
    /**
884
     * 解序列化后处理
885
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
886
    public function __wakeup()
887
    {
888
        $this->initialize();
889
    }
890
891
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __debugInfo()
Loading history...
892
    {
893
        $attrs = get_object_vars($this);
894
895
        foreach (['db', 'queryInstance', 'event'] as $name) {
896
            unset($attrs[$name]);
897
        }
898
899
        return $attrs;
900
    }
901
902
    /**
903
     * 修改器 设置数据对象的值
904
     * @access public
905
     * @param string $name  名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
906
     * @param mixed  $value 值
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
907
     * @return void
908
     */
909
    public function __set(string $name, $value): void
910
    {
911
        $this->setAttr($name, $value);
912
    }
913
914
    /**
915
     * 获取器 获取数据对象的值
916
     * @access public
917
     * @param string $name 名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
918
     * @return mixed
919
     */
920
    public function __get(string $name)
921
    {
922
        return $this->getAttr($name);
923
    }
924
925
    /**
926
     * 检测数据对象的值
927
     * @access public
928
     * @param string $name 名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
929
     * @return bool
930
     */
931
    public function __isset(string $name): bool
932
    {
933
        return !is_null($this->getAttr($name));
934
    }
935
936
    /**
937
     * 销毁数据对象的值
938
     * @access public
939
     * @param string $name 名称
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
940
     * @return void
941
     */
942
    public function __unset(string $name): void
943
    {
944
        unset($this->data[$name], $this->relation[$name]);
945
    }
946
947
    // ArrayAccess
948
    public function offsetSet($name, $value)
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
949
    {
950
        $this->setAttr($name, $value);
951
    }
952
953
    public function offsetExists($name): bool
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function offsetExists()
Loading history...
954
    {
955
        return $this->__isset($name);
956
    }
957
958
    public function offsetUnset($name)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function offsetUnset()
Loading history...
959
    {
960
        $this->__unset($name);
961
    }
962
963
    public function offsetGet($name)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function offsetGet()
Loading history...
964
    {
965
        return $this->getAttr($name);
966
    }
967
968
    /**
969
     * 设置不使用的全局查询范围
970
     * @access public
971
     * @param array $scope 不启用的全局查询范围
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
972
     * @return Query
973
     */
974
    public static function withoutGlobalScope(array $scope = null)
975
    {
976
        $model = new static();
977
978
        return $model->db($scope);
979
    }
980
981
    /**
982
     * 切换后缀进行查询
983
     * @access public
984
     * @param string $suffix 切换的表后缀
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
985
     * @return Model
986
     */
987
    public static function suffix(string $suffix)
988
    {
989
        $model = new static();
990
        $model->setSuffix($suffix);
991
992
        return $model;
993
    }
994
995
    public function __call($method, $args)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __call()
Loading history...
996
    {
997
        if ('withattr' == strtolower($method)) {
998
            return call_user_func_array([$this, 'withAttribute'], $args);
999
        }
1000
1001
        return call_user_func_array([$this->db(), $method], $args);
1002
    }
1003
1004
    public static function __callStatic($method, $args)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __callStatic()
Loading history...
1005
    {
1006
        $model = new static();
1007
1008
        return call_user_func_array([$model->db(), $method], $args);
1009
    }
1010
1011
    /**
1012
     * 析构方法
1013
     * @access public
1014
     */
1015
    public function __destruct()
1016
    {
1017
        if ($this->lazySave) {
1018
            $this->save();
1019
        }
1020
    }
1021
}
1022