Completed
Pull Request — master (#163)
by
unknown
08:39
created

Form::collectFieldAssets()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 4
nop 0
dl 0
loc 25
rs 8.5806
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\Support\Facades\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
     * Available fields.
119
     *
120
     * @var array
121
     */
122
    public static $availableFields = [];
123
124
    /**
125
     * Collected field assets.
126
     *
127
     * @var array
128
     */
129
    protected static $collectedAssets = [];
130
131
    /**
132
     * @param \$model
133
     * @param \Closure $callback
134
     */
135
    public function __construct($model, Closure $callback)
136
    {
137
        $this->model = $model;
138
139
        $this->builder = new Builder($this);
140
141
        $this->callable = $callback;
142
143
        $callback($this);
144
    }
145
146
    /**
147
     * Set up the form.
148
     */
149
    protected function setUp()
150
    {
151
        call_user_func($this->callable, $this);
152
    }
153
154
    /**
155
     * @param Field $field
156
     *
157
     * @return $this
158
     */
159
    public function pushField(Field $field)
160
    {
161
        $field->setForm($this);
162
163
        $this->builder->fields()->push($field);
164
165
        return $this;
166
    }
167
168
    /**
169
     * @return Model
170
     */
171
    public function model()
172
    {
173
        return $this->model;
174
    }
175
176
    /**
177
     * @return Builder
178
     */
179
    public function builder()
180
    {
181
        return $this->builder;
182
    }
183
184
    /**
185
     * Generate a edit form.
186
     *
187
     * @param $id
188
     *
189
     * @return $this
190
     */
191
    public function edit($id)
192
    {
193
        $this->builder->setMode(Builder::MODE_EDIT);
194
        $this->builder->setResourceId($id);
195
196
        $this->setFieldValue($id);
197
198
        return $this;
199
    }
200
201
    /**
202
     * @param $id
203
     *
204
     * @return $this
205
     */
206
    public function view($id)
207
    {
208
        $this->builder->setMode(Builder::MODE_VIEW);
209
        $this->builder->setResourceId($id);
210
211
        $this->setFieldValue($id);
212
213
        return $this;
214
    }
215
216
    /**
217
     * Destroy data entity and remove files.
218
     *
219
     * @param $id
220
     *
221
     * @return mixed
222
     */
223
    public function destroy($id)
224
    {
225
        $ids = explode(',', $id);
226
227
        foreach ($ids as $id) {
228
            if (empty($id)) {
229
                continue;
230
            }
231
            $this->deleteFilesAndImages($id);
232
            $this->model->find($id)->delete();
233
        }
234
235
        return true;
236
    }
237
238
    /**
239
     * Remove files or images in record.
240
     *
241
     * @param $id
242
     */
243
    protected function deleteFilesAndImages($id)
244
    {
245
        $data = $this->model->with($this->getRelations())
246
            ->findOrFail($id)->toArray();
247
248
        $this->builder->fields()->filter(function ($field) {
249
            return $field instanceof Field\File;
250
        })->each(function (File $file) use ($data) {
251
            $file->setOriginal($data);
252
253
            $file->destroy();
254
        });
255
    }
256
257
    /**
258
     * Store a new record.
259
     *
260
     * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
261
     */
262
    public function store()
263
    {
264
        $data = Input::all();
265
266
        if (!$this->validate($data)) {
267
            return back()->withInput()->withErrors($this->validator->messages());
268
        }
269
270
        $this->prepare($data, $this->saving);
271
272 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...
273
            $inserts = $this->prepareInsert($this->updates);
274
275
            foreach ($inserts as $column => $value) {
276
                if (is_array($value)) {
277
                    $value = implode(',', $value);
278
                }
279
                $this->model->setAttribute($column, $value);
280
            }
281
282
            $this->model->save();
283
284
            $this->saveRelation($this->relations);
285
        });
286
287
        $this->complete($this->saved);
288
289
        return redirect($this->resource(0));
290
    }
291
292
    /**
293
     * Prepare input data for insert or update.
294
     *
295
     * @param array    $data
296
     * @param callable $callback
297
     */
298
    protected function prepare($data = [], Closure $callback = null)
299
    {
300
        $this->inputs = $data;
301
302
        if ($callback instanceof Closure) {
303
            $callback($this);
304
        }
305
306
        $this->relations = $this->getRelationInputs($data);
307
308
        $updates = array_except($this->inputs, array_keys($this->relations));
309
310
        $this->updates = array_filter($updates, function ($val) {
311
            return !is_null($val);
312
        });
313
    }
314
315
    /**
316
     * Get inputs for relations.
317
     *
318
     * @param array $inputs
319
     *
320
     * @return array
321
     */
322
    protected function getRelationInputs($inputs = [])
323
    {
324
        $relations = [];
325
326
        foreach ($inputs as $column => $value) {
327
            if (method_exists($this->model, $column)) {
328
                $relation = call_user_func([$this->model, $column]);
329
330
                if ($relation instanceof Relation) {
331
                    $relations[$column] = $value;
332
                }
333
            }
334
        }
335
336
        return $relations;
337
    }
338
339
    /**
340
     * Callback after saving a Model.
341
     *
342
     * @param Closure|null $callback
343
     *
344
     * @return void
345
     */
346
    protected function complete(Closure $callback = null)
347
    {
348
        if ($callback instanceof Closure) {
349
            $callback($this);
350
        }
351
    }
352
353
    /**
354
     * Save relations data.
355
     *
356
     * @param array $relations
357
     *
358
     * @return void
359
     */
360
    protected function saveRelation($relations)
361
    {
362
        foreach ($relations as $name => $values) {
363
            if (!method_exists($this->model, $name)) {
364
                continue;
365
            }
366
367
            $values = $this->prepareInsert([$name => $values]);
368
369
            $relation = $this->model->$name();
370
371
            switch (get_class($relation)) {
372
                case \Illuminate\Database\Eloquent\Relations\BelongsToMany::class:
373
                case \Illuminate\Database\Eloquent\Relations\MorphToMany::class:
374
                    $relation->attach($values[$name]);
375
                    break;
376
                case \Illuminate\Database\Eloquent\Relations\HasOne::class:
377
                    $related = $relation->getRelated();
378
                    foreach ($values[$name] as $column => $value) {
379
                        $related->setAttribute($column, $value);
380
                    }
381
382
                    $relation->save($related);
383
                    break;
384
            }
385
        }
386
    }
387
388
    /**
389
     * Handle update.
390
     *
391
     * @param int $id
392
     *
393
     * @return $this|\Illuminate\Http\RedirectResponse
394
     */
395
    public function update($id)
396
    {
397
        $data = Input::all();
398
399
        $data = $this->handleEditable($data);
400
401
        if ($this->handleOrderable($id, $data)) {
402
            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...
403
        }
404
405
        if (!$this->validate($data)) {
406
            return back()->withInput()->withErrors($this->validator->messages());
407
        }
408
409
        $this->model = $this->model->with($this->getRelations())->findOrFail($id);
410
411
        $this->setFieldOriginalValue();
412
413
        $this->prepare($data, $this->saving);
414
415 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...
416
            $updates = $this->prepareUpdate($this->updates);
417
418
            foreach ($updates as $column => $value) {
419
                if (is_array($value)) {
420
                    $value = implode(',', $value);
421
                }
422
423
                $this->model->setAttribute($column, $value);
424
            }
425
426
            $this->model->save();
427
428
            $this->updateRelation($this->relations);
429
        });
430
431
        $this->complete($this->saved);
432
433
        return redirect($this->resource(-1));
434
    }
435
436
    /**
437
     * Handle editable update.
438
     *
439
     * @param array $input
440
     *
441
     * @return array
442
     */
443
    protected function handleEditable(array $input = [])
444
    {
445
        if (array_key_exists('_editable', $input)) {
446
            $name = $input['name'];
447
            $value = $input['value'];
448
449
            array_forget($input, ['pk', 'value', 'name']);
450
            array_set($input, $name, $value);
451
        }
452
453
        return $input;
454
    }
455
456
    /**
457
     * Handle orderable update.
458
     *
459
     * @param int   $id
460
     * @param array $input
461
     *
462
     * @return array
463
     */
464
    protected function handleOrderable($id, array $input = [])
465
    {
466
        if (array_key_exists('_orderable', $input)) {
467
            $model = $this->model->find($id);
468
469
            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...
470
                $input['_orderable'] == 1 ? $model->moveOrderUp() : $model->moveOrderDown();
471
472
                return true;
473
            }
474
        }
475
476
        return false;
477
    }
478
479
    /**
480
     * Update relation data.
481
     *
482
     * @param array $relations
483
     *
484
     * @return void
485
     */
486
    protected function updateRelation($relations)
487
    {
488
        foreach ($relations as $name => $values) {
489
            if (!method_exists($this->model, $name)) {
490
                continue;
491
            }
492
493
            $prepared = $this->prepareUpdate([$name => $values]);
494
495
            if (empty($prepared)) {
496
                continue;
497
            }
498
499
            $relation = $this->model->$name();
500
501
            switch (get_class($relation)) {
502
                case \Illuminate\Database\Eloquent\Relations\BelongsToMany::class:
503
                case \Illuminate\Database\Eloquent\Relations\MorphToMany::class:
504
                    $relation->sync($prepared[$name]);
505
                    break;
506
                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...
507
508
                    $related = $this->model->$name;
509
510
                    // if related is empty
511
                    if (is_null($related)) {
512
                        $related = $relation->getRelated();
513
                        $related->{$relation->getForeignKey()} = $this->model->{$this->model->getKeyName()};
514
                    }
515
516
                    foreach ($prepared[$name] as $column => $value) {
517
                        $related->setAttribute($column, $value);
518
                    }
519
520
                    $related->save();
521
                    break;
522
            }
523
        }
524
    }
525
526
    /**
527
     * Prepare input data for update.
528
     *
529
     * @param $updates
530
     *
531
     * @return array
532
     */
533
    protected function prepareUpdate($updates)
534
    {
535
        $prepared = [];
536
537
        foreach ($this->builder->fields() as $field) {
538
            $columns = $field->column();
539
540
            $value = $this->getDataByColumn($updates, $columns);
541
542
            if ($value !== '' && $value !== '0' && !$field instanceof File && empty($value)) {
543
                continue;
544
            }
545
546
            if (method_exists($field, 'prepare')) {
547
                $value = $field->prepare($value);
548
            }
549
550
            if ($value != $field->original()) {
551
                if (is_array($columns)) {
552
                    foreach ($columns as $name => $column) {
553
                        array_set($prepared, $column, $value[$name]);
554
                    }
555
                } elseif (is_string($columns)) {
556
                    array_set($prepared, $columns, $value);
557
                }
558
            }
559
        }
560
561
        return $prepared;
562
    }
563
564
    /**
565
     * Prepare input data for insert.
566
     *
567
     * @param $inserts
568
     *
569
     * @return array
570
     */
571
    protected function prepareInsert($inserts)
572
    {
573
        $first = current($inserts);
574
575
        if (is_array($first) && Arr::isAssoc($first)) {
576
            $inserts = array_dot($inserts);
577
        }
578
579
        foreach ($inserts as $column => $value) {
580
            if (is_null($field = $this->getFieldByColumn($column))) {
581
                unset($inserts[$column]);
582
                continue;
583
            }
584
585
            if (method_exists($field, 'prepare')) {
586
                $inserts[$column] = $field->prepare($value);
587
            }
588
        }
589
590
        $prepared = [];
591
592
        foreach ($inserts as $key => $value) {
593
            array_set($prepared, $key, $value);
594
        }
595
596
        return $prepared;
597
    }
598
599
    /**
600
     * Set saving callback.
601
     *
602
     * @param callable $callback
603
     *
604
     * @return void
605
     */
606
    public function saving(Closure $callback)
607
    {
608
        $this->saving = $callback;
609
    }
610
611
    /**
612
     * Set saved callback.
613
     *
614
     * @param callable $callback
615
     *
616
     * @return void
617
     */
618
    public function saved(Closure $callback)
619
    {
620
        $this->saved = $callback;
621
    }
622
623
    /**
624
     * @param array        $data
625
     * @param string|array $columns
626
     *
627
     * @return array|mixed
628
     */
629
    protected function getDataByColumn($data, $columns)
630
    {
631
        if (is_string($columns)) {
632
            return array_get($data, $columns);
633
        }
634
635
        if (is_array($columns)) {
636
            $value = [];
637
            foreach ($columns as $name => $column) {
638
                if (!array_has($data, $column)) {
639
                    continue;
640
                }
641
                $value[$name] = array_get($data, $column);
642
            }
643
644
            return $value;
645
        }
646
    }
647
648
    /**
649
     * Find field object by column.
650
     *
651
     * @param $column
652
     *
653
     * @return mixed
654
     */
655
    protected function getFieldByColumn($column)
656
    {
657
        return $this->builder->fields()->first(
658
            function ($index, Field $field) use ($column) {
659
                if (is_array($field->column())) {
660
                    return in_array($column, $field->column());
661
                }
662
663
                return $field->column() == $column;
664
            }
665
        );
666
    }
667
668
    /**
669
     * Set original data for each field.
670
     *
671
     * @return void
672
     */
673
    protected function setFieldOriginalValue()
674
    {
675
        $values = $this->model->toArray();
676
677
        $this->builder->fields()->each(function (Field $field) use ($values) {
678
            $field->setOriginal($values);
679
        });
680
    }
681
682
    /**
683
     * Set all fields value in form.
684
     *
685
     * @param $id
686
     *
687
     * @return void
688
     */
689
    protected function setFieldValue($id)
690
    {
691
        $relations = $this->getRelations();
692
693
        $this->model = $this->model->with($relations)->findOrFail($id);
694
695
        $data = $this->model->toArray();
696
697
        $this->builder->fields()->each(function (Field $field) use ($data) {
698
            $field->fill($data);
699
        });
700
    }
701
702
    /**
703
     * Validate input data.
704
     *
705
     * @param $input
706
     *
707
     * @return bool
708
     */
709
    protected function validate($input)
710
    {
711
        $data = $rules = [];
712
713
        foreach ($this->builder->fields() as $field) {
714
            if (!method_exists($field, 'rules') || !$rule = $field->rules()) {
715
                continue;
716
            }
717
718
            $columns = $field->column();
719
720
            if (is_string($columns)) {
721
                if (!array_key_exists($columns, $input)) {
722
                    continue;
723
                }
724
725
                $value = array_get($input, $columns);
726
727
                // remove empty options from multiple select.
728
                if ($field instanceof Field\MultipleSelect) {
729
                    $value = array_filter($value);
730
                }
731
732
                $data[$field->label()] = $value;
733
                $rules[$field->label()] = $rule;
734
            }
735
736
            if (is_array($columns)) {
737
                foreach ($columns as $key => $column) {
738
                    if (!array_key_exists($column, $input)) {
739
                        continue;
740
                    }
741
                    $data[$field->label().$key] = array_get($input, $column);
742
                    $rules[$field->label().$key] = $rule;
743
                }
744
            }
745
        }
746
747
        $this->validator = Validator::make($data, $rules);
748
749
        return $this->validator->passes();
750
    }
751
752
    /**
753
     * Get all relations of model from callable.
754
     *
755
     * @return array
756
     */
757
    public function getRelations()
758
    {
759
        $relations = $columns = [];
760
761
        foreach ($this->builder->fields() as $field) {
762
            $columns[] = $field->column();
763
        }
764
765
        foreach (array_flatten($columns) as $column) {
766
            if (str_contains($column, '.')) {
767
                list($relation) = explode('.', $column);
768
769
                if (method_exists($this->model, $relation) &&
770
                    $this->model->$relation() instanceof Relation
771
                ) {
772
                    $relations[] = $relation;
773
                }
774
            } elseif (method_exists($this->model, $column)) {
775
                $relations[] = $column;
776
            }
777
        }
778
779
        return array_unique($relations);
780
    }
781
782
    /**
783
     * Get current resource route url.
784
     *
785
     * @param int $slice
786
     *
787
     * @return string
788
     */
789
    public function resource($slice = -2)
790
    {
791
        $route = app('router')->current();
792
793
        $segments = explode('/', trim($route->getUri(), '/'));
794
795
        if ($slice != 0) {
796
            $segments = array_slice($segments, 0, $slice);
797
        }
798
799
        return '/'.implode('/', $segments);
800
    }
801
802
    /**
803
     * Render the form contents.
804
     *
805
     * @return string
806
     */
807
    public function render()
808
    {
809
        try {
810
            return $this->builder->render();
811
        } catch (\Exception $e) {
812
            return with(new Handle($e))->render();
813
        }
814
    }
815
816
    /**
817
     * Get or set input data.
818
     *
819
     * @param string $key
820
     * @param null   $value
821
     *
822
     * @return array|mixed
823
     */
824
    public function input($key, $value = null)
825
    {
826
        if (is_null($value)) {
827
            return array_get($this->inputs, $key);
828
        }
829
830
        return array_set($this->inputs, $key, $value);
831
    }
832
833
    /**
834
     * Register builtin fields.
835
     *
836
     * @return void
837
     */
838
    public static function registerBuiltinFields()
839
    {
840
        $map = [
841
            'button'            => \Encore\Admin\Form\Field\Button::class,
842
            'checkbox'          => \Encore\Admin\Form\Field\Checkbox::class,
843
            'code'              => \Encore\Admin\Form\Field\Code::class,
844
            'color'             => \Encore\Admin\Form\Field\Color::class,
845
            'currency'          => \Encore\Admin\Form\Field\Currency::class,
846
            'date'              => \Encore\Admin\Form\Field\Date::class,
847
            'dateRange'         => \Encore\Admin\Form\Field\DateRange::class,
848
            'datetime'          => \Encore\Admin\Form\Field\Datetime::class,
849
            'dateTimeRange'     => \Encore\Admin\Form\Field\DatetimeRange::class,
850
            'decimal'           => \Encore\Admin\Form\Field\Decimal::class,
851
            'display'           => \Encore\Admin\Form\Field\Display::class,
852
            'divider'           => \Encore\Admin\Form\Field\Divide::class,
853
            'divide'            => \Encore\Admin\Form\Field\Divide::class,
854
            'editor'            => \Encore\Admin\Form\Field\Editor::class,
855
            'email'             => \Encore\Admin\Form\Field\Email::class,
856
            'embedsMany'        => \Encore\Admin\Form\Field\EmbedsMany::class,
857
            'file'              => \Encore\Admin\Form\Field\File::class,
858
            'hasMany'           => \Encore\Admin\Form\Field\HasMany::class,
859
            'hidden'            => \Encore\Admin\Form\Field\Hidden::class,
860
            'id'                => \Encore\Admin\Form\Field\Id::class,
861
            'image'             => \Encore\Admin\Form\Field\Image::class,
862
            'ip'                => \Encore\Admin\Form\Field\Ip::class,
863
            'json'              => \Encore\Admin\Form\Field\Json::class,
864
            'map'               => \Encore\Admin\Form\Field\Map::class,
865
            'mobile'            => \Encore\Admin\Form\Field\Mobile::class,
866
            'month'             => \Encore\Admin\Form\Field\Month::class,
867
            'multipleSelect'    => \Encore\Admin\Form\Field\MultipleSelect::class,
868
            'number'            => \Encore\Admin\Form\Field\Number::class,
869
            'password'          => \Encore\Admin\Form\Field\Password::class,
870
            'radio'             => \Encore\Admin\Form\Field\Radio::class,
871
            'rate'              => \Encore\Admin\Form\Field\Rate::class,
872
            'select'            => \Encore\Admin\Form\Field\Select::class,
873
            'slider'            => \Encore\Admin\Form\Field\Slider::class,
874
            'switch'            => \Encore\Admin\Form\Field\SwitchField::class,
875
            'text'              => \Encore\Admin\Form\Field\Text::class,
876
            'textarea'          => \Encore\Admin\Form\Field\Textarea::class,
877
            'time'              => \Encore\Admin\Form\Field\Time::class,
878
            'timeRange'         => \Encore\Admin\Form\Field\TimeRange::class,
879
            'url'               => \Encore\Admin\Form\Field\Url::class,
880
            'year'              => \Encore\Admin\Form\Field\Year::class,
881
        ];
882
883
        foreach ($map as $abstract => $class) {
884
            static::extend($abstract, $class);
885
        }
886
    }
887
888
    /**
889
     * Register custom field.
890
     *
891
     * @param string $abstract
892
     * @param string $class
893
     *
894
     * @return void
895
     */
896
    public static function extend($abstract, $class)
897
    {
898
        static::$availableFields[$abstract] = $class;
899
    }
900
901
    /**
902
     * Remove registered field.
903
     *
904
     * @param array|string $abstract
905
     */
906
    public static function forget($abstract)
907
    {
908
        array_forget(static::$availableFields, $abstract);
909
    }
910
911
    /**
912
     * Find field class.
913
     *
914
     * @param string $method
915
     *
916
     * @return bool|mixed
917
     */
918 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...
919
    {
920
        $class = array_get(static::$availableFields, $method);
921
922
        if (class_exists($class)) {
923
            return $class;
924
        }
925
926
        return false;
927
    }
928
929
    /**
930
     * Collect assets required by registered field.
931
     *
932
     * @return array
933
     */
934
    public static function collectFieldAssets()
935
    {
936
        if (!empty(static::$collectedAssets)) {
937
            return static::$collectedAssets;
938
        }
939
940
        $css = collect();
941
        $js = collect();
942
943
        foreach (static::$availableFields as $field) {
944
            if (!method_exists($field, 'getAssets')) {
945
                continue;
946
            }
947
948
            $assets = call_user_func([$field, 'getAssets']);
949
950
            $css->push(array_get($assets, 'css'));
951
            $js->push(array_get($assets, 'js'));
952
        }
953
954
        return static::$collectedAssets = [
955
            'css' => $css->flatten()->unique()->filter()->toArray(),
956
            'js'  => $js->flatten()->unique()->filter()->toArray(),
957
        ];
958
    }
959
960
    /**
961
     * Getter.
962
     *
963
     * @param string $name
964
     *
965
     * @return array|mixed
966
     */
967
    public function __get($name)
968
    {
969
        return $this->input($name);
970
    }
971
972
    /**
973
     * Setter.
974
     *
975
     * @param string $name
976
     * @param $value
977
     */
978
    public function __set($name, $value)
979
    {
980
        $this->input($name, $value);
981
    }
982
983
    /**
984
     * Generate a Field object and add to form builder if Field exists.
985
     *
986
     * @param string $method
987
     * @param array  $arguments
988
     *
989
     * @return Field|void
990
     */
991 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...
992
    {
993
        if ($className = static::findFieldClass($method)) {
994
            $column = array_get($arguments, 0, ''); //[0];
995
996
            $element = new $className($column, array_slice($arguments, 1));
997
998
            $this->pushField($element);
999
1000
            return $element;
1001
        }
1002
    }
1003
1004
    /**
1005
     * Render the contents of the form when casting to string.
1006
     *
1007
     * @return string
1008
     */
1009
    public function __toString()
1010
    {
1011
        return $this->render();
1012
    }
1013
}
1014