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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

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