Completed
Push — 6.0 ( aafdeb...540bb9 )
by liu
03:05
created

Model::__set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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
     * @return $this
276
     */
277
    public function setQuery(Query $query)
278
    {
279
        $this->queryInstance = clone $query;
280
        return $this;
281
    }
282
283
    /**
284
     * 设置当前模型数据表的后缀
285
     * @access public
286
     * @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...
287
     * @return $this
288
     */
289
    public function setSuffix(string $suffix)
290
    {
291
        $this->suffix = $suffix;
292
        return $this;
293
    }
294
295
    /**
296
     * 获取当前模型的数据表后缀
297
     * @access public
298
     * @return string
299
     */
300
    public function getSuffix(): string
301
    {
302
        return $this->suffix ?: '';
303
    }
304
305
    /**
306
     * 获取当前模型的数据库查询对象
307
     * @access public
308
     * @param array|false $scope 使用的全局查询范围
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
309
     * @return Query
310
     */
311
    public function db($scope = []): Query
312
    {
313
        /** @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...
314
        if ($this->queryInstance) {
315
            $query = $this->queryInstance->removeOption();
316
        } else {
317
            $query = $this->db->buildQuery($this->connection)
318
                ->name($this->name . $this->suffix)
319
                ->pk($this->pk);
320
        }
321
322
        $query->model($this)
323
            ->json($this->json, $this->jsonAssoc)
324
            ->setFieldType(array_merge($this->schema, $this->jsonType));
325
326
        if (!empty($this->table)) {
327
            $query->table($this->table . $this->suffix);
328
        }
329
330
        // 软删除
331
        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...
332
            $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

332
            $this->/** @scrutinizer ignore-call */ 
333
                   withNoTrashed($query);
Loading history...
333
        }
334
335
        // 全局作用域
336
        $globalScope = is_array($scope) && !empty($scope) ? $scope : $this->globalScope;
337
338
        if (!empty($globalScope) && false !== $scope) {
339
            $query->scope($globalScope);
340
        }
341
342
        // 返回当前模型的数据库查询对象
343
        return $query;
344
    }
345
346
    /**
347
     *  初始化模型
348
     * @access private
349
     * @return void
350
     */
351
    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...
352
    {
353
        if (!isset(static::$initialized[static::class])) {
354
            static::$initialized[static::class] = true;
355
            static::init();
356
        }
357
    }
358
359
    /**
360
     * 初始化处理
361
     * @access protected
362
     * @return void
363
     */
364
    protected static function init()
365
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
366
367
    protected function checkData(): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function checkData()
Loading history...
368
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
369
370
    protected function checkResult($result): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function checkResult()
Loading history...
371
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
372
373
    /**
374
     * 更新是否强制写入数据 而不做比较
375
     * @access public
376
     * @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...
377
     * @return $this
378
     */
379
    public function force(bool $force = true)
380
    {
381
        $this->force = $force;
382
        return $this;
383
    }
384
385
    /**
386
     * 判断force
387
     * @access public
388
     * @return bool
389
     */
390
    public function isForce(): bool
391
    {
392
        return $this->force;
393
    }
394
395
    /**
396
     * 新增数据是否使用Replace
397
     * @access public
398
     * @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...
399
     * @return $this
400
     */
401
    public function replace(bool $replace = true)
402
    {
403
        $this->replace = $replace;
404
        return $this;
405
    }
406
407
    /**
408
     * 刷新模型数据
409
     * @access public
410
     * @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...
411
     * @return $this
412
     */
413
    public function refresh(bool $relation = false)
414
    {
415
        if ($this->exists) {
416
            $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...
417
            $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...
418
419
            if ($relation) {
420
                $this->relation = [];
421
            }
422
        }
423
424
        return $this;
425
    }
426
427
    /**
428
     * 设置数据是否存在
429
     * @access public
430
     * @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...
431
     * @return $this
432
     */
433
    public function exists(bool $exists = true)
434
    {
435
        $this->exists = $exists;
436
        return $this;
437
    }
438
439
    /**
440
     * 判断数据是否存在数据库
441
     * @access public
442
     * @return bool
443
     */
444
    public function isExists(): bool
445
    {
446
        return $this->exists;
447
    }
448
449
    /**
450
     * 判断模型是否为空
451
     * @access public
452
     * @return bool
453
     */
454
    public function isEmpty(): bool
455
    {
456
        return empty($this->data);
457
    }
458
459
    /**
460
     * 延迟保存当前数据对象
461
     * @access public
462
     * @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...
463
     * @return void
464
     */
465
    public function lazySave($data = []): void
466
    {
467
        if (false === $data) {
468
            $this->lazySave = false;
469
        } else {
470
            if (is_array($data)) {
471
                $this->setAttrs($data);
472
            }
473
474
            $this->lazySave = true;
475
        }
476
    }
477
478
    /**
479
     * 保存当前数据对象
480
     * @access public
481
     * @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...
482
     * @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...
483
     * @return bool
484
     */
485
    public function save(array $data = [], string $sequence = null): bool
486
    {
487
        // 数据对象赋值
488
        $this->setAttrs($data);
489
490
        if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {
491
            return false;
492
        }
493
494
        $result = $this->exists ? $this->updateData() : $this->insertData($sequence);
495
496
        if (false === $result) {
497
            return false;
498
        }
499
500
        // 写入回调
501
        $this->trigger('AfterWrite');
502
503
        // 重新记录原始数据
504
        $this->origin   = $this->data;
505
        $this->set      = [];
506
        $this->lazySave = false;
507
508
        return true;
509
    }
510
511
    /**
512
     * 检查数据是否允许写入
513
     * @access protected
514
     * @return array
515
     */
516
    protected function checkAllowFields(): array
517
    {
518
        // 检测字段
519
        if (empty($this->field)) {
520
            if (!empty($this->schema)) {
521
                $this->field = array_keys(array_merge($this->schema, $this->jsonType));
522
            } else {
523
                $query = $this->db();
524
                $table = $this->table ? $this->table . $this->suffix : $query->getTable();
525
526
                $this->field = $query->getConnection()->getTableFields($table);
527
            }
528
529
            return $this->field;
530
        }
531
532
        $field = $this->field;
533
534
        if ($this->autoWriteTimestamp) {
535
            array_push($field, $this->createTime, $this->updateTime);
536
        }
537
538
        if (!empty($this->disuse)) {
539
            // 废弃字段
540
            $field = array_diff($field, $this->disuse);
541
        }
542
543
        return $field;
544
    }
545
546
    /**
547
     * 保存写入数据
548
     * @access protected
549
     * @return bool
550
     */
551
    protected function updateData(): bool
552
    {
553
        // 事件回调
554
        if (false === $this->trigger('BeforeUpdate')) {
555
            return false;
556
        }
557
558
        $this->checkData();
559
560
        // 获取有更新的数据
561
        $data = $this->getChangedData();
562
563
        if (empty($data)) {
564
            // 关联更新
565
            if (!empty($this->relationWrite)) {
566
                $this->autoRelationUpdate();
567
            }
568
569
            return true;
570
        }
571
572
        if ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
573
            // 自动写入更新时间
574
            $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

574
            $data[$this->updateTime]       = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->updateTime);
Loading history...
575
            $this->data[$this->updateTime] = $data[$this->updateTime];
576
        }
577
578
        // 检查允许字段
579
        $allowFields = $this->checkAllowFields();
580
581
        foreach ($this->relationWrite as $name => $val) {
582
            if (!is_array($val)) {
583
                continue;
584
            }
585
586
            foreach ($val as $key) {
587
                if (isset($data[$key])) {
588
                    unset($data[$key]);
589
                }
590
            }
591
        }
592
593
        // 模型更新
594
        $db = $this->db();
595
        $db->startTrans();
596
597
        try {
598
            $where  = $this->getWhere();
599
            $result = $db->where($where)
600
                ->strict(false)
601
                ->field($allowFields)
602
                ->update($data);
603
604
            $this->checkResult($result);
605
606
            // 关联更新
607
            if (!empty($this->relationWrite)) {
608
                $this->autoRelationUpdate();
609
            }
610
611
            $db->commit();
612
613
            // 更新回调
614
            $this->trigger('AfterUpdate');
615
616
            return true;
617
        } catch (\Exception $e) {
618
            $db->rollback();
619
            throw $e;
620
        }
621
    }
622
623
    /**
624
     * 新增写入数据
625
     * @access protected
626
     * @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...
627
     * @return bool
628
     */
629
    protected function insertData(string $sequence = null): bool
630
    {
631
        // 时间戳自动写入
632
        if ($this->autoWriteTimestamp) {
633
            if ($this->createTime && !isset($this->data[$this->createTime])) {
634
                $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

634
                $this->data[$this->createTime] = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->createTime);
Loading history...
635
            }
636
637
            if ($this->updateTime && !isset($this->data[$this->updateTime])) {
638
                $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
639
            }
640
        }
641
642
        if (false === $this->trigger('BeforeInsert')) {
643
            return false;
644
        }
645
646
        $this->checkData();
647
648
        // 检查允许字段
649
        $allowFields = $this->checkAllowFields();
650
651
        $db = $this->db();
652
        $db->startTrans();
653
654
        try {
655
            $result = $db->strict(false)
656
                ->field($allowFields)
657
                ->replace($this->replace)
658
                ->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

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