Completed
Push — master ( b50b45...3d945d )
by Song
02:38
created

Form::setAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin;
4
5
use Closure;
6
use Encore\Admin\Exception\Handler;
7
use Encore\Admin\Form\Builder;
8
use Encore\Admin\Form\Field;
9
use Encore\Admin\Form\Row;
10
use Encore\Admin\Form\Tab;
11
use Illuminate\Contracts\Support\Renderable;
12
use Illuminate\Database\Eloquent\Model;
13
use Illuminate\Database\Eloquent\Relations;
14
use Illuminate\Database\Eloquent\SoftDeletes;
15
use Illuminate\Http\Request;
16
use Illuminate\Support\Arr;
17
use Illuminate\Support\Facades\DB;
18
use Illuminate\Support\Facades\Input;
19
use Illuminate\Support\MessageBag;
20
use Illuminate\Support\Str;
21
use Illuminate\Validation\Validator;
22
use Spatie\EloquentSortable\Sortable;
23
use Symfony\Component\HttpFoundation\Response;
24
25
/**
26
 * Class Form.
27
 *
28
 * @method Field\Text           text($column, $label = '')
29
 * @method Field\Checkbox       checkbox($column, $label = '')
30
 * @method Field\Radio          radio($column, $label = '')
31
 * @method Field\Select         select($column, $label = '')
32
 * @method Field\MultipleSelect multipleSelect($column, $label = '')
33
 * @method Field\Textarea       textarea($column, $label = '')
34
 * @method Field\Hidden         hidden($column, $label = '')
35
 * @method Field\Id             id($column, $label = '')
36
 * @method Field\Ip             ip($column, $label = '')
37
 * @method Field\Url            url($column, $label = '')
38
 * @method Field\Color          color($column, $label = '')
39
 * @method Field\Email          email($column, $label = '')
40
 * @method Field\Mobile         mobile($column, $label = '')
41
 * @method Field\Slider         slider($column, $label = '')
42
 * @method Field\Map            map($latitude, $longitude, $label = '')
43
 * @method Field\Editor         editor($column, $label = '')
44
 * @method Field\File           file($column, $label = '')
45
 * @method Field\Image          image($column, $label = '')
46
 * @method Field\Date           date($column, $label = '')
47
 * @method Field\Datetime       datetime($column, $label = '')
48
 * @method Field\Time           time($column, $label = '')
49
 * @method Field\Year           year($column, $label = '')
50
 * @method Field\Month          month($column, $label = '')
51
 * @method Field\DateRange      dateRange($start, $end, $label = '')
52
 * @method Field\DateTimeRange  datetimeRange($start, $end, $label = '')
53
 * @method Field\TimeRange      timeRange($start, $end, $label = '')
54
 * @method Field\Number         number($column, $label = '')
55
 * @method Field\Currency       currency($column, $label = '')
56
 * @method Field\HasMany        hasMany($relationName, $callback)
57
 * @method Field\SwitchField    switch($column, $label = '')
58
 * @method Field\Display        display($column, $label = '')
59
 * @method Field\Rate           rate($column, $label = '')
60
 * @method Field\Divide         divider()
61
 * @method Field\Password       password($column, $label = '')
62
 * @method Field\Decimal        decimal($column, $label = '')
63
 * @method Field\Html           html($html, $label = '')
64
 * @method Field\Tags           tags($column, $label = '')
65
 * @method Field\Icon           icon($column, $label = '')
66
 * @method Field\Embeds         embeds($column, $label = '')
67
 * @method Field\MultipleImage  multipleImage($column, $label = '')
68
 * @method Field\MultipleFile   multipleFile($column, $label = '')
69
 * @method Field\Captcha        captcha($column, $label = '')
70
 * @method Field\Listbox        listbox($column, $label = '')
71
 */
72
class Form implements Renderable
73
{
74
    /**
75
     * Eloquent model of the form.
76
     *
77
     * @var Model
78
     */
79
    protected $model;
80
81
    /**
82
     * @var \Illuminate\Validation\Validator
83
     */
84
    protected $validator;
85
86
    /**
87
     * @var Builder
88
     */
89
    protected $builder;
90
91
    /**
92
     * Submitted callback.
93
     *
94
     * @var Closure[]
95
     */
96
    protected $submitted = [];
97
98
    /**
99
     * Saving callback.
100
     *
101
     * @var Closure[]
102
     */
103
    protected $saving = [];
104
105
    /**
106
     * Saved callback.
107
     *
108
     * @var Closure[]
109
     */
110
    protected $saved = [];
111
112
    /**
113
     * Callbacks after getting editing model.
114
     *
115
     * @var Closure[]
116
     */
117
    protected $editing = [];
118
119
    /**
120
     * Data for save to current model from input.
121
     *
122
     * @var array
123
     */
124
    protected $updates = [];
125
126
    /**
127
     * Data for save to model's relations from input.
128
     *
129
     * @var array
130
     */
131
    protected $relations = [];
132
133
    /**
134
     * Input data.
135
     *
136
     * @var array
137
     */
138
    protected $inputs = [];
139
140
    /**
141
     * Available fields.
142
     *
143
     * @var array
144
     */
145
    public static $availableFields = [];
146
147
    /**
148
     * Form field alias.
149
     *
150
     * @var array
151
     */
152
    public static $fieldAlias = [];
153
154
    /**
155
     * Ignored saving fields.
156
     *
157
     * @var array
158
     */
159
    protected $ignored = [];
160
161
    /**
162
     * Collected field assets.
163
     *
164
     * @var array
165
     */
166
    protected static $collectedAssets = [];
167
168
    /**
169
     * @var Form\Tab
170
     */
171
    protected $tab = null;
172
173
    /**
174
     * Remove flag in `has many` form.
175
     */
176
    const REMOVE_FLAG_NAME = '_remove_';
177
178
    /**
179
     * Field rows in form.
180
     *
181
     * @var array
182
     */
183
    public $rows = [];
184
185
    /**
186
     * Create a new form instance.
187
     *
188
     * @param $model
189
     * @param \Closure $callback
190
     */
191
    public function __construct($model, Closure $callback = null)
192
    {
193
        $this->model = $model;
194
195
        $this->builder = new Builder($this);
196
197
        if ($callback instanceof Closure) {
198
            $callback($this);
199
        }
200
    }
201
202
    /**
203
     * @param Field $field
204
     *
205
     * @return $this
206
     */
207
    public function pushField(Field $field)
208
    {
209
        $field->setForm($this);
210
211
        $this->builder->fields()->push($field);
212
213
        return $this;
214
    }
215
216
    /**
217
     * @return Model
218
     */
219
    public function model()
220
    {
221
        if ($this->isSoftDeletes()) {
222
            return $this->model->withTrashed();
223
        }
224
225
        return $this->model;
226
    }
227
228
    /**
229
     * @return Builder
230
     */
231
    public function builder()
232
    {
233
        return $this->builder;
234
    }
235
236
    /**
237
     * Generate a edit form.
238
     *
239
     * @param $id
240
     *
241
     * @return $this
242
     */
243
    public function edit($id)
244
    {
245
        $this->builder->setMode(Builder::MODE_EDIT);
246
        $this->builder->setResourceId($id);
247
248
        $this->setFieldValue($id);
249
250
        return $this;
251
    }
252
253
    /**
254
     * Use tab to split form.
255
     *
256
     * @param string  $title
257
     * @param Closure $content
258
     *
259
     * @return $this
260
     */
261
    public function tab($title, Closure $content, $active = false)
262
    {
263
        $this->getTab()->append($title, $content, $active);
264
265
        return $this;
266
    }
267
268
    /**
269
     * Get Tab instance.
270
     *
271
     * @return Tab
272
     */
273
    public function getTab()
274
    {
275
        if (is_null($this->tab)) {
276
            $this->tab = new Tab($this);
277
        }
278
279
        return $this->tab;
280
    }
281
282
    /**
283
     * If is a soft-deletes model.
284
     *
285
     * @return bool
286
     */
287
    protected function isSoftDeletes()
288
    {
289
        return in_array(SoftDeletes::class, class_uses($this->model));
290
    }
291
292
    /**
293
     * Destroy data entity and remove files.
294
     *
295
     * @param $id
296
     *
297
     * @return mixed
298
     */
299
    public function destroy($id)
300
    {
301
        collect(explode(',', $id))->filter()->each(function ($id) {
302
303
            $model = $this->model()->findOrFail($id);
304
305
            if ($model->trashed()) {
306
                $this->deleteFiles($id, true);
307
                $model->forceDelete();
308
309
                return;
310
            }
311
312
            $this->deleteFiles($id);
313
            $model->delete();
314
        });
315
316
        return true;
317
    }
318
319
    /**
320
     * Remove files in record.
321
     *
322
     * @param mixed $id
323
     * @param bool  $forceDelete
324
     */
325
    protected function deleteFiles($id, $forceDelete = false)
326
    {
327
        // If it's a soft delete, the files in the data will not be deleted.
328
        if (!$forceDelete && $this->isSoftDeletes()) {
329
            return;
330
        }
331
332
        $data = $this
0 ignored issues
show
Bug introduced by
The method findOrFail does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Eloquent\Model.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
333
            ->model()
334
            ->with($this->getRelations())
335
            ->findOrFail($id)->toArray();
336
337
        $this->builder->fields()->filter(function ($field) {
338
            return $field instanceof Field\File;
339
        })->each(function (Field\File $file) use ($data) {
340
            $file->setOriginal($data);
341
342
            $file->destroy();
343
        });
344
    }
345
346
    /**
347
     * Store a new record.
348
     *
349
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\Http\JsonResponse
350
     */
351
    public function store()
352
    {
353
        $data = Input::all();
354
355
        // Handle validation errors.
356
        if ($validationMessages = $this->validationMessages($data)) {
357
            return back()->withInput()->withErrors($validationMessages);
358
        }
359
360
        if (($response = $this->prepare($data)) instanceof Response) {
361
            return $response;
362
        }
363
364 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...
365
            $inserts = $this->prepareInsert($this->updates);
366
367
            foreach ($inserts as $column => $value) {
368
                $this->model->setAttribute($column, $value);
369
            }
370
371
            $this->model->save();
372
373
            $this->updateRelation($this->relations);
374
        });
375
376
        if (($response = $this->callSaved()) instanceof Response) {
377
            return $response;
378
        }
379
380
        if ($response = $this->ajaxResponse(trans('admin.save_succeeded'))) {
381
            return $response;
382
        }
383
384
        return $this->redirectAfterStore();
385
    }
386
387
    /**
388
     * Get ajax response.
389
     *
390
     * @param string $message
391
     *
392
     * @return bool|\Illuminate\Http\JsonResponse
393
     */
394
    protected function ajaxResponse($message)
395
    {
396
        $request = Request::capture();
397
398
        // ajax but not pjax
399
        if ($request->ajax() && !$request->pjax()) {
400
            return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
401
                'status'  => true,
402
                'message' => $message,
403
            ]);
404
        }
405
406
        return false;
407
    }
408
409
    /**
410
     * Prepare input data for insert or update.
411
     *
412
     * @param array $data
413
     *
414
     * @return mixed
415
     */
416
    protected function prepare($data = [])
417
    {
418
        if (($response = $this->callSubmitted()) instanceof Response) {
419
            return $response;
420
        }
421
422
        $this->inputs = array_merge($this->removeIgnoredFields($data), $this->inputs);
423
424
        if (($response = $this->callSaving()) instanceof Response) {
425
            return $response;
426
        }
427
428
        $this->relations = $this->getRelationInputs($this->inputs);
429
430
        $this->updates = array_except($this->inputs, array_keys($this->relations));
431
    }
432
433
    /**
434
     * Remove ignored fields from input.
435
     *
436
     * @param array $input
437
     *
438
     * @return array
439
     */
440
    protected function removeIgnoredFields($input)
441
    {
442
        array_forget($input, $this->ignored);
443
444
        return $input;
445
    }
446
447
    /**
448
     * Get inputs for relations.
449
     *
450
     * @param array $inputs
451
     *
452
     * @return array
453
     */
454
    protected function getRelationInputs($inputs = [])
455
    {
456
        $relations = [];
457
458
        foreach ($inputs as $column => $value) {
459
            if (method_exists($this->model, $column)) {
460
                $relation = call_user_func([$this->model, $column]);
461
462
                if ($relation instanceof Relations\Relation) {
463
                    $relations[$column] = $value;
464
                }
465
            }
466
        }
467
468
        return $relations;
469
    }
470
471
    /**
472
     * Call editing callbacks.
473
     *
474
     * @return void
475
     */
476
    protected function callEditing()
477
    {
478
        foreach ($this->editing as $func) {
479
            call_user_func($func, $this);
480
        }
481
    }
482
483
    /**
484
     * Call submitted callback.
485
     *
486
     * @return mixed
487
     */
488
    protected function callSubmitted()
489
    {
490
        foreach ($this->submitted as $func) {
491
            if ($func instanceof Closure && ($ret = call_user_func($func, $this)) instanceof Response) {
492
                return $ret;
493
            }
494
        }
495
    }
496
497
    /**
498
     * Call saving callback.
499
     *
500
     * @return mixed
501
     */
502
    protected function callSaving()
503
    {
504
        foreach ($this->saving as $func) {
505
            if ($func instanceof Closure && ($ret = call_user_func($func, $this)) instanceof Response) {
506
                return $ret;
507
            }
508
        }
509
    }
510
511
    /**
512
     * Callback after saving a Model.
513
     *
514
     * @return mixed|null
515
     */
516
    protected function callSaved()
517
    {
518
        foreach ($this->saved as $func) {
519
            if ($func instanceof Closure && ($ret = call_user_func($func, $this)) instanceof Response) {
520
                return $ret;
521
            }
522
        }
523
    }
524
525
    /**
526
     * Handle update.
527
     *
528
     * @param int $id
529
     *
530
     * @return \Symfony\Component\HttpFoundation\Response
531
     */
532
    public function update($id, $data = null)
533
    {
534
        $data = ($data) ?: Input::all();
535
536
        $isEditable = $this->isEditable($data);
537
538
        $data = $this->handleEditable($data);
539
540
        $data = $this->handleFileDelete($data);
541
542
        if ($this->handleOrderable($id, $data)) {
543
            return response([
0 ignored issues
show
Bug Compatibility introduced by
The expression response(array('status' ...n.update_succeeded'))); of type Illuminate\Http\Response...Routing\ResponseFactory adds the type Illuminate\Contracts\Routing\ResponseFactory to the return on line 543 which is incompatible with the return type documented by Encore\Admin\Form::update of type Symfony\Component\HttpFoundation\Response.
Loading history...
544
                'status'  => true,
545
                'message' => trans('admin.update_succeeded'),
546
            ]);
547
        }
548
549
        /* @var Model $this->model */
550
        $this->model = $this->model->with($this->getRelations())->findOrFail($id);
0 ignored issues
show
Bug introduced by
The method findOrFail does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Eloquent\Model.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
551
552
        $this->setFieldOriginalValue();
553
554
        // Handle validation errors.
555
        if ($validationMessages = $this->validationMessages($data)) {
556
            if (!$isEditable) {
557
                return back()->withInput()->withErrors($validationMessages);
558
            } else {
559
                return response()->json(['errors' => array_dot($validationMessages->getMessages())], 422);
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
560
            }
561
        }
562
563
        if (($response = $this->prepare($data)) instanceof Response) {
564
            return $response;
565
        }
566
567 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...
568
            $updates = $this->prepareUpdate($this->updates);
569
570
            foreach ($updates as $column => $value) {
571
                /* @var Model $this->model */
572
                $this->model->setAttribute($column, $value);
573
            }
574
575
            $this->model->save();
576
577
            $this->updateRelation($this->relations);
578
        });
579
580
        if (($result = $this->callSaved()) instanceof Response) {
581
            return $result;
582
        }
583
584
        if ($response = $this->ajaxResponse(trans('admin.update_succeeded'))) {
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->ajaxResponse(tran...in.update_succeeded')); of type boolean|Illuminate\Http\JsonResponse adds the type boolean to the return on line 585 which is incompatible with the return type documented by Encore\Admin\Form::update of type Symfony\Component\HttpFoundation\Response.
Loading history...
585
            return $response;
586
        }
587
588
        return $this->redirectAfterUpdate($id);
589
    }
590
591
    /**
592
     * Get RedirectResponse after store.
593
     *
594
     * @return \Illuminate\Http\RedirectResponse
595
     */
596
    protected function redirectAfterStore()
597
    {
598
        $resourcesPath = $this->resource(0);
599
600
        $key = $this->model->getKey();
601
602
        return $this->redirectAfterSaving($resourcesPath, $key);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->redirectAfterSaving($resourcesPath, $key); of type Illuminate\Http\Redirect...nate\Routing\Redirector adds the type Illuminate\Routing\Redirector to the return on line 602 which is incompatible with the return type documented by Encore\Admin\Form::redirectAfterStore of type Illuminate\Http\RedirectResponse.
Loading history...
603
    }
604
605
    /**
606
     * Get RedirectResponse after update.
607
     *
608
     * @param mixed $key
609
     *
610
     * @return \Illuminate\Http\RedirectResponse
611
     */
612
    protected function redirectAfterUpdate($key)
613
    {
614
        $resourcesPath = $this->resource(-1);
615
616
        return $this->redirectAfterSaving($resourcesPath, $key);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->redirectAfterSaving($resourcesPath, $key); of type Illuminate\Http\Redirect...nate\Routing\Redirector adds the type Illuminate\Routing\Redirector to the return on line 616 which is incompatible with the return type documented by Encore\Admin\Form::redirectAfterUpdate of type Illuminate\Http\RedirectResponse.
Loading history...
617
    }
618
619
    /**
620
     * Get RedirectResponse after data saving.
621
     *
622
     * @param string $resourcesPath
623
     * @param string $key
624
     *
625
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
626
     */
627
    protected function redirectAfterSaving($resourcesPath, $key)
628
    {
629
        if (request('after-save') == 1) {
630
            // continue editing
631
            $url = rtrim($resourcesPath, '/')."/{$key}/edit";
632
        } elseif (request('after-save') == 2) {
633
            // view resource
634
            $url = rtrim($resourcesPath, '/')."/{$key}";
635
        } else {
636
            $url = request(Builder::PREVIOUS_URL_KEY) ?: $resourcesPath;
637
        }
638
639
        admin_toastr(trans('admin.save_succeeded'));
640
641
        return redirect($url);
642
    }
643
644
    /**
645
     * Check if request is from editable.
646
     *
647
     * @param array $input
648
     *
649
     * @return bool
650
     */
651
    protected function isEditable(array $input = [])
652
    {
653
        return array_key_exists('_editable', $input);
654
    }
655
656
    /**
657
     * Handle editable update.
658
     *
659
     * @param array $input
660
     *
661
     * @return array
662
     */
663
    protected function handleEditable(array $input = [])
664
    {
665
        if (array_key_exists('_editable', $input)) {
666
            $name = $input['name'];
667
            $value = $input['value'];
668
669
            array_forget($input, ['pk', 'value', 'name']);
670
            array_set($input, $name, $value);
671
        }
672
673
        return $input;
674
    }
675
676
    /**
677
     * @param array $input
678
     *
679
     * @return array
680
     */
681
    protected function handleFileDelete(array $input = [])
682
    {
683
        if (array_key_exists(Field::FILE_DELETE_FLAG, $input)) {
684
            $input[Field::FILE_DELETE_FLAG] = $input['key'];
685
            unset($input['key']);
686
        }
687
688
        Input::replace($input);
689
690
        return $input;
691
    }
692
693
    /**
694
     * Handle orderable update.
695
     *
696
     * @param int   $id
697
     * @param array $input
698
     *
699
     * @return bool
700
     */
701
    protected function handleOrderable($id, array $input = [])
702
    {
703
        if (array_key_exists('_orderable', $input)) {
704
            $model = $this->model->find($id);
705
706
            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...
707
                $input['_orderable'] == 1 ? $model->moveOrderUp() : $model->moveOrderDown();
708
709
                return true;
710
            }
711
        }
712
713
        return false;
714
    }
715
716
    /**
717
     * Update relation data.
718
     *
719
     * @param array $relationsData
720
     *
721
     * @return void
722
     */
723
    protected function updateRelation($relationsData)
724
    {
725
        foreach ($relationsData as $name => $values) {
726
            if (!method_exists($this->model, $name)) {
727
                continue;
728
            }
729
730
            $relation = $this->model->$name();
731
732
            $oneToOneRelation = $relation instanceof Relations\HasOne
733
                || $relation instanceof Relations\MorphOne
734
                || $relation instanceof Relations\BelongsTo;
735
736
            $prepared = $this->prepareUpdate([$name => $values], $oneToOneRelation);
737
738
            if (empty($prepared)) {
739
                continue;
740
            }
741
742
            switch (get_class($relation)) {
743
                case Relations\BelongsToMany::class:
744
                case Relations\MorphToMany::class:
745
                    if (isset($prepared[$name])) {
746
                        $relation->sync($prepared[$name]);
747
                    }
748
                    break;
749 View Code Duplication
                case Relations\HasOne::class:
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...
750
751
                    $related = $this->model->$name;
752
753
                    // if related is empty
754
                    if (is_null($related)) {
755
                        $related = $relation->getRelated();
756
                        $related->{$relation->getForeignKeyName()} = $this->model->{$this->model->getKeyName()};
757
                    }
758
759
                    foreach ($prepared[$name] as $column => $value) {
760
                        $related->setAttribute($column, $value);
761
                    }
762
763
                    $related->save();
764
                    break;
765 View Code Duplication
                case Relations\BelongsTo::class:
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...
766
767
                    $parent = $this->model->$name;
768
769
                    // if related is empty
770
                    if (is_null($parent)) {
771
                        $parent = $relation->getRelated();
772
                    }
773
774
                    foreach ($prepared[$name] as $column => $value) {
775
                        $parent->setAttribute($column, $value);
776
                    }
777
778
                    $parent->save();
779
780
                    // When in creating, associate two models
781
                    if (!$this->model->{$relation->getForeignKey()}) {
782
                        $this->model->{$relation->getForeignKey()} = $parent->getKey();
783
784
                        $this->model->save();
785
                    }
786
787
                    break;
788
                case Relations\MorphOne::class:
789
                    $related = $this->model->$name;
790
                    if (is_null($related)) {
791
                        $related = $relation->make();
792
                    }
793
                    foreach ($prepared[$name] as $column => $value) {
794
                        $related->setAttribute($column, $value);
795
                    }
796
                    $related->save();
797
                    break;
798
                case Relations\HasMany::class:
799
                case Relations\MorphMany::class:
800
801
                    foreach ($prepared[$name] as $related) {
802
                        /** @var Relations\Relation $relation */
803
                        $relation = $this->model()->$name();
804
805
                        $keyName = $relation->getRelated()->getKeyName();
806
807
                        $instance = $relation->findOrNew(array_get($related, $keyName));
808
809
                        if ($related[static::REMOVE_FLAG_NAME] == 1) {
810
                            $instance->delete();
811
812
                            continue;
813
                        }
814
815
                        array_forget($related, static::REMOVE_FLAG_NAME);
816
817
                        $instance->fill($related);
818
819
                        $instance->save();
820
                    }
821
822
                    break;
823
            }
824
        }
825
    }
826
827
    /**
828
     * Prepare input data for update.
829
     *
830
     * @param array $updates
831
     * @param bool  $oneToOneRelation If column is one-to-one relation.
832
     *
833
     * @return array
834
     */
835
    protected function prepareUpdate(array $updates, $oneToOneRelation = false)
836
    {
837
        $prepared = [];
838
839
        /** @var Field $field */
840
        foreach ($this->builder->fields() as $field) {
841
            $columns = $field->column();
842
843
            // If column not in input array data, then continue.
844
            if (!array_has($updates, $columns)) {
845
                continue;
846
            }
847
848
            if ($this->invalidColumn($columns, $oneToOneRelation)) {
849
                continue;
850
            }
851
852
            $value = $this->getDataByColumn($updates, $columns);
853
854
            $value = $field->prepare($value);
855
856 View Code Duplication
            if (is_array($columns)) {
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...
857
                foreach ($columns as $name => $column) {
858
                    array_set($prepared, $column, $value[$name]);
859
                }
860
            } elseif (is_string($columns)) {
861
                array_set($prepared, $columns, $value);
862
            }
863
        }
864
865
        return $prepared;
866
    }
867
868
    /**
869
     * @param string|array $columns
870
     * @param bool         $oneToOneRelation
871
     *
872
     * @return bool
873
     */
874
    protected function invalidColumn($columns, $oneToOneRelation = false)
875
    {
876
        foreach ((array) $columns as $column) {
877
            if ((!$oneToOneRelation && Str::contains($column, '.')) ||
878
                ($oneToOneRelation && !Str::contains($column, '.'))) {
879
                return true;
880
            }
881
        }
882
883
        return false;
884
    }
885
886
    /**
887
     * Prepare input data for insert.
888
     *
889
     * @param $inserts
890
     *
891
     * @return array
892
     */
893
    protected function prepareInsert($inserts)
894
    {
895
        if ($this->isHasOneRelation($inserts)) {
896
            $inserts = array_dot($inserts);
897
        }
898
899
        foreach ($inserts as $column => $value) {
900
            if (is_null($field = $this->getFieldByColumn($column))) {
901
                unset($inserts[$column]);
902
                continue;
903
            }
904
905
            $inserts[$column] = $field->prepare($value);
906
        }
907
908
        $prepared = [];
909
910
        foreach ($inserts as $key => $value) {
911
            array_set($prepared, $key, $value);
912
        }
913
914
        return $prepared;
915
    }
916
917
    /**
918
     * Is input data is has-one relation.
919
     *
920
     * @param array $inserts
921
     *
922
     * @return bool
923
     */
924
    protected function isHasOneRelation($inserts)
925
    {
926
        $first = current($inserts);
927
928
        if (!is_array($first)) {
929
            return false;
930
        }
931
932
        if (is_array(current($first))) {
933
            return false;
934
        }
935
936
        return Arr::isAssoc($first);
937
    }
938
939
    /**
940
     * Set after getting editing model callback.
941
     *
942
     * @param Closure $callback
943
     *
944
     * @return void
945
     */
946
    public function editing(Closure $callback)
947
    {
948
        $this->editing[] = $callback;
949
    }
950
951
    /**
952
     * Set submitted callback.
953
     *
954
     * @param Closure $callback
955
     *
956
     * @return void
957
     */
958
    public function submitted(Closure $callback)
959
    {
960
        $this->submitted[] = $callback;
961
    }
962
963
    /**
964
     * Set saving callback.
965
     *
966
     * @param Closure $callback
967
     *
968
     * @return void
969
     */
970
    public function saving(Closure $callback)
971
    {
972
        $this->saving[] = $callback;
973
    }
974
975
    /**
976
     * Set saved callback.
977
     *
978
     * @param Closure $callback
979
     *
980
     * @return void
981
     */
982
    public function saved(Closure $callback)
983
    {
984
        $this->saved[] = $callback;
985
    }
986
987
    /**
988
     * Ignore fields to save.
989
     *
990
     * @param string|array $fields
991
     *
992
     * @return $this
993
     */
994
    public function ignore($fields)
995
    {
996
        $this->ignored = array_merge($this->ignored, (array) $fields);
997
998
        return $this;
999
    }
1000
1001
    /**
1002
     * @param array        $data
1003
     * @param string|array $columns
1004
     *
1005
     * @return array|mixed
1006
     */
1007 View Code Duplication
    protected function getDataByColumn($data, $columns)
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...
1008
    {
1009
        if (is_string($columns)) {
1010
            return array_get($data, $columns);
1011
        }
1012
1013
        if (is_array($columns)) {
1014
            $value = [];
1015
            foreach ($columns as $name => $column) {
1016
                if (!array_has($data, $column)) {
1017
                    continue;
1018
                }
1019
                $value[$name] = array_get($data, $column);
1020
            }
1021
1022
            return $value;
1023
        }
1024
    }
1025
1026
    /**
1027
     * Find field object by column.
1028
     *
1029
     * @param $column
1030
     *
1031
     * @return mixed
1032
     */
1033
    protected function getFieldByColumn($column)
1034
    {
1035
        return $this->builder->fields()->first(
1036
            function (Field $field) use ($column) {
1037
                if (is_array($field->column())) {
1038
                    return in_array($column, $field->column());
1039
                }
1040
1041
                return $field->column() == $column;
1042
            }
1043
        );
1044
    }
1045
1046
    /**
1047
     * Set original data for each field.
1048
     *
1049
     * @return void
1050
     */
1051
    protected function setFieldOriginalValue()
1052
    {
1053
//        static::doNotSnakeAttributes($this->model);
1054
1055
        $values = $this->model->toArray();
1056
1057
        $this->builder->fields()->each(function (Field $field) use ($values) {
1058
            $field->setOriginal($values);
1059
        });
1060
    }
1061
1062
    /**
1063
     * Set all fields value in form.
1064
     *
1065
     * @param $id
1066
     *
1067
     * @return void
1068
     */
1069
    protected function setFieldValue($id)
1070
    {
1071
        $relations = $this->getRelations();
1072
1073
        $this->model = $this->model->with($relations)->findOrFail($id);
0 ignored issues
show
Bug introduced by
The method findOrFail does only exist in Illuminate\Database\Eloquent\Builder, but not in Illuminate\Database\Eloquent\Model.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
1074
1075
        $this->callEditing();
1076
1077
//        static::doNotSnakeAttributes($this->model);
1078
1079
        $data = $this->model->toArray();
1080
1081
        $this->builder->fields()->each(function (Field $field) use ($data) {
1082
            if (!in_array($field->column(), $this->ignored)) {
1083
                $field->fill($data);
1084
            }
1085
        });
1086
    }
1087
1088
    /**
1089
     * Don't snake case attributes.
1090
     *
1091
     * @param Model $model
1092
     *
1093
     * @return void
1094
     */
1095
    protected static function doNotSnakeAttributes(Model $model)
1096
    {
1097
        $class = get_class($model);
1098
1099
        $class::$snakeAttributes = false;
1100
    }
1101
1102
    /**
1103
     * Get validation messages.
1104
     *
1105
     * @param array $input
1106
     *
1107
     * @return MessageBag|bool
1108
     */
1109
    public function validationMessages($input)
1110
    {
1111
        $failedValidators = [];
1112
1113
        /** @var Field $field */
1114
        foreach ($this->builder->fields() as $field) {
1115
            if (!$validator = $field->getValidator($input)) {
1116
                continue;
1117
            }
1118
1119
            if (($validator instanceof Validator) && !$validator->passes()) {
1120
                $failedValidators[] = $validator;
1121
            }
1122
        }
1123
1124
        $message = $this->mergeValidationMessages($failedValidators);
1125
1126
        return $message->any() ? $message : false;
1127
    }
1128
1129
    /**
1130
     * Merge validation messages from input validators.
1131
     *
1132
     * @param \Illuminate\Validation\Validator[] $validators
1133
     *
1134
     * @return MessageBag
1135
     */
1136
    protected function mergeValidationMessages($validators)
1137
    {
1138
        $messageBag = new MessageBag();
1139
1140
        foreach ($validators as $validator) {
1141
            $messageBag = $messageBag->merge($validator->messages());
1142
        }
1143
1144
        return $messageBag;
1145
    }
1146
1147
    /**
1148
     * Get all relations of model from callable.
1149
     *
1150
     * @return array
1151
     */
1152
    public function getRelations()
1153
    {
1154
        $relations = $columns = [];
1155
1156
        /** @var Field $field */
1157
        foreach ($this->builder->fields() as $field) {
1158
            $columns[] = $field->column();
1159
        }
1160
1161
        foreach (array_flatten($columns) as $column) {
1162
            if (str_contains($column, '.')) {
1163
                list($relation) = explode('.', $column);
1164
1165
                if (method_exists($this->model, $relation) &&
1166
                    $this->model->$relation() instanceof Relations\Relation
1167
                ) {
1168
                    $relations[] = $relation;
1169
                }
1170
            } elseif (method_exists($this->model, $column) &&
1171
                !method_exists(Model::class, $column)
1172
            ) {
1173
                $relations[] = $column;
1174
            }
1175
        }
1176
1177
        return array_unique($relations);
1178
    }
1179
1180
    /**
1181
     * Set action for form.
1182
     *
1183
     * @param string $action
1184
     *
1185
     * @return $this
1186
     */
1187
    public function setAction($action)
1188
    {
1189
        $this->builder()->setAction($action);
1190
1191
        return $this;
1192
    }
1193
1194
    /**
1195
     * Set field and label width in current form.
1196
     *
1197
     * @param int $fieldWidth
1198
     * @param int $labelWidth
1199
     *
1200
     * @return $this
1201
     */
1202
    public function setWidth($fieldWidth = 8, $labelWidth = 2)
1203
    {
1204
        $this->builder()->fields()->each(function ($field) use ($fieldWidth, $labelWidth) {
1205
            /* @var Field $field  */
1206
            $field->setWidth($fieldWidth, $labelWidth);
1207
        });
1208
1209
        $this->builder()->setWidth($fieldWidth, $labelWidth);
1210
1211
        return $this;
1212
    }
1213
1214
    /**
1215
     * Set view for form.
1216
     *
1217
     * @param string $view
1218
     *
1219
     * @return $this
1220
     */
1221
    public function setView($view)
1222
    {
1223
        $this->builder()->setView($view);
1224
1225
        return $this;
1226
    }
1227
1228
    /**
1229
     * Set title for form.
1230
     *
1231
     * @param string $title
1232
     *
1233
     * @return $this
1234
     */
1235
    public function setTitle($title = '')
1236
    {
1237
        $this->builder()->setTitle($title);
1238
1239
        return $this;
1240
    }
1241
1242
    /**
1243
     * Add a row in form.
1244
     *
1245
     * @param Closure $callback
1246
     *
1247
     * @return $this
1248
     */
1249
    public function row(Closure $callback)
1250
    {
1251
        $this->rows[] = new Row($callback, $this);
1252
1253
        return $this;
1254
    }
1255
1256
    /**
1257
     * Tools setting for form.
1258
     *
1259
     * @param Closure $callback
1260
     */
1261
    public function tools(Closure $callback)
1262
    {
1263
        $callback->call($this, $this->builder->getTools());
1264
    }
1265
1266
    /**
1267
     * Disable form submit.
1268
     *
1269
     * @return $this
1270
     *
1271
     * @deprecated
1272
     */
1273
    public function disableSubmit()
1274
    {
1275
        $this->builder()->getFooter()->disableSubmit();
1276
1277
        return $this;
1278
    }
1279
1280
    /**
1281
     * Disable form reset.
1282
     *
1283
     * @return $this
1284
     *
1285
     * @deprecated
1286
     */
1287
    public function disableReset()
1288
    {
1289
        $this->builder()->getFooter()->disableReset();
1290
1291
        return $this;
1292
    }
1293
1294
    /**
1295
     * Disable View Checkbox on footer.
1296
     *
1297
     * @return $this
1298
     */
1299
    public function disableViewCheck()
1300
    {
1301
        $this->builder()->getFooter()->disableViewCheck();
1302
1303
        return $this;
1304
    }
1305
1306
    /**
1307
     * Disable Editing Checkbox on footer.
1308
     *
1309
     * @return $this
1310
     */
1311
    public function disableEditingCheck()
1312
    {
1313
        $this->builder()->getFooter()->disableEditingCheck();
1314
1315
        return $this;
1316
    }
1317
1318
    /**
1319
     * Footer setting for form.
1320
     *
1321
     * @param Closure $callback
1322
     */
1323
    public function footer(Closure $callback)
1324
    {
1325
        call_user_func($callback, $this->builder()->getFooter());
1326
    }
1327
1328
    /**
1329
     * Get current resource route url.
1330
     *
1331
     * @param int $slice
1332
     *
1333
     * @return string
1334
     */
1335
    public function resource($slice = -2)
1336
    {
1337
        $segments = explode('/', trim(app('request')->getUri(), '/'));
1338
1339
        if ($slice != 0) {
1340
            $segments = array_slice($segments, 0, $slice);
1341
        }
1342
        // # fix #1768
1343
        if ($segments[0] == 'http:' && (config('admin.https') || config('admin.secure'))) {
1344
            $segments[0] = 'https:';
1345
        }
1346
1347
        return implode('/', $segments);
1348
    }
1349
1350
    /**
1351
     * Render the form contents.
1352
     *
1353
     * @return string
1354
     */
1355
    public function render()
1356
    {
1357
        try {
1358
            return $this->builder->render();
1359
        } catch (\Exception $e) {
1360
            return Handler::renderException($e);
1361
        }
1362
    }
1363
1364
    /**
1365
     * Get or set input data.
1366
     *
1367
     * @param string $key
1368
     * @param null   $value
1369
     *
1370
     * @return array|mixed
1371
     */
1372
    public function input($key, $value = null)
1373
    {
1374
        if (is_null($value)) {
1375
            return array_get($this->inputs, $key);
1376
        }
1377
1378
        return array_set($this->inputs, $key, $value);
1379
    }
1380
1381
    /**
1382
     * Register builtin fields.
1383
     *
1384
     * @return void
1385
     */
1386
    public static function registerBuiltinFields()
1387
    {
1388
        $map = [
1389
            'button'         => Field\Button::class,
1390
            'checkbox'       => Field\Checkbox::class,
1391
            'color'          => Field\Color::class,
1392
            'currency'       => Field\Currency::class,
1393
            'date'           => Field\Date::class,
1394
            'dateRange'      => Field\DateRange::class,
1395
            'datetime'       => Field\Datetime::class,
1396
            'dateTimeRange'  => Field\DatetimeRange::class,
1397
            'datetimeRange'  => Field\DatetimeRange::class,
1398
            'decimal'        => Field\Decimal::class,
1399
            'display'        => Field\Display::class,
1400
            'divider'        => Field\Divide::class,
1401
            'divide'         => Field\Divide::class,
1402
            'embeds'         => Field\Embeds::class,
1403
            'editor'         => Field\Editor::class,
1404
            'email'          => Field\Email::class,
1405
            'file'           => Field\File::class,
1406
            'hasMany'        => Field\HasMany::class,
1407
            'hidden'         => Field\Hidden::class,
1408
            'id'             => Field\Id::class,
1409
            'image'          => Field\Image::class,
1410
            'ip'             => Field\Ip::class,
1411
            'map'            => Field\Map::class,
1412
            'mobile'         => Field\Mobile::class,
1413
            'month'          => Field\Month::class,
1414
            'multipleSelect' => Field\MultipleSelect::class,
1415
            'number'         => Field\Number::class,
1416
            'password'       => Field\Password::class,
1417
            'radio'          => Field\Radio::class,
1418
            'rate'           => Field\Rate::class,
1419
            'select'         => Field\Select::class,
1420
            'slider'         => Field\Slider::class,
1421
            'switch'         => Field\SwitchField::class,
1422
            'text'           => Field\Text::class,
1423
            'textarea'       => Field\Textarea::class,
1424
            'time'           => Field\Time::class,
1425
            'timeRange'      => Field\TimeRange::class,
1426
            'url'            => Field\Url::class,
1427
            'year'           => Field\Year::class,
1428
            'html'           => Field\Html::class,
1429
            'tags'           => Field\Tags::class,
1430
            'icon'           => Field\Icon::class,
1431
            'multipleFile'   => Field\MultipleFile::class,
1432
            'multipleImage'  => Field\MultipleImage::class,
1433
            'captcha'        => Field\Captcha::class,
1434
            'listbox'        => Field\Listbox::class,
1435
        ];
1436
1437
        foreach ($map as $abstract => $class) {
1438
            static::extend($abstract, $class);
1439
        }
1440
    }
1441
1442
    /**
1443
     * Register custom field.
1444
     *
1445
     * @param string $abstract
1446
     * @param string $class
1447
     *
1448
     * @return void
1449
     */
1450
    public static function extend($abstract, $class)
1451
    {
1452
        static::$availableFields[$abstract] = $class;
1453
    }
1454
1455
    /**
1456
     * Set form field alias.
1457
     *
1458
     * @param string $field
1459
     * @param string $alias
1460
     *
1461
     * @return void
1462
     */
1463
    public static function alias($field, $alias)
1464
    {
1465
        static::$fieldAlias[$alias] = $field;
1466
    }
1467
1468
    /**
1469
     * Remove registered field.
1470
     *
1471
     * @param array|string $abstract
1472
     */
1473
    public static function forget($abstract)
1474
    {
1475
        array_forget(static::$availableFields, $abstract);
1476
    }
1477
1478
    /**
1479
     * Find field class.
1480
     *
1481
     * @param string $method
1482
     *
1483
     * @return bool|mixed
1484
     */
1485
    public static function findFieldClass($method)
1486
    {
1487
        // If alias exists.
1488
        if (isset(static::$fieldAlias[$method])) {
1489
            $method = static::$fieldAlias[$method];
1490
        }
1491
1492
        $class = array_get(static::$availableFields, $method);
1493
1494
        if (class_exists($class)) {
1495
            return $class;
1496
        }
1497
1498
        return false;
1499
    }
1500
1501
    /**
1502
     * Collect assets required by registered field.
1503
     *
1504
     * @return array
1505
     */
1506
    public static function collectFieldAssets()
1507
    {
1508
        if (!empty(static::$collectedAssets)) {
1509
            return static::$collectedAssets;
1510
        }
1511
1512
        $css = collect();
1513
        $js = collect();
1514
1515
        foreach (static::$availableFields as $field) {
1516
            if (!method_exists($field, 'getAssets')) {
1517
                continue;
1518
            }
1519
1520
            $assets = call_user_func([$field, 'getAssets']);
1521
1522
            $css->push(array_get($assets, 'css'));
1523
            $js->push(array_get($assets, 'js'));
1524
        }
1525
1526
        return static::$collectedAssets = [
1527
            'css' => $css->flatten()->unique()->filter()->toArray(),
1528
            'js'  => $js->flatten()->unique()->filter()->toArray(),
1529
        ];
1530
    }
1531
1532
    /**
1533
     * Getter.
1534
     *
1535
     * @param string $name
1536
     *
1537
     * @return array|mixed
1538
     */
1539
    public function __get($name)
1540
    {
1541
        return $this->input($name);
1542
    }
1543
1544
    /**
1545
     * Setter.
1546
     *
1547
     * @param string $name
1548
     * @param $value
1549
     */
1550
    public function __set($name, $value)
1551
    {
1552
        $this->input($name, $value);
1553
    }
1554
1555
    /**
1556
     * Generate a Field object and add to form builder if Field exists.
1557
     *
1558
     * @param string $method
1559
     * @param array  $arguments
1560
     *
1561
     * @return Field
1562
     */
1563
    public function __call($method, $arguments)
1564
    {
1565
        if ($className = static::findFieldClass($method)) {
1566
            $column = array_get($arguments, 0, ''); //[0];
1567
1568
            $element = new $className($column, array_slice($arguments, 1));
1569
1570
            $this->pushField($element);
1571
1572
            return $element;
1573
        }
1574
1575
        admin_error('Error', "Field type [$method] does not exist.");
1576
1577
        return new Field\Nullable();
1578
    }
1579
}
1580