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

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