InputBuilder   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Test Coverage

Coverage 98.85%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 80
c 4
b 0
f 0
dl 0
loc 185
ccs 86
cts 87
cp 0.9885
rs 9.76
wmc 33

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getOptions() 0 3 1
A factory() 0 3 1
A getDefaultOptions() 0 5 1
A build() 0 25 5
A __construct() 0 4 1
A parseOption() 0 9 3
A render() 0 4 1
B parseOptions() 0 33 6
A parseOptionTypeSpecial() 0 12 3
A parseOptionEmptyData() 0 11 2
B parseOptionConstraints() 0 24 8
A getType() 0 3 1
1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of FlexPHP.
4
 *
5
 * (c) Freddie Gar <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace FlexPHP\Inputs\Builder;
11
12
use InvalidArgumentException;
13
use Symfony\Component\Form\Extension\Core\Type\FormType;
14
use Symfony\Component\Form\Extension\Core\Type\TextType;
15
use Symfony\Component\Form\FormBuilderInterface;
16
use Symfony\Component\Form\FormInterface;
17
use Symfony\Component\Form\Forms;
18
19
class InputBuilder extends AbstractBuilder
20
{
21
    /**
22
     * @var string
23
     */
24
    protected $type;
25
26
    /**
27
     * @param array<string, mixed> $options
28
     */
29 62
    public function __construct(string $name, array $options)
30
    {
31 62
        $this->name = $name;
32 62
        $this->options = $this->parseOptions($this->getDefaultOptions($options));
33 62
    }
34
35 62
    public function getOptions(): array
36
    {
37 62
        return $this->options;
38
    }
39
40 62
    public function build(): FormInterface
41
    {
42 62
        $options = $this->getOptions();
43 62
        $classType = \trim($this->getType());
44
45 62
        if (\strpos($classType, 'Symfony') === false) {
46
            // Not symfony type
47 18
            $type = \preg_replace('/type$/i', '', $classType) ?? $classType;
48 18
            $classType = \sprintf('\Symfony\Component\Form\Extension\Core\Type\%1$sType', \ucwords($type));
49 44
        } elseif (!empty($options['type']) && \stripos($classType, $options['type']) === false) {
50
            // Symfony type, but its diff in options type contraint
51 4
            $type = $options['type'];
52 4
            $classType = \sprintf('\Symfony\Component\Form\Extension\Core\Type\%1$sType', \ucwords($type));
53
        }
54
55 62
        unset($options['type']);
56
57 62
        if (!\class_exists($classType)) {
58 2
            throw new InvalidArgumentException(\sprintf('Type [%1$s] is not supported', $classType));
59
        }
60
61
        return $this
62 60
            ->factory()
63 60
            ->add($this->getName(), $classType, $options)
64 60
            ->getForm();
65
    }
66
67 62
    public function render(): string
68
    {
69 62
        return $this->twig()->createTemplate(\sprintf('{{ form_row(form.%1$s) }}', $this->getName()))->render([
70 62
            'form' => $this->build()->createView(),
71
        ]);
72
    }
73
74
    /**
75
     * @return FormBuilderInterface<string>
76
     */
77 60
    protected function factory(): FormBuilderInterface
78
    {
79 60
        return Forms::createFormFactory()->createBuilder(FormType::class, null);
80
    }
81
82 44
    protected function getType(): string
83
    {
84 44
        return TextType::class;
85
    }
86
87
    /**
88
     * @param array<string> $options
89
     *
90
     * @return array<mixed>
91
     */
92 62
    private function getDefaultOptions(array $options = []): array
93
    {
94 62
        return (array)\array_merge([
95 62
            'required' => false,
96 62
        ], $options);
97
    }
98
99
    /**
100
     * @param array<mixed> $options
101
     *
102
     * @return array<string>
103
     */
104 62
    private function parseOptions(array $options): array
105
    {
106 62
        $_options = [];
107
108 62
        if (!empty($options['attr']['type'])) {
109 1
            $options['type'] = $options['attr']['type'];
110 1
            unset($options['attr']['type']);
111
        }
112
113 62
        foreach ($options as $option => $value) {
114 62
            switch ($option) {
115 62
                case 'default':
116 1
                    $_options['data'] = $value;
117
118 1
                    break;
119 62
                case 'constraints':
120 21
                    $_options = $this->parseOptionConstraints($_options, $value);
121
122 21
                    break;
123 62
                case 'empty_data':
124 3
                    $_options = $this->parseOptionEmptyData($_options, $option, $value);
125
126 3
                    break;
127
                default:
128 62
                    $_options = $this->parseOption($_options, $option, $value);
129
130 62
                    break;
131
            }
132
133 62
            unset($options[$option]);
134
        }
135
136 62
        return $this->parseOptionTypeSpecial($_options);
137
    }
138
139 3
    private function parseOptionEmptyData(array $_options, string $option, string $value): array
140
    {
141 3
        $_options[$option] = $value;
142
143 3
        if (empty($_options['attr'])) {
144 2
            $_options['attr'] = [];
145
        }
146
147 3
        $_options['attr']['placeholder'] = $value;
148
149 3
        return $_options;
150
    }
151
152 21
    private function parseOptionConstraints(array $_options, array $value): array
153
    {
154 21
        foreach ($value as $attribute => $_value) {
155 21
            if (\is_int($attribute)) {
156 1
                $attribute = $_value;
157 1
                $_value = true;
158
            }
159
160 21
            if ($attribute === 'required') {
161 6
                $_options['required'] = $_value && !\preg_match('/^false$/i', (string)$_value);
162
            } elseif (\in_array($attribute, ['length', 'mincheck', 'maxcheck', 'check', 'equalto'])) {
163 5
                $_options['attr']['data-parsley-' . $attribute] = $_value;
164 10
            } elseif ($attribute === 'range') {
165 1
                $_options['type'] = $attribute;
166 1
                [$min, $max] = \explode(',', $_value);
167 1
                $_options['attr'] = \compact('min', 'max');
168 9
            } elseif ($attribute === 'type') {
169 3
                $_options['type'] = $_value;
170
            } else {
171 6
                $_options['attr'][$attribute] = $_value;
172
            }
173
        }
174
175 21
        return $_options;
176
    }
177
178 62
    private function parseOptionTypeSpecial(array $_options): array
179
    {
180 62
        if (!empty($_options['type'])) {
181 8
            $_type = \strtolower($_options['type']);
182
183 8
            if (\in_array($_type, ['digits', 'alphanum'])) {
184 2
                $_options['attr']['data-parsley-type'] = $_type;
185 2
                $_options['type'] = 'text';
186
            }
187
        }
188
189 62
        return $_options;
190
    }
191
192
    /**
193
     * @param mixed $value
194
     */
195 62
    private function parseOption(array $_options, string $option, $value): array
196
    {
197 62
        if (\is_array($value) && !empty($_options[$option])) {
198 1
            $_options[$option] = \array_merge_recursive($_options[$option], $value);
199
        } else {
200 62
            $_options[$option] = $value;
201
        }
202
203 62
        return $_options;
204
    }
205
}
206