Passed
Pull Request — master (#192)
by Sergei
02:45
created

FieldFactory::makeFieldConfig()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

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

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