Passed
Push — 6.0 ( ed4dba...e05903 )
by liu
02:58
created

Model::setUpdateWhere()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
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 JsonSerializable;
17
use think\db\Query;
18
use think\facade\Db;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, think\Db. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 $query;
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
     * 架构函数
162
     * @access public
163
     * @param  array $data 数据
164
     */
165
    public function __construct(array $data = [])
166
    {
167
        $this->data = $data;
168
169
        if (!empty($this->data)) {
170
            // 废弃字段
171
            foreach ((array) $this->disuse as $key) {
172
                if (array_key_exists($key, $this->data)) {
173
                    unset($this->data[$key]);
174
                }
175
            }
176
        }
177
178
        // 记录原始数据
179
        $this->origin = $this->data;
180
181
        $config = Container::pull('config');
182
183
        if (empty($this->name)) {
184
            // 当前模型名
185
            $name       = str_replace('\\', '/', static::class);
186
            $this->name = basename($name);
187
        }
188
189
        if (is_null($this->autoWriteTimestamp)) {
0 ignored issues
show
introduced by
The condition is_null($this->autoWriteTimestamp) is always false.
Loading history...
190
            // 自动写入时间戳
191
            $this->autoWriteTimestamp = $config->get('database.auto_timestamp');
192
        }
193
194
        if (is_null($this->dateFormat)) {
0 ignored issues
show
introduced by
The condition is_null($this->dateFormat) is always false.
Loading history...
195
            // 设置时间戳格式
196
            $this->dateFormat = $config->get('database.datetime_format');
197
        }
198
199
        if (!empty($this->connection) && is_array($this->connection)) {
0 ignored issues
show
introduced by
The condition is_array($this->connection) is always false.
Loading history...
200
            // 设置模型的数据库连接
201
            $this->connection = array_merge($config->get('database'), $this->connection);
202
        }
203
204
        // 执行初始化操作
205
        $this->initialize();
206
    }
207
208
    /**
209
     * 获取当前模型名称
210
     * @access public
211
     * @return string
212
     */
213
    public function getName(): string
214
    {
215
        return $this->name;
216
    }
217
218
    /**
219
     * 创建新的模型实例
220
     * @access public
221
     * @param  array    $data 数据
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
222
     * @param  mixed    $where 更新条件
223
     * @return Model
224
     */
225
    public function newInstance(array $data = [], $where = null): Model
226
    {
227
        if (empty($data)) {
228
            return new static();
229
        }
230
231
        $model = (new static($data))->exists(true)->setUpdateWhere($where);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $model is correct as new static($data)->exist...>setUpdateWhere($where) targeting think\Model::setUpdateWhere() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
232
233
        $model->trigger('after_read');
234
235
        return $model;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $model returns the type void which is incompatible with the type-hinted return think\Model.
Loading history...
236
    }
237
238
    /**
239
     * 设置模型的更新条件
240
     * @access protected
241
     * @param  mixed $where 更新条件
242
     * @return void
243
     */
244
    protected function setUpdateWhere($where): void
245
    {
246
        $this->updateWhere = $where;
247
    }
248
249
    /**
250
     * 创建模型的查询对象
251
     * @access protected
252
     * @return Query
253
     */
254
    protected function buildQuery(): Query
255
    {
256
        $connection = Db::buildConnection($this->connection);
0 ignored issues
show
Bug introduced by
The method buildConnection() does not exist on think\facade\Db. Since you implemented __callStatic, 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

256
        /** @scrutinizer ignore-call */ 
257
        $connection = Db::buildConnection($this->connection);
Loading history...
257
258
        if ($this->query) {
259
            $query = new $this->query($connection);
260
        } else {
261
            $queryClass = $connection->getConfig('query');
262
            $query      = new $queryClass($connection);
263
        }
264
265
        $query->model($this)
266
            ->name($this->name)
267
            ->json($this->json, $this->jsonAssoc)
268
            ->setFieldType($this->schema);
269
270
        if (!empty($this->table)) {
271
            $query->table($this->table);
272
        }
273
274
        return $query->pk($this->pk);
275
    }
276
277
    /**
278
     * 获取当前模型的数据库查询对象
279
     * @access public
280
     * @param  Query $query 查询对象实例
281
     * @return $this
282
     */
283
    public function setQuery(Query $query)
284
    {
285
        $this->queryInstance = $query;
286
        return $this;
287
    }
288
289
    /**
290
     * 获取当前模型的数据库查询对象
291
     * @access public
292
     * @param  array|false $scope 使用的全局查询范围
293
     * @return Query
294
     */
295
    public function db($scope = []): Query
296
    {
297
        if ($this->queryInstance) {
298
            return $this->queryInstance;
299
        }
300
301
        $query = $this->buildQuery();
302
303
        // 软删除
304
        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...
305
            $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

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

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

647
                $this->data[$this->createTime] = $this->autoWriteTimestamp(/** @scrutinizer ignore-type */ $this->createTime);
Loading history...
648
            }
649
650
            if ($this->updateTime && !isset($this->data[$this->updateTime])) {
651
                $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
652
            }
653
        }
654
655
        if (false === $this->trigger('before_insert')) {
656
            return false;
657
        }
658
659
        $this->checkData();
660
661
        // 检查允许字段
662
        $allowFields = $this->checkAllowFields($auto);
663
664
        $db = $this->db();
665
        $db->startTrans();
666
667
        try {
668
            $result = $db->strict(false)
669
                ->field($allowFields)
670
                ->replace($this->replace)
671
                ->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

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