Completed
Push — master ( 1cf1dc...74f937 )
by Kristijan
04:42
created

Form::setModel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 1
rs 9.4285
1
<?php
2
3
namespace Kris\LaravelFormBuilder;
4
5
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
6
use Illuminate\Contracts\Validation\Factory as ValidatorFactory;
7
use Illuminate\Contracts\Validation\Validator;
8
use Illuminate\Http\Exceptions\HttpResponseException;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\Arr;
11
use Kris\LaravelFormBuilder\Events\AfterFieldCreation;
12
use Kris\LaravelFormBuilder\Events\AfterFormValidation;
13
use Kris\LaravelFormBuilder\Events\BeforeFormValidation;
14
use Kris\LaravelFormBuilder\Fields\FormField;
15
16
class Form
17
{
18
19
    /**
20
     * All fields that are added.
21
     *
22
     * @var array
23
     */
24
    protected $fields = [];
25
26
    /**
27
     * Model to use.
28
     *
29
     * @var mixed
30
     */
31
    protected $model = [];
32
33
    /**
34
     * @var EventDispatcher
35
     */
36
    protected $eventDispatcher;
37
38
    /**
39
     * @var FormHelper
40
     */
41
    protected $formHelper;
42
43
    /**
44
     * Form options.
45
     *
46
     * @var array
47
     */
48
    protected $formOptions = [
49
        'method' => 'GET',
50
        'url' => null
51
    ];
52
53
    /**
54
     * Additional data which can be used to build fields.
55
     *
56
     * @var array
57
     */
58
    protected $data = [];
59
60
    /**
61
     * Wether errors for each field should be shown when calling form($form) or form_rest($form).
62
     *
63
     * @var bool
64
     */
65
    protected $showFieldErrors = true;
66
67
    /**
68
     * Enable html5 validation.
69
     *
70
     * @var bool
71
     */
72
    protected $clientValidationEnabled = true;
73
74
    /**
75
     * Name of the parent form if any.
76
     *
77
     * @var string|null
78
     */
79
    protected $name = null;
80
81
    /**
82
     * @var FormBuilder
83
     */
84
    protected $formBuilder;
85
86
    /**
87
     * @var ValidatorFactory
88
     */
89
    protected $validatorFactory;
90
91
    /**
92
     * @var Validator
93
     */
94
    protected $validator = null;
95
96
    /**
97
     * @var Request
98
     */
99
    protected $request;
100
101
    /**
102
     * List of fields to not render.
103
     *
104
     * @var array
105
     **/
106
    protected $exclude = [];
107
108
    /**
109
     * Wether the form is beign rebuild.
110
     *
111
     * @var bool
112
     */
113
    protected $rebuilding = false;
114
115
    /**
116
     * @var string
117
     */
118
    protected $templatePrefix;
119
120
    /**
121
     * @var string
122
     */
123
    protected $languageName;
124
125
    /**
126
     * Build the form.
127
     *
128
     * @return mixed
129
     */
130 3
    public function buildForm()
131
    {
132 3
    }
133
134
    /**
135
     * Rebuild the form from scratch.
136
     *
137
     * @return $this
138
     */
139 17
    public function rebuildForm()
140
    {
141 17
        $this->rebuilding = true;
142
        // If form is plain, buildForm method is empty, so we need to take
143
        // existing fields and add them again
144 17
        if (get_class($this) === 'Kris\LaravelFormBuilder\Form') {
145 16
            foreach ($this->fields as $name => $field) {
146
                // Remove any temp variables added in previous instance
147 7
                $options = array_except($field->getOptions(), 'tmp');
148 16
                $this->add($name, $field->getType(), $options);
149
            }
150
        } else {
151 3
            $this->buildForm();
152
        }
153 17
        $this->rebuilding = false;
154
155 17
        return $this;
156
    }
157
158
    /**
159
     * Create the FormField object.
160
     *
161
     * @param string $name
162
     * @param string $type
163
     * @param array  $options
164
     * @return FormField
165
     */
166 53
    protected function makeField($name, $type = 'text', array $options = [])
167
    {
168 53
        $this->setupFieldOptions($name, $options);
169
170 53
        $fieldName = $this->getFieldName($name);
171
172 53
        $fieldType = $this->getFieldType($type);
173
174 52
        $field = new $fieldType($fieldName, $type, $this, $options);
175
176 49
        $this->eventDispatcher->fire(new AfterFieldCreation($this, $field));
177
178 49
        return $field;
179
    }
180
181
    /**
182
     * Create a new field and add it to the form.
183
     *
184
     * @param string $name
185
     * @param string $type
186
     * @param array  $options
187
     * @param bool   $modify
188
     * @return $this
189
     */
190 55
    public function add($name, $type = 'text', array $options = [], $modify = false)
191
    {
192 55
        $this->formHelper->checkFieldName($name, get_class($this));
193
194 53
        if ($this->rebuilding && !$this->has($name)) {
195
            return $this;
196
        }
197
198 53
        $this->addField($this->makeField($name, $type, $options), $modify);
199
200 49
        return $this;
201
    }
202
203
    /**
204
     * Add a FormField to the form's fields.
205
     *
206
     * @param FormField $field
207
     * @return $this
208
     */
209 49
    protected function addField(FormField $field, $modify = false)
210
    {
211 49
        if (!$modify && !$this->rebuilding) {
212 49
            $this->preventDuplicate($field->getRealName());
213
        }
214
215
216 49
        if ($field->getType() == 'file') {
217 3
            $this->formOptions['files'] = true;
218
        }
219
220 49
        $this->fields[$field->getRealName()] = $field;
221
222 49
        return $this;
223
    }
224
225
    /**
226
     * Add field before another field.
227
     *
228
     * @param string  $name         Name of the field before which new field is added.
229
     * @param string  $fieldName    Field name which will be added.
230
     * @param string  $type
231
     * @param array   $options
232
     * @param bool $modify
233
     * @return $this
234
     */
235 1
    public function addBefore($name, $fieldName, $type = 'text', $options = [], $modify = false)
236
    {
237 1
        $offset = array_search($name, array_keys($this->fields));
238
239 1
        $beforeFields = array_slice($this->fields, 0, $offset);
240 1
        $afterFields = array_slice($this->fields, $offset);
241
242 1
        $this->fields = $beforeFields;
243
244 1
        $this->add($fieldName, $type, $options, $modify);
245
246 1
        $this->fields += $afterFields;
247
248 1
        return $this;
249
    }
250
251
    /**
252
     * Add field before another field.
253
     *
254
     * @param string  $name         Name of the field after which new field is added.
255
     * @param string  $fieldName    Field name which will be added.
256
     * @param string  $type
257
     * @param array   $options
258
     * @param bool $modify
259
     * @return $this
260
     */
261 1
    public function addAfter($name, $fieldName, $type = 'text', $options = [], $modify = false)
262
    {
263 1
        $offset = array_search($name, array_keys($this->fields));
264
265 1
        $beforeFields = array_slice($this->fields, 0, $offset + 1);
266 1
        $afterFields = array_slice($this->fields, $offset + 1);
267
268 1
        $this->fields = $beforeFields;
269
270 1
        $this->add($fieldName, $type, $options, $modify);
271
272 1
        $this->fields += $afterFields;
273
274 1
        return $this;
275
    }
276
277
    /**
278
     * Take another form and add it's fields directly to this form.
279
     *
280
     * @param mixed   $class        Form to merge.
281
     * @param array   $options
282
     * @param boolean $modify
283
     * @return $this
284
     */
285 1
    public function compose($class, array $options = [], $modify = false)
286
    {
287 1
        $options['class'] = $class;
288
289
        // If we pass a ready made form just extract the fields.
290 1
        if ($class instanceof Form) {
291 1
            $fields = $class->getFields();
292
        } elseif ($class instanceof Fields\ChildFormType) {
293
            $fields = $class->getForm()->getFields();
294
        } elseif (is_string($class)) {
295
            // If its a string of a class make it the usual way.
296
            $options['model'] = $this->model;
297
            $options['name'] = $this->name;
298
299
            $form = $this->formBuilder->create($class, $options);
300
            $fields = $form->getFields();
301
        } else {
302
            throw new \InvalidArgumentException(
303
                "[{$class}] is invalid. Please provide either a full class name, Form or ChildFormType"
304
            );
305
        }
306
307 1
        foreach ($fields as $field) {
308 1
            $this->addField($field, $modify);
309
        }
310
311 1
        return $this;
312
    }
313
314
    /**
315
     * Remove field with specified name from the form.
316
     *
317
     * @param $name
318
     * @return $this
319
     */
320 2
    public function remove($name)
321
    {
322 2
        if ($this->has($name)) {
323 2
            unset($this->fields[$name]);
324
        }
325
326 2
        return $this;
327
    }
328
329
    /**
330
     * Modify existing field. If it doesn't exist, it is added to form.
331
     *
332
     * @param string $name
333
     * @param string $type
334
     * @param array  $options
335
     * @param bool   $overwriteOptions
336
     * @return Form
337
     */
338 1
    public function modify($name, $type = 'text', array $options = [], $overwriteOptions = false)
339
    {
340
        // If we don't want to overwrite options, we merge them with old options.
341 1
        if ($overwriteOptions === false && $this->has($name)) {
342 1
            $options = $this->formHelper->mergeOptions(
343 1
                $this->getField($name)->getOptions(),
344 1
                $options
345
            );
346
        }
347
348 1
        return $this->add($name, $type, $options, true);
349
    }
350
351
    /**
352
     * Render full form.
353
     *
354
     * @param array $options
355
     * @param bool  $showStart
356
     * @param bool  $showFields
357
     * @param bool  $showEnd
358
     * @return string
359
     */
360 7
    public function renderForm(array $options = [], $showStart = true, $showFields = true, $showEnd = true)
361
    {
362 7
        return $this->render($options, $this->fields, $showStart, $showFields, $showEnd);
0 ignored issues
show
Documentation introduced by
$this->fields is of type array, 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...
363
    }
364
365
    /**
366
     * Render rest of the form.
367
     *
368
     * @param bool $showFormEnd
369
     * @param bool $showFields
370
     * @return string
371
     */
372 1
    public function renderRest($showFormEnd = true, $showFields = true)
373
    {
374 1
        $fields = $this->getUnrenderedFields();
375
376 1
        return $this->render([], $fields, false, $showFields, $showFormEnd);
0 ignored issues
show
Documentation introduced by
$fields is of type array, 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...
377
    }
378
379
    /**
380
     * Renders the rest of the form up until the specified field name.
381
     *
382
     * @param string $field_name
383
     * @param bool   $showFormEnd
384
     * @param bool   $showFields
385
     * @return string
386
     */
387 2
    public function renderUntil($field_name, $showFormEnd = true, $showFields = true)
388
    {
389 2
        if (!$this->has($field_name)) {
390 1
            $this->fieldDoesNotExist($field_name);
391
        }
392
393 1
        $fields = $this->getUnrenderedFields();
394
395 1
        $i = 1;
396 1
        foreach ($fields as $key => $value) {
397 1
            if ($value->getRealName() == $field_name) {
398 1
                break;
399
            }
400 1
            $i++;
401
        }
402
403 1
        $fields = array_slice($fields, 0, $i, true);
404
405 1
        return $this->render([], $fields, false, $showFields, $showFormEnd);
0 ignored issues
show
Documentation introduced by
$fields is of type array, 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...
406
    }
407
408
    /**
409
     * Get single field instance from form object.
410
     *
411
     * @param string $name
412
     * @return FormField
413
     */
414 26
    public function getField($name)
415
    {
416 26
        if ($this->has($name)) {
417 25
            return $this->fields[$name];
418
        }
419
420 1
        $this->fieldDoesNotExist($name);
421
    }
422
423
    /**
424
     * Check if form has field.
425
     *
426
     * @param string $name
427
     * @return bool
428
     */
429 49
    public function has($name)
430
    {
431 49
        return array_key_exists($name, $this->fields);
432
    }
433
434
    /**
435
     * Get all form options.
436
     *
437
     * @return array
438
     */
439 2
    public function getFormOptions()
440
    {
441 2
        return $this->formOptions;
442
    }
443
444
    /**
445
     * Get single form option.
446
     *
447
     * @param string $option
448
     * @param mixed|null $default
449
     * @return mixed
450
     */
451 110
    public function getFormOption($option, $default = null)
452
    {
453 110
        return array_get($this->formOptions, $option, $default);
454
    }
455
456
    /**
457
     * Set single form option on form.
458
     *
459
     * @param string $option
460
     * @param mixed $value
461
     *
462
     * @return $this
463
     */
464 2
    public function setFormOption($option, $value)
465
    {
466 2
        $this->formOptions[$option] = $value;
467
468 2
        return $this;
469
    }
470
471
    /**
472
     * Set form options.
473
     *
474
     * @param array $formOptions
475
     * @return $this
476
     */
477 110
    public function setFormOptions(array $formOptions)
478
    {
479 110
        $this->formOptions = $this->formHelper->mergeOptions($this->formOptions, $formOptions);
480 110
        $this->checkIfNamedForm();
481 110
        $this->pullFromOptions('data', 'addData');
482 110
        $this->pullFromOptions('model', 'setupModel');
483 110
        $this->pullFromOptions('errors_enabled', 'setErrorsEnabled');
484 110
        $this->pullFromOptions('client_validation', 'setClientValidationEnabled');
485 110
        $this->pullFromOptions('template_prefix', 'setTemplatePrefix');
486 110
        $this->pullFromOptions('language_name', 'setLanguageName');
487
488 110
        return $this;
489
    }
490
491
    /**
492
     * Get an option from provided options and call method with that value.
493
     *
494
     * @param string $name
495
     * @param string $method
496
     */
497 110
    protected function pullFromOptions($name, $method)
498
    {
499 110
        if (array_get($this->formOptions, $name) !== null) {
500 18
            $this->{$method}(array_pull($this->formOptions, $name));
501
        }
502 110
    }
503
504
    /**
505
     * Get form http method.
506
     *
507
     * @return string
508
     */
509 3
    public function getMethod()
510
    {
511 3
        return $this->formOptions['method'];
512
    }
513
514
    /**
515
     * Set form http method.
516
     *
517
     * @param string $method
518
     * @return $this
519
     */
520 1
    public function setMethod($method)
521
    {
522 1
        $this->formOptions['method'] = $method;
523
524 1
        return $this;
525
    }
526
527
    /**
528
     * Get form action url.
529
     *
530
     * @return string
531
     */
532 3
    public function getUrl()
533
    {
534 3
        return $this->formOptions['url'];
535
    }
536
537
    /**
538
     * Set form action url.
539
     *
540
     * @param string $url
541
     * @return $this
542
     */
543 1
    public function setUrl($url)
544
    {
545 1
        $this->formOptions['url'] = $url;
546
547 1
        return $this;
548
    }
549
550
    /**
551
     * Returns the name of the form.
552
     *
553
     * @return string|null
554
     */
555 54
    public function getName()
556
    {
557 54
        return $this->name;
558
    }
559
560
    /**
561
     * Set the name of the form.
562
     *
563
     * @param string $name
564
     * @param bool $rebuild
565
     * @return $this
566
     */
567 10
    public function setName($name, $rebuild = true)
568
    {
569 10
        $this->name = $name;
570
571 10
        if ($rebuild) {
572 10
            $this->rebuildForm();
573
        }
574
575 10
        return $this;
576
    }
577
578
    /**
579
     * Get model that is bind to form object.
580
     *
581
     * @return mixed
582
     */
583 83
    public function getModel()
584
    {
585 83
        return $this->model;
586
    }
587
588
    /**
589
     * Set model to form object.
590
     *
591
     * @param mixed $model
592
     * @return $this
593
     * @deprecated deprecated since 1.6.31, will be removed in 1.7 - pass model as option when creating a form
594
     */
595 15
    public function setModel($model)
596
    {
597 15
        $this->model = $model;
598
599 15
        $this->rebuildForm();
600
601 15
        return $this;
602
    }
603
604
    /**
605
     * Setup model for form, add namespace if needed for child forms.
606
     *
607
     * @return $this
608
     */
609 12
    protected function setupModel($model)
610
    {
611 12
        $this->model = $model;
612
613 12
        return $this;
614
    }
615
616
    /**
617
     * Get all fields.
618
     *
619
     * @return FormField[]
620
     */
621 30
    public function getFields()
622
    {
623 30
        return $this->fields;
624
    }
625
626
    /**
627
     * Get field dynamically.
628
     *
629
     * @param string $name
630
     * @return FormField
631
     */
632 19
    public function __get($name)
633
    {
634 19
        if ($this->has($name)) {
635 18
            return $this->getField($name);
636
        }
637 3
    }
638
639
    /**
640
     * Check if field exists when fetched using magic methods.
641
     *
642
     * @param string $name
643
     * @return bool
644
     */
645
    public function __isset($name)
646
    {
647
        return $this->has($name);
648
    }
649
650
    /**
651
     * Set the Event Dispatcher to fire Laravel events.
652
     *
653
     * @param EventDispatcher $eventDispatcher
654
     * @return $this
655
     */
656 110
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
657
    {
658 110
        $this->eventDispatcher = $eventDispatcher;
659
660 110
        return $this;
661
    }
662
663
    /**
664
     * Set the form helper only on first instantiation.
665
     *
666
     * @param FormHelper $formHelper
667
     * @return $this
668
     */
669 110
    public function setFormHelper(FormHelper $formHelper)
670
    {
671 110
        $this->formHelper = $formHelper;
672
673 110
        return $this;
674
    }
675
676
    /**
677
     * Get form helper.
678
     *
679
     * @return FormHelper
680
     */
681 87
    public function getFormHelper()
682
    {
683 87
        return $this->formHelper;
684
    }
685
686
    /**
687
     * Add custom field.
688
     *
689
     * @param $name
690
     * @param $class
691
     */
692 2
    public function addCustomField($name, $class)
693
    {
694 2
        if ($this->rebuilding && $this->formHelper->hasCustomField($name)) {
695
            return $this;
696
        }
697
698 2
        $this->formHelper->addCustomField($name, $class);
699 2
    }
700
701
    /**
702
     * Returns wether form errors should be shown under every field.
703
     *
704
     * @return bool
705
     */
706 87
    public function haveErrorsEnabled()
707
    {
708 87
        return $this->showFieldErrors;
709
    }
710
711
    /**
712
     * Enable or disable showing errors under fields
713
     *
714
     * @param bool $enabled
715
     * @return $this
716
     */
717 1
    public function setErrorsEnabled($enabled)
718
    {
719 1
        $this->showFieldErrors = (bool) $enabled;
720
721 1
        return $this;
722
    }
723
724
    /**
725
     * Is client validation enabled?
726
     *
727
     * @return bool
728
     */
729 21
    public function clientValidationEnabled()
730
    {
731 21
        return $this->clientValidationEnabled;
732
    }
733
734
    /**
735
     * Enable/disable client validation.
736
     *
737
     * @param bool $enable
738
     * @return $this
739
     */
740 2
    public function setClientValidationEnabled($enable)
741
    {
742 2
        $this->clientValidationEnabled = (bool) $enable;
743
744 2
        return $this;
745
    }
746
747
    /**
748
     * Add any aditional data that field needs (ex. array of choices).
749
     *
750
     * @deprecated deprecated since 1.6.20, will be removed in 1.7 - use 3rd param on create, or 2nd on plain method to pass data
751
     * will be switched to protected in 1.7.
752
     * @param string $name
753
     * @param mixed $data
754
     */
755 1
    public function setData($name, $data)
756
    {
757 1
        $this->data[$name] = $data;
758 1
    }
759
760
    /**
761
     * Get single additional data.
762
     *
763
     * @param string $name
764
     * @param null   $default
765
     * @return mixed
766
     */
767 18
    public function getData($name = null, $default = null)
768
    {
769 18
        if (is_null($name)) {
770 17
            return $this->data;
771
        }
772
773 1
        return array_get($this->data, $name, $default);
774
    }
775
776
    /**
777
     * Add multiple peices of data at once.
778
     *
779
     * @deprecated deprecated since 1.6.12, will be removed in 1.7 - use 3rd param on create, or 2nd on plain method to pass data
780
     * will be switched to protected in 1.7.
781
     * @param $data
782
     * @return $this
783
     **/
784 110
    public function addData(array $data)
785
    {
786 110
        foreach ($data as $key => $value) {
787 1
            $this->setData($key, $value);
0 ignored issues
show
Deprecated Code introduced by
The method Kris\LaravelFormBuilder\Form::setData() has been deprecated with message: deprecated since 1.6.20, will be removed in 1.7 - use 3rd param on create, or 2nd on plain method to pass data
will be switched to protected in 1.7.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
788
        }
789
790 110
        return $this;
791
    }
792
793
    /**
794
     * Get current request.
795
     *
796
     * @return \Illuminate\Http\Request
797
     */
798 87
    public function getRequest()
799
    {
800 87
        return $this->request;
801
    }
802
803
    /**
804
     * Set request on form.
805
     *
806
     * @param Request $request
807
     * @return $this
808
     */
809 110
    public function setRequest(Request $request)
810
    {
811 110
        $this->request = $request;
812
813 110
        return $this;
814
    }
815
816
    /**
817
     * Get template prefix that is prepended to all template paths.
818
     *
819
     * @return string
820
     */
821 37
    public function getTemplatePrefix()
822
    {
823 37
        if ($this->templatePrefix !== null) {
824 4
            return $this->templatePrefix;
825
        }
826
827 33
        return $this->formHelper->getConfig('template_prefix');
828
    }
829
830
    /**
831
     * Set a template prefix for the form and its fields.
832
     *
833
     * @param string $prefix
834
     * @return $this
835
     */
836 4
    public function setTemplatePrefix($prefix)
837
    {
838 4
        $this->templatePrefix = (string) $prefix;
839
840 4
        return $this;
841
    }
842
843
    /**
844
     * Get the language name.
845
     *
846
     * @return string
847
     */
848 85
    public function getLanguageName()
849
    {
850 85
        return $this->languageName;
851
    }
852
853
    /**
854
     * Set a language name, used as prefix for translated strings.
855
     *
856
     * @param string $prefix
857
     * @return $this
858
     */
859 11
    public function setLanguageName($prefix)
860
    {
861 11
        $this->languageName = (string) $prefix;
862
863 11
        return $this;
864
    }
865
866
    /**
867
     * Render the form.
868
     *
869
     * @param array $options
870
     * @param string $fields
871
     * @param bool $showStart
872
     * @param bool $showFields
873
     * @param bool $showEnd
874
     * @return string
875
     */
876 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
877
    {
878 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
879
880 9
        $this->setupNamedModel();
881
882 9
        return $this->formHelper->getView()
883 9
            ->make($this->getTemplate())
884 9
            ->with(compact('showStart', 'showFields', 'showEnd'))
885 9
            ->with('formOptions', $formOptions)
886 9
            ->with('fields', $fields)
887 9
            ->with('model', $this->getModel())
888 9
            ->with('exclude', $this->exclude)
889 9
            ->with('form', $this)
890 9
            ->render();
891
    }
892
893
    /**
894
     * Get template from options if provided, otherwise fallback to config.
895
     *
896
     * @return mixed
897
     */
898 9
    protected function getTemplate()
899
    {
900 9
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->formHelper->getConfig('form'));
901
    }
902
903
    /**
904
     * Get all fields that are not rendered.
905
     *
906
     * @return array
907
     */
908 2
    protected function getUnrenderedFields()
909
    {
910 2
        $unrenderedFields = [];
911
912 2
        foreach ($this->fields as $field) {
913 2
            if (!$field->isRendered()) {
914 2
                $unrenderedFields[] = $field;
915 2
                continue;
916
            }
917
        }
918
919 2
        return $unrenderedFields;
920
    }
921
922
    /**
923
     * Prevent adding fields with same name.
924
     *
925
     * @param string $name
926
     * @throws \InvalidArgumentException
927
     * @return void
928
     */
929 49
    protected function preventDuplicate($name)
930
    {
931 49
        if ($this->has($name)) {
932 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
933
        }
934 49
    }
935
936
    /**
937
     * Returns and checks the type of the field.
938
     *
939
     * @param string $type
940
     * @return string
941
     */
942 53
    protected function getFieldType($type)
943
    {
944 53
        $fieldType = $this->formHelper->getFieldType($type);
945
946 52
        return $fieldType;
947
    }
948
949
    /**
950
     * Check if form is named form.
951
     *
952
     * @return void
953
     */
954 110
    protected function checkIfNamedForm()
955
    {
956 110
        if ($this->getFormOption('name')) {
957 8
            $this->name = array_pull($this->formOptions, 'name', $this->name);
958
        }
959 110
    }
960
961
    /**
962
     * Set up options on single field depending on form options.
963
     *
964
     * @param string $name
965
     * @param $options
966
     */
967 53
    protected function setupFieldOptions($name, &$options)
968
    {
969 53
        $options['real_name'] = $name;
970 53
    }
971
972
    /**
973
     * Set namespace to model if form is named so the data is bound properly.
974
     * Returns true if model is changed, otherwise false.
975
     *
976
     * @return bool
977
     */
978 9
    protected function setupNamedModel()
979
    {
980 9
        if (!$this->getModel() || !$this->getName()) {
981 8
            return false;
982
        }
983
984 1
        $dotName = $this->formHelper->transformToDotSyntax($this->getName());
985 1
        $model = $this->formHelper->convertModelToArray($this->getModel());
986
987 1
        if (!array_get($model, $dotName)) {
0 ignored issues
show
Bug introduced by
It seems like $model defined by $this->formHelper->conve...rray($this->getModel()) on line 985 can also be of type null or object; however, array_get() does only seem to accept object<ArrayAccess>|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
988 1
            $newModel = [];
989 1
            array_set($newModel, $dotName, $model);
990 1
            $this->model = $newModel;
991
992 1
            return true;
993
        }
994
995
        return false;
996
    }
997
998
999
    /**
1000
     * Set form builder instance on helper so we can use it later.
1001
     *
1002
     * @param FormBuilder $formBuilder
1003
     * @return $this
1004
     */
1005 110
    public function setFormBuilder(FormBuilder $formBuilder)
1006
    {
1007 110
        $this->formBuilder = $formBuilder;
1008
1009 110
        return $this;
1010
    }
1011
1012
    /**
1013
     * Returns the instance of the FormBuilder.
1014
     *
1015
     * @return FormBuilder
1016
     */
1017 12
    public function getFormBuilder()
1018
    {
1019 12
        return $this->formBuilder;
1020
    }
1021
1022
    /**
1023
     * Set the Validator instance on this so we can use it later.
1024
     *
1025
     * @param ValidatorFactory $validator
1026
     * @return $this
1027
     */
1028 110
    public function setValidator(ValidatorFactory $validator)
1029
    {
1030 110
        $this->validatorFactory = $validator;
1031
1032 110
        return $this;
1033
    }
1034
1035
    /**
1036
     * Returns the validator instance.
1037
     *
1038
     * @return Validator
1039
     */
1040 1
    public function getValidator()
1041
    {
1042 1
        return $this->validator;
1043
    }
1044
1045
    /**
1046
     * Exclude some fields from rendering.
1047
     *
1048
     * @return $this
1049
     */
1050
    public function exclude(array $fields)
1051
    {
1052
        $this->exclude = array_merge($this->exclude, $fields);
1053
1054
        return $this;
1055
    }
1056
1057
1058
    /**
1059
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1060
     *
1061
     * @param string $name
1062
     * @return string
1063
     */
1064 53
    protected function getFieldName($name)
1065
    {
1066 53
        $formName = $this->getName();
1067 53
        if ($formName !== null) {
1068 14
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1069 6
                return $this->formHelper->transformToBracketSyntax(
1070 6
                    $this->formHelper->transformToDotSyntax(
1071 6
                        $formName . '[' . $name . ']'
1072
                    )
1073
                );
1074
            }
1075
1076 11
            return $formName . '[' . $name . ']';
1077
        }
1078
1079 53
        return $name;
1080
    }
1081
1082
    /**
1083
     * Disable all fields in a form.
1084
     */
1085 1
    public function disableFields()
1086
    {
1087 1
        foreach ($this->fields as $field) {
1088 1
            $field->disable();
1089
        }
1090 1
    }
1091
1092
    /**
1093
     * Enable all fields in a form.
1094
     */
1095 1
    public function enableFields()
1096
    {
1097 1
        foreach ($this->fields as $field) {
1098 1
            $field->enable();
1099
        }
1100 1
    }
1101
1102
    /**
1103
     * Validate the form.
1104
     *
1105
     * @param array $validationRules
1106
     * @param array $messages
1107
     * @return Validator
1108
     */
1109 9
    public function validate($validationRules = [], $messages = [])
1110
    {
1111 9
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1112 9
        $rules = array_merge($fieldRules['rules'], $validationRules);
1113 9
        $messages = array_merge($fieldRules['error_messages'], $messages);
1114
1115 9
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1116 9
        $this->validator->setAttributeNames($fieldRules['attributes']);
1117
1118 9
        $this->eventDispatcher->fire(new BeforeFormValidation($this, $this->validator));
1119
1120 9
        return $this->validator;
1121
    }
1122
1123
    /**
1124
     * Get validation rules for the form.
1125
     *
1126
     * @param array $overrideRules
1127
     * @return array
1128
     */
1129 1
    public function getRules($overrideRules = [])
1130
    {
1131 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1132
1133 1
        return array_merge($fieldRules['rules'], $overrideRules);
1134
    }
1135
1136
    /**
1137
     * Redirects to a destination when form is invalid.
1138
     *
1139
     * @param  string|null $destination The target url.
1140
     * @return HttpResponseException
1141
     */
1142 3
    public function redirectIfNotValid($destination = null)
1143
    {
1144 3
        if (! $this->isValid()) {
1145 3
            $response = redirect($destination);
1146
1147 3
            if (is_null($destination)) {
1148 2
                $response = $response->back();
1149
            }
1150
1151 3
            $response = $response->withErrors($this->getErrors())->withInput();
1152
1153 3
            throw new HttpResponseException($response);
1154
        }
1155
    }
1156
1157
    /**
1158
     * Get all form field attributes, including child forms, in a flat array.
1159
     *
1160
     * @return array
1161
     */
1162 3
    public function getAllAttributes()
1163
    {
1164 3
        return $this->formHelper->mergeAttributes($this->fields);
1165
    }
1166
1167
    /**
1168
     * Check if the form is valid.
1169
     *
1170
     * @return bool
1171
     */
1172 9
    public function isValid()
1173
    {
1174 9
        if (!$this->validator) {
1175 8
            $this->validate();
1176
        }
1177
1178 9
        $isValid = !$this->validator->fails();
1179
1180 9
        $this->formHelper->alterValid($this, $this, $isValid);
1181
1182 9
        $this->eventDispatcher->fire(new AfterFormValidation($this, $this->validator, $isValid));
1183
1184 9
        return $isValid;
1185
    }
1186
1187
    /**
1188
     * Optionally change the validation result, and/or add error messages.
1189
     *
1190
     * @param Form $mainForm
1191
     * @param bool $isValid
1192
     * @return void|array
1193
     */
1194 9
    public function alterValid(Form $mainForm, &$isValid)
0 ignored issues
show
Unused Code introduced by
The parameter $mainForm is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $isValid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1195
    {
1196
        // return ['name' => ['Some other error about the Name field.']];
1197 9
    }
1198
1199
    /**
1200
     * Get validation errors.
1201
     *
1202
     * @return array
1203
     */
1204 8
    public function getErrors()
1205
    {
1206 8
        if (!$this->validator || !$this->validator instanceof Validator) {
1207 1
            throw new \InvalidArgumentException(
1208 1
                sprintf(
1209 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1210 1
                    get_class($this)
1211
                )
1212
            );
1213
        }
1214
1215 7
        return $this->validator->getMessageBag()->getMessages();
1216
    }
1217
1218
    /**
1219
     * Get all Request values from all fields, and nothing else.
1220
     *
1221
     * @param bool $with_nulls
1222
     * @return array
1223
     */
1224 3
    public function getFieldValues($with_nulls = true)
1225
    {
1226 3
        $request_values = $this->getRequest()->all();
1227
1228 3
        $values = [];
1229 3
        foreach ($this->getAllAttributes() as $attribute) {
1230 3
            $value = Arr::get($request_values, $attribute);
1231 3
            if ($with_nulls || $value !== null) {
1232 3
                Arr::set($values, $attribute, $value);
1233
            }
1234
        }
1235
1236
        // If this form is a child form, cherry pick a part
1237 3
        if ($prefix = $this->getName()) {
1238 1
            $prefix = $this->formHelper->transformToDotSyntax($prefix);
1239 1
            $values = Arr::get($values, $prefix);
1240
        }
1241
1242
        // Allow form-specific value alters
1243 3
        $this->formHelper->alterFieldValues($this, $values);
1244
1245 3
        return $values;
1246
    }
1247
1248
    /**
1249
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1250
     *
1251
     * @param array $values
1252
     * @return void
1253
     */
1254 3
    public function alterFieldValues(array &$values)
0 ignored issues
show
Unused Code introduced by
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1255
    {
1256 3
    }
1257
1258
    /**
1259
     * Throw an exception indicating a field does not exist on the class.
1260
     *
1261
     * @param string $name
1262
     * @throws \InvalidArgumentException
1263
     * @return void
1264
     */
1265 2
    protected function fieldDoesNotExist($name)
1266
    {
1267 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1268
    }
1269
}
1270