Completed
Push — master ( 3660c3...7e35c8 )
by Arjay
06:44
created

QueryBuilderEngine::castColumn()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 9
rs 9.6666
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace Yajra\Datatables\Engines;
4
5
use Closure;
6
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
7
use Illuminate\Database\Query\Builder;
8
use Illuminate\Support\Str;
9
use Yajra\Datatables\Helper;
10
use Yajra\Datatables\Request;
11
12
/**
13
 * Class QueryBuilderEngine.
14
 *
15
 * @package Yajra\Datatables\Engines
16
 * @author  Arjay Angeles <[email protected]>
17
 */
18
class QueryBuilderEngine extends BaseEngine
19
{
20
    /**
21
     * @param \Illuminate\Database\Query\Builder $builder
22
     * @param \Yajra\Datatables\Request $request
23
     */
24
    public function __construct(Builder $builder, Request $request)
25
    {
26
        $this->query = $builder;
27
        $this->init($request, $builder);
28
    }
29
30
    /**
31
     * Initialize attributes.
32
     *
33
     * @param  \Yajra\Datatables\Request $request
34
     * @param  \Illuminate\Database\Query\Builder $builder
35
     * @param  string $type
36
     */
37
    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...
38
    {
39
        $this->request    = $request;
40
        $this->query_type = $type;
41
        $this->columns    = $builder->columns;
42
        $this->connection = $builder->getConnection();
43
        $this->prefix     = $this->connection->getTablePrefix();
44
        $this->database   = $this->connection->getDriverName();
45
        if ($this->isDebugging()) {
46
            $this->connection->enableQueryLog();
47
        }
48
    }
49
50
    /**
51
     * Set auto filter off and run your own filter.
52
     * Overrides global search
53
     *
54
     * @param \Closure $callback
55
     * @return $this
56
     */
57
    public function filter(Closure $callback)
58
    {
59
        $this->overrideGlobalSearch($callback, $this->query);
60
61
        return $this;
62
    }
63
64
    /**
65
     * Organizes works
66
     *
67
     * @param bool $mDataSupport
68
     * @param bool $orderFirst
69
     * @return \Illuminate\Http\JsonResponse
70
     */
71
    public function make($mDataSupport = false, $orderFirst = false)
72
    {
73
        return parent::make($mDataSupport, $orderFirst);
74
    }
75
76
    /**
77
     * Count total items.
78
     *
79
     * @return integer
80
     */
81
    public function totalCount()
82
    {
83
        return $this->count();
84
    }
85
86
    /**
87
     * Counts current query.
88
     *
89
     * @return int
90
     */
91
    public function count()
92
    {
93
        $myQuery = clone $this->query;
94
        // if its a normal query ( no union, having and distinct word )
95
        // replace the select with static text to improve performance
96
        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...
97
            $row_count = $this->connection->getQueryGrammar()->wrap('row_count');
98
            $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...
99
        }
100
101
        return $this->connection->table($this->connection->raw('(' . $myQuery->toSql() . ') count_row_table'))
102
                                ->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...
103
    }
104
105
    /**
106
     * Perform global search.
107
     *
108
     * @return void
109
     */
110
    public function filtering()
111
    {
112
        $this->query->where(
113
            function ($query) {
114
                $globalKeyword = $this->setupKeyword($this->request->keyword());
115
                $queryBuilder  = $this->getQueryBuilder($query);
116
117
                foreach ($this->request->searchableColumnIndex() as $index) {
118
                    $columnName = $this->getColumnName($index);
119
                    if ($this->isBlacklisted($columnName)) {
120
                        continue;
121
                    }
122
123
                    // check if custom column filtering is applied
124
                    if (isset($this->columnDef['filter'][$columnName])) {
125
                        $columnDef = $this->columnDef['filter'][$columnName];
126
                        // check if global search should be applied for the specific column
127
                        $applyGlobalSearch = count($columnDef['parameters']) == 0 || end($columnDef['parameters']) !== false;
128
                        if (! $applyGlobalSearch) {
129
                            continue;
130
                        }
131
132
                        if ($columnDef['method'] instanceof Closure) {
133
                            $whereQuery = $queryBuilder->newQuery();
134
                            call_user_func_array($columnDef['method'], [$whereQuery, $this->request->keyword()]);
135
                            $queryBuilder->addNestedWhereQuery($whereQuery, 'or');
136
                        } else {
137
                            $this->compileColumnQuery(
138
                                $queryBuilder,
139
                                Helper::getOrMethod($columnDef['method']),
140
                                $columnDef['parameters'],
141
                                $columnName,
142
                                $this->request->keyword()
143
                            );
144
                        }
145
                    } else {
146
                        if (count(explode('.', $columnName)) > 1) {
147
                            $eagerLoads     = $this->getEagerLoads();
148
                            $parts          = explode('.', $columnName);
149
                            $relationColumn = array_pop($parts);
150
                            $relation       = implode('.', $parts);
151
                            if (in_array($relation, $eagerLoads)) {
152
                                $this->compileRelationSearch(
153
                                    $queryBuilder,
154
                                    $relation,
155
                                    $relationColumn,
156
                                    $globalKeyword
157
                                );
158
                            } else {
159
                                $this->compileGlobalSearch($queryBuilder, $columnName, $globalKeyword);
160
                            }
161
                        } else {
162
                            $this->compileGlobalSearch($queryBuilder, $columnName, $globalKeyword);
163
                        }
164
                    }
165
166
                    $this->isFilterApplied = true;
167
                }
168
            }
169
        );
170
    }
171
172
    /**
173
     * Perform filter column on selected field.
174
     *
175
     * @param mixed $query
176
     * @param string|Closure $method
177
     * @param mixed $parameters
178
     * @param string $column
179
     * @param string $keyword
180
     */
181
    protected function compileColumnQuery($query, $method, $parameters, $column, $keyword)
182
    {
183
        if (method_exists($query, $method)
184
            && count($parameters) <= with(new \ReflectionMethod($query, $method))->getNumberOfParameters()
185
        ) {
186
            if (Str::contains(Str::lower($method), 'raw')
0 ignored issues
show
Bug introduced by
It seems like $method defined by parameter $method on line 181 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...
187
                || Str::contains(Str::lower($method), 'exists')
0 ignored issues
show
Bug introduced by
It seems like $method defined by parameter $method on line 181 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
            ) {
189
                call_user_func_array(
190
                    [$query, $method],
191
                    $this->parameterize($parameters, $keyword)
192
                );
193
            } else {
194
                call_user_func_array(
195
                    [$query, $method],
196
                    $this->parameterize($column, $parameters, $keyword)
197
                );
198
            }
199
        }
200
    }
201
202
    /**
203
     * Build Query Builder Parameters.
204
     *
205
     * @return array
206
     */
207
    protected function parameterize()
208
    {
209
        $args       = func_get_args();
210
        $keyword    = count($args) > 2 ? $args[2] : $args[1];
211
        $parameters = Helper::buildParameters($args);
212
        $parameters = Helper::replacePatternWithKeyword($parameters, $keyword, '$1');
213
214
        return $parameters;
215
    }
216
217
    /**
218
     * Get eager loads keys if eloquent.
219
     *
220
     * @return array
221
     */
222
    protected function getEagerLoads()
223
    {
224
        if ($this->query_type == 'eloquent') {
225
            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...
226
        }
227
228
        return [];
229
    }
230
231
    /**
232
     * Add relation query on global search.
233
     *
234
     * @param mixed $query
235
     * @param string $relation
236
     * @param string $column
237
     * @param string $keyword
238
     */
239
    protected function compileRelationSearch($query, $relation, $column, $keyword)
240
    {
241
        $myQuery = clone $this->query;
242
        $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...
243
            $sql = $q->select($this->connection->raw('count(1)'))
244
                     ->where($column, 'like', $keyword)
245
                     ->toSql();
246
            $sql = "($sql) >= 1";
247
            $query->orWhereRaw($sql, [$keyword]);
248
        });
249
    }
250
251
    /**
252
     * Add a query on global search.
253
     *
254
     * @param mixed $query
255
     * @param string $column
256
     * @param string $keyword
257
     */
258
    protected function compileGlobalSearch($query, $column, $keyword)
259
    {
260
        if ($this->isSmartSearch()) {
261
            $column = $this->castColumn($column);
262
            $sql    = $column . ' LIKE ?';
263
            if ($this->isCaseInsensitive()) {
264
                $sql     = 'LOWER(' . $column . ') LIKE ?';
265
                $keyword = Str::lower($keyword);
266
            }
267
268
            $query->orWhereRaw($sql, [$keyword]);
269
        } else { // exact match
270
            $query->orWhereRaw("$column like ?", [$keyword]);
271
        }
272
    }
273
274
    /**
275
     * Wrap a column and cast in pgsql.
276
     *
277
     * @param  string $column
278
     * @return string
279
     */
280
    public function castColumn($column)
281
    {
282
        $column = $this->connection->getQueryGrammar()->wrap($column);
283
        if ($this->database === 'pgsql') {
284
            $column = 'CAST(' . $column . ' as TEXT)';
285
        }
286
287
        return $column;
288
    }
289
290
    /**
291
     * Perform column search.
292
     *
293
     * @return void
294
     */
295
    public function columnSearch()
296
    {
297
        $columns = $this->request->get('columns', []);
298
299
        foreach ($columns as $index => $column) {
300
            if (! $this->request->isColumnSearchable($index)) {
301
                continue;
302
            }
303
304
            $column = $this->getColumnName($index);
305
306
            if (isset($this->columnDef['filter'][$column])) {
307
                $columnDef = $this->columnDef['filter'][$column];
308
                // get a raw keyword (without wildcards)
309
                $keyword = $this->getSearchKeyword($index, true);
310
                $builder = $this->getQueryBuilder();
311
312
                if ($columnDef['method'] instanceof Closure) {
313
                    $whereQuery = $builder->newQuery();
314
                    call_user_func_array($columnDef['method'], [$whereQuery, $keyword]);
315
                    $builder->addNestedWhereQuery($whereQuery);
316
                } else {
317
                    $this->compileColumnQuery(
318
                        $builder,
319
                        $columnDef['method'],
320
                        $columnDef['parameters'],
321
                        $column,
322
                        $keyword
323
                    );
324
                }
325
            } else {
326 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...
327
                    $eagerLoads     = $this->getEagerLoads();
328
                    $parts          = explode('.', $column);
329
                    $relationColumn = array_pop($parts);
330
                    $relation       = implode('.', $parts);
331
                    if (in_array($relation, $eagerLoads)) {
332
                        $column = $this->joinEagerLoadedColumn($relation, $relationColumn);
333
                    }
334
                }
335
336
                $column          = $this->castColumn($column);
337
                $keyword         = $this->getSearchKeyword($index);
338
                $caseInsensitive = $this->isCaseInsensitive();
339
340
                if (! $caseInsensitive) {
341
                    $column = strstr($column, '(') ? $this->connection->raw($column) : $column;
342
                }
343
344
                $this->compileColumnSearch($index, $column, $keyword, $caseInsensitive);
345
            }
346
347
            $this->isFilterApplied = true;
348
        }
349
    }
350
351
    /**
352
     * Get proper keyword to use for search.
353
     *
354
     * @param int $i
355
     * @param bool $raw
356
     * @return string
357
     */
358
    private function getSearchKeyword($i, $raw = false)
359
    {
360
        $keyword = $this->request->columnKeyword($i);
361
        if ($raw || $this->request->isRegex($i)) {
362
            return $keyword;
363
        }
364
365
        return $this->setupKeyword($keyword);
366
    }
367
368
    /**
369
     * Compile queries for column search.
370
     *
371
     * @param int $i
372
     * @param mixed $column
373
     * @param string $keyword
374
     * @param bool $caseSensitive
375
     */
376
    protected function compileColumnSearch($i, $column, $keyword, $caseSensitive = true)
377
    {
378
        if ($this->request->isRegex($i)) {
379
            $this->regexColumnSearch($column, $keyword, $caseSensitive);
380
        } elseif ($this->isSmartSearch()) {
381
            $sql     = $caseSensitive ? $column . ' LIKE ?' : 'LOWER(' . $column . ') LIKE ?';
382
            $keyword = $caseSensitive ? $keyword : Str::lower($keyword);
383
            $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...
384
        } else { // exact match
385
            $this->query->whereRaw("$column LIKE ?", [$keyword]);
386
        }
387
    }
388
389
    /**
390
     * Compile regex query column search.
391
     *
392
     * @param mixed $column
393
     * @param string $keyword
394
     * @param bool $caseSensitive
395
     */
396
    protected function regexColumnSearch($column, $keyword, $caseSensitive = true)
397
    {
398
        if ($this->isOracleSql()) {
399
            $sql = $caseSensitive ? 'REGEXP_LIKE( ' . $column . ' , ? )' : 'REGEXP_LIKE( LOWER(' . $column . ') , ?, \'i\' )';
400
            $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...
401
        } else {
402
            $sql = $caseSensitive ? $column . ' REGEXP ?' : 'LOWER(' . $column . ') REGEXP ?';
403
            $this->query->whereRaw($sql, [Str::lower($keyword)]);
404
        }
405
    }
406
407
    /**
408
     * Perform sorting of columns.
409
     *
410
     * @return void
411
     */
412
    public function ordering()
413
    {
414
        if ($this->orderCallback) {
415
            call_user_func($this->orderCallback, $this->getQueryBuilder());
416
417
            return;
418
        }
419
420
        foreach ($this->request->orderableColumns() as $orderable) {
421
            $column = $this->getColumnName($orderable['column'], true);
422
423
            if ($this->isBlacklisted($column)) {
424
                continue;
425
            }
426
427
            if (isset($this->columnDef['order'][$column])) {
428
                $method     = $this->columnDef['order'][$column]['method'];
429
                $parameters = $this->columnDef['order'][$column]['parameters'];
430
                $this->compileColumnQuery(
431
                    $this->getQueryBuilder(),
432
                    $method,
433
                    $parameters,
434
                    $column,
435
                    $orderable['direction']
436
                );
437
            } else {
438 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...
439
                    $eagerLoads     = $this->getEagerLoads();
440
                    $parts          = explode('.', $column);
441
                    $relationColumn = array_pop($parts);
442
                    $relation       = implode('.', $parts);
443
444
                    if (in_array($relation, $eagerLoads)) {
445
                        $column = $this->joinEagerLoadedColumn($relation, $relationColumn);
446
                    }
447
                }
448
449
                $this->getQueryBuilder()->orderBy($column, $orderable['direction']);
450
            }
451
        }
452
    }
453
454
    /**
455
     * Join eager loaded relation and get the related column name.
456
     *
457
     * @param string $relation
458
     * @param string $relationColumn
459
     * @return string
460
     */
461
    protected function joinEagerLoadedColumn($relation, $relationColumn)
462
    {
463
        $joins = [];
464
        foreach ((array) $this->getQueryBuilder()->joins as $key => $join) {
465
            $joins[] = $join->table;
466
        }
467
468
        $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...
469
        if ($model instanceof BelongsToMany) {
470
            $pivot   = $model->getTable();
471
            $pivotPK = $model->getForeignKey();
472
            $pivotFK = $model->getQualifiedParentKeyName();
473
474
            if (! in_array($pivot, $joins)) {
475
                $this->getQueryBuilder()->leftJoin($pivot, $pivotPK, '=', $pivotFK);
476
            }
477
478
            $related = $model->getRelated();
479
            $table   = $related->getTable();
480
            $tablePK = $related->getForeignKey();
481
            $tableFK = $related->getQualifiedKeyName();
482
483
            if (! in_array($table, $joins)) {
484
                $this->getQueryBuilder()->leftJoin($table, $pivot . '.' . $tablePK, '=', $tableFK);
485
            }
486
        } else {
487
            $table   = $model->getRelated()->getTable();
488
            $foreign = $model->getQualifiedForeignKey();
489
            $other   = $model->getQualifiedOtherKeyName();
490
            if (! in_array($table, $joins)) {
491
                $this->getQueryBuilder()->leftJoin($table, $foreign, '=', $other);
492
            }
493
        }
494
495
        $column = $table . '.' . $relationColumn;
496
497
        return $column;
498
    }
499
500
    /**
501
     * Perform pagination
502
     *
503
     * @return void
504
     */
505
    public function paging()
506
    {
507
        $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...
508
                    ->take((int) $this->request['length'] > 0 ? $this->request['length'] : 10);
509
    }
510
511
    /**
512
     * Get results
513
     *
514
     * @return array|static[]
515
     */
516
    public function results()
517
    {
518
        return $this->query->get();
519
    }
520
}
521