Completed
Push — master ( f95c98...4cd325 )
by Kristijan
9s
created

Form   F

Complexity

Total Complexity 108

Size/Duplication

Total Lines 1137
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 100%

Importance

Changes 44
Bugs 8 Features 21
Metric Value
c 44
b 8
f 21
dl 0
loc 1137
ccs 273
cts 273
cp 1
rs 1.913
wmc 108
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 checkIfNamedForm() 0 6 2
A setValidator() 0 6 1
A getRules() 0 6 1
A rebuildForm() 0 18 3
A makeField() 0 14 1
A add() 0 12 3
A addField() 0 15 4
A addBefore() 0 15 1
A addAfter() 0 15 1
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 has() 0 4 1
A getFormOptions() 0 4 1
A setFormOption() 0 6 1
A setFormOptions() 0 13 1
A pullFromOptions() 0 6 2
A setMethod() 0 6 1
A setUrl() 0 6 1
A getName() 0 4 1
A setName() 0 10 2
A getModel() 0 4 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 getUnrenderedFields() 0 13 3
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 exclude() 0 6 1
A setModel() 0 10 1
A getFieldName() 0 8 2
A disableFields() 0 6 2
A enableFields() 0 6 2
A validate() 0 13 1
A redirectIfNotValid() 0 14 3
A isValid() 0 12 2
A getErrors() 0 13 3
A fieldDoesNotExist() 0 4 1

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 14
    public function rebuildForm()
137
    {
138 14
        $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 14
        if (get_class($this) === 'Kris\LaravelFormBuilder\Form') {
142 13
            foreach ($this->fields as $name => $field) {
143
                // Remove any temp variables added in previous instance
144 5
                $options = array_except($field->getOptions(), 'tmp');
145 13
                $this->add($name, $field->getType(), $options);
146
            }
147
        } else {
148 3
            $this->buildForm();
149
        }
150 14
        $this->rebuilding = false;
151
152 14
        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 46
    protected function makeField($name, $type = 'text', array $options = [])
164
    {
165 46
        $this->setupFieldOptions($name, $options);
166
167 46
        $fieldName = $this->getFieldName($name);
168
169 46
        $fieldType = $this->getFieldType($type);
170
171 45
        $field = new $fieldType($fieldName, $type, $this, $options);
172
173 42
        $this->eventDispatcher->fire(new AfterFieldCreation($this, $field));
174
175 42
        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 48
    public function add($name, $type = 'text', array $options = [], $modify = false)
188
    {
189 48
        $this->formHelper->checkFieldName($name, get_class($this));
190
191 46
        if ($this->rebuilding && !$this->has($name)) {
192
            return $this;
193
        }
194
195 46
        $this->addField($this->makeField($name, $type, $options), $modify);
196
197 42
        return $this;
198
    }
199
200
    /**
201
     * Add a FormField to the form's fields
202
     *
203
     * @param FormField $field
204
     * @return $this
205
     */
206 42
    protected function addField(FormField $field, $modify = false)
207
    {
208 42
        if (!$modify && !$this->rebuilding) {
209 42
            $this->preventDuplicate($field->getRealName());
210
        }
211
212
213 42
        if ($field->getType() == 'file') {
214 3
            $this->formOptions['files'] = true;
215
        }
216
217 42
        $this->fields[$field->getRealName()] = $field;
218
219 42
        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
        } 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
        }
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
        }
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
            );
341
        }
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
        }
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 24
    public function getField($name)
410
    {
411 24
        if ($this->has($name)) {
412 23
            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 42
    public function has($name)
425
    {
426 42
        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
        }
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 51
    public function getName()
549
    {
550 51
        return $this->name;
551
    }
552
553
    /**
554
     * @param string $name
555
     * @param bool $rebuild
556
     *
557
     * @return $this
558
     */
559 8
    public function setName($name, $rebuild = true)
560
    {
561 8
        $this->name = $name;
562
563 8
        if ($rebuild) {
564 8
            $this->rebuildForm();
565
        }
566
567 8
        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 18
    public function getFields()
617
    {
618 18
        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 16
    public function clientValidationEnabled()
710
    {
711 16
        return $this->clientValidationEnabled;
712
    }
713
714
    /**
715
     * Enable/disable client validation
716
     *
717
     * @param boolean $enable
718
     * @return $this
719
     */
720 2
    public function setClientValidationEnabled($enable)
721
    {
722 2
        $this->clientValidationEnabled = (boolean) $enable;
723
724 2
        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 13
    public function getData($name = null, $default = null)
748
    {
749 13
        if (is_null($name)) {
750 12
            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 35
    public function getTemplatePrefix()
802
    {
803 35
        if ($this->templatePrefix !== null) {
804 4
            return $this->templatePrefix;
805
        }
806
807 31
        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 9
    public function setLanguageName($prefix)
840
    {
841 9
        $this->languageName = (string) $prefix;
842
843 9
        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
        }
898
899 2
        return $unrenderedFields;
900
    }
901
902
    /**
903
     * Prevent adding fields with same name
904
     *
905
     * @param string $name
906
     */
907 42
    protected function preventDuplicate($name)
908
    {
909 42
        if ($this->has($name)) {
910 1
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
911
        }
912 42
    }
913
914
    /**
915
     * @param string $type
916
     * @return string
917
     */
918 46
    protected function getFieldType($type)
919
    {
920 46
        $fieldType = $this->formHelper->getFieldType($type);
921
922 45
        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
        }
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 46
    protected function setupFieldOptions($name, &$options)
942
    {
943 46
        $options['real_name'] = $name;
944 46
    }
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 26
    protected function setupNamedModel()
953
    {
954 26
        if (!$this->getModel() || !$this->getName()) {
955 25
            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 46
    protected function getFieldName($name)
1025
    {
1026 46
        if ($this->getName() !== null) {
1027 10
            return $this->getName().'['.$name.']';
1028
        }
1029
1030 46
        return $name;
1031
    }
1032
1033
    /**
1034
     * Disable all fields in a form
1035
     */
1036 1
    public function disableFields()
1037
    {
1038 1
        foreach ($this->fields as $field) {
1039 1
            $field->disable();
1040
        }
1041 1
    }
1042
1043
    /**
1044
     * Enable all fields in a form
1045
     */
1046 1
    public function enableFields()
1047
    {
1048 1
        foreach ($this->fields as $field) {
1049 1
            $field->enable();
1050
        }
1051 1
    }
1052
1053
    /**
1054
     * Validate the form
1055
     *
1056
     * @param array $validationRules
1057
     * @param array $messages
1058
     * @return Validator
1059
     */
1060 7
    public function validate($validationRules = [], $messages = [])
1061
    {
1062 7
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1063 7
        $rules = array_merge($fieldRules['rules'], $validationRules);
1064 7
        $messages = array_merge($fieldRules['error_messages'], $messages);
1065
1066 7
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1067 7
        $this->validator->setAttributeNames($fieldRules['attributes']);
1068
1069 7
        $this->eventDispatcher->fire(new BeforeFormValidation($this, $this->validator));
1070
1071 7
        return $this->validator;
1072
    }
1073
1074
    /**
1075
     * Get validatdion rules for the form
1076
     *
1077
     * @param array $overrideRules
1078
     * @return array
1079
     */
1080 1
    public function getRules($overrideRules = [])
1081
    {
1082 1
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1083
1084 1
        return array_merge($fieldRules['rules'], $overrideRules);
1085
    }
1086
1087 2
    public function redirectIfNotValid($destination = null)
1088
    {
1089 2
        if (! $this->isValid()) {
1090 2
            $response = redirect($destination);
1091
1092 2
            if (is_null($destination)) {
1093 1
                $response = $response->back();
1094
            }
1095
1096 2
            $response = $response->withErrors($this->getErrors())->withInput();
1097
1098 2
            throw new HttpResponseException($response);
1099
        }
1100
    }
1101
1102
    /**
1103
     * Check if the form is valid
1104
     *
1105
     * @return bool
1106
     */
1107 7
    public function isValid()
1108
    {
1109 7
        if (!$this->validator) {
1110 6
            $this->validate();
1111
        }
1112
1113 7
        $isValid = !$this->validator->fails();
1114
1115 7
        $this->eventDispatcher->fire(new AfterFormValidation($this, $this->validator, $isValid));
1116
1117 7
        return $isValid;
1118
    }
1119
1120
    /**
1121
     * Get validation errors
1122
     *
1123
     * @return array
1124
     */
1125 6
    public function getErrors()
1126
    {
1127 6
        if (!$this->validator || !$this->validator instanceof Validator) {
1128 1
            throw new \InvalidArgumentException(
1129
                sprintf(
1130 1
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1131
                    get_class($this)
1132
                )
1133
            );
1134
        }
1135
1136 5
        return $this->validator->getMessageBag()->getMessages();
1137
    }
1138
1139
    /**
1140
     * Throw an exception indicating a field does not exist on the class
1141
     *
1142
     * @param string $name
1143
     * @throws \InvalidArgumentException
1144
     */
1145 2
    protected function fieldDoesNotExist($name)
1146
    {
1147 2
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1148
    }
1149
}
1150