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

Form::checkIfNamedForm()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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