Passed
Pull Request — 5.1 (#1748)
by guanguans
09:27
created

RelationShip::belongsToMany()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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

346
        $localKey   = $localKey ?: $this->/** @scrutinizer ignore-call */ getPk();
Loading history...
347
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
348
349
        return new HasOne($this, $model, $foreignKey, $localKey);
350
    }
351
352
    /**
353
     * BELONGS TO 关联定义
354
     * @access public
355
     * @param  string $model      模型名
356
     * @param  string $foreignKey 关联外键
357
     * @param  string $localKey   关联主键
358
     * @return BelongsTo
359
     */
360
    public function belongsTo($model, $foreignKey = '', $localKey = '')
361
    {
362
        // 记录当前关联信息
363
        $model      = $this->parseModel($model);
364
        $foreignKey = $foreignKey ?: $this->getForeignKey((new $model)->getName());
365
        $localKey   = $localKey ?: (new $model)->getPk();
366
        $trace      = debug_backtrace(false, 2);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $options of debug_backtrace(). ( Ignorable by Annotation )

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

366
        $trace      = debug_backtrace(/** @scrutinizer ignore-type */ false, 2);
Loading history...
367
        $relation   = Loader::parseName($trace[1]['function']);
368
369
        return new BelongsTo($this, $model, $foreignKey, $localKey, $relation);
370
    }
371
372
    /**
373
     * HAS MANY 关联定义
374
     * @access public
375
     * @param  string $model      模型名
376
     * @param  string $foreignKey 关联外键
377
     * @param  string $localKey   当前主键
378
     * @return HasMany
379
     */
380
    public function hasMany($model, $foreignKey = '', $localKey = '')
381
    {
382
        // 记录当前关联信息
383
        $model      = $this->parseModel($model);
384
        $localKey   = $localKey ?: $this->getPk();
385
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
386
387
        return new HasMany($this, $model, $foreignKey, $localKey);
388
    }
389
390
    /**
391
     * HAS MANY 远程关联定义
392
     * @access public
393
     * @param  string $model      模型名
394
     * @param  string $through    中间模型名
395
     * @param  string $foreignKey 关联外键
396
     * @param  string $throughKey 关联外键
397
     * @param  string $localKey   当前主键
398
     * @return HasManyThrough
399
     */
400
    public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '')
401
    {
402
        // 记录当前关联信息
403
        $model      = $this->parseModel($model);
404
        $through    = $this->parseModel($through);
405
        $localKey   = $localKey ?: $this->getPk();
406
        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
407
        $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName());
408
409
        return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey);
410
    }
411
412
    /**
413
     * BELONGS TO MANY 关联定义
414
     * @access public
415
     * @param  string $model      模型名
416
     * @param  string $table      中间表名
417
     * @param  string $foreignKey 关联外键
418
     * @param  string $localKey   当前模型关联键
419
     * @return BelongsToMany
420
     */
421
    public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = '')
422
    {
423
        // 记录当前关联信息
424
        $model      = $this->parseModel($model);
425
        $name       = Loader::parseName(basename(str_replace('\\', '/', $model)));
426
        $table      = $table ?: Loader::parseName($this->name) . '_' . $name;
427
        $foreignKey = $foreignKey ?: $name . '_id';
428
        $localKey   = $localKey ?: $this->getForeignKey($this->name);
429
430
        return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
431
    }
432
433
    /**
434
     * MORPH  One 关联定义
435
     * @access public
436
     * @param  string       $model 模型名
437
     * @param  string|array $morph 多态字段信息
438
     * @param  string       $type  多态类型
439
     * @return MorphOne
440
     */
441
    public function morphOne($model, $morph = null, $type = '')
442
    {
443
        // 记录当前关联信息
444
        $model = $this->parseModel($model);
445
446
        if (is_null($morph)) {
447
            $trace = debug_backtrace(false, 2);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $options of debug_backtrace(). ( Ignorable by Annotation )

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

447
            $trace = debug_backtrace(/** @scrutinizer ignore-type */ false, 2);
Loading history...
448
            $morph = Loader::parseName($trace[1]['function']);
449
        }
450
451
        if (is_array($morph)) {
452
            list($morphType, $foreignKey) = $morph;
453
        } else {
454
            $morphType  = $morph . '_type';
455
            $foreignKey = $morph . '_id';
456
        }
457
458
        $type = $type ?: get_class($this);
459
460
        return new MorphOne($this, $model, $foreignKey, $morphType, $type);
461
    }
462
463
    /**
464
     * MORPH  MANY 关联定义
465
     * @access public
466
     * @param  string       $model 模型名
467
     * @param  string|array $morph 多态字段信息
468
     * @param  string       $type  多态类型
469
     * @return MorphMany
470
     */
471
    public function morphMany($model, $morph = null, $type = '')
472
    {
473
        // 记录当前关联信息
474
        $model = $this->parseModel($model);
475
476
        if (is_null($morph)) {
477
            $trace = debug_backtrace(false, 2);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $options of debug_backtrace(). ( Ignorable by Annotation )

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

477
            $trace = debug_backtrace(/** @scrutinizer ignore-type */ false, 2);
Loading history...
478
            $morph = Loader::parseName($trace[1]['function']);
479
        }
480
481
        $type = $type ?: get_class($this);
482
483
        if (is_array($morph)) {
484
            list($morphType, $foreignKey) = $morph;
485
        } else {
486
            $morphType  = $morph . '_type';
487
            $foreignKey = $morph . '_id';
488
        }
489
490
        return new MorphMany($this, $model, $foreignKey, $morphType, $type);
491
    }
492
493
    /**
494
     * MORPH TO 关联定义
495
     * @access public
496
     * @param  string|array $morph 多态字段信息
497
     * @param  array        $alias 多态别名定义
498
     * @return MorphTo
499
     */
500
    public function morphTo($morph = null, $alias = [])
501
    {
502
        $trace    = debug_backtrace(false, 2);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $options of debug_backtrace(). ( Ignorable by Annotation )

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

502
        $trace    = debug_backtrace(/** @scrutinizer ignore-type */ false, 2);
Loading history...
503
        $relation = Loader::parseName($trace[1]['function']);
504
505
        if (is_null($morph)) {
506
            $morph = $relation;
507
        }
508
509
        // 记录当前关联信息
510
        if (is_array($morph)) {
511
            list($morphType, $foreignKey) = $morph;
512
        } else {
513
            $morphType  = $morph . '_type';
514
            $foreignKey = $morph . '_id';
515
        }
516
517
        return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
518
    }
519
520
    /**
521
     * 解析模型的完整命名空间
522
     * @access protected
523
     * @param  string $model 模型名(或者完整类名)
524
     * @return string
525
     */
526
    protected function parseModel($model)
527
    {
528
        if (false === strpos($model, '\\')) {
529
            $path = explode('\\', static::class);
530
            array_pop($path);
531
            array_push($path, Loader::parseName($model, 1));
532
            $model = implode('\\', $path);
533
        }
534
535
        return $model;
536
    }
537
538
    /**
539
     * 获取模型的默认外键名
540
     * @access protected
541
     * @param  string $name 模型名
542
     * @return string
543
     */
544
    protected function getForeignKey($name)
545
    {
546
        if (strpos($name, '\\')) {
547
            $name = basename(str_replace('\\', '/', $name));
548
        }
549
550
        return Loader::parseName($name) . '_id';
551
    }
552
553
    /**
554
     * 检查属性是否为关联属性 如果是则返回关联方法名
555
     * @access protected
556
     * @param  string $attr 关联属性名
557
     * @return string|false
558
     */
559
    protected function isRelationAttr($attr)
560
    {
561
        $relation = Loader::parseName($attr, 1, false);
562
563
        if (method_exists($this, $relation) && !method_exists('think\Model', $relation)) {
564
            return $relation;
565
        }
566
567
        return false;
568
    }
569
570
    /**
571
     * 智能获取关联模型数据
572
     * @access protected
573
     * @param  Relation  $modelRelation 模型关联对象
574
     * @return mixed
575
     */
576
    protected function getRelationData(Relation $modelRelation)
577
    {
578
        if ($this->parent && !$modelRelation->isSelfRelation() && get_class($this->parent) == get_class($modelRelation->getModel())) {
579
            $value = $this->parent;
580
        } else {
581
            // 获取关联数据
582
            $value = $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

582
            /** @scrutinizer ignore-call */ 
583
            $value = $modelRelation->getRelation();
Loading history...
583
        }
584
585
        return $value;
586
    }
587
588
    /**
589
     * 关联数据自动写入检查
590
     * @access protected
591
     * @return void
592
     */
593
    protected function checkAutoRelationWrite()
594
    {
595
        foreach ($this->together as $key => $name) {
596
            if (is_array($name)) {
597
                if (key($name) === 0) {
598
                    $this->relationWrite[$key] = [];
599
                    // 绑定关联属性
600
                    foreach ((array) $name as $val) {
601
                        if (isset($this->data[$val])) {
602
                            $this->relationWrite[$key][$val] = $this->data[$val];
603
                        }
604
                    }
605
                } else {
606
                    // 直接传入关联数据
607
                    $this->relationWrite[$key] = $name;
608
                }
609
            } elseif (isset($this->relation[$name])) {
610
                $this->relationWrite[$name] = $this->relation[$name];
611
            } elseif (isset($this->data[$name])) {
612
                $this->relationWrite[$name] = $this->data[$name];
613
                unset($this->data[$name]);
614
            }
615
        }
616
    }
617
618
    /**
619
     * 自动关联数据更新(针对一对一关联)
620
     * @access protected
621
     * @return void
622
     */
623
    protected function autoRelationUpdate()
624
    {
625
        foreach ($this->relationWrite as $name => $val) {
626
            if ($val instanceof Model) {
627
                $val->isUpdate()->save();
628
            } else {
629
                $model = $this->getRelation($name);
630
                if ($model instanceof Model) {
631
                    $model->isUpdate()->save($val);
632
                }
633
            }
634
        }
635
    }
636
637
    /**
638
     * 自动关联数据写入(针对一对一关联)
639
     * @access protected
640
     * @return void
641
     */
642
    protected function autoRelationInsert()
643
    {
644
        foreach ($this->relationWrite as $name => $val) {
645
            $method = Loader::parseName($name, 1, false);
646
            $this->$method()->save($val);
647
        }
648
    }
649
650
    /**
651
     * 自动关联数据删除(支持一对一及一对多关联)
652
     * @access protected
653
     * @return void
654
     */
655
    protected function autoRelationDelete()
656
    {
657
        foreach ($this->relationWrite as $key => $name) {
658
            $name   = is_numeric($key) ? $name : $key;
659
            $result = $this->getRelation($name);
660
661
            if ($result instanceof Model) {
662
                $result->delete();
663
            } elseif ($result instanceof Collection) {
664
                foreach ($result as $model) {
665
                    $model->delete();
666
                }
667
            }
668
        }
669
    }
670
}
671