Completed
Push — master ( 6d9a36...486225 )
by Arjay
03:16
created

Builder::getColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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