Completed
Push — master ( 5c063d...442463 )
by Kristijan
18:00 queued 03:02
created

Form::getNameKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Kris\LaravelFormBuilder;
4
5
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
6
use Illuminate\Contracts\Validation\Factory as ValidatorFactory;
7
use Illuminate\Contracts\Validation\Validator;
8
use Illuminate\Http\Exceptions\HttpResponseException;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\Arr;
11
use Kris\LaravelFormBuilder\Events\AfterFieldCreation;
12
use Kris\LaravelFormBuilder\Events\AfterFormValidation;
13
use Kris\LaravelFormBuilder\Events\BeforeFormValidation;
14
use Kris\LaravelFormBuilder\Fields\FormField;
15
use Kris\LaravelFormBuilder\Filters\FilterResolver;
16
17
class Form
18
{
19
    /**
20
     * All fields that are added.
21
     *
22
     * @var array
23
     */
24
    protected $fields = [];
25
26
    /**
27
     * Model to use.
28
     *
29
     * @var mixed
30
     */
31
    protected $model = [];
32
33
    /**
34
     * @var EventDispatcher
35
     */
36
    protected $eventDispatcher;
37
38
    /**
39
     * @var FormHelper
40
     */
41
    protected $formHelper;
42
43
    /**
44
     * Form options.
45
     *
46
     * @var array
47
     */
48
    protected $formOptions = [
49
        'method' => 'GET',
50
        'url' => null
51
    ];
52
53
    /**
54
     * Form specific configuration.
55
     *
56
     * @var array
57
     */
58
    protected $formConfig = [];
59
60
    /**
61
     * Additional data which can be used to build fields.
62
     *
63
     * @var array
64
     */
65
    protected $data = [];
66
67
    /**
68
     * Wether errors for each field should be shown when calling form($form) or form_rest($form).
69
     *
70
     * @var bool
71
     */
72
    protected $showFieldErrors = true;
73
74
    /**
75
     * Enable html5 validation.
76
     *
77
     * @var bool
78
     */
79
    protected $clientValidationEnabled = true;
80
81
    /**
82
     * Name of the parent form if any.
83
     *
84
     * @var string|null
85
     */
86
    protected $name = null;
87
88
    /**
89
     * @var FormBuilder
90
     */
91
    protected $formBuilder;
92
93
    /**
94
     * @var ValidatorFactory
95
     */
96
    protected $validatorFactory;
97
98
    /**
99
     * @var Validator
100
     */
101
    protected $validator = null;
102
103
    /**
104
     * @var Request
105
     */
106
    protected $request;
107
108
    /**
109
     * List of fields to not render.
110
     *
111
     * @var array
112
     **/
113
    protected $exclude = [];
114
115
    /**
116
     * Wether the form is beign rebuild.
117
     *
118
     * @var bool
119
     */
120
    protected $rebuilding = false;
121
122
    /**
123
     * @var string
124
     */
125
    protected $templatePrefix;
126
127
    /**
128
     * @var string
129
     */
130
    protected $languageName;
131
132
    /**
133
     * @var string
134
     */
135
    protected $translationTemplate;
136
137
    /**
138
     * To filter and mutate request values or not.
139
     *
140
     * @var bool
141
     */
142
    protected $lockFiltering = false;
143
144
    /**
145
     * Define the error bag name for the form.
146
     *
147
     * @var string
148
     */
149
    protected $errorBag = 'default';
150
151
    /**
152
     * Build the form.
153
     *
154
     * @return mixed
155
     */
156 3
    public function buildForm()
157
    {
158 3
    }
159
160
    /**
161
     * Rebuild the form from scratch.
162
     *
163
     * @return $this
164
     */
165 19
    public function rebuildForm()
166
    {
167 19
        $this->rebuilding = true;
168
        // If form is plain, buildForm method is empty, so we need to take
169
        // existing fields and add them again
170 19
        if (get_class($this) === 'Kris\LaravelFormBuilder\Form') {
171 18
            foreach ($this->fields as $name => $field) {
172
                // Remove any temp variables added in previous instance
173 7
                $options =  Arr::except($field->getOptions(), 'tmp');
174 7
                $this->add($name, $field->getType(), $options);
175 18
            }
176 18
        } else {
177 3
            $this->buildForm();
178
        }
179 19
        $this->rebuilding = false;
180
181 19
        return $this;
182
    }
183
184
    /**
185
     * Create the FormField object.
186
     *
187
     * @param string $name
188
     * @param string $type
189
     * @param array  $options
190
     * @return FormField
191
     */
192 66
    protected function makeField($name, $type = 'text', array $options = [])
193
    {
194 66
        $this->setupFieldOptions($name, $options);
195
196 66
        $fieldName = $this->getFieldName($name);
197
198 66
        $fieldType = $this->getFieldType($type);
199
200 65
        $field = new $fieldType($fieldName, $type, $this, $options);
201
202 62
        $this->eventDispatcher->dispatch(new AfterFieldCreation($this, $field));
203
204 62
        return $field;
205
    }
206
207
    /**
208
     * Create a new field and add it to the form.
209
     *
210
     * @param string $name
211
     * @param string $type
212
     * @param array  $options
213
     * @param bool   $modify
214
     * @return $this
215
     */
216 68
    public function add($name, $type = 'text', array $options = [], $modify = false)
217
    {
218 68
        $this->formHelper->checkFieldName($name, get_class($this));
219
220 66
        if ($this->rebuilding && !$this->has($name)) {
221
            return $this;
222
        }
223
224 66
        $this->addField($this->makeField($name, $type, $options), $modify);
225
226 62
        return $this;
227
    }
228
229
    /**
230
     * Add a FormField to the form's fields.
231
     *
232
     * @param FormField $field
233
     * @return $this
234
     */
235 62
    protected function addField(FormField $field, $modify = false)
236
    {
237 62
        if (!$modify && !$this->rebuilding) {
238 62
            $this->preventDuplicate($field->getRealName());
239 62
        }
240
241
242 62
        if ($field->getType() == 'file') {
243 3
            $this->formOptions['files'] = true;
244 3
        }
245
246 62
        $this->fields[$field->getRealName()] = $field;
247
248 62
        return $this;
249
    }
250
251
    /**
252
     * Add field before another field.
253
     *
254
     * @param string  $name         Name of the field before which new field is added.
255
     * @param string  $fieldName    Field name which will be added.
256
     * @param string  $type
257
     * @param array   $options
258
     * @param bool $modify
259
     * @return $this
260
     */
261 1
    public function addBefore($name, $fieldName, $type = 'text', $options = [], $modify = false)
262
    {
263 1
        $offset = array_search($name, array_keys($this->fields));
264
265 1
        $beforeFields = array_slice($this->fields, 0, $offset);
266 1
        $afterFields = array_slice($this->fields, $offset);
267
268 1
        $this->fields = $beforeFields;
269
270 1
        $this->add($fieldName, $type, $options, $modify);
271
272 1
        $this->fields += $afterFields;
273
274 1
        return $this;
275
    }
276
277
    /**
278
     * Add field before another field.
279
     *
280
     * @param string  $name         Name of the field after which new field is added.
281
     * @param string  $fieldName    Field name which will be added.
282
     * @param string  $type
283
     * @param array   $options
284
     * @param bool $modify
285
     * @return $this
286
     */
287 1
    public function addAfter($name, $fieldName, $type = 'text', $options = [], $modify = false)
288
    {
289 1
        $offset = array_search($name, array_keys($this->fields));
290
291 1
        $beforeFields = array_slice($this->fields, 0, $offset + 1);
292 1
        $afterFields = array_slice($this->fields, $offset + 1);
293
294 1
        $this->fields = $beforeFields;
295
296 1
        $this->add($fieldName, $type, $options, $modify);
297
298 1
        $this->fields += $afterFields;
299
300 1
        return $this;
301
    }
302
303
    /**
304
     * Take another form and add it's fields directly to this form.
305
     *
306
     * @param mixed   $class        Form to merge.
307
     * @param array   $options
308
     * @param boolean $modify
309
     * @return $this
310
     */
311 1
    public function compose($class, array $options = [], $modify = false)
312
    {
313 1
        $options['class'] = $class;
314
315
        // If we pass a ready made form just extract the fields.
316 1
        if ($class instanceof Form) {
317 1
            $fields = $class->getFields();
318 1
        } elseif ($class instanceof Fields\ChildFormType) {
319
            $fields = $class->getForm()->getFields();
320
        } elseif (is_string($class)) {
321
            // If its a string of a class make it the usual way.
322
            $options['model'] = $this->model;
323
            $options['name'] = $this->name;
324
325
            $form = $this->formBuilder->create($class, $options);
326
            $fields = $form->getFields();
327
        } else {
328
            throw new \InvalidArgumentException(
329
                "[{$class}] is invalid. Please provide either a full class name, Form or ChildFormType"
330
            );
331
        }
332
333 1
        foreach ($fields as $field) {
334 1
            $this->addField($field, $modify);
335 1
        }
336
337 1
        return $this;
338
    }
339
340
    /**
341
     * Remove field with specified name from the form.
342
     *
343
     * @param string|string[] $names
344
     * @return $this
345
     */
346 2
    public function remove($names)
347
    {
348 2
        foreach (is_array($names) ? $names : func_get_args() as $name) {
349 2
            if ($this->has($name)) {
350 2
                unset($this->fields[$name]);
351 2
            }
352 2
        }
353
354 2
        return $this;
355
    }
356
357
    /**
358
     * Take only the given fields from the form.
359
     *
360
     * @param string|string[] $fieldNames
361
     * @return $this
362
     */
363 1
    public function only($fieldNames)
364
    {
365 1
        $newFields = [];
366
367 1
        foreach (is_array($fieldNames) ? $fieldNames : func_get_args() as $fieldName) {
368 1
            $newFields[$fieldName] = $this->getField($fieldName);
369 1
        }
370
371 1
        $this->fields = $newFields;
372
373 1
        return $this;
374
    }
375
376
    /**
377
     * Modify existing field. If it doesn't exist, it is added to form.
378
     *
379
     * @param string $name
380
     * @param string $type
381
     * @param array  $options
382
     * @param bool   $overwriteOptions
383
     * @return Form
384
     */
385 1
    public function modify($name, $type = 'text', array $options = [], $overwriteOptions = false)
386
    {
387
        // If we don't want to overwrite options, we merge them with old options.
388 1
        if ($overwriteOptions === false && $this->has($name)) {
389 1
            $options = $this->formHelper->mergeOptions(
390 1
                $this->getField($name)->getOptions(),
391
                $options
392 1
            );
393 1
        }
394
395 1
        return $this->add($name, $type, $options, true);
396
    }
397
398
    /**
399
     * Render full form.
400
     *
401
     * @param array $options
402
     * @param bool  $showStart
403
     * @param bool  $showFields
404
     * @param bool  $showEnd
405
     * @return string
406
     */
407 7
    public function renderForm(array $options = [], $showStart = true, $showFields = true, $showEnd = true)
408
    {
409 7
        return $this->render($options, $this->fields, $showStart, $showFields, $showEnd);
0 ignored issues
show
Documentation introduced by
$this->fields is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
410
    }
411
412
    /**
413
     * Render rest of the form.
414
     *
415
     * @param bool $showFormEnd
416
     * @param bool $showFields
417
     * @return string
418
     */
419 1
    public function renderRest($showFormEnd = true, $showFields = true)
420
    {
421 1
        $fields = $this->getUnrenderedFields();
422
423 1
        return $this->render([], $fields, false, $showFields, $showFormEnd);
0 ignored issues
show
Documentation introduced by
$fields is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
424
    }
425
426
    /**
427
     * Renders the rest of the form up until the specified field name.
428
     *
429
     * @param string $field_name
430
     * @param bool   $showFormEnd
431
     * @param bool   $showFields
432
     * @return string
433
     */
434 2
    public function renderUntil($field_name, $showFormEnd = true, $showFields = true)
435
    {
436 2
        if (!$this->has($field_name)) {
437 1
            $this->fieldDoesNotExist($field_name);
438
        }
439
440 1
        $fields = $this->getUnrenderedFields();
441
442 1
        $i = 1;
443 1
        foreach ($fields as $key => $value) {
444 1
            if ($value->getRealName() == $field_name) {
445 1
                break;
446
            }
447 1
            $i++;
448 1
        }
449
450 1
        $fields = array_slice($fields, 0, $i, true);
451
452 1
        return $this->render([], $fields, false, $showFields, $showFormEnd);
0 ignored issues
show
Documentation introduced by
$fields is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
453
    }
454
455
    /**
456
     * Get single field instance from form object.
457
     *
458
     * @param string $name
459
     * @return FormField
460
     */
461 36
    public function getField($name)
462
    {
463 36
        if ($this->has($name)) {
464 35
            return $this->fields[$name];
465
        }
466
467 1
        $this->fieldDoesNotExist($name);
468
    }
469
470 102
    public function getErrorBag()
471
    {
472 102
        return $this->errorBag;
473
    }
474
475
    /**
476
     * Check if form has field.
477
     *
478
     * @param string $name
479
     * @return bool
480
     */
481 62
    public function has($name)
482
    {
483 62
        return array_key_exists($name, $this->fields);
484
    }
485
486
    /**
487
     * Get all form options.
488
     *
489
     * @return array
490
     */
491 2
    public function getFormOptions()
492
    {
493 2
        return $this->formOptions;
494
    }
495
496
    /**
497
     * Get single form option.
498
     *
499
     * @param string $option
500
     * @param mixed|null $default
501
     * @return mixed
502
     */
503 130
    public function getFormOption($option, $default = null)
504
    {
505 130
        return Arr::get($this->formOptions, $option, $default);
506
    }
507
508
    /**
509
     * Set single form option on form.
510
     *
511
     * @param string $option
512
     * @param mixed $value
513
     *
514
     * @return $this
515
     */
516 2
    public function setFormOption($option, $value)
517
    {
518 2
        $this->formOptions[$option] = $value;
519
520 2
        return $this;
521
    }
522
523
    /**
524
     * Get the passed config key using the custom
525
     * form config, if any.
526
     *
527
     * @param string $key
528
     * @param mixed $default
529
     *
530
     * @return mixed
531
     */
532 104
    public function getConfig($key = null, $default = null)
533
    {
534 104
        return $this->formHelper->getConfig($key, $default, $this->formConfig);
535
    }
536
537
    /**
538
     * Set form options.
539
     *
540
     * @param array $formOptions
541
     * @return $this
542
     */
543 130
    public function setFormOptions(array $formOptions)
544
    {
545 130
        $this->formOptions = $this->formHelper->mergeOptions($this->formOptions, $formOptions);
546 130
        $this->checkIfNamedForm();
547 130
        $this->pullFromOptions('data', 'addData');
548 130
        $this->pullFromOptions('model', 'setupModel');
549 130
        $this->pullFromOptions('errors_enabled', 'setErrorsEnabled');
550 130
        $this->pullFromOptions('client_validation', 'setClientValidationEnabled');
551 130
        $this->pullFromOptions('template_prefix', 'setTemplatePrefix');
552 130
        $this->pullFromOptions('language_name', 'setLanguageName');
553 130
        $this->pullFromOptions('translation_template', 'setTranslationTemplate');
554
555 130
        return $this;
556
    }
557
558
    /**
559
     * Get an option from provided options and call method with that value.
560
     *
561
     * @param string $name
562
     * @param string $method
563
     */
564 130
    protected function pullFromOptions($name, $method)
565
    {
566 130
        if (Arr::get($this->formOptions, $name) !== null) {
567 20
            $this->{$method}(Arr::pull($this->formOptions, $name));
568 20
        }
569 130
    }
570
571
    /**
572
     * Get form http method.
573
     *
574
     * @return string
575
     */
576 3
    public function getMethod()
577
    {
578 3
        return $this->formOptions['method'];
579
    }
580
581
    /**
582
     * Set form http method.
583
     *
584
     * @param string $method
585
     * @return $this
586
     */
587 1
    public function setMethod($method)
588
    {
589 1
        $this->formOptions['method'] = $method;
590
591 1
        return $this;
592
    }
593
594
    /**
595
     * Get form action url.
596
     *
597
     * @return string
598
     */
599 3
    public function getUrl()
600
    {
601 3
        return $this->formOptions['url'];
602
    }
603
604
    /**
605
     * Set form action url.
606
     *
607
     * @param string $url
608
     * @return $this
609
     */
610 1
    public function setUrl($url)
611
    {
612 1
        $this->formOptions['url'] = $url;
613
614 1
        return $this;
615
    }
616
617
    /**
618
     * Returns the name of the form.
619
     *
620
     * @return string|null
621
     */
622 70
    public function getName()
623
    {
624 70
        return $this->name;
625
    }
626
627
    /**
628
     * Get dot notation key for the form.
629
     *
630
     * @return string
631
     **/
632
    public function getNameKey()
633
    {
634 12
        return $this->formHelper->transformToDotSyntax($this->name);
635
    }
636 12
637
    /**
638 12
     * Set the name of the form.
639 12
     *
640 12
     * @param string $name
641
     * @param bool $rebuild
642 12
     * @return $this
643
     */
644
    public function setName($name, $rebuild = true)
645
    {
646
        $this->name = $name;
647
648
        if ($rebuild) {
649
            $this->rebuildForm();
650 97
        }
651
652 97
        return $this;
653
    }
654
655
    /**
656
     * Get model that is bind to form object.
657
     *
658
     * @return mixed
659
     */
660
    public function getModel()
661
    {
662 17
        return $this->model;
663
    }
664 17
665
    /**
666 17
     * Set model to form object.
667
     *
668 17
     * @param mixed $model
669
     * @return $this
670
     * @deprecated deprecated since 1.6.31, will be removed in 1.7 - pass model as option when creating a form
671
     */
672
    public function setModel($model)
673
    {
674
        $this->model = $model;
675
676 12
        $this->rebuildForm();
677
678 12
        return $this;
679 12
    }
680
681 12
    /**
682
     * Setup model for form, add namespace if needed for child forms.
683
     *
684
     * @return $this
685
     */
686
    protected function setupModel($model)
687
    {
688
        $this->model = $model;
689 130
        $this->setupNamedModel();
690
691 130
        return $this;
692
    }
693
694
    /**
695
     * Get all fields.
696
     *
697
     * @return FormField[]
698
     */
699
    public function getFields()
700 20
    {
701
        return $this->fields;
702 20
    }
703 19
704
    /**
705 3
     * Get field dynamically.
706
     *
707
     * @param string $name
708
     * @return FormField
709
     */
710
    public function __get($name)
711
    {
712
        if ($this->has($name)) {
713
            return $this->getField($name);
714
        }
715
    }
716
717
    /**
718
     * Check if field exists when fetched using magic methods.
719
     *
720
     * @param string $name
721
     * @return bool
722
     */
723
    public function __isset($name)
724 130
    {
725
        return $this->has($name);
726 130
    }
727
728 130
    /**
729
     * Set the Event Dispatcher to fire Laravel events.
730
     *
731
     * @param EventDispatcher $eventDispatcher
732
     * @return $this
733
     */
734
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
735
    {
736
        $this->eventDispatcher = $eventDispatcher;
737 130
738
        return $this;
739 130
    }
740
741 130
    /**
742
     * Set the form helper only on first instantiation.
743
     *
744
     * @param FormHelper $formHelper
745
     * @return $this
746
     */
747
    public function setFormHelper(FormHelper $formHelper)
748
    {
749 102
        $this->formHelper = $formHelper;
750
751 102
        return $this;
752
    }
753
754
    /**
755
     * Get form helper.
756
     *
757
     * @return FormHelper
758
     */
759
    public function getFormHelper()
760 2
    {
761
        return $this->formHelper;
762 2
    }
763
764
    /**
765
     * Add custom field.
766 2
     *
767 2
     * @param $name
768
     * @param $class
769
     */
770
    public function addCustomField($name, $class)
771
    {
772
        if ($this->rebuilding && $this->formHelper->hasCustomField($name)) {
773
            return $this;
774 102
        }
775
776 102
        $this->formHelper->addCustomField($name, $class);
777
    }
778
779
    /**
780
     * Returns wether form errors should be shown under every field.
781
     *
782
     * @return bool
783
     */
784
    public function haveErrorsEnabled()
785 1
    {
786
        return $this->showFieldErrors;
787 1
    }
788
789 1
    /**
790
     * Enable or disable showing errors under fields
791
     *
792
     * @param bool $enabled
793
     * @return $this
794
     */
795
    public function setErrorsEnabled($enabled)
796
    {
797 102
        $this->showFieldErrors = (bool) $enabled;
798
799 102
        return $this;
800
    }
801
802
    /**
803
     * Is client validation enabled?
804
     *
805
     * @return bool
806
     */
807
    public function clientValidationEnabled()
808 2
    {
809
        return $this->clientValidationEnabled;
810 2
    }
811
812 2
    /**
813
     * Enable/disable client validation.
814
     *
815
     * @param bool $enable
816
     * @return $this
817
     */
818
    public function setClientValidationEnabled($enable)
819
    {
820
        $this->clientValidationEnabled = (bool) $enable;
821
822
        return $this;
823 1
    }
824
825 1
    /**
826 1
     * Add any aditional data that field needs (ex. array of choices).
827
     *
828
     * @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
829
     * will be switched to protected in 1.7.
830
     * @param string $name
831
     * @param mixed $data
832
     */
833
    public function setData($name, $data)
834
    {
835 20
        $this->data[$name] = $data;
836
    }
837 20
838 19
    /**
839
     * Get single additional data.
840
     *
841 1
     * @param string $name
842
     * @param null   $default
843
     * @return mixed
844
     */
845
    public function getData($name = null, $default = null)
846
    {
847
        if (is_null($name)) {
848
            return $this->data;
849
        }
850
851
        return Arr::get($this->data, $name, $default);
852 130
    }
853
854 130
    /**
855 1
     * Add multiple peices of data at once.
856 130
     *
857
     * @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
858 130
     * will be switched to protected in 1.7.
859
     * @param $data
860
     * @return $this
861
     **/
862
    public function addData(array $data)
863
    {
864
        foreach ($data as $key => $value) {
865
            $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...
866 102
        }
867
868 102
        return $this;
869
    }
870
871
    /**
872
     * Get current request.
873
     *
874
     * @return \Illuminate\Http\Request
875
     */
876
    public function getRequest()
877 130
    {
878
        return $this->request;
879 130
    }
880
881 130
    /**
882
     * Set request on form.
883
     *
884
     * @param Request $request
885
     * @return $this
886
     */
887
    public function setRequest(Request $request)
888
    {
889 39
        $this->request = $request;
890
891 39
        return $this;
892 4
    }
893
894
    /**
895 35
     * Get template prefix that is prepended to all template paths.
896
     *
897
     * @return string
898
     */
899
    public function getTemplatePrefix()
900
    {
901
        if ($this->templatePrefix !== null) {
902
            return $this->templatePrefix;
903
        }
904 4
905
        return $this->getConfig('template_prefix');
906 4
    }
907
908 4
    /**
909
     * Set a template prefix for the form and its fields.
910
     *
911
     * @param string $prefix
912
     * @return $this
913
     */
914
    public function setTemplatePrefix($prefix)
915
    {
916 99
        $this->templatePrefix = (string) $prefix;
917
918 99
        return $this;
919
    }
920
921
    /**
922
     * Get the language name.
923
     *
924
     * @return string
925
     */
926
    public function getLanguageName()
927 13
    {
928
        return $this->languageName;
929 13
    }
930
931 13
    /**
932
     * Set a language name, used as prefix for translated strings.
933
     *
934
     * @param string $prefix
935
     * @return $this
936
     */
937
    public function setLanguageName($prefix)
938
    {
939 101
        $this->languageName = (string) $prefix;
940
941 101
        return $this;
942
    }
943
944
    /**
945
     * Get the translation template.
946
     *
947
     * @return string
948
     */
949
    public function getTranslationTemplate()
950 11
    {
951
        return $this->translationTemplate;
952 11
    }
953
954 11
    /**
955
     * Set a translation template, used to determine labels for fields.
956
     *
957
     * @param string $template
958
     * @return $this
959
     */
960
    public function setTranslationTemplate($template)
961
    {
962
        $this->translationTemplate = (string) $template;
963
964
        return $this;
965
    }
966
967 9
    /**
968
     * Render the form.
969 9
     *
970
     * @param array $options
971 9
     * @param string $fields
972
     * @param bool $showStart
973 9
     * @param bool $showFields
974 9
     * @param bool $showEnd
975 9
     * @return string
976 9
     */
977 9
    protected function render($options, $fields, $showStart, $showFields, $showEnd)
978 9
    {
979 9
        $formOptions = $this->formHelper->mergeOptions($this->formOptions, $options);
980 9
981 9
        $this->setupNamedModel();
982
983
        return $this->formHelper->getView()
984
            ->make($this->getTemplate())
985
            ->with(compact('showStart', 'showFields', 'showEnd'))
986
            ->with('formOptions', $formOptions)
987
            ->with('fields', $fields)
988
            ->with('model', $this->getModel())
989 9
            ->with('exclude', $this->exclude)
990
            ->with('form', $this)
991 9
            ->render();
992
    }
993
994
    /**
995
     * Get template from options if provided, otherwise fallback to config.
996
     *
997
     * @return mixed
998
     */
999 2
    protected function getTemplate()
1000
    {
1001 2
        return $this->getTemplatePrefix() . $this->getFormOption('template', $this->getConfig('form'));
1002
    }
1003 2
1004 2
    /**
1005 2
     * Get all fields that are not rendered.
1006 2
     *
1007
     * @return array
1008 2
     */
1009
    protected function getUnrenderedFields()
1010 2
    {
1011
        $unrenderedFields = [];
1012
1013
        foreach ($this->fields as $field) {
1014
            if (!$field->isRendered()) {
1015
                $unrenderedFields[] = $field;
1016
                continue;
1017
            }
1018
        }
1019
1020 62
        return $unrenderedFields;
1021
    }
1022 62
1023 1
    /**
1024
     * Prevent adding fields with same name.
1025 62
     *
1026
     * @param string $name
1027
     * @throws \InvalidArgumentException
1028
     * @return void
1029
     */
1030
    protected function preventDuplicate($name)
1031
    {
1032
        if ($this->has($name)) {
1033 66
            throw new \InvalidArgumentException('Field ['.$name.'] already exists in the form '.get_class($this));
1034
        }
1035 66
    }
1036
1037 65
    /**
1038
     * Returns and checks the type of the field.
1039
     *
1040
     * @param string $type
1041
     * @return string
1042
     */
1043
    protected function getFieldType($type)
1044
    {
1045 130
        $fieldType = $this->formHelper->getFieldType($type);
1046
1047 130
        return $fieldType;
1048 8
    }
1049 8
1050 130
    /**
1051
     * Check if form is named form.
1052
     *
1053
     * @return void
1054
     */
1055
    protected function checkIfNamedForm()
1056
    {
1057
        if ($this->getFormOption('name')) {
1058 66
            $this->name = Arr::pull($this->formOptions, 'name', $this->name);
1059
        }
1060 66
    }
1061 66
1062
    /**
1063
     * Set up options on single field depending on form options.
1064
     *
1065
     * @param string $name
1066
     * @param $options
1067
     */
1068
    protected function setupFieldOptions($name, &$options)
1069 21
    {
1070
        $options['real_name'] = $name;
1071 21
    }
1072 19
1073
    /**
1074
     * Set namespace to model if form is named so the data is bound properly.
1075 3
     * Returns true if model is changed, otherwise false.
1076 3
     *
1077 3
     * @return bool
1078 3
     */
1079
    protected function setupNamedModel()
1080 3
    {
1081 1
        if (!$this->getModel() || !$this->getName()) {
1082 1
            return false;
1083 1
        }
1084
1085 1
        $dotName = $this->getNameKey();
1086
        $model = $this->formHelper->convertModelToArray($this->getModel());
1087
        $isCollectionFormModel = (bool) preg_match('/^.*\.\d+$/', $dotName);
1088 2
        $isCollectionPrototype = strpos($dotName, '__NAME__') !== false;
1089
1090
        if (!Arr::get($model, $dotName) && !$isCollectionFormModel && !$isCollectionPrototype) {
0 ignored issues
show
Bug introduced by
It seems like $model defined by $this->formHelper->conve...rray($this->getModel()) on line 1086 can also be of type null or object; however, Illuminate\Support\Arr::get() does only seem to accept object<ArrayAccess>|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1091
            $newModel = [];
1092
            Arr::set($newModel, $dotName, $model);
1093
            $this->model = $newModel;
1094
1095
            return true;
1096
        }
1097 130
1098
        return false;
1099 130
    }
1100
1101 130
    /**
1102
     * Set form builder instance on helper so we can use it later.
1103
     *
1104
     * @param FormBuilder $formBuilder
1105
     * @return $this
1106
     */
1107
    public function setFormBuilder(FormBuilder $formBuilder)
1108
    {
1109 20
        $this->formBuilder = $formBuilder;
1110
1111 20
        return $this;
1112
    }
1113
1114
    /**
1115
     * Returns the instance of the FormBuilder.
1116
     *
1117
     * @return FormBuilder
1118
     */
1119
    public function getFormBuilder()
1120 130
    {
1121
        return $this->formBuilder;
1122 130
    }
1123
1124 130
    /**
1125
     * Set the Validator instance on this so we can use it later.
1126
     *
1127
     * @param ValidatorFactory $validator
1128
     * @return $this
1129
     */
1130
    public function setValidator(ValidatorFactory $validator)
1131
    {
1132 1
        $this->validatorFactory = $validator;
1133
1134 1
        return $this;
1135
    }
1136
1137
    /**
1138
     * Returns the validator instance.
1139
     *
1140
     * @return Validator
1141
     */
1142
    public function getValidator()
1143
    {
1144
        return $this->validator;
1145
    }
1146
1147
    /**
1148
     * Exclude some fields from rendering.
1149
     *
1150
     * @return $this
1151
     */
1152
    public function exclude(array $fields)
1153
    {
1154
        $this->exclude = array_merge($this->exclude, $fields);
1155 66
1156
        return $this;
1157 66
    }
1158 66
1159 14
    /**
1160 6
     * If form is named form, modify names to be contained in single key (parent[child_field_name]).
1161 6
     *
1162 6
     * @param string $name
1163 6
     * @return string
1164 6
     */
1165
    protected function getFieldName($name)
1166
    {
1167 11
        $formName = $this->getName();
1168
        if ($formName !== null) {
1169
            if (strpos($formName, '[') !== false || strpos($formName, ']') !== false) {
1170 66
                return $this->formHelper->transformToBracketSyntax(
1171
                    $this->formHelper->transformToDotSyntax(
1172
                        $formName . '[' . $name . ']'
1173
                    )
1174
                );
1175
            }
1176 1
1177
            return $formName . '[' . $name . ']';
1178 1
        }
1179 1
1180 1
        return $name;
1181 1
    }
1182
1183
    /**
1184
     * Disable all fields in a form.
1185
     */
1186 1
    public function disableFields()
1187
    {
1188 1
        foreach ($this->fields as $field) {
1189 1
            $field->disable();
1190 1
        }
1191 1
    }
1192
1193
    /**
1194
     * Enable all fields in a form.
1195
     */
1196
    public function enableFields()
1197
    {
1198
        foreach ($this->fields as $field) {
1199
            $field->enable();
1200 9
        }
1201
    }
1202 9
1203 9
    /**
1204 9
     * Validate the form.
1205
     *
1206 9
     * @param array $validationRules
1207 9
     * @param array $messages
1208
     * @return Validator
1209 9
     */
1210
    public function validate($validationRules = [], $messages = [])
1211 9
    {
1212
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1213
        $rules = array_merge($fieldRules->getRules(), $validationRules);
1214
        $messages = array_merge($fieldRules->getMessages(), $messages);
1215
1216
        $this->validator = $this->validatorFactory->make($this->getRequest()->all(), $rules, $messages);
1217
        $this->validator->setAttributeNames($fieldRules->getAttributes());
1218
1219
        $this->eventDispatcher->dispatch(new BeforeFormValidation($this, $this->validator));
1220 1
1221
        return $this->validator;
1222 1
    }
1223
1224 1
    /**
1225
     * Get validation rules for the form.
1226
     *
1227
     * @param array $overrideRules
1228
     * @return array
1229
     */
1230
    public function getRules($overrideRules = [])
1231
    {
1232
        $fieldRules = $this->formHelper->mergeFieldsRules($this->fields);
1233 3
1234
        return array_merge($fieldRules->getRules(), $overrideRules);
1235 3
    }
1236 3
1237
    /**
1238 3
     * Redirects to a destination when form is invalid.
1239 2
     *
1240 2
     * @param  string|null $destination The target url.
1241
     * @return HttpResponseException
1242 3
     */
1243
    public function redirectIfNotValid($destination = null)
1244 3
    {
1245
        if (! $this->isValid()) {
1246
            $response = redirect($destination);
1247
1248
            if (is_null($destination)) {
1249
                $response = $response->back();
1250
            }
1251
1252
            $response = $response->withErrors($this->getErrors(), $this->getErrorBag())->withInput();
1253 3
1254
            throw new HttpResponseException($response);
1255 3
        }
1256
    }
1257
1258
    /**
1259
     * Get all form field attributes, including child forms, in a flat array.
1260
     *
1261
     * @return array
1262
     */
1263 9
    public function getAllAttributes()
1264
    {
1265 9
        return $this->formHelper->mergeAttributes($this->fields);
1266 8
    }
1267 8
1268
    /**
1269 9
     * Check if the form is valid.
1270
     *
1271 9
     * @return bool
1272
     */
1273 9
    public function isValid()
1274
    {
1275 9
        if (!$this->validator) {
1276
            $this->validate();
1277
        }
1278
1279
        $isValid = !$this->validator->fails();
1280
1281
        $this->formHelper->alterValid($this, $this, $isValid);
1282
1283
        $this->eventDispatcher->dispatch(new AfterFormValidation($this, $this->validator, $isValid));
1284
1285 9
        return $isValid;
1286
    }
1287
1288 9
    /**
1289
     * Optionally change the validation result, and/or add error messages.
1290
     *
1291
     * @param Form $mainForm
1292
     * @param bool $isValid
1293
     * @return void|array
1294
     */
1295 8
    public function alterValid(Form $mainForm, &$isValid)
0 ignored issues
show
Unused Code introduced by
The parameter $mainForm is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $isValid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1296
    {
1297 8
        // return ['name' => ['Some other error about the Name field.']];
1298 1
    }
1299 1
1300 1
    /**
1301 1
     * Get validation errors.
1302 1
     *
1303 1
     * @return array
1304
     */
1305
    public function getErrors()
1306 7
    {
1307
        if (!$this->validator || !$this->validator instanceof Validator) {
1308
            throw new \InvalidArgumentException(
1309
                sprintf(
1310
                    'Form %s was not validated. To validate it, call "isValid" method before retrieving the errors',
1311
                    get_class($this)
1312
                )
1313
            );
1314
        }
1315 3
1316
        return $this->validator->getMessageBag()->getMessages();
1317 3
    }
1318
1319 3
    /**
1320 3
     * Get all Request values from all fields, and nothing else.
1321 3
     *
1322 3
     * @param bool $with_nulls
1323 3
     * @return array
1324 3
     */
1325 3
    public function getFieldValues($with_nulls = true)
1326
    {
1327
        $request_values = $this->getRequest()->all();
1328 3
1329 1
        $values = [];
1330 1
        foreach ($this->getAllAttributes() as $attribute) {
1331 1
            $value = Arr::get($request_values, $attribute);
1332
            if ($with_nulls || $value !== null) {
1333
                Arr::set($values, $attribute, $value);
1334 3
            }
1335
        }
1336 3
1337
        // If this form is a child form, cherry pick a part
1338
        if ($this->getName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1339
            $prefix = $this->getNameKey();
1340
            $values = Arr::get($values, $prefix);
1341
        }
1342
1343
        // Allow form-specific value alters
1344
        $this->formHelper->alterFieldValues($this, $values);
1345 3
1346
        return $values;
1347 3
    }
1348
1349
    /**
1350
     * Optionally mess with this form's $values before it's returned from getFieldValues().
1351
     *
1352
     * @param array $values
1353
     * @return void
1354
     */
1355
    public function alterFieldValues(array &$values)
0 ignored issues
show
Unused Code introduced by
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1356 2
    {
1357
    }
1358 2
1359
    /**
1360
     * Throw an exception indicating a field does not exist on the class.
1361
     *
1362
     * @param string $name
1363
     * @throws \InvalidArgumentException
1364
     * @return void
1365
     */
1366
    protected function fieldDoesNotExist($name)
1367 130
    {
1368
        throw new \InvalidArgumentException('Field ['.$name.'] does not exist in '.get_class($this));
1369
    }
1370 130
1371 130
    /**
1372
     * Method filterFields used as *Main* method for starting
1373 130
     * filtering and request field mutating process.
1374 1
     *
1375
     * @return \Kris\LaravelFormBuilder\Form
1376 1
     */
1377 1
    public function filterFields()
1378
    {
1379 1
        // If filtering is unlocked/allowed we can start with filtering process.
1380 1
        if (!$this->isFilteringLocked()) {
1381 1
            $filters = array_filter($this->getFilters());
1382 1
1383
            if (count($filters)) {
1384 1
                $dotForm = $this->getNameKey();
1385 1
1386 1
                $request = $this->getRequest();
1387 1
                $requestData = $request->all();
1388 1
1389 1
                foreach ($filters as $field => $fieldFilters) {
1390 1
                    $dotField = $this->formHelper->transformToDotSyntax($field);
1391 1
                    $fieldData = Arr::get($requestData, $dotField);
1392 1
                    if ($fieldData !== null) {
1393 1
                        // Assign current Raw/Unmutated value from request.
1394
                        $localDotField = preg_replace('#^' . preg_quote("$dotForm.", '#') . '#', '', $dotField);
1395 1
                        $localBracketField = $this->formHelper->transformToBracketSyntax($localDotField);
1396 1
                        $this->getField($localBracketField)->setRawValue($fieldData);
1397 1
                        foreach ($fieldFilters as $filter) {
1398 1
                            $filterObj = FilterResolver::instance($filter);
1399 130
                            $fieldData = $filterObj->filter($fieldData);
1400
                        }
1401 130
                        Arr::set($requestData, $dotField, $fieldData);
1402
                    }
1403
                }
1404
1405
                foreach ($requestData as $name => $value) {
1406
                    $request[$name] = $value;
1407
                }
1408
            }
1409 130
        }
1410
1411 130
        return $this;
1412 130
    }
1413 17
1414 130
    /**
1415
     * Method getFilters used to return array of all binded filters to form fields.
1416 130
     *
1417
     * @return array
1418
     */
1419
    public function getFilters()
1420
    {
1421
        $filters = [];
1422
        foreach ($this->getFields() as $field) {
1423
            $filters[$field->getName()] = $field->getFilters();
1424
        }
1425 1
1426
        return $filters;
1427 1
    }
1428 1
1429
    /**
1430
     * If lockFiltering is set to true then we will not
1431
     * filter fields and mutate request data binded to fields.
1432
     *
1433
     * @return \Kris\LaravelFormBuilder\Form
1434
     */
1435
    public function lockFiltering()
1436
    {
1437
        $this->lockFiltering = true;
1438
        return $this;
1439
    }
1440
1441
    /**
1442
     * Unlock fields filtering/mutating.
1443
     *
1444
     * @return \Kris\LaravelFormBuilder\Form
1445
     */
1446
    public function unlockFiltering()
1447
    {
1448 130
        $this->lockFiltering = false;
1449
        return $this;
1450 130
    }
1451
1452
    /**
1453
     * Method isFilteringLocked used to check
1454
     * if current filteringLocked property status is set to true.
1455
     *
1456
     * @return bool
1457
     */
1458
    public function isFilteringLocked()
1459
    {
1460
        return !$this->lockFiltering ? false : true;
1461
    }
1462
1463
    /**
1464
     * Method getRawValues returns Unfiltered/Unmutated fields -> values.
1465
     *
1466
     * @return array
1467
     */
1468
    public function getRawValues()
1469
    {
1470
        $rawValues = [];
1471
        foreach ($this->getFields() as $field) {
1472
            $rawValues[$field->getName()] = $field->getRawValue();
1473
        }
1474
1475
        return $rawValues;
1476
    }
1477
}
1478