Completed
Push — master ( ebf51c...4d883b )
by Arjay
03:50
created

QueryBuilderEngine::prepareKeyword()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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