Completed
Push — master ( 1f4971...3a4844 )
by Arjay
01:15
created

DataTable::toColumnsCollection()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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