Completed
Push — master ( e68595...6e0959 )
by Arjay
03:12
created

QueryBuilderEngine::joinEagerLoadedColumn()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 44
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
cc 7
eloc 29
c 4
b 2
f 0
nc 16
nop 2
dl 0
loc 44
rs 6.7272
1
<?php
2
3
namespace Yajra\Datatables\Engines;
4
5
use Closure;
6
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
7
use Illuminate\Database\Eloquent\Relations\HasOne;
8
use Illuminate\Database\Query\Builder;
9
use Illuminate\Support\Str;
10
use Yajra\Datatables\Helper;
11
use Yajra\Datatables\Request;
12
13
/**
14
 * Class QueryBuilderEngine.
15
 *
16
 * @package Yajra\Datatables\Engines
17
 * @author  Arjay Angeles <[email protected]>
18
 */
19
class QueryBuilderEngine extends BaseEngine
20
{
21
    /**
22
     * @param \Illuminate\Database\Query\Builder $builder
23
     * @param \Yajra\Datatables\Request $request
24
     */
25
    public function __construct(Builder $builder, Request $request)
26
    {
27
        $this->query = $builder;
28
        $this->init($request, $builder);
29
    }
30
31
    /**
32
     * Initialize attributes.
33
     *
34
     * @param  \Yajra\Datatables\Request $request
35
     * @param  \Illuminate\Database\Query\Builder $builder
36
     * @param  string $type
37
     */
38
    protected function init($request, $builder, $type = 'builder')
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
39
    {
40
        $this->request    = $request;
41
        $this->query_type = $type;
42
        $this->columns    = $builder->columns;
43
        $this->connection = $builder->getConnection();
44
        $this->prefix     = $this->connection->getTablePrefix();
45
        $this->database   = $this->connection->getDriverName();
46
        if ($this->isDebugging()) {
47
            $this->connection->enableQueryLog();
48
        }
49
    }
50
51
    /**
52
     * Set auto filter off and run your own filter.
53
     * Overrides global search
54
     *
55
     * @param \Closure $callback
56
     * @return $this
57
     */
58
    public function filter(Closure $callback)
59
    {
60
        $this->overrideGlobalSearch($callback, $this->query);
61
62
        return $this;
63
    }
64
65
    /**
66
     * Organizes works
67
     *
68
     * @param bool $mDataSupport
69
     * @param bool $orderFirst
70
     * @return \Illuminate\Http\JsonResponse
71
     */
72
    public function make($mDataSupport = false, $orderFirst = false)
73
    {
74
        return parent::make($mDataSupport, $orderFirst);
75
    }
76
77
    /**
78
     * Count total items.
79
     *
80
     * @return integer
81
     */
82
    public function totalCount()
83
    {
84
        return $this->count();
85
    }
86
87
    /**
88
     * Counts current query.
89
     *
90
     * @return int
91
     */
92
    public function count()
93
    {
94
        $myQuery = clone $this->query;
95
        // if its a normal query ( no union, having and distinct word )
96
        // replace the select with static text to improve performance
97
        if (! Str::contains(Str::lower($myQuery->toSql()), ['union', 'having', 'distinct', 'order by', 'group by'])) {
0 ignored issues
show
Bug introduced by
The method toSql does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
98
            $row_count = $this->connection->getQueryGrammar()->wrap('row_count');
99
            $myQuery->select($this->connection->raw("'1' as {$row_count}"));
0 ignored issues
show
Bug introduced by
The method select does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
100
        }
101
102
        return $this->connection->table($this->connection->raw('(' . $myQuery->toSql() . ') count_row_table'))
103
                                ->setBindings($myQuery->getBindings())->count();
0 ignored issues
show
Bug introduced by
The method getBindings does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
104
    }
105
106
    /**
107
     * Perform global search.
108
     *
109
     * @return void
110
     */
111
    public function filtering()
112
    {
113
        $this->query->where(
114
            function ($query) {
115
                $globalKeyword = $this->setupKeyword($this->request->keyword());
116
                $queryBuilder  = $this->getQueryBuilder($query);
117
118
                foreach ($this->request->searchableColumnIndex() as $index) {
119
                    $columnName = $this->getColumnName($index);
120
                    if ($this->isBlacklisted($columnName)) {
121
                        continue;
122
                    }
123
124
                    // check if custom column filtering is applied
125
                    if (isset($this->columnDef['filter'][$columnName])) {
126
                        $columnDef = $this->columnDef['filter'][$columnName];
127
                        // check if global search should be applied for the specific column
128
                        $applyGlobalSearch = count($columnDef['parameters']) == 0 || end($columnDef['parameters']) !== false;
129
                        if (! $applyGlobalSearch) {
130
                            continue;
131
                        }
132
133
                        if ($columnDef['method'] instanceof Closure) {
134
                            $whereQuery = $queryBuilder->newQuery();
135
                            call_user_func_array($columnDef['method'], [$whereQuery, $this->request->keyword()]);
136
                            $queryBuilder->addNestedWhereQuery($whereQuery, 'or');
137
                        } else {
138
                            $this->compileColumnQuery(
139
                                $queryBuilder,
140
                                Helper::getOrMethod($columnDef['method']),
141
                                $columnDef['parameters'],
142
                                $columnName,
143
                                $this->request->keyword()
144
                            );
145
                        }
146
                    } else {
147
                        if (count(explode('.', $columnName)) > 1) {
148
                            $eagerLoads     = $this->getEagerLoads();
149
                            $parts          = explode('.', $columnName);
150
                            $relationColumn = array_pop($parts);
151
                            $relation       = implode('.', $parts);
152
                            if (in_array($relation, $eagerLoads)) {
153
                                $this->compileRelationSearch(
154
                                    $queryBuilder,
155
                                    $relation,
156
                                    $relationColumn,
157
                                    $globalKeyword
158
                                );
159
                            } else {
160
                                $this->compileGlobalSearch($queryBuilder, $columnName, $globalKeyword);
161
                            }
162
                        } else {
163
                            $this->compileGlobalSearch($queryBuilder, $columnName, $globalKeyword);
164
                        }
165
                    }
166
167
                    $this->isFilterApplied = true;
168
                }
169
            }
170
        );
171
    }
172
173
    /**
174
     * Perform filter column on selected field.
175
     *
176
     * @param mixed $query
177
     * @param string|Closure $method
178
     * @param mixed $parameters
179
     * @param string $column
180
     * @param string $keyword
181
     */
182
    protected function compileColumnQuery($query, $method, $parameters, $column, $keyword)
183
    {
184
        if (method_exists($query, $method)
185
            && count($parameters) <= with(new \ReflectionMethod($query, $method))->getNumberOfParameters()
186
        ) {
187
            if (Str::contains(Str::lower($method), 'raw')
0 ignored issues
show
Bug introduced by
It seems like $method defined by parameter $method on line 182 can also be of type object<Closure>; however, Illuminate\Support\Str::lower() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
188
                || Str::contains(Str::lower($method), 'exists')
0 ignored issues
show
Bug introduced by
It seems like $method defined by parameter $method on line 182 can also be of type object<Closure>; however, Illuminate\Support\Str::lower() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
189
            ) {
190
                call_user_func_array(
191
                    [$query, $method],
192
                    $this->parameterize($parameters, $keyword)
193
                );
194
            } else {
195
                call_user_func_array(
196
                    [$query, $method],
197
                    $this->parameterize($column, $parameters, $keyword)
198
                );
199
            }
200
        }
201
    }
202
203
    /**
204
     * Build Query Builder Parameters.
205
     *
206
     * @return array
207
     */
208
    protected function parameterize()
209
    {
210
        $args       = func_get_args();
211
        $keyword    = count($args) > 2 ? $args[2] : $args[1];
212
        $parameters = Helper::buildParameters($args);
213
        $parameters = Helper::replacePatternWithKeyword($parameters, $keyword, '$1');
214
215
        return $parameters;
216
    }
217
218
    /**
219
     * Get eager loads keys if eloquent.
220
     *
221
     * @return array
222
     */
223
    protected function getEagerLoads()
224
    {
225
        if ($this->query_type == 'eloquent') {
226
            return array_keys($this->query->getEagerLoads());
0 ignored issues
show
Bug introduced by
The method getEagerLoads does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Query\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
227
        }
228
229
        return [];
230
    }
231
232
    /**
233
     * Add relation query on global search.
234
     *
235
     * @param mixed $query
236
     * @param string $relation
237
     * @param string $column
238
     * @param string $keyword
239
     */
240
    protected function compileRelationSearch($query, $relation, $column, $keyword)
241
    {
242
        $myQuery = clone $this->query;
243
        $myQuery->orWhereHas($relation, function ($q) use ($column, $keyword, $query) {
0 ignored issues
show
Bug introduced by
The method orWhereHas does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Query\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
244
            $sql = $q->select($this->connection->raw('count(1)'))
245
                     ->where($column, 'like', $keyword)
246
                     ->toSql();
247
            $sql = "($sql) >= 1";
248
            $query->orWhereRaw($sql, [$keyword]);
249
        });
250
    }
251
252
    /**
253
     * Add a query on global search.
254
     *
255
     * @param mixed $query
256
     * @param string $column
257
     * @param string $keyword
258
     */
259
    protected function compileGlobalSearch($query, $column, $keyword)
260
    {
261
        if ($this->isSmartSearch()) {
262
            $column = $this->castColumn($column);
263
            $sql    = $column . ' LIKE ?';
264
            if ($this->isCaseInsensitive()) {
265
                $sql     = 'LOWER(' . $column . ') LIKE ?';
266
                $keyword = Str::lower($keyword);
267
            }
268
269
            $query->orWhereRaw($sql, [$keyword]);
270
        } else { // exact match
271
            $query->orWhereRaw("$column like ?", [$keyword]);
272
        }
273
    }
274
275
    /**
276
     * Wrap a column and cast in pgsql.
277
     *
278
     * @param  string $column
279
     * @return string
280
     */
281
    public function castColumn($column)
282
    {
283
        $column = $this->connection->getQueryGrammar()->wrap($column);
284
        if ($this->database === 'pgsql') {
285
            $column = 'CAST(' . $column . ' as TEXT)';
286
        } elseif ($this->database === 'firebird') {
287
            $column = 'CAST(' . $column . ' as VARCHAR(255))';
288
        }
289
290
        return $column;
291
    }
292
293
    /**
294
     * Perform column search.
295
     *
296
     * @return void
297
     */
298
    public function columnSearch()
299
    {
300
        $columns = $this->request->get('columns', []);
301
302
        foreach ($columns as $index => $column) {
303
            if (! $this->request->isColumnSearchable($index)) {
304
                continue;
305
            }
306
307
            $column = $this->getColumnName($index);
308
309
            if (isset($this->columnDef['filter'][$column])) {
310
                $columnDef = $this->columnDef['filter'][$column];
311
                // get a raw keyword (without wildcards)
312
                $keyword = $this->getSearchKeyword($index, true);
313
                $builder = $this->getQueryBuilder();
314
315
                if ($columnDef['method'] instanceof Closure) {
316
                    $whereQuery = $builder->newQuery();
317
                    call_user_func_array($columnDef['method'], [$whereQuery, $keyword]);
318
                    $builder->addNestedWhereQuery($whereQuery);
319
                } else {
320
                    $this->compileColumnQuery(
321
                        $builder,
322
                        $columnDef['method'],
323
                        $columnDef['parameters'],
324
                        $column,
325
                        $keyword
326
                    );
327
                }
328
            } else {
329 View Code Duplication
                if (count(explode('.', $column)) > 1) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
330
                    $eagerLoads     = $this->getEagerLoads();
331
                    $parts          = explode('.', $column);
332
                    $relationColumn = array_pop($parts);
333
                    $relation       = implode('.', $parts);
334
                    if (in_array($relation, $eagerLoads)) {
335
                        $column = $this->joinEagerLoadedColumn($relation, $relationColumn);
336
                    }
337
                }
338
339
                $column          = $this->castColumn($column);
340
                $keyword         = $this->getSearchKeyword($index);
341
                $caseInsensitive = $this->isCaseInsensitive();
342
343
                if (! $caseInsensitive) {
344
                    $column = strstr($column, '(') ? $this->connection->raw($column) : $column;
345
                }
346
347
                $this->compileColumnSearch($index, $column, $keyword, $caseInsensitive);
348
            }
349
350
            $this->isFilterApplied = true;
351
        }
352
    }
353
354
    /**
355
     * Get proper keyword to use for search.
356
     *
357
     * @param int $i
358
     * @param bool $raw
359
     * @return string
360
     */
361
    private function getSearchKeyword($i, $raw = false)
362
    {
363
        $keyword = $this->request->columnKeyword($i);
364
        if ($raw || $this->request->isRegex($i)) {
365
            return $keyword;
366
        }
367
368
        return $this->setupKeyword($keyword);
369
    }
370
371
    /**
372
     * Compile queries for column search.
373
     *
374
     * @param int $i
375
     * @param mixed $column
376
     * @param string $keyword
377
     * @param bool $caseSensitive
378
     */
379
    protected function compileColumnSearch($i, $column, $keyword, $caseSensitive = true)
380
    {
381
        if ($this->request->isRegex($i)) {
382
            $this->regexColumnSearch($column, $keyword, $caseSensitive);
383
        } elseif ($this->isSmartSearch()) {
384
            $sql     = $caseSensitive ? $column . ' LIKE ?' : 'LOWER(' . $column . ') LIKE ?';
385
            $keyword = $caseSensitive ? $keyword : Str::lower($keyword);
386
            $this->query->whereRaw($sql, [$keyword]);
0 ignored issues
show
Bug introduced by
The method whereRaw does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
387
        } else { // exact match
388
            $this->query->whereRaw("$column LIKE ?", [$keyword]);
389
        }
390
    }
391
392
    /**
393
     * Compile regex query column search.
394
     *
395
     * @param mixed $column
396
     * @param string $keyword
397
     * @param bool $caseSensitive
398
     */
399
    protected function regexColumnSearch($column, $keyword, $caseSensitive = true)
400
    {
401
        if ($this->isOracleSql()) {
402
            $sql = $caseSensitive ? 'REGEXP_LIKE( ' . $column . ' , ? )' : 'REGEXP_LIKE( LOWER(' . $column . ') , ?, \'i\' )';
403
            $this->query->whereRaw($sql, [$keyword]);
0 ignored issues
show
Bug introduced by
The method whereRaw does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
404
        } else {
405
            $sql = $caseSensitive ? $column . ' REGEXP ?' : 'LOWER(' . $column . ') REGEXP ?';
406
            $this->query->whereRaw($sql, [Str::lower($keyword)]);
407
        }
408
    }
409
410
    /**
411
     * Perform sorting of columns.
412
     *
413
     * @return void
414
     */
415
    public function ordering()
416
    {
417
        if ($this->orderCallback) {
418
            call_user_func($this->orderCallback, $this->getQueryBuilder());
419
420
            return;
421
        }
422
423
        foreach ($this->request->orderableColumns() as $orderable) {
424
            $column = $this->getColumnName($orderable['column'], true);
425
426
            if ($this->isBlacklisted($column)) {
427
                continue;
428
            }
429
430
            if (isset($this->columnDef['order'][$column])) {
431
                $method     = $this->columnDef['order'][$column]['method'];
432
                $parameters = $this->columnDef['order'][$column]['parameters'];
433
                $this->compileColumnQuery(
434
                    $this->getQueryBuilder(),
435
                    $method,
436
                    $parameters,
437
                    $column,
438
                    $orderable['direction']
439
                );
440
            } else {
441 View Code Duplication
                if (count(explode('.', $column)) > 1) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
442
                    $eagerLoads     = $this->getEagerLoads();
443
                    $parts          = explode('.', $column);
444
                    $relationColumn = array_pop($parts);
445
                    $relation       = implode('.', $parts);
446
447
                    if (in_array($relation, $eagerLoads)) {
448
                        $column = $this->joinEagerLoadedColumn($relation, $relationColumn);
449
                    }
450
                }
451
452
                $this->getQueryBuilder()->orderBy($column, $orderable['direction']);
453
            }
454
        }
455
    }
456
457
    /**
458
     * Join eager loaded relation and get the related column name.
459
     *
460
     * @param string $relation
461
     * @param string $relationColumn
462
     * @return string
463
     */
464
    protected function joinEagerLoadedColumn($relation, $relationColumn)
465
    {
466
        $joins = [];
467
        foreach ((array) $this->getQueryBuilder()->joins as $key => $join) {
468
            $joins[] = $join->table;
469
        }
470
471
        $model = $this->query->getRelation($relation);
0 ignored issues
show
Bug introduced by
The method getRelation does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Query\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
472
        if ($model instanceof BelongsToMany) {
473
            $pivot   = $model->getTable();
474
            $pivotPK = $model->getForeignKey();
475
            $pivotFK = $model->getQualifiedParentKeyName();
476
477
            if (! in_array($pivot, $joins)) {
478
                $this->getQueryBuilder()->leftJoin($pivot, $pivotPK, '=', $pivotFK);
479
            }
480
481
            $related = $model->getRelated();
482
            $table   = $related->getTable();
483
            $tablePK = $related->getForeignKey();
484
            $tableFK = $related->getQualifiedKeyName();
485
486
            if (! in_array($table, $joins)) {
487
                $this->getQueryBuilder()->leftJoin($table, $pivot . '.' . $tablePK, '=', $tableFK);
488
            }
489
        } else {
490
            $table = $model->getRelated()->getTable();
491
            if ($model instanceof HasOne) {
492
                $foreign = $model->getForeignKey();
493
                $other   = $model->getQualifiedParentKeyName();
494
            } else {
495
                $foreign = $model->getQualifiedForeignKey();
496
                $other   = $model->getQualifiedOtherKeyName();
497
            }
498
499
            if (! in_array($table, $joins)) {
500
                $this->getQueryBuilder()->leftJoin($table, $foreign, '=', $other);
501
            }
502
        }
503
504
        $column = $table . '.' . $relationColumn;
505
506
        return $column;
507
    }
508
509
    /**
510
     * Perform pagination
511
     *
512
     * @return void
513
     */
514
    public function paging()
515
    {
516
        $this->query->skip($this->request['start'])
0 ignored issues
show
Bug introduced by
The method skip does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
517
                    ->take((int) $this->request['length'] > 0 ? $this->request['length'] : 10);
518
    }
519
520
    /**
521
     * Get results
522
     *
523
     * @return array|static[]
524
     */
525
    public function results()
526
    {
527
        return $this->query->get();
528
    }
529
}
530