Completed
Pull Request — master (#578)
by
unknown
03:19
created

Form   F

Complexity

Total Complexity 149

Size/Duplication

Total Lines 1457
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Test Coverage

Coverage 93.38%

Importance

Changes 0
Metric Value
dl 0
loc 1457
ccs 367
cts 393
cp 0.9338
rs 0.8
c 0
b 0
f 0
wmc 149
lcom 1
cbo 18

86 Methods

Rating   Name   Duplication   Size   Complexity  
A buildForm() 0 3 1
A rebuildForm() 0 18 3
A makeField() 0 14 1
A add() 0 12 3
A addField() 0 15 4
A addBefore() 0 15 1
A addAfter() 0 15 1
A compose() 0 28 5
A remove() 0 10 4
A modify() 0 12 3
A renderForm() 0 4 1
A renderRest() 0 6 1
A renderUntil() 0 20 4
A getField() 0 8 2
A getErrorBag() 0 4 1
A has() 0 4 1
A getFormOptions() 0 4 1
A getFormOption() 0 4 1
A setFormOption() 0 6 1
A getConfig() 0 4 1
A setFormOptions() 0 14 1
A pullFromOptions() 0 6 2
A getMethod() 0 4 1
A setMethod() 0 6 1
A getUrl() 0 4 1
A setUrl() 0 6 1
A getName() 0 4 1
A setName() 0 10 2
A getModel() 0 4 1
A setModel() 0 8 1
A setupModel() 0 7 1
A getFields() 0 4 1
A __get() 0 6 2
A __isset() 0 4 1
A setEventDispatcher() 0 6 1
A setFormHelper() 0 6 1
A getFormHelper() 0 4 1
A addCustomField() 0 8 3
A haveErrorsEnabled() 0 4 1
A setErrorsEnabled() 0 6 1
A clientValidationEnabled() 0 4 1
A setClientValidationEnabled() 0 6 1
A setData() 0 4 1
A getData() 0 8 2
A addData() 0 8 2
A getRequest() 0 4 1
A setRequest() 0 6 1
A getTemplatePrefix() 0 8 2
A setTemplatePrefix() 0 6 1
A getLanguageName() 0 4 1
A setLanguageName() 0 6 1
A getTranslationTemplate() 0 4 1
A setTranslationTemplate() 0 6 1
A render() 0 18 1
A buildFormOptionsForFormBuilder() 0 16 4
A getTemplate() 0 4 1
A getUnrenderedFields() 0 13 3
A preventDuplicate() 0 6 2
A getFieldType() 0 6 1
A checkIfNamedForm() 0 6 2
A setupFieldOptions() 0 4 1
B setupNamedModel() 0 21 6
A setFormBuilder() 0 6 1
A getFormBuilder() 0 4 1
A setValidator() 0 6 1
A getValidator() 0 4 1
A exclude() 0 6 1
A getFieldName() 0 17 4
A disableFields() 0 6 2
A enableFields() 0 6 2
A validate() 0 13 1
A getRules() 0 6 1
A redirectIfNotValid() 0 14 3
A getAllAttributes() 0 4 1
A isValid() 0 14 2
A alterValid() 0 4 1
A getErrors() 0 13 3
A getFieldValues() 0 23 5
A alterFieldValues() 0 3 1
A fieldDoesNotExist() 0 4 1
B filterFields() 0 36 7
A getFilters() 0 9 2
A lockFiltering() 0 5 1
A unlockFiltering() 0 5 1
A isFilteringLocked() 0 4 2
A getRawValues() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like Form often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Form, and based on these observations, apply Extract Interface, too.

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