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

Form::getNameKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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