Completed
Push — 6.0 ( 6faeca...d95081 )
by liu
02:54
created

HasManyThrough::eagerlyWhere()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 4
nop 5
dl 0
loc 21
ccs 0
cts 11
cp 0
crap 12
rs 9.9332
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
12
namespace think\model\relation;
13
14
use Closure;
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
22
/**
23
 * 远程一对多关联类
24
 */
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...
25
class HasManyThrough extends Relation
26
{
27
    /**
28
     * 中间关联表外键
29
     * @var string
30
     */
31
    protected $throughKey;
32
33
    /**
34
     * 中间主键
35
     * @var string
36
     */
37
    protected $throughPk;
38
39
    /**
40
     * 中间表查询对象
41
     * @var Query
42
     */
43
    protected $through;
44
45
    /**
46
     * 架构函数
47
     * @access public
48
     * @param  Model  $parent     上级模型对象
49
     * @param  string $model      模型名
50
     * @param  string $through    中间模型名
51
     * @param  string $foreignKey 关联外键
52
     * @param  string $throughKey 关联外键
53
     * @param  string $localKey   当前主键
54
     * @param  string $throughPk  中间表主键
55
     */
56
    public function __construct(Model $parent, string $model, string $through, string $foreignKey, string $throughKey, string $localKey, string $throughPk)
57
    {
58
        $this->parent     = $parent;
59
        $this->model      = $model;
60
        $this->through    = (new $through)->db();
61
        $this->foreignKey = $foreignKey;
62
        $this->throughKey = $throughKey;
63
        $this->localKey   = $localKey;
64
        $this->throughPk  = $throughPk;
65
        $this->query      = (new $model)->db();
66
    }
67
68
    /**
69
     * 延迟获取关联数据
70
     * @access public
71
     * @param  array   $subRelation 子关联名
72
     * @param  Closure $closure     闭包查询条件
73
     * @return Collection
74
     */
75
    public function getRelation(array $subRelation = [], \Closure $closure = null): Collection
76
    {
77
        if ($closure) {
78
            $closure($this->query);
79
        }
80
81
        $this->baseQuery();
82
83
        return $this->query->relation($subRelation)
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->query->rel...nt(clone $this->parent) could return the type array which is incompatible with the type-hinted return think\Collection. Consider adding an additional type-check to rule them out.
Loading history...
84
            ->select()
85
            ->setParent(clone $this->parent);
0 ignored issues
show
introduced by
The method setParent() does not exist on think\Collection. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

85
            ->/** @scrutinizer ignore-call */ setParent(clone $this->parent);
Loading history...
86
    }
87
88
    /**
89
     * 根据关联条件查询当前模型
90
     * @access public
91
     * @param  string  $operator 比较操作符
92
     * @param  integer $count    个数
93
     * @param  string  $id       关联表的统计字段
94
     * @param  string  $joinType JOIN类型
95
     * @return Query
96
     */
97
    public function has(string $operator = '>=', int $count = 1, string $id = '*', $joinType = '')
0 ignored issues
show
Unused Code introduced by
The parameter $operator is not used and could be removed. ( Ignorable by Annotation )

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

97
    public function has(/** @scrutinizer ignore-unused */ string $operator = '>=', int $count = 1, string $id = '*', $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $joinType is not used and could be removed. ( Ignorable by Annotation )

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

97
    public function has(string $operator = '>=', int $count = 1, string $id = '*', /** @scrutinizer ignore-unused */ $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $id is not used and could be removed. ( Ignorable by Annotation )

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

97
    public function has(string $operator = '>=', int $count = 1, /** @scrutinizer ignore-unused */ string $id = '*', $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $count is not used and could be removed. ( Ignorable by Annotation )

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

97
    public function has(string $operator = '>=', /** @scrutinizer ignore-unused */ int $count = 1, string $id = '*', $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
98
    {
99
        return $this->parent;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->parent returns the type think\Model which is incompatible with the documented return type think\db\Query.
Loading history...
100
    }
101
102
    /**
103
     * 根据关联条件查询当前模型
104
     * @access public
105
     * @param  mixed  $where 查询条件(数组或者闭包)
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
106
     * @param  mixed  $fields 字段
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
107
     * @param  string $joinType JOIN类型
108
     * @return Query
109
     */
110
    public function hasWhere($where = [], $fields = null, $joinType = '')
0 ignored issues
show
Unused Code introduced by
The parameter $joinType is not used and could be removed. ( Ignorable by Annotation )

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

110
    public function hasWhere($where = [], $fields = null, /** @scrutinizer ignore-unused */ $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fields is not used and could be removed. ( Ignorable by Annotation )

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

110
    public function hasWhere($where = [], /** @scrutinizer ignore-unused */ $fields = null, $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $where is not used and could be removed. ( Ignorable by Annotation )

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

110
    public function hasWhere(/** @scrutinizer ignore-unused */ $where = [], $fields = null, $joinType = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
    {
112
        throw new Exception('relation not support: hasWhere');
113
    }
114
115
    /**
116
     * 预载入关联查询(数据集)
117
     * @access protected
118
     * @param  array   $resultSet   数据集
119
     * @param  string  $relation    当前关联名
120
     * @param  array   $subRelation 子关联名
121
     * @param  Closure $closure     闭包
122
     * @return void
123
     */
124
    public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null): void
125
    {
126
        $localKey   = $this->localKey;
127
        $foreignKey = $this->foreignKey;
128
129
        $range = [];
130
        foreach ($resultSet as $result) {
131
            // 获取关联外键列表
132
            if (isset($result->$localKey)) {
133
                $range[] = $result->$localKey;
134
            }
135
        }
136
137
        if (!empty($range)) {
138
            $this->query->removeWhereField($foreignKey);
139
140
            $data = $this->eagerlyWhere([
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
141
                [$this->foreignKey, 'in', $range],
142
            ], $foreignKey, $relation, $subRelation, $closure);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
143
144
            // 关联属性名
145
            $attr = App::parseName($relation);
146
147
            // 关联数据封装
148
            foreach ($resultSet as $result) {
149
                $pk = $result->$localKey;
150
                if (!isset($data[$pk])) {
151
                    $data[$pk] = [];
152
                }
153
154
                // 设置关联属性
155
                $result->setRelation($attr, $this->resultSetBuild($data[$pk], clone $this->parent));
156
            }
157
        }
158
    }
159
160
    /**
161
     * 预载入关联查询(数据)
162
     * @access protected
163
     * @param  Model   $result      数据对象
164
     * @param  string  $relation    当前关联名
165
     * @param  array   $subRelation 子关联名
166
     * @param  Closure $closure     闭包
167
     * @return void
168
     */
169
    public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null): void
170
    {
171
        $localKey   = $this->localKey;
172
        $foreignKey = $this->foreignKey;
173
        $pk         = $result->$localKey;
174
175
        $this->query->removeWhereField($foreignKey);
176
177
        $data = $this->eagerlyWhere([
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
178
            [$foreignKey, '=', $pk],
179
        ], $foreignKey, $relation, $subRelation, $closure);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
180
181
        // 关联数据封装
182
        if (!isset($data[$pk])) {
183
            $data[$pk] = [];
184
        }
185
186
        $result->setRelation(App::parseName($relation), $this->resultSetBuild($data[$pk], clone $this->parent));
187
    }
188
189
    /**
190
     * 关联模型预查询
191
     * @access public
192
     * @param  array   $where       关联预查询条件
193
     * @param  string  $key         关联键名
194
     * @param  string  $relation    关联名
195
     * @param  array   $subRelation 子关联
196
     * @param  Closure $closure
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
197
     * @return array
198
     */
199
    protected function eagerlyWhere(array $where, string $key, string $relation, array $subRelation = [], Closure $closure = null)
0 ignored issues
show
Unused Code introduced by
The parameter $relation is not used and could be removed. ( Ignorable by Annotation )

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

199
    protected function eagerlyWhere(array $where, string $key, /** @scrutinizer ignore-unused */ string $relation, array $subRelation = [], Closure $closure = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $subRelation is not used and could be removed. ( Ignorable by Annotation )

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

199
    protected function eagerlyWhere(array $where, string $key, string $relation, /** @scrutinizer ignore-unused */ array $subRelation = [], Closure $closure = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

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

199
    protected function eagerlyWhere(array $where, /** @scrutinizer ignore-unused */ string $key, string $relation, array $subRelation = [], Closure $closure = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
200
    {
201
        // 预载入关联查询 支持嵌套预载入
202
        $throughList = $this->through->where($where)->select();
203
        $keys        = $throughList->column($this->throughPk, $this->throughPk);
204
205
        if ($closure) {
206
            $closure($this->query);
207
        }
208
209
        $list = $this->query->where($this->throughKey, 'in', $keys)->select();
210
211
        // 组装模型数据
212
        $data = [];
213
        $keys = $throughList->column($this->foreignKey, $this->throughPk);
214
215
        foreach ($list as $set) {
216
            $data[$keys[$set->{$this->throughKey}]][] = $set;
217
        }
218
219
        return $data;
220
    }
221
222
    /**
223
     * 关联统计
224
     * @access public
225
     * @param  Model   $result  数据对象
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 2 found
Loading history...
226
     * @param  Closure $closure 闭包
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 1 found
Loading history...
227
     * @param  string  $aggregate 聚合查询方法
228
     * @param  string  $field 字段
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
229
     * @return integer
230
     */
231
    public function relationCount(Model $result, Closure $closure, string $aggregate = 'count', string $field = '*')
0 ignored issues
show
Unused Code introduced by
The parameter $closure is not used and could be removed. ( Ignorable by Annotation )

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

231
    public function relationCount(Model $result, /** @scrutinizer ignore-unused */ Closure $closure, string $aggregate = 'count', string $field = '*')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $aggregate is not used and could be removed. ( Ignorable by Annotation )

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

231
    public function relationCount(Model $result, Closure $closure, /** @scrutinizer ignore-unused */ string $aggregate = 'count', string $field = '*')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $field is not used and could be removed. ( Ignorable by Annotation )

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

231
    public function relationCount(Model $result, Closure $closure, string $aggregate = 'count', /** @scrutinizer ignore-unused */ string $field = '*')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $result is not used and could be removed. ( Ignorable by Annotation )

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

231
    public function relationCount(/** @scrutinizer ignore-unused */ Model $result, Closure $closure, string $aggregate = 'count', string $field = '*')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
232
    {}
0 ignored issues
show
Coding Style introduced by
Closing brace must be on a line by itself
Loading history...
233
234
    /**
235
     * 执行基础查询(仅执行一次)
236
     * @access protected
237
     * @return void
238
     */
239
    protected function baseQuery(): void
240
    {
241
        if (empty($this->baseQuery) && $this->parent->getData()) {
242
            $alias        = App::parseName(App::classBaseName($this->model));
243
            $throughTable = $this->through->getTable();
244
            $pk           = $this->throughPk;
245
            $throughKey   = $this->throughKey;
246
            $modelTable   = $this->parent->getTable();
0 ignored issues
show
Bug introduced by
The method getTable() 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

246
            /** @scrutinizer ignore-call */ 
247
            $modelTable   = $this->parent->getTable();
Loading history...
247
            $fields       = $this->getQueryFields($alias);
248
249
            $this->query
250
                ->field($fields)
251
                ->alias($alias)
252
                ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey)
253
                ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey)
254
                ->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey});
255
256
            $this->baseQuery = true;
257
        }
258
    }
259
260
}
261