Completed
Push — 6.0 ( a99d0b...cc2e0b )
by liu
02:48
created

Model::isExists()   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 0
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 Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件
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 Query whereTime(string $field, string $op, mixed $range = null) static 查询日期和时间
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 Query whereBetweenTime(string $field, mixed $startTime, mixed $endTime) static 查询日期或者时间范围
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 Query whereBetweenTimeField(string $startField, string $endField) static 查询当前时间在两个时间字段范围
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 Query whereYear(string $field, string $year = 'this year') static 查询某年
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 Query whereMonth(string $field, string $month = 'this month') static 查询某月
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 Query whereDay(string $field, string $day = 'today') static 查询某日
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 Query whereRaw(string $where, array $bind = []) static 表达式查询
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 Query whereExp(string $field, string $condition, array $bind = []) static 字段表达式查询
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 Query when(mixed $condition, mixed $query, mixed $otherwise = null) static 条件查询
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 Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
35
 * @method Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
36
 * @method Query with(mixed $with) static 关联预载入
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
37
 * @method Query count(string $field) static Count统计查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
38
 * @method Query min(string $field) static Min统计查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
39
 * @method Query max(string $field) static Max统计查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
40
 * @method Query sum(string $field) static SUM统计查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
41
 * @method Query avg(string $field) static Avg统计查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
42
 * @method Query field(mixed $field, boolean $except = false) static 指定查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
43
 * @method Query fieldRaw(string $field, array $bind = []) static 指定查询字段
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
44
 * @method Query union(mixed $union, boolean $all = false) static UNION查询
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
45
 * @method Query limit(mixed $offset, integer $length = null) static 查询LIMIT
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
46
 * @method Query order(mixed $field, string $order = null) static 查询ORDER
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
47
 * @method Query orderRaw(string $field, array $bind = []) static 查询ORDER
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
48
 * @method Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
49
 * @method mixed value(string $field) static 获取某个字段的值
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
50
 * @method array column(string $field, string $key = '') static 获取某个列的值
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
51
 * @method Model find(mixed $data = null) static 查询单个记录 不存在返回Null
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
52
 * @method Model findOrEmpty(mixed $data = null) static 查询单个记录 不存在返回空模型
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
53
 * @method \think\model\Collection select(mixed $data = null) static 查询多个记录
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
54
 * @method Model withAttr(array $name,\Closure $closure) 动态定义获取器
1 ignored issue
show
Coding Style introduced by
Tag value for @method tag indented incorrectly; expected 2 spaces but found 1
Loading history...
55
 */
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...
56
abstract class Model implements JsonSerializable, ArrayAccess
57
{
58
    use model\concern\Attribute;
59
    use model\concern\RelationShip;
60
    use model\concern\ModelEvent;
61
    use model\concern\TimeStamp;
62
    use model\concern\Conversion;
63
64
    /**
65
     * 数据是否存在
66
     * @var bool
67
     */
68
    private $exists = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "exists" must be prefixed with an underscore
Loading history...
69
70
    /**
71
     * 是否强制更新所有数据
72
     * @var bool
73
     */
74
    private $force = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "force" must be prefixed with an underscore
Loading history...
75
76
    /**
77
     * 是否Replace
78
     * @var bool
79
     */
80
    private $replace = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "replace" must be prefixed with an underscore
Loading history...
81
82
    /**
83
     * 更新条件
84
     * @var array
85
     */
86
    private $updateWhere;
0 ignored issues
show
Coding Style introduced by
Private member variable "updateWhere" must be prefixed with an underscore
Loading history...
87
88
    /**
89
     * 数据库配置
90
     * @var string
91
     */
92
    protected $connection;
93
94
    /**
95
     * 模型名称
96
     * @var string
97
     */
98
    protected $name;
99
100
    /**
101
     * 数据表名称
102
     * @var string
103
     */
104
    protected $table;
105
106
    /**
107
     * 写入自动完成定义
108
     * @var array
109
     */
110
    protected $auto = [];
111
112
    /**
113
     * 新增自动完成定义
114
     * @var array
115
     */
116
    protected $insert = [];
117
118
    /**
119
     * 更新自动完成定义
120
     * @var array
121
     */
122
    protected $update = [];
123
124
    /**
125
     * 初始化过的模型.
126
     * @var array
127
     */
128
    protected static $initialized = [];
129
130
    /**
131
     * 查询对象实例
132
     * @var Query
133
     */
134
    protected $queryInstance;
135
136
    /**
137
     * 软删除字段默认值
138
     * @var mixed
139
     */
140
    protected $defaultSoftDelete;
141
142
    /**
143
     * 全局查询范围
144
     * @var array
145
     */
146
    protected $globalScope = [];
147
148
    /**
149
     * 延迟保存信息
150
     * @var bool
151
     */
152
    private $lazySave = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "lazySave" must be prefixed with an underscore
Loading history...
153
154
    /**
155
     * 服务注入
156
     * @var Closure
157
     */
158
    protected static $maker;
159
160
    /**
161
     * 设置服务注入
162
     * @access public
163
     * @param  Closure $maker
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
164
     * @return void
165
     */
166
    public static function maker(Closure $maker)
167
    {
168
        static::$maker = $maker;
169
    }
170
171
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $db should have a doc-comment as per coding-style.
Loading history...
172
     * 设置Db对象
173
     * @access public
174
     * @param  Db $lang Db对象
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter $lang does not match actual variable name $db
Loading history...
175
     * @return void
176
     */
177
    public function setDb(Db $db)
178
    {
179
        $this->db = $db;
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
180
    }
181
182
    /**
183
     * 设置Connection信息
184
     * @access public
185
     * @param  mixed $connection 数据库配置
186
     * @return void
187
     */
188
    public function setConnection($connection)
189
    {
190
        $this->connection = $connection;
191
    }
192
193
    /**
194
     * 获取Connection信息
195
     * @access public
196
     * @return void
197
     */
198
    public function getConnection()
199
    {
200
        return $this->connection;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->connection returns the type string which is incompatible with the documented return type void.
Loading history...
201
    }
202
203
    /**
204
     * 架构函数
205
     * @access public
206
     * @param  array $data 数据
207
     */
208
    public function __construct(array $data = [])
209
    {
210
        $this->data = $data;
211
212
        if (!empty($this->data)) {
213
            // 废弃字段
214
            foreach ((array) $this->disuse as $key) {
215
                if (array_key_exists($key, $this->data)) {
216
                    unset($this->data[$key]);
217
                }
218
            }
219
        }
220
221
        // 记录原始数据
222
        $this->origin = $this->data;
223
224
        if (empty($this->name)) {
225
            // 当前模型名
226
            $name       = str_replace('\\', '/', static::class);
227
            $this->name = basename($name);
228
        }
229
230
        // 执行初始化操作
231
        $this->initialize();
232
    }
233
234
    /**
235
     * 获取当前模型名称
236
     * @access public
237
     * @return string
238
     */
239
    public function getName(): string
240
    {
241
        return $this->name;
242
    }
243
244
    /**
245
     * 创建新的模型实例
246
     * @access public
247
     * @param  array    $data 数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
248
     * @param  mixed    $where 更新条件
249
     * @return Model
250
     */
251
    public function newInstance(array $data = [], $where = null): Model
252
    {
253
        if (empty($data)) {
254
            return new static();
255
        }
256
257
        $model = (new static($data))->exists(true);
258
        $model->setUpdateWhere($where);
259
260
        $model->trigger('after_read');
261
262
        return $model;
263
    }
264
265
    /**
266
     * 设置模型的更新条件
267
     * @access protected
268
     * @param  mixed $where 更新条件
269
     * @return void
270
     */
271
    protected function setUpdateWhere($where): void
272
    {
273
        $this->updateWhere = $where;
274
    }
275
276
    /**
277
     * 创建模型的查询对象
278
     * @access protected
279
     * @return Query
280
     */
281
    protected function buildQuery(): Query
282
    {
283
        /** @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...
284
        if (static::$maker) {
285
            call_user_func(static::$maker, $this);
286
        }
287
288
        $query = $this->db->buildQuery($this->connection);
289
290
        $query->model($this)
291
            ->name($this->name)
292
            ->json($this->json, $this->jsonAssoc)
293
            ->setFieldType($this->schema);
294
295
        if (!empty($this->table)) {
296
            $query->table($this->table);
297
        }
298
299
        return $query->pk($this->pk);
300
    }
301
302
    /**
303
     * 获取当前模型的数据库查询对象
304
     * @access public
305
     * @param  Query $query 查询对象实例
306
     * @return $this
307
     */
308
    public function setQuery(Query $query)
309
    {
310
        $this->queryInstance = $query;
311
        return $this;
312
    }
313
314
    /**
315
     * 获取当前模型的数据库查询对象
316
     * @access public
317
     * @param  array|false $scope 使用的全局查询范围
318
     * @return Query
319
     */
320
    public function db($scope = []): Query
321
    {
322
        if ($this->queryInstance) {
323
            return $this->queryInstance;
324
        }
325
326
        $query = $this->buildQuery();
327
328
        // 软删除
329
        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...
330
            $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

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

607
            $this->data[$this->updateTime] = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->updateTime);
Loading history...
608
            $data[$this->updateTime]       = $this->data[$this->updateTime];
609
        }
610
611
        // 检查允许字段
612
        $allowFields = $this->checkAllowFields($auto);
613
614
        foreach ($this->relationWrite as $name => $val) {
615
            if (!is_array($val)) {
616
                continue;
617
            }
618
619
            foreach ($val as $key) {
620
                if (isset($data[$key])) {
621
                    unset($data[$key]);
622
                }
623
            }
624
        }
625
626
        // 模型更新
627
        $db = $this->db();
628
        $db->startTrans();
629
630
        try {
631
            $where  = $this->getWhere();
632
            $result = $db->where($where)
633
                ->strict(false)
634
                ->field($allowFields)
635
                ->update($data);
636
637
            $this->checkResult($result);
638
639
            // 关联更新
640
            if (!empty($this->relationWrite)) {
641
                $this->autoRelationUpdate();
642
            }
643
644
            $db->commit();
645
646
            // 更新回调
647
            $this->trigger('after_update');
648
649
            return true;
650
        } catch (\Exception $e) {
651
            $db->rollback();
652
            throw $e;
653
        }
654
    }
655
656
    /**
657
     * 新增写入数据
658
     * @access protected
659
     * @param  string   $sequence 自增名
660
     * @return bool
661
     */
662
    protected function insertData(string $sequence = null): bool
663
    {
664
        // 自动写入
665
        $auto = array_merge($this->auto, $this->insert);
666
667
        $this->autoCompleteData($auto);
668
669
        // 时间戳自动写入
670
        if ($this->autoWriteTimestamp) {
671
            if ($this->createTime && !isset($this->data[$this->createTime])) {
672
                $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

672
                $this->data[$this->createTime] = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->createTime);
Loading history...
673
            }
674
675
            if ($this->updateTime && !isset($this->data[$this->updateTime])) {
676
                $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
677
            }
678
        }
679
680
        if (false === $this->trigger('before_insert')) {
681
            return false;
682
        }
683
684
        $this->checkData();
685
686
        // 检查允许字段
687
        $allowFields = $this->checkAllowFields($auto);
688
689
        $db = $this->db();
690
        $db->startTrans();
691
692
        try {
693
            $result = $db->strict(false)
694
                ->field($allowFields)
695
                ->replace($this->replace)
696
                ->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

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