Completed
Push — master ( 607042...904759 )
by Arjay
15:02
created

DataTable   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 572
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 7

Importance

Changes 0
Metric Value
wmc 52
lcom 3
cbo 7
dl 0
loc 572
rs 7.44
c 0
b 0
f 0

33 Methods

Rating   Name   Duplication   Size   Complexity  
A render() 0 16 6
A request() 0 4 2
A ajax() 0 23 4
A printPreview() 0 6 1
A getDataForPrint() 0 6 1
A printColumns() 0 4 2
A getPrintColumnsFromBuilder() 0 4 1
A getExportColumnsFromBuilder() 0 4 1
A getColumnsFromBuilder() 0 4 1
A html() 0 4 1
A builder() 0 4 2
A mapResponseToColumns() 0 10 2
A getAjaxResponseData() 0 9 1
A getHtmlBuilder() 0 9 2
A withHtml() 0 6 1
A before() 0 6 1
A response() 0 6 1
A excel() 0 6 1
A buildExcelFile() 0 6 1
A getFilename() 0 4 2
A setFilename() 0 6 1
A filename() 0 4 1
A getDataForExport() 0 6 1
A exportColumns() 0 4 2
A csv() 0 6 1
A pdf() 0 8 2
A snappyPdf() 0 11 1
A addScope() 0 6 1
A addScopes() 0 6 1
A with() 0 10 2
A __get() 0 6 2
A applyScopes() 0 8 2
A getBuilderParameters() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like DataTable 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 DataTable, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Yajra\DataTables\Services;
4
5
use Illuminate\Http\JsonResponse;
6
use Illuminate\Support\Collection;
7
use Yajra\DataTables\Contracts\DataTableScope;
8
use Yajra\DataTables\Contracts\DataTableButtons;
9
use Yajra\DataTables\Transformers\DataArrayTransformer;
10
11
abstract class DataTable implements DataTableButtons
12
{
13
    /**
14
     * DataTables print preview view.
15
     *
16
     * @var string
17
     */
18
    protected $printPreview = 'datatables::print';
19
20
    /**
21
     * Name of the dataTable variable.
22
     *
23
     * @var string
24
     */
25
    protected $dataTableVariable = 'dataTable';
26
27
    /**
28
     * List of columns to be excluded from export.
29
     *
30
     * @var string|array
31
     */
32
    protected $excludeFromExport = [];
33
34
    /**
35
     * List of columns to be excluded from printing.
36
     *
37
     * @var string|array
38
     */
39
    protected $excludeFromPrint = [];
40
41
    /**
42
     * List of columns to be exported.
43
     *
44
     * @var string|array
45
     */
46
    protected $exportColumns = '*';
47
48
    /**
49
     * List of columns to be printed.
50
     *
51
     * @var string|array
52
     */
53
    protected $printColumns = '*';
54
55
    /**
56
     * Query scopes.
57
     *
58
     * @var \Yajra\DataTables\Contracts\DataTableScope[]
59
     */
60
    protected $scopes = [];
61
62
    /**
63
     * Html builder.
64
     *
65
     * @var \Yajra\DataTables\Html\Builder
66
     */
67
    protected $htmlBuilder;
68
69
    /**
70
     * Html builder extension callback.
71
     *
72
     * @var callable
73
     */
74
    protected $htmlCallback;
75
76
    /**
77
     * Export filename.
78
     *
79
     * @var string
80
     */
81
    protected $filename = '';
82
83
    /**
84
     * Custom attributes set on the class.
85
     *
86
     * @var array
87
     */
88
    protected $attributes = [];
89
90
    /**
91
     * Callback before sending the response.
92
     *
93
     * @var callable
94
     */
95
    protected $beforeCallback;
96
97
    /**
98
     * Callback after processing the response.
99
     *
100
     * @var callable
101
     */
102
    protected $responseCallback;
103
104
    /**
105
     * Available button actions. When calling an action, the value will be used
106
     * as the function name (so it should be available)
107
     * If you want to add or disable an action, overload and modify this property.
108
     *
109
     * @var array
110
     */
111
    protected $actions = ['print', 'csv', 'excel', 'pdf'];
112
113
    /**
114
     * @var \Yajra\DataTables\Utilities\Request
115
     */
116
    protected $request;
117
118
    /**
119
     * Export class handler.
120
     *
121
     * @var string
122
     */
123
    protected $exportClass = DataTablesExportHandler::class;
124
125
    /**
126
     * CSV export type writer.
127
     *
128
     * @var string
129
     */
130
    protected $csvWriter = "Csv";
131
132
    /**
133
     * Excel export type writer.
134
     *
135
     * @var string
136
     */
137
    protected $excelWriter = "Xlsx";
138
139
    /**
140
     * PDF export type writer.
141
     *
142
     * @var string
143
     */
144
    protected $pdfWriter = "Dompdf";
145
146
    /**
147
     * Process dataTables needed render output.
148
     *
149
     * @param string $view
150
     * @param array $data
151
     * @param array $mergeData
152
     * @return mixed
153
     */
154
    public function render($view, $data = [], $mergeData = [])
155
    {
156
        if ($this->request()->ajax() && $this->request()->wantsJson()) {
157
            return app()->call([$this, 'ajax']);
158
        }
159
160
        if ($action = $this->request()->get('action') and in_array($action, $this->actions)) {
161
            if ($action == 'print') {
162
                return app()->call([$this, 'printPreview']);
163
            }
164
165
            return app()->call([$this, $action]);
166
        }
167
168
        return view($view, $data, $mergeData)->with($this->dataTableVariable, $this->getHtmlBuilder());
169
    }
170
171
    /**
172
     * Get DataTables Request instance.
173
     *
174
     * @return \Yajra\DataTables\Utilities\Request
175
     */
176
    public function request()
177
    {
178
        return $this->request ?: $this->request = resolve('datatables.request');
179
    }
180
181
    /**
182
     * Display ajax response.
183
     *
184
     * @return \Illuminate\Http\JsonResponse
185
     */
186
    public function ajax()
187
    {
188
        $source = null;
189
        if (method_exists($this, 'query')) {
190
            $source = app()->call([$this, 'query']);
191
            $source = $this->applyScopes($source);
192
        }
193
194
        /** @var \Yajra\DataTables\DataTableAbstract $dataTable */
195
        $dataTable = app()->call([$this, 'dataTable'], compact('source'));
196
197
        if ($callback = $this->beforeCallback) {
198
            $callback($dataTable);
199
        }
200
201
        if ($callback = $this->responseCallback) {
202
            $data = new Collection($dataTable->toArray());
203
204
            return new JsonResponse($callback($data));
205
        }
206
207
        return $dataTable->toJson();
208
    }
209
210
    /**
211
     * Display printable view of datatables.
212
     *
213
     * @return \Illuminate\Contracts\View\View
214
     */
215
    public function printPreview()
216
    {
217
        $data = $this->getDataForPrint();
218
219
        return view($this->printPreview, compact('data'));
220
    }
221
222
    /**
223
     * Get mapped columns versus final decorated output.
224
     *
225
     * @return array
226
     */
227
    protected function getDataForPrint()
228
    {
229
        $columns = $this->printColumns();
230
231
        return $this->mapResponseToColumns($columns, 'printable');
232
    }
233
234
    /**
235
     * Get printable columns.
236
     *
237
     * @return array|string
238
     */
239
    protected function printColumns()
240
    {
241
        return is_array($this->printColumns) ? $this->printColumns : $this->getPrintColumnsFromBuilder();
242
    }
243
244
    /**
245
     * Get filtered print columns definition from html builder.
246
     *
247
     * @return \Illuminate\Support\Collection
248
     */
249
    protected function getPrintColumnsFromBuilder()
250
    {
251
        return $this->html()->removeColumn(...$this->excludeFromPrint)->getColumns();
252
    }
253
254
    /**
255
     * Get filtered export columns definition from html builder.
256
     *
257
     * @return \Illuminate\Support\Collection
258
     */
259
    protected function getExportColumnsFromBuilder()
260
    {
261
        return $this->html()->removeColumn(...$this->excludeFromExport)->getColumns();
262
    }
263
264
    /**
265
     * Get columns definition from html builder.
266
     *
267
     * @return \Illuminate\Support\Collection
268
     */
269
    protected function getColumnsFromBuilder()
270
    {
271
        return $this->html()->getColumns();
272
    }
273
274
    /**
275
     * Optional method if you want to use html builder.
276
     *
277
     * @return \Yajra\DataTables\Html\Builder
278
     */
279
    public function html()
280
    {
281
        return $this->builder();
282
    }
283
284
    /**
285
     * Get DataTables Html Builder instance.
286
     *
287
     * @return \Yajra\DataTables\Html\Builder
288
     */
289
    public function builder()
290
    {
291
        return $this->htmlBuilder ?: $this->htmlBuilder = app('datatables.html');
292
    }
293
294
    /**
295
     * Map ajax response to columns definition.
296
     *
297
     * @param mixed $columns
298
     * @param string $type
299
     * @return array
300
     */
301
    protected function mapResponseToColumns($columns, $type)
302
    {
303
        return array_map(function ($row) use ($columns, $type) {
304
            if ($columns) {
305
                return (new DataArrayTransformer())->transform($row, $columns, $type);
306
            }
307
308
            return $row;
309
        }, $this->getAjaxResponseData());
310
    }
311
312
    /**
313
     * Get decorated data as defined in datatables ajax response.
314
     *
315
     * @return array
316
     */
317
    protected function getAjaxResponseData()
318
    {
319
        $this->request()->merge(['length' => -1]);
320
321
        $response = app()->call([$this, 'ajax']);
322
        $data     = $response->getData(true);
323
324
        return $data['data'];
325
    }
326
327
    /**
328
     * @return \Yajra\DataTables\Html\Builder
329
     */
330
    protected function getHtmlBuilder()
331
    {
332
        $builder = $this->html();
333
        if ($this->htmlCallback) {
334
            call_user_func($this->htmlCallback, $builder);
335
        }
336
337
        return $builder;
338
    }
339
340
    /**
341
     * Add html builder callback hook.
342
     *
343
     * @param callable $callback
344
     * @return $this
345
     */
346
    public function withHtml(callable $callback)
347
    {
348
        $this->htmlCallback = $callback;
349
350
        return $this;
351
    }
352
353
    /**
354
     * Add callback before sending the response.
355
     *
356
     * @param callable $callback
357
     * @return $this
358
     */
359
    public function before(callable $callback)
360
    {
361
        $this->beforeCallback = $callback;
362
363
        return $this;
364
    }
365
366
    /**
367
     * Add callback after the response was processed.
368
     *
369
     * @param callable $callback
370
     * @return $this
371
     */
372
    public function response(callable $callback)
373
    {
374
        $this->responseCallback = $callback;
375
376
        return $this;
377
    }
378
379
    /**
380
     * Export results to Excel file.
381
     *
382
     * @return void
383
     */
384
    public function excel()
385
    {
386
        $ext = "." . strtolower($this->excelWriter);
387
388
        return $this->buildExcelFile()->download($this->getFilename() . $ext, $this->excelWriter);
389
    }
390
391
    /**
392
     * Build excel file and prepare for export.
393
     *
394
     * @return \Maatwebsite\Excel\Concerns\Exportable
0 ignored issues
show
Comprehensibility Bug introduced by
The return type \Maatwebsite\Excel\Concerns\Exportable is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?

In PHP traits cannot be used for type-hinting as they do not define a well-defined structure. This is because any class that uses a trait can rename that trait’s methods.

If you would like to return an object that has a guaranteed set of methods, you could create a companion interface that lists these methods explicitly.

Loading history...
395
     */
396
    protected function buildExcelFile()
397
    {
398
        $dataForExport = collect($this->getDataForExport());
399
400
        return new $this->exportClass($dataForExport);
401
    }
402
403
    /**
404
     * Get export filename.
405
     *
406
     * @return string
407
     */
408
    public function getFilename()
409
    {
410
        return $this->filename ?: $this->filename();
411
    }
412
413
    /**
414
     * Set export filename.
415
     *
416
     * @param string $filename
417
     * @return DataTable
418
     */
419
    public function setFilename($filename)
420
    {
421
        $this->filename = $filename;
422
423
        return $this;
424
    }
425
426
    /**
427
     * Get filename for export.
428
     *
429
     * @return string
430
     */
431
    protected function filename()
432
    {
433
        return class_basename($this) . '_' . date('YmdHis');
434
    }
435
436
    /**
437
     * Get mapped columns versus final decorated output.
438
     *
439
     * @return array
440
     */
441
    protected function getDataForExport()
442
    {
443
        $columns = $this->exportColumns();
444
445
        return $this->mapResponseToColumns($columns, 'exportable');
446
    }
447
448
    /**
449
     * Get export columns definition.
450
     *
451
     * @return array|string
452
     */
453
    private function exportColumns()
454
    {
455
        return is_array($this->exportColumns) ? $this->exportColumns : $this->getExportColumnsFromBuilder();
456
    }
457
458
    /**
459
     * Export results to CSV file.
460
     *
461
     * @return mixed
462
     */
463
    public function csv()
464
    {
465
        $ext = "." . strtolower($this->csvWriter);
466
467
        return $this->buildExcelFile()->download($this->getFilename() . $ext, $this->csvWriter);
468
    }
469
470
    /**
471
     * Export results to PDF file.
472
     *
473
     * @return mixed
474
     */
475
    public function pdf()
476
    {
477
        if ('snappy' == config('datatables-buttons.pdf_generator', 'snappy')) {
478
            return $this->snappyPdf();
479
        }
480
481
        return $this->buildExcelFile()->download($this->getFilename() . ".pdf", $this->pdfWriter);
482
    }
483
484
    /**
485
     * PDF version of the table using print preview blade template.
486
     *
487
     * @return mixed
488
     */
489
    public function snappyPdf()
490
    {
491
        /** @var \Barryvdh\Snappy\PdfWrapper $snappy */
492
        $snappy      = resolve('snappy.pdf.wrapper');
493
        $options     = config('datatables-buttons.snappy.options');
494
        $orientation = config('datatables-buttons.snappy.orientation');
495
496
        $snappy->setOptions($options)->setOrientation($orientation);
497
498
        return $snappy->loadHTML($this->printPreview())->download($this->getFilename() . '.pdf');
499
    }
500
501
    /**
502
     * Add basic array query scopes.
503
     *
504
     * @param \Yajra\DataTables\Contracts\DataTableScope $scope
505
     * @return $this
506
     */
507
    public function addScope(DataTableScope $scope)
508
    {
509
        $this->scopes[] = $scope;
510
511
        return $this;
512
    }
513
514
    /**
515
     * Push multiples scopes to array query scopes.
516
     *
517
     * @param array $scopes
518
     * @return $this
519
     */
520
    public function addScopes(array $scopes)
521
    {
522
        array_push($this->scopes, $scopes);
523
524
        return $this;
525
    }
526
527
    /**
528
     * Set a custom class attribute.
529
     *
530
     * @param mixed $key
531
     * @param mixed|null $value
532
     * @return $this
533
     */
534
    public function with($key, $value = null)
535
    {
536
        if (is_array($key)) {
537
            $this->attributes = array_merge($this->attributes, $key);
538
        } else {
539
            $this->attributes[$key] = $value;
540
        }
541
542
        return $this;
543
    }
544
545
    /**
546
     * Dynamically retrieve the value of an attribute.
547
     *
548
     * @param string $key
549
     * @return mixed|null
550
     */
551
    public function __get($key)
552
    {
553
        if (array_key_exists($key, $this->attributes)) {
554
            return $this->attributes[$key];
555
        }
556
    }
557
558
    /**
559
     * Apply query scopes.
560
     *
561
     * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $query
562
     * @return mixed
563
     */
564
    protected function applyScopes($query)
565
    {
566
        foreach ($this->scopes as $scope) {
567
            $scope->apply($query);
568
        }
569
570
        return $query;
571
    }
572
573
    /**
574
     * Get default builder parameters.
575
     *
576
     * @return array
577
     */
578
    protected function getBuilderParameters()
579
    {
580
        return config('datatables-buttons.parameters');
581
    }
582
}
583