Completed
Push — master ( 6dd28e...5c063d )
by Kristijan
04:11 queued 10s
created

Form::only()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 1
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 3
rs 9.8666
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 7
                $this->add($name, $field->getType(), $options);
175 18
            }
176 18
        } 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 62
        }
240
241
242 62
        if ($field->getType() == 'file') {
243 3
            $this->formOptions['files'] = true;
244 3
        }
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 1
        } 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 1
        }
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 2
            }
352 2
        }
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 1
        }
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
                $options
392 1
            );
393 1
        }
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 1
        }
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 20
        }
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
     * Set the name of the form.
629
     *
630
     * @param string $name
631
     * @param bool $rebuild
632
     * @return $this
633
     */
634 12
    public function setName($name, $rebuild = true)
635
    {
636 12
        $this->name = $name;
637
638 12
        if ($rebuild) {
639 12
            $this->rebuildForm();
640 12
        }
641
642 12
        return $this;
643
    }
644
645
    /**
646
     * Get model that is bind to form object.
647
     *
648
     * @return mixed
649
     */
650 97
    public function getModel()
651
    {
652 97
        return $this->model;
653
    }
654
655
    /**
656
     * Set model to form object.
657
     *
658
     * @param mixed $model
659
     * @return $this
660
     * @deprecated deprecated since 1.6.31, will be removed in 1.7 - pass model as option when creating a form
661
     */
662 17
    public function setModel($model)
663
    {
664 17
        $this->model = $model;
665
666 17
        $this->rebuildForm();
667
668 17
        return $this;
669
    }
670
671
    /**
672
     * Setup model for form, add namespace if needed for child forms.
673
     *
674
     * @return $this
675
     */
676 12
    protected function setupModel($model)
677
    {
678 12
        $this->model = $model;
679 12
        $this->setupNamedModel();
680
681 12
        return $this;
682
    }
683
684
    /**
685
     * Get all fields.
686
     *
687
     * @return FormField[]
688
     */
689 130
    public function getFields()
690
    {
691 130
        return $this->fields;
692
    }
693
694
    /**
695
     * Get field dynamically.
696
     *
697
     * @param string $name
698
     * @return FormField
699
     */
700 20
    public function __get($name)
701
    {
702 20
        if ($this->has($name)) {
703 19
            return $this->getField($name);
704
        }
705 3
    }
706
707
    /**
708
     * Check if field exists when fetched using magic methods.
709
     *
710
     * @param string $name
711
     * @return bool
712
     */
713
    public function __isset($name)
714
    {
715
        return $this->has($name);
716
    }
717
718
    /**
719
     * Set the Event Dispatcher to fire Laravel events.
720
     *
721
     * @param EventDispatcher $eventDispatcher
722
     * @return $this
723
     */
724 130
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
725
    {
726 130
        $this->eventDispatcher = $eventDispatcher;
727
728 130
        return $this;
729
    }
730
731
    /**
732
     * Set the form helper only on first instantiation.
733
     *
734
     * @param FormHelper $formHelper
735
     * @return $this
736
     */
737 130
    public function setFormHelper(FormHelper $formHelper)
738
    {
739 130
        $this->formHelper = $formHelper;
740
741 130
        return $this;
742
    }
743
744
    /**
745
     * Get form helper.
746
     *
747
     * @return FormHelper
748
     */
749 102
    public function getFormHelper()
750
    {
751 102
        return $this->formHelper;
752
    }
753
754
    /**
755
     * Add custom field.
756
     *
757
     * @param $name
758
     * @param $class
759
     */
760 2
    public function addCustomField($name, $class)
761
    {
762 2
        if ($this->rebuilding && $this->formHelper->hasCustomField($name)) {
763
            return $this;
764
        }
765
766 2
        $this->formHelper->addCustomField($name, $class);
767 2
    }
768
769
    /**
770
     * Returns wether form errors should be shown under every field.
771
     *
772
     * @return bool
773
     */
774 102
    public function haveErrorsEnabled()
775
    {
776 102
        return $this->showFieldErrors;
777
    }
778
779
    /**
780
     * Enable or disable showing errors under fields
781
     *
782
     * @param bool $enabled
783
     * @return $this
784
     */
785 1
    public function setErrorsEnabled($enabled)
786
    {
787 1
        $this->showFieldErrors = (bool) $enabled;
788
789 1
        return $this;
790
    }
791
792
    /**
793
     * Is client validation enabled?
794
     *
795
     * @return bool
796
     */
797 102
    public function clientValidationEnabled()
798
    {
799 102
        return $this->clientValidationEnabled;
800
    }
801
802
    /**
803
     * Enable/disable client validation.
804
     *
805
     * @param bool $enable
806
     * @return $this
807
     */
808 2
    public function setClientValidationEnabled($enable)
809
    {
810 2
        $this->clientValidationEnabled = (bool) $enable;
811
812 2
        return $this;
813
    }
814
815
    /**
816
     * Add any aditional data that field needs (ex. array of choices).
817
     *
818
     * @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
819
     * will be switched to protected in 1.7.
820
     * @param string $name
821
     * @param mixed $data
822
     */
823 1
    public function setData($name, $data)
824
    {
825 1
        $this->data[$name] = $data;
826 1
    }
827
828
    /**
829
     * Get single additional data.
830
     *
831
     * @param string $name
832
     * @param null   $default
833
     * @return mixed
834
     */
835 20
    public function getData($name = null, $default = null)
836
    {
837 20
        if (is_null($name)) {
838 19
            return $this->data;
839
        }
840
841 1
        return Arr::get($this->data, $name, $default);
842
    }
843
844
    /**
845
     * Add multiple peices of data at once.
846
     *
847
     * @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
848
     * will be switched to protected in 1.7.
849
     * @param $data
850
     * @return $this
851
     **/
852 130
    public function addData(array $data)
853
    {
854 130
        foreach ($data as $key => $value) {
855 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...
856 130
        }
857
858 130
        return $this;
859
    }
860
861
    /**
862
     * Get current request.
863
     *
864
     * @return \Illuminate\Http\Request
865
     */
866 102
    public function getRequest()
867
    {
868 102
        return $this->request;
869
    }
870
871
    /**
872
     * Set request on form.
873
     *
874
     * @param Request $request
875
     * @return $this
876
     */
877 130
    public function setRequest(Request $request)
878
    {
879 130
        $this->request = $request;
880
881 130
        return $this;
882
    }
883
884
    /**
885
     * Get template prefix that is prepended to all template paths.
886
     *
887
     * @return string
888
     */
889 39
    public function getTemplatePrefix()
890
    {
891 39
        if ($this->templatePrefix !== null) {
892 4
            return $this->templatePrefix;
893
        }
894
895 35
        return $this->getConfig('template_prefix');
896
    }
897
898
    /**
899
     * Set a template prefix for the form and its fields.
900
     *
901
     * @param string $prefix
902
     * @return $this
903
     */
904 4
    public function setTemplatePrefix($prefix)
905
    {
906 4
        $this->templatePrefix = (string) $prefix;
907
908 4
        return $this;
909
    }
910
911
    /**
912
     * Get the language name.
913
     *
914
     * @return string
915
     */
916 99
    public function getLanguageName()
917
    {
918 99
        return $this->languageName;
919
    }
920
921
    /**
922
     * Set a language name, used as prefix for translated strings.
923
     *
924
     * @param string $prefix
925
     * @return $this
926
     */
927 13
    public function setLanguageName($prefix)
928
    {
929 13
        $this->languageName = (string) $prefix;
930
931 13
        return $this;
932
    }
933
934
    /**
935
     * Get the translation template.
936
     *
937
     * @return string
938
     */
939 101
    public function getTranslationTemplate()
940
    {
941 101
        return $this->translationTemplate;
942
    }
943
944
    /**
945
     * Set a translation template, used to determine labels for fields.
946
     *
947
     * @param string $template
948
     * @return $this
949
     */
950 11
    public function setTranslationTemplate($template)
951
    {
952 11
        $this->translationTemplate = (string) $template;
953
954 11
        return $this;
955
    }
956
957
    /**
958
     * Render the form.
959
     *
960
     * @param array $options
961
     * @param string $fields
962
     * @param bool $showStart
963
     * @param bool $showFields
964
     * @param bool $showEnd
965
     * @return string
966
     */
967 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
968
    {
969 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
970
971 9
        $this->setupNamedModel();
972
973 9
        return $this->formHelper->getView()
974 9
            ->make($this->getTemplate())
975 9
            ->with(compact('showStart', 'showFields', 'showEnd'))
976 9
            ->with('formOptions', $formOptions)
977 9
            ->with('fields', $fields)
978 9
            ->with('model', $this->getModel())
979 9
            ->with('exclude', $this->exclude)
980 9
            ->with('form', $this)
981 9
            ->render();
982
    }
983
984
    /**
985
     * Get template from options if provided, otherwise fallback to config.
986
     *
987
     * @return mixed
988
     */
989 9
    protected function getTemplate()
990
    {
991 9
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->getConfig('form'));
992
    }
993
994
    /**
995
     * Get all fields that are not rendered.
996
     *
997
     * @return array
998
     */
999 2
    protected function getUnrenderedFields()
1000
    {
1001 2
        $unrenderedFields = [];
1002
1003 2
        foreach ($this->fields as $field) {
1004 2
            if (!$field->isRendered()) {
1005 2
                $unrenderedFields[] = $field;
1006 2
                continue;
1007
            }
1008 2
        }
1009
1010 2
        return $unrenderedFields;
1011
    }
1012
1013
    /**
1014
     * Prevent adding fields with same name.
1015
     *
1016
     * @param string $name
1017
     * @throws \InvalidArgumentException
1018
     * @return void
1019
     */
1020 62
    protected function preventDuplicate($name)
1021
    {
1022 62
        if ($this->has($name)) {
1023 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
1024
        }
1025 62
    }
1026
1027
    /**
1028
     * Returns and checks the type of the field.
1029
     *
1030
     * @param string $type
1031
     * @return string
1032
     */
1033 66
    protected function getFieldType($type)
1034
    {
1035 66
        $fieldType = $this->formHelper->getFieldType($type);
1036
1037 65
        return $fieldType;
1038
    }
1039
1040
    /**
1041
     * Check if form is named form.
1042
     *
1043
     * @return void
1044
     */
1045 130
    protected function checkIfNamedForm()
1046
    {
1047 130
        if ($this->getFormOption('name')) {
1048 8
            $this->name = Arr::pull($this->formOptions, 'name', $this->name);
1049 8
        }
1050 130
    }
1051
1052
    /**
1053
     * Set up options on single field depending on form options.
1054
     *
1055
     * @param string $name
1056
     * @param $options
1057
     */
1058 66
    protected function setupFieldOptions($name, &$options)
1059
    {
1060 66
        $options['real_name'] = $name;
1061 66
    }
1062
1063
    /**
1064
     * Set namespace to model if form is named so the data is bound properly.
1065
     * Returns true if model is changed, otherwise false.
1066
     *
1067
     * @return bool
1068
     */
1069 21
    protected function setupNamedModel()
1070
    {
1071 21
        if (!$this->getModel() || !$this->getName()) {
1072 19
            return false;
1073
        }
1074
1075 3
        $dotName = $this->formHelper->transformToDotSyntax($this->getName());
1076 3
        $model = $this->formHelper->convertModelToArray($this->getModel());
1077 3
        $isCollectionFormModel = (bool) preg_match('/^.*\.\d+$/', $dotName);
1078 3
        $isCollectionPrototype = strpos($dotName, '__NAME__') !== false;
1079
1080 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 1076 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...
1081 1
            $newModel = [];
1082 1
            Arr::set($newModel, $dotName, $model);
1083 1
            $this->model = $newModel;
1084
1085 1
            return true;
1086
        }
1087
1088 2
        return false;
1089
    }
1090
1091
    /**
1092
     * Set form builder instance on helper so we can use it later.
1093
     *
1094
     * @param FormBuilder $formBuilder
1095
     * @return $this
1096
     */
1097 130
    public function setFormBuilder(FormBuilder $formBuilder)
1098
    {
1099 130
        $this->formBuilder = $formBuilder;
1100
1101 130
        return $this;
1102
    }
1103
1104
    /**
1105
     * Returns the instance of the FormBuilder.
1106
     *
1107
     * @return FormBuilder
1108
     */
1109 20
    public function getFormBuilder()
1110
    {
1111 20
        return $this->formBuilder;
1112
    }
1113
1114
    /**
1115
     * Set the Validator instance on this so we can use it later.
1116
     *
1117
     * @param ValidatorFactory $validator
1118
     * @return $this
1119
     */
1120 130
    public function setValidator(ValidatorFactory $validator)
1121
    {
1122 130
        $this->validatorFactory = $validator;
1123
1124 130
        return $this;
1125
    }
1126
1127
    /**
1128
     * Returns the validator instance.
1129
     *
1130
     * @return Validator
1131
     */
1132 1
    public function getValidator()
1133
    {
1134 1
        return $this->validator;
1135
    }
1136
1137
    /**
1138
     * Exclude some fields from rendering.
1139
     *
1140
     * @return $this
1141
     */
1142
    public function exclude(array $fields)
1143
    {
1144
        $this->exclude = array_merge($this->exclude, $fields);
1145
1146
        return $this;
1147
    }
1148
1149
    /**
1150
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1151
     *
1152
     * @param string $name
1153
     * @return string
1154
     */
1155 66
    protected function getFieldName($name)
1156
    {
1157 66
        $formName = $this->getName();
1158 66
        if ($formName !== null) {
1159 14
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1160 6
                return $this->formHelper->transformToBracketSyntax(
1161 6
                    $this->formHelper->transformToDotSyntax(
1162 6
                        $formName . '[' . $name . ']'
1163 6
                    )
1164 6
                );
1165
            }
1166
1167 11
            return $formName . '[' . $name . ']';
1168
        }
1169
1170 66
        return $name;
1171
    }
1172
1173
    /**
1174
     * Disable all fields in a form.
1175
     */
1176 1
    public function disableFields()
1177
    {
1178 1
        foreach ($this->fields as $field) {
1179 1
            $field->disable();
1180 1
        }
1181 1
    }
1182
1183
    /**
1184
     * Enable all fields in a form.
1185
     */
1186 1
    public function enableFields()
1187
    {
1188 1
        foreach ($this->fields as $field) {
1189 1
            $field->enable();
1190 1
        }
1191 1
    }
1192
1193
    /**
1194
     * Validate the form.
1195
     *
1196
     * @param array $validationRules
1197
     * @param array $messages
1198
     * @return Validator
1199
     */
1200 9
    public function validate($validationRules = [], $messages = [])
1201
    {
1202 9
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1203 9
        $rules = array_merge($fieldRules->getRules(), $validationRules);
1204 9
        $messages = array_merge($fieldRules->getMessages(), $messages);
1205
1206 9
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1207 9
        $this->validator->setAttributeNames($fieldRules->getAttributes());
1208
1209 9
        $this->eventDispatcher->dispatch(new BeforeFormValidation($this, $this->validator));
1210
1211 9
        return $this->validator;
1212
    }
1213
1214
    /**
1215
     * Get validation rules for the form.
1216
     *
1217
     * @param array $overrideRules
1218
     * @return array
1219
     */
1220 1
    public function getRules($overrideRules = [])
1221
    {
1222 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1223
1224 1
        return array_merge($fieldRules->getRules(), $overrideRules);
1225
    }
1226
1227
    /**
1228
     * Redirects to a destination when form is invalid.
1229
     *
1230
     * @param  string|null $destination The target url.
1231
     * @return HttpResponseException
1232
     */
1233 3
    public function redirectIfNotValid($destination = null)
1234
    {
1235 3
        if (! $this->isValid()) {
1236 3
            $response = redirect($destination);
1237
1238 3
            if (is_null($destination)) {
1239 2
                $response = $response->back();
1240 2
            }
1241
1242 3
            $response = $response->withErrors($this->getErrors(), $this->getErrorBag())->withInput();
1243
1244 3
            throw new HttpResponseException($response);
1245
        }
1246
    }
1247
1248
    /**
1249
     * Get all form field attributes, including child forms, in a flat array.
1250
     *
1251
     * @return array
1252
     */
1253 3
    public function getAllAttributes()
1254
    {
1255 3
        return $this->formHelper->mergeAttributes($this->fields);
1256
    }
1257
1258
    /**
1259
     * Check if the form is valid.
1260
     *
1261
     * @return bool
1262
     */
1263 9
    public function isValid()
1264
    {
1265 9
        if (!$this->validator) {
1266 8
            $this->validate();
1267 8
        }
1268
1269 9
        $isValid = !$this->validator->fails();
1270
1271 9
        $this->formHelper->alterValid($this, $this, $isValid);
1272
1273 9
        $this->eventDispatcher->dispatch(new AfterFormValidation($this, $this->validator, $isValid));
1274
1275 9
        return $isValid;
1276
    }
1277
1278
    /**
1279
     * Optionally change the validation result, and/or add error messages.
1280
     *
1281
     * @param Form $mainForm
1282
     * @param bool $isValid
1283
     * @return void|array
1284
     */
1285 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...
1286
    {
1287
        // return ['name' => ['Some other error about the Name field.']];
1288 9
    }
1289
1290
    /**
1291
     * Get validation errors.
1292
     *
1293
     * @return array
1294
     */
1295 8
    public function getErrors()
1296
    {
1297 8
        if (!$this->validator || !$this->validator instanceof Validator) {
1298 1
            throw new \InvalidArgumentException(
1299 1
                sprintf(
1300 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1301 1
                    get_class($this)
1302 1
                )
1303 1
            );
1304
        }
1305
1306 7
        return $this->validator->getMessageBag()->getMessages();
1307
    }
1308
1309
    /**
1310
     * Get all Request values from all fields, and nothing else.
1311
     *
1312
     * @param bool $with_nulls
1313
     * @return array
1314
     */
1315 3
    public function getFieldValues($with_nulls = true)
1316
    {
1317 3
        $request_values = $this->getRequest()->all();
1318
1319 3
        $values = [];
1320 3
        foreach ($this->getAllAttributes() as $attribute) {
1321 3
            $value = Arr::get($request_values, $attribute);
1322 3
            if ($with_nulls || $value !== null) {
1323 3
                Arr::set($values, $attribute, $value);
1324 3
            }
1325 3
        }
1326
1327
        // If this form is a child form, cherry pick a part
1328 3
        if ($prefix = $this->getName()) {
1329 1
            $prefix = $this->formHelper->transformToDotSyntax($prefix);
1330 1
            $values = Arr::get($values, $prefix);
1331 1
        }
1332
1333
        // Allow form-specific value alters
1334 3
        $this->formHelper->alterFieldValues($this, $values);
1335
1336 3
        return $values;
1337
    }
1338
1339
    /**
1340
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1341
     *
1342
     * @param array $values
1343
     * @return void
1344
     */
1345 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...
1346
    {
1347 3
    }
1348
1349
    /**
1350
     * Throw an exception indicating a field does not exist on the class.
1351
     *
1352
     * @param string $name
1353
     * @throws \InvalidArgumentException
1354
     * @return void
1355
     */
1356 2
    protected function fieldDoesNotExist($name)
1357
    {
1358 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1359
    }
1360
1361
    /**
1362
     * Method filterFields used as *Main* method for starting
1363
     * filtering and request field mutating process.
1364
     *
1365
     * @return \Kris\LaravelFormBuilder\Form
1366
     */
1367 130
    public function filterFields()
1368
    {
1369
        // If filtering is unlocked/allowed we can start with filtering process.
1370 130
        if (!$this->isFilteringLocked()) {
1371 130
            $filters = array_filter($this->getFilters());
1372
1373 130
            if (count($filters)) {
1374 1
                $dotForm = $this->formHelper->transformToDotSyntax($this->getName());
1375
1376 1
                $request = $this->getRequest();
1377 1
                $requestData = $request->all();
1378
1379 1
                foreach ($filters as $field => $fieldFilters) {
1380 1
                    $dotField = $this->formHelper->transformToDotSyntax($field);
1381 1
                    $fieldData = Arr::get($requestData, $dotField);
1382 1
                    if ($fieldData !== null) {
1383
                        // Assign current Raw/Unmutated value from request.
1384 1
                        $localDotField = preg_replace('#^' . preg_quote("$dotForm.", '#') . '#', '', $dotField);
1385 1
                        $localBracketField = $this->formHelper->transformToBracketSyntax($localDotField);
1386 1
                        $this->getField($localBracketField)->setRawValue($fieldData);
1387 1
                        foreach ($fieldFilters as $filter) {
1388 1
                            $filterObj = FilterResolver::instance($filter);
1389 1
                            $fieldData = $filterObj->filter($fieldData);
1390 1
                        }
1391 1
                        Arr::set($requestData, $dotField, $fieldData);
1392 1
                    }
1393 1
                }
1394
1395 1
                foreach ($requestData as $name => $value) {
1396 1
                    $request[$name] = $value;
1397 1
                }
1398 1
            }
1399 130
        }
1400
1401 130
        return $this;
1402
    }
1403
1404
    /**
1405
     * Method getFilters used to return array of all binded filters to form fields.
1406
     *
1407
     * @return array
1408
     */
1409 130
    public function getFilters()
1410
    {
1411 130
        $filters = [];
1412 130
        foreach ($this->getFields() as $field) {
1413 17
            $filters[$field->getName()] = $field->getFilters();
1414 130
        }
1415
1416 130
        return $filters;
1417
    }
1418
1419
    /**
1420
     * If lockFiltering is set to true then we will not
1421
     * filter fields and mutate request data binded to fields.
1422
     *
1423
     * @return \Kris\LaravelFormBuilder\Form
1424
     */
1425 1
    public function lockFiltering()
1426
    {
1427 1
        $this->lockFiltering = true;
1428 1
        return $this;
1429
    }
1430
1431
    /**
1432
     * Unlock fields filtering/mutating.
1433
     *
1434
     * @return \Kris\LaravelFormBuilder\Form
1435
     */
1436
    public function unlockFiltering()
1437
    {
1438
        $this->lockFiltering = false;
1439
        return $this;
1440
    }
1441
1442
    /**
1443
     * Method isFilteringLocked used to check
1444
     * if current filteringLocked property status is set to true.
1445
     *
1446
     * @return bool
1447
     */
1448 130
    public function isFilteringLocked()
1449
    {
1450 130
        return !$this->lockFiltering ? false : true;
1451
    }
1452
1453
    /**
1454
     * Method getRawValues returns Unfiltered/Unmutated fields -> values.
1455
     *
1456
     * @return array
1457
     */
1458
    public function getRawValues()
1459
    {
1460
        $rawValues = [];
1461
        foreach ($this->getFields() as $field) {
1462
            $rawValues[$field->getName()] = $field->getRawValue();
1463
        }
1464
1465
        return $rawValues;
1466
    }
1467
}
1468