Completed
Push — master ( 7761d4...144654 )
by Song
02:35
created

Form::handleOrderable()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 2
dl 0
loc 14
rs 9.2
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
     * @param \$model
119
     * @param \Closure $callback
120
     */
121
    public function __construct($model, Closure $callback)
122
    {
123
        $this->model = $model;
124
125
        $this->builder = new Builder($this);
126
127
        $this->callable = $callback;
128
129
        $callback($this);
130
    }
131
132
    /**
133
     * Set up the form.
134
     */
135
    protected function setUp()
136
    {
137
        call_user_func($this->callable, $this);
138
    }
139
140
    /**
141
     * @param Field $field
142
     *
143
     * @return $this
144
     */
145
    public function pushField(Field $field)
146
    {
147
        $field->setForm($this);
148
149
        $this->builder->fields()->push($field);
150
151
        return $this;
152
    }
153
154
    /**
155
     * @return Model
156
     */
157
    public function model()
158
    {
159
        return $this->model;
160
    }
161
162
    /**
163
     * @return Builder
164
     */
165
    public function builder()
166
    {
167
        return $this->builder;
168
    }
169
170
    /**
171
     * Generate a edit form.
172
     *
173
     * @param $id
174
     *
175
     * @return $this
176
     */
177
    public function edit($id)
178
    {
179
        $this->builder->setMode(Builder::MODE_EDIT);
180
        $this->builder->setResourceId($id);
181
182
        $this->setFieldValue($id);
183
184
        return $this;
185
    }
186
187
    /**
188
     * @param $id
189
     *
190
     * @return $this
191
     */
192
    public function view($id)
193
    {
194
        $this->builder->setMode(Builder::MODE_VIEW);
195
        $this->builder->setResourceId($id);
196
197
        $this->setFieldValue($id);
198
199
        return $this;
200
    }
201
202
    /**
203
     * Destroy data entity and remove files.
204
     *
205
     * @param $id
206
     *
207
     * @return mixed
208
     */
209
    public function destroy($id)
210
    {
211
        $ids = explode(',', $id);
212
213
        foreach ($ids as $id) {
214
            if (empty($id)) {
215
                continue;
216
            }
217
            $this->deleteFilesAndImages($id);
218
            $this->model->find($id)->delete();
219
        }
220
221
        return true;
222
    }
223
224
    /**
225
     * Remove files or images in record.
226
     *
227
     * @param $id
228
     */
229
    protected function deleteFilesAndImages($id)
230
    {
231
        $data = $this->model->with($this->getRelations())
232
            ->findOrFail($id)->toArray();
233
234
        $this->builder->fields()->filter(function ($field) {
235
            return $field instanceof Field\File;
236
        })->each(function (File $file) use ($data) {
237
            $file->setOriginal($data);
238
239
            $file->destroy();
240
        });
241
    }
242
243
    /**
244
     * Store a new record.
245
     *
246
     * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
247
     */
248
    public function store()
249
    {
250
        $data = Input::all();
251
252
        if (!$this->validate($data)) {
253
            return back()->withInput()->withErrors($this->validator->messages());
254
        }
255
256
        $this->prepare($data, $this->saving);
257
258 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...
259
            $inserts = $this->prepareInsert($this->updates);
260
261
            foreach ($inserts as $column => $value) {
262
                if (is_array($value)) {
263
                    $value = implode(',', $value);
264
                }
265
                $this->model->setAttribute($column, $value);
266
            }
267
268
            $this->model->save();
269
270
            $this->saveRelation($this->relations);
271
        });
272
273
        $this->complete($this->saved);
274
275
        return redirect($this->resource(0));
276
    }
277
278
    /**
279
     * Prepare input data for insert or update.
280
     *
281
     * @param array    $data
282
     * @param callable $callback
283
     */
284
    protected function prepare($data = [], Closure $callback = null)
285
    {
286
        $this->inputs = $data;
287
288
        if ($callback instanceof Closure) {
289
            $callback($this);
290
        }
291
292
        $this->relations = $this->getRelationInputs($data);
293
294
        $updates = array_except($this->inputs, array_keys($this->relations));
295
296
        $this->updates = array_filter($updates, function ($val) {
297
            return !is_null($val);
298
        });
299
    }
300
301
    /**
302
     * Get inputs for relations.
303
     *
304
     * @param array $inputs
305
     *
306
     * @return array
307
     */
308
    protected function getRelationInputs($inputs = [])
309
    {
310
        $relations = [];
311
312
        foreach ($inputs as $column => $value) {
313
            if (method_exists($this->model, $column)) {
314
                $relation = call_user_func([$this->model, $column]);
315
316
                if ($relation instanceof Relation) {
317
                    $relations[$column] = $value;
318
                }
319
            }
320
        }
321
322
        return $relations;
323
    }
324
325
    /**
326
     * Callback after saving a Model.
327
     *
328
     * @param Closure|null $callback
329
     *
330
     * @return void
331
     */
332
    protected function complete(Closure $callback = null)
333
    {
334
        if ($callback instanceof Closure) {
335
            $callback($this);
336
        }
337
    }
338
339
    /**
340
     * Save relations data.
341
     *
342
     * @param array $relations
343
     *
344
     * @return void
345
     */
346
    protected function saveRelation($relations)
347
    {
348
        foreach ($relations as $name => $values) {
349
            if (!method_exists($this->model, $name)) {
350
                continue;
351
            }
352
353
            $values = $this->prepareInsert([$name => $values]);
354
355
            $relation = $this->model->$name();
356
357
            switch (get_class($relation)) {
358
                case \Illuminate\Database\Eloquent\Relations\BelongsToMany::class:
359
                case \Illuminate\Database\Eloquent\Relations\MorphToMany::class:
360
                    $relation->attach($values[$name]);
361
                    break;
362
                case \Illuminate\Database\Eloquent\Relations\HasOne::class:
363
                    $related = $relation->getRelated();
364
                    foreach ($values[$name] as $column => $value) {
365
                        $related->setAttribute($column, $value);
366
                    }
367
368
                    $relation->save($related);
369
                    break;
370
            }
371
        }
372
    }
373
374
    /**
375
     * Handle update.
376
     *
377
     * @param int $id
378
     *
379
     * @return $this|\Illuminate\Http\RedirectResponse
380
     */
381
    public function update($id)
382
    {
383
        $data = Input::all();
384
385
        $data = $this->handleEditable($data);
386
387
        if ($this->handleOrderable($id, $data)) {
388
            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...
389
        }
390
391
        if (!$this->validate($data)) {
392
            return back()->withInput()->withErrors($this->validator->messages());
393
        }
394
395
        $this->model = $this->model->with($this->getRelations())->findOrFail($id);
396
397
        $this->setFieldOriginalValue();
398
399
        $this->prepare($data, $this->saving);
400
401 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...
402
            $updates = $this->prepareUpdate($this->updates);
403
404
            foreach ($updates as $column => $value) {
405
                if (is_array($value)) {
406
                    $value = implode(',', $value);
407
                }
408
409
                $this->model->setAttribute($column, $value);
410
            }
411
412
            $this->model->save();
413
414
            $this->updateRelation($this->relations);
415
        });
416
417
        $this->complete($this->saved);
418
419
        return redirect($this->resource(-1));
420
    }
421
422
    /**
423
     * Handle editable update.
424
     *
425
     * @param array $input
426
     *
427
     * @return array
428
     */
429
    protected function handleEditable(array $input = [])
430
    {
431
        if (array_key_exists('_editable', $input)) {
432
            $name = $input['name'];
433
            $value = $input['value'];
434
435
            array_forget($input, ['pk', 'value', 'name']);
436
            array_set($input, $name, $value);
437
        }
438
439
        return $input;
440
    }
441
442
    /**
443
     * Handle orderable update.
444
     *
445
     * @param int   $id
446
     * @param array $input
447
     *
448
     * @return array
449
     */
450
    protected function handleOrderable($id, array $input = [])
451
    {
452
        if (array_key_exists('_orderable', $input)) {
453
            $model = $this->model->find($id);
454
455
            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...
456
                $input['_orderable'] == 1 ? $model->moveOrderUp() : $model->moveOrderDown();
457
458
                return true;
459
            }
460
        }
461
462
        return false;
463
    }
464
465
    /**
466
     * Update relation data.
467
     *
468
     * @param array $relations
469
     *
470
     * @return void
471
     */
472
    protected function updateRelation($relations)
473
    {
474
        foreach ($relations as $name => $values) {
475
            if (!method_exists($this->model, $name)) {
476
                continue;
477
            }
478
479
            $prepared = $this->prepareUpdate([$name => $values]);
480
481
            if (empty($prepared)) {
482
                continue;
483
            }
484
485
            $relation = $this->model->$name();
486
487
            switch (get_class($relation)) {
488
                case \Illuminate\Database\Eloquent\Relations\BelongsToMany::class:
489
                case \Illuminate\Database\Eloquent\Relations\MorphToMany::class:
490
                    $relation->sync($prepared[$name]);
491
                    break;
492
                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...
493
494
                    $related = $this->model->$name;
495
496
                    // if related is empty
497
                    if (is_null($related)) {
498
                        $related = $relation->getRelated();
499
                        $related->{$relation->getForeignKey()} = $this->model->{$this->model->getKeyName()};
500
                    }
501
502
                    foreach ($prepared[$name] as $column => $value) {
503
                        $related->setAttribute($column, $value);
504
                    }
505
506
                    $related->save();
507
                    break;
508
            }
509
        }
510
    }
511
512
    /**
513
     * Prepare input data for update.
514
     *
515
     * @param $updates
516
     *
517
     * @return array
518
     */
519
    protected function prepareUpdate($updates)
520
    {
521
        $prepared = [];
522
523
        foreach ($this->builder->fields() as $field) {
0 ignored issues
show
Bug introduced by
The expression $this->builder->fields() of type object<Illuminate\Support\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
524
            $columns = $field->column();
525
526
            $value = $this->getDataByColumn($updates, $columns);
527
528
            if ($value !== '' && $value !== '0' && !$field instanceof File && empty($value)) {
529
                continue;
530
            }
531
532
            if (method_exists($field, 'prepare')) {
533
                $value = $field->prepare($value);
534
            }
535
536
            if ($value != $field->original()) {
537
                if (is_array($columns)) {
538
                    foreach ($columns as $name => $column) {
539
                        array_set($prepared, $column, $value[$name]);
540
                    }
541
                } elseif (is_string($columns)) {
542
                    array_set($prepared, $columns, $value);
543
                }
544
            }
545
        }
546
547
        return $prepared;
548
    }
549
550
    /**
551
     * Prepare input data for insert.
552
     *
553
     * @param $inserts
554
     *
555
     * @return array
556
     */
557
    protected function prepareInsert($inserts)
558
    {
559
        $first = current($inserts);
560
561
        if (is_array($first) && Arr::isAssoc($first)) {
562
            $inserts = array_dot($inserts);
563
        }
564
565
        foreach ($inserts as $column => $value) {
566
            if (is_null($field = $this->getFieldByColumn($column))) {
567
                unset($inserts[$column]);
568
                continue;
569
            }
570
571
            if (method_exists($field, 'prepare')) {
572
                $inserts[$column] = $field->prepare($value);
573
            }
574
        }
575
576
        $prepared = [];
577
578
        foreach ($inserts as $key => $value) {
579
            array_set($prepared, $key, $value);
580
        }
581
582
        return $prepared;
583
    }
584
585
    /**
586
     * Set saving callback.
587
     *
588
     * @param callable $callback
589
     *
590
     * @return void
591
     */
592
    public function saving(Closure $callback)
593
    {
594
        $this->saving = $callback;
595
    }
596
597
    /**
598
     * Set saved callback.
599
     *
600
     * @param callable $callback
601
     *
602
     * @return void
603
     */
604
    public function saved(Closure $callback)
605
    {
606
        $this->saved = $callback;
607
    }
608
609
    /**
610
     * @param array        $data
611
     * @param string|array $columns
612
     *
613
     * @return array|mixed
614
     */
615
    protected function getDataByColumn($data, $columns)
616
    {
617
        if (is_string($columns)) {
618
            return array_get($data, $columns);
619
        }
620
621
        if (is_array($columns)) {
622
            $value = [];
623
            foreach ($columns as $name => $column) {
624
                if (!array_has($data, $column)) {
625
                    continue;
626
                }
627
                $value[$name] = array_get($data, $column);
628
            }
629
630
            return $value;
631
        }
632
    }
633
634
    /**
635
     * Find field object by column.
636
     *
637
     * @param $column
638
     *
639
     * @return mixed
640
     */
641
    protected function getFieldByColumn($column)
642
    {
643
        return $this->builder->fields()->first(
644
            function ($index, Field $field) use ($column) {
645
                if (is_array($field->column())) {
646
                    return in_array($column, $field->column());
647
                }
648
649
                return $field->column() == $column;
650
            }
651
        );
652
    }
653
654
    /**
655
     * Set original data for each field.
656
     *
657
     * @return void
658
     */
659
    protected function setFieldOriginalValue()
660
    {
661
        $values = $this->model->toArray();
662
663
        $this->builder->fields()->each(function (Field $field) use ($values) {
664
            $field->setOriginal($values);
665
        });
666
    }
667
668
    /**
669
     * Set all fields value in form.
670
     *
671
     * @param $id
672
     *
673
     * @return void
674
     */
675
    protected function setFieldValue($id)
676
    {
677
        $relations = $this->getRelations();
678
679
        $this->model = $this->model->with($relations)->findOrFail($id);
680
681
        $data = $this->model->toArray();
682
683
        $this->builder->fields()->each(function (Field $field) use ($data) {
684
            $field->fill($data);
685
        });
686
    }
687
688
    /**
689
     * Validate input data.
690
     *
691
     * @param $input
692
     *
693
     * @return bool
694
     */
695
    protected function validate($input)
696
    {
697
        $data = $rules = [];
698
699
        foreach ($this->builder->fields() as $field) {
0 ignored issues
show
Bug introduced by
The expression $this->builder->fields() of type object<Illuminate\Support\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
700
            if (!method_exists($field, 'rules') || !$rule = $field->rules()) {
701
                continue;
702
            }
703
704
            $columns = $field->column();
705
706
            if (is_string($columns)) {
707
                if (!array_key_exists($columns, $input)) {
708
                    continue;
709
                }
710
711
                $data[$field->label()] = array_get($input, $columns);
712
                $rules[$field->label()] = $rule;
713
            }
714
715
            if (is_array($columns)) {
716
                foreach ($columns as $key => $column) {
717
                    if (!array_key_exists($column, $input)) {
718
                        continue;
719
                    }
720
                    $data[$field->label().$key] = array_get($input, $column);
721
                    $rules[$field->label().$key] = $rule;
722
                }
723
            }
724
        }
725
726
        $this->validator = Validator::make($data, $rules);
727
728
        return $this->validator->passes();
729
    }
730
731
    /**
732
     * Get all relations of model from callable.
733
     *
734
     * @return array
735
     */
736
    public function getRelations()
737
    {
738
        $relations = $columns = [];
739
740
        foreach ($this->builder->fields() as $field) {
0 ignored issues
show
Bug introduced by
The expression $this->builder->fields() of type object<Illuminate\Support\Collection>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
741
            $columns[] = $field->column();
742
        }
743
744
        foreach (array_flatten($columns) as $column) {
745
            if (str_contains($column, '.')) {
746
                list($relation) = explode('.', $column);
747
748
                if (method_exists($this->model, $relation) &&
749
                    $this->model->$relation() instanceof Relation
750
                ) {
751
                    $relations[] = $relation;
752
                }
753
            } elseif (method_exists($this->model, $column)) {
754
                $relations[] = $column;
755
            }
756
        }
757
758
        return array_unique($relations);
759
    }
760
761
    /**
762
     * Get current resource route url.
763
     *
764
     * @param int $slice
765
     *
766
     * @return string
767
     */
768
    public function resource($slice = -2)
769
    {
770
        $route = app('router')->current();
771
772
        $segments = explode('/', trim($route->getUri(), '/'));
773
774
        if ($slice != 0) {
775
            $segments = array_slice($segments, 0, $slice);
776
        }
777
778
        return '/'.implode('/', $segments);
779
    }
780
781
    /**
782
     * Render the form contents.
783
     *
784
     * @return string
785
     */
786
    public function render()
787
    {
788
        try {
789
            return $this->builder->render();
790
        } catch (\Exception $e) {
791
            return with(new Handle($e))->render();
792
        }
793
    }
794
795
    /**
796
     * Get or set input data.
797
     *
798
     * @param string $key
799
     * @param null   $value
800
     *
801
     * @return array|mixed
802
     */
803
    public function input($key, $value = null)
804
    {
805
        if (is_null($value)) {
806
            return array_get($this->inputs, $key);
807
        }
808
809
        return array_set($this->inputs, $key, $value);
810
    }
811
812
    /**
813
     * Getter.
814
     *
815
     * @param string $name
816
     *
817
     * @return array|mixed
818
     */
819
    public function __get($name)
820
    {
821
        return $this->input($name);
822
    }
823
824
    /**
825
     * Setter.
826
     *
827
     * @param string $name
828
     * @param $value
829
     */
830
    public function __set($name, $value)
831
    {
832
        $this->input($name, $value);
833
    }
834
835
    /**
836
     * Generate a Field object and add to form builder if Field exists.
837
     *
838
     * @param string $method
839
     * @param array  $arguments
840
     *
841
     * @return Field|void
842
     */
843 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...
844
    {
845
        if ($className = static::findFieldClass($method)) {
846
            $column = array_get($arguments, 0, ''); //[0];
847
848
            $element = new $className($column, array_slice($arguments, 1));
849
850
            $this->pushField($element);
851
852
            return $element;
853
        }
854
    }
855
856 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...
857
    {
858
        $className = __NAMESPACE__.'\\Form\\Field\\'.ucfirst($method);
859
860
        if (class_exists($className)) {
861
            return $className;
862
        }
863
864
        if ($method == 'switch') {
865
            return __NAMESPACE__.'\\Form\\Field\\SwitchField';
866
        }
867
868
        return false;
869
    }
870
871
    /**
872
     * Render the contents of the form when casting to string.
873
     *
874
     * @return string
875
     */
876
    public function __toString()
877
    {
878
        return $this->render();
879
    }
880
}
881