Passed
Pull Request — master (#192)
by Sergei
02:47
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\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