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

FieldFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 1
eloc 0
c 2
b 1
f 0
nc 1
nop 11
dl 0
loc 13
ccs 1
cts 1
cp 1
crap 1
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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