Completed
Push — master ( 356601...b2b7ae )
by Arjay
08:01
created

QueryBuilderEngine::getNullsLastSql()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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