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

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