Completed
Pull Request — master (#350)
by Matthew
04:40
created

Form::addAfter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 5
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
ccs 8
cts 8
cp 1
crap 1
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 51
    protected function makeField($name, $type = 'text', array $options = [])
167
    {
168 51
        $this->setupFieldOptions($name, $options);
169
170 51
        $fieldName = $this->getFieldName($name);
171
172 51
        $fieldType = $this->getFieldType($type);
173
174 50
        $field = new $fieldType($fieldName, $type, $this, $options);
175
176 47
        $this->eventDispatcher->fire(new AfterFieldCreation($this, $field));
177
178 47
        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 53
    public function add($name, $type = 'text', array $options = [], $modify = false)
191
    {
192 53
        $this->formHelper->checkFieldName($name, get_class($this));
193
194 51
        if ($this->rebuilding && !$this->has($name)) {
195
            return $this;
196
        }
197
198 51
        $this->addField($this->makeField($name, $type, $options), $modify);
199
200 47
        return $this;
201
    }
202
203
    /**
204
     * Add a FormField to the form's fields.
205
     *
206
     * @param FormField $field
207
     * @return $this
208
     */
209 47
    protected function addField(FormField $field, $modify = false)
210
    {
211 47
        if (!$modify && !$this->rebuilding) {
212 47
            $this->preventDuplicate($field->getRealName());
213
        }
214
215
216 47
        if ($field->getType() == 'file') {
217 3
            $this->formOptions['files'] = true;
218
        }
219
220 47
        $this->fields[$field->getRealName()] = $field;
221
222 47
        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
                $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 25
    public function getField($name)
415
    {
416 25
        if ($this->has($name)) {
417 24
            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 47
    public function has($name)
430
    {
431 47
        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 107
    public function getFormOption($option, $default = null)
452
    {
453 107
        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 107
    public function setFormOptions(array $formOptions)
478
    {
479 107
        $this->formOptions = $this->formHelper->mergeOptions($this->formOptions, $formOptions);
480 107
        $this->checkIfNamedForm();
481 107
        $this->pullFromOptions('data', 'addData');
482 107
        $this->pullFromOptions('model', 'setupModel');
483 107
        $this->pullFromOptions('errors_enabled', 'setErrorsEnabled');
484 107
        $this->pullFromOptions('client_validation', 'setClientValidationEnabled');
485 107
        $this->pullFromOptions('template_prefix', 'setTemplatePrefix');
486 107
        $this->pullFromOptions('language_name', 'setLanguageName');
487
488 107
        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 107
    protected function pullFromOptions($name, $method)
498
    {
499 107
        if (array_get($this->formOptions, $name) !== null) {
500 18
            $this->{$method}(array_pull($this->formOptions, $name));
501
        }
502 107
    }
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 52
    public function getName()
556
    {
557 52
        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 81
    public function getModel()
584
    {
585 81
        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 29
    public function getFields()
622
    {
623 29
        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 107
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
657
    {
658 107
        $this->eventDispatcher = $eventDispatcher;
659
660 107
        return $this;
661
    }
662
663
    /**
664
     * Set the form helper only on first instantiation.
665
     *
666
     * @param FormHelper $formHelper
667
     * @return $this
668
     */
669 107
    public function setFormHelper(FormHelper $formHelper)
670
    {
671 107
        $this->formHelper = $formHelper;
672
673 107
        return $this;
674
    }
675
676
    /**
677
     * Get form helper.
678
     *
679
     * @return FormHelper
680
     */
681 85
    public function getFormHelper()
682
    {
683 85
        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
        $this->formHelper->addCustomField($name, $class);
695 2
    }
696
697
    /**
698
     * Returns wether form errors should be shown under every field.
699
     *
700
     * @return bool
701
     */
702 85
    public function haveErrorsEnabled()
703
    {
704 85
        return $this->showFieldErrors;
705
    }
706
707
    /**
708
     * Enable or disable showing errors under fields
709
     *
710
     * @param bool $enabled
711
     * @return $this
712
     */
713 1
    public function setErrorsEnabled($enabled)
714
    {
715 1
        $this->showFieldErrors = (bool) $enabled;
716
717 1
        return $this;
718
    }
719
720
    /**
721
     * Is client validation enabled?
722
     *
723
     * @return bool
724
     */
725 21
    public function clientValidationEnabled()
726
    {
727 21
        return $this->clientValidationEnabled;
728
    }
729
730
    /**
731
     * Enable/disable client validation.
732
     *
733
     * @param bool $enable
734
     * @return $this
735
     */
736 2
    public function setClientValidationEnabled($enable)
737
    {
738 2
        $this->clientValidationEnabled = (bool) $enable;
739
740 2
        return $this;
741
    }
742
743
    /**
744
     * Add any aditional data that field needs (ex. array of choices).
745
     *
746
     * @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
747
     * will be switched to protected in 1.7.
748
     * @param string $name
749
     * @param mixed $data
750
     */
751 1
    public function setData($name, $data)
752
    {
753 1
        $this->data[$name] = $data;
754 1
    }
755
756
    /**
757
     * Get single additional data.
758
     *
759
     * @param string $name
760
     * @param null   $default
761
     * @return mixed
762
     */
763 18
    public function getData($name = null, $default = null)
764
    {
765 18
        if (is_null($name)) {
766 17
            return $this->data;
767
        }
768
769 1
        return array_get($this->data, $name, $default);
770
    }
771
772
    /**
773
     * Add multiple peices of data at once.
774
     *
775
     * @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
776
     * will be switched to protected in 1.7.
777
     * @param $data
778
     * @return $this
779
     **/
780 107
    public function addData(array $data)
781
    {
782 107
        foreach ($data as $key => $value) {
783 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...
784
        }
785
786 107
        return $this;
787
    }
788
789
    /**
790
     * Get current request.
791
     *
792
     * @return \Illuminate\Http\Request
793
     */
794 85
    public function getRequest()
795
    {
796 85
        return $this->request;
797
    }
798
799
    /**
800
     * Set request on form.
801
     *
802
     * @param Request $request
803
     * @return $this
804
     */
805 107
    public function setRequest(Request $request)
806
    {
807 107
        $this->request = $request;
808
809 107
        return $this;
810
    }
811
812
    /**
813
     * Get template prefix that is prepended to all template paths.
814
     *
815
     * @return string
816
     */
817 37
    public function getTemplatePrefix()
818
    {
819 37
        if ($this->templatePrefix !== null) {
820 4
            return $this->templatePrefix;
821
        }
822
823 33
        return $this->formHelper->getConfig('template_prefix');
824
    }
825
826
    /**
827
     * Set a template prefix for the form and its fields.
828
     *
829
     * @param string $prefix
830
     * @return $this
831
     */
832 4
    public function setTemplatePrefix($prefix)
833
    {
834 4
        $this->templatePrefix = (string) $prefix;
835
836 4
        return $this;
837
    }
838
839
    /**
840
     * Get the language name.
841
     *
842
     * @return string
843
     */
844 83
    public function getLanguageName()
845
    {
846 83
        return $this->languageName;
847
    }
848
849
    /**
850
     * Set a language name, used as prefix for translated strings.
851
     *
852
     * @param string $prefix
853
     * @return $this
854
     */
855 11
    public function setLanguageName($prefix)
856
    {
857 11
        $this->languageName = (string) $prefix;
858
859 11
        return $this;
860
    }
861
862
    /**
863
     * Render the form.
864
     *
865
     * @param array $options
866
     * @param string $fields
867
     * @param bool $showStart
868
     * @param bool $showFields
869
     * @param bool $showEnd
870
     * @return string
871
     */
872 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
873
    {
874 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
875
876 9
        $this->setupNamedModel();
877
878 9
        return $this->formHelper->getView()
879 9
            ->make($this->getTemplate())
880 9
            ->with(compact('showStart', 'showFields', 'showEnd'))
881 9
            ->with('formOptions', $formOptions)
882 9
            ->with('fields', $fields)
883 9
            ->with('model', $this->getModel())
884 9
            ->with('exclude', $this->exclude)
885 9
            ->with('form', $this)
886 9
            ->render();
887
    }
888
889
    /**
890
     * Get template from options if provided, otherwise fallback to config.
891
     *
892
     * @return mixed
893
     */
894 9
    protected function getTemplate()
895
    {
896 9
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->formHelper->getConfig('form'));
897
    }
898
899
    /**
900
     * Get all fields that are not rendered.
901
     *
902
     * @return array
903
     */
904 2
    protected function getUnrenderedFields()
905
    {
906 2
        $unrenderedFields = [];
907
908 2
        foreach ($this->fields as $field) {
909 2
            if (!$field->isRendered()) {
910 2
                $unrenderedFields[] = $field;
911 2
                continue;
912
            }
913
        }
914
915 2
        return $unrenderedFields;
916
    }
917
918
    /**
919
     * Prevent adding fields with same name.
920
     *
921
     * @param string $name
922
     * @throws \InvalidArgumentException
923
     * @return void
924
     */
925 47
    protected function preventDuplicate($name)
926
    {
927 47
        if ($this->has($name)) {
928 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
929
        }
930 47
    }
931
932
    /**
933
     * Returns and checks the type of the field.
934
     *
935
     * @param string $type
936
     * @return string
937
     */
938 51
    protected function getFieldType($type)
939
    {
940 51
        $fieldType = $this->formHelper->getFieldType($type);
941
942 50
        return $fieldType;
943
    }
944
945
    /**
946
     * Check if form is named form.
947
     *
948
     * @return void
949
     */
950 107
    protected function checkIfNamedForm()
951
    {
952 107
        if ($this->getFormOption('name')) {
953 8
            $this->name = array_pull($this->formOptions, 'name', $this->name);
954
        }
955 107
    }
956
957
    /**
958
     * Set up options on single field depending on form options.
959
     *
960
     * @param string $name
961
     * @param $options
962
     */
963 51
    protected function setupFieldOptions($name, &$options)
964
    {
965 51
        $options['real_name'] = $name;
966 51
    }
967
968
    /**
969
     * Set namespace to model if form is named so the data is bound properly.
970
     * Returns true if model is changed, otherwise false.
971
     *
972
     * @return bool
973
     */
974 9
    protected function setupNamedModel()
975
    {
976 9
        if (!$this->getModel() || !$this->getName()) {
977 8
            return false;
978
        }
979
980 1
        $dotName = $this->formHelper->transformToDotSyntax($this->getName());
981 1
        $model = $this->formHelper->convertModelToArray($this->getModel());
982
983 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 981 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...
984 1
            $newModel = [];
985 1
            array_set($newModel, $dotName, $model);
986 1
            $this->model = $newModel;
987
988 1
            return true;
989
        }
990
991
        return false;
992
    }
993
994
995
    /**
996
     * Set form builder instance on helper so we can use it later.
997
     *
998
     * @param FormBuilder $formBuilder
999
     * @return $this
1000
     */
1001 107
    public function setFormBuilder(FormBuilder $formBuilder)
1002
    {
1003 107
        $this->formBuilder = $formBuilder;
1004
1005 107
        return $this;
1006
    }
1007
1008
    /**
1009
     * Returns the instance of the FormBuilder.
1010
     *
1011
     * @return FormBuilder
1012
     */
1013 12
    public function getFormBuilder()
1014
    {
1015 12
        return $this->formBuilder;
1016
    }
1017
1018
    /**
1019
     * Set the Validator instance on this so we can use it later.
1020
     *
1021
     * @param ValidatorFactory $validator
1022
     * @return $this
1023
     */
1024 107
    public function setValidator(ValidatorFactory $validator)
1025
    {
1026 107
        $this->validatorFactory = $validator;
1027
1028 107
        return $this;
1029
    }
1030
1031
    /**
1032
     * Returns the validator instance.
1033
     *
1034
     * @return Validator
1035
     */
1036 1
    public function getValidator()
1037
    {
1038 1
        return $this->validator;
1039
    }
1040
1041
    /**
1042
     * Exclude some fields from rendering.
1043
     *
1044
     * @return $this
1045
     */
1046
    public function exclude(array $fields)
1047
    {
1048
        $this->exclude = array_merge($this->exclude, $fields);
1049
1050
        return $this;
1051
    }
1052
1053
1054
    /**
1055
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1056
     *
1057
     * @param string $name
1058
     * @return string
1059
     */
1060 51
    protected function getFieldName($name)
1061
    {
1062 51
        $formName = $this->getName();
1063 51
        if ($formName !== null) {
1064 14
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1065 6
                return $this->formHelper->transformToBracketSyntax(
1066 6
                    $this->formHelper->transformToDotSyntax(
1067 6
                        $formName . '[' . $name . ']'
1068
                    )
1069
                );
1070
            }
1071
1072 11
            return $formName . '[' . $name . ']';
1073
        }
1074
1075 51
        return $name;
1076
    }
1077
1078
    /**
1079
     * Disable all fields in a form.
1080
     */
1081 1
    public function disableFields()
1082
    {
1083 1
        foreach ($this->fields as $field) {
1084 1
            $field->disable();
1085
        }
1086 1
    }
1087
1088
    /**
1089
     * Enable all fields in a form.
1090
     */
1091 1
    public function enableFields()
1092
    {
1093 1
        foreach ($this->fields as $field) {
1094 1
            $field->enable();
1095
        }
1096 1
    }
1097
1098
    /**
1099
     * Validate the form.
1100
     *
1101
     * @param array $validationRules
1102
     * @param array $messages
1103
     * @return Validator
1104
     */
1105 8
    public function validate($validationRules = [], $messages = [])
1106
    {
1107 8
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1108 8
        $rules = array_merge($fieldRules['rules'], $validationRules);
1109 8
        $messages = array_merge($fieldRules['error_messages'], $messages);
1110
1111 8
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1112 8
        $this->validator->setAttributeNames($fieldRules['attributes']);
1113
1114 8
        $this->eventDispatcher->fire(new BeforeFormValidation($this, $this->validator));
1115
1116 8
        return $this->validator;
1117
    }
1118
1119
    /**
1120
     * Get validation rules for the form.
1121
     *
1122
     * @param array $overrideRules
1123
     * @return array
1124
     */
1125 1
    public function getRules($overrideRules = [])
1126
    {
1127 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1128
1129 1
        return array_merge($fieldRules['rules'], $overrideRules);
1130
    }
1131
1132
    /**
1133
     * Redirects to a destination when form is invalid.
1134
     *
1135
     * @param  string|null $destination The target url.
1136
     * @return HttpResponseException
1137
     */
1138 2
    public function redirectIfNotValid($destination = null)
1139
    {
1140 2
        if (! $this->isValid()) {
1141 2
            $response = redirect($destination);
1142
1143 2
            if (is_null($destination)) {
1144 1
                $response = $response->back();
1145
            }
1146
1147 2
            $response = $response->withErrors($this->getErrors())->withInput();
1148
1149 2
            throw new HttpResponseException($response);
1150
        }
1151
    }
1152
1153
    /**
1154
     * Get all form field attributes, including child forms, in a flat array.
1155
     *
1156
     * @return array
1157
     */
1158 3
    public function getAllAttributes()
1159
    {
1160 3
        return $this->formHelper->mergeAttributes($this->fields);
1161
    }
1162
1163
    /**
1164
     * Check if the form is valid.
1165
     *
1166
     * @return bool
1167
     */
1168 8
    public function isValid()
1169
    {
1170 8
        if (!$this->validator) {
1171 7
            $this->validate();
1172
        }
1173
1174 8
        $isValid = !$this->validator->fails();
1175
1176 8
        $this->formHelper->alterValid($this, $this, $isValid);
1177
1178 8
        $this->eventDispatcher->fire(new AfterFormValidation($this, $this->validator, $isValid));
1179
1180 8
        return $isValid;
1181
    }
1182
1183
    /**
1184
     * Optionally change the validation result, and/or add error messages.
1185
     *
1186
     * @param Form $mainForm
1187
     * @param bool $isValid
1188
     * @return void|array
1189
     */
1190 8
    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...
1191
    {
1192
        // return ['name' => ['Some other error about the Name field.']];
1193 8
    }
1194
1195
    /**
1196
     * Get validation errors.
1197
     *
1198
     * @return array
1199
     */
1200 7
    public function getErrors()
1201
    {
1202 7
        if (!$this->validator || !$this->validator instanceof Validator) {
1203 1
            throw new \InvalidArgumentException(
1204
                sprintf(
1205 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1206
                    get_class($this)
1207
                )
1208
            );
1209
        }
1210
1211 6
        return $this->validator->getMessageBag()->getMessages();
1212
    }
1213
1214
    /**
1215
     * Get all Request values from all fields, and nothing else.
1216
     *
1217
     * @param bool $with_nulls
1218
     * @return array
1219
     */
1220 3
    public function getFieldValues($with_nulls = true)
1221
    {
1222 3
        $request_values = $this->getRequest()->all();
1223
1224 3
        $values = [];
1225 3
        foreach ($this->getAllAttributes() as $attribute) {
1226 3
            $value = Arr::get($request_values, $attribute);
1227 3
            if ($with_nulls || $value !== null) {
1228 3
                Arr::set($values, $attribute, $value);
1229
            }
1230
        }
1231
1232
        // If this form is a child form, cherry pick a part
1233 3
        if ($prefix = $this->getName()) {
1234 1
            $prefix = $this->formHelper->transformToDotSyntax($prefix);
1235 1
            $values = Arr::get($values, $prefix);
1236
        }
1237
1238
        // Allow form-specific value alters
1239 3
        $this->formHelper->alterFieldValues($this, $values);
1240
1241 3
        return $values;
1242
    }
1243
1244
    /**
1245
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1246
     *
1247
     * @param array $values
1248
     * @return void
1249
     */
1250 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...
1251
    {
1252 3
    }
1253
1254
    /**
1255
     * Throw an exception indicating a field does not exist on the class.
1256
     *
1257
     * @param string $name
1258
     * @throws \InvalidArgumentException
1259
     * @return void
1260
     */
1261 2
    protected function fieldDoesNotExist($name)
1262
    {
1263 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1264
    }
1265
}
1266