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

FieldFactory::field()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3.0052

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
nc 3
nop 2
dl 0
loc 21
ccs 11
cts 12
cp 0.9167
crap 3.0052
rs 9.8666
c 1
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\Button;
14
use Yiisoft\Form\Field\ButtonGroup;
15
use Yiisoft\Form\Field\Checkbox;
16
use Yiisoft\Form\Field\CheckboxList;
17
use Yiisoft\Form\Field\Date;
18
use Yiisoft\Form\Field\DateTime;
19
use Yiisoft\Form\Field\DateTimeLocal;
20
use Yiisoft\Form\Field\Email;
21
use Yiisoft\Form\Field\Fieldset;
22
use Yiisoft\Form\Field\Hidden;
23
use Yiisoft\Form\Field\Image;
24
use Yiisoft\Form\Field\Number;
25
use Yiisoft\Form\Field\Part\Error;
26
use Yiisoft\Form\Field\Part\Hint;
27
use Yiisoft\Form\Field\Part\Label;
28
use Yiisoft\Form\Field\Password;
29
use Yiisoft\Form\Field\RadioList;
30
use Yiisoft\Form\Field\Range;
31
use Yiisoft\Form\Field\ResetButton;
32
use Yiisoft\Form\Field\Select;
33
use Yiisoft\Form\Field\SubmitButton;
34
use Yiisoft\Form\Field\Telephone;
35
use Yiisoft\Form\Field\Text;
36
use Yiisoft\Form\Field\Textarea;
37
use Yiisoft\Form\Field\Url;
38
use Yiisoft\Widget\WidgetFactory;
39
40
use function in_array;
41
42
final class FieldFactory
43
{
44
    private const SUPPORT_PLACEHOLDER = 1;
45
46
    private ?array $baseFieldConfig = null;
47
48
    /**
49
     * @param array[] $fieldConfigs
50
     */
51 17
    public function __construct(
52
        private ?string $containerTag = null,
53
        private array $containerTagAttributes = [],
54
        private ?bool $useContainer = null,
55
        private ?string $template = null,
56
        private ?bool $setInputIdAttribute = null,
57
        private array $inputTagAttributes = [],
58
        private array $labelConfig = [],
59
        private array $hintConfig = [],
60
        private array $errorConfig = [],
61
        private ?bool $usePlaceholder = null,
62
        private array $fieldConfigs = [],
63
    ) {
64
    }
65
66 1
    public function button(array $config = []): Button
67
    {
68 1
        return $this->field(Button::class, $config);
69
    }
70
71 1
    public function buttonGroup(array $config = []): ButtonGroup
72
    {
73 1
        return $this->field(ButtonGroup::class, $config);
74
    }
75
76 1
    public function checkbox(FormModelInterface $formModel, string $attribute, array $config = []): Checkbox
77
    {
78 1
        return $this->input(Checkbox::class, $formModel, $attribute, $config);
79
    }
80
81 1
    public function checkboxList(FormModelInterface $formModel, string $attribute, array $config = []): CheckboxList
82
    {
83
        return $this
84 1
            ->field(CheckboxList::class, $config)
85 1
            ->attribute($formModel, $attribute);
86
    }
87
88 1
    public function date(FormModelInterface $formModel, string $attribute, array $config = []): Date
89
    {
90 1
        return $this->input(Date::class, $formModel, $attribute, $config);
91
    }
92
93 1
    public function dateTime(FormModelInterface $formModel, string $attribute, array $config = []): DateTime
94
    {
95 1
        return $this->input(DateTime::class, $formModel, $attribute, $config);
96
    }
97
98 1
    public function dateTimeLocal(FormModelInterface $formModel, string $attribute, array $config = []): DateTimeLocal
99
    {
100 1
        return $this->input(DateTimeLocal::class, $formModel, $attribute, $config);
101
    }
102
103 1
    public function email(FormModelInterface $formModel, string $attribute, array $config = []): Email
104
    {
105 1
        return $this->input(Email::class, $formModel, $attribute, $config);
106
    }
107
108 1
    public function fieldset(array $config = []): Fieldset
109
    {
110 1
        return $this->field(Fieldset::class, $config);
111
    }
112
113 1
    public function hidden(FormModelInterface $formModel, string $attribute, array $config = []): Hidden
114
    {
115 1
        return $this->input(Hidden::class, $formModel, $attribute, $config);
116
    }
117
118 1
    public function image(array $config = []): Image
119
    {
120 1
        return $this->field(Image::class, $config);
121
    }
122
123 1
    public function number(FormModelInterface $formModel, string $attribute, array $config = []): Number
124
    {
125 1
        return $this->input(Number::class, $formModel, $attribute, $config);
126
    }
127
128 1
    public function password(FormModelInterface $formModel, string $attribute, array $config = []): Password
129
    {
130 1
        return $this->input(Password::class, $formModel, $attribute, $config);
131
    }
132
133 1
    public function radioList(FormModelInterface $formModel, string $attribute, array $config = []): RadioList
134
    {
135
        return $this
136 1
            ->field(RadioList::class, $config)
137 1
            ->attribute($formModel, $attribute);
138
    }
139
140 1
    public function range(FormModelInterface $formModel, string $attribute, array $config = []): Range
141
    {
142 1
        return $this->input(Range::class, $formModel, $attribute, $config);
143
    }
144
145 1
    public function resetButton(array $config = []): ResetButton
146
    {
147 1
        return $this->field(ResetButton::class, $config);
148
    }
149
150 1
    public function select(FormModelInterface $formModel, string $attribute, array $config = []): Select
151
    {
152 1
        return $this->input(Select::class, $formModel, $attribute, $config);
153
    }
154
155 1
    public function submitButton(array $config = []): SubmitButton
156
    {
157 1
        return $this->field(SubmitButton::class, $config);
158
    }
159
160 1
    public function telephone(FormModelInterface $formModel, string $attribute, array $config = []): Telephone
161
    {
162 1
        return $this->input(Telephone::class, $formModel, $attribute, $config);
163
    }
164
165 12
    public function text(FormModelInterface $formModel, string $attribute, array $config = []): Text
166
    {
167 12
        return $this->input(Text::class, $formModel, $attribute, $config);
168
    }
169
170 1
    public function textarea(FormModelInterface $formModel, string $attribute, array $config = []): Textarea
171
    {
172 1
        return $this->input(Textarea::class, $formModel, $attribute, $config);
173
    }
174
175 1
    public function url(FormModelInterface $formModel, string $attribute, array $config = []): Url
176
    {
177 1
        return $this->input(Url::class, $formModel, $attribute, $config);
178
    }
179
180 4
    public function label(FormModelInterface $formModel, string $attribute, array $config = []): Label
181
    {
182 4
        $widgetConfig = array_merge(
183 4
            $this->makeLabelConfig(),
184
            $config,
185
        );
186 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\RadioList or Yiisoft\Form\Field\Base\AbstractInputField or Yiisoft\Form\Field\CheckboxList. ( Ignorable by Annotation )

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

186
        return Label::widget($widgetConfig)->/** @scrutinizer ignore-call */ attribute($formModel, $attribute);
Loading history...
187
    }
188
189 3
    public function hint(FormModelInterface $formModel, string $attribute, array $config = []): Hint
190
    {
191 3
        $widgetConfig = array_merge(
192 3
            $this->hintConfig,
193
            $config,
194
        );
195 3
        return Hint::widget($widgetConfig)->attribute($formModel, $attribute);
196
    }
197
198 3
    public function error(FormModelInterface $formModel, string $attribute, array $config = []): Error
199
    {
200 3
        $widgetConfig = array_merge(
201 3
            $this->errorConfig,
202
            $config,
203
        );
204 3
        return Error::widget($widgetConfig)->attribute($formModel, $attribute);
205
    }
206
207
    /**
208
     * @psalm-template T
209
     * @psalm-param class-string<T> $class
210
     * @psalm-return T
211
     */
212 25
    public function input(string $class, FormModelInterface $formModel, string $attribute, array $config = []): object
213
    {
214 25
        $widget = $this->field($class, $config);
215 25
        if (!$widget instanceof AbstractInputField) {
216
            throw new InvalidArgumentException(
217
                sprintf(
218
                    'Input widget must be instance of "%s".',
219
                    AbstractInputField::class
220
                )
221
            );
222
        }
223
224 25
        return $widget->attribute($formModel, $attribute);
225
    }
226
227
    /**
228
     * @psalm-template T
229
     * @psalm-param class-string<T> $class
230
     * @psalm-return T
231
     */
232 33
    public function field(string $class, array $config = []): object
233
    {
234 33
        $traits = class_uses($class);
235 33
        if ($traits === false) {
236
            throw new RuntimeException('Invalid field class.');
237
        }
238
239 33
        $supports = [];
240 33
        if (in_array(PlaceholderTrait::class, $traits, true)) {
241 18
            $supports[] = self::SUPPORT_PLACEHOLDER;
242
        }
243
244 33
        $config = array_merge(
245 33
            $this->makeFieldConfig($supports),
246 33
            $this->fieldConfigs[$class] ?? [],
247
            $config,
248 33
            ['class' => $class],
249
        );
250
251
        /** @psalm-var T&AbstractField */
252 33
        return WidgetFactory::createWidget($config);
253
    }
254
255
    /**
256
     * @param int[] $supports
257
     */
258 33
    private function makeFieldConfig(array $supports): array
259
    {
260 33
        $config = $this->makeBaseFieldConfig();
261 33
        foreach ($supports as $support) {
262
            switch ($support) {
263 18
                case self::SUPPORT_PLACEHOLDER:
264 18
                    if ($this->usePlaceholder !== null) {
265 2
                        $config['usePlaceholder()'] = [$this->usePlaceholder];
266
                    }
267 18
                    break;
268
            }
269
        }
270 33
        return $config;
271
    }
272
273 33
    private function makeBaseFieldConfig(): array
274
    {
275 33
        if ($this->baseFieldConfig === null) {
276 10
            $this->baseFieldConfig = [];
277
278 10
            if ($this->containerTag !== null) {
279 2
                $this->baseFieldConfig['containerTag()'] = [$this->containerTag];
280
            }
281
282 10
            if ($this->containerTagAttributes !== []) {
283 2
                $this->baseFieldConfig['containerTagAttributes()'] = [$this->containerTagAttributes];
284
            }
285
286 10
            if ($this->useContainer !== null) {
287 1
                $this->baseFieldConfig['useContainer()'] = [$this->useContainer];
288
            }
289
290 10
            if ($this->template !== null) {
291 1
                $this->baseFieldConfig['template()'] = [$this->template];
292
            }
293
294 10
            if ($this->setInputIdAttribute !== null) {
295 1
                $this->baseFieldConfig['setInputIdAttribute()'] = [$this->setInputIdAttribute];
296
            }
297
298 10
            if ($this->inputTagAttributes !== []) {
299 2
                $this->baseFieldConfig['inputTagAttributes()'] = [$this->inputTagAttributes];
300
            }
301
302 10
            $labelConfig = $this->makeLabelConfig();
303 10
            if ($labelConfig !== []) {
304 2
                $this->baseFieldConfig['labelConfig()'] = [$labelConfig];
305
            }
306
307 10
            if ($this->hintConfig !== []) {
308 1
                $this->baseFieldConfig['hintConfig()'] = [$this->hintConfig];
309
            }
310
311 10
            if ($this->errorConfig !== []) {
312 1
                $this->baseFieldConfig['errorConfig()'] = [$this->errorConfig];
313
            }
314
        }
315 33
        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...
316
    }
317
318 14
    private function makeLabelConfig(): array
319
    {
320 14
        $config = [];
321
322 14
        if ($this->setInputIdAttribute === false) {
323 2
            $config['useInputIdAttribute()'] = [false];
324
        }
325
326 14
        return array_merge($config, $this->labelConfig);
327
    }
328
}
329