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

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