Completed
Push — master ( f5d123...d49380 )
by Arjay
01:29
created

DataTable::ajax()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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