Passed
Pull Request — master (#192)
by Sergei
03:23
created

FieldFactory::number()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
10
use Yiisoft\Form\Field\Base\AbstractInputField;
11
use Yiisoft\Form\Field\Base\AbstractField;
12
use Yiisoft\Form\Field\Base\PlaceholderTrait;
13
use Yiisoft\Form\Field\Checkbox;
14
use Yiisoft\Form\Field\Date;
15
use Yiisoft\Form\Field\DateTime;
16
use Yiisoft\Form\Field\DateTimeLocal;
17
use Yiisoft\Form\Field\Email;
18
use Yiisoft\Form\Field\Hidden;
19
use Yiisoft\Form\Field\Image;
20
use Yiisoft\Form\Field\Number;
21
use Yiisoft\Form\Field\Part\Error;
22
use Yiisoft\Form\Field\Part\Hint;
23
use Yiisoft\Form\Field\Part\Label;
24
use Yiisoft\Form\Field\Password;
25
use Yiisoft\Form\Field\Range;
26
use Yiisoft\Form\Field\ResetButton;
27
use Yiisoft\Form\Field\Select;
28
use Yiisoft\Form\Field\SubmitButton;
29
use Yiisoft\Form\Field\Telephone;
30
use Yiisoft\Form\Field\Text;
31
use Yiisoft\Form\Field\Textarea;
32
use Yiisoft\Form\Field\Url;
33
use Yiisoft\Widget\WidgetFactory;
34
35
use function in_array;
36
37
final class FieldFactory
38
{
39
    private const SUPPORT_PLACEHOLDER = 1;
40
41
    private ?array $baseFieldConfig = null;
42
43
    /**
44
     * @param array[] $fieldConfigs
45
     */
46 17
    public function __construct(
47
        private ?string $containerTag = null,
48
        private array $containerTagAttributes = [],
49
        private ?bool $useContainer = null,
50
        private ?string $template = null,
51
        private ?bool $setInputIdAttribute = null,
52
        private array $inputTagAttributes = [],
53
        private array $labelConfig = [],
54
        private array $hintConfig = [],
55
        private array $errorConfig = [],
56
        private ?bool $usePlaceholder = null,
57
        private array $fieldConfigs = [],
58
    ) {
59
    }
60
61 1
    public function checkbox(FormModelInterface $formModel, string $attribute, array $config = []): Checkbox
62
    {
63 1
        return $this->input(Checkbox::class, $formModel, $attribute, $config);
64
    }
65
66 1
    public function date(FormModelInterface $formModel, string $attribute, array $config = []): Date
67
    {
68 1
        return $this->input(Date::class, $formModel, $attribute, $config);
69
    }
70
71 1
    public function dateTime(FormModelInterface $formModel, string $attribute, array $config = []): DateTime
72
    {
73 1
        return $this->input(DateTime::class, $formModel, $attribute, $config);
74
    }
75
76 1
    public function dateTimeLocal(FormModelInterface $formModel, string $attribute, array $config = []): DateTimeLocal
77
    {
78 1
        return $this->input(DateTimeLocal::class, $formModel, $attribute, $config);
79
    }
80
81 1
    public function email(FormModelInterface $formModel, string $attribute, array $config = []): Email
82
    {
83 1
        return $this->input(Email::class, $formModel, $attribute, $config);
84
    }
85
86 1
    public function hidden(FormModelInterface $formModel, string $attribute, array $config = []): Hidden
87
    {
88 1
        return $this->input(Hidden::class, $formModel, $attribute, $config);
89
    }
90
91 1
    public function image(array $config = []): Image
92
    {
93 1
        return $this->field(Image::class, $config);
94
    }
95
96 1
    public function number(FormModelInterface $formModel, string $attribute, array $config = []): Number
97
    {
98 1
        return $this->input(Number::class, $formModel, $attribute, $config);
99
    }
100
101 1
    public function password(FormModelInterface $formModel, string $attribute, array $config = []): Password
102
    {
103 1
        return $this->input(Password::class, $formModel, $attribute, $config);
104
    }
105
106 1
    public function range(FormModelInterface $formModel, string $attribute, array $config = []): Range
107
    {
108 1
        return $this->input(Range::class, $formModel, $attribute, $config);
109
    }
110
111 1
    public function resetButton(array $config = []): ResetButton
112
    {
113 1
        return $this->field(ResetButton::class, $config);
114
    }
115
116 1
    public function select(FormModelInterface $formModel, string $attribute, array $config = []): Select
117
    {
118 1
        return $this->input(Select::class, $formModel, $attribute, $config);
119
    }
120
121 1
    public function submitButton(array $config = []): SubmitButton
122
    {
123 1
        return $this->field(SubmitButton::class, $config);
124
    }
125
126 1
    public function telephone(FormModelInterface $formModel, string $attribute, array $config = []): Telephone
127
    {
128 1
        return $this->input(Telephone::class, $formModel, $attribute, $config);
129
    }
130
131 10
    public function text(FormModelInterface $formModel, string $attribute, array $config = []): Text
132
    {
133 10
        return $this->input(Text::class, $formModel, $attribute, $config);
134
    }
135
136 1
    public function textarea(FormModelInterface $formModel, string $attribute, array $config = []): Textarea
137
    {
138 1
        return $this->input(Textarea::class, $formModel, $attribute, $config);
139
    }
140
141 1
    public function url(FormModelInterface $formModel, string $attribute, array $config = []): Url
142
    {
143 1
        return $this->input(Url::class, $formModel, $attribute, $config);
144
    }
145
146 4
    public function label(FormModelInterface $formModel, string $attribute, array $config = []): Label
147
    {
148 4
        $widgetConfig = array_merge(
149 4
            $this->makeLabelConfig(),
150
            $config,
151
        );
152 4
        return Label::widget($widgetConfig)->attribute($formModel, $attribute);
0 ignored issues
show
Bug introduced by
The method attribute() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of Yiisoft\Widget\Widget such as Yiisoft\Form\Field\Part\Label or Yiisoft\Form\Field\Part\Error or Yiisoft\Form\Field\Part\Hint or Yiisoft\Form\Field\Base\AbstractInputField. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

152
        return Label::widget($widgetConfig)->/** @scrutinizer ignore-call */ attribute($formModel, $attribute);
Loading history...
153
    }
154
155 3
    public function hint(FormModelInterface $formModel, string $attribute, array $config = []): Hint
156
    {
157 3
        $widgetConfig = array_merge(
158 3
            $this->hintConfig,
159
            $config,
160
        );
161 3
        return Hint::widget($widgetConfig)->attribute($formModel, $attribute);
162
    }
163
164 3
    public function error(FormModelInterface $formModel, string $attribute, array $config = []): Error
165
    {
166 3
        $widgetConfig = array_merge(
167 3
            $this->errorConfig,
168
            $config,
169
        );
170 3
        return Error::widget($widgetConfig)->attribute($formModel, $attribute);
171
    }
172
173
    /**
174
     * @psalm-template T
175
     * @psalm-param class-string<T> $class
176
     * @psalm-return T
177
     */
178 23
    public function input(string $class, FormModelInterface $formModel, string $attribute, array $config = []): object
179
    {
180 23
        $widget = $this->field($class, $config);
181 23
        if (!$widget instanceof AbstractInputField) {
182
            throw new InvalidArgumentException(
183
                sprintf(
184
                    'Input widget must be instance of "%s".',
185
                    AbstractInputField::class
186
                )
187
            );
188
        }
189
190 23
        return $widget->attribute($formModel, $attribute);
191
    }
192
193
    /**
194
     * @psalm-template T
195
     * @psalm-param class-string<T> $class
196
     * @psalm-return T
197
     */
198 26
    public function field(string $class, array $config = []): object
199
    {
200 26
        $traits = class_uses($class);
201 26
        if ($traits === false) {
202
            throw new RuntimeException('Invalid field class.');
203
        }
204
205 26
        $supports = [];
206 26
        if (in_array(PlaceholderTrait::class, $traits, true)) {
207 16
            $supports[] = self::SUPPORT_PLACEHOLDER;
208
        }
209
210 26
        $config = array_merge(
211 26
            $this->makeFieldConfig($supports),
212 26
            $this->fieldConfigs[$class] ?? [],
213
            $config,
214 26
            ['class' => $class],
215
        );
216
217
        /** @psalm-var T&AbstractField */
218 26
        return WidgetFactory::createWidget($config);
219
    }
220
221
    /**
222
     * @param int[] $supports
223
     */
224 26
    private function makeFieldConfig(array $supports): array
225
    {
226 26
        $config = $this->makeBaseFieldConfig();
227 26
        foreach ($supports as $support) {
228
            switch ($support) {
229 16
                case self::SUPPORT_PLACEHOLDER:
230 16
                    if ($this->usePlaceholder !== null) {
231 2
                        $config['usePlaceholder()'] = [$this->usePlaceholder];
232
                    }
233 16
                    break;
234
            }
235
        }
236 26
        return $config;
237
    }
238
239 26
    private function makeBaseFieldConfig(): array
240
    {
241 26
        if ($this->baseFieldConfig === null) {
242 10
            $this->baseFieldConfig = [];
243
244 10
            if ($this->containerTag !== null) {
245 2
                $this->baseFieldConfig['containerTag()'] = [$this->containerTag];
246
            }
247
248 10
            if ($this->containerTagAttributes !== []) {
249 2
                $this->baseFieldConfig['containerTagAttributes()'] = [$this->containerTagAttributes];
250
            }
251
252 10
            if ($this->useContainer !== null) {
253 1
                $this->baseFieldConfig['useContainer()'] = [$this->useContainer];
254
            }
255
256 10
            if ($this->template !== null) {
257 1
                $this->baseFieldConfig['template()'] = [$this->template];
258
            }
259
260 10
            if ($this->setInputIdAttribute !== null) {
261 1
                $this->baseFieldConfig['setInputIdAttribute()'] = [$this->setInputIdAttribute];
262
            }
263
264 10
            if ($this->inputTagAttributes !== []) {
265 2
                $this->baseFieldConfig['inputTagAttributes()'] = [$this->inputTagAttributes];
266
            }
267
268 10
            $labelConfig = $this->makeLabelConfig();
269 10
            if ($labelConfig !== []) {
270 2
                $this->baseFieldConfig['labelConfig()'] = [$labelConfig];
271
            }
272
273 10
            if ($this->hintConfig !== []) {
274 1
                $this->baseFieldConfig['hintConfig()'] = [$this->hintConfig];
275
            }
276
277 10
            if ($this->errorConfig !== []) {
278 1
                $this->baseFieldConfig['errorConfig()'] = [$this->errorConfig];
279
            }
280
        }
281 26
        return $this->baseFieldConfig;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->baseFieldConfig could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
282
    }
283
284 14
    private function makeLabelConfig(): array
285
    {
286 14
        $config = [];
287
288 14
        if ($this->setInputIdAttribute === false) {
289 2
            $config['useInputIdAttribute()'] = [false];
290
        }
291
292 14
        return array_merge($config, $this->labelConfig);
293
    }
294
}
295