Completed
Push — master ( 449e14...07a6c4 )
by Arjay
01:18
created

DataTable   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 495
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 10

Importance

Changes 0
Metric Value
wmc 48
lcom 3
cbo 10
dl 0
loc 495
rs 8.4864
c 0
b 0
f 0

31 Methods

Rating   Name   Duplication   Size   Complexity  
B render() 0 16 6
A request() 0 4 2
A ajax() 0 16 3
dataTable() 0 1 ?
A printPreview() 0 6 1
A getDataForPrint() 0 6 1
A printColumns() 0 4 2
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 4 1
A buildExcelFile() 0 11 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 4 1
A pdf() 0 8 2
A snappyPdf() 0 13 1
A addScope() 0 6 1
A with() 0 10 2
A __get() 0 8 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 Maatwebsite\Excel\Classes\LaravelExcelWorksheet;
8
use Maatwebsite\Excel\Writers\LaravelExcelWriter;
9
use Yajra\DataTables\Contracts\DataTableButtons;
10
use Yajra\DataTables\Contracts\DataTableScope;
11
use Yajra\DataTables\Contracts\DataTableService;
12
use Yajra\DataTables\Factory;
13
use Yajra\DataTables\Transformers\DataTransformer;
14
15
abstract class DataTable implements DataTableService, DataTableButtons
16
{
17
    /**
18
     * Datatables print preview view.
19
     *
20
     * @var string
21
     */
22
    protected $printPreview = 'datatables::print';
23
24
    /**
25
     * List of columns to be exported.
26
     *
27
     * @var string|array
28
     */
29
    protected $exportColumns = '*';
30
31
    /**
32
     * List of columns to be printed.
33
     *
34
     * @var string|array
35
     */
36
    protected $printColumns = '*';
37
38
    /**
39
     * Query scopes.
40
     *
41
     * @var \Yajra\DataTables\Contracts\DataTableScope[]
42
     */
43
    protected $scopes = [];
44
45
    /**
46
     * Html builder.
47
     *
48
     * @var \Yajra\DataTables\Html\Builder
49
     */
50
    protected $htmlBuilder;
51
52
    /**
53
     * Html builder extension callback.
54
     *
55
     * @var callable
56
     */
57
    protected $htmlCallback;
58
59
    /**
60
     * Export filename.
61
     *
62
     * @var string
63
     */
64
    protected $filename = '';
65
66
    /**
67
     * Custom attributes set on the class.
68
     *
69
     * @var array
70
     */
71
    protected $attributes = [];
72
73
    /**
74
     * Callback before sending the response.
75
     *
76
     * @var callable
77
     */
78
    protected $beforeCallback;
79
80
    /**
81
     * Callback after processing the response.
82
     *
83
     * @var callable
84
     */
85
    protected $responseCallback;
86
87
    /**
88
     * Available button actions. When calling an action, the value will be used
89
     * as the function name (so it should be available)
90
     * If you want to add or disable an action, overload and modify this property
91
     *
92
     * @var array
93
     */
94
    protected $actions = ['print', 'csv', 'excel', 'pdf'];
95
96
    /**
97
     * @var \Yajra\DataTables\Utilities\Request
98
     */
99
    protected $request;
100
101
    /**
102
     * Process dataTables needed render output.
103
     *
104
     * @param string $view
105
     * @param array  $data
106
     * @param array  $mergeData
107
     * @return mixed
108
     */
109
    public function render($view, $data = [], $mergeData = [])
110
    {
111
        if ($this->request()->ajax() && $this->request()->wantsJson()) {
112
            return $this->ajax();
113
        }
114
115
        if ($action = $this->request()->get('action') AND in_array($action, $this->actions)) {
116
            if ($action == 'print') {
117
                return $this->printPreview();
118
            }
119
120
            return call_user_func_array([$this, $action], []);
121
        }
122
123
        return view($view, $data, $mergeData)->with('dataTable', $this->getHtmlBuilder());
124
    }
125
126
    /**
127
     * Get Datatables Request instance.
128
     *
129
     * @return \Yajra\DataTables\Utilities\Request
130
     */
131
    public function request()
132
    {
133
        return $this->request ?: $this->request = resolve('datatables.request');
134
    }
135
136
    /**
137
     * Display ajax response.
138
     *
139
     * @return \Illuminate\Http\JsonResponse
140
     */
141
    public function ajax()
142
    {
143
        $dataTable = $this->dataTable();
144
145
        if ($callback = $this->beforeCallback) {
146
            $callback($dataTable);
147
        }
148
149
        if ($callback = $this->responseCallback) {
150
            $data = new Collection($dataTable->toArray());
151
152
            return new JsonResponse($callback($data));
153
        }
154
155
        return $dataTable->toJson();
156
    }
157
158
    /**
159
     * Build dataTable class.
160
     *
161
     * @return \Yajra\DataTables\DataTableAbstract
162
     */
163
    abstract protected function dataTable();
164
165
    /**
166
     * Display printable view of datatables.
167
     *
168
     * @return \Illuminate\Contracts\View\View
169
     */
170
    public function printPreview()
171
    {
172
        $data = $this->getDataForPrint();
173
174
        return view($this->printPreview, compact('data'));
175
    }
176
177
    /**
178
     * Get mapped columns versus final decorated output.
179
     *
180
     * @return array
181
     */
182
    protected function getDataForPrint()
183
    {
184
        $columns = $this->printColumns();
185
186
        return $this->mapResponseToColumns($columns, 'printable');
187
    }
188
189
    /**
190
     * Get printable columns.
191
     *
192
     * @return array|string
193
     */
194
    protected function printColumns()
195
    {
196
        return is_array($this->printColumns) ? $this->printColumns : $this->getColumnsFromBuilder();
197
    }
198
199
    /**
200
     * Get columns definition from html builder.
201
     *
202
     * @return \Illuminate\Support\Collection
203
     */
204
    protected function getColumnsFromBuilder()
205
    {
206
        return $this->html()->getColumns();
207
    }
208
209
    /**
210
     * Optional method if you want to use html builder.
211
     *
212
     * @return \Yajra\DataTables\Html\Builder
213
     */
214
    public function html()
215
    {
216
        return $this->builder();
217
    }
218
219
    /**
220
     * Get Datatables Html Builder instance.
221
     *
222
     * @return \Yajra\DataTables\Html\Builder
223
     */
224
    public function builder()
225
    {
226
        return $this->htmlBuilder ?: $this->htmlBuilder = app('datatables.html');
227
    }
228
229
    /**
230
     * Map ajax response to columns definition.
231
     *
232
     * @param mixed  $columns
233
     * @param string $type
234
     * @return array
235
     */
236
    protected function mapResponseToColumns($columns, $type)
237
    {
238
        return array_map(function ($row) use ($columns, $type) {
239
            if ($columns) {
240
                return (new DataTransformer())->transform($row, $columns, $type);
241
            }
242
243
            return $row;
244
        }, $this->getAjaxResponseData());
245
    }
246
247
    /**
248
     * Get decorated data as defined in datatables ajax response.
249
     *
250
     * @return array
251
     */
252
    protected function getAjaxResponseData()
253
    {
254
        $this->request()->merge(['length' => -1]);
255
256
        $response = $this->ajax();
257
        $data     = $response->getData(true);
258
259
        return $data['data'];
260
    }
261
262
    /**
263
     * @return \Yajra\DataTables\Html\Builder
264
     */
265
    protected function getHtmlBuilder()
266
    {
267
        $builder = $this->html();
268
        if ($this->htmlCallback) {
269
            call_user_func($this->htmlCallback, $builder);
270
        }
271
272
        return $builder;
273
    }
274
275
    /**
276
     * Add html builder callback hook.
277
     *
278
     * @param callable $callback
279
     * @return $this
280
     */
281
    public function withHtml(callable $callback)
282
    {
283
        $this->htmlCallback = $callback;
284
285
        return $this;
286
    }
287
288
    /**
289
     * Add callback before sending the response.
290
     *
291
     * @param callable $callback
292
     * @return $this
293
     */
294
    public function before(callable $callback)
295
    {
296
        $this->beforeCallback = $callback;
297
298
        return $this;
299
    }
300
301
    /**
302
     * Add callback after the response was processed.
303
     *
304
     * @param callable $callback
305
     * @return $this
306
     */
307
    public function response(callable $callback)
308
    {
309
        $this->responseCallback = $callback;
310
311
        return $this;
312
    }
313
314
    /**
315
     * Export results to Excel file.
316
     *
317
     * @return void
318
     */
319
    public function excel()
320
    {
321
        $this->buildExcelFile()->download('xls');
322
    }
323
324
    /**
325
     * Build excel file and prepare for export.
326
     *
327
     * @return \Maatwebsite\Excel\Writers\LaravelExcelWriter
328
     */
329
    protected function buildExcelFile()
330
    {
331
        /** @var \Maatwebsite\Excel\Excel $excel */
332
        $excel = app('excel');
333
334
        return $excel->create($this->getFilename(), function (LaravelExcelWriter $excel) {
335
            $excel->sheet('exported-data', function (LaravelExcelWorksheet $sheet) {
336
                $sheet->fromArray($this->getDataForExport());
337
            });
338
        });
339
    }
340
341
    /**
342
     * Get export filename.
343
     *
344
     * @return string
345
     */
346
    public function getFilename()
347
    {
348
        return $this->filename ?: $this->filename();
349
    }
350
351
    /**
352
     * Set export filename.
353
     *
354
     * @param string $filename
355
     * @return DataTable
356
     */
357
    public function setFilename($filename)
358
    {
359
        $this->filename = $filename;
360
361
        return $this;
362
    }
363
364
    /**
365
     * Get filename for export.
366
     *
367
     * @return string
368
     */
369
    protected function filename()
370
    {
371
        return 'export_' . time();
372
    }
373
374
    /**
375
     * Get mapped columns versus final decorated output.
376
     *
377
     * @return array
378
     */
379
    protected function getDataForExport()
380
    {
381
        $columns = $this->exportColumns();
382
383
        return $this->mapResponseToColumns($columns, 'exportable');
384
    }
385
386
    /**
387
     * Get export columns definition.
388
     *
389
     * @return array|string
390
     */
391
    private function exportColumns()
392
    {
393
        return is_array($this->exportColumns) ? $this->exportColumns : $this->getColumnsFromBuilder();
394
    }
395
396
    /**
397
     * Export results to CSV file.
398
     *
399
     * @return void
400
     */
401
    public function csv()
402
    {
403
        $this->buildExcelFile()->download('csv');
404
    }
405
406
    /**
407
     * Export results to PDF file.
408
     *
409
     * @return mixed
410
     */
411
    public function pdf()
412
    {
413
        if ('snappy' == config('datatables-buttons.pdf_generator', 'snappy')) {
414
            return $this->snappyPdf();
415
        } else {
416
            $this->buildExcelFile()->download('pdf');
417
        }
418
    }
419
420
    /**
421
     * PDF version of the table using print preview blade template.
422
     *
423
     * @return mixed
424
     */
425
    public function snappyPdf()
426
    {
427
        /** @var \Barryvdh\Snappy\PdfWrapper $snappy */
428
        $snappy      = resolve('snappy.pdf.wrapper');
429
        $options     = config('datatables-buttons.snappy.options');
430
        $orientation = config('datatables-buttons.snappy.orientation');
431
432
        $snappy->setOptions($options)
433
               ->setOrientation($orientation);
434
435
        return $snappy->loadHTML($this->printPreview())
436
                      ->download($this->getFilename() . ".pdf");
437
    }
438
439
    /**
440
     * Add basic array query scopes.
441
     *
442
     * @param \Yajra\DataTables\Contracts\DataTableScope $scope
443
     * @return $this
444
     */
445
    public function addScope(DataTableScope $scope)
446
    {
447
        $this->scopes[] = $scope;
448
449
        return $this;
450
    }
451
452
    /**
453
     * Set a custom class attribute.
454
     *
455
     * @param mixed      $key
456
     * @param mixed|null $value
457
     * @return $this
458
     */
459
    public function with($key, $value = null)
460
    {
461
        if (is_array($key)) {
462
            $this->attributes = array_merge($this->attributes, $key);
463
        } else {
464
            $this->attributes[$key] = $value;
465
        }
466
467
        return $this;
468
    }
469
470
    /**
471
     * Dynamically retrieve the value of an attribute.
472
     *
473
     * @param string $key
474
     * @return mixed|null
475
     */
476
    public function __get($key)
477
    {
478
        if (array_key_exists($key, $this->attributes)) {
479
            return $this->attributes[$key];
480
        }
481
482
        return null;
483
    }
484
485
    /**
486
     * Apply query scopes.
487
     *
488
     * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $query
489
     * @return mixed
490
     */
491
    protected function applyScopes($query)
492
    {
493
        foreach ($this->scopes as $scope) {
494
            $scope->apply($query);
495
        }
496
497
        return $query;
498
    }
499
500
    /**
501
     * Get default builder parameters.
502
     *
503
     * @return array
504
     */
505
    protected function getBuilderParameters()
506
    {
507
        return config('datatables-buttons.parameters');
508
    }
509
}
510