Completed
Pull Request — master (#254)
by Rudie
07:09
created

Form::setEventDispatcher()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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