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

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

114
        return Label::widget($widgetConfig)->/** @scrutinizer ignore-call */ attribute($formModel, $attribute);
Loading history...
115
    }
116
117 3
    public function hint(FormModelInterface $formModel, string $attribute, array $config = []): Hint
118
    {
119 3
        $widgetConfig = array_merge(
120 3
            $this->hintConfig,
121
            $config,
122
        );
123 3
        return Hint::widget($widgetConfig)->attribute($formModel, $attribute);
124
    }
125
126 3
    public function error(FormModelInterface $formModel, string $attribute, array $config = []): Error
127
    {
128 3
        $widgetConfig = array_merge(
129 3
            $this->errorConfig,
130
            $config,
131
        );
132 3
        return Error::widget($widgetConfig)->attribute($formModel, $attribute);
133
    }
134
135
    /**
136
     * @psalm-template T
137
     * @psalm-param class-string<T> $class
138
     * @psalm-return T
139
     */
140 20
    public function field(string $class, FormModelInterface $formModel, string $attribute, array $config = []): object
141
    {
142 20
        $traits = class_uses($class);
143 20
        if ($traits === false) {
144
            throw new RuntimeException('Invalid field class.');
145
        }
146
147 20
        $supports = [];
148 20
        if (in_array(PlaceholderTrait::class, $traits, true)) {
149 16
            $supports[] = self::SUPPORT_PLACEHOLDER;
150
        }
151
152 20
        $config = array_merge(
153 20
            $this->makeFieldConfig($supports),
154 20
            $this->fieldConfigs[$class] ?? [],
155
            $config,
156 20
            ['class' => $class],
157
        );
158
159
        /** @psalm-var T&AbstractField $widget */
160 20
        $widget = WidgetFactory::createWidget($config);
161
162 20
        return $widget->attribute($formModel, $attribute);
163
    }
164
165
    /**
166
     * @param int[] $supports
167
     */
168 20
    private function makeFieldConfig(array $supports): array
169
    {
170 20
        $config = $this->makeBaseFieldConfig();
171 20
        foreach ($supports as $support) {
172
            switch ($support) {
173 16
                case self::SUPPORT_PLACEHOLDER:
174 16
                    if ($this->usePlaceholder !== null) {
175 2
                        $config['usePlaceholder()'] = [$this->usePlaceholder];
176
                    }
177 16
                    break;
178
            }
179
        }
180 20
        return $config;
181
    }
182
183 20
    private function makeBaseFieldConfig(): array
184
    {
185 20
        if ($this->baseFieldConfig === null) {
186 10
            $this->baseFieldConfig = [];
187
188 10
            if ($this->containerTag !== null) {
189 2
                $this->baseFieldConfig['containerTag()'] = [$this->containerTag];
190
            }
191
192 10
            if ($this->containerTagAttributes !== []) {
193 2
                $this->baseFieldConfig['containerTagAttributes()'] = [$this->containerTagAttributes];
194
            }
195
196 10
            if ($this->useContainer !== null) {
197 1
                $this->baseFieldConfig['useContainer()'] = [$this->useContainer];
198
            }
199
200 10
            if ($this->template !== null) {
201 1
                $this->baseFieldConfig['template()'] = [$this->template];
202
            }
203
204 10
            if ($this->setInputIdAttribute !== null) {
205 1
                $this->baseFieldConfig['setInputIdAttribute()'] = [$this->setInputIdAttribute];
206
            }
207
208 10
            if ($this->inputTagAttributes !== []) {
209 2
                $this->baseFieldConfig['inputTagAttributes()'] = [$this->inputTagAttributes];
210
            }
211
212 10
            $labelConfig = $this->makeLabelConfig();
213 10
            if ($labelConfig !== []) {
214 2
                $this->baseFieldConfig['labelConfig()'] = [$labelConfig];
215
            }
216
217 10
            if ($this->hintConfig !== []) {
218 1
                $this->baseFieldConfig['hintConfig()'] = [$this->hintConfig];
219
            }
220
221 10
            if ($this->errorConfig !== []) {
222 1
                $this->baseFieldConfig['errorConfig()'] = [$this->errorConfig];
223
            }
224
        }
225 20
        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...
226
    }
227
228 14
    private function makeLabelConfig(): array
229
    {
230 14
        $config = [];
231
232 14
        if ($this->setInputIdAttribute === false) {
233 2
            $config['useInputIdAttribute()'] = [false];
234
        }
235
236 14
        return array_merge($config, $this->labelConfig);
237
    }
238
}
239