Completed
Push — master ( 733e70...5336e9 )
by Arjay
05:23
created

BaseEngine::setRowClass()   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 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
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\Resource\Collection;
9
use Yajra\Datatables\Contracts\DataTableEngineContract;
10
use Yajra\Datatables\Helper;
11
use Yajra\Datatables\Processors\DataProcessor;
12
13
/**
14
 * Class BaseEngine.
15
 *
16
 * @package Yajra\Datatables\Engines
17
 * @author  Arjay Angeles <[email protected]>
18
 */
19
abstract class BaseEngine implements DataTableEngineContract
20
{
21
    /**
22
     * Datatables Request object.
23
     *
24
     * @var \Yajra\Datatables\Request
25
     */
26
    public $request;
27
28
    /**
29
     * Database connection used.
30
     *
31
     * @var \Illuminate\Database\Connection
32
     */
33
    protected $connection;
34
35
    /**
36
     * Builder object.
37
     *
38
     * @var \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder
39
     */
40
    protected $query;
41
42
    /**
43
     * Query builder object.
44
     *
45
     * @var \Illuminate\Database\Query\Builder
46
     */
47
    protected $builder;
48
49
    /**
50
     * Array of result columns/fields.
51
     *
52
     * @var array
53
     */
54
    protected $columns = [];
55
56
    /**
57
     * DT columns definitions container (add/edit/remove/filter/order/escape).
58
     *
59
     * @var array
60
     */
61
    protected $columnDef = [
62
        'index'     => false,
63
        'append'    => [],
64
        'edit'      => [],
65
        'excess'    => ['rn', 'row_num'],
66
        'filter'    => [],
67
        'order'     => [],
68
        'escape'    => [],
69
        'blacklist' => ['password', 'remember_token'],
70
        'whitelist' => '*',
71
    ];
72
73
    /**
74
     * Query type.
75
     *
76
     * @var string
77
     */
78
    protected $query_type;
79
80
    /**
81
     * Extra/Added columns.
82
     *
83
     * @var array
84
     */
85
    protected $extraColumns = [];
86
87
    /**
88
     * Total records.
89
     *
90
     * @var int
91
     */
92
    protected $totalRecords = 0;
93
94
    /**
95
     * Total filtered records.
96
     *
97
     * @var int
98
     */
99
    protected $filteredRecords = 0;
100
101
    /**
102
     * Auto-filter flag.
103
     *
104
     * @var bool
105
     */
106
    protected $autoFilter = true;
107
108
    /**
109
     * Callback to override global search.
110
     *
111
     * @var \Closure
112
     */
113
    protected $filterCallback;
114
115
    /**
116
     * Parameters to passed on filterCallback.
117
     *
118
     * @var mixed
119
     */
120
    protected $filterCallbackParameters;
121
122
    /**
123
     * DT row templates container.
124
     *
125
     * @var array
126
     */
127
    protected $templates = [
128
        'DT_RowId'    => '',
129
        'DT_RowClass' => '',
130
        'DT_RowData'  => [],
131
        'DT_RowAttr'  => [],
132
    ];
133
134
    /**
135
     * Output transformer.
136
     *
137
     * @var \League\Fractal\TransformerAbstract
138
     */
139
    protected $transformer = null;
140
141
    /**
142
     * Database prefix
143
     *
144
     * @var string
145
     */
146
    protected $prefix;
147
148
    /**
149
     * Database driver used.
150
     *
151
     * @var string
152
     */
153
    protected $database;
154
155
    /**
156
     * [internal] Track if any filter was applied for at least one column
157
     *
158
     * @var boolean
159
     */
160
    protected $isFilterApplied = false;
161
162
    /**
163
     * Fractal serializer class.
164
     *
165
     * @var string|null
166
     */
167
    protected $serializer = null;
168
169
    /**
170
     * Custom ordering callback.
171
     *
172
     * @var \Closure
173
     */
174
    protected $orderCallback;
175
176
    /**
177
     * Array of data to append on json response.
178
     *
179
     * @var array
180
     */
181
    private $appends = [];
182
183
    /**
184
     * Setup search keyword.
185
     *
186
     * @param  string $value
187
     * @return string
188
     */
189
    public function setupKeyword($value)
190
    {
191
        if ($this->isSmartSearch()) {
192
            $keyword = '%' . $value . '%';
193
            if ($this->isWildcard()) {
194
                $keyword = $this->wildcardLikeString($value);
195
            }
196
            // remove escaping slash added on js script request
197
            $keyword = str_replace('\\', '%', $keyword);
198
199
            return $keyword;
200
        }
201
202
        return $value;
203
    }
204
205
    /**
206
     * Check if DataTables uses smart search.
207
     *
208
     * @return bool
209
     */
210
    protected function isSmartSearch()
211
    {
212
        return Config::get('datatables.search.smart', true);
213
    }
214
215
    /**
216
     * Get config use wild card status.
217
     *
218
     * @return bool
219
     */
220
    public function isWildcard()
221
    {
222
        return Config::get('datatables.search.use_wildcards', false);
223
    }
224
225
    /**
226
     * Adds % wildcards to the given string.
227
     *
228
     * @param string $str
229
     * @param bool $lowercase
230
     * @return string
231
     */
232
    public function wildcardLikeString($str, $lowercase = true)
233
    {
234
        $wild   = '%';
235
        $length = Str::length($str);
236
        if ($length) {
237
            for ($i = 0; $i < $length; $i++) {
238
                $wild .= $str[$i] . '%';
239
            }
240
        }
241
        if ($lowercase) {
242
            $wild = Str::lower($wild);
243
        }
244
245
        return $wild;
246
    }
247
248
    /**
249
     * Will prefix column if needed.
250
     *
251
     * @param string $column
252
     * @return string
253
     */
254
    public function prefixColumn($column)
255
    {
256
        $table_names = $this->tableNames();
257
        if (count(
258
            array_filter($table_names, function ($value) use (&$column) {
259
                return strpos($column, $value . '.') === 0;
260
            })
261
        )) {
262
            // the column starts with one of the table names
263
            $column = $this->prefix . $column;
264
        }
265
266
        return $column;
267
    }
268
269
    /**
270
     * Will look through the query and all it's joins to determine the table names.
271
     *
272
     * @return array
273
     */
274
    public function tableNames()
275
    {
276
        $names          = [];
277
        $query          = $this->getQueryBuilder();
278
        $names[]        = $query->from;
279
        $joins          = $query->joins ?: [];
280
        $databasePrefix = $this->prefix;
281
        foreach ($joins as $join) {
282
            $table   = preg_split('/ as /i', $join->table);
283
            $names[] = $table[0];
284
            if (isset($table[1]) && ! empty($databasePrefix) && strpos($table[1], $databasePrefix) == 0) {
285
                $names[] = preg_replace('/^' . $databasePrefix . '/', '', $table[1]);
286
            }
287
        }
288
289
        return $names;
290
    }
291
292
    /**
293
     * Get Query Builder object.
294
     *
295
     * @param mixed $instance
296
     * @return mixed
297
     */
298
    public function getQueryBuilder($instance = null)
299
    {
300
        if (! $instance) {
301
            $instance = $this->query;
302
        }
303
304
        if ($this->isQueryBuilder()) {
305
            return $instance;
306
        }
307
308
        return $instance->getQuery();
309
    }
310
311
    /**
312
     * Check query type is a builder.
313
     *
314
     * @return bool
315
     */
316
    public function isQueryBuilder()
317
    {
318
        return $this->query_type == 'builder';
319
    }
320
321
    /**
322
     * Add column in collection.
323
     *
324
     * @param string $name
325
     * @param string|callable $content
326
     * @param bool|int $order
327
     * @return $this
328
     */
329
    public function addColumn($name, $content, $order = false)
330
    {
331
        $this->extraColumns[] = $name;
332
333
        $this->columnDef['append'][] = ['name' => $name, 'content' => $content, 'order' => $order];
334
335
        return $this;
336
    }
337
338
    /**
339
     * Add DT row index column on response.
340
     *
341
     * @return $this
342
     */
343
    public function addIndexColumn()
344
    {
345
        $this->columnDef['index'] = true;
346
347
        return $this;
348
    }
349
350
    /**
351
     * Edit column's content.
352
     *
353
     * @param string $name
354
     * @param string|callable $content
355
     * @return $this
356
     */
357
    public function editColumn($name, $content)
358
    {
359
        $this->columnDef['edit'][] = ['name' => $name, 'content' => $content];
360
361
        return $this;
362
    }
363
364
    /**
365
     * Remove column from collection.
366
     *
367
     * @return $this
368
     */
369
    public function removeColumn()
370
    {
371
        $names                     = func_get_args();
372
        $this->columnDef['excess'] = array_merge($this->columnDef['excess'], $names);
373
374
        return $this;
375
    }
376
377
    /**
378
     * Declare columns to escape values.
379
     *
380
     * @param string|array $columns
381
     * @return $this
382
     */
383
    public function escapeColumns($columns = '*')
384
    {
385
        $this->columnDef['escape'] = $columns;
386
387
        return $this;
388
    }
389
390
    /**
391
     * Allows previous API calls where the methods were snake_case.
392
     * Will convert a camelCase API call to a snake_case call.
393
     * Allow query builder method to be used by the engine.
394
     *
395
     * @param  string $name
396
     * @param  array $arguments
397
     * @return mixed
398
     */
399
    public function __call($name, $arguments)
400
    {
401
        $name = Str::camel(Str::lower($name));
402
        if (method_exists($this, $name)) {
403
            return call_user_func_array([$this, $name], $arguments);
404
        } elseif (method_exists($this->getQueryBuilder(), $name)) {
405
            call_user_func_array([$this->getQueryBuilder(), $name], $arguments);
406
        } else {
407
            trigger_error('Call to undefined method ' . __CLASS__ . '::' . $name . '()', E_USER_ERROR);
408
        }
409
410
        return $this;
411
    }
412
413
    /**
414
     * Sets DT_RowClass template.
415
     * result: <tr class="output_from_your_template">.
416
     *
417
     * @param string|callable $content
418
     * @return $this
419
     */
420
    public function setRowClass($content)
421
    {
422
        $this->templates['DT_RowClass'] = $content;
423
424
        return $this;
425
    }
426
427
    /**
428
     * Sets DT_RowId template.
429
     * result: <tr id="output_from_your_template">.
430
     *
431
     * @param string|callable $content
432
     * @return $this
433
     */
434
    public function setRowId($content)
435
    {
436
        $this->templates['DT_RowId'] = $content;
437
438
        return $this;
439
    }
440
441
    /**
442
     * Set DT_RowData templates.
443
     *
444
     * @param array $data
445
     * @return $this
446
     */
447
    public function setRowData(array $data)
448
    {
449
        $this->templates['DT_RowData'] = $data;
450
451
        return $this;
452
    }
453
454
    /**
455
     * Add DT_RowData template.
456
     *
457
     * @param string $key
458
     * @param string|callable $value
459
     * @return $this
460
     */
461
    public function addRowData($key, $value)
462
    {
463
        $this->templates['DT_RowData'][$key] = $value;
464
465
        return $this;
466
    }
467
468
    /**
469
     * Set DT_RowAttr templates.
470
     * result: <tr attr1="attr1" attr2="attr2">.
471
     *
472
     * @param array $data
473
     * @return $this
474
     */
475
    public function setRowAttr(array $data)
476
    {
477
        $this->templates['DT_RowAttr'] = $data;
478
479
        return $this;
480
    }
481
482
    /**
483
     * Add DT_RowAttr template.
484
     *
485
     * @param string $key
486
     * @param string|callable $value
487
     * @return $this
488
     */
489
    public function addRowAttr($key, $value)
490
    {
491
        $this->templates['DT_RowAttr'][$key] = $value;
492
493
        return $this;
494
    }
495
496
    /**
497
     * Override default column filter search.
498
     *
499
     * @param string $column
500
     * @param string|Closure $method
501
     * @return $this
502
     * @internal param $mixed ...,... All the individual parameters required for specified $method
503
     * @internal string $1 Special variable that returns the requested search keyword.
504
     */
505
    public function filterColumn($column, $method)
506
    {
507
        $params                             = func_get_args();
508
        $this->columnDef['filter'][$column] = ['method' => $method, 'parameters' => array_splice($params, 2)];
509
510
        return $this;
511
    }
512
513
    /**
514
     * Order each given columns versus the given custom sql.
515
     *
516
     * @param array $columns
517
     * @param string $sql
518
     * @param array $bindings
519
     * @return $this
520
     */
521
    public function orderColumns(array $columns, $sql, $bindings = [])
522
    {
523
        foreach ($columns as $column) {
524
            $this->orderColumn($column, str_replace(':column', $column, $sql), $bindings);
525
        }
526
527
        return $this;
528
    }
529
530
    /**
531
     * Override default column ordering.
532
     *
533
     * @param string $column
534
     * @param string $sql
535
     * @param array $bindings
536
     * @return $this
537
     * @internal string $1 Special variable that returns the requested order direction of the column.
538
     */
539
    public function orderColumn($column, $sql, $bindings = [])
540
    {
541
        $this->columnDef['order'][$column] = ['method' => 'orderByRaw', 'parameters' => [$sql, $bindings]];
542
543
        return $this;
544
    }
545
546
    /**
547
     * Set data output transformer.
548
     *
549
     * @param \League\Fractal\TransformerAbstract $transformer
550
     * @return $this
551
     */
552
    public function setTransformer($transformer)
553
    {
554
        $this->transformer = $transformer;
555
556
        return $this;
557
    }
558
559
    /**
560
     * Set fractal serializer class.
561
     *
562
     * @param string $serializer
563
     * @return $this
564
     */
565
    public function setSerializer($serializer)
566
    {
567
        $this->serializer = $serializer;
568
569
        return $this;
570
    }
571
572
    /**
573
     * Organizes works.
574
     *
575
     * @param bool $mDataSupport
576
     * @param bool $orderFirst
577
     * @return \Illuminate\Http\JsonResponse
578
     */
579
    public function make($mDataSupport = false, $orderFirst = false)
580
    {
581
        $this->totalRecords = $this->totalCount();
582
583
        if ($this->totalRecords) {
584
            $this->orderRecords(! $orderFirst);
585
            $this->filterRecords();
586
            $this->orderRecords($orderFirst);
587
            $this->paginate();
588
        }
589
590
        return $this->render($mDataSupport);
591
    }
592
593
    /**
594
     * Sort records.
595
     *
596
     * @param  boolean $skip
597
     * @return void
598
     */
599
    public function orderRecords($skip)
600
    {
601
        if (! $skip) {
602
            $this->ordering();
603
        }
604
    }
605
606
    /**
607
     * Perform necessary filters.
608
     *
609
     * @return void
610
     */
611
    public function filterRecords()
612
    {
613
        if ($this->autoFilter && $this->request->isSearchable()) {
614
            $this->filtering();
615
        }
616
617
        if (is_callable($this->filterCallback)) {
618
            call_user_func($this->filterCallback, $this->filterCallbackParameters);
619
        }
620
621
        $this->columnSearch();
622
        $this->filteredRecords = $this->isFilterApplied ? $this->count() : $this->totalRecords;
623
    }
624
625
    /**
626
     * Apply pagination.
627
     *
628
     * @return void
629
     */
630
    public function paginate()
631
    {
632
        if ($this->request->isPaginationable()) {
633
            $this->paging();
634
        }
635
    }
636
637
    /**
638
     * Render json response.
639
     *
640
     * @param bool $object
641
     * @return \Illuminate\Http\JsonResponse
642
     */
643
    public function render($object = false)
644
    {
645
        $output = array_merge([
646
            'draw'            => (int) $this->request['draw'],
647
            'recordsTotal'    => $this->totalRecords,
648
            'recordsFiltered' => $this->filteredRecords,
649
        ], $this->appends);
650
651
        if (isset($this->transformer)) {
652
            $fractal = app('datatables.fractal');
653
654
            if ($this->serializer) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->serializer of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
655
                $fractal->setSerializer(new $this->serializer);
656
            }
657
658
            //Get transformer reflection
659
            //Firs method parameter should be data/object to transform
660
            $reflection = new \ReflectionMethod($this->transformer, 'transform');
661
            $parameter  = $reflection->getParameters()[0];
662
663
            //If parameter is class assuming it requires object
664
            //Else just pass array by default
665
            if ($parameter->getClass()) {
666
                $resource = new Collection($this->results(), $this->createTransformer());
667
            } else {
668
                $resource = new Collection(
669
                    $this->getProcessedData($object),
670
                    $this->createTransformer()
671
                );
672
            }
673
674
            $collection     = $fractal->createData($resource)->toArray();
675
            $output['data'] = $collection['data'];
676
        } else {
677
            $output['data'] = Helper::transform($this->getProcessedData($object));
678
        }
679
680
        if ($this->isDebugging()) {
681
            $output = $this->showDebugger($output);
682
        }
683
684
        return new JsonResponse($output);
685
    }
686
687
    /**
688
     * Get or create transformer instance.
689
     *
690
     * @return \League\Fractal\TransformerAbstract
691
     */
692
    protected function createTransformer()
693
    {
694
        if ($this->transformer instanceof \League\Fractal\TransformerAbstract) {
695
            return $this->transformer;
696
        }
697
698
        return new $this->transformer();
699
    }
700
701
    /**
702
     * Get processed data
703
     *
704
     * @param bool|false $object
705
     * @return array
706
     */
707
    private function getProcessedData($object = false)
708
    {
709
        $processor = new DataProcessor(
710
            $this->results(),
711
            $this->columnDef,
712
            $this->templates,
713
            $this->request['start']
714
        );
715
716
        return $processor->process($object);
717
    }
718
719
    /**
720
     * Check if app is in debug mode.
721
     *
722
     * @return bool
723
     */
724
    public function isDebugging()
725
    {
726
        return Config::get('app.debug', false);
727
    }
728
729
    /**
730
     * Append debug parameters on output.
731
     *
732
     * @param  array $output
733
     * @return array
734
     */
735
    public function showDebugger(array $output)
736
    {
737
        $output['queries'] = $this->connection->getQueryLog();
738
        $output['input']   = $this->request->all();
739
740
        return $output;
741
    }
742
743
    /**
744
     * Update flags to disable global search
745
     *
746
     * @param  \Closure $callback
747
     * @param  mixed $parameters
748
     * @param  bool $autoFilter
749
     */
750
    public function overrideGlobalSearch(\Closure $callback, $parameters, $autoFilter = false)
751
    {
752
        $this->autoFilter               = $autoFilter;
753
        $this->isFilterApplied          = true;
754
        $this->filterCallback           = $callback;
755
        $this->filterCallbackParameters = $parameters;
756
    }
757
758
    /**
759
     * Get config is case insensitive status.
760
     *
761
     * @return bool
762
     */
763
    public function isCaseInsensitive()
764
    {
765
        return Config::get('datatables.search.case_insensitive', false);
766
    }
767
768
    /**
769
     * Append data on json response.
770
     *
771
     * @param mixed $key
772
     * @param mixed $value
773
     * @return $this
774
     */
775
    public function with($key, $value = '')
776
    {
777
        if (is_array($key)) {
778
            $this->appends = $key;
779
        } elseif (is_callable($value)) {
780
            $this->appends[$key] = value($value);
781
        } else {
782
            $this->appends[$key] = value($value);
783
        }
784
785
        return $this;
786
    }
787
788
    /**
789
     * Override default ordering method with a closure callback.
790
     *
791
     * @param \Closure $closure
792
     * @return $this
793
     */
794
    public function order(\Closure $closure)
795
    {
796
        $this->orderCallback = $closure;
797
798
        return $this;
799
    }
800
801
    /**
802
     * Update list of columns that is not allowed for search/sort.
803
     *
804
     * @param  array $blacklist
805
     * @return $this
806
     */
807
    public function blacklist(array $blacklist)
808
    {
809
        $this->columnDef['blacklist'] = $blacklist;
810
811
        return $this;
812
    }
813
814
    /**
815
     * Update list of columns that is not allowed for search/sort.
816
     *
817
     * @param  string|array $whitelist
818
     * @return $this
819
     */
820
    public function whitelist($whitelist = '*')
821
    {
822
        $this->columnDef['whitelist'] = $whitelist;
823
824
        return $this;
825
    }
826
827
    /**
828
     * Set smart search config at runtime.
829
     *
830
     * @param bool $bool
831
     * @return $this
832
     */
833
    public function smart($bool = true)
834
    {
835
        Config::set('datatables.search.smart', $bool);
836
837
        return $this;
838
    }
839
840
    /**
841
     * Check if column is blacklisted.
842
     *
843
     * @param string $column
844
     * @return bool
845
     */
846
    protected function isBlacklisted($column)
847
    {
848
        if (in_array($column, $this->columnDef['blacklist'])) {
849
            return true;
850
        }
851
852
        if ($this->columnDef['whitelist'] === '*' || in_array($column, $this->columnDef['whitelist'])) {
853
            return false;
854
        }
855
856
        return true;
857
    }
858
859
    /**
860
     * Get column name to be use for filtering and sorting.
861
     *
862
     * @param integer $index
863
     * @param bool $wantsAlias
864
     * @return string
865
     */
866
    protected function getColumnName($index, $wantsAlias = false)
867
    {
868
        $column = $this->request->columnName($index);
869
870
        // DataTables is using make(false)
871
        if (is_numeric($column)) {
872
            $column = $this->getColumnNameByIndex($index);
873
        }
874
875
        if (Str::contains(Str::upper($column), ' AS ')) {
876
            $column = $this->extractColumnName($column, $wantsAlias);
877
        }
878
879
        return $column;
880
    }
881
882
    /**
883
     * Get column name by order column index.
884
     *
885
     * @param int $index
886
     * @return mixed
887
     */
888
    protected function getColumnNameByIndex($index)
889
    {
890
        $name = isset($this->columns[$index]) && $this->columns[$index] <> '*' ? $this->columns[$index] : $this->getPrimaryKeyName();
891
892
        return in_array($name, $this->extraColumns, true) ? $this->getPrimaryKeyName() : $name;
893
    }
894
895
    /**
896
     * If column name could not be resolved then use primary key.
897
     *
898
     * @return string
899
     */
900
    protected function getPrimaryKeyName()
901
    {
902
        if ($this->isEloquent()) {
903
            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...
904
        }
905
906
        return 'id';
907
    }
908
909
    /**
910
     * Check if the engine used was eloquent.
911
     *
912
     * @return bool
913
     */
914
    protected function isEloquent()
915
    {
916
        return $this->query_type === 'eloquent';
917
    }
918
919
    /**
920
     * Get column name from string.
921
     *
922
     * @param string $str
923
     * @param bool $wantsAlias
924
     * @return string
925
     */
926
    protected function extractColumnName($str, $wantsAlias)
927
    {
928
        $matches = explode(' as ', Str::lower($str));
929
930
        if (! empty($matches)) {
931
            if ($wantsAlias) {
932
                return array_pop($matches);
933
            } else {
934
                return array_shift($matches);
935
            }
936
        } elseif (strpos($str, '.')) {
937
            $array = explode('.', $str);
938
939
            return array_pop($array);
940
        }
941
942
        return $str;
943
    }
944
945
    /**
946
     * Check if the current sql language is based on oracle syntax.
947
     *
948
     * @return bool
949
     */
950
    protected function isOracleSql()
951
    {
952
        return in_array($this->database, ['oracle', 'oci8']);
953
    }
954
955
    /**
956
     * Set total records manually.
957
     *
958
     * @param int $total
959
     * @return $this
960
     */
961
    public function setTotalRecords($total)
962
    {
963
        $this->totalRecords = $total;
964
965
        return $this;
966
    }
967
}
968