Completed
Pull Request — master (#6)
by Ozan
01:40
created

Builder::setTitle()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
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
     * Determine if the datatable has a custom id.
133
     *  
134
     * @return boolean
135
     */
136
    private function hasCustomTableId()
137
    {
138
        return $this->tableAttributes['id'] != 'dataTableBuilder';
139
    }
140
141
    /**
142
     * Prepare ajax attributes.
143
     */
144
    private function prepareAjaxAttributes()
145
    {
146
        $queryString = '';
147
        if ($this->hasCustomTableId()) {
148
            $queryString = '?'.http_build_query([
149
                'tableId' => $this->tableAttributes['id'],
150
            ]);
151
        }
152
153
        if (is_array($this->ajax)) {
154
            $this->ajax['url'] = $this->ajax['url'].$queryString;
155
        } else {
156
            $this->ajax = $this->ajax.$queryString;
157
        }
158
    }
159
160
    /**
161
     * Get generated raw scripts.
162
     *
163
     * @return string
164
     */
165
    public function generateScripts()
166
    {
167
        $this->prepareAjaxAttributes();
168
169
        $args = array_merge(
170
            $this->attributes, [
171
                'ajax'    => $this->ajax,
172
                'columns' => $this->collection->toArray(),
173
            ]
174
        );
175
176
        $parameters = $this->parameterize($args);
177
178
        return sprintf(
179
            $this->template(),
180
            $this->tableAttributes['id'], $parameters
181
        );
182
    }
183
184
    /**
185
     * Generate DataTables js parameters.
186
     *
187
     * @param  array $attributes
188
     * @return string
189
     */
190
    public function parameterize($attributes = [])
191
    {
192
        $parameters = (new Parameters($attributes))->toArray();
193
194
        $values = [];
195
        $replacements = [];
196
        foreach($parameters as $key => &$value){
197
            if (!is_array($value)) {
198
                if (strpos($value, '$.') === 0)
199
                {
200
                    // Store function string.
201
                    $values[] = $value;
202
                    // Replace function string in $foo with a 'unique' special key.
203
                    $value = '%' . $key . '%';
204
                    // Later on, we'll look for the value, and replace it.
205
                    $replacements[] = '"' . $value . '"';
206
                }
207
            }
208
        }
209
210
        list($ajaxDataFunction, $parameters) = $this->encodeAjaxDataFunction($parameters);
211
        list($columnFunctions, $parameters) = $this->encodeColumnFunctions($parameters);
212
        list($callbackFunctions, $parameters) = $this->encodeCallbackFunctions($parameters);
213
214
        $json = json_encode($parameters);
215
216
        $json = str_replace($replacements, $values, $json);
217
218
        $json = $this->decodeAjaxDataFunction($ajaxDataFunction, $json);
219
        $json = $this->decodeColumnFunctions($columnFunctions, $json);
220
        $json = $this->decodeCallbackFunctions($callbackFunctions, $json);
221
222
        return $json;
223
    }
224
225
    /**
226
     * Encode ajax data function param.
227
     *
228
     * @param array $parameters
229
     * @return mixed
230
     */
231
    protected function encodeAjaxDataFunction($parameters)
232
    {
233
        $ajaxData = '';
234
        if (isset($parameters['ajax']['data'])) {
235
            $ajaxData                   = $parameters['ajax']['data'];
236
            $parameters['ajax']['data'] = "#ajax_data#";
237
        }
238
239
        return [$ajaxData, $parameters];
240
    }
241
242
    /**
243
     * Encode columns render function.
244
     *
245
     * @param array $parameters
246
     * @return array
247
     */
248
    protected function encodeColumnFunctions(array $parameters)
249
    {
250
        $columnFunctions = [];
251
        foreach ($parameters['columns'] as $i => $column) {
252
            unset($parameters['columns'][$i]['exportable']);
253
            unset($parameters['columns'][$i]['printable']);
254
            unset($parameters['columns'][$i]['footer']);
255
256
            if (isset($column['render'])) {
257
                $columnFunctions[$i]                 = $column['render'];
258
                $parameters['columns'][$i]['render'] = "#column_function.{$i}#";
259
            }
260
        }
261
262
        return [$columnFunctions, $parameters];
263
    }
264
265
    /**
266
     * Encode DataTables callbacks function.
267
     *
268
     * @param array $parameters
269
     * @return array
270
     */
271
    protected function encodeCallbackFunctions(array $parameters)
272
    {
273
        $callbackFunctions = [];
274
        foreach ($parameters as $key => $callback) {
275
            if (in_array($key, $this->validCallbacks)) {
276
                $callbackFunctions[$key] = $this->compileCallback($callback);
277
                $parameters[$key]        = "#callback_function.{$key}#";
278
            }
279
        }
280
281
        return [$callbackFunctions, $parameters];
282
    }
283
284
    /**
285
     * Compile DataTable callback value.
286
     *
287
     * @param mixed $callback
288
     * @return mixed|string
289
     */
290
    private function compileCallback($callback)
291
    {
292
        if (is_callable($callback)) {
293
            return value($callback);
294
        } elseif ($this->view->exists($callback)) {
295
            return $this->view->make($callback)->render();
296
        }
297
298
        return $callback;
299
    }
300
301
    /**
302
     * Decode ajax data method.
303
     *
304
     * @param string $function
305
     * @param string $json
306
     * @return string
307
     */
308
    protected function decodeAjaxDataFunction($function, $json)
309
    {
310
        return str_replace("\"#ajax_data#\"", $function, $json);
311
    }
312
313
    /**
314
     * Decode columns render functions.
315
     *
316
     * @param array $columnFunctions
317
     * @param string $json
318
     * @return string
319
     */
320
    protected function decodeColumnFunctions(array $columnFunctions, $json)
321
    {
322
        foreach ($columnFunctions as $i => $function) {
323
            $json = str_replace("\"#column_function.{$i}#\"", $function, $json);
324
        }
325
326
        return $json;
327
    }
328
329
    /**
330
     * Decode DataTables callbacks function.
331
     *
332
     * @param array $callbackFunctions
333
     * @param string $json
334
     * @return string
335
     */
336
    protected function decodeCallbackFunctions(array $callbackFunctions, $json)
337
    {
338
        foreach ($callbackFunctions as $i => $function) {
339
            $json = str_replace("\"#callback_function.{$i}#\"", $function, $json);
340
        }
341
342
        return $json;
343
    }
344
345
    /**
346
     * Get javascript template to use.
347
     *
348
     * @return string
349
     */
350
    protected function template()
351
    {
352
        return $this->view->make(
353
            $this->template ?: $this->config->get('datatables.script_template', 'datatables::script')
354
        )->render();
355
    }
356
357
    /**
358
     * Sets HTML table attribute(s).
359
     *
360
     * @param string|array $attribute
361
     * @param mixed $value
362
     * @return $this
363
     */
364
    public function setTableAttribute($attribute, $value = null)
365
    {
366
        if (is_array($attribute)) {
367
            $this->setTableAttributes($attribute);
368
        } else {
369
            $this->tableAttributes[$attribute] = $value;
370
        }
371
372
        return $this;
373
    }
374
375
    /**
376
     * Sets multiple HTML table attributes at once.
377
     *
378
     * @param array $attributes
379
     * @return $this
380
     */
381
    public function setTableAttributes(array $attributes)
382
    {
383
        foreach ($attributes as $attribute => $value) {
384
            $this->setTableAttribute($attribute, $value);
385
        }
386
387
        return $this;
388
    }
389
390
    /**
391
     * Retrieves HTML table attribute value.
392
     *
393
     * @param string $attribute
394
     * @return mixed
395
     * @throws \Exception
396
     */
397
    public function getTableAttribute($attribute)
398
    {
399
        if (! array_key_exists($attribute, $this->tableAttributes)) {
400
            throw new \Exception("Table attribute '{$attribute}' does not exist.");
401
        }
402
403
        return $this->tableAttributes[$attribute];
404
    }
405
406
    /**
407
     * Add a column in collection using attributes.
408
     *
409
     * @param  array $attributes
410
     * @return $this
411
     */
412
    public function addColumn(array $attributes)
413
    {
414
        $this->collection->push(new Column($attributes));
415
416
        return $this;
417
    }
418
419
    /**
420
     * Add a Column object in collection.
421
     *
422
     * @param \Yajra\Datatables\Html\Column $column
423
     * @return $this
424
     */
425
    public function add(Column $column)
426
    {
427
        $this->collection->push($column);
428
429
        return $this;
430
    }
431
432
    /**
433
     * Set datatables columns from array definition.
434
     *
435
     * @param array $columns
436
     * @return $this
437
     */
438
    public function columns(array $columns)
439
    {
440
        foreach ($columns as $key => $value) {
441
            if (! is_a($value, Column::class)) {
442
                if (is_array($value)) {
443
                    $attributes = array_merge(['name' => $key, 'data' => $key], $this->setTitle($key, $value));
444
                } else {
445
                    $attributes = [
446
                        'name'  => $value,
447
                        'data'  => $value,
448
                        'title' => $this->getQualifiedTitle($value),
449
                    ];
450
                }
451
452
                $this->collection->push(new Column($attributes));
453
            } else {
454
                $this->collection->push($value);
455
            }
456
        }
457
458
        return $this;
459
    }
460
461
    /**
462
     * Set title attribute of an array if not set.
463
     *
464
     * @param string $title
465
     * @param array $attributes
466
     * @return array
467
     */
468
    public function setTitle($title, array $attributes)
469
    {
470
        if (! isset($attributes['title'])) {
471
            $attributes['title'] = $this->getQualifiedTitle($title);
472
        }
473
474
        return $attributes;
475
    }
476
477
    /**
478
     * Convert string into a readable title.
479
     *
480
     * @param string $title
481
     * @return string
482
     */
483
    public function getQualifiedTitle($title)
484
    {
485
        return Str::title(str_replace(['.', '_'], ' ', Str::snake($title)));
486
    }
487
488
    /**
489
     * Add a checkbox column.
490
     *
491
     * @param  array $attributes
492
     * @return $this
493
     */
494
    public function addCheckbox(array $attributes = [])
495
    {
496
        $attributes = array_merge([
497
            'defaultContent' => '<input type="checkbox" ' . $this->html->attributes($attributes) . '/>',
498
            'title'          => $this->form->checkbox('', '', false, ['id' => 'dataTablesCheckbox']),
499
            'data'           => 'checkbox',
500
            'name'           => 'checkbox',
501
            'orderable'      => false,
502
            'searchable'     => false,
503
            'exportable'     => false,
504
            'printable'      => true,
505
            'width'          => '10px',
506
        ], $attributes);
507
        $this->collection->push(new Column($attributes));
508
509
        return $this;
510
    }
511
512
    /**
513
     * Add a action column.
514
     *
515
     * @param  array $attributes
516
     * @return $this
517
     */
518
    public function addAction(array $attributes = [])
519
    {
520
        $attributes = array_merge([
521
            'defaultContent' => '',
522
            'data'           => 'action',
523
            'name'           => 'action',
524
            'title'          => 'Action',
525
            'render'         => null,
526
            'orderable'      => false,
527
            'searchable'     => false,
528
            'exportable'     => false,
529
            'printable'      => true,
530
            'footer'         => '',
531
        ], $attributes);
532
        $this->collection->push(new Column($attributes));
533
534
        return $this;
535
    }
536
537
    /**
538
     * Add a index column.
539
     *
540
     * @param  array $attributes
541
     * @return $this
542
     */
543
    public function addIndex(array $attributes = [])
544
    {
545
        $indexColumn = Config::get('datatables.index_column', 'DT_Row_Index');
546
        $attributes  = array_merge([
547
            'defaultContent' => '',
548
            'data'           => $indexColumn,
549
            'name'           => $indexColumn,
550
            'title'          => '',
551
            'render'         => null,
552
            'orderable'      => false,
553
            'searchable'     => false,
554
            'exportable'     => false,
555
            'printable'      => true,
556
            'footer'         => '',
557
        ], $attributes);
558
        $this->collection->push(new Column($attributes));
559
560
        return $this;
561
    }
562
563
    /**
564
     * Setup ajax parameter for datatables pipeline plugin
565
     *
566
     * @param  string $url
567
     * @param  string $pages
568
     * @return $this
569
     */
570
    public function pipeline($url, $pages)
571
    {
572
        $this->ajax = "$.fn.dataTable.pipeline({ url: '{$url}', pages: {$pages} })";
573
574
        return $this;
575
    }
576
577
    /**
578
     * Setup ajax parameter
579
     *
580
     * @param  string|array $attributes
581
     * @return $this
582
     */
583
    public function ajax($attributes)
584
    {
585
        $this->ajax = $attributes;
586
587
        return $this;
588
    }
589
590
    /**
591
     * Generate DataTable's table html.
592
     *
593
     * @param array $attributes
594
     * @param bool $drawFooter
595
     * @return string
596
     */
597
    public function table(array $attributes = [], $drawFooter = false)
598
    {
599
        $this->tableAttributes = array_merge($this->tableAttributes, $attributes);
600
601
        $th       = $this->compileTableHeaders();
602
        $htmlAttr = $this->html->attributes($this->tableAttributes);
603
604
        $tableHtml = '<table ' . $htmlAttr . '>';
605
        $tableHtml .= '<thead><tr>' . implode('', $th) . '</tr></thead>';
606
        if ($drawFooter) {
607
            $tf = $this->compileTableFooter();
608
            $tableHtml .= '<tfoot><tr>' . implode('', $tf) . '</tr></tfoot>';
609
        }
610
        $tableHtml .= '</table>';
611
612
        return $tableHtml;
613
    }
614
615
    /**
616
     * Compile table headers and to support responsive extension.
617
     *
618
     * @return array
619
     */
620
    private function compileTableHeaders()
621
    {
622
        $th = [];
623
        foreach ($this->collection->toArray() as $row) {
624
            $thAttr = $this->html->attributes(array_merge(
625
                array_only($row, ['class', 'id', 'width', 'style', 'data-class', 'data-hide']),
626
                $row['attributes']
627
            ));
628
            $th[]   = '<th ' . $thAttr . '>' . $row['title'] . '</th>';
629
        }
630
631
        return $th;
632
    }
633
634
    /**
635
     * Compile table footer contents.
636
     *
637
     * @return array
638
     */
639
    private function compileTableFooter()
640
    {
641
        $footer = [];
642
        foreach ($this->collection->toArray() as $row) {
643
            $footer[] = '<th>' . $row['footer'] . '</th>';
644
        }
645
646
        return $footer;
647
    }
648
649
    /**
650
     * Configure DataTable's parameters.
651
     *
652
     * @param  array $attributes
653
     * @return $this
654
     */
655
    public function parameters(array $attributes = [])
656
    {
657
        $this->attributes = array_merge($this->attributes, $attributes);
658
659
        return $this;
660
    }
661
662
    /**
663
     * Set custom javascript template.
664
     *
665
     * @param string $template
666
     * @return $this
667
     */
668
    public function setTemplate($template)
669
    {
670
        $this->template = $template;
671
672
        return $this;
673
    }
674
675
    /**
676
     * Get collection of columns.
677
     *
678
     * @return \Illuminate\Support\Collection
679
     */
680
    public function getColumns()
681
    {
682
        return $this->collection;
683
    }
684
}
685