Completed
Pull Request — master (#266)
by Rudie
08:26
created

Form::getMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
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 the entire fields part of the form.
367
     *
368
     * @return string
369
     */
370 10
    public function renderFields()
371
    {
372 10
        $fields = $this->fields;
373 10
        if (!empty($this->exclude)) {
374
            $fields = array_diff_key($fields, array_flip($this->exclude));
375
        }
376
377 10
        return $this->formHelper->getView()
378 10
            ->make($this->getFieldsTemplate())
379 10
            ->with('form', $this)
380 10
            ->with('fields', $fields)
381 10
            ->render();
382
    }
383
384
    /**
385
     * Render rest of the form.
386
     *
387
     * @param bool $showFormEnd
388
     * @param bool $showFields
389
     * @return string
390
     */
391 1
    public function renderRest($showFormEnd = true, $showFields = true)
392
    {
393 1
        $fields = $this->getUnrenderedFields();
394
395 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...
396
    }
397
398
    /**
399
     * Renders the rest of the form up until the specified field name.
400
     *
401
     * @param string $field_name
402
     * @param bool   $showFormEnd
403
     * @param bool   $showFields
404
     * @return string
405
     */
406 2
    public function renderUntil($field_name, $showFormEnd = true, $showFields = true)
407
    {
408 2
        if (!$this->has($field_name)) {
409 1
            $this->fieldDoesNotExist($field_name);
410
        }
411
412 1
        $fields = $this->getUnrenderedFields();
413
414 1
        $i = 1;
415 1
        foreach ($fields as $key => $value) {
416 1
            if ($value->getRealName() == $field_name) {
417 1
                break;
418
            }
419 1
            $i++;
420
        }
421
422 1
        $fields = array_slice($fields, 0, $i, true);
423
424 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...
425
    }
426
427
    /**
428
     * Get single field instance from form object.
429
     *
430
     * @param string $name
431
     * @return FormField
432
     */
433 25
    public function getField($name)
434
    {
435 25
        if ($this->has($name)) {
436 24
            return $this->fields[$name];
437
        }
438
439 1
        $this->fieldDoesNotExist($name);
440
    }
441
442
    /**
443
     * Check if form has field.
444
     *
445
     * @param string $name
446
     * @return bool
447
     */
448 47
    public function has($name)
449
    {
450 47
        return array_key_exists($name, $this->fields);
451
    }
452
453
    /**
454
     * Get all form options.
455
     *
456
     * @return array
457
     */
458 2
    public function getFormOptions()
459
    {
460 2
        return $this->formOptions;
461
    }
462
463
    /**
464
     * Get single form option.
465
     *
466
     * @param string $option
467
     * @param mixed|null $default
468
     * @return mixed
469
     */
470 107
    public function getFormOption($option, $default = null)
471
    {
472 107
        return array_get($this->formOptions, $option, $default);
473
    }
474
475
    /**
476
     * Set single form option on form.
477
     *
478
     * @param string $option
479
     * @param mixed $value
480
     *
481
     * @return $this
482
     */
483 2
    public function setFormOption($option, $value)
484
    {
485 2
        $this->formOptions[$option] = $value;
486
487 2
        return $this;
488
    }
489
490
    /**
491
     * Set form options.
492
     *
493
     * @param array $formOptions
494
     * @return $this
495
     */
496 107
    public function setFormOptions(array $formOptions)
497
    {
498 107
        $this->formOptions = $this->formHelper->mergeOptions($this->formOptions, $formOptions);
499 107
        $this->checkIfNamedForm();
500 107
        $this->pullFromOptions('data', 'addData');
501 107
        $this->pullFromOptions('model', 'setupModel');
502 107
        $this->pullFromOptions('errors_enabled', 'setErrorsEnabled');
503 107
        $this->pullFromOptions('client_validation', 'setClientValidationEnabled');
504 107
        $this->pullFromOptions('template_prefix', 'setTemplatePrefix');
505 107
        $this->pullFromOptions('language_name', 'setLanguageName');
506
507 107
        return $this;
508
    }
509
510
    /**
511
     * Get an option from provided options and call method with that value.
512
     *
513
     * @param string $name
514
     * @param string $method
515
     */
516 107
    protected function pullFromOptions($name, $method)
517
    {
518 107
        if (array_get($this->formOptions, $name) !== null) {
519 18
            $this->{$method}(array_pull($this->formOptions, $name));
520
        }
521 107
    }
522
523
    /**
524
     * Get form http method.
525
     *
526
     * @return string
527
     */
528 3
    public function getMethod()
529
    {
530 3
        return $this->formOptions['method'];
531
    }
532
533
    /**
534
     * Set form http method.
535
     *
536
     * @param string $method
537
     * @return $this
538
     */
539 1
    public function setMethod($method)
540
    {
541 1
        $this->formOptions['method'] = $method;
542
543 1
        return $this;
544
    }
545
546
    /**
547
     * Get form action url.
548
     *
549
     * @return string
550
     */
551 3
    public function getUrl()
552
    {
553 3
        return $this->formOptions['url'];
554
    }
555
556
    /**
557
     * Set form action url.
558
     *
559
     * @param string $url
560
     * @return $this
561
     */
562 1
    public function setUrl($url)
563
    {
564 1
        $this->formOptions['url'] = $url;
565
566 1
        return $this;
567
    }
568
569
    /**
570
     * Returns the name of the form.
571
     *
572
     * @return string|null
573
     */
574 52
    public function getName()
575
    {
576 52
        return $this->name;
577
    }
578
579
    /**
580
     * Set the name of the form.
581
     *
582
     * @param string $name
583
     * @param bool $rebuild
584
     * @return $this
585
     */
586 10
    public function setName($name, $rebuild = true)
587
    {
588 10
        $this->name = $name;
589
590 10
        if ($rebuild) {
591 10
            $this->rebuildForm();
592
        }
593
594 10
        return $this;
595
    }
596
597
    /**
598
     * Get model that is bind to form object.
599
     *
600
     * @return mixed
601
     */
602 81
    public function getModel()
603
    {
604 81
        return $this->model;
605
    }
606
607
    /**
608
     * Set model to form object.
609
     *
610
     * @param mixed $model
611
     * @return $this
612
     * @deprecated deprecated since 1.6.31, will be removed in 1.7 - pass model as option when creating a form
613
     */
614 15
    public function setModel($model)
615
    {
616 15
        $this->model = $model;
617
618 15
        $this->rebuildForm();
619
620 15
        return $this;
621
    }
622
623
    /**
624
     * Setup model for form, add namespace if needed for child forms.
625
     *
626
     * @return $this
627
     */
628 12
    protected function setupModel($model)
629
    {
630 12
        $this->model = $model;
631
632 12
        return $this;
633
    }
634
635
    /**
636
     * Get all fields.
637
     *
638
     * @return FormField[]
639
     */
640 29
    public function getFields()
641
    {
642 29
        return $this->fields;
643
    }
644
645
    /**
646
     * Get field dynamically.
647
     *
648
     * @param string $name
649
     * @return FormField
650
     */
651 19
    public function __get($name)
652
    {
653 19
        if ($this->has($name)) {
654 18
            return $this->getField($name);
655
        }
656 3
    }
657
658
    /**
659
     * Check if field exists when fetched using magic methods.
660
     *
661
     * @param string $name
662
     * @return bool
663
     */
664
    public function __isset($name)
665
    {
666
        return $this->has($name);
667
    }
668
669
    /**
670
     * Set the Event Dispatcher to fire Laravel events.
671
     *
672
     * @param EventDispatcher $eventDispatcher
673
     * @return $this
674
     */
675 107
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
676
    {
677 107
        $this->eventDispatcher = $eventDispatcher;
678
679 107
        return $this;
680
    }
681
682
    /**
683
     * Set the form helper only on first instantiation.
684
     *
685
     * @param FormHelper $formHelper
686
     * @return $this
687
     */
688 107
    public function setFormHelper(FormHelper $formHelper)
689
    {
690 107
        $this->formHelper = $formHelper;
691
692 107
        return $this;
693
    }
694
695
    /**
696
     * Get form helper.
697
     *
698
     * @return FormHelper
699
     */
700 85
    public function getFormHelper()
701
    {
702 85
        return $this->formHelper;
703
    }
704
705
    /**
706
     * Add custom field.
707
     *
708
     * @param $name
709
     * @param $class
710
     */
711 2
    public function addCustomField($name, $class)
712
    {
713 2
        $this->formHelper->addCustomField($name, $class);
714 2
    }
715
716
    /**
717
     * Returns wether form errors should be shown under every field.
718
     *
719
     * @return bool
720
     */
721 85
    public function haveErrorsEnabled()
722
    {
723 85
        return $this->showFieldErrors;
724
    }
725
726
    /**
727
     * Enable or disable showing errors under fields
728
     *
729
     * @param bool $enabled
730
     * @return $this
731
     */
732 1
    public function setErrorsEnabled($enabled)
733
    {
734 1
        $this->showFieldErrors = (bool) $enabled;
735
736 1
        return $this;
737
    }
738
739
    /**
740
     * Is client validation enabled?
741
     *
742
     * @return bool
743
     */
744 21
    public function clientValidationEnabled()
745
    {
746 21
        return $this->clientValidationEnabled;
747
    }
748
749
    /**
750
     * Enable/disable client validation.
751
     *
752
     * @param bool $enable
753
     * @return $this
754
     */
755 2
    public function setClientValidationEnabled($enable)
756
    {
757 2
        $this->clientValidationEnabled = (bool) $enable;
758
759 2
        return $this;
760
    }
761
762
    /**
763
     * Add any aditional data that field needs (ex. array of choices).
764
     *
765
     * @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
766
     * will be switched to protected in 1.7.
767
     * @param string $name
768
     * @param mixed $data
769
     */
770 1
    public function setData($name, $data)
771
    {
772 1
        $this->data[$name] = $data;
773 1
    }
774
775
    /**
776
     * Get single additional data.
777
     *
778
     * @param string $name
779
     * @param null   $default
780
     * @return mixed
781
     */
782 18
    public function getData($name = null, $default = null)
783
    {
784 18
        if (is_null($name)) {
785 17
            return $this->data;
786
        }
787
788 1
        return array_get($this->data, $name, $default);
789
    }
790
791
    /**
792
     * Add multiple peices of data at once.
793
     *
794
     * @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
795
     * will be switched to protected in 1.7.
796
     * @param $data
797
     * @return $this
798
     **/
799 107
    public function addData(array $data)
800
    {
801 107
        foreach ($data as $key => $value) {
802 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...
803
        }
804
805 107
        return $this;
806
    }
807
808
    /**
809
     * Get current request.
810
     *
811
     * @return \Illuminate\Http\Request
812
     */
813 85
    public function getRequest()
814
    {
815 85
        return $this->request;
816
    }
817
818
    /**
819
     * Set request on form.
820
     *
821
     * @param Request $request
822
     * @return $this
823
     */
824 107
    public function setRequest(Request $request)
825
    {
826 107
        $this->request = $request;
827
828 107
        return $this;
829
    }
830
831
    /**
832
     * Get template prefix that is prepended to all template paths.
833
     *
834
     * @return string
835
     */
836 37
    public function getTemplatePrefix()
837
    {
838 37
        if ($this->templatePrefix !== null) {
839 4
            return $this->templatePrefix;
840
        }
841
842 33
        return $this->formHelper->getConfig('template_prefix');
843
    }
844
845
    /**
846
     * Set a template prefix for the form and its fields.
847
     *
848
     * @param string $prefix
849
     * @return $this
850
     */
851 4
    public function setTemplatePrefix($prefix)
852
    {
853 4
        $this->templatePrefix = (string) $prefix;
854
855 4
        return $this;
856
    }
857
858
    /**
859
     * Get the language name.
860
     *
861
     * @return string
862
     */
863 83
    public function getLanguageName()
864
    {
865 83
        return $this->languageName;
866
    }
867
868
    /**
869
     * Set a language name, used as prefix for translated strings.
870
     *
871
     * @param string $prefix
872
     * @return $this
873
     */
874 11
    public function setLanguageName($prefix)
875
    {
876 11
        $this->languageName = (string) $prefix;
877
878 11
        return $this;
879
    }
880
881
    /**
882
     * Render the form.
883
     *
884
     * @param array $options
885
     * @param string $fields
886
     * @param bool $showStart
887
     * @param bool $showFields
888
     * @param bool $showEnd
889
     * @return string
890
     */
891 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
892
    {
893 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
894
895 9
        $this->setupNamedModel();
896
897 9
        return $this->formHelper->getView()
898 9
            ->make($this->getTemplate())
899 9
            ->with(compact('showStart', 'showFields', 'showEnd'))
900 9
            ->with('formOptions', $formOptions)
901 9
            ->with('fields', $fields)
902 9
            ->with('model', $this->getModel())
903 9
            ->with('exclude', $this->exclude)
904 9
            ->with('form', $this)
905 9
            ->render();
906
    }
907
908
    /**
909
     * Get template from options if provided, otherwise fallback to config.
910
     *
911
     * @return mixed
912
     */
913 9
    protected function getTemplate()
914
    {
915 9
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->formHelper->getConfig('form'));
916
    }
917
918
    /**
919
     * Get fields template from options if provided, otherwise fallback to config
920
     *
921
     * @return mixed
922
     */
923 10
    protected function getFieldsTemplate()
924
    {
925 10
        return $this->getTemplatePrefix() . $this->getFormOption('fields_template', $this->formHelper->getConfig('fields'));
926
    }
927
928
    /**
929
     * Get all fields that are not rendered.
930
     *
931
     * @return array
932
     */
933 2
    protected function getUnrenderedFields()
934
    {
935 2
        $unrenderedFields = [];
936
937 2
        foreach ($this->fields as $field) {
938 2
            if (!$field->isRendered()) {
939 2
                $unrenderedFields[] = $field;
940 2
                continue;
941
            }
942
        }
943
944 2
        return $unrenderedFields;
945
    }
946
947
    /**
948
     * Prevent adding fields with same name.
949
     *
950
     * @param string $name
951
     * @throws \InvalidArgumentException
952
     * @return void
953
     */
954 47
    protected function preventDuplicate($name)
955
    {
956 47
        if ($this->has($name)) {
957 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
958
        }
959 47
    }
960
961
    /**
962
     * Returns and checks the type of the field.
963
     *
964
     * @param string $type
965
     * @return string
966
     */
967 51
    protected function getFieldType($type)
968
    {
969 51
        $fieldType = $this->formHelper->getFieldType($type);
970
971 50
        return $fieldType;
972
    }
973
974
    /**
975
     * Check if form is named form.
976
     *
977
     * @return void
978
     */
979 107
    protected function checkIfNamedForm()
980
    {
981 107
        if ($this->getFormOption('name')) {
982 8
            $this->name = array_pull($this->formOptions, 'name', $this->name);
983
        }
984 107
    }
985
986
    /**
987
     * Set up options on single field depending on form options.
988
     *
989
     * @param string $name
990
     * @param $options
991
     */
992 51
    protected function setupFieldOptions($name, &$options)
993
    {
994 51
        $options['real_name'] = $name;
995 51
    }
996
997
    /**
998
     * Set namespace to model if form is named so the data is bound properly.
999
     * Returns true if model is changed, otherwise false.
1000
     *
1001
     * @return bool
1002
     */
1003 9
    protected function setupNamedModel()
1004
    {
1005 9
        if (!$this->getModel() || !$this->getName()) {
1006 8
            return false;
1007
        }
1008
1009 1
        $dotName = $this->formHelper->transformToDotSyntax($this->getName());
1010 1
        $model = $this->formHelper->convertModelToArray($this->getModel());
1011
1012 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 1010 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...
1013 1
            $newModel = [];
1014 1
            array_set($newModel, $dotName, $model);
1015 1
            $this->model = $newModel;
1016
1017 1
            return true;
1018
        }
1019
1020
        return false;
1021
    }
1022
1023
1024
    /**
1025
     * Set form builder instance on helper so we can use it later.
1026
     *
1027
     * @param FormBuilder $formBuilder
1028
     * @return $this
1029
     */
1030 107
    public function setFormBuilder(FormBuilder $formBuilder)
1031
    {
1032 107
        $this->formBuilder = $formBuilder;
1033
1034 107
        return $this;
1035
    }
1036
1037
    /**
1038
     * Returns the instance of the FormBuilder.
1039
     *
1040
     * @return FormBuilder
1041
     */
1042 12
    public function getFormBuilder()
1043
    {
1044 12
        return $this->formBuilder;
1045
    }
1046
1047
    /**
1048
     * Set the Validator instance on this so we can use it later.
1049
     *
1050
     * @param ValidatorFactory $validator
1051
     * @return $this
1052
     */
1053 107
    public function setValidator(ValidatorFactory $validator)
1054
    {
1055 107
        $this->validatorFactory = $validator;
1056
1057 107
        return $this;
1058
    }
1059
1060
    /**
1061
     * Returns the validator instance.
1062
     *
1063
     * @return Validator
1064
     */
1065 1
    public function getValidator()
1066
    {
1067 1
        return $this->validator;
1068
    }
1069
1070
    /**
1071
     * Exclude some fields from rendering.
1072
     *
1073
     * @return $this
1074
     */
1075
    public function exclude(array $fields)
1076
    {
1077
        $this->exclude = array_merge($this->exclude, $fields);
1078
1079
        return $this;
1080
    }
1081
1082
1083
    /**
1084
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1085
     *
1086
     * @param string $name
1087
     * @return string
1088
     */
1089 51
    protected function getFieldName($name)
1090
    {
1091 51
        $formName = $this->getName();
1092 51
        if ($formName !== null) {
1093 14
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1094 6
                return $this->formHelper->transformToBracketSyntax(
1095 6
                    $this->formHelper->transformToDotSyntax(
1096 6
                        $formName . '[' . $name . ']'
1097
                    )
1098
                );
1099
            }
1100
1101 11
            return $formName . '[' . $name . ']';
1102
        }
1103
1104 51
        return $name;
1105
    }
1106
1107
    /**
1108
     * Disable all fields in a form.
1109
     */
1110 1
    public function disableFields()
1111
    {
1112 1
        foreach ($this->fields as $field) {
1113 1
            $field->disable();
1114
        }
1115 1
    }
1116
1117
    /**
1118
     * Enable all fields in a form.
1119
     */
1120 1
    public function enableFields()
1121
    {
1122 1
        foreach ($this->fields as $field) {
1123 1
            $field->enable();
1124
        }
1125 1
    }
1126
1127
    /**
1128
     * Validate the form.
1129
     *
1130
     * @param array $validationRules
1131
     * @param array $messages
1132
     * @return Validator
1133
     */
1134 8
    public function validate($validationRules = [], $messages = [])
1135
    {
1136 8
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1137 8
        $rules = array_merge($fieldRules['rules'], $validationRules);
1138 8
        $messages = array_merge($fieldRules['error_messages'], $messages);
1139
1140 8
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1141 8
        $this->validator->setAttributeNames($fieldRules['attributes']);
1142
1143 8
        $this->eventDispatcher->fire(new BeforeFormValidation($this, $this->validator));
1144
1145 8
        return $this->validator;
1146
    }
1147
1148
    /**
1149
     * Get validation rules for the form.
1150
     *
1151
     * @param array $overrideRules
1152
     * @return array
1153
     */
1154 1
    public function getRules($overrideRules = [])
1155
    {
1156 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1157
1158 1
        return array_merge($fieldRules['rules'], $overrideRules);
1159
    }
1160
1161
    /**
1162
     * Redirects to a destination when form is invalid.
1163
     *
1164
     * @param  string|null $destination The target url.
1165
     * @return HttpResponseException
1166
     */
1167 2
    public function redirectIfNotValid($destination = null)
1168
    {
1169 2
        if (! $this->isValid()) {
1170 2
            $response = redirect($destination);
1171
1172 2
            if (is_null($destination)) {
1173 1
                $response = $response->back();
1174
            }
1175
1176 2
            $response = $response->withErrors($this->getErrors())->withInput();
1177
1178 2
            throw new HttpResponseException($response);
1179
        }
1180
    }
1181
1182
    /**
1183
     * Get all form field attributes, including child forms, in a flat array.
1184
     *
1185
     * @return array
1186
     */
1187 3
    public function getAllAttributes()
1188
    {
1189 3
        return $this->formHelper->mergeAttributes($this->fields);
1190
    }
1191
1192
    /**
1193
     * Check if the form is valid.
1194
     *
1195
     * @return bool
1196
     */
1197 8
    public function isValid()
1198
    {
1199 8
        if (!$this->validator) {
1200 7
            $this->validate();
1201
        }
1202
1203 8
        $isValid = !$this->validator->fails();
1204
1205 8
        $this->formHelper->alterValid($this, $this, $isValid);
1206
1207 8
        $this->eventDispatcher->fire(new AfterFormValidation($this, $this->validator, $isValid));
1208
1209 8
        return $isValid;
1210
    }
1211
1212
    /**
1213
     * Optionally change the validation result, and/or add error messages.
1214
     *
1215
     * @param Form $mainForm
1216
     * @param bool $isValid
1217
     * @return void|array
1218
     */
1219 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...
1220
    {
1221
        // return ['name' => ['Some other error about the Name field.']];
1222 8
    }
1223
1224
    /**
1225
     * Get validation errors.
1226
     *
1227
     * @return array
1228
     */
1229 7
    public function getErrors()
1230
    {
1231 7
        if (!$this->validator || !$this->validator instanceof Validator) {
1232 1
            throw new \InvalidArgumentException(
1233
                sprintf(
1234 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1235
                    get_class($this)
1236
                )
1237
            );
1238
        }
1239
1240 6
        return $this->validator->getMessageBag()->getMessages();
1241
    }
1242
1243
    /**
1244
     * Get all Request values from all fields, and nothing else.
1245
     *
1246
     * @param bool $with_nulls
1247
     * @return array
1248
     */
1249 3
    public function getFieldValues($with_nulls = true)
1250
    {
1251 3
        $request_values = $this->getRequest()->all();
1252
1253 3
        $values = [];
1254 3
        foreach ($this->getAllAttributes() as $attribute) {
1255 3
            $value = Arr::get($request_values, $attribute);
1256 3
            if ($with_nulls || $value !== null) {
1257 3
                Arr::set($values, $attribute, $value);
1258
            }
1259
        }
1260
1261
        // If this form is a child form, cherry pick a part
1262 3
        if ($prefix = $this->getName()) {
1263 1
            $prefix = $this->formHelper->transformToDotSyntax($prefix);
1264 1
            $values = Arr::get($values, $prefix);
1265
        }
1266
1267
        // Allow form-specific value alters
1268 3
        $this->formHelper->alterFieldValues($this, $values);
1269
1270 3
        return $values;
1271
    }
1272
1273
    /**
1274
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1275
     *
1276
     * @param array $values
1277
     * @return void
1278
     */
1279 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...
1280
    {
1281 3
    }
1282
1283
    /**
1284
     * Throw an exception indicating a field does not exist on the class.
1285
     *
1286
     * @param string $name
1287
     * @throws \InvalidArgumentException
1288
     * @return void
1289
     */
1290 2
    protected function fieldDoesNotExist($name)
1291
    {
1292 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1293
    }
1294
}
1295