Completed
Push — master ( 6e0959...6d9a36 )
by Arjay
07:26
created

QueryBuilderEngine::columnSearch()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 48
Code Lines 32

Duplication

Lines 14
Ratio 29.17 %

Importance

Changes 11
Bugs 5 Features 2
Metric Value
cc 7
eloc 32
nc 7
nop 0
dl 14
loc 48
rs 6.7272
c 11
b 5
f 2
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->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
     * Wrap column with DB grammar.
108
     *
109
     * @param string $column
110
     * @return string
111
     */
112
    protected function wrap($column) {
113
        return $this->connection->getQueryGrammar()->wrap($column);
114
    }
115
116
    /**
117
     * Perform global search.
118
     *
119
     * @return void
120
     */
121
    public function filtering()
122
    {
123
        $this->query->where(
124
            function ($query) {
125
                $globalKeyword = $this->setupKeyword($this->request->keyword());
126
                $queryBuilder  = $this->getQueryBuilder($query);
127
128
                foreach ($this->request->searchableColumnIndex() as $index) {
129
                    $columnName = $this->getColumnName($index);
130
                    if ($this->isBlacklisted($columnName)) {
131
                        continue;
132
                    }
133
134
                    // check if custom column filtering is applied
135
                    if (isset($this->columnDef['filter'][$columnName])) {
136
                        $columnDef = $this->columnDef['filter'][$columnName];
137
                        // check if global search should be applied for the specific column
138
                        $applyGlobalSearch = count($columnDef['parameters']) == 0 || end($columnDef['parameters']) !== false;
139
                        if (! $applyGlobalSearch) {
140
                            continue;
141
                        }
142
143
                        if ($columnDef['method'] instanceof Closure) {
144
                            $whereQuery = $queryBuilder->newQuery();
145
                            call_user_func_array($columnDef['method'], [$whereQuery, $this->request->keyword()]);
146
                            $queryBuilder->addNestedWhereQuery($whereQuery, 'or');
147
                        } else {
148
                            $this->compileColumnQuery(
149
                                $queryBuilder,
150
                                Helper::getOrMethod($columnDef['method']),
151
                                $columnDef['parameters'],
152
                                $columnName,
153
                                $this->request->keyword()
154
                            );
155
                        }
156 View Code Duplication
                    } else {
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...
157
                        if (count(explode('.', $columnName)) > 1) {
158
                            $eagerLoads     = $this->getEagerLoads();
159
                            $parts          = explode('.', $columnName);
160
                            $relationColumn = array_pop($parts);
161
                            $relation       = implode('.', $parts);
162
                            if (in_array($relation, $eagerLoads)) {
163
                                $this->compileRelationSearch(
164
                                    $queryBuilder,
165
                                    $relation,
166
                                    $relationColumn,
167
                                    $globalKeyword
168
                                );
169
                            } else {
170
                                $this->compileQuerySearch($queryBuilder, $columnName, $globalKeyword);
171
                            }
172
                        } else {
173
                            $this->compileQuerySearch($queryBuilder, $columnName, $globalKeyword);
174
                        }
175
                    }
176
177
                    $this->isFilterApplied = true;
178
                }
179
            }
180
        );
181
    }
182
183
    /**
184
     * Perform filter column on selected field.
185
     *
186
     * @param mixed $query
187
     * @param string|Closure $method
188
     * @param mixed $parameters
189
     * @param string $column
190
     * @param string $keyword
191
     */
192
    protected function compileColumnQuery($query, $method, $parameters, $column, $keyword)
193
    {
194
        if (method_exists($query, $method)
195
            && count($parameters) <= with(new \ReflectionMethod($query, $method))->getNumberOfParameters()
196
        ) {
197
            if (Str::contains(Str::lower($method), 'raw')
0 ignored issues
show
Bug introduced by
It seems like $method defined by parameter $method on line 192 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...
198
                || Str::contains(Str::lower($method), 'exists')
0 ignored issues
show
Bug introduced by
It seems like $method defined by parameter $method on line 192 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...
199
            ) {
200
                call_user_func_array(
201
                    [$query, $method],
202
                    $this->parameterize($parameters, $keyword)
203
                );
204
            } else {
205
                call_user_func_array(
206
                    [$query, $method],
207
                    $this->parameterize($column, $parameters, $keyword)
208
                );
209
            }
210
        }
211
    }
212
213
    /**
214
     * Build Query Builder Parameters.
215
     *
216
     * @return array
217
     */
218
    protected function parameterize()
219
    {
220
        $args       = func_get_args();
221
        $keyword    = count($args) > 2 ? $args[2] : $args[1];
222
        $parameters = Helper::buildParameters($args);
223
        $parameters = Helper::replacePatternWithKeyword($parameters, $keyword, '$1');
224
225
        return $parameters;
226
    }
227
228
    /**
229
     * Get eager loads keys if eloquent.
230
     *
231
     * @return array
232
     */
233
    protected function getEagerLoads()
234
    {
235
        if ($this->query_type == 'eloquent') {
236
            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...
237
        }
238
239
        return [];
240
    }
241
242
    /**
243
     * Add relation query on global search.
244
     *
245
     * @param mixed $query
246
     * @param string $relation
247
     * @param string $column
248
     * @param string $keyword
249
     */
250
    protected function compileRelationSearch($query, $relation, $column, $keyword)
251
    {
252
        $myQuery = clone $this->query;
253
        $myQuery->orWhereHas($relation, function ($builder) 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...
254
            $builder->select($this->connection->raw('count(1)'));
255
            $this->compileQuerySearch($builder, $column, $keyword, '');
256
            $builder = "({$builder->toSql()}) >= 1";
257
258
            $query->orWhereRaw($builder, [$keyword]);
259
        });
260
    }
261
262
    /**
263
     * Compile query builder where clause depending on configurations.
264
     *
265
     * @param mixed $query
266
     * @param string $column
267
     * @param string $keyword
268
     * @param string $relation
269
     */
270
    protected function compileQuerySearch($query, $column, $keyword, $relation = 'or')
271
    {
272
        $column = strstr($column, '(') ? $this->connection->raw($column) : $column;
273
        $column = $this->castColumn($column);
0 ignored issues
show
Bug introduced by
It seems like $column can also be of type object<Illuminate\Database\Query\Expression>; however, Yajra\Datatables\Engines...derEngine::castColumn() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
274
        $sql    = $column . ' LIKE ?';
275
276
        if ($this->isCaseInsensitive()) {
277
            $sql     = 'LOWER(' . $column . ') LIKE ?';
278
            $keyword = Str::lower($keyword);
279
        }
280
281
        if ($this->isWildcard()) {
282
            $keyword = $this->wildcardLikeString($keyword);
283
        }
284
285
        if ($this->isSmartSearch()) {
286
            $keyword = "%$keyword%";
287
        }
288
289
        $query->{$relation .'WhereRaw'}($sql, [$keyword]);
290
    }
291
292
    /**
293
     * Wrap a column and cast in pgsql.
294
     *
295
     * @param  string $column
296
     * @return string
297
     */
298
    public function castColumn($column)
299
    {
300
        $column = $this->wrap($column);
301
        if ($this->database === 'pgsql') {
302
            $column = 'CAST(' . $column . ' as TEXT)';
303
        } elseif ($this->database === 'firebird') {
304
            $column = 'CAST(' . $column . ' as VARCHAR(255))';
305
        }
306
307
        return $column;
308
    }
309
310
    /**
311
     * Perform column search.
312
     *
313
     * @return void
314
     */
315
    public function columnSearch()
316
    {
317
        $columns = $this->request->get('columns', []);
318
319
        foreach ($columns as $index => $column) {
320
            if (! $this->request->isColumnSearchable($index)) {
321
                continue;
322
            }
323
324
            $column = $this->getColumnName($index);
325
326
            if (isset($this->columnDef['filter'][$column])) {
327
                $columnDef = $this->columnDef['filter'][$column];
328
                // get a raw keyword (without wildcards)
329
                $keyword = $this->getSearchKeyword($index, true);
330
                $builder = $this->getQueryBuilder();
331
332
                if ($columnDef['method'] instanceof Closure) {
333
                    $whereQuery = $builder->newQuery();
334
                    call_user_func_array($columnDef['method'], [$whereQuery, $keyword]);
335
                    $builder->addNestedWhereQuery($whereQuery);
336
                } else {
337
                    $this->compileColumnQuery(
338
                        $builder,
339
                        $columnDef['method'],
340
                        $columnDef['parameters'],
341
                        $column,
342
                        $keyword
343
                    );
344
                }
345 View Code Duplication
            } else {
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...
346
                if (count(explode('.', $column)) > 1) {
347
                    $eagerLoads     = $this->getEagerLoads();
348
                    $parts          = explode('.', $column);
349
                    $relationColumn = array_pop($parts);
350
                    $relation       = implode('.', $parts);
351
                    if (in_array($relation, $eagerLoads)) {
352
                        $column = $this->joinEagerLoadedColumn($relation, $relationColumn);
353
                    }
354
                }
355
356
                $keyword = $this->getSearchKeyword($index);
357
                $this->compileColumnSearch($index, $column, $keyword);
358
            }
359
360
            $this->isFilterApplied = true;
361
        }
362
    }
363
364
    /**
365
     * Get proper keyword to use for search.
366
     *
367
     * @param int $i
368
     * @param bool $raw
369
     * @return string
370
     */
371
    private function getSearchKeyword($i, $raw = false)
372
    {
373
        $keyword = $this->request->columnKeyword($i);
374
        if ($raw || $this->request->isRegex($i)) {
375
            return $keyword;
376
        }
377
378
        return $this->setupKeyword($keyword);
379
    }
380
381
    /**
382
     * Compile queries for column search.
383
     *
384
     * @param int $i
385
     * @param mixed $column
386
     * @param string $keyword
387
     */
388
    protected function compileColumnSearch($i, $column, $keyword)
389
    {
390
        if ($this->request->isRegex($i)) {
391
            $column = strstr($column, '(') ? $this->connection->raw($column) : $column;
392
            $this->regexColumnSearch($column, $keyword);
393
        } else {
394
            $this->compileQuerySearch($this->query, $column, $keyword, '');
395
        }
396
    }
397
398
    /**
399
     * Compile regex query column search.
400
     *
401
     * @param mixed $column
402
     * @param string $keyword
403
     */
404
    protected function regexColumnSearch($column, $keyword)
405
    {
406
        if ($this->isOracleSql()) {
407
            $sql = ! $this->isCaseInsensitive() ? 'REGEXP_LIKE( ' . $column . ' , ? )' : 'REGEXP_LIKE( LOWER(' . $column . ') , ?, \'i\' )';
408
            $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...
409
        } else {
410
            $sql = ! $this->isCaseInsensitive() ? $column . ' REGEXP ?' : 'LOWER(' . $column . ') REGEXP ?';
411
            $this->query->whereRaw($sql, [Str::lower($keyword)]);
412
        }
413
    }
414
415
    /**
416
     * Perform sorting of columns.
417
     *
418
     * @return void
419
     */
420
    public function ordering()
421
    {
422
        if ($this->orderCallback) {
423
            call_user_func($this->orderCallback, $this->getQueryBuilder());
424
425
            return;
426
        }
427
428
        foreach ($this->request->orderableColumns() as $orderable) {
429
            $column = $this->getColumnName($orderable['column'], true);
430
431
            if ($this->isBlacklisted($column)) {
432
                continue;
433
            }
434
435
            if (isset($this->columnDef['order'][$column])) {
436
                $method     = $this->columnDef['order'][$column]['method'];
437
                $parameters = $this->columnDef['order'][$column]['parameters'];
438
                $this->compileColumnQuery(
439
                    $this->getQueryBuilder(),
440
                    $method,
441
                    $parameters,
442
                    $column,
443
                    $orderable['direction']
444
                );
445
            } else {
446
                if (count(explode('.', $column)) > 1) {
447
                    $eagerLoads     = $this->getEagerLoads();
448
                    $parts          = explode('.', $column);
449
                    $relationColumn = array_pop($parts);
450
                    $relation       = implode('.', $parts);
451
452
                    if (in_array($relation, $eagerLoads)) {
453
                        $column = $this->joinEagerLoadedColumn($relation, $relationColumn);
454
                    }
455
                }
456
457
                $this->getQueryBuilder()->orderBy($column, $orderable['direction']);
458
            }
459
        }
460
    }
461
462
    /**
463
     * Join eager loaded relation and get the related column name.
464
     *
465
     * @param string $relation
466
     * @param string $relationColumn
467
     * @return string
468
     */
469
    protected function joinEagerLoadedColumn($relation, $relationColumn)
470
    {
471
        $joins = [];
472
        foreach ((array) $this->getQueryBuilder()->joins as $key => $join) {
473
            $joins[] = $join->table;
474
        }
475
476
        $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...
477
        if ($model instanceof BelongsToMany) {
478
            $pivot   = $model->getTable();
479
            $pivotPK = $model->getForeignKey();
480
            $pivotFK = $model->getQualifiedParentKeyName();
481
482
            if (! in_array($pivot, $joins)) {
483
                $this->getQueryBuilder()->leftJoin($pivot, $pivotPK, '=', $pivotFK);
484
            }
485
486
            $related = $model->getRelated();
487
            $table   = $related->getTable();
488
            $tablePK = $related->getForeignKey();
489
            $tableFK = $related->getQualifiedKeyName();
490
491
            if (! in_array($table, $joins)) {
492
                $this->getQueryBuilder()->leftJoin($table, $pivot . '.' . $tablePK, '=', $tableFK);
493
            }
494
        } else {
495
            $table = $model->getRelated()->getTable();
496
            if ($model instanceof HasOne) {
497
                $foreign = $model->getForeignKey();
498
                $other   = $model->getQualifiedParentKeyName();
499
            } else {
500
                $foreign = $model->getQualifiedForeignKey();
501
                $other   = $model->getQualifiedOtherKeyName();
502
            }
503
504
            if (! in_array($table, $joins)) {
505
                $this->getQueryBuilder()->leftJoin($table, $foreign, '=', $other);
506
            }
507
        }
508
509
        $column = $table . '.' . $relationColumn;
510
511
        return $column;
512
    }
513
514
    /**
515
     * Perform pagination
516
     *
517
     * @return void
518
     */
519
    public function paging()
520
    {
521
        $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...
522
                    ->take((int) $this->request['length'] > 0 ? $this->request['length'] : 10);
523
    }
524
525
    /**
526
     * Get results
527
     *
528
     * @return array|static[]
529
     */
530
    public function results()
531
    {
532
        return $this->query->get();
533
    }
534
}
535