Passed
Pull Request — master (#192)
by Alexander
28:18 queued 25:44
created

FieldFactory   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 302
Duplicated Lines 0 %

Test Coverage

Coverage 95.2%

Importance

Changes 6
Bugs 1 Features 0
Metric Value
eloc 104
c 6
b 1
f 0
dl 0
loc 302
ccs 119
cts 125
cp 0.952
rs 5.04
wmc 57

31 Methods

Rating   Name   Duplication   Size   Complexity  
A resetButton() 0 3 1
A label() 0 7 1
A range() 0 3 1
A __construct() 0 20 1
A radioList() 0 5 1
A file() 0 3 1
A textarea() 0 3 1
A hidden() 0 3 1
A input() 0 13 2
A text() 0 3 1
A button() 0 3 1
A error() 0 7 1
A fieldset() 0 3 1
A date() 0 3 1
A buttonGroup() 0 3 1
A password() 0 3 1
A dateTimeLocal() 0 3 1
A url() 0 3 1
A number() 0 3 1
A checkboxList() 0 5 1
A image() 0 3 1
A email() 0 3 1
A hint() 0 7 1
F makeFieldConfig() 0 81 26
A field() 0 11 1
A telephone() 0 3 1
A errorSummary() 0 5 1
A submitButton() 0 3 1
A select() 0 3 1
A dateTime() 0 3 1
A checkbox() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like FieldFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FieldFactory, and based on these observations, apply Extract Interface, too.

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

201
        return Label::widget($widgetConfig)->/** @scrutinizer ignore-call */ attribute($formModel, $attribute);
Loading history...
202
    }
203
204 3
    public function hint(FormModelInterface $formModel, string $attribute, array $config = []): Hint
205
    {
206 3
        $widgetConfig = array_merge(
207 3
            $this->hintConfig,
208
            $config,
209
        );
210 3
        return Hint::widget($widgetConfig)->attribute($formModel, $attribute);
211
    }
212
213 3
    public function error(FormModelInterface $formModel, string $attribute, array $config = []): Error
214
    {
215 3
        $widgetConfig = array_merge(
216 3
            $this->errorConfig,
217
            $config,
218
        );
219 3
        return Error::widget($widgetConfig)->attribute($formModel, $attribute);
220
    }
221
222
    /**
223
     * @psalm-template T
224
     * @psalm-param class-string<T> $class
225
     * @psalm-return T
226
     */
227 32
    public function input(string $class, FormModelInterface $formModel, string $attribute, array $config = []): object
228
    {
229 32
        $widget = $this->field($class, $config);
230 32
        if (!$widget instanceof InputField) {
231 1
            throw new InvalidArgumentException(
232 1
                sprintf(
233
                    'Input widget must be instance of "%s".',
234
                    InputField::class
235
                )
236
            );
237
        }
238
239 31
        return $widget->attribute($formModel, $attribute);
240
    }
241
242
    /**
243
     * @psalm-template T
244
     * @psalm-param class-string<T> $class
245
     * @psalm-return T
246
     */
247 47
    public function field(string $class, array $config = []): object
248
    {
249 47
        $config = array_merge(
250 47
            $this->makeFieldConfig($class),
251 47
            $this->fieldConfigs[$class] ?? [],
252
            $config,
253 47
            ['class' => $class],
254
        );
255
256
        /** @psalm-var T */
257 47
        return WidgetFactory::createWidget($config);
258
    }
259
260
    /**
261
     * @psalm-param class-string $class
262
     */
263 47
    private function makeFieldConfig(string $class): array
264
    {
265 47
        $config = [];
266
267 47
        if ($this->containerTag !== null) {
268 2
            $config['containerTag()'] = [$this->containerTag];
269
        }
270 47
        if ($this->containerTagAttributes !== []) {
271 4
            $config['containerTagAttributes()'] = [$this->containerTagAttributes];
272
        }
273 47
        if ($this->containerClass !== null) {
274
            $config['containerClass()'] = is_array($this->containerClass)
275
                ? $this->containerClass
276
                : [$this->containerClass];
277
        }
278 47
        if ($this->useContainer !== null) {
279 1
            $config['useContainer()'] = [$this->useContainer];
280
        }
281
282 47
        if (is_a($class, PartsField::class, true)) {
283 43
            if ($this->template !== null) {
284 1
                $config['template()'] = [$this->template];
285
            }
286 43
            if ($this->templateBegin !== null) {
287 1
                $config['templateBegin()'] = [$this->templateBegin];
288
            }
289 43
            if ($this->templateEnd !== null) {
290 1
                $config['templateEnd()'] = [$this->templateEnd];
291
            }
292 43
            if ($this->labelConfig !== []) {
293 1
                $config['labelConfig()'] = [$this->labelConfig];
294
            }
295 43
            if ($this->hintConfig !== []) {
296 1
                $config['hintConfig()'] = [$this->hintConfig];
297
            }
298 43
            if ($this->errorConfig !== []) {
299 1
                $config['errorConfig()'] = [$this->errorConfig];
300
            }
301
        }
302
303 47
        if (is_a($class, InputField::class, true)) {
304 31
            if ($this->setInputIdAttribute !== null) {
305 1
                $config['setInputIdAttribute()'] = [$this->setInputIdAttribute];
306 1
                if ($this->setInputIdAttribute === false) {
307 1
                    $config['labelConfig()'] = [
308 1
                        $this->labelConfig + ['useInputIdAttribute()' => [false]],
309
                    ];
310
                }
311
            }
312 31
            if ($this->inputTagAttributes !== []) {
313 2
                $config['inputTagAttributes()'] = [$this->inputTagAttributes];
314
            }
315 31
            if ($this->inputClass !== null) {
316
                $config['inputClass()'] = is_array($this->inputClass)
317
                    ? $this->inputClass
318
                    : [$this->inputClass];
319
            }
320
        }
321
322 47
        if (is_a($class, PlaceholderInterface::class, true)) {
323 22
            if ($this->usePlaceholder !== null) {
324 2
                $config['usePlaceholder()'] = [$this->usePlaceholder];
325
            }
326
        }
327
328 47
        if (is_a($class, EnrichmentFromRulesInterface::class, true)) {
329 28
            if ($this->enrichmentFromRules !== null) {
330 1
                $config['enrichmentFromRules()'] = [$this->enrichmentFromRules];
331
            }
332
        }
333
334 47
        if (is_a($class, ValidationClassInterface::class, true)) {
335 31
            if ($this->validClass !== null) {
336 1
                $config['validClass()'] = [$this->validClass];
337
            }
338 31
            if ($this->invalidClass !== null) {
339 1
                $config['invalidClass()'] = [$this->invalidClass];
340
            }
341
        }
342
343 47
        return $config;
344
    }
345
}
346