Completed
Pull Request — master (#348)
by
unknown
04:42
created

Form::hasCustom()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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