Completed
Push — master ( 241c47...2e2adf )
by Arjay
12s
created

DataTable   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 508
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 10

Importance

Changes 0
Metric Value
wmc 50
lcom 3
cbo 10
dl 0
loc 508
rs 8.6206
c 0
b 0
f 0

31 Methods

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