Completed
Pull Request — master (#208)
by
unknown
04:47
created

Form   D

Complexity

Total Complexity 110

Size/Duplication

Total Lines 1114
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 42
Bugs 11 Features 20
Metric Value
wmc 110
c 42
b 11
f 20
lcom 1
cbo 9
dl 0
loc 1114
ccs 264
cts 264
cp 1
rs 4.4102

68 Methods

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