Completed
Push — master ( 3ac451...8d1c67 )
by Kristijan
08:43 queued 07:16
created

Form   F

Complexity

Total Complexity 136

Size/Duplication

Total Lines 1355
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Test Coverage

Coverage 92.41%

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 1355
ccs 365
cts 395
cp 0.9241
rs 0.6314
wmc 136
lcom 1
cbo 16

81 Methods

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