Completed
Push — master ( 564bff...76f52b )
by Kristijan
10s
created

Form::renderUntil()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 6
nop 3
dl 0
loc 20
ccs 11
cts 11
cp 1
crap 4
rs 9.2
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
     * Additional data which can be used to build fields.
55
     *
56
     * @var array
57
     */
58
    protected $data = [];
59
60
    /**
61
     * Wether errors for each field should be shown when calling form($form) or form_rest($form).
62
     *
63
     * @var bool
64
     */
65
    protected $showFieldErrors = true;
66
67
    /**
68
     * Enable html5 validation.
69
     *
70
     * @var bool
71
     */
72
    protected $clientValidationEnabled = true;
73
74
    /**
75
     * Name of the parent form if any.
76
     *
77
     * @var string|null
78
     */
79
    protected $name = null;
80
81
    /**
82
     * @var FormBuilder
83
     */
84
    protected $formBuilder;
85
86
    /**
87
     * @var ValidatorFactory
88
     */
89
    protected $validatorFactory;
90
91
    /**
92
     * @var Validator
93
     */
94
    protected $validator = null;
95
96
    /**
97
     * @var Request
98
     */
99
    protected $request;
100
101
    /**
102
     * List of fields to not render.
103
     *
104
     * @var array
105
     **/
106
    protected $exclude = [];
107
108
    /**
109
     * Wether the form is beign rebuild.
110
     *
111
     * @var bool
112
     */
113
    protected $rebuilding = false;
114
115
    /**
116
     * @var string
117
     */
118
    protected $templatePrefix;
119
120
    /**
121
     * @var string
122
     */
123
    protected $languageName;
124
125
    /**
126
     * @var string
127
     */
128
    protected $translationTemplate;
129
130
    /**
131
     * To filter and mutate request values or not.
132
     *
133
     * @var bool
134
     */
135
    protected $lockFiltering = false;
136
137
    /**
138
     * Build the form.
139
     *
140
     * @return mixed
141
     */
142 3
    public function buildForm()
143
    {
144 3
    }
145
146
    /**
147
     * Rebuild the form from scratch.
148
     *
149
     * @return $this
150
     */
151 19
    public function rebuildForm()
152
    {
153 19
        $this->rebuilding = true;
154
        // If form is plain, buildForm method is empty, so we need to take
155
        // existing fields and add them again
156 19
        if (get_class($this) === 'Kris\LaravelFormBuilder\Form') {
157 18
            foreach ($this->fields as $name => $field) {
158
                // Remove any temp variables added in previous instance
159 7
                $options = array_except($field->getOptions(), 'tmp');
160 18
                $this->add($name, $field->getType(), $options);
161
            }
162
        } else {
163 3
            $this->buildForm();
164
        }
165 19
        $this->rebuilding = false;
166
167 19
        return $this;
168
    }
169
170
    /**
171
     * Create the FormField object.
172
     *
173
     * @param string $name
174
     * @param string $type
175
     * @param array  $options
176
     * @return FormField
177
     */
178 65
    protected function makeField($name, $type = 'text', array $options = [])
179
    {
180 65
        $this->setupFieldOptions($name, $options);
181
182 65
        $fieldName = $this->getFieldName($name);
183
184 65
        $fieldType = $this->getFieldType($type);
185
186 64
        $field = new $fieldType($fieldName, $type, $this, $options);
187
188 61
        $this->eventDispatcher->fire(new AfterFieldCreation($this, $field));
189
190 61
        return $field;
191
    }
192
193
    /**
194
     * Create a new field and add it to the form.
195
     *
196
     * @param string $name
197
     * @param string $type
198
     * @param array  $options
199
     * @param bool   $modify
200
     * @return $this
201
     */
202 67
    public function add($name, $type = 'text', array $options = [], $modify = false)
203
    {
204 67
        $this->formHelper->checkFieldName($name, get_class($this));
205
206 65
        if ($this->rebuilding && !$this->has($name)) {
207
            return $this;
208
        }
209
210 65
        $this->addField($this->makeField($name, $type, $options), $modify);
211
212 61
        return $this;
213
    }
214
215
    /**
216
     * Add a FormField to the form's fields.
217
     *
218
     * @param FormField $field
219
     * @return $this
220
     */
221 61
    protected function addField(FormField $field, $modify = false)
222
    {
223 61
        if (!$modify && !$this->rebuilding) {
224 61
            $this->preventDuplicate($field->getRealName());
225
        }
226
227
228 61
        if ($field->getType() == 'file') {
229 3
            $this->formOptions['files'] = true;
230
        }
231
232 61
        $this->fields[$field->getRealName()] = $field;
233
234 61
        return $this;
235
    }
236
237
    /**
238
     * Add field before another field.
239
     *
240
     * @param string  $name         Name of the field before which new field is added.
241
     * @param string  $fieldName    Field name which will be added.
242
     * @param string  $type
243
     * @param array   $options
244
     * @param bool $modify
245
     * @return $this
246
     */
247 1
    public function addBefore($name, $fieldName, $type = 'text', $options = [], $modify = false)
248
    {
249 1
        $offset = array_search($name, array_keys($this->fields));
250
251 1
        $beforeFields = array_slice($this->fields, 0, $offset);
252 1
        $afterFields = array_slice($this->fields, $offset);
253
254 1
        $this->fields = $beforeFields;
255
256 1
        $this->add($fieldName, $type, $options, $modify);
257
258 1
        $this->fields += $afterFields;
259
260 1
        return $this;
261
    }
262
263
    /**
264
     * Add field before another field.
265
     *
266
     * @param string  $name         Name of the field after which new field is added.
267
     * @param string  $fieldName    Field name which will be added.
268
     * @param string  $type
269
     * @param array   $options
270
     * @param bool $modify
271
     * @return $this
272
     */
273 1
    public function addAfter($name, $fieldName, $type = 'text', $options = [], $modify = false)
274
    {
275 1
        $offset = array_search($name, array_keys($this->fields));
276
277 1
        $beforeFields = array_slice($this->fields, 0, $offset + 1);
278 1
        $afterFields = array_slice($this->fields, $offset + 1);
279
280 1
        $this->fields = $beforeFields;
281
282 1
        $this->add($fieldName, $type, $options, $modify);
283
284 1
        $this->fields += $afterFields;
285
286 1
        return $this;
287
    }
288
289
    /**
290
     * Take another form and add it's fields directly to this form.
291
     *
292
     * @param mixed   $class        Form to merge.
293
     * @param array   $options
294
     * @param boolean $modify
295
     * @return $this
296
     */
297 1
    public function compose($class, array $options = [], $modify = false)
298
    {
299 1
        $options['class'] = $class;
300
301
        // If we pass a ready made form just extract the fields.
302 1
        if ($class instanceof Form) {
303 1
            $fields = $class->getFields();
304
        } elseif ($class instanceof Fields\ChildFormType) {
305
            $fields = $class->getForm()->getFields();
306
        } elseif (is_string($class)) {
307
            // If its a string of a class make it the usual way.
308
            $options['model'] = $this->model;
309
            $options['name'] = $this->name;
310
311
            $form = $this->formBuilder->create($class, $options);
312
            $fields = $form->getFields();
313
        } else {
314
            throw new \InvalidArgumentException(
315
                "[{$class}] is invalid. Please provide either a full class name, Form or ChildFormType"
316
            );
317
        }
318
319 1
        foreach ($fields as $field) {
320 1
            $this->addField($field, $modify);
321
        }
322
323 1
        return $this;
324
    }
325
326
    /**
327
     * Remove field with specified name from the form.
328
     *
329
     * @param $name
330
     * @return $this
331
     */
332 2
    public function remove($name)
333
    {
334 2
        if ($this->has($name)) {
335 2
            unset($this->fields[$name]);
336
        }
337
338 2
        return $this;
339
    }
340
341
    /**
342
     * Modify existing field. If it doesn't exist, it is added to form.
343
     *
344
     * @param string $name
345
     * @param string $type
346
     * @param array  $options
347
     * @param bool   $overwriteOptions
348
     * @return Form
349
     */
350 1
    public function modify($name, $type = 'text', array $options = [], $overwriteOptions = false)
351
    {
352
        // If we don't want to overwrite options, we merge them with old options.
353 1
        if ($overwriteOptions === false && $this->has($name)) {
354 1
            $options = $this->formHelper->mergeOptions(
355 1
                $this->getField($name)->getOptions(),
356 1
                $options
357
            );
358
        }
359
360 1
        return $this->add($name, $type, $options, true);
361
    }
362
363
    /**
364
     * Render full form.
365
     *
366
     * @param array $options
367
     * @param bool  $showStart
368
     * @param bool  $showFields
369
     * @param bool  $showEnd
370
     * @return string
371
     */
372 7
    public function renderForm(array $options = [], $showStart = true, $showFields = true, $showEnd = true)
373
    {
374 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...
375
    }
376
377
    /**
378
     * Render rest of the form.
379
     *
380
     * @param bool $showFormEnd
381
     * @param bool $showFields
382
     * @return string
383
     */
384 1
    public function renderRest($showFormEnd = true, $showFields = true)
385
    {
386 1
        $fields = $this->getUnrenderedFields();
387
388 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...
389
    }
390
391
    /**
392
     * Renders the rest of the form up until the specified field name.
393
     *
394
     * @param string $field_name
395
     * @param bool   $showFormEnd
396
     * @param bool   $showFields
397
     * @return string
398
     */
399 2
    public function renderUntil($field_name, $showFormEnd = true, $showFields = true)
400
    {
401 2
        if (!$this->has($field_name)) {
402 1
            $this->fieldDoesNotExist($field_name);
403
        }
404
405 1
        $fields = $this->getUnrenderedFields();
406
407 1
        $i = 1;
408 1
        foreach ($fields as $key => $value) {
409 1
            if ($value->getRealName() == $field_name) {
410 1
                break;
411
            }
412 1
            $i++;
413
        }
414
415 1
        $fields = array_slice($fields, 0, $i, true);
416
417 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...
418
    }
419
420
    /**
421
     * Get single field instance from form object.
422
     *
423
     * @param string $name
424
     * @return FormField
425
     */
426 34
    public function getField($name)
427
    {
428 34
        if ($this->has($name)) {
429 33
            return $this->fields[$name];
430
        }
431
432 1
        $this->fieldDoesNotExist($name);
433
    }
434
435
    /**
436
     * Check if form has field.
437
     *
438
     * @param string $name
439
     * @return bool
440
     */
441 61
    public function has($name)
442
    {
443 61
        return array_key_exists($name, $this->fields);
444
    }
445
446
    /**
447
     * Get all form options.
448
     *
449
     * @return array
450
     */
451 2
    public function getFormOptions()
452
    {
453 2
        return $this->formOptions;
454
    }
455
456
    /**
457
     * Get single form option.
458
     *
459
     * @param string $option
460
     * @param mixed|null $default
461
     * @return mixed
462
     */
463 129
    public function getFormOption($option, $default = null)
464
    {
465 129
        return array_get($this->formOptions, $option, $default);
466
    }
467
468
    /**
469
     * Set single form option on form.
470
     *
471
     * @param string $option
472
     * @param mixed $value
473
     *
474
     * @return $this
475
     */
476 2
    public function setFormOption($option, $value)
477
    {
478 2
        $this->formOptions[$option] = $value;
479
480 2
        return $this;
481
    }
482
483
    /**
484
     * Set form options.
485
     *
486
     * @param array $formOptions
487
     * @return $this
488
     */
489 129
    public function setFormOptions(array $formOptions)
490
    {
491 129
        $this->formOptions = $this->formHelper->mergeOptions($this->formOptions, $formOptions);
492 129
        $this->checkIfNamedForm();
493 129
        $this->pullFromOptions('data', 'addData');
494 129
        $this->pullFromOptions('model', 'setupModel');
495 129
        $this->pullFromOptions('errors_enabled', 'setErrorsEnabled');
496 129
        $this->pullFromOptions('client_validation', 'setClientValidationEnabled');
497 129
        $this->pullFromOptions('template_prefix', 'setTemplatePrefix');
498 129
        $this->pullFromOptions('language_name', 'setLanguageName');
499 129
        $this->pullFromOptions('translation_template', 'setTranslationTemplate');
500
501 129
        return $this;
502
    }
503
504
    /**
505
     * Get an option from provided options and call method with that value.
506
     *
507
     * @param string $name
508
     * @param string $method
509
     */
510 129
    protected function pullFromOptions($name, $method)
511
    {
512 129
        if (array_get($this->formOptions, $name) !== null) {
513 20
            $this->{$method}(array_pull($this->formOptions, $name));
514
        }
515 129
    }
516
517
    /**
518
     * Get form http method.
519
     *
520
     * @return string
521
     */
522 3
    public function getMethod()
523
    {
524 3
        return $this->formOptions['method'];
525
    }
526
527
    /**
528
     * Set form http method.
529
     *
530
     * @param string $method
531
     * @return $this
532
     */
533 1
    public function setMethod($method)
534
    {
535 1
        $this->formOptions['method'] = $method;
536
537 1
        return $this;
538
    }
539
540
    /**
541
     * Get form action url.
542
     *
543
     * @return string
544
     */
545 3
    public function getUrl()
546
    {
547 3
        return $this->formOptions['url'];
548
    }
549
550
    /**
551
     * Set form action url.
552
     *
553
     * @param string $url
554
     * @return $this
555
     */
556 1
    public function setUrl($url)
557
    {
558 1
        $this->formOptions['url'] = $url;
559
560 1
        return $this;
561
    }
562
563
    /**
564
     * Returns the name of the form.
565
     *
566
     * @return string|null
567
     */
568 66
    public function getName()
569
    {
570 66
        return $this->name;
571
    }
572
573
    /**
574
     * Set the name of the form.
575
     *
576
     * @param string $name
577
     * @param bool $rebuild
578
     * @return $this
579
     */
580 12
    public function setName($name, $rebuild = true)
581
    {
582 12
        $this->name = $name;
583
584 12
        if ($rebuild) {
585 12
            $this->rebuildForm();
586
        }
587
588 12
        return $this;
589
    }
590
591
    /**
592
     * Get model that is bind to form object.
593
     *
594
     * @return mixed
595
     */
596 96
    public function getModel()
597
    {
598 96
        return $this->model;
599
    }
600
601
    /**
602
     * Set model to form object.
603
     *
604
     * @param mixed $model
605
     * @return $this
606
     * @deprecated deprecated since 1.6.31, will be removed in 1.7 - pass model as option when creating a form
607
     */
608 17
    public function setModel($model)
609
    {
610 17
        $this->model = $model;
611
612 17
        $this->rebuildForm();
613
614 17
        return $this;
615
    }
616
617
    /**
618
     * Setup model for form, add namespace if needed for child forms.
619
     *
620
     * @return $this
621
     */
622 12
    protected function setupModel($model)
623
    {
624 12
        $this->model = $model;
625
626 12
        return $this;
627
    }
628
629
    /**
630
     * Get all fields.
631
     *
632
     * @return FormField[]
633
     */
634 129
    public function getFields()
635
    {
636 129
        return $this->fields;
637
    }
638
639
    /**
640
     * Get field dynamically.
641
     *
642
     * @param string $name
643
     * @return FormField
644
     */
645 20
    public function __get($name)
646
    {
647 20
        if ($this->has($name)) {
648 19
            return $this->getField($name);
649
        }
650 3
    }
651
652
    /**
653
     * Check if field exists when fetched using magic methods.
654
     *
655
     * @param string $name
656
     * @return bool
657
     */
658
    public function __isset($name)
659
    {
660
        return $this->has($name);
661
    }
662
663
    /**
664
     * Set the Event Dispatcher to fire Laravel events.
665
     *
666
     * @param EventDispatcher $eventDispatcher
667
     * @return $this
668
     */
669 129
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
670
    {
671 129
        $this->eventDispatcher = $eventDispatcher;
672
673 129
        return $this;
674
    }
675
676
    /**
677
     * Set the form helper only on first instantiation.
678
     *
679
     * @param FormHelper $formHelper
680
     * @return $this
681
     */
682 129
    public function setFormHelper(FormHelper $formHelper)
683
    {
684 129
        $this->formHelper = $formHelper;
685
686 129
        return $this;
687
    }
688
689
    /**
690
     * Get form helper.
691
     *
692
     * @return FormHelper
693
     */
694 101
    public function getFormHelper()
695
    {
696 101
        return $this->formHelper;
697
    }
698
699
    /**
700
     * Add custom field.
701
     *
702
     * @param $name
703
     * @param $class
704
     */
705 2
    public function addCustomField($name, $class)
706
    {
707 2
        if ($this->rebuilding && $this->formHelper->hasCustomField($name)) {
708
            return $this;
709
        }
710
711 2
        $this->formHelper->addCustomField($name, $class);
712 2
    }
713
714
    /**
715
     * Returns wether form errors should be shown under every field.
716
     *
717
     * @return bool
718
     */
719 101
    public function haveErrorsEnabled()
720
    {
721 101
        return $this->showFieldErrors;
722
    }
723
724
    /**
725
     * Enable or disable showing errors under fields
726
     *
727
     * @param bool $enabled
728
     * @return $this
729
     */
730 1
    public function setErrorsEnabled($enabled)
731
    {
732 1
        $this->showFieldErrors = (bool) $enabled;
733
734 1
        return $this;
735
    }
736
737
    /**
738
     * Is client validation enabled?
739
     *
740
     * @return bool
741
     */
742 101
    public function clientValidationEnabled()
743
    {
744 101
        return $this->clientValidationEnabled;
745
    }
746
747
    /**
748
     * Enable/disable client validation.
749
     *
750
     * @param bool $enable
751
     * @return $this
752
     */
753 2
    public function setClientValidationEnabled($enable)
754
    {
755 2
        $this->clientValidationEnabled = (bool) $enable;
756
757 2
        return $this;
758
    }
759
760
    /**
761
     * Add any aditional data that field needs (ex. array of choices).
762
     *
763
     * @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
764
     * will be switched to protected in 1.7.
765
     * @param string $name
766
     * @param mixed $data
767
     */
768 1
    public function setData($name, $data)
769
    {
770 1
        $this->data[$name] = $data;
771 1
    }
772
773
    /**
774
     * Get single additional data.
775
     *
776
     * @param string $name
777
     * @param null   $default
778
     * @return mixed
779
     */
780 20
    public function getData($name = null, $default = null)
781
    {
782 20
        if (is_null($name)) {
783 19
            return $this->data;
784
        }
785
786 1
        return array_get($this->data, $name, $default);
787
    }
788
789
    /**
790
     * Add multiple peices of data at once.
791
     *
792
     * @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
793
     * will be switched to protected in 1.7.
794
     * @param $data
795
     * @return $this
796
     **/
797 129
    public function addData(array $data)
798
    {
799 129
        foreach ($data as $key => $value) {
800 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...
801
        }
802
803 129
        return $this;
804
    }
805
806
    /**
807
     * Get current request.
808
     *
809
     * @return \Illuminate\Http\Request
810
     */
811 129
    public function getRequest()
812
    {
813 129
        return $this->request;
814
    }
815
816
    /**
817
     * Set request on form.
818
     *
819
     * @param Request $request
820
     * @return $this
821
     */
822 129
    public function setRequest(Request $request)
823
    {
824 129
        $this->request = $request;
825
826 129
        return $this;
827
    }
828
829
    /**
830
     * Get template prefix that is prepended to all template paths.
831
     *
832
     * @return string
833
     */
834 39
    public function getTemplatePrefix()
835
    {
836 39
        if ($this->templatePrefix !== null) {
837 4
            return $this->templatePrefix;
838
        }
839
840 35
        return $this->formHelper->getConfig('template_prefix');
841
    }
842
843
    /**
844
     * Set a template prefix for the form and its fields.
845
     *
846
     * @param string $prefix
847
     * @return $this
848
     */
849 4
    public function setTemplatePrefix($prefix)
850
    {
851 4
        $this->templatePrefix = (string) $prefix;
852
853 4
        return $this;
854
    }
855
856
    /**
857
     * Get the language name.
858
     *
859
     * @return string
860
     */
861 98
    public function getLanguageName()
862
    {
863 98
        return $this->languageName;
864
    }
865
866
    /**
867
     * Set a language name, used as prefix for translated strings.
868
     *
869
     * @param string $prefix
870
     * @return $this
871
     */
872 13
    public function setLanguageName($prefix)
873
    {
874 13
        $this->languageName = (string) $prefix;
875
876 13
        return $this;
877
    }
878
879
    /**
880
     * Get the translation template.
881
     *
882
     * @return string
883
     */
884 100
    public function getTranslationTemplate()
885
    {
886 100
        return $this->translationTemplate;
887
    }
888
889
    /**
890
     * Set a translation template, used to determine labels for fields.
891
     *
892
     * @param string $template
893
     * @return $this
894
     */
895 11
    public function setTranslationTemplate($template)
896
    {
897 11
        $this->translationTemplate = (string) $template;
898
899 11
        return $this;
900
    }
901
902
    /**
903
     * Render the form.
904
     *
905
     * @param array $options
906
     * @param string $fields
907
     * @param bool $showStart
908
     * @param bool $showFields
909
     * @param bool $showEnd
910
     * @return string
911
     */
912 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
913
    {
914 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
915
916 9
        $this->setupNamedModel();
917
918 9
        return $this->formHelper->getView()
919 9
            ->make($this->getTemplate())
920 9
            ->with(compact('showStart', 'showFields', 'showEnd'))
921 9
            ->with('formOptions', $formOptions)
922 9
            ->with('fields', $fields)
923 9
            ->with('model', $this->getModel())
924 9
            ->with('exclude', $this->exclude)
925 9
            ->with('form', $this)
926 9
            ->render();
927
    }
928
929
    /**
930
     * Get template from options if provided, otherwise fallback to config.
931
     *
932
     * @return mixed
933
     */
934 9
    protected function getTemplate()
935
    {
936 9
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->formHelper->getConfig('form'));
937
    }
938
939
    /**
940
     * Get all fields that are not rendered.
941
     *
942
     * @return array
943
     */
944 2
    protected function getUnrenderedFields()
945
    {
946 2
        $unrenderedFields = [];
947
948 2
        foreach ($this->fields as $field) {
949 2
            if (!$field->isRendered()) {
950 2
                $unrenderedFields[] = $field;
951 2
                continue;
952
            }
953
        }
954
955 2
        return $unrenderedFields;
956
    }
957
958
    /**
959
     * Prevent adding fields with same name.
960
     *
961
     * @param string $name
962
     * @throws \InvalidArgumentException
963
     * @return void
964
     */
965 61
    protected function preventDuplicate($name)
966
    {
967 61
        if ($this->has($name)) {
968 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
969
        }
970 61
    }
971
972
    /**
973
     * Returns and checks the type of the field.
974
     *
975
     * @param string $type
976
     * @return string
977
     */
978 65
    protected function getFieldType($type)
979
    {
980 65
        $fieldType = $this->formHelper->getFieldType($type);
981
982 64
        return $fieldType;
983
    }
984
985
    /**
986
     * Check if form is named form.
987
     *
988
     * @return void
989
     */
990 129
    protected function checkIfNamedForm()
991
    {
992 129
        if ($this->getFormOption('name')) {
993 8
            $this->name = array_pull($this->formOptions, 'name', $this->name);
994
        }
995 129
    }
996
997
    /**
998
     * Set up options on single field depending on form options.
999
     *
1000
     * @param string $name
1001
     * @param $options
1002
     */
1003 65
    protected function setupFieldOptions($name, &$options)
1004
    {
1005 65
        $options['real_name'] = $name;
1006 65
    }
1007
1008
    /**
1009
     * Set namespace to model if form is named so the data is bound properly.
1010
     * Returns true if model is changed, otherwise false.
1011
     *
1012
     * @return bool
1013
     */
1014 9
    protected function setupNamedModel()
1015
    {
1016 9
        if (!$this->getModel() || !$this->getName()) {
1017 8
            return false;
1018
        }
1019
1020 1
        $dotName = $this->formHelper->transformToDotSyntax($this->getName());
1021 1
        $model = $this->formHelper->convertModelToArray($this->getModel());
1022
1023 1
        if (!array_get($model, $dotName)) {
0 ignored issues
show
Bug introduced by
It seems like $model defined by $this->formHelper->conve...rray($this->getModel()) on line 1021 can also be of type null or object; however, array_get() does only seem to accept object<ArrayAccess>|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1024 1
            $newModel = [];
1025 1
            array_set($newModel, $dotName, $model);
1026 1
            $this->model = $newModel;
1027
1028 1
            return true;
1029
        }
1030
1031
        return false;
1032
    }
1033
1034
    /**
1035
     * Set form builder instance on helper so we can use it later.
1036
     *
1037
     * @param FormBuilder $formBuilder
1038
     * @return $this
1039
     */
1040 129
    public function setFormBuilder(FormBuilder $formBuilder)
1041
    {
1042 129
        $this->formBuilder = $formBuilder;
1043
1044 129
        return $this;
1045
    }
1046
1047
    /**
1048
     * Returns the instance of the FormBuilder.
1049
     *
1050
     * @return FormBuilder
1051
     */
1052 12
    public function getFormBuilder()
1053
    {
1054 12
        return $this->formBuilder;
1055
    }
1056
1057
    /**
1058
     * Set the Validator instance on this so we can use it later.
1059
     *
1060
     * @param ValidatorFactory $validator
1061
     * @return $this
1062
     */
1063 129
    public function setValidator(ValidatorFactory $validator)
1064
    {
1065 129
        $this->validatorFactory = $validator;
1066
1067 129
        return $this;
1068
    }
1069
1070
    /**
1071
     * Returns the validator instance.
1072
     *
1073
     * @return Validator
1074
     */
1075 1
    public function getValidator()
1076
    {
1077 1
        return $this->validator;
1078
    }
1079
1080
    /**
1081
     * Exclude some fields from rendering.
1082
     *
1083
     * @return $this
1084
     */
1085
    public function exclude(array $fields)
1086
    {
1087
        $this->exclude = array_merge($this->exclude, $fields);
1088
1089
        return $this;
1090
    }
1091
1092
    /**
1093
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1094
     *
1095
     * @param string $name
1096
     * @return string
1097
     */
1098 65
    protected function getFieldName($name)
1099
    {
1100 65
        $formName = $this->getName();
1101 65
        if ($formName !== null) {
1102 14
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1103 6
                return $this->formHelper->transformToBracketSyntax(
1104 6
                    $this->formHelper->transformToDotSyntax(
1105 6
                        $formName . '[' . $name . ']'
1106
                    )
1107
                );
1108
            }
1109
1110 11
            return $formName . '[' . $name . ']';
1111
        }
1112
1113 65
        return $name;
1114
    }
1115
1116
    /**
1117
     * Disable all fields in a form.
1118
     */
1119 1
    public function disableFields()
1120
    {
1121 1
        foreach ($this->fields as $field) {
1122 1
            $field->disable();
1123
        }
1124 1
    }
1125
1126
    /**
1127
     * Enable all fields in a form.
1128
     */
1129 1
    public function enableFields()
1130
    {
1131 1
        foreach ($this->fields as $field) {
1132 1
            $field->enable();
1133
        }
1134 1
    }
1135
1136
    /**
1137
     * Validate the form.
1138
     *
1139
     * @param array $validationRules
1140
     * @param array $messages
1141
     * @return Validator
1142
     */
1143 9
    public function validate($validationRules = [], $messages = [])
1144
    {
1145 9
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1146 9
        $rules = array_merge($fieldRules['rules'], $validationRules);
1147 9
        $messages = array_merge($fieldRules['error_messages'], $messages);
1148
1149 9
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1150 9
        $this->validator->setAttributeNames($fieldRules['attributes']);
1151
1152 9
        $this->eventDispatcher->fire(new BeforeFormValidation($this, $this->validator));
1153
1154 9
        return $this->validator;
1155
    }
1156
1157
    /**
1158
     * Get validation rules for the form.
1159
     *
1160
     * @param array $overrideRules
1161
     * @return array
1162
     */
1163 1
    public function getRules($overrideRules = [])
1164
    {
1165 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1166
1167 1
        return array_merge($fieldRules['rules'], $overrideRules);
1168
    }
1169
1170
    /**
1171
     * Redirects to a destination when form is invalid.
1172
     *
1173
     * @param  string|null $destination The target url.
1174
     * @return HttpResponseException
1175
     */
1176 3
    public function redirectIfNotValid($destination = null)
1177
    {
1178 3
        if (! $this->isValid()) {
1179 3
            $response = redirect($destination);
1180
1181 3
            if (is_null($destination)) {
1182 2
                $response = $response->back();
1183
            }
1184
1185 3
            $response = $response->withErrors($this->getErrors())->withInput();
1186
1187 3
            throw new HttpResponseException($response);
1188
        }
1189
    }
1190
1191
    /**
1192
     * Get all form field attributes, including child forms, in a flat array.
1193
     *
1194
     * @return array
1195
     */
1196 3
    public function getAllAttributes()
1197
    {
1198 3
        return $this->formHelper->mergeAttributes($this->fields);
1199
    }
1200
1201
    /**
1202
     * Check if the form is valid.
1203
     *
1204
     * @return bool
1205
     */
1206 9
    public function isValid()
1207
    {
1208 9
        if (!$this->validator) {
1209 8
            $this->validate();
1210
        }
1211
1212 9
        $isValid = !$this->validator->fails();
1213
1214 9
        $this->formHelper->alterValid($this, $this, $isValid);
1215
1216 9
        $this->eventDispatcher->fire(new AfterFormValidation($this, $this->validator, $isValid));
1217
1218 9
        return $isValid;
1219
    }
1220
1221
    /**
1222
     * Optionally change the validation result, and/or add error messages.
1223
     *
1224
     * @param Form $mainForm
1225
     * @param bool $isValid
1226
     * @return void|array
1227
     */
1228 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...
1229
    {
1230
        // return ['name' => ['Some other error about the Name field.']];
1231 9
    }
1232
1233
    /**
1234
     * Get validation errors.
1235
     *
1236
     * @return array
1237
     */
1238 8
    public function getErrors()
1239
    {
1240 8
        if (!$this->validator || !$this->validator instanceof Validator) {
1241 1
            throw new \InvalidArgumentException(
1242 1
                sprintf(
1243 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1244 1
                    get_class($this)
1245
                )
1246
            );
1247
        }
1248
1249 7
        return $this->validator->getMessageBag()->getMessages();
1250
    }
1251
1252
    /**
1253
     * Get all Request values from all fields, and nothing else.
1254
     *
1255
     * @param bool $with_nulls
1256
     * @return array
1257
     */
1258 3
    public function getFieldValues($with_nulls = true)
1259
    {
1260 3
        $request_values = $this->getRequest()->all();
1261
1262 3
        $values = [];
1263 3
        foreach ($this->getAllAttributes() as $attribute) {
1264 3
            $value = Arr::get($request_values, $attribute);
1265 3
            if ($with_nulls || $value !== null) {
1266 3
                Arr::set($values, $attribute, $value);
1267
            }
1268
        }
1269
1270
        // If this form is a child form, cherry pick a part
1271 3
        if ($prefix = $this->getName()) {
1272 1
            $prefix = $this->formHelper->transformToDotSyntax($prefix);
1273 1
            $values = Arr::get($values, $prefix);
1274
        }
1275
1276
        // Allow form-specific value alters
1277 3
        $this->formHelper->alterFieldValues($this, $values);
1278
1279 3
        return $values;
1280
    }
1281
1282
    /**
1283
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1284
     *
1285
     * @param array $values
1286
     * @return void
1287
     */
1288 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...
1289
    {
1290 3
    }
1291
1292
    /**
1293
     * Throw an exception indicating a field does not exist on the class.
1294
     *
1295
     * @param string $name
1296
     * @throws \InvalidArgumentException
1297
     * @return void
1298
     */
1299 2
    protected function fieldDoesNotExist($name)
1300
    {
1301 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1302
    }
1303
1304
    /**
1305
     * Method filterFields used as *Main* method for starting
1306
     * filtering and request field mutating process.
1307
     *
1308
     * @return \Kris\LaravelFormBuilder\Form
1309
     */
1310 129
    public function filterFields()
1311
    {
1312
        // If filtering is unlocked/allowed we can start with filtering process.
1313 129
        if (!$this->isFilteringLocked()) {
1314
            // Init required vars.
1315 129
            $filters = $this->getFilters();
1316 129
            $request = $this->getRequest();
1317
1318 129
            if (!empty($filters)) {
1319 16
                foreach ($filters as $field => $fieldFilters) {
1320
                    // If field exist in request object, try to mutate/filter
1321
                    // it to filtered value if there is one.
1322 16
                    if (array_key_exists($field, $request->all())) {
1323
                        // Assign current Raw/Unmutated value from request.
1324 1
                        $this->fields[$field]->setRawValue($request[$field]);
1325 1
                        foreach ($fieldFilters as $filter) {
1326 1
                            $filterObj = FilterResolver::instance($filter);
1327 16
                            $request[$field] = $filterObj->filter($request[$field]);
1328
                        }
1329
                    }
1330
                }
1331
            }
1332
        }
1333
1334 129
        return $this;
1335
    }
1336
1337
    /**
1338
     * Method getFilters used to return array of all binded filters to form fields.
1339
     *
1340
     * @return array
1341
     */
1342 129
    public function getFilters()
1343
    {
1344 129
        $filters = [];
1345 129
        foreach ($this->getFields() as $field) {
1346 17
            $filters[$field->getName()] = $field->getFilters();
1347
        }
1348
1349 129
        return $filters;
1350
    }
1351
1352
    /**
1353
     * If lockFiltering is set to true then we will not
1354
     * filter fields and mutate request data binded to fields.
1355
     *
1356
     * @return \Kris\LaravelFormBuilder\Form
1357
     */
1358 1
    public function lockFiltering()
1359
    {
1360 1
        $this->lockFiltering = true;
1361 1
        return $this;
1362
    }
1363
1364
    /**
1365
     * Unlock fields filtering/mutating.
1366
     *
1367
     * @return \Kris\LaravelFormBuilder\Form
1368
     */
1369
    public function unlockFiltering()
1370
    {
1371
        $this->lockFiltering = false;
1372
        return $this;
1373
    }
1374
1375
    /**
1376
     * Method isFilteringLocked used to check
1377
     * if current filteringLocked property status is set to true.
1378
     *
1379
     * @return bool
1380
     */
1381 129
    public function isFilteringLocked()
1382
    {
1383 129
        return !$this->lockFiltering ? false : true;
1384
    }
1385
1386
    /**
1387
     * Method getRawValues returns Unfiltered/Unmutated fields -> values.
1388
     *
1389
     * @return array
1390
     */
1391
    public function getRawValues()
1392
    {
1393
        $rawValues = [];
1394
        foreach ($this->getFields() as $field) {
1395
            $rawValues[$field->getName()] = $field->getRawValue();
1396
        }
1397
1398
        return $rawValues;
1399
    }
1400
}
1401