Completed
Push — 6.0 ( 8d8f1e...6bb935 )
by liu
03:06
created

Model   F

Complexity

Total Complexity 137

Size/Duplication

Total Lines 1037
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 295
dl 0
loc 1037
ccs 0
cts 328
cp 0
rs 2
c 0
b 0
f 0
wmc 137

52 Methods

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

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use ArrayAccess;
16
use Closure;
17
use JsonSerializable;
18
use think\db\Query;
19
20
/**
21
 * Class Model
22
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
23
 * @mixin Query
1 ignored issue
show
Coding Style introduced by
Tag value for @mixin tag indented incorrectly; expected 3 spaces but found 1
Loading history...
24
 * @method 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 string
85
     */
86
    protected $suffix;
87
88
    /**
89
     * 更新条件
90
     * @var array
91
     */
92
    private $updateWhere;
0 ignored issues
show
Coding Style introduced by
Private member variable "updateWhere" must be prefixed with an underscore
Loading history...
93
94
    /**
95
     * 数据库配置
96
     * @var string
97
     */
98
    protected $connection;
99
100
    /**
101
     * 模型名称
102
     * @var string
103
     */
104
    protected $name;
105
106
    /**
107
     * 数据表名称
108
     * @var string
109
     */
110
    protected $table;
111
112
    /**
113
     * 写入自动完成定义
114
     * @var array
115
     */
116
    protected $auto = [];
117
118
    /**
119
     * 新增自动完成定义
120
     * @var array
121
     */
122
    protected $insert = [];
123
124
    /**
125
     * 更新自动完成定义
126
     * @var array
127
     */
128
    protected $update = [];
129
130
    /**
131
     * 初始化过的模型.
132
     * @var array
133
     */
134
    protected static $initialized = [];
135
136
    /**
137
     * 查询对象实例
138
     * @var Query
139
     */
140
    protected $queryInstance;
141
142
    /**
143
     * 软删除字段默认值
144
     * @var mixed
145
     */
146
    protected $defaultSoftDelete;
147
148
    /**
149
     * 全局查询范围
150
     * @var array
151
     */
152
    protected $globalScope = [];
153
154
    /**
155
     * 延迟保存信息
156
     * @var bool
157
     */
158
    private $lazySave = false;
0 ignored issues
show
Coding Style introduced by
Private member variable "lazySave" must be prefixed with an underscore
Loading history...
159
160
    /**
161
     * Db对象
162
     * @var Db
163
     */
164
    protected $db;
165
166
    /**
167
     * Event对象
168
     * @var Event
169
     */
170
    protected $event;
171
172
    /**
173
     * 服务注入
174
     * @var Closure
175
     */
176
    protected static $maker;
177
178
    /**
179
     * 设置服务注入
180
     * @access public
181
     * @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...
182
     * @return void
183
     */
184
    public static function maker(Closure $maker)
185
    {
186
        static::$maker = $maker;
187
    }
188
189
    /**
190
     * 设置Db对象
191
     * @access public
192
     * @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...
193
     * @return void
194
     */
195
    public function setDb(Db $db)
196
    {
197
        $this->db = $db;
198
    }
199
200
    /**
201
     * 设置Event对象
202
     * @access public
203
     * @param Event $event Event对象
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
204
     * @return void
205
     */
206
    public function setEvent(Event $event)
207
    {
208
        $this->event = $event;
209
    }
210
211
    /**
212
     * 设置Connection信息
213
     * @access public
214
     * @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...
215
     * @return void
216
     */
217
    public function setConnection($connection)
218
    {
219
        $this->connection = $connection;
220
    }
221
222
    /**
223
     * 获取Connection信息
224
     * @access public
225
     * @return string|array
226
     */
227
    public function getConnection()
228
    {
229
        return $this->connection;
230
    }
231
232
    /**
233
     * 架构函数
234
     * @access public
235
     * @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...
236
     */
237
    public function __construct(array $data = [])
238
    {
239
        $this->data = $data;
240
241
        if (!empty($this->data)) {
242
            // 废弃字段
243
            foreach ((array) $this->disuse as $key) {
244
                if (array_key_exists($key, $this->data)) {
245
                    unset($this->data[$key]);
246
                }
247
            }
248
        }
249
250
        // 记录原始数据
251
        $this->origin = $this->data;
252
253
        if (empty($this->name)) {
254
            // 当前模型名
255
            $name       = str_replace('\\', '/', static::class);
256
            $this->name = basename($name);
257
        }
258
259
        if (static::$maker) {
260
            call_user_func(static::$maker, $this);
261
        }
262
263
        // 执行初始化操作
264
        $this->initialize();
265
    }
266
267
    /**
268
     * 获取当前模型名称
269
     * @access public
270
     * @return string
271
     */
272
    public function getName(): string
273
    {
274
        return $this->name;
275
    }
276
277
    /**
278
     * 创建新的模型实例
279
     * @access public
280
     * @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...
281
     * @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...
282
     * @return Model
283
     */
284
    public function newInstance(array $data = [], $where = null): Model
285
    {
286
        if (empty($data)) {
287
            return new static();
288
        }
289
290
        $model = (new static($data))->exists(true);
291
        $model->setUpdateWhere($where);
292
293
        $model->trigger('AfterRead');
294
295
        return $model;
296
    }
297
298
    /**
299
     * 设置模型的更新条件
300
     * @access protected
301
     * @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...
302
     * @return void
303
     */
304
    protected function setUpdateWhere($where): void
305
    {
306
        $this->updateWhere = $where;
307
    }
308
309
    /**
310
     * 设置当前模型的数据库查询对象
311
     * @access public
312
     * @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...
313
     * @return $this
314
     */
315
    public function setQuery(Query $query)
316
    {
317
        $this->queryInstance = clone $query;
318
        return $this;
319
    }
320
321
    /**
322
     * 设置当前模型数据表的后缀
323
     * @access public
324
     * @param string $suffix 数据表后缀
1 ignored issue
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
325
     * @return $this
326
     */
327
    public function setSuffix(string $suffix)
328
    {
329
        $this->suffix = $suffix;
330
        return $this;
331
    }
332
333
    /**
334
     * 获取当前模型的数据表后缀
335
     * @access public
336
     * @return string
337
     */
338
    public function getSuffix(): string
339
    {
340
        return $this->suffix ?: '';
341
    }
342
343
    /**
344
     * 获取当前模型的数据库查询对象
345
     * @access public
346
     * @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...
347
     * @return Query
348
     */
349
    public function db($scope = []): Query
350
    {
351
        /** @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...
352
        if ($this->queryInstance) {
353
            $query = $this->queryInstance->removeOption();
354
        } else {
355
            $query = $this->db->buildQuery($this->connection)
356
                ->name($this->name . $this->suffix)
357
                ->pk($this->pk);
358
        }
359
360
        $query->model($this)
361
            ->json($this->json, $this->jsonAssoc)
362
            ->setFieldType($this->schema);
363
364
        if (!empty($this->table)) {
365
            $query->table($this->table . $this->suffix);
366
        }
367
368
        // 软删除
369
        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...
370
            $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

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

646
            $data[$this->updateTime]       = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->updateTime);
Loading history...
647
            $this->data[$this->updateTime] = $data[$this->updateTime];
648
        }
649
650
        // 检查允许字段
651
        $allowFields = $this->checkAllowFields($auto);
652
653
        foreach ($this->relationWrite as $name => $val) {
654
            if (!is_array($val)) {
655
                continue;
656
            }
657
658
            foreach ($val as $key) {
659
                if (isset($data[$key])) {
660
                    unset($data[$key]);
661
                }
662
            }
663
        }
664
665
        // 模型更新
666
        $db = $this->db();
667
        $db->startTrans();
668
669
        try {
670
            $where  = $this->getWhere();
671
            $result = $db->where($where)
672
                ->strict(false)
673
                ->field($allowFields)
674
                ->update($data);
675
676
            $this->checkResult($result);
677
678
            // 关联更新
679
            if (!empty($this->relationWrite)) {
680
                $this->autoRelationUpdate();
681
            }
682
683
            $db->commit();
684
685
            // 更新回调
686
            $this->trigger('AfterUpdate');
687
688
            return true;
689
        } catch (\Exception $e) {
690
            $db->rollback();
691
            throw $e;
692
        }
693
    }
694
695
    /**
696
     * 新增写入数据
697
     * @access protected
698
     * @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...
699
     * @return bool
700
     */
701
    protected function insertData(string $sequence = null): bool
702
    {
703
        // 自动写入
704
        $auto = array_merge($this->auto, $this->insert);
705
706
        $this->autoCompleteData($auto);
707
708
        // 时间戳自动写入
709
        if ($this->autoWriteTimestamp) {
710
            if ($this->createTime && !isset($this->data[$this->createTime])) {
711
                $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

711
                $this->data[$this->createTime] = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->createTime);
Loading history...
712
            }
713
714
            if ($this->updateTime && !isset($this->data[$this->updateTime])) {
715
                $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
716
            }
717
        }
718
719
        if (false === $this->trigger('BeforeInsert')) {
720
            return false;
721
        }
722
723
        $this->checkData();
724
725
        // 检查允许字段
726
        $allowFields = $this->checkAllowFields($auto);
727
728
        $db = $this->db();
729
        $db->startTrans();
730
731
        try {
732
            $result = $db->strict(false)
733
                ->field($allowFields)
734
                ->replace($this->replace)
735
                ->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

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