Completed
Pull Request — master (#251)
by Rudie
11:38 queued 07:11
created

Form   F

Complexity

Total Complexity 110

Size/Duplication

Total Lines 1146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 94.67%

Importance

Changes 44
Bugs 8 Features 21
Metric Value
c 44
b 8
f 21
dl 0
loc 1146
ccs 302
cts 319
cp 0.9467
rs 1.913
wmc 110
lcom 1
cbo 14

69 Methods

Rating   Name   Duplication   Size   Complexity  
A buildForm() 0 3 1
A renderForm() 0 4 1
A renderRest() 0 6 1
A getFormOption() 0 4 1
A getMethod() 0 4 1
A getUrl() 0 4 1
A setClientValidationEnabled() 0 6 1
A setData() 0 4 1
A getRequest() 0 4 1
A setRequest() 0 6 1
A setValidator() 0 6 1
A makeField() 0 14 1
A addBefore() 0 15 1
A addAfter() 0 15 1
A has() 0 4 1
A getFormOptions() 0 4 1
A setFormOption() 0 6 1
A setFormOptions() 0 13 1
A setMethod() 0 6 1
A setUrl() 0 6 1
A getName() 0 4 1
A getModel() 0 4 1
A setModel() 0 10 1
A setupModel() 0 8 1
A getFields() 0 4 1
A __get() 0 6 2
A setEventDispatcher() 0 6 1
A setFormHelper() 0 6 1
A getFormHelper() 0 4 1
A addCustomField() 0 4 1
A haveErrorsEnabled() 0 4 1
A setErrorsEnabled() 0 6 1
A clientValidationEnabled() 0 4 1
A getData() 0 8 2
A addData() 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 validate() 0 13 1
A getRules() 0 6 1
A fieldDoesNotExist() 0 4 1
A rebuildForm() 0 18 3
A add() 0 12 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 getField() 0 8 2
A pullFromOptions() 0 6 2
A setName() 0 10 2
A getUnrenderedFields() 0 13 3
A checkIfNamedForm() 0 6 2
A exclude() 0 6 1
A getFieldName() 0 17 4
A disableFields() 0 6 2
A enableFields() 0 6 2
A redirectIfNotValid() 0 14 3
A isValid() 0 12 2
A getErrors() 0 13 3

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