Completed
Push — master ( 7df444...936d32 )
by Kristijan
13:12 queued 09:40
created

Form   F

Complexity

Total Complexity 141

Size/Duplication

Total Lines 1399
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Test Coverage

Coverage 92.86%

Importance

Changes 0
Metric Value
dl 0
loc 1399
ccs 377
cts 406
cp 0.9286
rs 0.8
c 0
b 0
f 0
wmc 141
lcom 1
cbo 16

84 Methods

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

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

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

    return array();
}

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

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

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