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

Form::removeAll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1392 1
            $prefix = $this->getNameKey();
1393 1
            $values = Arr::get($values, $prefix);
1394
        }
1395
1396
        // Allow form-specific value alters
1397 3
        $this->formHelper->alterFieldValues($this, $values);
1398
1399 3
        return $values;
1400
    }
1401
1402
    /**
1403
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1404
     *
1405
     * @param array $values
1406
     * @return void
1407
     */
1408 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...
1409
    {
1410 3
    }
1411
1412
    /**
1413
     * Throw an exception indicating a field does not exist on the class.
1414
     *
1415
     * @param string $name
1416
     * @throws \InvalidArgumentException
1417
     * @return void
1418
     */
1419 2
    protected function fieldDoesNotExist($name)
1420
    {
1421 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1422
    }
1423
1424
    /**
1425
     * Method filterFields used as *Main* method for starting
1426
     * filtering and request field mutating process.
1427
     *
1428
     * @return \Kris\LaravelFormBuilder\Form
1429
     */
1430 132
    public function filterFields()
1431
    {
1432
        // If filtering is unlocked/allowed we can start with filtering process.
1433 132
        if (!$this->isFilteringLocked()) {
1434 132
            $filters = array_filter($this->getFilters());
1435
1436 132
            if (count($filters)) {
1437 1
                $dotForm = $this->getNameKey();
1438
1439 1
                $request = $this->getRequest();
1440 1
                $requestData = $request->all();
1441
1442 1
                foreach ($filters as $field => $fieldFilters) {
1443 1
                    $dotField = $this->formHelper->transformToDotSyntax($field);
1444 1
                    $fieldData = Arr::get($requestData, $dotField);
1445 1
                    if ($fieldData !== null) {
1446
                        // Assign current Raw/Unmutated value from request.
1447 1
                        $localDotField = preg_replace('#^' . preg_quote("$dotForm.", '#') . '#', '', $dotField);
1448 1
                        $localBracketField = $this->formHelper->transformToBracketSyntax($localDotField);
1449 1
                        $this->getField($localBracketField)->setRawValue($fieldData);
1450 1
                        foreach ($fieldFilters as $filter) {
1451 1
                            $filterObj = FilterResolver::instance($filter);
1452 1
                            $fieldData = $filterObj->filter($fieldData);
1453
                        }
1454 1
                        Arr::set($requestData, $dotField, $fieldData);
1455
                    }
1456
                }
1457
1458 1
                foreach ($requestData as $name => $value) {
1459 1
                    $request[$name] = $value;
1460
                }
1461
            }
1462
        }
1463
1464 132
        return $this;
1465
    }
1466
1467
    /**
1468
     * Method getFilters used to return array of all binded filters to form fields.
1469
     *
1470
     * @return array
1471
     */
1472 132
    public function getFilters()
1473
    {
1474 132
        $filters = [];
1475 132
        foreach ($this->getFields() as $field) {
1476 17
            $filters[$field->getName()] = $field->getFilters();
1477
        }
1478
1479 132
        return $filters;
1480
    }
1481
1482
    /**
1483
     * If lockFiltering is set to true then we will not
1484
     * filter fields and mutate request data binded to fields.
1485
     *
1486
     * @return \Kris\LaravelFormBuilder\Form
1487
     */
1488 1
    public function lockFiltering()
1489
    {
1490 1
        $this->lockFiltering = true;
1491 1
        return $this;
1492
    }
1493
1494
    /**
1495
     * Unlock fields filtering/mutating.
1496
     *
1497
     * @return \Kris\LaravelFormBuilder\Form
1498
     */
1499
    public function unlockFiltering()
1500
    {
1501
        $this->lockFiltering = false;
1502
        return $this;
1503
    }
1504
1505
    /**
1506
     * Method isFilteringLocked used to check
1507
     * if current filteringLocked property status is set to true.
1508
     *
1509
     * @return bool
1510
     */
1511 132
    public function isFilteringLocked()
1512
    {
1513 132
        return !$this->lockFiltering ? false : true;
1514
    }
1515
1516
    /**
1517
     * Method getRawValues returns Unfiltered/Unmutated fields -> values.
1518
     *
1519
     * @return array
1520
     */
1521
    public function getRawValues()
1522
    {
1523
        $rawValues = [];
1524
        foreach ($this->getFields() as $field) {
1525
            $rawValues[$field->getName()] = $field->getRawValue();
1526
        }
1527
1528
        return $rawValues;
1529
    }
1530
}
1531