This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Sofa\Eloquence; |
||
4 | |||
5 | use Illuminate\Database\Eloquent\Collection; |
||
6 | use Illuminate\Support\Str; |
||
7 | use Sofa\Eloquence\Contracts\Relations\Joiner; |
||
8 | use Sofa\Eloquence\Searchable\Column; |
||
9 | use Illuminate\Database\Query\Expression; |
||
10 | use Sofa\Hookable\Builder as HookableBuilder; |
||
11 | use Sofa\Eloquence\Searchable\ColumnCollection; |
||
12 | use Sofa\Eloquence\Contracts\Relations\JoinerFactory; |
||
13 | use Sofa\Eloquence\Contracts\Searchable\ParserFactory; |
||
14 | use Illuminate\Database\Query\Grammars\PostgresGrammar; |
||
15 | use Sofa\Eloquence\Searchable\Subquery as SearchableSubquery; |
||
16 | |||
17 | /** |
||
18 | * @method $this leftJoin($table, $one, $operator, $two) |
||
19 | */ |
||
20 | class Builder extends HookableBuilder |
||
21 | { |
||
22 | /** |
||
23 | * Parser factory instance. |
||
24 | * |
||
25 | * @var ParserFactory |
||
26 | */ |
||
27 | protected static $parser; |
||
28 | |||
29 | /** |
||
30 | * Joiner factory instance. |
||
31 | * |
||
32 | * @var JoinerFactory |
||
33 | */ |
||
34 | protected static $joinerFactory; |
||
35 | |||
36 | /** |
||
37 | * Relations joiner instance. |
||
38 | * |
||
39 | * @var Joiner |
||
40 | */ |
||
41 | protected $joiner; |
||
42 | |||
43 | /* |
||
44 | |-------------------------------------------------------------------------- |
||
45 | | Additional features |
||
46 | |-------------------------------------------------------------------------- |
||
47 | */ |
||
48 | |||
49 | /** |
||
50 | * Execute the query as a "select" statement. |
||
51 | * |
||
52 | * @param array $columns |
||
53 | * @return Collection |
||
54 | */ |
||
55 | public function get($columns = ['*']) |
||
56 | { |
||
57 | if ($this->query->from instanceof Subquery) { |
||
58 | $this->wheresToSubquery($this->query->from); |
||
59 | } |
||
60 | |||
61 | return parent::get($columns); |
||
0 ignored issues
–
show
Bug
Compatibility
introduced
by
![]() |
|||
62 | } |
||
63 | |||
64 | /** |
||
65 | * Search through any columns on current table or any defined relations |
||
66 | * and return results ordered by search relevance. |
||
67 | * |
||
68 | * @param array|string $query |
||
69 | * @param array $columns |
||
70 | * @param bool $fulltext |
||
71 | * @param float $threshold |
||
72 | * @return $this |
||
73 | */ |
||
74 | public function search($query, $columns = null, $fulltext = true, $threshold = null) |
||
75 | { |
||
76 | if (is_bool($columns)) { |
||
77 | list($fulltext, $columns) = [$columns, []]; |
||
78 | } |
||
79 | |||
80 | $parser = static::$parser->make(); |
||
81 | |||
82 | $words = is_array($query) ? $query : $parser->parseQuery($query, $fulltext); |
||
83 | |||
84 | $columns = $parser->parseWeights($columns ?: $this->model->getSearchableColumns()); |
||
85 | |||
86 | if (count($words) && count($columns)) { |
||
87 | $this->query->from($this->buildSubquery($words, $columns, $threshold)); |
||
88 | } |
||
89 | |||
90 | return $this; |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Build the search subquery. |
||
95 | * |
||
96 | * @param array $words |
||
97 | * @param array $mappings |
||
98 | * @param float $threshold |
||
99 | * @return SearchableSubquery |
||
100 | */ |
||
101 | protected function buildSubquery(array $words, array $mappings, $threshold) |
||
102 | { |
||
103 | $subquery = new SearchableSubquery($this->query->newQuery(), $this->model->getTable()); |
||
104 | |||
105 | $columns = $this->joinForSearch($mappings, $subquery); |
||
106 | |||
107 | $threshold = (is_null($threshold)) |
||
108 | ? array_sum($columns->getWeights()) / 4 |
||
109 | : (float) $threshold; |
||
110 | |||
111 | $subquery->select($this->model->getTable() . '.*') |
||
0 ignored issues
–
show
The method
select does not exist on object<Sofa\Eloquence\Searchable\Subquery> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
112 | ->from($this->model->getTable()) |
||
113 | ->groupBy($this->model->getQualifiedKeyName()); |
||
114 | |||
115 | $this->addSearchClauses($subquery, $columns, $words, $threshold); |
||
116 | |||
117 | return $subquery; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Add select and where clauses on the subquery. |
||
122 | * |
||
123 | * @param SearchableSubquery $subquery |
||
124 | * @param ColumnCollection $columns |
||
125 | * @param array $words |
||
126 | * @param float $threshold |
||
127 | * @return void |
||
128 | */ |
||
129 | protected function addSearchClauses( |
||
130 | SearchableSubquery $subquery, |
||
131 | ColumnCollection $columns, |
||
132 | array $words, |
||
133 | $threshold |
||
134 | ) { |
||
135 | $whereBindings = $this->searchSelect($subquery, $columns, $words, $threshold); |
||
0 ignored issues
–
show
The call to
Builder::searchSelect() has too many arguments starting with $threshold .
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. In this case you can add the ![]() |
|||
136 | |||
137 | // For morphOne/morphMany support we need to port the bindings from JoinClauses. |
||
138 | $joinBindings = collect($subquery->getQuery()->joins)->flatMap(function ($join) { |
||
139 | return $join->getBindings(); |
||
140 | })->all(); |
||
141 | |||
142 | $this->addBinding($joinBindings, 'select'); |
||
0 ignored issues
–
show
The method
addBinding does not exist on object<Sofa\Eloquence\Builder> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
143 | |||
144 | // Developer may want to skip the score threshold filtering by passing zero |
||
145 | // value as threshold in order to simply order full result by relevance. |
||
146 | // Otherwise we are going to add where clauses for speed improvement. |
||
147 | if ($threshold > 0) { |
||
148 | $this->searchWhere($subquery, $columns, $words, $whereBindings); |
||
149 | } |
||
150 | |||
151 | $this->query->where('relevance', '>=', new Expression(number_format($threshold, 2))); |
||
152 | |||
153 | $this->query->orders = array_merge( |
||
154 | [['column' => 'relevance', 'direction' => 'desc']], |
||
155 | (array) $this->query->orders |
||
156 | ); |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Apply relevance select on the subquery. |
||
161 | * |
||
162 | * @param SearchableSubquery $subquery |
||
163 | * @param ColumnCollection $columns |
||
164 | * @param array $words |
||
165 | * @return array |
||
166 | */ |
||
167 | protected function searchSelect(SearchableSubquery $subquery, ColumnCollection $columns, array $words) |
||
168 | { |
||
169 | $cases = $bindings = []; |
||
170 | |||
171 | foreach ($columns as $column) { |
||
172 | list($cases[], $binding) = $this->buildCase($column, $words); |
||
173 | |||
174 | $bindings = array_merge_recursive($bindings, $binding); |
||
175 | } |
||
176 | |||
177 | $select = implode(' + ', $cases); |
||
178 | |||
179 | $subquery->selectRaw("max({$select}) as relevance"); |
||
0 ignored issues
–
show
The method
selectRaw does not exist on object<Sofa\Eloquence\Searchable\Subquery> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
180 | |||
181 | $this->addBinding($bindings['select'], 'select'); |
||
0 ignored issues
–
show
The method
addBinding does not exist on object<Sofa\Eloquence\Builder> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
182 | |||
183 | return $bindings['where']; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Apply where clauses on the subquery. |
||
188 | * |
||
189 | * @param SearchableSubquery $subquery |
||
190 | * @param ColumnCollection $columns |
||
191 | * @param array $words |
||
192 | * @return void |
||
193 | */ |
||
194 | protected function searchWhere( |
||
195 | SearchableSubquery $subquery, |
||
196 | ColumnCollection $columns, |
||
197 | array $words, |
||
198 | array $bindings |
||
199 | ) { |
||
200 | $operator = $this->getLikeOperator(); |
||
201 | |||
202 | $wheres = []; |
||
203 | |||
204 | foreach ($columns as $column) { |
||
205 | $wheres[] = implode( |
||
206 | ' or ', |
||
207 | array_fill(0, count($words), sprintf('%s %s ?', $column->getWrapped(), $operator)) |
||
208 | ); |
||
209 | } |
||
210 | |||
211 | $where = implode(' or ', $wheres); |
||
212 | |||
213 | $subquery->whereRaw("({$where})"); |
||
0 ignored issues
–
show
The method
whereRaw does not exist on object<Sofa\Eloquence\Searchable\Subquery> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
214 | |||
215 | $this->addBinding($bindings, 'select'); |
||
0 ignored issues
–
show
The method
addBinding does not exist on object<Sofa\Eloquence\Builder> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
![]() |
|||
216 | } |
||
217 | |||
218 | /** |
||
219 | * Move where clauses to subquery to improve performance. |
||
220 | * |
||
221 | * @param SearchableSubquery $subquery |
||
222 | * @return void |
||
223 | */ |
||
224 | protected function wheresToSubquery(SearchableSubquery $subquery) |
||
225 | { |
||
226 | $bindingKey = 0; |
||
227 | |||
228 | $typesToMove = [ |
||
229 | 'basic', 'in', 'notin', 'between', 'null', |
||
230 | 'notnull', 'date', 'day', 'month', 'year', |
||
231 | ]; |
||
232 | |||
233 | // Here we are going to move all the where clauses that we might apply |
||
234 | // on the subquery in order to improve performance, since this way |
||
235 | // we can drastically reduce number of joined rows on subquery. |
||
236 | foreach ((array) $this->query->wheres as $key => $where) { |
||
237 | $type = strtolower($where['type']); |
||
238 | |||
239 | $bindingsCount = $this->countBindings($where, $type); |
||
240 | |||
241 | if (in_array($type, $typesToMove) && $this->model->hasColumn($where['column'])) { |
||
242 | unset($this->query->wheres[$key]); |
||
243 | |||
244 | $where['column'] = $this->model->getTable() . '.' . $where['column']; |
||
245 | |||
246 | $subquery->getQuery()->wheres[] = $where; |
||
247 | |||
248 | $whereBindings = $this->query->getRawBindings()['where']; |
||
249 | |||
250 | $bindings = array_splice($whereBindings, $bindingKey, $bindingsCount); |
||
251 | |||
252 | $this->query->setBindings($whereBindings, 'where'); |
||
253 | |||
254 | $this->query->addBinding($bindings, 'select'); |
||
255 | |||
256 | // if where is not to be moved onto the subquery, let's increment |
||
257 | // binding key appropriately, so we can reliably move binding |
||
258 | // for the next where clauses in the loop that is running. |
||
259 | } else { |
||
260 | $bindingKey += $bindingsCount; |
||
261 | } |
||
262 | } |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * Get number of bindings provided for a where clause. |
||
267 | * |
||
268 | * @param array $where |
||
269 | * @param string $type |
||
270 | * @return int |
||
271 | */ |
||
272 | protected function countBindings(array $where, $type) |
||
273 | { |
||
274 | if ($this->isHasWhere($where, $type)) { |
||
275 | return substr_count($where['column'] . $where['value'], '?'); |
||
276 | } elseif ($type === 'basic') { |
||
277 | return (int) !$where['value'] instanceof Expression; |
||
278 | } elseif (in_array($type, ['basic', 'date', 'year', 'month', 'day'])) { |
||
279 | return (int) !$where['value'] instanceof Expression; |
||
280 | } elseif (in_array($type, ['null', 'notnull'])) { |
||
281 | return 0; |
||
282 | } elseif ($type === 'between') { |
||
283 | return 2; |
||
284 | } elseif (in_array($type, ['in', 'notin'])) { |
||
285 | return count($where['values']); |
||
286 | } elseif ($type === 'raw') { |
||
287 | return substr_count($where['sql'], '?'); |
||
288 | } elseif (in_array($type, ['nested', 'sub', 'exists', 'notexists', 'insub', 'notinsub'])) { |
||
289 | return count($where['query']->getBindings()); |
||
290 | } |
||
291 | } |
||
292 | |||
293 | /** |
||
294 | * Determine whether where clause is eloquent has subquery. |
||
295 | * |
||
296 | * @param array $where |
||
297 | * @param string $type |
||
298 | * @return bool |
||
299 | */ |
||
300 | protected function isHasWhere($where, $type) |
||
301 | { |
||
302 | return $type === 'basic' |
||
303 | && $where['column'] instanceof Expression |
||
304 | && $where['value'] instanceof Expression; |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Build case clause from all words for a single column. |
||
309 | * |
||
310 | * @param Column $column |
||
311 | * @param array $words |
||
312 | * @return array |
||
313 | */ |
||
314 | protected function buildCase(Column $column, array $words) |
||
315 | { |
||
316 | // THIS IS BAD |
||
317 | // @todo refactor |
||
318 | |||
319 | $operator = $this->getLikeOperator(); |
||
320 | |||
321 | $bindings['select'] = $bindings['where'] = array_map(function ($word) { |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$bindings was never initialized. Although not strictly required by PHP, it is generally a good practice to add $bindings = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
322 | return $this->caseBinding($word); |
||
323 | }, $words); |
||
324 | |||
325 | $case = $this->buildEqualsCase($column, $words); |
||
326 | |||
327 | if (strpos(implode('', $words), '*') !== false) { |
||
328 | $leftMatching = []; |
||
329 | |||
330 | View Code Duplication | foreach ($words as $key => $word) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
331 | if ($this->isLeftMatching($word)) { |
||
332 | $leftMatching[] = sprintf('%s %s ?', $column->getWrapped(), $operator); |
||
333 | $bindings['select'][] = $bindings['where'][$key] = $this->caseBinding($word) . '%'; |
||
334 | } |
||
335 | } |
||
336 | |||
337 | View Code Duplication | if (count($leftMatching)) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
338 | $leftMatching = implode(' or ', $leftMatching); |
||
339 | $score = 5 * $column->getWeight(); |
||
340 | $case .= " + case when {$leftMatching} then {$score} else 0 end"; |
||
341 | } |
||
342 | |||
343 | $wildcards = []; |
||
344 | |||
345 | View Code Duplication | foreach ($words as $key => $word) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
346 | if ($this->isWildcard($word)) { |
||
347 | $wildcards[] = sprintf('%s %s ?', $column->getWrapped(), $operator); |
||
348 | $bindings['select'][] = $bindings['where'][$key] = '%' . $this->caseBinding($word) . '%'; |
||
349 | } |
||
350 | } |
||
351 | |||
352 | View Code Duplication | if (count($wildcards)) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
353 | $wildcards = implode(' or ', $wildcards); |
||
354 | $score = 1 * $column->getWeight(); |
||
355 | $case .= " + case when {$wildcards} then {$score} else 0 end"; |
||
356 | } |
||
357 | } |
||
358 | |||
359 | return [$case, $bindings]; |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * Replace '?' with single character SQL wildcards. |
||
364 | * |
||
365 | * @param string $word |
||
366 | * @return string |
||
367 | */ |
||
368 | protected function caseBinding($word) |
||
369 | { |
||
370 | $parser = static::$parser->make(); |
||
371 | |||
372 | return str_replace('?', '_', $parser->stripWildcards($word)); |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * Build basic search case for 'equals' comparison. |
||
377 | * |
||
378 | * @param Column $column |
||
379 | * @param array $words |
||
380 | * @return string |
||
381 | */ |
||
382 | protected function buildEqualsCase(Column $column, array $words) |
||
383 | { |
||
384 | $equals = implode(' or ', array_fill(0, count($words), sprintf('%s = ?', $column->getWrapped()))); |
||
385 | |||
386 | $score = 15 * $column->getWeight(); |
||
387 | |||
388 | return "case when {$equals} then {$score} else 0 end"; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Determine whether word ends with wildcard. |
||
393 | * |
||
394 | * @param string $word |
||
395 | * @return bool |
||
396 | */ |
||
397 | protected function isLeftMatching($word) |
||
398 | { |
||
399 | return Str::endsWith($word, '*'); |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Determine whether word starts and ends with wildcards. |
||
404 | * |
||
405 | * @param string $word |
||
406 | * @return bool |
||
407 | */ |
||
408 | protected function isWildcard($word) |
||
409 | { |
||
410 | return Str::endsWith($word, '*') && Str::startsWith($word, '*'); |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Get driver-specific case insensitive like operator. |
||
415 | * |
||
416 | * @return string |
||
417 | */ |
||
418 | public function getLikeOperator() |
||
419 | { |
||
420 | $grammar = $this->query->getGrammar(); |
||
421 | |||
422 | if ($grammar instanceof PostgresGrammar) { |
||
423 | return 'ilike'; |
||
424 | } |
||
425 | |||
426 | return 'like'; |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * Join related tables on the search subquery. |
||
431 | * |
||
432 | * @param array $mappings |
||
433 | * @param SearchableSubquery $subquery |
||
434 | * @return ColumnCollection |
||
435 | */ |
||
436 | protected function joinForSearch($mappings, $subquery) |
||
437 | { |
||
438 | $mappings = is_array($mappings) ? $mappings : (array) $mappings; |
||
439 | |||
440 | $columns = new ColumnCollection; |
||
441 | |||
442 | $grammar = $this->query->getGrammar(); |
||
443 | |||
444 | $joiner = static::$joinerFactory->make($subquery->getQuery(), $this->model); |
||
445 | |||
446 | // Here we loop through the search mappings in order to join related tables |
||
447 | // appropriately and build a searchable column collection, which we will |
||
448 | // use to build select and where clauses with correct table prefixes. |
||
449 | foreach ($mappings as $mapping => $weight) { |
||
450 | if (strpos($mapping, '.') !== false) { |
||
451 | list($relation, $column) = $this->model->parseMappedColumn($mapping); |
||
452 | |||
453 | $related = $joiner->leftJoin($relation); |
||
454 | |||
455 | $columns->add( |
||
456 | new Column($grammar, $related->getTable(), $column, $mapping, $weight) |
||
457 | ); |
||
458 | } else { |
||
459 | $columns->add( |
||
460 | new Column($grammar, $this->model->getTable(), $mapping, $mapping, $weight) |
||
461 | ); |
||
462 | } |
||
463 | } |
||
464 | |||
465 | return $columns; |
||
466 | } |
||
467 | |||
468 | /** |
||
469 | * Prefix selected columns with table name in order to avoid collisions. |
||
470 | * |
||
471 | * @return $this |
||
472 | */ |
||
473 | public function prefixColumnsForJoin() |
||
474 | { |
||
475 | if (!$columns = $this->query->columns) { |
||
476 | return $this->select($this->model->getTable() . '.*'); |
||
477 | } |
||
478 | |||
479 | foreach ($columns as $key => $column) { |
||
480 | if ($this->model->hasColumn($column)) { |
||
481 | $columns[$key] = $this->model->getTable() . '.' . $column; |
||
482 | } |
||
483 | } |
||
484 | |||
485 | $this->query->columns = $columns; |
||
486 | |||
487 | return $this; |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * Join related tables. |
||
492 | * |
||
493 | * @param array|string $relations |
||
494 | * @param string $type |
||
495 | * @return $this |
||
496 | */ |
||
497 | public function joinRelations($relations, $type = 'inner') |
||
498 | { |
||
499 | if (is_null($this->joiner)) { |
||
500 | $this->joiner = static::$joinerFactory->make($this); |
||
0 ignored issues
–
show
$this is of type this<Sofa\Eloquence\Builder> , but the function expects a object<Illuminate\Database\Query\Builder> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
501 | } |
||
502 | |||
503 | if (!is_array($relations)) { |
||
504 | list($relations, $type) = [func_get_args(), 'inner']; |
||
505 | } |
||
506 | |||
507 | foreach ($relations as $relation) { |
||
508 | $this->joiner->join($relation, $type); |
||
509 | } |
||
510 | |||
511 | return $this; |
||
512 | } |
||
513 | |||
514 | /** |
||
515 | * Left join related tables. |
||
516 | * |
||
517 | * @param array|string $relations |
||
518 | * @return $this |
||
519 | */ |
||
520 | public function leftJoinRelations($relations) |
||
521 | { |
||
522 | $relations = is_array($relations) ? $relations : func_get_args(); |
||
523 | |||
524 | return $this->joinRelations($relations, 'left'); |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * Right join related tables. |
||
529 | * |
||
530 | * @param array|string $relations |
||
531 | * @return $this |
||
532 | */ |
||
533 | public function rightJoinRelations($relations) |
||
534 | { |
||
535 | $relations = is_array($relations) ? $relations : func_get_args(); |
||
536 | |||
537 | return $this->joinRelations($relations, 'right'); |
||
538 | } |
||
539 | |||
540 | /** |
||
541 | * Set search query parser factory instance. |
||
542 | * |
||
543 | * @param ParserFactory $factory |
||
544 | */ |
||
545 | public static function setParserFactory(ParserFactory $factory) |
||
546 | { |
||
547 | static::$parser = $factory; |
||
548 | } |
||
549 | |||
550 | /** |
||
551 | * Set the relations joiner factory instance. |
||
552 | * |
||
553 | * @param JoinerFactory $factory |
||
554 | */ |
||
555 | public static function setJoinerFactory(JoinerFactory $factory) |
||
556 | { |
||
557 | static::$joinerFactory = $factory; |
||
558 | } |
||
559 | } |
||
560 |