Completed
Push — 6.0 ( 2a00ae...39e6cf )
by yun
04:09
created

Model::reflesh()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 1
dl 0
loc 12
ccs 0
cts 7
cp 0
crap 12
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
     * 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
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...
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对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
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 数据库配置
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
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 数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
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  数据
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
258
     * @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...
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 更新条件
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
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 查询对象实例
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
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 使用的全局查询范围
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
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
                ->name($this->name)
312
                ->pk($this->pk);
313
        }
314
315
        $query->model($this)
316
            ->json($this->json, $this->jsonAssoc)
317
            ->setFieldType($this->schema);
318
319
        if (!empty($this->table)) {
320
            $query->table($this->table);
321
        }
322
323
        // 软删除
324
        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...
325
            $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

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

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

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

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