Passed
Push — 6.0 ( ae3266...6faeca )
by liu
04:09
created

RelationShip::hasOneThrough()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 1
nop 5
dl 0
loc 10
ccs 0
cts 7
cp 0
crap 20
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\model\concern;
14
15
use think\App;
16
use think\Collection;
17
use think\db\Query;
18
use think\Exception;
19
use think\Model;
20
use think\model\Relation;
21
use think\model\relation\BelongsTo;
22
use think\model\relation\BelongsToMany;
23
use think\model\relation\HasMany;
24
use think\model\relation\HasManyThrough;
25
use think\model\relation\HasOne;
26
use think\model\relation\HasOneThrough;
27
use think\model\relation\MorphMany;
28
use think\model\relation\MorphOne;
29
use think\model\relation\MorphTo;
30
31
/**
32
 * 模型关联处理
33
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package 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...
34
trait RelationShip
35
{
36
    /**
37
     * 父关联模型对象
38
     * @var object
39
     */
40
    private $parent;
0 ignored issues
show
Coding Style introduced by
Private member variable "parent" must be prefixed with an underscore
Loading history...
41
42
    /**
43
     * 模型关联数据
44
     * @var array
45
     */
46
    private $relation = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "relation" must be prefixed with an underscore
Loading history...
47
48
    /**
49
     * 关联写入定义信息
50
     * @var array
51
     */
52
    private $together = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "together" must be prefixed with an underscore
Loading history...
53
54
    /**
55
     * 关联自动写入信息
56
     * @var array
57
     */
58
    protected $relationWrite = [];
59
60
    /**
61
     * 设置父关联对象
62
     * @access public
63
     * @param  Model $model  模型对象
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
64
     * @return $this
65
     */
66
    public function setParent(Model $model)
67
    {
68
        $this->parent = $model;
69
70
        return $this;
71
    }
72
73
    /**
74
     * 获取父关联对象
75
     * @access public
76
     * @return Model
77
     */
78
    public function getParent(): Model
79
    {
80
        return $this->parent;
81
    }
82
83
    /**
84
     * 获取当前模型的关联模型数据
85
     * @access public
86
     * @param  string $name 关联方法名
87
     * @param  bool   $auto 不存在是否自动获取
88
     * @return mixed
89
     */
90
    public function getRelation(string $name = null, bool $auto = false)
91
    {
92
        if (is_null($name)) {
93
            return $this->relation;
94
        }
95
96
        if (array_key_exists($name, $this->relation)) {
97
            return $this->relation[$name];
98
        } elseif ($auto) {
99
            $method = App::parseName($name, 1, false);
100
            return $this->$method()->getRelation();
101
        }
102
    }
103
104
    /**
105
     * 设置关联数据对象值
106
     * @access public
107
     * @param  string $name  属性名
108
     * @param  mixed  $value 属性值
109
     * @param  array  $data  数据
110
     * @return $this
111
     */
112
    public function setRelation(string $name, $value, array $data = [])
113
    {
114
        // 检测修改器
115
        $method = 'set' . App::parseName($name, 1) . 'Attr';
116
117
        if (method_exists($this, $method)) {
118
            $value = $this->$method($value, array_merge($this->data, $data));
119
        }
120
121
        $this->relation[$name] = $value;
122
123
        return $this;
124
    }
125
126
    /**
127
     * 查询当前模型的关联数据
128
     * @access public
129
     * @param  array $relations 关联名
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter name; 1 found
Loading history...
130
     * @param  array $withRelationAttr   关联获取器
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 3 found
Loading history...
131
     * @return void
132
     */
133
    public function relationQuery(array $relations, array $withRelationAttr = []): void
134
    {
135
        foreach ($relations as $key => $relation) {
136
            $subRelation = '';
137
            $closure     = null;
138
139
            if ($relation instanceof \Closure) {
140
                // 支持闭包查询过滤关联条件
141
                $closure  = $relation;
142
                $relation = $key;
143
            }
144
145
            if (is_array($relation)) {
146
                $subRelation = $relation;
147
                $relation    = $key;
148
            } elseif (strpos($relation, '.')) {
149
                list($relation, $subRelation) = explode('.', $relation, 2);
150
            }
151
152
            $method       = App::parseName($relation, 1, false);
153
            $relationName = App::parseName($relation);
154
155
            $relationResult = $this->$method();
156
157
            if (isset($withRelationAttr[$relationName])) {
158
                $relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
159
            }
160
161
            $this->relation[$relation] = $relationResult->getRelation($subRelation, $closure);
162
        }
163
    }
164
165
    /**
166
     * 关联数据写入
167
     * @access public
168
     * @param  array $relation 关联
169
     * @return $this
170
     */
171
    public function together(array $relation)
172
    {
173
        $this->together = $relation;
174
175
        $this->checkAutoRelationWrite();
176
177
        return $this;
178
    }
179
180
    /**
181
     * 根据关联条件查询当前模型
182
     * @access public
183
     * @param  string  $relation 关联方法名
184
     * @param  mixed   $operator 比较操作符
185
     * @param  integer $count    个数
186
     * @param  string  $id       关联表的统计字段
187
     * @param  string  $joinType JOIN类型
188
     * @return Query
189
     */
190
    public static function has(string $relation, string $operator = '>=', int $count = 1, string $id = '*', string $joinType = ''): Query
191
    {
192
        return (new static())
193
            ->$relation()
194
            ->has($operator, $count, $id, $joinType);
195
    }
196
197
    /**
198
     * 根据关联条件查询当前模型
199
     * @access public
200
     * @param  string $relation 关联方法名
201
     * @param  mixed  $where    查询条件(数组或者闭包)
202
     * @param  mixed  $fields   字段
203
     * @param  string $joinType JOIN类型
204
     * @return Query
205
     */
206
    public static function hasWhere(string $relation, $where = [], string $fields = '*', string $joinType = ''): Query
207
    {
208
        return (new static())
209
            ->$relation()
210
            ->hasWhere($where, $fields, $joinType);
211
    }
212
213
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $relations should have a doc-comment as per coding-style.
Loading history...
214
     * 预载入关联查询 返回数据集
215
     * @access public
216
     * @param  array  $resultSet 数据集
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter name; 1 found
Loading history...
217
     * @param  string $relation  关联名
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter $relation does not match actual variable name $relations
Loading history...
Coding Style introduced by
Expected 9 spaces after parameter name; 2 found
Loading history...
218
     * @param  array  $withRelationAttr 关联获取器
219
     * @param  bool   $join      是否为JOIN方式
0 ignored issues
show
Coding Style introduced by
Expected 13 spaces after parameter name; 6 found
Loading history...
220
     * @return void
221
     */
222
    public function eagerlyResultSet(array &$resultSet, array $relations, array $withRelationAttr = [], bool $join = false): void
223
    {
224
        foreach ($relations as $key => $relation) {
225
            $subRelation = [];
226
            $closure     = null;
227
228
            if ($relation instanceof \Closure) {
229
                $closure  = $relation;
230
                $relation = $key;
231
            }
232
233
            if (is_array($relation)) {
234
                $subRelation = $relation;
235
                $relation    = $key;
236
            } elseif (strpos($relation, '.')) {
237
                list($relation, $subRelation) = explode('.', $relation, 2);
238
239
                $subRelation = [$subRelation];
240
            }
241
242
            $relation     = App::parseName($relation, 1, false);
243
            $relationName = App::parseName($relation);
244
245
            $relationResult = $this->$relation();
246
247
            if (isset($withRelationAttr[$relationName])) {
248
                $relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
249
            }
250
251
            $relationResult->eagerlyResultSet($resultSet, $relation, $subRelation, $closure, $join);
252
        }
253
    }
254
255
    /**
256
     * 预载入关联查询 返回模型对象
257
     * @access public
258
     * @param  Model    $result    数据对象
0 ignored issues
show
Coding Style introduced by
Expected 11 spaces after parameter name; 4 found
Loading history...
259
     * @param  array    $relations 关联
0 ignored issues
show
Coding Style introduced by
Expected 8 spaces after parameter name; 1 found
Loading history...
260
     * @param  array    $withRelationAttr 关联获取器
261
     * @param  bool     $join      是否为JOIN方式
0 ignored issues
show
Coding Style introduced by
Expected 13 spaces after parameter name; 6 found
Loading history...
262
     * @return void
263
     */
264
    public function eagerlyResult(Model $result, array $relations, array $withRelationAttr = [], bool $join = false): void
265
    {
266
        foreach ($relations as $key => $relation) {
267
            $subRelation = [];
268
            $closure     = null;
269
270
            if ($relation instanceof \Closure) {
271
                $closure  = $relation;
272
                $relation = $key;
273
            }
274
275
            if (is_array($relation)) {
276
                $subRelation = $relation;
277
                $relation    = $key;
278
            } elseif (strpos($relation, '.')) {
279
                list($relation, $subRelation) = explode('.', $relation, 2);
280
281
                $subRelation = [$subRelation];
282
            }
283
284
            $relation     = App::parseName($relation, 1, false);
285
            $relationName = App::parseName($relation);
286
287
            $relationResult = $this->$relation();
288
289
            if (isset($withRelationAttr[$relationName])) {
290
                $relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
291
            }
292
293
            $relationResult->eagerlyResult($result, $relation, $subRelation, $closure, $join);
294
        }
295
    }
296
297
    /**
298
     * 绑定(一对一)关联属性到当前模型
299
     * @access protected
300
     * @param  string   $relation    关联名称
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 4 found
Loading history...
301
     * @param  array    $attrs       绑定属性
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 7 found
Loading history...
302
     * @return $this
303
     * @throws Exception
304
     */
305
    public function bindAttr(string $relation, array $attrs = [])
306
    {
307
        $relation = $this->getRelation($relation);
308
309
        foreach ($attrs as $key => $attr) {
310
            $key   = is_numeric($key) ? $attr : $key;
311
            $value = $this->getOrigin($key);
0 ignored issues
show
Bug introduced by
It seems like getOrigin() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

311
            /** @scrutinizer ignore-call */ 
312
            $value = $this->getOrigin($key);
Loading history...
312
313
            if (!is_null($value)) {
314
                throw new Exception('bind attr has exists:' . $key);
315
            } else {
316
                $this->set($key, $relation ? $relation->$attr : null);
0 ignored issues
show
Bug introduced by
It seems like set() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

316
                $this->/** @scrutinizer ignore-call */ 
317
                       set($key, $relation ? $relation->$attr : null);
Loading history...
317
            }
318
        }
319
320
        return $this;
321
    }
322
323
    /**
324
     * 关联统计
325
     * @access public
326
     * @param  Model    $result     数据对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 5 found
Loading history...
327
     * @param  array    $relations  关联名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
328
     * @param  string   $aggregate  聚合查询方法
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
329
     * @param  string   $field      字段
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 6 found
Loading history...
330
     * @return void
331
     */
332
    public function relationCount(Model $result, array $relations, string $aggregate = 'sum', string $field = '*'): void
333
    {
334
        foreach ($relations as $key => $relation) {
335
            $closure = $name = null;
336
337
            if ($relation instanceof \Closure) {
338
                $closure  = $relation;
339
                $relation = $key;
340
            } elseif (is_string($key)) {
341
                $name     = $relation;
342
                $relation = $key;
343
            }
344
345
            $relation = App::parseName($relation, 1, false);
346
            $count    = $this->$relation()->relationCount($result, $closure, $aggregate, $field, $name);
347
348
            if (empty($name)) {
349
                $name = App::parseName($relation) . '_' . $aggregate;
350
            }
351
352
            $result->setAttr($name, $count);
353
        }
354
    }
355
356
    /**
357
     * HAS ONE 关联定义
358
     * @access public
359
     * @param  string $model      模型名
360
     * @param  string $foreignKey 关联外键
361
     * @param  string $localKey   当前主键
362
     * @return HasOne
363
     */
364
    public function hasOne(string $model, string $foreignKey = '', string $localKey = ''): HasOne
365
    {
366
        // 记录当前关联信息
367
        $model      = $this->parseModel($model);
368
        $localKey   = $localKey ?: $this->getPk();
0 ignored issues
show
Bug introduced by
It seems like getPk() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

368
        $localKey   = $localKey ?: $this->/** @scrutinizer ignore-call */ getPk();
Loading history...
369
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
370
371
        return new HasOne($this, $model, $foreignKey, $localKey);
372
    }
373
374
    /**
375
     * BELONGS TO 关联定义
376
     * @access public
377
     * @param  string $model      模型名
378
     * @param  string $foreignKey 关联外键
379
     * @param  string $localKey   关联主键
380
     * @return BelongsTo
381
     */
382
    public function belongsTo(string $model, string $foreignKey = '', string $localKey = ''): BelongsTo
383
    {
384
        // 记录当前关联信息
385
        $model      = $this->parseModel($model);
386
        $foreignKey = $foreignKey ?: $this->getForeignKey((new $model)->getName());
387
        $localKey   = $localKey ?: (new $model)->getPk();
388
        $trace      = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
389
        $relation   = App::parseName($trace[1]['function']);
390
391
        return new BelongsTo($this, $model, $foreignKey, $localKey, $relation);
392
    }
393
394
    /**
395
     * HAS MANY 关联定义
396
     * @access public
397
     * @param  string $model      模型名
398
     * @param  string $foreignKey 关联外键
399
     * @param  string $localKey   当前主键
400
     * @return HasMany
401
     */
402
    public function hasMany(string $model, string $foreignKey = '', string $localKey = ''): HasMany
403
    {
404
        // 记录当前关联信息
405
        $model      = $this->parseModel($model);
406
        $localKey   = $localKey ?: $this->getPk();
407
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
408
409
        return new HasMany($this, $model, $foreignKey, $localKey);
410
    }
411
412
    /**
413
     * HAS MANY 远程关联定义
414
     * @access public
415
     * @param  string $model      模型名
416
     * @param  string $through    中间模型名
417
     * @param  string $foreignKey 关联外键
418
     * @param  string $throughKey 关联外键
419
     * @param  string $localKey   当前主键
420
     * @return HasManyThrough
421
     */
422
    public function hasManyThrough(string $model, string $through, string $foreignKey = '', string $throughKey = '', string $localKey = ''): HasManyThrough
423
    {
424
        // 记录当前关联信息
425
        $model      = $this->parseModel($model);
426
        $through    = $this->parseModel($through);
427
        $localKey   = $localKey ?: $this->getPk();
428
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
429
        $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName());
430
431
        return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey);
432
    }
433
434
    /**
435
     * HAS ONE 远程关联定义
436
     * @access public
437
     * @param  string $model      模型名
438
     * @param  string $through    中间模型名
439
     * @param  string $foreignKey 关联外键
440
     * @param  string $throughKey 关联外键
441
     * @param  string $localKey   当前主键
442
     * @return HasOneThrough
443
     */
444
    public function hasOneThrough(string $model, string $through, string $foreignKey = '', string $throughKey = '', string $localKey = ''): HasOneThrough
445
    {
446
        // 记录当前关联信息
447
        $model      = $this->parseModel($model);
448
        $through    = $this->parseModel($through);
449
        $localKey   = $localKey ?: $this->getPk();
450
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
451
        $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName());
452
453
        return new HasOneThrough($this, $model, $through, $foreignKey, $throughKey, $localKey);
454
    }
455
456
    /**
457
     * BELONGS TO MANY 关联定义
458
     * @access public
459
     * @param  string $model      模型名
460
     * @param  string $table      中间表名
461
     * @param  string $foreignKey 关联外键
462
     * @param  string $localKey   当前模型关联键
463
     * @return BelongsToMany
464
     */
465
    public function belongsToMany(string $model, string $table = '', string $foreignKey = '', string $localKey = ''): BelongsToMany
466
    {
467
        // 记录当前关联信息
468
        $model      = $this->parseModel($model);
469
        $name       = App::parseName(App::classBaseName($model));
470
        $table      = $table ?: App::parseName($this->name) . '_' . $name;
471
        $foreignKey = $foreignKey ?: $name . '_id';
472
        $localKey   = $localKey ?: $this->getForeignKey($this->name);
473
474
        return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
475
    }
476
477
    /**
478
     * MORPH  One 关联定义
479
     * @access public
480
     * @param  string       $model 模型名
481
     * @param  string|array $morph 多态字段信息
482
     * @param  string       $type  多态类型
483
     * @return MorphOne
484
     */
485
    public function morphOne(string $model, $morph = null, string $type = ''): MorphOne
486
    {
487
        // 记录当前关联信息
488
        $model = $this->parseModel($model);
489
490
        if (is_null($morph)) {
491
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
492
            $morph = App::parseName($trace[1]['function']);
493
        }
494
495
        if (is_array($morph)) {
496
            list($morphType, $foreignKey) = $morph;
497
        } else {
498
            $morphType  = $morph . '_type';
499
            $foreignKey = $morph . '_id';
500
        }
501
502
        $type = $type ?: get_class($this);
503
504
        return new MorphOne($this, $model, $foreignKey, $morphType, $type);
505
    }
506
507
    /**
508
     * MORPH  MANY 关联定义
509
     * @access public
510
     * @param  string       $model 模型名
511
     * @param  string|array $morph 多态字段信息
512
     * @param  string       $type  多态类型
513
     * @return MorphMany
514
     */
515
    public function morphMany(string $model, $morph = null, string $type = ''): MorphMany
516
    {
517
        // 记录当前关联信息
518
        $model = $this->parseModel($model);
519
520
        if (is_null($morph)) {
521
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
522
            $morph = App::parseName($trace[1]['function']);
523
        }
524
525
        $type = $type ?: get_class($this);
526
527
        if (is_array($morph)) {
528
            list($morphType, $foreignKey) = $morph;
529
        } else {
530
            $morphType  = $morph . '_type';
531
            $foreignKey = $morph . '_id';
532
        }
533
534
        return new MorphMany($this, $model, $foreignKey, $morphType, $type);
535
    }
536
537
    /**
538
     * MORPH TO 关联定义
539
     * @access public
540
     * @param  string|array $morph 多态字段信息
541
     * @param  array        $alias 多态别名定义
542
     * @return MorphTo
543
     */
544
    public function morphTo($morph = null, array $alias = []): MorphTo
545
    {
546
        $trace    = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
547
        $relation = App::parseName($trace[1]['function']);
548
549
        if (is_null($morph)) {
550
            $morph = $relation;
551
        }
552
553
        // 记录当前关联信息
554
        if (is_array($morph)) {
555
            list($morphType, $foreignKey) = $morph;
556
        } else {
557
            $morphType  = $morph . '_type';
558
            $foreignKey = $morph . '_id';
559
        }
560
561
        return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
562
    }
563
564
    /**
565
     * 解析模型的完整命名空间
566
     * @access protected
567
     * @param  string $model 模型名(或者完整类名)
568
     * @return string
569
     */
570
    protected function parseModel(string $model): string
571
    {
572
        if (false === strpos($model, '\\')) {
573
            $path = explode('\\', static::class);
574
            array_pop($path);
575
            array_push($path, App::parseName($model, 1));
576
            $model = implode('\\', $path);
577
        }
578
579
        return $model;
580
    }
581
582
    /**
583
     * 获取模型的默认外键名
584
     * @access protected
585
     * @param  string $name 模型名
586
     * @return string
587
     */
588
    protected function getForeignKey(string $name): string
589
    {
590
        if (strpos($name, '\\')) {
591
            $name = App::classBaseName($name);
592
        }
593
594
        return App::parseName($name) . '_id';
595
    }
596
597
    /**
598
     * 检查属性是否为关联属性 如果是则返回关联方法名
599
     * @access protected
600
     * @param  string $attr 关联属性名
601
     * @return string|false
602
     */
603
    protected function isRelationAttr(string $attr)
604
    {
605
        $relation = App::parseName($attr, 1, false);
606
607
        if (method_exists($this, $relation) && !method_exists('think\Model', $relation)) {
608
            return $relation;
609
        }
610
611
        return false;
612
    }
613
614
    /**
615
     * 智能获取关联模型数据
616
     * @access protected
617
     * @param  Relation $modelRelation 模型关联对象
618
     * @return mixed
619
     */
620
    protected function getRelationData(Relation $modelRelation)
621
    {
622
        if ($this->parent && !$modelRelation->isSelfRelation() && get_class($this->parent) == get_class($modelRelation->getModel())) {
623
            return $this->parent;
624
        }
625
626
        // 获取关联数据
627
        return $modelRelation->getRelation();
0 ignored issues
show
Bug introduced by
The method getRelation() does not exist on think\model\Relation. 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

627
        return $modelRelation->/** @scrutinizer ignore-call */ getRelation();
Loading history...
628
    }
629
630
    /**
631
     * 关联数据自动写入检查
632
     * @access protected
633
     * @return void
634
     */
635
    protected function checkAutoRelationWrite(): void
636
    {
637
        foreach ($this->together as $key => $name) {
638
            if (is_array($name)) {
639
                if (key($name) === 0) {
640
                    $this->relationWrite[$key] = [];
641
                    // 绑定关联属性
642
                    foreach ($name as $val) {
643
                        if (isset($this->data[$val])) {
644
                            $this->relationWrite[$key][$val] = $this->data[$val];
645
                        }
646
                    }
647
                } else {
648
                    // 直接传入关联数据
649
                    $this->relationWrite[$key] = $name;
650
                }
651
            } elseif (isset($this->relation[$name])) {
652
                $this->relationWrite[$name] = $this->relation[$name];
653
            } elseif (isset($this->data[$name])) {
654
                $this->relationWrite[$name] = $this->data[$name];
655
                unset($this->data[$name]);
656
            }
657
        }
658
    }
659
660
    /**
661
     * 自动关联数据更新(针对一对一关联)
662
     * @access protected
663
     * @return void
664
     */
665
    protected function autoRelationUpdate(): void
666
    {
667
        foreach ($this->relationWrite as $name => $val) {
668
            if ($val instanceof Model) {
669
                $val->exists(true)->save();
670
            } else {
671
                $model = $this->getRelation($name, true);
672
673
                if ($model instanceof Model) {
674
                    $model->exists(true)->save($val);
675
                }
676
            }
677
        }
678
    }
679
680
    /**
681
     * 自动关联数据写入(针对一对一关联)
682
     * @access protected
683
     * @return void
684
     */
685
    protected function autoRelationInsert(): void
686
    {
687
        foreach ($this->relationWrite as $name => $val) {
688
            $method = App::parseName($name, 1, false);
689
            $this->$method()->save($val);
690
        }
691
    }
692
693
    /**
694
     * 自动关联数据删除(支持一对一及一对多关联)
695
     * @access protected
696
     * @return void
697
     */
698
    protected function autoRelationDelete(): void
699
    {
700
        foreach ($this->relationWrite as $key => $name) {
701
            $name   = is_numeric($key) ? $name : $key;
702
            $result = $this->getRelation($name, true);
703
704
            if ($result instanceof Model) {
705
                $result->delete();
706
            } elseif ($result instanceof Collection) {
707
                foreach ($result as $model) {
708
                    $model->delete();
709
                }
710
            }
711
        }
712
    }
713
714
    /**
715
     * 移除当前模型的关联属性
716
     * @access public
717
     * @return $this
718
     */
719
    public function removeRelation()
720
    {
721
        $this->relation = [];
722
        return $this;
723
    }
724
}
725