Completed
Push — master ( 22bc8c...4e6ac6 )
by Arjay
02:26
created

BaseEngine   F

Complexity

Total Complexity 86

Size/Duplication

Total Lines 893
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 10

Importance

Changes 17
Bugs 7 Features 4
Metric Value
wmc 86
c 17
b 7
f 4
lcom 4
cbo 10
dl 0
loc 893
rs 1.263

45 Methods

Rating   Name   Duplication   Size   Complexity  
A setupKeyword() 0 15 3
A isSmartSearch() 0 4 1
A isWildcard() 0 4 1
A wildcardLikeString() 0 15 4
A prefixColumn() 0 14 2
B tableNames() 0 17 6
A getQueryBuilder() 0 12 3
A isQueryBuilder() 0 4 1
A addColumn() 0 8 1
A editColumn() 0 6 1
A removeColumn() 0 7 1
A escapeColumns() 0 6 1
A __call() 0 13 3
A setRowClass() 0 6 1
A setRowId() 0 6 1
A setRowData() 0 6 1
A addRowData() 0 6 1
A setRowAttr() 0 6 1
A addRowAttr() 0 6 1
A filterColumn() 0 7 1
A orderColumn() 0 6 1
A setTransformer() 0 6 1
A setSerializer() 0 6 1
A make() 0 13 2
A orderRecords() 0 6 2
B filterRecords() 0 13 5
A paginate() 0 6 2
B render() 0 45 6
A getProcessedData() 0 10 1
A isDebugging() 0 4 1
A showDebugger() 0 7 1
A overrideGlobalSearch() 0 7 1
A isCaseInsensitive() 0 4 1
A with() 0 12 3
A order() 0 6 1
A blacklist() 0 6 1
A whitelist() 0 6 1
A smart() 0 6 1
A isBlacklisted() 0 12 4
A getColumnName() 0 15 3
A getColumnNameByIndex() 0 6 4
A getPrimaryKeyName() 0 8 2
A isEloquent() 0 4 1
A extractColumnName() 0 18 4
A isOracleSql() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like BaseEngine often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BaseEngine, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Yajra\Datatables\Engines;
4
5
use Illuminate\Http\JsonResponse;
6
use Illuminate\Support\Facades\Config;
7
use Illuminate\Support\Str;
8
use League\Fractal\Manager;
9
use League\Fractal\Resource\Collection;
10
use League\Fractal\Serializer\DataArraySerializer;
11
use Yajra\Datatables\Contracts\DataTableEngineContract;
12
use Yajra\Datatables\Helper;
13
use Yajra\Datatables\Processors\DataProcessor;
14
15
/**
16
 * Class BaseEngine.
17
 *
18
 * @package Yajra\Datatables\Engines
19
 * @author  Arjay Angeles <[email protected]>
20
 */
21
abstract class BaseEngine implements DataTableEngineContract
22
{
23
    /**
24
     * Datatables Request object.
25
     *
26
     * @var \Yajra\Datatables\Request
27
     */
28
    public $request;
29
30
    /**
31
     * Database connection used.
32
     *
33
     * @var \Illuminate\Database\Connection
34
     */
35
    protected $connection;
36
37
    /**
38
     * Builder object.
39
     *
40
     * @var \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder
41
     */
42
    protected $query;
43
44
    /**
45
     * Query builder object.
46
     *
47
     * @var \Illuminate\Database\Query\Builder
48
     */
49
    protected $builder;
50
51
    /**
52
     * Array of result columns/fields.
53
     *
54
     * @var array
55
     */
56
    protected $columns = [];
57
58
    /**
59
     * DT columns definitions container (add/edit/remove/filter/order/escape).
60
     *
61
     * @var array
62
     */
63
    protected $columnDef = [
64
        'append'    => [],
65
        'edit'      => [],
66
        'excess'    => ['rn', 'row_num'],
67
        'filter'    => [],
68
        'order'     => [],
69
        'escape'    => [],
70
        'blacklist' => ['password', 'remember_token'],
71
        'whitelist' => '*',
72
    ];
73
74
    /**
75
     * Query type.
76
     *
77
     * @var string
78
     */
79
    protected $query_type;
80
81
    /**
82
     * Extra/Added columns.
83
     *
84
     * @var array
85
     */
86
    protected $extraColumns = [];
87
88
    /**
89
     * Total records.
90
     *
91
     * @var int
92
     */
93
    protected $totalRecords = 0;
94
95
    /**
96
     * Total filtered records.
97
     *
98
     * @var int
99
     */
100
    protected $filteredRecords = 0;
101
102
    /**
103
     * Auto-filter flag.
104
     *
105
     * @var bool
106
     */
107
    protected $autoFilter = true;
108
109
    /**
110
     * Callback to override global search.
111
     *
112
     * @var \Closure
113
     */
114
    protected $filterCallback;
115
116
    /**
117
     * Parameters to passed on filterCallback.
118
     *
119
     * @var mixed
120
     */
121
    protected $filterCallbackParameters;
122
123
    /**
124
     * DT row templates container.
125
     *
126
     * @var array
127
     */
128
    protected $templates = [
129
        'DT_RowId'    => '',
130
        'DT_RowClass' => '',
131
        'DT_RowData'  => [],
132
        'DT_RowAttr'  => [],
133
    ];
134
135
    /**
136
     * Output transformer.
137
     *
138
     * @var \League\Fractal\TransformerAbstract
139
     */
140
    protected $transformer = null;
141
142
    /**
143
     * Database prefix
144
     *
145
     * @var string
146
     */
147
    protected $prefix;
148
149
    /**
150
     * Database driver used.
151
     *
152
     * @var string
153
     */
154
    protected $database;
155
156
    /**
157
     * [internal] Track if any filter was applied for at least one column
158
     *
159
     * @var boolean
160
     */
161
    protected $isFilterApplied = false;
162
163
    /**
164
     * Fractal serializer class.
165
     *
166
     * @var string
167
     */
168
    protected $serializer;
169
170
    /**
171
     * Custom ordering callback.
172
     *
173
     * @var \Closure
174
     */
175
    protected $orderCallback;
176
177
    /**
178
     * Array of data to append on json response.
179
     *
180
     * @var array
181
     */
182
    private $appends = [];
183
184
    /**
185
     * Setup search keyword.
186
     *
187
     * @param  string $value
188
     * @return string
189
     */
190
    public function setupKeyword($value)
191
    {
192
        if ($this->isSmartSearch()) {
193
            $keyword = '%' . $value . '%';
194
            if ($this->isWildcard()) {
195
                $keyword = $this->wildcardLikeString($value);
196
            }
197
            // remove escaping slash added on js script request
198
            $keyword = str_replace('\\', '%', $keyword);
199
200
            return $keyword;
201
        }
202
203
        return $value;
204
    }
205
206
    /**
207
     * Check if DataTables uses smart search.
208
     *
209
     * @return bool
210
     */
211
    protected function isSmartSearch()
212
    {
213
        return Config::get('datatables.search.smart', true);
214
    }
215
216
    /**
217
     * Get config use wild card status.
218
     *
219
     * @return bool
220
     */
221
    public function isWildcard()
222
    {
223
        return Config::get('datatables.search.use_wildcards', false);
224
    }
225
226
    /**
227
     * Adds % wildcards to the given string.
228
     *
229
     * @param string $str
230
     * @param bool $lowercase
231
     * @return string
232
     */
233
    public function wildcardLikeString($str, $lowercase = true)
234
    {
235
        $wild   = '%';
236
        $length = strlen($str);
237
        if ($length) {
238
            for ($i = 0; $i < $length; $i++) {
239
                $wild .= $str[$i] . '%';
240
            }
241
        }
242
        if ($lowercase) {
243
            $wild = Str::lower($wild);
244
        }
245
246
        return $wild;
247
    }
248
249
    /**
250
     * Will prefix column if needed.
251
     *
252
     * @param string $column
253
     * @return string
254
     */
255
    public function prefixColumn($column)
256
    {
257
        $table_names = $this->tableNames();
258
        if (count(
259
            array_filter($table_names, function ($value) use (&$column) {
260
                return strpos($column, $value . '.') === 0;
261
            })
262
        )) {
263
            // the column starts with one of the table names
264
            $column = $this->prefix . $column;
265
        }
266
267
        return $column;
268
    }
269
270
    /**
271
     * Will look through the query and all it's joins to determine the table names.
272
     *
273
     * @return array
274
     */
275
    public function tableNames()
276
    {
277
        $names          = [];
278
        $query          = $this->getQueryBuilder();
279
        $names[]        = $query->from;
280
        $joins          = $query->joins ?: [];
281
        $databasePrefix = $this->prefix;
282
        foreach ($joins as $join) {
283
            $table   = preg_split('/ as /i', $join->table);
284
            $names[] = $table[0];
285
            if (isset($table[1]) && ! empty($databasePrefix) && strpos($table[1], $databasePrefix) == 0) {
286
                $names[] = preg_replace('/^' . $databasePrefix . '/', '', $table[1]);
287
            }
288
        }
289
290
        return $names;
291
    }
292
293
    /**
294
     * Get Query Builder object.
295
     *
296
     * @param mixed $instance
297
     * @return mixed
298
     */
299
    public function getQueryBuilder($instance = null)
300
    {
301
        if (! $instance) {
302
            $instance = $this->query;
303
        }
304
305
        if ($this->isQueryBuilder()) {
306
            return $instance;
307
        }
308
309
        return $instance->getQuery();
310
    }
311
312
    /**
313
     * Check query type is a builder.
314
     *
315
     * @return bool
316
     */
317
    public function isQueryBuilder()
318
    {
319
        return $this->query_type == 'builder';
320
    }
321
322
    /**
323
     * Add column in collection.
324
     *
325
     * @param string $name
326
     * @param string $content
327
     * @param bool|int $order
328
     * @return $this
329
     */
330
    public function addColumn($name, $content, $order = false)
331
    {
332
        $this->extraColumns[] = $name;
333
334
        $this->columnDef['append'][] = ['name' => $name, 'content' => $content, 'order' => $order];
335
336
        return $this;
337
    }
338
339
    /**
340
     * Edit column's content.
341
     *
342
     * @param string $name
343
     * @param string $content
344
     * @return $this
345
     */
346
    public function editColumn($name, $content)
347
    {
348
        $this->columnDef['edit'][] = ['name' => $name, 'content' => $content];
349
350
        return $this;
351
    }
352
353
    /**
354
     * Remove column from collection.
355
     *
356
     * @return $this
357
     */
358
    public function removeColumn()
359
    {
360
        $names                     = func_get_args();
361
        $this->columnDef['excess'] = array_merge($this->columnDef['excess'], $names);
362
363
        return $this;
364
    }
365
366
    /**
367
     * Declare columns to escape values.
368
     *
369
     * @param string|array $columns
370
     * @return $this
371
     */
372
    public function escapeColumns($columns = '*')
373
    {
374
        $this->columnDef['escape'] = $columns;
375
376
        return $this;
377
    }
378
379
    /**
380
     * Allows previous API calls where the methods were snake_case.
381
     * Will convert a camelCase API call to a snake_case call.
382
     * Allow query builder method to be used by the engine.
383
     *
384
     * @param  string $name
385
     * @param  array $arguments
386
     * @return mixed
387
     */
388
    public function __call($name, $arguments)
389
    {
390
        $name = Str::camel(Str::lower($name));
391
        if (method_exists($this, $name)) {
392
            return call_user_func_array([$this, $name], $arguments);
393
        } elseif (method_exists($this->getQueryBuilder(), $name)) {
394
            call_user_func_array([$this->getQueryBuilder(), $name], $arguments);
395
        } else {
396
            trigger_error('Call to undefined method ' . __CLASS__ . '::' . $name . '()', E_USER_ERROR);
397
        }
398
399
        return $this;
400
    }
401
402
    /**
403
     * Sets DT_RowClass template.
404
     * result: <tr class="output_from_your_template">.
405
     *
406
     * @param string|callable $content
407
     * @return $this
408
     */
409
    public function setRowClass($content)
410
    {
411
        $this->templates['DT_RowClass'] = $content;
412
413
        return $this;
414
    }
415
416
    /**
417
     * Sets DT_RowId template.
418
     * result: <tr id="output_from_your_template">.
419
     *
420
     * @param string|callable $content
421
     * @return $this
422
     */
423
    public function setRowId($content)
424
    {
425
        $this->templates['DT_RowId'] = $content;
426
427
        return $this;
428
    }
429
430
    /**
431
     * Set DT_RowData templates.
432
     *
433
     * @param array $data
434
     * @return $this
435
     */
436
    public function setRowData(array $data)
437
    {
438
        $this->templates['DT_RowData'] = $data;
439
440
        return $this;
441
    }
442
443
    /**
444
     * Add DT_RowData template.
445
     *
446
     * @param string $key
447
     * @param string|callable $value
448
     * @return $this
449
     */
450
    public function addRowData($key, $value)
451
    {
452
        $this->templates['DT_RowData'][$key] = $value;
453
454
        return $this;
455
    }
456
457
    /**
458
     * Set DT_RowAttr templates.
459
     * result: <tr attr1="attr1" attr2="attr2">.
460
     *
461
     * @param array $data
462
     * @return $this
463
     */
464
    public function setRowAttr(array $data)
465
    {
466
        $this->templates['DT_RowAttr'] = $data;
467
468
        return $this;
469
    }
470
471
    /**
472
     * Add DT_RowAttr template.
473
     *
474
     * @param string $key
475
     * @param string|callable $value
476
     * @return $this
477
     */
478
    public function addRowAttr($key, $value)
479
    {
480
        $this->templates['DT_RowAttr'][$key] = $value;
481
482
        return $this;
483
    }
484
485
    /**
486
     * Override default column filter search.
487
     *
488
     * @param string $column
489
     * @param string|Closure $method
490
     * @return $this
491
     * @internal param $mixed ...,... All the individual parameters required for specified $method
492
     * @internal string $1 Special variable that returns the requested search keyword.
493
     */
494
    public function filterColumn($column, $method)
495
    {
496
        $params                             = func_get_args();
497
        $this->columnDef['filter'][$column] = ['method' => $method, 'parameters' => array_splice($params, 2)];
498
499
        return $this;
500
    }
501
502
    /**
503
     * Override default column ordering.
504
     *
505
     * @param string $column
506
     * @param string $sql
507
     * @param array $bindings
508
     * @return $this
509
     * @internal string $1 Special variable that returns the requested order direction of the column.
510
     */
511
    public function orderColumn($column, $sql, $bindings = [])
512
    {
513
        $this->columnDef['order'][$column] = ['method' => 'orderByRaw', 'parameters' => [$sql, $bindings]];
514
515
        return $this;
516
    }
517
518
    /**
519
     * Set data output transformer.
520
     *
521
     * @param \League\Fractal\TransformerAbstract $transformer
522
     * @return $this
523
     */
524
    public function setTransformer($transformer)
525
    {
526
        $this->transformer = $transformer;
527
528
        return $this;
529
    }
530
531
    /**
532
     * Set fractal serializer class.
533
     *
534
     * @param string $serializer
535
     * @return $this
536
     */
537
    public function setSerializer($serializer)
538
    {
539
        $this->serializer = $serializer;
540
541
        return $this;
542
    }
543
544
    /**
545
     * Organizes works.
546
     *
547
     * @param bool $mDataSupport
548
     * @param bool $orderFirst
549
     * @return \Illuminate\Http\JsonResponse
550
     */
551
    public function make($mDataSupport = false, $orderFirst = false)
552
    {
553
        $this->totalRecords = $this->totalCount();
554
555
        if ($this->totalRecords) {
556
            $this->orderRecords(! $orderFirst);
557
            $this->filterRecords();
558
            $this->orderRecords($orderFirst);
559
            $this->paginate();
560
        }
561
562
        return $this->render($mDataSupport);
563
    }
564
565
    /**
566
     * Sort records.
567
     *
568
     * @param  boolean $skip
569
     * @return void
570
     */
571
    public function orderRecords($skip)
572
    {
573
        if (! $skip) {
574
            $this->ordering();
575
        }
576
    }
577
578
    /**
579
     * Perform necessary filters.
580
     *
581
     * @return void
582
     */
583
    public function filterRecords()
584
    {
585
        if ($this->autoFilter && $this->request->isSearchable()) {
586
            $this->filtering();
587
        } else {
588
            if (is_callable($this->filterCallback)) {
589
                call_user_func($this->filterCallback, $this->filterCallbackParameters);
590
            }
591
        }
592
593
        $this->columnSearch();
594
        $this->filteredRecords = $this->isFilterApplied ? $this->count() : $this->totalRecords;
595
    }
596
597
    /**
598
     * Apply pagination.
599
     *
600
     * @return void
601
     */
602
    public function paginate()
603
    {
604
        if ($this->request->isPaginationable()) {
605
            $this->paging();
606
        }
607
    }
608
609
    /**
610
     * Render json response.
611
     *
612
     * @param bool $object
613
     * @return \Illuminate\Http\JsonResponse
614
     */
615
    public function render($object = false)
616
    {
617
        $output = array_merge([
618
            'draw'            => (int) $this->request['draw'],
619
            'recordsTotal'    => $this->totalRecords,
620
            'recordsFiltered' => $this->filteredRecords,
621
        ], $this->appends);
622
623
        if (isset($this->transformer)) {
624
            $fractal = new Manager();
625
            if ($this->request->get('include')) {
626
                $fractal->parseIncludes($this->request->get('include'));
627
            }
628
629
            $serializer = $this->serializer ?: Config::get('datatables.fractal.serializer', DataArraySerializer::class);
630
            $fractal->setSerializer(new $serializer);
631
632
            //Get transformer reflection
633
            //Firs method parameter should be data/object to transform
634
            $reflection = new \ReflectionMethod($this->transformer, 'transform');
635
            $parameter  = $reflection->getParameters()[0];
636
637
            //If parameter is class assuming it requires object
638
            //Else just pass array by default
639
            if ($parameter->getClass()) {
640
                $resource = new Collection($this->results(), new $this->transformer());
641
            } else {
642
                $resource = new Collection(
643
                    $this->getProcessedData($object),
644
                    new $this->transformer()
645
                );
646
            }
647
648
            $collection     = $fractal->createData($resource)->toArray();
649
            $output['data'] = $collection['data'];
650
        } else {
651
            $output['data'] = Helper::transform($this->getProcessedData($object));
652
        }
653
654
        if ($this->isDebugging()) {
655
            $output = $this->showDebugger($output);
656
        }
657
658
        return new JsonResponse($output);
659
    }
660
661
    /**
662
     * Get processed data
663
     *
664
     * @param bool|false $object
665
     * @return array
666
     */
667
    private function getProcessedData($object = false)
668
    {
669
        $processor = new DataProcessor(
670
            $this->results(),
671
            $this->columnDef,
672
            $this->templates
673
        );
674
675
        return $processor->process($object);
676
    }
677
678
    /**
679
     * Check if app is in debug mode.
680
     *
681
     * @return bool
682
     */
683
    public function isDebugging()
684
    {
685
        return Config::get('app.debug', false);
686
    }
687
688
    /**
689
     * Append debug parameters on output.
690
     *
691
     * @param  array $output
692
     * @return array
693
     */
694
    public function showDebugger(array $output)
695
    {
696
        $output['queries'] = $this->connection->getQueryLog();
697
        $output['input']   = $this->request->all();
698
699
        return $output;
700
    }
701
702
    /**
703
     * Update flags to disable global search
704
     *
705
     * @param  \Closure $callback
706
     * @param  mixed $parameters
707
     * @return void
708
     */
709
    public function overrideGlobalSearch(\Closure $callback, $parameters)
710
    {
711
        $this->autoFilter               = false;
712
        $this->isFilterApplied          = true;
713
        $this->filterCallback           = $callback;
714
        $this->filterCallbackParameters = $parameters;
715
    }
716
717
    /**
718
     * Get config is case insensitive status.
719
     *
720
     * @return bool
721
     */
722
    public function isCaseInsensitive()
723
    {
724
        return Config::get('datatables.search.case_insensitive', false);
725
    }
726
727
    /**
728
     * Append data on json response.
729
     *
730
     * @param mixed $key
731
     * @param mixed $value
732
     * @return $this
733
     */
734
    public function with($key, $value = '')
735
    {
736
        if (is_array($key)) {
737
            $this->appends = $key;
738
        } elseif (is_callable($value)) {
739
            $this->appends[$key] = value($value);
740
        } else {
741
            $this->appends[$key] = value($value);
742
        }
743
744
        return $this;
745
    }
746
747
    /**
748
     * Override default ordering method with a closure callback.
749
     *
750
     * @param \Closure $closure
751
     * @return $this
752
     */
753
    public function order(\Closure $closure)
754
    {
755
        $this->orderCallback = $closure;
756
757
        return $this;
758
    }
759
760
    /**
761
     * Update list of columns that is not allowed for search/sort.
762
     *
763
     * @param  array $blacklist
764
     * @return $this
765
     */
766
    public function blacklist(array $blacklist)
767
    {
768
        $this->columnDef['blacklist'] = $blacklist;
769
770
        return $this;
771
    }
772
773
    /**
774
     * Update list of columns that is not allowed for search/sort.
775
     *
776
     * @param  string|array $whitelist
777
     * @return $this
778
     */
779
    public function whitelist($whitelist = '*')
780
    {
781
        $this->columnDef['whitelist'] = $whitelist;
782
783
        return $this;
784
    }
785
786
    /**
787
     * Set smart search config at runtime.
788
     *
789
     * @param bool $bool
790
     * @return $this
791
     */
792
    public function smart($bool = true)
793
    {
794
        Config::set('datatables.search.smart', $bool);
795
796
        return $this;
797
    }
798
799
    /**
800
     * Check if column is blacklisted.
801
     *
802
     * @param string $column
803
     * @return bool
804
     */
805
    protected function isBlacklisted($column)
806
    {
807
        if (in_array($column, $this->columnDef['blacklist'])) {
808
            return true;
809
        }
810
811
        if ($this->columnDef['whitelist'] === '*' || in_array($column, $this->columnDef['whitelist'])) {
812
            return false;
813
        }
814
815
        return true;
816
    }
817
818
    /**
819
     * Get column name to be use for filtering and sorting.
820
     *
821
     * @param integer $index
822
     * @param bool $wantsAlias
823
     * @return string
824
     */
825
    protected function getColumnName($index, $wantsAlias = false)
826
    {
827
        $column = $this->request->columnName($index);
828
829
        // DataTables is using make(false)
830
        if (is_numeric($column)) {
831
            $column = $this->getColumnNameByIndex($index);
832
        }
833
834
        if (Str::contains(Str::upper($column), ' AS ')) {
835
            $column = $this->extractColumnName($column, $wantsAlias);
836
        }
837
838
        return $column;
839
    }
840
841
    /**
842
     * Get column name by order column index.
843
     *
844
     * @param int $index
845
     * @return mixed
846
     */
847
    protected function getColumnNameByIndex($index)
848
    {
849
        $name = isset($this->columns[$index]) && $this->columns[$index] <> '*' ? $this->columns[$index] : $this->getPrimaryKeyName();
850
851
        return in_array($name, $this->extraColumns, true) ? $this->getPrimaryKeyName() : $name;
852
    }
853
854
    /**
855
     * If column name could not be resolved then use primary key.
856
     *
857
     * @return string
858
     */
859
    protected function getPrimaryKeyName()
860
    {
861
        if ($this->isEloquent()) {
862
            return $this->query->getModel()->getKeyName();
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...
863
        }
864
865
        return 'id';
866
    }
867
868
    /**
869
     * Check if the engine used was eloquent.
870
     *
871
     * @return bool
872
     */
873
    protected function isEloquent()
874
    {
875
        return $this->query_type === 'eloquent';
876
    }
877
878
    /**
879
     * Get column name from string.
880
     *
881
     * @param string $str
882
     * @param bool $wantsAlias
883
     * @return string
884
     */
885
    protected function extractColumnName($str, $wantsAlias)
886
    {
887
        $matches = explode(' as ', Str::lower($str));
888
889
        if (! empty($matches)) {
890
            if ($wantsAlias) {
891
                return array_pop($matches);
892
            } else {
893
                return array_shift($matches);
894
            }
895
        } elseif (strpos($str, '.')) {
896
            $array = explode('.', $str);
897
898
            return array_pop($array);
899
        }
900
901
        return $str;
902
    }
903
904
    /**
905
     * Check if the current sql language is based on oracle syntax.
906
     *
907
     * @return bool
908
     */
909
    protected function isOracleSql()
910
    {
911
        return in_array($this->database, ['oracle', 'oci8']);
912
    }
913
}
914