Passed
Pull Request — master (#192)
by Sergei
02:47
created

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

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