Completed
Push — master ( ceb694...183c93 )
by Rudie
01:46
created

FormField   F

Complexity

Total Complexity 124

Size/Duplication

Total Lines 988
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 92.28%

Importance

Changes 0
Metric Value
wmc 124
lcom 1
cbo 13
dl 0
loc 988
ccs 287
cts 311
cp 0.9228
rs 1.612
c 0
b 0
f 0

51 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
B setupValue() 0 21 7
getTemplate() 0 1 ?
A getViewTemplate() 0 4 1
B render() 0 40 6
A getRenderData() 0 4 1
A getModelValueAttribute() 0 11 4
A transformKey() 0 4 1
F prepareOptions() 0 65 14
A prepareRules() 0 26 5
A normalizeRules() 0 21 5
A getName() 0 4 1
A setName() 0 6 1
A getNameKey() 0 4 1
A getOptions() 0 4 1
A getOption() 0 4 1
A setOptions() 0 6 1
A setOption() 0 6 1
A getType() 0 4 1
A setType() 0 8 2
A getParent() 0 4 1
A isRendered() 0 4 1
A getDefaults() 0 4 1
A allDefaults() 0 19 1
A getRealName() 0 4 1
A setValue() 0 20 5
A setTemplate() 0 4 1
B addErrorClass() 0 26 10
A setDefaultOptions() 0 10 1
B setDefaultClasses() 0 18 7
A needsLabel() 0 11 4
A disable() 0 6 1
A enable() 0 6 1
A getAllAttributes() 0 4 1
A getValue() 0 4 1
A getDefaultValue() 0 4 1
A isValidValue() 0 4 1
A initFilters() 0 19 3
A setFilters() 0 9 2
A getFilters() 0 4 1
A addFilter() 0 28 4
A removeFilter() 0 10 2
A removeFilters() 0 12 3
A clearFilters() 0 5 1
A setFiltersOverride() 0 5 1
A getFiltersOverride() 0 4 1
A setRawValue() 0 5 1
A getRawValue() 0 4 1
A getConfig() 0 4 1
A setupLabel() 0 20 4
A getValidationRules() 0 26 5

How to fix   Complexity   

Complex Class

Complex classes like FormField 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 FormField, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Kris\LaravelFormBuilder\Fields;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Str;
7
use Kris\LaravelFormBuilder\Filters\Exception\FilterAlreadyBindedException;
8
use Kris\LaravelFormBuilder\Filters\FilterInterface;
9
use Kris\LaravelFormBuilder\Filters\FilterResolver;
10
use Kris\LaravelFormBuilder\Form;
11
use Kris\LaravelFormBuilder\FormHelper;
12
use Kris\LaravelFormBuilder\Rules;
13
14
/**
15
 * Class FormField
16
 *
17
 * @package Kris\LaravelFormBuilder\Fields
18
 */
19
abstract class FormField
20
{
21
    /**
22
     * Name of the field.
23
     *
24
     * @var string
25
     */
26
    protected $name;
27
28
    /**
29
     * Type of the field.
30
     *
31
     * @var string
32
     */
33
    protected $type;
34
35
    /**
36
     * All options for the field.
37
     *
38
     * @var array
39
     */
40
    protected $options = [];
41
42
    /**
43
     * Is field rendered.
44
     *
45
     * @var bool
46
     */
47
    protected $rendered = false;
48
49
    /**
50
     * @var Form
51
     */
52
    protected $parent;
53
54
    /**
55
     * @var string
56
     */
57
    protected $template;
58
59
    /**
60
     * @var FormHelper
61
     */
62
    protected $formHelper;
63
64
    /**
65
     * Name of the property for value setting.
66
     *
67
     * @var string
68
     */
69
    protected $valueProperty = 'value';
70
71
    /**
72
     * Name of the property for default value.
73
     *
74
     * @var string
75
     */
76
    protected $defaultValueProperty = 'default_value';
77
78
    /**
79
     * Is default value set?
80
     *
81
     * @var bool|false
82
     */
83
    protected $hasDefault = false;
84
85
    /**
86
     * @var \Closure|null
87
     */
88
    protected $valueClosure = null;
89
90
    /**
91
     * Array of filters key(alias/name) => objects.
92
     *
93
     * @var array
94
     */
95
    protected $filters = [];
96
97
    /**
98
     * Raw/unfiltered field value.
99
     *
100
     * @var mixed $rawValues
101
     */
102
    protected $rawValue;
103
104
    /**
105
     * Override filters with same alias/name for field.
106
     *
107
     * @var bool
108
     */
109
    protected $filtersOverride = false;
110
111
    /**
112
     * @param string $name
113
     * @param string $type
114
     * @param Form $parent
115
     * @param array $options
116
     */
117 105
    public function __construct($name, $type, Form $parent, array $options = [])
118
    {
119 105
        $this->name = $name;
120 105
        $this->type = $type;
121 105
        $this->parent = $parent;
122 105
        $this->formHelper = $this->parent->getFormHelper();
123 105
        $this->setTemplate();
124 105
        $this->setDefaultOptions($options);
125 105
        $this->setupValue();
126 100
        $this->initFilters();
127 100
    }
128
129
130
    /**
131
     * Setup the value of the form field.
132
     *
133
     * @return void
134
     */
135 105
    protected function setupValue()
136
    {
137 105
        $value = $this->getOption($this->valueProperty);
138 105
        $isChild = $this->getOption('is_child');
139
140 105
        if ($value instanceof \Closure) {
141
            $this->valueClosure = $value;
142
        }
143
144 105
        if (($value === null || $value instanceof \Closure) && !$isChild) {
145 94
            if ($this instanceof EntityType) {
146 5
                $attributeName = $this->name;
147
            } else {
148 89
                $attributeName = $this->getOption('property', $this->name);
149
            }
150
151 94
            $this->setValue($this->getModelValueAttribute($this->parent->getModel(), $attributeName));
152 25
        } elseif (!$isChild) {
153 14
            $this->hasDefault = true;
154
        }
155 100
    }
156
157
    /**
158
     * Get the template, can be config variable or view path.
159
     *
160
     * @return string
161
     */
162
    abstract protected function getTemplate();
163
164
    /**
165
     * @return string
166
     */
167 35
    protected function getViewTemplate()
168
    {
169 35
        return $this->parent->getTemplatePrefix() . $this->getOption('template', $this->template);
170
    }
171
172
    /**
173
     * Render the field.
174
     *
175
     * @param array $options
176
     * @param bool  $showLabel
177
     * @param bool  $showField
178
     * @param bool  $showError
179
     * @return string
180
     */
181 35
    public function render(array $options = [], $showLabel = true, $showField = true, $showError = true)
182
    {
183 35
        $this->prepareOptions($options);
184 35
        $value = $this->getValue();
185 35
        $defaultValue = $this->getDefaultValue();
186
187 35
        if ($showField) {
188 35
            $this->rendered = true;
189
        }
190
191
        // Override default value with value
192 35
        if (!$this->isValidValue($value) && $this->isValidValue($defaultValue)) {
193
            $this->setOption($this->valueProperty, $defaultValue);
194
        }
195
196 35
        if (!$this->needsLabel()) {
197 11
            $showLabel = false;
198
        }
199
200 35
        if ($showError) {
201 34
            $showError = $this->parent->haveErrorsEnabled();
202
        }
203
204 35
        $data = $this->getRenderData();
205
206 35
        return $this->formHelper->getView()->make(
207 35
            $this->getViewTemplate(),
208
            $data + [
209 35
                'name' => $this->name,
210 35
                'nameKey' => $this->getNameKey(),
211 35
                'type' => $this->type,
212 35
                'options' => $this->options,
213 35
                'showLabel' => $showLabel,
214 35
                'showField' => $showField,
215 35
                'showError' => $showError,
216 35
                'errorBag'  => $this->parent->getErrorBag(),
217 35
                'translationTemplate' => $this->parent->getTranslationTemplate(),
218
            ]
219 35
        )->render();
220
    }
221
222
    /**
223
     * Return the extra render data for this form field, passed into the field's template directly.
224
     *
225
     * @return array
226
     */
227 35
    protected function getRenderData()
228
    {
229 35
        return [];
230
    }
231
232
    /**
233
     * Get the attribute value from the model by name.
234
     *
235
     * @param mixed $model
236
     * @param string $name
237
     * @return mixed
238
     */
239 96
    protected function getModelValueAttribute($model, $name)
240
    {
241 96
        $transformedName = $this->transformKey($name);
242 96
        if (is_string($model)) {
243
            return $model;
244 96
        } elseif (is_object($model)) {
245 5
            return object_get($model, $transformedName);
246 94
        } elseif (is_array($model)) {
247 93
            return Arr::get($model, $transformedName);
248
        }
249 5
    }
250
251
    /**
252
     * Transform array like syntax to dot syntax.
253
     *
254
     * @param string $key
255
     * @return mixed
256
     */
257 105
    protected function transformKey($key)
258
    {
259 105
        return $this->formHelper->transformToDotSyntax($key);
260
    }
261
262
    /**
263
     * Prepare options for rendering.
264
     *
265
     * @param array $options
266
     * @return array The parsed options
267
     */
268 105
    protected function prepareOptions(array $options = [])
269
    {
270 105
        $helper = $this->formHelper;
271
272 105
        $this->options = $this->prepareRules($options);
273 105
        $this->options = $helper->mergeOptions($this->options, $options);
274
275 105
        $rulesParser = $helper->createRulesParser($this);
276 105
        $rules = $this->getOption('rules');
277 105
        $parsedRules = $rules ? $rulesParser->parse($rules) : [];
278
279
280 105
        foreach (['attr', 'label_attr', 'wrapper'] as $appendable) {
281
            // Append values to the 'class' attribute
282 105
            if ($this->getOption("{$appendable}.class_append")) {
283
                // Combine the current class attribute with the appends
284 3
                $append = $this->getOption("{$appendable}.class_append");
285 3
                $classAttribute = $this->getOption("{$appendable}.class", '') . ' ' . $append;
286 3
                $this->setOption("{$appendable}.class", $classAttribute);
287
288
                // Then remove the class_append option to prevent it from showing up as an attribute in the HTML
289 3
                $this->setOption("{$appendable}.class_append", null);
290
            }
291
        }
292
293 105
        if ($this->getOption('attr.multiple') && !$this->getOption('tmp.multipleBracesSet')) {
294 2
            $this->name = $this->name . '[]';
295 2
            $this->setOption('tmp.multipleBracesSet', true);
296
        }
297
298 105
        if ($this->parent->haveErrorsEnabled()) {
299 105
            $this->addErrorClass();
300
        }
301
302 105
        if ($this->getOption('required') === true || isset($parsedRules['required'])) {
303 16
            $lblClass = $this->getOption('label_attr.class', '');
304 16
            $requiredClass = $this->getConfig('defaults.required_class', 'required');
305
306 16
            if (!Str::contains($lblClass, $requiredClass)) {
307 16
                $lblClass .= ' ' . $requiredClass;
308 16
                $this->setOption('label_attr.class', $lblClass);
309
            }
310
311 16
            if ($this->parent->clientValidationEnabled()) {
312 15
                $this->setOption('attr.required', 'required');
313
            }
314
        }
315
316 105
        if ($this->parent->clientValidationEnabled() && $parsedRules) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsedRules of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
317 13
            $attrs = $this->getOption('attr') + $parsedRules;
318 13
            $this->setOption('attr', $attrs);
319
        }
320
321 105
        $this->setOption('wrapperAttrs', $helper->prepareAttributes($this->getOption('wrapper')));
322 105
        $this->setOption('errorAttrs', $helper->prepareAttributes($this->getOption('errors')));
323
324 105
        if ($this->getOption('help_block.text')) {
325 1
            $this->setOption(
326 1
                'help_block.helpBlockAttrs',
327 1
                $helper->prepareAttributes($this->getOption('help_block.attr'))
328
            );
329
        }
330
331 105
        return $this->options;
332
    }
333
334
    /**
335
     * Normalize and merge rules.
336
     * @param array $sourceOptions
337
     * @return array
338
     */
339 105
    protected function prepareRules(array &$sourceOptions = [])
340
    {
341 105
        $options = $this->options;
342
343
        // Normalize rules
344 105
        if (array_key_exists('rules_append', $sourceOptions)) {
345 1
            $sourceOptions['rules_append'] = $this->normalizeRules($sourceOptions['rules_append']);
346
        }
347
348 105
        if (array_key_exists('rules', $sourceOptions)) {
349 27
            $sourceOptions['rules'] = $this->normalizeRules($sourceOptions['rules']);
350
        }
351
352 105
        if (array_key_exists('rules', $options)) {
353 105
            $options['rules'] = $this->normalizeRules($options['rules']);
354
        }
355
356
357
        // Append rules
358 105
        if ($rulesToBeAppended = Arr::pull($sourceOptions, 'rules_append')) {
359 1
            $mergedRules = array_values(array_unique(array_merge($options['rules'], $rulesToBeAppended), SORT_REGULAR));
360 1
            $options['rules'] = $mergedRules;
361
        }
362
363 105
        return $options;
364
    }
365
366
    /**
367
     * Normalize the the given rule expression to an array.
368
     * @param mixed $rules
369
     * @return array
370
     */
371 105
    protected function normalizeRules($rules)
372
    {
373 105
        if (empty($rules)) {
374 104
            return [];
375
        }
376
377 14
        if (is_string($rules)) {
378 14
            return explode('|', $rules);
379
        }
380
381 8
        if (is_array($rules)) {
382 8
            $normalizedRules = [];
383 8
            foreach ($rules as $rule) {
384 8
                $normalizedRules[] = $this->normalizeRules($rule);
385
            }
386
387 8
            return array_values(array_unique(Arr::flatten($normalizedRules), SORT_REGULAR));
0 ignored issues
show
Documentation introduced by
$normalizedRules is of type array, but the function expects a object<Illuminate\Support\iterable>.

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...
388
        }
389
390 1
        return $rules;
391
    }
392
393
394
    /**
395
     * Get name of the field.
396
     *
397
     * @return string
398
     */
399 39
    public function getName()
400
    {
401 39
        return $this->name;
402
    }
403
404
    /**
405
     * Set name of the field.
406
     *
407
     * @param string $name
408
     * @return $this
409
     */
410 11
    public function setName($name)
411
    {
412 11
        $this->name = $name;
413
414 11
        return $this;
415
    }
416
417
    /**
418
     * Get dot notation key for fields.
419
     *
420
     * @return string
421
     **/
422 55
    public function getNameKey()
423
    {
424 55
        return $this->transformKey($this->name);
425
    }
426
427
    /**
428
     * Get field options.
429
     *
430
     * @return array
431
     */
432 12
    public function getOptions()
433
    {
434 12
        return $this->options;
435
    }
436
437
    /**
438
     * Get single option from options array. Can be used with dot notation ('attr.class').
439
     *
440
     * @param string $option
441
     * @param mixed|null $default
442
     * @return mixed
443
     */
444 105
    public function getOption($option, $default = null)
445
    {
446 105
        return Arr::get($this->options, $option, $default);
447
    }
448
449
    /**
450
     * Set field options.
451
     *
452
     * @param array $options
453
     * @return $this
454
     */
455 11
    public function setOptions($options)
456
    {
457 11
        $this->options = $this->prepareOptions($options);
458
459 11
        return $this;
460
    }
461
462
    /**
463
     * Set single option on the field.
464
     *
465
     * @param string $name
466
     * @param mixed $value
467
     * @return $this
468
     */
469 105
    public function setOption($name, $value)
470
    {
471 105
        Arr::set($this->options, $name, $value);
472
473 105
        return $this;
474
    }
475
476
    /**
477
     * Get the type of the field.
478
     *
479
     * @return string
480
     */
481 69
    public function getType()
482
    {
483 69
        return $this->type;
484
    }
485
486
    /**
487
     * Set type of the field.
488
     *
489
     * @param mixed $type
490
     * @return $this
491
     */
492 1
    public function setType($type)
493
    {
494 1
        if ($this->formHelper->getFieldType($type)) {
495 1
            $this->type = $type;
496
        }
497
498 1
        return $this;
499
    }
500
501
    /**
502
     * @return Form
503
     */
504 105
    public function getParent()
505
    {
506 105
        return $this->parent;
507
    }
508
509
    /**
510
     * Check if the field is rendered.
511
     *
512
     * @return bool
513
     */
514 4
    public function isRendered()
515
    {
516 4
        return $this->rendered;
517
    }
518
519
    /**
520
     * Default options for field.
521
     *
522
     * @return array
523
     */
524 76
    protected function getDefaults()
525
    {
526 76
        return [];
527
    }
528
529
    /**
530
     * Defaults used across all fields.
531
     *
532
     * @return array
533
     */
534 105
    private function allDefaults()
535
    {
536
        return [
537 105
            'wrapper' => ['class' => $this->getConfig('defaults.wrapper_class')],
538 105
            'attr' => ['class' => $this->getConfig('defaults.field_class')],
539 105
            'help_block' => ['text' => null, 'tag' => 'p', 'attr' => [
540 105
                'class' => $this->getConfig('defaults.help_block_class')
541
            ]],
542
            'value' => null,
543
            'default_value' => null,
544
            'label' => null,
545
            'label_show' => true,
546
            'is_child' => false,
547 105
            'label_attr' => ['class' => $this->getConfig('defaults.label_class')],
548 105
            'errors' => ['class' => $this->getConfig('defaults.error_class')],
549
            'rules' => [],
550
            'error_messages' => []
551
        ];
552
    }
553
554
    /**
555
     * Get real name of the field without form namespace.
556
     *
557
     * @return string
558
     */
559 104
    public function getRealName()
560
    {
561 104
        return $this->getOption('real_name', $this->name);
562
    }
563
564
    /**
565
     * @param $value
566
     * @return $this
567
     */
568 97
    public function setValue($value)
569
    {
570 97
        if ($this->hasDefault) {
571 1
            return $this;
572
        }
573
574 97
        $closure = $this->valueClosure;
575
576 97
        if ($closure instanceof \Closure) {
577
            $value = $closure($value ?: null);
578
        }
579
580 97
        if (!$this->isValidValue($value)) {
581 92
            $value = $this->getOption($this->defaultValueProperty);
582
        }
583
584 97
        $this->options[$this->valueProperty] = $value;
585
586 97
        return $this;
587
    }
588
589
    /**
590
     * Set the template property on the object.
591
     *
592
     * @return void
593
     */
594 105
    private function setTemplate()
595
    {
596 105
        $this->template = $this->getConfig($this->getTemplate(), $this->getTemplate());
597 105
    }
598
599
    /**
600
     * Add error class to wrapper if validation errors exist.
601
     *
602
     * @return void
603
     */
604 105
    protected function addErrorClass()
605
    {
606 105
        $errors = [];
607 105
        if ($this->parent->getRequest()->hasSession()) {
608 104
            $errors = $this->parent->getRequest()->session()->get('errors');
609
        }
610 105
        $errorBag = $this->parent->getErrorBag();
611
612 105
        if ($errors && $errors->hasBag($errorBag) && $errors->getBag($errorBag)->has($this->getNameKey())) {
613
            $fieldErrorClass = $this->getConfig('defaults.field_error_class');
614
            $fieldClass = $this->getOption('attr.class');
615
616
            if ($fieldErrorClass && !Str::contains($fieldClass, $fieldErrorClass)) {
617
                $fieldClass .= ' ' . $fieldErrorClass;
618
                $this->setOption('attr.class', $fieldClass);
619
            }
620
621
            $wrapperErrorClass = $this->getConfig('defaults.wrapper_error_class');
622
            $wrapperClass = $this->getOption('wrapper.class');
623
624
            if ($wrapperErrorClass && $this->getOption('wrapper') && !Str::contains($wrapperClass, $wrapperErrorClass)) {
625
                $wrapperClass .= ' ' . $wrapperErrorClass;
626
                $this->setOption('wrapper.class', $wrapperClass);
627
            }
628
        }
629 105
    }
630
631
    /**
632
     * Merge all defaults with field specific defaults and set template if passed.
633
     *
634
     * @param array $options
635
     */
636 105
    protected function setDefaultOptions(array $options = [])
637
    {
638 105
        $this->options = $this->formHelper->mergeOptions($this->allDefaults(), $this->getDefaults());
639 105
        $this->options = $this->prepareOptions($options);
640
641 105
        $defaults = $this->setDefaultClasses($options);
642 105
        $this->options = $this->formHelper->mergeOptions($this->options, $defaults);
643
644 105
        $this->setupLabel();
645 105
    }
646
647
    /**
648
     * Creates default wrapper classes for the form element.
649
     *
650
     * @param array $options
651
     * @return array
652
     */
653 105
    protected function setDefaultClasses(array $options = [])
654
    {
655 105
        $wrapper_class = $this->getConfig('defaults.' . $this->type . '.wrapper_class', '');
656 105
        $label_class = $this->getConfig('defaults.' . $this->type . '.label_class', '');
657 105
        $field_class = $this->getConfig('defaults.' . $this->type . '.field_class', '');
658
659 105
        $defaults = [];
660 105
        if ($wrapper_class && !Arr::get($options, 'wrapper.class')) {
661
            $defaults['wrapper']['class'] = $wrapper_class;
662
        }
663 105
        if ($label_class && !Arr::get($options, 'label_attr.class')) {
664
            $defaults['label_attr']['class'] = $label_class;
665
        }
666 105
        if ($field_class && !Arr::get($options, 'attr.class')) {
667 1
            $defaults['attr']['class'] = $field_class;
668
        }
669 105
        return $defaults;
670
    }
671
672
    /**
673
     * Setup the label for the form field.
674
     *
675
     * @return void
676
     */
677 105
    protected function setupLabel()
678
    {
679 105
        if ($this->getOption('label') !== null) {
680 26
            return;
681
        }
682
683 103
        if ($template = $this->parent->getTranslationTemplate()) {
684 3
            $label = str_replace(
685 3
                ['{name}', '{type}'],
686 3
                [$this->getRealName(), 'label'],
687
                $template
688
            );
689 100
        } elseif ($langName = $this->parent->getLanguageName()) {
690 4
            $label = sprintf('%s.%s', $langName, $this->getRealName());
691
        } else {
692 97
            $label = $this->getRealName();
693
        }
694
695 103
        $this->setOption('label', $this->formHelper->formatLabel($label));
696 103
    }
697
698
    /**
699
     * Check if fields needs label.
700
     *
701
     * @return bool
702
     */
703 35
    protected function needsLabel()
704
    {
705
        // If field is <select> and child of choice, we don't need label for it
706 35
        $isChildSelect = $this->type == 'select' && $this->getOption('is_child') === true;
707
708 35
        if ($this->type == 'hidden' || $isChildSelect) {
709 11
            return false;
710
        }
711
712 31
        return true;
713
    }
714
715
    /**
716
     * Disable field.
717
     *
718
     * @return $this
719
     */
720 1
    public function disable()
721
    {
722 1
        $this->setOption('attr.disabled', 'disabled');
723
724 1
        return $this;
725
    }
726
727
    /**
728
     * Enable field.
729
     *
730
     * @return $this
731
     */
732 1
    public function enable()
733
    {
734 1
        Arr::forget($this->options, 'attr.disabled');
735
736 1
        return $this;
737
    }
738
739
    /**
740
     * Get validation rules for a field if any with label for attributes.
741
     *
742
     * @return array|null
743
     */
744 10
    public function getValidationRules()
745
    {
746 10
        $rules = $this->getOption('rules', []);
747 10
        $name = $this->getNameKey();
748 10
        $messages = $this->getOption('error_messages', []);
749 10
        $formName = $this->parent->getNameKey();
750
751 10
        if ($messages && $formName) {
752 1
            $newMessages = [];
753 1
            foreach ($messages as $messageKey => $message) {
754 1
                $messageKey = sprintf('%s.%s', $formName, $messageKey);
755 1
                $newMessages[$messageKey] = $message;
756
            }
757 1
            $messages = $newMessages;
758
        }
759
760 10
        if (!$rules) {
761 2
            return (new Rules([]))->setFieldName($this->getNameKey());
762
        }
763
764 9
        return (new Rules(
765 9
            [$name => $rules],
766 9
            [$name => $this->getOption('label')],
767
            $messages
768 9
        ))->setFieldName($this->getNameKey());
769
    }
770
771
    /**
772
     * Get this field's attributes, probably just one.
773
     *
774
     * @return array
775
     */
776 3
    public function getAllAttributes()
777
    {
778 3
        return [$this->getNameKey()];
779
    }
780
781
    /**
782
     * Get value property.
783
     *
784
     * @param mixed|null $default
785
     * @return mixed
786
     */
787 40
    public function getValue($default = null)
788
    {
789 40
        return $this->getOption($this->valueProperty, $default);
790
    }
791
792
    /**
793
     * Get default value property.
794
     *
795
     * @param mixed|null $default
796
     * @return mixed
797
     */
798 35
    public function getDefaultValue($default = null)
799
    {
800 35
        return $this->getOption($this->defaultValueProperty, $default);
801
    }
802
803
    /**
804
     * Check if provided value is valid for this type.
805
     *
806
     * @return bool
807
     */
808 97
    protected function isValidValue($value)
809
    {
810 97
        return $value !== null;
811
    }
812
813
    /**
814
     * Method initFilters used to initialize filters
815
     * from field options and bind it to the same.
816
     *
817
     * @return $this
818
     */
819 100
    protected function initFilters()
820
    {
821
        // If override status is set in field options to true
822
        // we will change filtersOverride property value to true
823
        // so we can override existing filters with registered
824
        // alias/name in addFilter method.
825 100
        $overrideStatus = $this->getOption('filters_override', false);
826 100
        if ($overrideStatus) {
827 2
            $this->setFiltersOverride(true);
828
        }
829
830
        // Get filters and bind it to field.
831 100
        $filters = $this->getOption('filters', []);
832 100
        foreach ($filters as $filter) {
833 8
            $this->addFilter($filter);
834
        }
835
836 100
        return $this;
837
    }
838
839
    /**
840
     * Method setFilters used to set filters to current filters property.
841
     *
842
     * @param  array $filters
843
     *
844
     * @return \Kris\LaravelFormBuilder\Fields\FormField
845
     */
846
    public function setFilters(array $filters)
847
    {
848
        $this->clearFilters();
849
        foreach ($filters as $filter) {
850
            $this->addFilter($filter);
851
        }
852
853
        return $this;
854
    }
855
856
    /**
857
     * Method getFilters returns array of binded filters
858
     * if there are any binded. Otherwise empty array.
859
     *
860
     * @return array
861
     */
862 23
    public function getFilters()
863
    {
864 23
        return $this->filters;
865
    }
866
867
    /**
868
     * @param  string|FilterInterface $filter
869
     *
870
     * @return \Kris\LaravelFormBuilder\Fields\FormField
871
     *
872
     * @throws FilterAlreadyBindedException
873
     */
874 8
    public function addFilter($filter)
875
    {
876
        // Resolve filter object from string/object or throw Ex.
877 8
        $filterObj = FilterResolver::instance($filter);
878
879
        // If filtersOverride is allowed we will override filter
880
        // with same alias/name if there is one with new resolved filter.
881 8
        if ($this->getFiltersOverride()) {
882 1
            if ($key = array_search($filterObj->getName(), $this->getFilters())) {
883
                $this->filters[$key] = $filterObj;
884
            } else {
885 1
                $this->filters[$filterObj->getName()] = $filterObj;
886
            }
887
        } else {
888
            // If filtersOverride is disabled and we found
889
            // equal alias defined we will throw Ex.
890 7
            if (array_key_exists($filterObj->getName(), $this->getFilters())) {
891 1
                $ex = new FilterAlreadyBindedException($filterObj->getName(), $this->getName());
892 1
                throw $ex;
893
            }
894
895
            // Filter with resolvedFilter alias/name doesn't exist
896
            // so we will bind it as new one to field.
897 7
            $this->filters[$filterObj->getName()] = $filterObj;
898
        }
899
900 8
        return $this;
901
    }
902
903
    /**
904
     * Method removeFilter used to remove filter by provided alias/name.
905
     *
906
     * @param  string $name
907
     *
908
     * @return \Kris\LaravelFormBuilder\Fields\FormField
909
     */
910 1
    public function removeFilter($name)
911
    {
912 1
        $filters = $this->getFilters();
913 1
        if (array_key_exists($name, $filters)) {
914 1
            unset($filters[$name]);
915 1
            $this->filters = $filters;
916
        }
917
918 1
        return $this;
919
    }
920
921
    /**
922
     * Method removeFilters used to remove filters by provided aliases/names.
923
     *
924
     * @param  array $filterNames
925
     *
926
     * @return \Kris\LaravelFormBuilder\Fields\FormField
927
     */
928 1
    public function removeFilters(array $filterNames)
929
    {
930 1
        $filters = $this->getFilters();
931 1
        foreach ($filterNames as $filterName) {
932 1
            if (array_key_exists($filterName, $filters)) {
933 1
                unset($filters[$filterName]);
934 1
                $this->filters = $filters;
935
            }
936
        }
937
938 1
        return $this;
939
    }
940
941
    /**
942
     * Method clearFilters used to empty current filters property.
943
     *
944
     * @return \Kris\LaravelFormBuilder\Fields\FormField
945
     */
946 1
    public function clearFilters()
947
    {
948 1
        $this->filters = [];
949 1
        return $this;
950
    }
951
952
    /**
953
     * Method used to set FiltersOverride status to provided value.
954
     *
955
     * @param $status
956
     *
957
     * @return \Kris\LaravelFormBuilder\Fields\FormField
958
     */
959 2
    public function setFiltersOverride($status)
960
    {
961 2
        $this->filtersOverride = $status;
962 2
        return $this;
963
    }
964
965
    /**
966
     * @return bool
967
     */
968 9
    public function getFiltersOverride()
969
    {
970 9
        return $this->filtersOverride;
971
    }
972
973
    /**
974
     * Method used to set Unfiltered/Unmutated field value.
975
     * Method is called before field value mutating starts - request value filtering.
976
     *
977
     * @param mixed $value
978
     *
979
     * @return \Kris\LaravelFormBuilder\Fields\FormField
980
     */
981 1
    public function setRawValue($value)
982
    {
983 1
        $this->rawValue = $value;
984 1
        return $this;
985
    }
986
987
    /**
988
     * Returns unfiltered raw value of field.
989
     *
990
     * @return mixed
991
     */
992
    public function getRawValue()
993
    {
994
        return $this->rawValue;
995
    }
996
997
    /**
998
     * Get config from the form.
999
     *
1000
     * @return mixed
1001
     */
1002 105
    private function getConfig($key = null, $default = null)
1003
    {
1004 105
        return $this->parent->getConfig($key, $default);
1005
    }
1006
}
1007