Completed
Pull Request — master (#574)
by
unknown
03:03
created

Form::add()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 4
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
ccs 5
cts 6
cp 0.8333
crap 3.0416
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
use Kris\LaravelFormBuilder\Filters\FilterResolver;
16
17
class Form
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
     * Form specific configuration.
55
     *
56
     * @var array
57
     */
58
    protected $formConfig = [];
59
60
    /**
61
     * Additional data which can be used to build fields.
62
     *
63
     * @var array
64
     */
65
    protected $data = [];
66
67
    /**
68
     * Wether errors for each field should be shown when calling form($form) or form_rest($form).
69
     *
70
     * @var bool
71
     */
72
    protected $showFieldErrors = true;
73
74
    /**
75
     * Enable html5 validation.
76
     *
77
     * @var bool
78
     */
79
    protected $clientValidationEnabled = true;
80
81
    /**
82
     * Name of the parent form if any.
83
     *
84
     * @var string|null
85
     */
86
    protected $name = null;
87
88
    /**
89
     * @var FormBuilder
90
     */
91
    protected $formBuilder;
92
93
    /**
94
     * @var ValidatorFactory
95
     */
96
    protected $validatorFactory;
97
98
    /**
99
     * @var Validator
100
     */
101
    protected $validator = null;
102
103
    /**
104
     * @var Request
105
     */
106
    protected $request;
107
108
    /**
109
     * List of fields to not render.
110
     *
111
     * @var array
112
     **/
113
    protected $exclude = [];
114
115
    /**
116
     * Wether the form is beign rebuild.
117
     *
118
     * @var bool
119
     */
120
    protected $rebuilding = false;
121
122
    /**
123
     * @var string
124
     */
125
    protected $templatePrefix;
126
127
    /**
128
     * @var string
129
     */
130
    protected $languageName;
131
132
    /**
133
     * @var string
134
     */
135
    protected $translationTemplate;
136
137
    /**
138
     * To filter and mutate request values or not.
139
     *
140
     * @var bool
141
     */
142
    protected $lockFiltering = false;
143
144
    /**
145
     * Define the error bag name for the form.
146
     *
147
     * @var string
148
     */
149
    protected $errorBag = 'default';
150
151
    /**
152
     * Build the form.
153
     *
154
     * @return mixed
155
     */
156 3
    public function buildForm()
157
    {
158 3
    }
159
160
    /**
161
     * Rebuild the form from scratch.
162
     *
163
     * @return $this
164
     */
165 19
    public function rebuildForm()
166
    {
167 19
        $this->rebuilding = true;
168
        // If form is plain, buildForm method is empty, so we need to take
169
        // existing fields and add them again
170 19
        if (get_class($this) === 'Kris\LaravelFormBuilder\Form') {
171 18
            foreach ($this->fields as $name => $field) {
172
                // Remove any temp variables added in previous instance
173 7
                $options =  Arr::except($field->getOptions(), 'tmp');
174 18
                $this->add($name, $field->getType(), $options);
175
            }
176
        } else {
177 3
            $this->buildForm();
178
        }
179 19
        $this->rebuilding = false;
180
181 19
        return $this;
182
    }
183
184
    /**
185
     * Create the FormField object.
186
     *
187
     * @param string $name
188
     * @param string $type
189
     * @param array  $options
190
     * @return FormField
191
     */
192 65
    protected function makeField($name, $type = 'text', array $options = [])
193
    {
194 65
        $this->setupFieldOptions($name, $options);
195
196 65
        $fieldName = $this->getFieldName($name);
197
198 65
        $fieldType = $this->getFieldType($type);
199
200 64
        $field = new $fieldType($fieldName, $type, $this, $options);
201
202 61
        $this->eventDispatcher->dispatch(new AfterFieldCreation($this, $field));
203
204 61
        return $field;
205
    }
206
207
    /**
208
     * Create a new field and add it to the form.
209
     *
210
     * @param string $name
211
     * @param string $type
212
     * @param array  $options
213
     * @param bool   $modify
214
     * @return $this
215
     */
216 67
    public function add($name, $type = 'text', array $options = [], $modify = false)
217
    {
218 67
        $this->formHelper->checkFieldName($name, get_class($this));
219
220 65
        if ($this->rebuilding && !$this->has($name)) {
221
            return $this;
222
        }
223
224 65
        $this->addField($this->makeField($name, $type, $options), $modify);
225
226 61
        return $this;
227
    }
228
229
    /**
230
     * Add a FormField to the form's fields.
231
     *
232
     * @param FormField $field
233
     * @return $this
234
     */
235 61
    protected function addField(FormField $field, $modify = false)
236
    {
237 61
        if (!$modify && !$this->rebuilding) {
238 61
            $this->preventDuplicate($field->getRealName());
239
        }
240
241
242 61
        if ($field->getType() == 'file') {
243 3
            $this->formOptions['files'] = true;
244
        }
245
246 61
        $this->fields[$field->getRealName()] = $field;
247
248 61
        return $this;
249
    }
250
251
    /**
252
     * Add field before another field.
253
     *
254
     * @param string  $name         Name of the field before 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 addBefore($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);
266 1
        $afterFields = array_slice($this->fields, $offset);
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
     * Add field before another field.
279
     *
280
     * @param string  $name         Name of the field after which new field is added.
281
     * @param string  $fieldName    Field name which will be added.
282
     * @param string  $type
283
     * @param array   $options
284
     * @param bool $modify
285
     * @return $this
286
     */
287 1
    public function addAfter($name, $fieldName, $type = 'text', $options = [], $modify = false)
288
    {
289 1
        $offset = array_search($name, array_keys($this->fields));
290
291 1
        $beforeFields = array_slice($this->fields, 0, $offset + 1);
292 1
        $afterFields = array_slice($this->fields, $offset + 1);
293
294 1
        $this->fields = $beforeFields;
295
296 1
        $this->add($fieldName, $type, $options, $modify);
297
298 1
        $this->fields += $afterFields;
299
300 1
        return $this;
301
    }
302
303
    /**
304
     * Take another form and add it's fields directly to this form.
305
     *
306
     * @param mixed   $class        Form to merge.
307
     * @param array   $options
308
     * @param boolean $modify
309
     * @return $this
310
     */
311 1
    public function compose($class, array $options = [], $modify = false)
312
    {
313 1
        $options['class'] = $class;
314
315
        // If we pass a ready made form just extract the fields.
316 1
        if ($class instanceof Form) {
317 1
            $fields = $class->getFields();
318
        } elseif ($class instanceof Fields\ChildFormType) {
319
            $fields = $class->getForm()->getFields();
320
        } elseif (is_string($class)) {
321
            // If its a string of a class make it the usual way.
322
            $options['model'] = $this->model;
323
            $options['name'] = $this->name;
324
325
            $form = $this->formBuilder->create($class, $options);
326
            $fields = $form->getFields();
327
        } else {
328
            throw new \InvalidArgumentException(
329
                "[{$class}] is invalid. Please provide either a full class name, Form or ChildFormType"
330
            );
331
        }
332
333 1
        foreach ($fields as $field) {
334 1
            $this->addField($field, $modify);
335
        }
336
337 1
        return $this;
338
    }
339
340
    /**
341
     * Remove field with specified name from the form.
342
     *
343
     * @param string|string[] $names
344
     * @return $this
345
     */
346 2
    public function remove($names)
347
    {
348 2
        foreach (is_array($names) ? $names : func_get_args() as $name) {
349 2
            if ($this->has($name)) {
350 2
                unset($this->fields[$name]);
351
            }
352
        }
353
354 2
        return $this;
355
    }
356
357
    /**
358
     * Modify existing field. If it doesn't exist, it is added to form.
359
     *
360
     * @param string $name
361
     * @param string $type
362
     * @param array  $options
363
     * @param bool   $overwriteOptions
364
     * @return Form
365
     */
366 1
    public function modify($name, $type = 'text', array $options = [], $overwriteOptions = false)
367
    {
368
        // If we don't want to overwrite options, we merge them with old options.
369 1
        if ($overwriteOptions === false && $this->has($name)) {
370 1
            $options = $this->formHelper->mergeOptions(
371 1
                $this->getField($name)->getOptions(),
372 1
                $options
373
            );
374
        }
375
376 1
        return $this->add($name, $type, $options, true);
377
    }
378
379
    /**
380
     * Render full form.
381
     *
382
     * @param array $options
383
     * @param bool  $showStart
384
     * @param bool  $showFields
385
     * @param bool  $showEnd
386
     * @return string
387
     */
388 7
    public function renderForm(array $options = [], $showStart = true, $showFields = true, $showEnd = true)
389
    {
390 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...
391
    }
392
393
    /**
394
     * Render rest of the form.
395
     *
396
     * @param bool $showFormEnd
397
     * @param bool $showFields
398
     * @return string
399
     */
400 1
    public function renderRest($showFormEnd = true, $showFields = true)
401
    {
402 1
        $fields = $this->getUnrenderedFields();
403
404 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...
405
    }
406
407
    /**
408
     * Renders the rest of the form up until the specified field name.
409
     *
410
     * @param string $field_name
411
     * @param bool   $showFormEnd
412
     * @param bool   $showFields
413
     * @return string
414
     */
415 2
    public function renderUntil($field_name, $showFormEnd = true, $showFields = true)
416
    {
417 2
        if (!$this->has($field_name)) {
418 1
            $this->fieldDoesNotExist($field_name);
419
        }
420
421 1
        $fields = $this->getUnrenderedFields();
422
423 1
        $i = 1;
424 1
        foreach ($fields as $key => $value) {
425 1
            if ($value->getRealName() == $field_name) {
426 1
                break;
427
            }
428 1
            $i++;
429
        }
430
431 1
        $fields = array_slice($fields, 0, $i, true);
432
433 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...
434
    }
435
436
    /**
437
     * Get single field instance from form object.
438
     *
439
     * @param string $name
440
     * @return FormField
441
     */
442 35
    public function getField($name)
443
    {
444 35
        if ($this->has($name)) {
445 34
            return $this->fields[$name];
446
        }
447
448 1
        $this->fieldDoesNotExist($name);
449
    }
450
451 101
    public function getErrorBag()
452
    {
453 101
        return $this->errorBag;
454
    }
455
456
    /**
457
     * Check if form has field.
458
     *
459
     * @param string $name
460
     * @return bool
461
     */
462 61
    public function has($name)
463
    {
464 61
        return array_key_exists($name, $this->fields);
465
    }
466
467
    /**
468
     * Get all form options.
469
     *
470
     * @return array
471
     */
472 2
    public function getFormOptions()
473
    {
474 2
        return $this->formOptions;
475
    }
476
477
    /**
478
     * Get single form option.
479
     *
480
     * @param string $option
481
     * @param mixed|null $default
482
     * @return mixed
483
     */
484 129
    public function getFormOption($option, $default = null)
485
    {
486 129
        return Arr::get($this->formOptions, $option, $default);
487
    }
488
489
    /**
490
     * Set single form option on form.
491
     *
492
     * @param string $option
493
     * @param mixed $value
494
     *
495
     * @return $this
496
     */
497 2
    public function setFormOption($option, $value)
498
    {
499 2
        $this->formOptions[$option] = $value;
500
501 2
        return $this;
502
    }
503
504
    /**
505
     * Get the passed config key using the custom
506
     * form config, if any.
507
     *
508
     * @param string $key
509
     * @param mixed $default
510
     *
511
     * @return mixed
512
     */
513 103
    public function getConfig($key = null, $default = null)
514
    {
515 103
        return $this->formHelper->getConfig($key, $default, $this->formConfig);
516
    }
517
518
    /**
519
     * Set form options.
520
     *
521
     * @param array $formOptions
522
     * @return $this
523
     */
524 129
    public function setFormOptions(array $formOptions)
525
    {
526 129
        $this->formOptions = $this->formHelper->mergeOptions($this->formOptions, $formOptions);
527 129
        $this->checkIfNamedForm();
528 129
        $this->pullFromOptions('data', 'addData');
529 129
        $this->pullFromOptions('model', 'setupModel');
530 129
        $this->pullFromOptions('errors_enabled', 'setErrorsEnabled');
531 129
        $this->pullFromOptions('client_validation', 'setClientValidationEnabled');
532 129
        $this->pullFromOptions('template_prefix', 'setTemplatePrefix');
533 129
        $this->pullFromOptions('language_name', 'setLanguageName');
534 129
        $this->pullFromOptions('translation_template', 'setTranslationTemplate');
535
536 129
        return $this;
537
    }
538
539
    /**
540
     * Get an option from provided options and call method with that value.
541
     *
542
     * @param string $name
543
     * @param string $method
544
     */
545 129
    protected function pullFromOptions($name, $method)
546
    {
547 129
        if (Arr::get($this->formOptions, $name) !== null) {
548 20
            $this->{$method}(Arr::pull($this->formOptions, $name));
549
        }
550 129
    }
551
552
    /**
553
     * Get form http method.
554
     *
555
     * @return string
556
     */
557 3
    public function getMethod()
558
    {
559 3
        return $this->formOptions['method'];
560
    }
561
562
    /**
563
     * Set form http method.
564
     *
565
     * @param string $method
566
     * @return $this
567
     */
568 1
    public function setMethod($method)
569
    {
570 1
        $this->formOptions['method'] = $method;
571
572 1
        return $this;
573
    }
574
575
    /**
576
     * Get form action url.
577
     *
578
     * @return string
579
     */
580 3
    public function getUrl()
581
    {
582 3
        return $this->formOptions['url'];
583
    }
584
585
    /**
586
     * Set form action url.
587
     *
588
     * @param string $url
589
     * @return $this
590
     */
591 1
    public function setUrl($url)
592
    {
593 1
        $this->formOptions['url'] = $url;
594
595 1
        return $this;
596
    }
597
598
    /**
599
     * Returns the name of the form.
600
     *
601
     * @return string|null
602
     */
603 69
    public function getName()
604
    {
605 69
        return $this->name;
606
    }
607
608
    /**
609
     * Set the name of the form.
610
     *
611
     * @param string $name
612
     * @param bool $rebuild
613
     * @return $this
614
     */
615 12
    public function setName($name, $rebuild = true)
616
    {
617 12
        $this->name = $name;
618
619 12
        if ($rebuild) {
620 12
            $this->rebuildForm();
621
        }
622
623 12
        return $this;
624
    }
625
626
    /**
627
     * Get model that is bind to form object.
628
     *
629
     * @return mixed
630
     */
631 96
    public function getModel()
632
    {
633 96
        return $this->model;
634
    }
635
636
    /**
637
     * Set model to form object.
638
     *
639
     * @param mixed $model
640
     * @return $this
641
     * @deprecated deprecated since 1.6.31, will be removed in 1.7 - pass model as option when creating a form
642
     */
643 17
    public function setModel($model)
644
    {
645 17
        $this->model = $model;
646
647 17
        $this->rebuildForm();
648
649 17
        return $this;
650
    }
651
652
    /**
653
     * Setup model for form, add namespace if needed for child forms.
654
     *
655
     * @return $this
656
     */
657 12
    protected function setupModel($model)
658
    {
659 12
        $this->model = $model;
660 12
        $this->setupNamedModel();
661
662 12
        return $this;
663
    }
664
665
    /**
666
     * Get all fields.
667
     *
668
     * @return FormField[]
669
     */
670 129
    public function getFields()
671
    {
672 129
        return $this->fields;
673
    }
674
675
    /**
676
     * Get field dynamically.
677
     *
678
     * @param string $name
679
     * @return FormField
680
     */
681 20
    public function __get($name)
682
    {
683 20
        if ($this->has($name)) {
684 19
            return $this->getField($name);
685
        }
686 3
    }
687
688
    /**
689
     * Check if field exists when fetched using magic methods.
690
     *
691
     * @param string $name
692
     * @return bool
693
     */
694
    public function __isset($name)
695
    {
696
        return $this->has($name);
697
    }
698
699
    /**
700
     * Set the Event Dispatcher to fire Laravel events.
701
     *
702
     * @param EventDispatcher $eventDispatcher
703
     * @return $this
704
     */
705 129
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
706
    {
707 129
        $this->eventDispatcher = $eventDispatcher;
708
709 129
        return $this;
710
    }
711
712
    /**
713
     * Set the form helper only on first instantiation.
714
     *
715
     * @param FormHelper $formHelper
716
     * @return $this
717
     */
718 129
    public function setFormHelper(FormHelper $formHelper)
719
    {
720 129
        $this->formHelper = $formHelper;
721
722 129
        return $this;
723
    }
724
725
    /**
726
     * Get form helper.
727
     *
728
     * @return FormHelper
729
     */
730 101
    public function getFormHelper()
731
    {
732 101
        return $this->formHelper;
733
    }
734
735
    /**
736
     * Add custom field.
737
     *
738
     * @param $name
739
     * @param $class
740
     */
741 2
    public function addCustomField($name, $class)
742
    {
743 2
        if ($this->rebuilding && $this->formHelper->hasCustomField($name)) {
744
            return $this;
745
        }
746
747 2
        $this->formHelper->addCustomField($name, $class);
748 2
    }
749
750
    /**
751
     * Returns wether form errors should be shown under every field.
752
     *
753
     * @return bool
754
     */
755 101
    public function haveErrorsEnabled()
756
    {
757 101
        return $this->showFieldErrors;
758
    }
759
760
    /**
761
     * Enable or disable showing errors under fields
762
     *
763
     * @param bool $enabled
764
     * @return $this
765
     */
766 1
    public function setErrorsEnabled($enabled)
767
    {
768 1
        $this->showFieldErrors = (bool) $enabled;
769
770 1
        return $this;
771
    }
772
773
    /**
774
     * Is client validation enabled?
775
     *
776
     * @return bool
777
     */
778 101
    public function clientValidationEnabled()
779
    {
780 101
        return $this->clientValidationEnabled;
781
    }
782
783
    /**
784
     * Enable/disable client validation.
785
     *
786
     * @param bool $enable
787
     * @return $this
788
     */
789 2
    public function setClientValidationEnabled($enable)
790
    {
791 2
        $this->clientValidationEnabled = (bool) $enable;
792
793 2
        return $this;
794
    }
795
796
    /**
797
     * Add any aditional data that field needs (ex. array of choices).
798
     *
799
     * @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
800
     * will be switched to protected in 1.7.
801
     * @param string $name
802
     * @param mixed $data
803
     */
804 1
    public function setData($name, $data)
805
    {
806 1
        $this->data[$name] = $data;
807 1
    }
808
809
    /**
810
     * Get single additional data.
811
     *
812
     * @param string $name
813
     * @param null   $default
814
     * @return mixed
815
     */
816 20
    public function getData($name = null, $default = null)
817
    {
818 20
        if (is_null($name)) {
819 19
            return $this->data;
820
        }
821
822 1
        return Arr::get($this->data, $name, $default);
823
    }
824
825
    /**
826
     * Add multiple peices of data at once.
827
     *
828
     * @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
829
     * will be switched to protected in 1.7.
830
     * @param $data
831
     * @return $this
832
     **/
833 129
    public function addData(array $data)
834
    {
835 129
        foreach ($data as $key => $value) {
836 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...
837
        }
838
839 129
        return $this;
840
    }
841
842
    /**
843
     * Get current request.
844
     *
845
     * @return \Illuminate\Http\Request
846
     */
847 101
    public function getRequest()
848
    {
849 101
        return $this->request;
850
    }
851
852
    /**
853
     * Set request on form.
854
     *
855
     * @param Request $request
856
     * @return $this
857
     */
858 129
    public function setRequest(Request $request)
859
    {
860 129
        $this->request = $request;
861
862 129
        return $this;
863
    }
864
865
    /**
866
     * Get template prefix that is prepended to all template paths.
867
     *
868
     * @return string
869
     */
870 39
    public function getTemplatePrefix()
871
    {
872 39
        if ($this->templatePrefix !== null) {
873 4
            return $this->templatePrefix;
874
        }
875
876 35
        return $this->getConfig('template_prefix');
877
    }
878
879
    /**
880
     * Set a template prefix for the form and its fields.
881
     *
882
     * @param string $prefix
883
     * @return $this
884
     */
885 4
    public function setTemplatePrefix($prefix)
886
    {
887 4
        $this->templatePrefix = (string) $prefix;
888
889 4
        return $this;
890
    }
891
892
    /**
893
     * Get the language name.
894
     *
895
     * @return string
896
     */
897 98
    public function getLanguageName()
898
    {
899 98
        return $this->languageName;
900
    }
901
902
    /**
903
     * Set a language name, used as prefix for translated strings.
904
     *
905
     * @param string $prefix
906
     * @return $this
907
     */
908 13
    public function setLanguageName($prefix)
909
    {
910 13
        $this->languageName = (string) $prefix;
911
912 13
        return $this;
913
    }
914
915
    /**
916
     * Get the translation template.
917
     *
918
     * @return string
919
     */
920 100
    public function getTranslationTemplate()
921
    {
922 100
        return $this->translationTemplate;
923
    }
924
925
    /**
926
     * Set a translation template, used to determine labels for fields.
927
     *
928
     * @param string $template
929
     * @return $this
930
     */
931 11
    public function setTranslationTemplate($template)
932
    {
933 11
        $this->translationTemplate = (string) $template;
934
935 11
        return $this;
936
    }
937
938
    /**
939
     * Render the form.
940
     *
941
     * @param array $options
942
     * @param string $fields
943
     * @param bool $showStart
944
     * @param bool $showFields
945
     * @param bool $showEnd
946
     * @return string
947
     */
948 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
949
    {
950 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
951
952 9
        $this->setupNamedModel();
953
954 9
        return $this->formHelper->getView()
955 9
            ->make($this->getTemplate())
956 9
            ->with(compact('showStart', 'showFields', 'showEnd'))
957 9
            ->with('formOptions', $formOptions)
958 9
            ->with('fields', $fields)
959 9
            ->with('model', $this->getModel())
960 9
            ->with('exclude', $this->exclude)
961 9
            ->with('form', $this)
962 9
            ->render();
963
    }
964
965
    /**
966
     * Get template from options if provided, otherwise fallback to config.
967
     *
968
     * @return mixed
969
     */
970 9
    protected function getTemplate()
971
    {
972 9
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->getConfig('form'));
973
    }
974
975
    /**
976
     * Get all fields that are not rendered.
977
     *
978
     * @return array
979
     */
980 2
    protected function getUnrenderedFields()
981
    {
982 2
        $unrenderedFields = [];
983
984 2
        foreach ($this->fields as $field) {
985 2
            if (!$field->isRendered()) {
986 2
                $unrenderedFields[] = $field;
987 2
                continue;
988
            }
989
        }
990
991 2
        return $unrenderedFields;
992
    }
993
994
    /**
995
     * Prevent adding fields with same name.
996
     *
997
     * @param string $name
998
     * @throws \InvalidArgumentException
999
     * @return void
1000
     */
1001 61
    protected function preventDuplicate($name)
1002
    {
1003 61
        if ($this->has($name)) {
1004 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
1005
        }
1006 61
    }
1007
1008
    /**
1009
     * Returns and checks the type of the field.
1010
     *
1011
     * @param string $type
1012
     * @return string
1013
     */
1014 65
    protected function getFieldType($type)
1015
    {
1016 65
        $fieldType = $this->formHelper->getFieldType($type);
1017
1018 64
        return $fieldType;
1019
    }
1020
1021
    /**
1022
     * Check if form is named form.
1023
     *
1024
     * @return void
1025
     */
1026 129
    protected function checkIfNamedForm()
1027
    {
1028 129
        if ($this->getFormOption('name')) {
1029 8
            $this->name = Arr::pull($this->formOptions, 'name', $this->name);
1030
        }
1031 129
    }
1032
1033
    /**
1034
     * Set up options on single field depending on form options.
1035
     *
1036
     * @param string $name
1037
     * @param $options
1038
     */
1039 65
    protected function setupFieldOptions($name, &$options)
1040
    {
1041 65
        $options['real_name'] = $name;
1042 65
    }
1043
1044
    /**
1045
     * Set namespace to model if form is named so the data is bound properly.
1046
     * Returns true if model is changed, otherwise false.
1047
     *
1048
     * @return bool
1049
     */
1050 21
    protected function setupNamedModel()
1051
    {
1052 21
        if (!$this->getModel() || !$this->getName()) {
1053 19
            return false;
1054
        }
1055
1056 3
        $dotName = $this->formHelper->transformToDotSyntax($this->getName());
1057 3
        $model = $this->formHelper->convertModelToArray($this->getModel());
1058 3
        $isCollectionFormModel = (bool) preg_match('/^.*\.\d+$/', $dotName);
1059 3
        $isCollectionPrototype = strpos($dotName, '__NAME__') !== false;
1060
1061 3
        if (!Arr::get($model, $dotName) && !$isCollectionFormModel && !$isCollectionPrototype) {
0 ignored issues
show
Bug introduced by
It seems like $model defined by $this->formHelper->conve...rray($this->getModel()) on line 1057 can also be of type null or object; however, Illuminate\Support\Arr::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...
1062 1
            $newModel = [];
1063 1
            Arr::set($newModel, $dotName, $model);
1064 1
            $this->model = $newModel;
1065
1066 1
            return true;
1067
        }
1068
1069 2
        return false;
1070
    }
1071
1072
    /**
1073
     * Set form builder instance on helper so we can use it later.
1074
     *
1075
     * @param FormBuilder $formBuilder
1076
     * @return $this
1077
     */
1078 129
    public function setFormBuilder(FormBuilder $formBuilder)
1079
    {
1080 129
        $this->formBuilder = $formBuilder;
1081
1082 129
        return $this;
1083
    }
1084
1085
    /**
1086
     * Returns the instance of the FormBuilder.
1087
     *
1088
     * @return FormBuilder
1089
     */
1090 20
    public function getFormBuilder()
1091
    {
1092 20
        return $this->formBuilder;
1093
    }
1094
1095
    /**
1096
     * Set the Validator instance on this so we can use it later.
1097
     *
1098
     * @param ValidatorFactory $validator
1099
     * @return $this
1100
     */
1101 129
    public function setValidator(ValidatorFactory $validator)
1102
    {
1103 129
        $this->validatorFactory = $validator;
1104
1105 129
        return $this;
1106
    }
1107
1108
    /**
1109
     * Returns the validator instance.
1110
     *
1111
     * @return Validator
1112
     */
1113 1
    public function getValidator()
1114
    {
1115 1
        return $this->validator;
1116
    }
1117
1118
    /**
1119
     * Exclude some fields from rendering.
1120
     *
1121
     * @return $this
1122
     */
1123
    public function exclude(array $fields)
1124
    {
1125
        $this->exclude = array_merge($this->exclude, $fields);
1126
1127
        return $this;
1128
    }
1129
1130
    /**
1131
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1132
     *
1133
     * @param string $name
1134
     * @return string
1135
     */
1136 65
    protected function getFieldName($name)
1137
    {
1138 65
        $formName = $this->getName();
1139 65
        if ($formName !== null) {
1140 14
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1141 6
                return $this->formHelper->transformToBracketSyntax(
1142 6
                    $this->formHelper->transformToDotSyntax(
1143 6
                        $formName . '[' . $name . ']'
1144
                    )
1145
                );
1146
            }
1147
1148 11
            return $formName . '[' . $name . ']';
1149
        }
1150
1151 65
        return $name;
1152
    }
1153
1154
    /**
1155
     * Disable all fields in a form.
1156
     */
1157 1
    public function disableFields()
1158
    {
1159 1
        foreach ($this->fields as $field) {
1160 1
            $field->disable();
1161
        }
1162 1
    }
1163
1164
    /**
1165
     * Enable all fields in a form.
1166
     */
1167 1
    public function enableFields()
1168
    {
1169 1
        foreach ($this->fields as $field) {
1170 1
            $field->enable();
1171
        }
1172 1
    }
1173
1174
    /**
1175
     * Validate the form.
1176
     *
1177
     * @param array $validationRules
1178
     * @param array $messages
1179
     * @return Validator
1180
     */
1181 9
    public function validate($validationRules = [], $messages = [])
1182
    {
1183 9
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1184 9
        $rules = array_merge($fieldRules->getRules(), $validationRules);
1185 9
        $messages = array_merge($fieldRules->getMessages(), $messages);
1186
1187 9
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1188 9
        $this->validator->setAttributeNames($fieldRules->getAttributes());
1189
1190 9
        $this->eventDispatcher->dispatch(new BeforeFormValidation($this, $this->validator));
1191
1192 9
        return $this->validator;
1193
    }
1194
1195
    /**
1196
     * Get validation rules for the form.
1197
     *
1198
     * @param array $overrideRules
1199
     * @return array
1200
     */
1201 1
    public function getRules($overrideRules = [])
1202
    {
1203 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1204
1205 1
        return array_merge($fieldRules->getRules(), $overrideRules);
1206
    }
1207
1208
    /**
1209
     * Redirects to a destination when form is invalid.
1210
     *
1211
     * @param  string|null $destination The target url.
1212
     * @return HttpResponseException
1213
     */
1214 3
    public function redirectIfNotValid($destination = null)
1215
    {
1216 3
        if (! $this->isValid()) {
1217 3
            $response = redirect($destination);
1218
1219 3
            if (is_null($destination)) {
1220 2
                $response = $response->back();
1221
            }
1222
1223 3
            $response = $response->withErrors($this->getErrors(), $this->getErrorBag())->withInput();
1224
1225 3
            throw new HttpResponseException($response);
1226
        }
1227
    }
1228
1229
    /**
1230
     * Get all form field attributes, including child forms, in a flat array.
1231
     *
1232
     * @return array
1233
     */
1234 3
    public function getAllAttributes()
1235
    {
1236 3
        return $this->formHelper->mergeAttributes($this->fields);
1237
    }
1238
1239
    /**
1240
     * Check if the form is valid.
1241
     *
1242
     * @return bool
1243
     */
1244 9
    public function isValid()
1245
    {
1246 9
        if (!$this->validator) {
1247 8
            $this->validate();
1248
        }
1249
1250 9
        $isValid = !$this->validator->fails();
1251
1252 9
        $this->formHelper->alterValid($this, $this, $isValid);
1253
1254 9
        $this->eventDispatcher->dispatch(new AfterFormValidation($this, $this->validator, $isValid));
1255
1256 9
        return $isValid;
1257
    }
1258
1259
    /**
1260
     * Optionally change the validation result, and/or add error messages.
1261
     *
1262
     * @param Form $mainForm
1263
     * @param bool $isValid
1264
     * @return void|array
1265
     */
1266 9
    public function alterValid(Form $mainForm, &$isValid)
0 ignored issues
show
Unused Code introduced by
The parameter $mainForm is not used and could be removed.

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

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

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

Loading history...
1267
    {
1268
        // return ['name' => ['Some other error about the Name field.']];
1269 9
    }
1270
1271
    /**
1272
     * Get validation errors.
1273
     *
1274
     * @return array
1275
     */
1276 8
    public function getErrors()
1277
    {
1278 8
        if (!$this->validator || !$this->validator instanceof Validator) {
1279 1
            throw new \InvalidArgumentException(
1280 1
                sprintf(
1281 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1282 1
                    get_class($this)
1283
                )
1284
            );
1285
        }
1286
1287 7
        return $this->validator->getMessageBag()->getMessages();
1288
    }
1289
1290
    /**
1291
     * Get all Request values from all fields, and nothing else.
1292
     *
1293
     * @param bool $with_nulls
1294
     * @return array
1295
     */
1296 3
    public function getFieldValues($with_nulls = true)
1297
    {
1298 3
        $request_values = $this->getRequest()->all();
1299
1300 3
        $values = [];
1301 3
        foreach ($this->getAllAttributes() as $attribute) {
1302 3
            $value = Arr::get($request_values, $attribute);
1303 3
            if ($with_nulls || $value !== null) {
1304 3
                Arr::set($values, $attribute, $value);
1305
            }
1306
        }
1307
1308
        // If this form is a child form, cherry pick a part
1309 3
        if ($prefix = $this->getName()) {
1310 1
            $prefix = $this->formHelper->transformToDotSyntax($prefix);
1311 1
            $values = Arr::get($values, $prefix);
1312
        }
1313
1314
        // Allow form-specific value alters
1315 3
        $this->formHelper->alterFieldValues($this, $values);
1316
1317 3
        return $values;
1318
    }
1319
1320
    /**
1321
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1322
     *
1323
     * @param array $values
1324
     * @return void
1325
     */
1326 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...
1327
    {
1328 3
    }
1329
1330
    /**
1331
     * Throw an exception indicating a field does not exist on the class.
1332
     *
1333
     * @param string $name
1334
     * @throws \InvalidArgumentException
1335
     * @return void
1336
     */
1337 2
    protected function fieldDoesNotExist($name)
1338
    {
1339 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1340
    }
1341
1342
    /**
1343
     * Method filterFields used as *Main* method for starting
1344
     * filtering and request field mutating process.
1345
     *
1346
     * @return \Kris\LaravelFormBuilder\Form
1347
     */
1348 129
    public function filterFields()
1349
    {
1350
        // If filtering is unlocked/allowed we can start with filtering process.
1351 129
        if (!$this->isFilteringLocked()) {
1352 129
            $filters = array_filter($this->getFilters());
1353
1354 129
            if (count($filters)) {
1355 1
                $dotForm = $this->formHelper->transformToDotSyntax($this->getName());
1356
1357 1
                $request = $this->getRequest();
1358 1
                $requestData = $request->all();
1359
1360 1
                foreach ($filters as $field => $fieldFilters) {
1361 1
                    $dotField = $this->formHelper->transformToDotSyntax($field);
1362 1
                    $fieldData = Arr::get($requestData, $dotField);
1363 1
                    if ($fieldData !== null) {
1364
                        // Assign current Raw/Unmutated value from request.
1365 1
                        $localDotField = preg_replace('#^' . preg_quote("$dotForm.", '#') . '#', '', $dotField);
1366 1
                        $localBracketField = $this->formHelper->transformToBracketSyntax($localDotField);
1367 1
                        $this->getField($localBracketField)->setRawValue($fieldData);
1368 1
                        foreach ($fieldFilters as $filter) {
1369 1
                            $filterObj = FilterResolver::instance($filter);
1370 1
                            $fieldData = $filterObj->filter($fieldData);
1371
                        }
1372 1
                        Arr::set($requestData, $dotField, $fieldData);
1373
                    }
1374
                }
1375
1376 1
                foreach ($requestData as $name => $value) {
1377 1
                    $request[$name] = $value;
1378
                }
1379
            }
1380
        }
1381
1382 129
        return $this;
1383
    }
1384
1385
    /**
1386
     * Method getFilters used to return array of all binded filters to form fields.
1387
     *
1388
     * @return array
1389
     */
1390 129
    public function getFilters()
1391
    {
1392 129
        $filters = [];
1393 129
        foreach ($this->getFields() as $field) {
1394 17
            $filters[$field->getName()] = $field->getFilters();
1395
        }
1396
1397 129
        return $filters;
1398
    }
1399
1400
    /**
1401
     * If lockFiltering is set to true then we will not
1402
     * filter fields and mutate request data binded to fields.
1403
     *
1404
     * @return \Kris\LaravelFormBuilder\Form
1405
     */
1406 1
    public function lockFiltering()
1407
    {
1408 1
        $this->lockFiltering = true;
1409 1
        return $this;
1410
    }
1411
1412
    /**
1413
     * Unlock fields filtering/mutating.
1414
     *
1415
     * @return \Kris\LaravelFormBuilder\Form
1416
     */
1417
    public function unlockFiltering()
1418
    {
1419
        $this->lockFiltering = false;
1420
        return $this;
1421
    }
1422
1423
    /**
1424
     * Method isFilteringLocked used to check
1425
     * if current filteringLocked property status is set to true.
1426
     *
1427
     * @return bool
1428
     */
1429 129
    public function isFilteringLocked()
1430
    {
1431 129
        return !$this->lockFiltering ? false : true;
1432
    }
1433
1434
    /**
1435
     * Method getRawValues returns Unfiltered/Unmutated fields -> values.
1436
     *
1437
     * @return array
1438
     */
1439
    public function getRawValues()
1440
    {
1441
        $rawValues = [];
1442
        foreach ($this->getFields() as $field) {
1443
            $rawValues[$field->getName()] = $field->getRawValue();
1444
        }
1445
1446
        return $rawValues;
1447
    }
1448
}
1449