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

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