Completed
Push — master ( 5336e9...66186a )
by Arjay
02:46
created

Builder::decodeCallbackFunctions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
1
<?php
2
3
namespace Yajra\Datatables\Html;
4
5
use Collective\Html\FormBuilder;
6
use Collective\Html\HtmlBuilder;
7
use Illuminate\Contracts\Config\Repository;
8
use Illuminate\Contracts\View\Factory;
9
use Illuminate\Routing\UrlGenerator;
10
use Illuminate\Support\Collection;
11
use Illuminate\Support\Facades\Config;
12
use Illuminate\Support\Str;
13
14
/**
15
 * Class Builder.
16
 *
17
 * @package Yajra\Datatables\Html
18
 * @author  Arjay Angeles <[email protected]>
19
 */
20
class Builder
21
{
22
    /**
23
     * @var Collection
24
     */
25
    public $collection;
26
27
    /**
28
     * @var Repository
29
     */
30
    public $config;
31
32
    /**
33
     * @var Factory
34
     */
35
    public $view;
36
37
    /**
38
     * @var HtmlBuilder
39
     */
40
    public $html;
41
42
    /**
43
     * @var UrlGenerator
44
     */
45
    public $url;
46
47
    /**
48
     * @var FormBuilder
49
     */
50
    public $form;
51
52
    /**
53
     * @var string|array
54
     */
55
    protected $ajax = '';
56
57
    /**
58
     * @var array
59
     */
60
    protected $tableAttributes = ['class' => 'table', 'id' => 'dataTableBuilder'];
61
62
    /**
63
     * @var string
64
     */
65
    protected $template = '';
66
67
    /**
68
     * @var array
69
     */
70
    protected $attributes = [];
71
72
    /**
73
     * Lists of valid DataTables Callbacks.
74
     *
75
     * @link https://datatables.net/reference/option/.
76
     * @var array
77
     */
78
    protected $validCallbacks = [
79
        'createdRow',
80
        'drawCallback',
81
        'footerCallback',
82
        'formatNumber',
83
        'headerCallback',
84
        'infoCallback',
85
        'initComplete',
86
        'preDrawCallback',
87
        'rowCallback',
88
        'stateLoadCallback',
89
        'stateLoaded',
90
        'stateLoadParams',
91
        'stateSaveCallback',
92
        'stateSaveParams',
93
    ];
94
95
    /**
96
     * @param Repository $config
97
     * @param Factory $view
98
     * @param HtmlBuilder $html
99
     * @param UrlGenerator $url
100
     * @param FormBuilder $form
101
     */
102
    public function __construct(
103
        Repository $config,
104
        Factory $view,
105
        HtmlBuilder $html,
106
        UrlGenerator $url,
107
        FormBuilder $form
108
    ) {
109
        $this->config     = $config;
110
        $this->view       = $view;
111
        $this->html       = $html;
112
        $this->url        = $url;
113
        $this->collection = new Collection;
114
        $this->form       = $form;
115
    }
116
117
    /**
118
     * Generate DataTable javascript.
119
     *
120
     * @param  null $script
121
     * @param  array $attributes
122
     * @return string
123
     */
124
    public function scripts($script = null, array $attributes = ['type' => 'text/javascript'])
125
    {
126
        $script = $script ?: $this->generateScripts();
127
128
        return '<script' . $this->html->attributes($attributes) . '>' . $script . '</script>' . PHP_EOL;
129
    }
130
131
    /**
132
     * Get generated raw scripts.
133
     *
134
     * @return string
135
     */
136
    public function generateScripts()
137
    {
138
        $args = array_merge(
139
            $this->attributes, [
140
                'ajax'    => $this->ajax,
141
                'columns' => $this->collection->toArray(),
142
            ]
143
        );
144
145
        $parameters = $this->parameterize($args);
146
147
        return sprintf(
148
            $this->template(),
149
            $this->tableAttributes['id'], $parameters
150
        );
151
    }
152
153
    /**
154
     * Generate DataTables js parameters.
155
     *
156
     * @param  array $attributes
157
     * @return string
158
     */
159
    public function parameterize($attributes = [])
160
    {
161
        $parameters = (new Parameters($attributes))->toArray();
162
163
        list($ajaxDataFunction, $parameters) = $this->encodeAjaxDataFunction($parameters);
164
        list($columnFunctions, $parameters) = $this->encodeColumnFunctions($parameters);
165
        list($callbackFunctions, $parameters) = $this->encodeCallbackFunctions($parameters);
166
167
        $json = json_encode($parameters);
168
169
        $json = $this->decodeAjaxDataFunction($ajaxDataFunction, $json);
170
        $json = $this->decodeColumnFunctions($columnFunctions, $json);
171
        $json = $this->decodeCallbackFunctions($callbackFunctions, $json);
172
173
        return $json;
174
    }
175
176
    /**
177
     * Encode ajax data function param.
178
     *
179
     * @param array $parameters
180
     * @return mixed
181
     */
182
    protected function encodeAjaxDataFunction($parameters)
183
    {
184
        $ajaxData = '';
185
        if (isset($parameters['ajax']['data'])) {
186
            $ajaxData                   = $parameters['ajax']['data'];
187
            $parameters['ajax']['data'] = "#ajax_data#";
188
        }
189
190
        return [$ajaxData, $parameters];
191
    }
192
193
    /**
194
     * Encode columns render function.
195
     *
196
     * @param array $parameters
197
     * @return array
198
     */
199
    protected function encodeColumnFunctions(array $parameters)
200
    {
201
        $columnFunctions = [];
202
        foreach ($parameters['columns'] as $i => $column) {
203
            unset($parameters['columns'][$i]['exportable']);
204
            unset($parameters['columns'][$i]['printable']);
205
            unset($parameters['columns'][$i]['footer']);
206
207
            if (isset($column['render'])) {
208
                $columnFunctions[$i]                 = $column['render'];
209
                $parameters['columns'][$i]['render'] = "#column_function.{$i}#";
210
            }
211
        }
212
213
        return [$columnFunctions, $parameters];
214
    }
215
216
    /**
217
     * Encode DataTables callbacks function.
218
     *
219
     * @param array $parameters
220
     * @return array
221
     */
222
    protected function encodeCallbackFunctions(array $parameters)
223
    {
224
        $callbackFunctions = [];
225
        foreach ($parameters as $key => $callback) {
226
            if (in_array($key, $this->validCallbacks)) {
227
                $callbackFunctions[$key] = $this->compileCallback($callback);
228
                $parameters[$key]        = "#callback_function.{$key}#";
229
            }
230
        }
231
232
        return [$callbackFunctions, $parameters];
233
    }
234
235
    /**
236
     * Compile DataTable callback value.
237
     *
238
     * @param mixed $callback
239
     * @return mixed|string
240
     */
241
    private function compileCallback($callback)
242
    {
243
        if (is_callable($callback)) {
244
            return value($callback);
245
        } elseif ($this->view->exists($callback)) {
246
            return $this->view->make($callback)->render();
247
        }
248
249
        return $callback;
250
    }
251
252
    /**
253
     * Decode ajax data method.
254
     *
255
     * @param string $function
256
     * @param string $json
257
     * @return string
258
     */
259
    protected function decodeAjaxDataFunction($function, $json)
260
    {
261
        return str_replace("\"#ajax_data#\"", $function, $json);
262
    }
263
264
    /**
265
     * Decode columns render functions.
266
     *
267
     * @param array $columnFunctions
268
     * @param string $json
269
     * @return string
270
     */
271
    protected function decodeColumnFunctions(array $columnFunctions, $json)
272
    {
273
        foreach ($columnFunctions as $i => $function) {
274
            $json = str_replace("\"#column_function.{$i}#\"", $function, $json);
275
        }
276
277
        return $json;
278
    }
279
280
    /**
281
     * Decode DataTables callbacks function.
282
     *
283
     * @param array $callbackFunctions
284
     * @param string $json
285
     * @return string
286
     */
287
    protected function decodeCallbackFunctions(array $callbackFunctions, $json)
288
    {
289
        foreach ($callbackFunctions as $i => $function) {
290
            $json = str_replace("\"#callback_function.{$i}#\"", $function, $json);
291
        }
292
293
        return $json;
294
    }
295
296
    /**
297
     * Get javascript template to use.
298
     *
299
     * @return string
300
     */
301
    protected function template()
302
    {
303
        return $this->view->make(
304
            $this->template ?: $this->config->get('datatables.script_template', 'datatables::script')
305
        )->render();
306
    }
307
308
    /**
309
     * Sets HTML table attribute(s).
310
     *
311
     * @param string|array $attribute
312
     * @param mixed $value
313
     * @return $this
314
     */
315
    public function setTableAttribute($attribute, $value = null)
316
    {
317
        if (is_array($attribute)) {
318
            $this->setTableAttributes($attribute);
319
        } else {
320
            $this->tableAttributes[$attribute] = $value;
321
        }
322
323
        return $this;
324
    }
325
326
    /**
327
     * Sets multiple HTML table attributes at once.
328
     *
329
     * @param array $attributes
330
     * @return $this
331
     */
332
    public function setTableAttributes(array $attributes)
333
    {
334
        foreach ($attributes as $attribute => $value) {
335
            $this->setTableAttribute($attribute, $value);
336
        }
337
338
        return $this;
339
    }
340
341
    /**
342
     * Retrieves HTML table attribute value.
343
     *
344
     * @param string $attribute
345
     * @return mixed
346
     * @throws \Exception
347
     */
348
    public function getTableAttribute($attribute)
349
    {
350
        if (! array_key_exists($attribute, $this->tableAttributes)) {
351
            throw new \Exception("Table attribute '{$attribute}' does not exist.");
352
        }
353
354
        return $this->tableAttributes[$attribute];
355
    }
356
357
    /**
358
     * Add a column in collection using attributes.
359
     *
360
     * @param  array $attributes
361
     * @return $this
362
     */
363
    public function addColumn(array $attributes)
364
    {
365
        $this->collection->push(new Column($attributes));
366
367
        return $this;
368
    }
369
370
    /**
371
     * Add a Column object in collection.
372
     *
373
     * @param \Yajra\Datatables\Html\Column $column
374
     * @return $this
375
     */
376
    public function add(Column $column)
377
    {
378
        $this->collection->push($column);
379
380
        return $this;
381
    }
382
383
    /**
384
     * Set datatables columns from array definition.
385
     *
386
     * @param array $columns
387
     * @return $this
388
     */
389
    public function columns(array $columns)
390
    {
391
        foreach ($columns as $key => $value) {
392
            if (! is_a($value, Column::class)) {
393
                if (is_array($value)) {
394
                    $attributes = array_merge(['name' => $key, 'data' => $key], $this->setTitle($key, $value));
395
                } else {
396
                    $attributes = [
397
                        'name'  => $value,
398
                        'data'  => $value,
399
                        'title' => $this->getQualifiedTitle($value),
400
                    ];
401
                }
402
403
                $this->collection->push(new Column($attributes));
404
            } else {
405
                $this->collection->push($value);
406
            }
407
        }
408
409
        return $this;
410
    }
411
412
    /**
413
     * Set title attribute of an array if not set.
414
     *
415
     * @param string $title
416
     * @param array $attributes
417
     * @return array
418
     */
419
    public function setTitle($title, array $attributes)
420
    {
421
        if (! isset($attributes['title'])) {
422
            $attributes['title'] = $this->getQualifiedTitle($title);
423
        }
424
425
        return $attributes;
426
    }
427
428
    /**
429
     * Convert string into a readable title.
430
     *
431
     * @param string $title
432
     * @return string
433
     */
434
    public function getQualifiedTitle($title)
435
    {
436
        return Str::title(str_replace(['.', '_'], ' ', Str::snake($title)));
437
    }
438
439
    /**
440
     * Add a checkbox column.
441
     *
442
     * @param  array $attributes
443
     * @return $this
444
     */
445
    public function addCheckbox(array $attributes = [])
446
    {
447
        $attributes = array_merge([
448
            'defaultContent' => '<input type="checkbox" ' . $this->html->attributes($attributes) . '/>',
449
            'title'          => $this->form->checkbox('', '', false, ['id' => 'dataTablesCheckbox']),
450
            'data'           => 'checkbox',
451
            'name'           => 'checkbox',
452
            'orderable'      => false,
453
            'searchable'     => false,
454
            'exportable'     => false,
455
            'printable'      => true,
456
            'width'          => '10px',
457
        ], $attributes);
458
        $this->collection->push(new Column($attributes));
459
460
        return $this;
461
    }
462
463
    /**
464
     * Add a action column.
465
     *
466
     * @param  array $attributes
467
     * @return $this
468
     */
469
    public function addAction(array $attributes = [])
470
    {
471
        $attributes = array_merge([
472
            'defaultContent' => '',
473
            'data'           => 'action',
474
            'name'           => 'action',
475
            'title'          => 'Action',
476
            'render'         => null,
477
            'orderable'      => false,
478
            'searchable'     => false,
479
            'exportable'     => false,
480
            'printable'      => true,
481
            'footer'         => '',
482
        ], $attributes);
483
        $this->collection->push(new Column($attributes));
484
485
        return $this;
486
    }
487
488
    /**
489
     * Add a index column.
490
     *
491
     * @param  array $attributes
492
     * @return $this
493
     */
494
    public function addIndex(array $attributes = [])
495
    {
496
        $indexColumn = Config::get('datatables.index_column', 'DT_Row_Index');
497
        $attributes  = array_merge([
498
            'defaultContent' => '',
499
            'data'           => $indexColumn,
500
            'name'           => $indexColumn,
501
            'title'          => '',
502
            'render'         => null,
503
            'orderable'      => false,
504
            'searchable'     => false,
505
            'exportable'     => false,
506
            'printable'      => true,
507
            'footer'         => '',
508
        ], $attributes);
509
        $this->collection->push(new Column($attributes));
510
511
        return $this;
512
    }
513
514
    /**
515
     * Setup ajax parameter
516
     *
517
     * @param  string|array $attributes
518
     * @return $this
519
     */
520
    public function ajax($attributes)
521
    {
522
        $this->ajax = $attributes;
523
524
        return $this;
525
    }
526
527
    /**
528
     * Generate DataTable's table html.
529
     *
530
     * @param array $attributes
531
     * @param bool $drawFooter
532
     * @return string
533
     */
534
    public function table(array $attributes = [], $drawFooter = false)
535
    {
536
        $this->tableAttributes = array_merge($this->tableAttributes, $attributes);
537
538
        $th       = $this->compileTableHeaders();
539
        $htmlAttr = $this->html->attributes($this->tableAttributes);
540
541
        $tableHtml = '<table ' . $htmlAttr . '>';
542
        $tableHtml .= '<thead><tr>' . implode('', $th) . '</tr></thead>';
543
        if ($drawFooter) {
544
            $tf = $this->compileTableFooter();
545
            $tableHtml .= '<tfoot><tr>' . implode('', $tf) . '</tr></tfoot>';
546
        }
547
        $tableHtml .= '</table>';
548
549
        return $tableHtml;
550
    }
551
552
    /**
553
     * Compile table headers and to support responsive extension.
554
     *
555
     * @return array
556
     */
557
    private function compileTableHeaders()
558
    {
559
        $th = [];
560
        foreach ($this->collection->toArray() as $row) {
561
            $thAttr = $this->html->attributes(
562
                array_only($row, ['class', 'id', 'width', 'style', 'data-class', 'data-hide'])
563
            );
564
            $th[]   = '<th ' . $thAttr . '>' . $row['title'] . '</th>';
565
        }
566
567
        return $th;
568
    }
569
570
    /**
571
     * Compile table footer contents.
572
     *
573
     * @return array
574
     */
575
    private function compileTableFooter()
576
    {
577
        $footer = [];
578
        foreach ($this->collection->toArray() as $row) {
579
            $footer[] = '<th>' . $row['footer'] . '</th>';
580
        }
581
582
        return $footer;
583
    }
584
585
    /**
586
     * Configure DataTable's parameters.
587
     *
588
     * @param  array $attributes
589
     * @return $this
590
     */
591
    public function parameters(array $attributes = [])
592
    {
593
        $this->attributes = array_merge($this->attributes, $attributes);
594
595
        return $this;
596
    }
597
598
    /**
599
     * Set custom javascript template.
600
     *
601
     * @param string $template
602
     * @return $this
603
     */
604
    public function setTemplate($template)
605
    {
606
        $this->template = $template;
607
608
        return $this;
609
    }
610
611
    /**
612
     * Get collection of columns.
613
     *
614
     * @return Collection
615
     */
616
    public function getColumns()
617
    {
618
        return $this->collection;
619
    }
620
}
621