Completed
Push — master ( f06f95...cfadd2 )
by Song
03:17
created

Form::resource()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin;
4
5
use Closure;
6
use Encore\Admin\Exception\Handle;
7
use Encore\Admin\Form\Builder;
8
use Encore\Admin\Form\Field;
9
use Encore\Admin\Form\Field\File;
10
use Illuminate\Database\Eloquent\Model;
11
use Illuminate\Database\Eloquent\Relations\Relation;
12
use Illuminate\Support\Arr;
13
use Illuminate\Support\Facades\DB;
14
use Illuminate\Support\Facades\Input;
15
use Illuminate\Validation\Validator;
16
use Spatie\EloquentSortable\Sortable;
17
18
/**
19
 * Class Form.
20
 *
21
 * @method Field\Text           text($column, $label = '')
22
 * @method Field\Checkbox       checkbox($column, $label = '')
23
 * @method Field\Radio          radio($column, $label = '')
24
 * @method Field\Select         select($column, $label = '')
25
 * @method Field\MultipleSelect multipleSelect($column, $label = '')
26
 * @method Field\Textarea       textarea($column, $label = '')
27
 * @method Field\Hidden         hidden($column, $label = '')
28
 * @method Field\Id             id($column, $label = '')
29
 * @method Field\Ip             ip($column, $label = '')
30
 * @method Field\Url            url($column, $label = '')
31
 * @method Field\Color          color($column, $label = '')
32
 * @method Field\Email          email($column, $label = '')
33
 * @method Field\Mobile         mobile($column, $label = '')
34
 * @method Field\Slider         slider($column, $label = '')
35
 * @method Field\Map            map($latitude, $longitude, $label = '')
36
 * @method Field\Editor         editor($column, $label = '')
37
 * @method Field\File           file($column, $label = '')
38
 * @method Field\Image          image($column, $label = '')
39
 * @method Field\Date           date($column, $label = '')
40
 * @method Field\Datetime       datetime($column, $label = '')
41
 * @method Field\Time           time($column, $label = '')
42
 * @method Field\Year           year($column, $label = '')
43
 * @method Field\Month          month($column, $label = '')
44
 * @method Field\DateRange      dateRange($start, $end, $label = '')
45
 * @method Field\DateTimeRange  dateTimeRange($start, $end, $label = '')
46
 * @method Field\TimeRange      timeRange($start, $end, $label = '')
47
 * @method Field\Number         number($column, $label = '')
48
 * @method Field\Currency       currency($column, $label = '')
49
 * @method Field\Json           json($column, $label = '')
50
 * @method Field\HasMany        hasMany($relationName, $callback)
51
 * @method Field\SwitchField    switch($column, $label = '')
52
 * @method Field\Display        display($column, $label = '')
53
 * @method Field\Rate           rate($column, $label = '')
54
 * @method Field\Divide         divide()
55
 * @method Field\Password       password($column, $label = '')
56
 * @method Field\Decimal        decimal($column, $label = '')
57
 */
58
class Form
59
{
60
    /**
61
     * Eloquent model of the form.
62
     *
63
     * @var
64
     */
65
    protected $model;
66
67
    /**
68
     * @var \Illuminate\Validation\Validator
69
     */
70
    protected $validator;
71
72
    /**
73
     * @var Builder
74
     */
75
    protected $builder;
76
77
    /**
78
     * Saving callback.
79
     *
80
     * @var Closure
81
     */
82
    protected $saving;
83
84
    /**
85
     * Saved callback.
86
     *
87
     * @var Closure
88
     */
89
    protected $saved;
90
91
    /**
92
     * Data for save to current model from input.
93
     *
94
     * @var array
95
     */
96
    protected $updates = [];
97
98
    /**
99
     * Data for save to model's relations from input.
100
     *
101
     * @var array
102
     */
103
    protected $relations = [];
104
105
    /**
106
     * Input data.
107
     *
108
     * @var array
109
     */
110
    protected $inputs = [];
111
112
    /**
113
     * @var callable
114
     */
115
    protected $callable;
116
117
    /**
118
     * Allow delete item in form page.
119
     *
120
     * @var bool
121
     */
122
    protected $allowDeletion = true;
123
124
    /**
125
     * Available fields.
126
     *
127
     * @var array
128
     */
129
    public static $availableFields = [];
130
131
    /**
132
     * Collected field assets.
133
     *
134
     * @var array
135
     */
136
    protected static $collectedAssets = [];
137
138
    /**
139
     * @param \$model
140
     * @param \Closure $callback
141
     */
142
    public function __construct($model, Closure $callback)
143
    {
144
        $this->model = $model;
145
146
        $this->builder = new Builder($this);
147
148
        $this->callable = $callback;
149
150
        $callback($this);
151
    }
152
153
    /**
154
     * Set up the form.
155
     */
156
    protected function setUp()
157
    {
158
        call_user_func($this->callable, $this);
159
    }
160
161
    /**
162
     * @param Field $field
163
     *
164
     * @return $this
165
     */
166
    public function pushField(Field $field)
167
    {
168
        $field->setForm($this);
169
170
        $this->builder->fields()->push($field);
171
172
        return $this;
173
    }
174
175
    /**
176
     * @return Model
177
     */
178
    public function model()
179
    {
180
        return $this->model;
181
    }
182
183
    /**
184
     * @return Builder
185
     */
186
    public function builder()
187
    {
188
        return $this->builder;
189
    }
190
191
    /**
192
     * Disable deletion in form page.
193
     *
194
     * @return $this
195
     */
196
    public function disableDeletion()
197
    {
198
        $this->builder->disableDeletion();
199
200
        $this->allowDeletion = false;
201
202
        return $this;
203
    }
204
205
    /**
206
     * Generate a edit form.
207
     *
208
     * @param $id
209
     *
210
     * @return $this
211
     */
212
    public function edit($id)
213
    {
214
        $this->builder->setMode(Builder::MODE_EDIT);
215
        $this->builder->setResourceId($id);
216
217
        $this->setFieldValue($id);
218
219
        return $this;
220
    }
221
222
    /**
223
     * @param $id
224
     *
225
     * @return $this
226
     */
227
    public function view($id)
228
    {
229
        $this->builder->setMode(Builder::MODE_VIEW);
230
        $this->builder->setResourceId($id);
231
232
        $this->setFieldValue($id);
233
234
        return $this;
235
    }
236
237
    /**
238
     * Destroy data entity and remove files.
239
     *
240
     * @param $id
241
     *
242
     * @return mixed
243
     */
244
    public function destroy($id)
245
    {
246
        $ids = explode(',', $id);
247
248
        foreach ($ids as $id) {
249
            if (empty($id)) {
250
                continue;
251
            }
252
            $this->deleteFilesAndImages($id);
253
            $this->model->find($id)->delete();
254
        }
255
256
        return true;
257
    }
258
259
    /**
260
     * Remove files or images in record.
261
     *
262
     * @param $id
263
     */
264
    protected function deleteFilesAndImages($id)
265
    {
266
        $data = $this->model->with($this->getRelations())
267
            ->findOrFail($id)->toArray();
268
269
        $this->builder->fields()->filter(function ($field) {
270
            return $field instanceof Field\File;
271
        })->each(function (File $file) use ($data) {
272
            $file->setOriginal($data);
273
274
            $file->destroy();
275
        });
276
    }
277
278
    /**
279
     * Store a new record.
280
     *
281
     * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
282
     */
283
    public function store()
284
    {
285
        $data = Input::all();
286
287
        if ($validator = $this->validationFails($data)) {
288
            return back()->withInput()->withErrors($validator->messages());
289
        }
290
291
        $this->prepare($data, $this->saving);
292
293 View Code Duplication
        DB::transaction(function () {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
            $inserts = $this->prepareInsert($this->updates);
295
296
            foreach ($inserts as $column => $value) {
297
                if (is_array($value)) {
298
                    $value = implode(',', $value);
299
                }
300
                $this->model->setAttribute($column, $value);
301
            }
302
303
            $this->model->save();
304
305
            $this->saveRelation($this->relations);
306
        });
307
308
        $this->complete($this->saved);
309
310
        return redirect($this->resource(0));
311
    }
312
313
    /**
314
     * Prepare input data for insert or update.
315
     *
316
     * @param array    $data
317
     * @param callable $callback
318
     */
319
    protected function prepare($data = [], Closure $callback = null)
320
    {
321
        $this->inputs = $data;
322
323
        if ($callback instanceof Closure) {
324
            $callback($this);
325
        }
326
327
        $this->relations = $this->getRelationInputs($data);
328
329
        $updates = array_except($this->inputs, array_keys($this->relations));
330
331
        $this->updates = array_filter($updates, function ($val) {
332
            return !is_null($val);
333
        });
334
    }
335
336
    /**
337
     * Get inputs for relations.
338
     *
339
     * @param array $inputs
340
     *
341
     * @return array
342
     */
343
    protected function getRelationInputs($inputs = [])
344
    {
345
        $relations = [];
346
347
        foreach ($inputs as $column => $value) {
348
            if (method_exists($this->model, $column)) {
349
                $relation = call_user_func([$this->model, $column]);
350
351
                if ($relation instanceof Relation) {
352
                    $relations[$column] = $value;
353
                }
354
            }
355
        }
356
357
        return $relations;
358
    }
359
360
    /**
361
     * Callback after saving a Model.
362
     *
363
     * @param Closure|null $callback
364
     *
365
     * @return void
366
     */
367
    protected function complete(Closure $callback = null)
368
    {
369
        if ($callback instanceof Closure) {
370
            $callback($this);
371
        }
372
    }
373
374
    /**
375
     * Save relations data.
376
     *
377
     * @param array $relations
378
     *
379
     * @return void
380
     */
381
    protected function saveRelation($relations)
382
    {
383
        foreach ($relations as $name => $values) {
384
            if (!method_exists($this->model, $name)) {
385
                continue;
386
            }
387
388
            $values = $this->prepareInsert([$name => $values]);
389
390
            $relation = $this->model->$name();
391
392
            switch (get_class($relation)) {
393
                case \Illuminate\Database\Eloquent\Relations\BelongsToMany::class:
394
                case \Illuminate\Database\Eloquent\Relations\MorphToMany::class:
395
                    $relation->attach($values[$name]);
396
                    break;
397
                case \Illuminate\Database\Eloquent\Relations\HasOne::class:
398
                    $related = $relation->getRelated();
399
                    foreach ($values[$name] as $column => $value) {
400
                        $related->setAttribute($column, $value);
401
                    }
402
403
                    $relation->save($related);
404
                    break;
405
            }
406
        }
407
    }
408
409
    /**
410
     * Handle update.
411
     *
412
     * @param int $id
413
     *
414
     * @return $this|\Illuminate\Http\RedirectResponse
415
     */
416
    public function update($id)
417
    {
418
        $data = Input::all();
419
420
        $data = $this->handleEditable($data);
421
422
        if ($this->handleOrderable($id, $data)) {
423
            return response(['status' => true, 'message' => trans('admin::lang.succeeded')]);
0 ignored issues
show
Documentation introduced by
array('status' => true, ...dmin::lang.succeeded')) is of type array<string,boolean|obj...torInterface>|string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
424
        }
425
426
        if ($validator = $this->validationFails($data)) {
427
            return back()->withInput()->withErrors($validator->messages());
428
        }
429
430
        $this->model = $this->model->with($this->getRelations())->findOrFail($id);
431
432
        $this->setFieldOriginalValue();
433
434
        $this->prepare($data, $this->saving);
435
436 View Code Duplication
        DB::transaction(function () {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
437
            $updates = $this->prepareUpdate($this->updates);
438
439
            foreach ($updates as $column => $value) {
440
                if (is_array($value)) {
441
                    $value = implode(',', $value);
442
                }
443
444
                $this->model->setAttribute($column, $value);
445
            }
446
447
            $this->model->save();
448
449
            $this->updateRelation($this->relations);
450
        });
451
452
        $this->complete($this->saved);
453
454
        return redirect($this->resource(-1));
455
    }
456
457
    /**
458
     * Handle editable update.
459
     *
460
     * @param array $input
461
     *
462
     * @return array
463
     */
464
    protected function handleEditable(array $input = [])
465
    {
466
        if (array_key_exists('_editable', $input)) {
467
            $name = $input['name'];
468
            $value = $input['value'];
469
470
            array_forget($input, ['pk', 'value', 'name']);
471
            array_set($input, $name, $value);
472
        }
473
474
        return $input;
475
    }
476
477
    /**
478
     * Handle orderable update.
479
     *
480
     * @param int   $id
481
     * @param array $input
482
     *
483
     * @return array
484
     */
485
    protected function handleOrderable($id, array $input = [])
486
    {
487
        if (array_key_exists('_orderable', $input)) {
488
            $model = $this->model->find($id);
489
490
            if ($model instanceof Sortable) {
0 ignored issues
show
Bug introduced by
The class Spatie\EloquentSortable\Sortable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
491
                $input['_orderable'] == 1 ? $model->moveOrderUp() : $model->moveOrderDown();
492
493
                return true;
494
            }
495
        }
496
497
        return false;
498
    }
499
500
    /**
501
     * Update relation data.
502
     *
503
     * @param array $relations
504
     *
505
     * @return void
506
     */
507
    protected function updateRelation($relations)
508
    {
509
        foreach ($relations as $name => $values) {
510
            if (!method_exists($this->model, $name)) {
511
                continue;
512
            }
513
514
            $prepared = $this->prepareUpdate([$name => $values]);
515
516
            if (empty($prepared)) {
517
                continue;
518
            }
519
520
            $relation = $this->model->$name();
521
522
            switch (get_class($relation)) {
523
                case \Illuminate\Database\Eloquent\Relations\BelongsToMany::class:
524
                case \Illuminate\Database\Eloquent\Relations\MorphToMany::class:
525
                    $relation->sync($prepared[$name]);
526
                    break;
527
                case \Illuminate\Database\Eloquent\Relations\HasOne::class:
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
528
529
                    $related = $this->model->$name;
530
531
                    // if related is empty
532
                    if (is_null($related)) {
533
                        $related = $relation->getRelated();
534
                        $related->{$relation->getForeignKey()} = $this->model->{$this->model->getKeyName()};
535
                    }
536
537
                    foreach ($prepared[$name] as $column => $value) {
538
                        $related->setAttribute($column, $value);
539
                    }
540
541
                    $related->save();
542
                    break;
543
            }
544
        }
545
    }
546
547
    /**
548
     * Prepare input data for update.
549
     *
550
     * @param $updates
551
     *
552
     * @return array
553
     */
554
    protected function prepareUpdate($updates)
555
    {
556
        $prepared = [];
557
558
        foreach ($this->builder->fields() as $field) {
559
            $columns = $field->column();
560
561
            $value = $this->getDataByColumn($updates, $columns);
562
563
            if ($value !== '' && $value !== '0' && !$field instanceof File && empty($value)) {
564
                continue;
565
            }
566
567
            if (method_exists($field, 'prepare')) {
568
                $value = $field->prepare($value);
569
            }
570
571
            if ($value != $field->original()) {
572
                if (is_array($columns)) {
573
                    foreach ($columns as $name => $column) {
574
                        array_set($prepared, $column, $value[$name]);
575
                    }
576
                } elseif (is_string($columns)) {
577
                    array_set($prepared, $columns, $value);
578
                }
579
            }
580
        }
581
582
        return $prepared;
583
    }
584
585
    /**
586
     * Prepare input data for insert.
587
     *
588
     * @param $inserts
589
     *
590
     * @return array
591
     */
592
    protected function prepareInsert($inserts)
593
    {
594
        $first = current($inserts);
595
596
        if (is_array($first) && Arr::isAssoc($first)) {
597
            $inserts = array_dot($inserts);
598
        }
599
600
        foreach ($inserts as $column => $value) {
601
            if (is_null($field = $this->getFieldByColumn($column))) {
602
                unset($inserts[$column]);
603
                continue;
604
            }
605
606
            if (method_exists($field, 'prepare')) {
607
                $inserts[$column] = $field->prepare($value);
608
            }
609
        }
610
611
        $prepared = [];
612
613
        foreach ($inserts as $key => $value) {
614
            array_set($prepared, $key, $value);
615
        }
616
617
        return $prepared;
618
    }
619
620
    /**
621
     * Set saving callback.
622
     *
623
     * @param callable $callback
624
     *
625
     * @return void
626
     */
627
    public function saving(Closure $callback)
628
    {
629
        $this->saving = $callback;
630
    }
631
632
    /**
633
     * Set saved callback.
634
     *
635
     * @param callable $callback
636
     *
637
     * @return void
638
     */
639
    public function saved(Closure $callback)
640
    {
641
        $this->saved = $callback;
642
    }
643
644
    /**
645
     * @param array        $data
646
     * @param string|array $columns
647
     *
648
     * @return array|mixed
649
     */
650
    protected function getDataByColumn($data, $columns)
651
    {
652
        if (is_string($columns)) {
653
            return array_get($data, $columns);
654
        }
655
656
        if (is_array($columns)) {
657
            $value = [];
658
            foreach ($columns as $name => $column) {
659
                if (!array_has($data, $column)) {
660
                    continue;
661
                }
662
                $value[$name] = array_get($data, $column);
663
            }
664
665
            return $value;
666
        }
667
    }
668
669
    /**
670
     * Find field object by column.
671
     *
672
     * @param $column
673
     *
674
     * @return mixed
675
     */
676
    protected function getFieldByColumn($column)
677
    {
678
        return $this->builder->fields()->first(
679
            function ($index, Field $field) use ($column) {
680
                if (is_array($field->column())) {
681
                    return in_array($column, $field->column());
682
                }
683
684
                return $field->column() == $column;
685
            }
686
        );
687
    }
688
689
    /**
690
     * Set original data for each field.
691
     *
692
     * @return void
693
     */
694
    protected function setFieldOriginalValue()
695
    {
696
        $values = $this->model->toArray();
697
698
        $this->builder->fields()->each(function (Field $field) use ($values) {
699
            $field->setOriginal($values);
700
        });
701
    }
702
703
    /**
704
     * Set all fields value in form.
705
     *
706
     * @param $id
707
     *
708
     * @return void
709
     */
710
    protected function setFieldValue($id)
711
    {
712
        $relations = $this->getRelations();
713
714
        $this->model = $this->model->with($relations)->findOrFail($id);
715
716
        $data = $this->model->toArray();
717
718
        $this->builder->fields()->each(function (Field $field) use ($data) {
719
            $field->fill($data);
720
        });
721
    }
722
723
    /**
724
     * Validation fails.
725
     *
726
     * @param array $input
727
     *
728
     * @return bool
729
     */
730
    protected function validationFails($input)
731
    {
732
        foreach ($this->builder->fields() as $field) {
733
734
            if (!$validator = $field->validate($input)) {
735
                continue;
736
            };
737
738
            if (($validator instanceof Validator) && !$validator->passes()) {
739
                return $validator;
740
            }
741
        }
742
743
        return false;
744
    }
745
746
    /**
747
     * Get all relations of model from callable.
748
     *
749
     * @return array
750
     */
751
    public function getRelations()
752
    {
753
        $relations = $columns = [];
754
755
        foreach ($this->builder->fields() as $field) {
756
            $columns[] = $field->column();
757
        }
758
759
        foreach (array_flatten($columns) as $column) {
760
            if (str_contains($column, '.')) {
761
                list($relation) = explode('.', $column);
762
763
                if (method_exists($this->model, $relation) &&
764
                    $this->model->$relation() instanceof Relation
765
                ) {
766
                    $relations[] = $relation;
767
                }
768
            } elseif (method_exists($this->model, $column)) {
769
                $relations[] = $column;
770
            }
771
        }
772
773
        return array_unique($relations);
774
    }
775
776
    /**
777
     * Get current resource route url.
778
     *
779
     * @param int $slice
780
     *
781
     * @return string
782
     */
783
    public function resource($slice = -2)
784
    {
785
        $route = app('router')->current();
786
787
        $segments = explode('/', trim($route->getUri(), '/'));
788
789
        if ($slice != 0) {
790
            $segments = array_slice($segments, 0, $slice);
791
        }
792
793
        return '/'.implode('/', $segments);
794
    }
795
796
    /**
797
     * Render the form contents.
798
     *
799
     * @return string
800
     */
801
    public function render()
802
    {
803
        try {
804
            return $this->builder->render();
805
        } catch (\Exception $e) {
806
            return with(new Handle($e))->render();
807
        }
808
    }
809
810
    /**
811
     * Get or set input data.
812
     *
813
     * @param string $key
814
     * @param null   $value
815
     *
816
     * @return array|mixed
817
     */
818
    public function input($key, $value = null)
819
    {
820
        if (is_null($value)) {
821
            return array_get($this->inputs, $key);
822
        }
823
824
        return array_set($this->inputs, $key, $value);
825
    }
826
827
    /**
828
     * Register builtin fields.
829
     *
830
     * @return void
831
     */
832
    public static function registerBuiltinFields()
833
    {
834
        $map = [
835
            'button'            => \Encore\Admin\Form\Field\Button::class,
836
            'checkbox'          => \Encore\Admin\Form\Field\Checkbox::class,
837
            'code'              => \Encore\Admin\Form\Field\Code::class,
838
            'color'             => \Encore\Admin\Form\Field\Color::class,
839
            'currency'          => \Encore\Admin\Form\Field\Currency::class,
840
            'date'              => \Encore\Admin\Form\Field\Date::class,
841
            'dateRange'         => \Encore\Admin\Form\Field\DateRange::class,
842
            'datetime'          => \Encore\Admin\Form\Field\Datetime::class,
843
            'dateTimeRange'     => \Encore\Admin\Form\Field\DatetimeRange::class,
844
            'decimal'           => \Encore\Admin\Form\Field\Decimal::class,
845
            'display'           => \Encore\Admin\Form\Field\Display::class,
846
            'divider'           => \Encore\Admin\Form\Field\Divide::class,
847
            'divide'            => \Encore\Admin\Form\Field\Divide::class,
848
            'editor'            => \Encore\Admin\Form\Field\Editor::class,
849
            'email'             => \Encore\Admin\Form\Field\Email::class,
850
            'embedsMany'        => \Encore\Admin\Form\Field\EmbedsMany::class,
851
            'file'              => \Encore\Admin\Form\Field\File::class,
852
            'hasMany'           => \Encore\Admin\Form\Field\HasMany::class,
853
            'hidden'            => \Encore\Admin\Form\Field\Hidden::class,
854
            'id'                => \Encore\Admin\Form\Field\Id::class,
855
            'image'             => \Encore\Admin\Form\Field\Image::class,
856
            'ip'                => \Encore\Admin\Form\Field\Ip::class,
857
            'json'              => \Encore\Admin\Form\Field\Json::class,
858
            'map'               => \Encore\Admin\Form\Field\Map::class,
859
            'mobile'            => \Encore\Admin\Form\Field\Mobile::class,
860
            'month'             => \Encore\Admin\Form\Field\Month::class,
861
            'multipleSelect'    => \Encore\Admin\Form\Field\MultipleSelect::class,
862
            'number'            => \Encore\Admin\Form\Field\Number::class,
863
            'password'          => \Encore\Admin\Form\Field\Password::class,
864
            'radio'             => \Encore\Admin\Form\Field\Radio::class,
865
            'rate'              => \Encore\Admin\Form\Field\Rate::class,
866
            'select'            => \Encore\Admin\Form\Field\Select::class,
867
            'slider'            => \Encore\Admin\Form\Field\Slider::class,
868
            'switch'            => \Encore\Admin\Form\Field\SwitchField::class,
869
            'text'              => \Encore\Admin\Form\Field\Text::class,
870
            'textarea'          => \Encore\Admin\Form\Field\Textarea::class,
871
            'time'              => \Encore\Admin\Form\Field\Time::class,
872
            'timeRange'         => \Encore\Admin\Form\Field\TimeRange::class,
873
            'url'               => \Encore\Admin\Form\Field\Url::class,
874
            'year'              => \Encore\Admin\Form\Field\Year::class,
875
        ];
876
877
        foreach ($map as $abstract => $class) {
878
            static::extend($abstract, $class);
879
        }
880
    }
881
882
    /**
883
     * Register custom field.
884
     *
885
     * @param string $abstract
886
     * @param string $class
887
     *
888
     * @return void
889
     */
890
    public static function extend($abstract, $class)
891
    {
892
        static::$availableFields[$abstract] = $class;
893
    }
894
895
    /**
896
     * Remove registered field.
897
     *
898
     * @param array|string $abstract
899
     */
900
    public static function forget($abstract)
901
    {
902
        array_forget(static::$availableFields, $abstract);
903
    }
904
905
    /**
906
     * Find field class.
907
     *
908
     * @param string $method
909
     *
910
     * @return bool|mixed
911
     */
912 View Code Duplication
    public static function findFieldClass($method)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
913
    {
914
        $class = array_get(static::$availableFields, $method);
915
916
        if (class_exists($class)) {
917
            return $class;
918
        }
919
920
        return false;
921
    }
922
923
    /**
924
     * Collect assets required by registered field.
925
     *
926
     * @return array
927
     */
928
    public static function collectFieldAssets()
929
    {
930
        if (!empty(static::$collectedAssets)) {
931
            return static::$collectedAssets;
932
        }
933
934
        $css = collect();
935
        $js = collect();
936
937
        foreach (static::$availableFields as $field) {
938
            if (!method_exists($field, 'getAssets')) {
939
                continue;
940
            }
941
942
            $assets = call_user_func([$field, 'getAssets']);
943
944
            $css->push(array_get($assets, 'css'));
945
            $js->push(array_get($assets, 'js'));
946
        }
947
948
        return static::$collectedAssets = [
949
            'css' => $css->flatten()->unique()->filter()->toArray(),
950
            'js'  => $js->flatten()->unique()->filter()->toArray(),
951
        ];
952
    }
953
954
    /**
955
     * Getter.
956
     *
957
     * @param string $name
958
     *
959
     * @return array|mixed
960
     */
961
    public function __get($name)
962
    {
963
        return $this->input($name);
964
    }
965
966
    /**
967
     * Setter.
968
     *
969
     * @param string $name
970
     * @param $value
971
     */
972
    public function __set($name, $value)
973
    {
974
        $this->input($name, $value);
975
    }
976
977
    /**
978
     * Generate a Field object and add to form builder if Field exists.
979
     *
980
     * @param string $method
981
     * @param array  $arguments
982
     *
983
     * @return Field|void
984
     */
985 View Code Duplication
    public function __call($method, $arguments)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
986
    {
987
        if ($className = static::findFieldClass($method)) {
988
            $column = array_get($arguments, 0, ''); //[0];
989
990
            $element = new $className($column, array_slice($arguments, 1));
991
992
            $this->pushField($element);
993
994
            return $element;
995
        }
996
    }
997
998
    /**
999
     * Render the contents of the form when casting to string.
1000
     *
1001
     * @return string
1002
     */
1003
    public function __toString()
1004
    {
1005
        return $this->render();
1006
    }
1007
}
1008