Completed
Push — master ( 358572...54c4c6 )
by Kristijan
03:25
created

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