Completed
Push — 6.0 ( 595f09...e2d008 )
by liu
02:55
created

Model::checkAllowFields()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 6
nop 1
dl 0
loc 28
ccs 0
cts 14
cp 0
crap 42
rs 9.2222
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
     * Db对象
156
     * @var Db
157
     */
158
    protected $db;
159
160
    /**
161
     * 服务注入
162
     * @var Closure
163
     */
164
    protected static $maker;
165
166
    /**
167
     * 设置服务注入
168
     * @access public
169
     * @param  Closure $maker
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
170
     * @return void
171
     */
172
    public static function maker(Closure $maker)
173
    {
174
        static::$maker = $maker;
175
    }
176
177
    /**
178
     * 设置Db对象
179
     * @access public
180
     * @param  Db $db Db对象
181
     * @return void
182
     */
183
    public function setDb(Db $db)
184
    {
185
        $this->db = $db;
186
    }
187
188
    /**
189
     * 设置Connection信息
190
     * @access public
191
     * @param  mixed $connection 数据库配置
192
     * @return void
193
     */
194
    public function setConnection($connection)
195
    {
196
        $this->connection = $connection;
197
    }
198
199
    /**
200
     * 获取Connection信息
201
     * @access public
202
     * @return string|array
203
     */
204
    public function getConnection()
205
    {
206
        return $this->connection;
207
    }
208
209
    /**
210
     * 架构函数
211
     * @access public
212
     * @param  array $data 数据
213
     */
214
    public function __construct(array $data = [])
215
    {
216
        $this->data = $data;
217
218
        if (!empty($this->data)) {
219
            // 废弃字段
220
            foreach ((array) $this->disuse as $key) {
221
                if (array_key_exists($key, $this->data)) {
222
                    unset($this->data[$key]);
223
                }
224
            }
225
        }
226
227
        // 记录原始数据
228
        $this->origin = $this->data;
229
230
        if (empty($this->name)) {
231
            // 当前模型名
232
            $name       = str_replace('\\', '/', static::class);
233
            $this->name = basename($name);
234
        }
235
236
        if (static::$maker) {
237
            call_user_func(static::$maker, $this);
238
        }
239
240
        // 执行初始化操作
241
        $this->initialize();
242
    }
243
244
    /**
245
     * 获取当前模型名称
246
     * @access public
247
     * @return string
248
     */
249
    public function getName(): string
250
    {
251
        return $this->name;
252
    }
253
254
    /**
255
     * 创建新的模型实例
256
     * @access public
257
     * @param  array    $data 数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
258
     * @param  mixed    $where 更新条件
259
     * @return Model
260
     */
261
    public function newInstance(array $data = [], $where = null): Model
262
    {
263
        if (empty($data)) {
264
            return new static();
265
        }
266
267
        $model = (new static($data))->exists(true);
268
        $model->setUpdateWhere($where);
269
270
        $model->trigger('after_read');
271
272
        return $model;
273
    }
274
275
    /**
276
     * 设置模型的更新条件
277
     * @access protected
278
     * @param  mixed $where 更新条件
279
     * @return void
280
     */
281
    protected function setUpdateWhere($where): void
282
    {
283
        $this->updateWhere = $where;
284
    }
285
286
    /**
287
     * 设置当前模型的数据库查询对象
288
     * @access public
289
     * @param  Query $query 查询对象实例
290
     * @return $this
291
     */
292
    public function setQuery(Query $query)
293
    {
294
        $this->queryInstance = clone $query;
295
        return $this;
296
    }
297
298
    /**
299
     * 获取当前模型的数据库查询对象
300
     * @access public
301
     * @param  array|false $scope 使用的全局查询范围
302
     * @return Query
303
     */
304
    public function db($scope = []): Query
305
    {
306
        /** @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...
307
        if ($this->queryInstance) {
308
            $query = $this->queryInstance->removeOption();
309
        } else {
310
            $query = $this->db->buildQuery($this->connection);
311
        }
312
313
        $query->model($this)
314
            ->name($this->name)
315
            ->json($this->json, $this->jsonAssoc)
316
            ->setFieldType($this->schema);
317
318
        if (!empty($this->table)) {
319
            $query->table($this->table);
320
        }
321
322
        $query->pk($this->pk);
0 ignored issues
show
Bug introduced by
It seems like $this->pk can also be of type array; however, parameter $pk of think\db\Query::pk() 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

322
        $query->pk(/** @scrutinizer ignore-type */ $this->pk);
Loading history...
323
324
        // 软删除
325
        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...
326
            $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

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

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

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

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