Passed
Pull Request — master (#192)
by Alexander
04:59 queued 02:28
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\Hidden;
12
use Yiisoft\Form\Field\Part\Error;
13
use Yiisoft\Form\Field\Part\Hint;
14
use Yiisoft\Form\Field\Part\Label;
15
use Yiisoft\Form\Field\Text;
16
use Yiisoft\Widget\WidgetFactory;
17
18
use function in_array;
19
20
final class FieldFactory
21
{
22
    private const SUPPORT_PLACEHOLDER = 1;
23
24
    private ?array $baseFieldConfig = null;
25
26
    /**
27
     * @param array[] $fieldConfigs
28
     */
29 17
    public function __construct(
30
        private ?string $containerTag = null,
31
        private array $containerTagAttributes = [],
32
        private ?bool $useContainer = null,
33
        private ?string $template = null,
34
        private ?bool $setInputIdAttribute = null,
35
        private array $inputTagAttributes = [],
36
        private array $labelConfig = [],
37
        private array $hintConfig = [],
38
        private array $errorConfig = [],
39
        private ?bool $usePlaceholder = null,
40
        private array $fieldConfigs = [],
41
    ) {
42
    }
43
44 1
    public function hidden(FormModelInterface $formModel, string $attribute, array $config = []): Hidden
45
    {
46 1
        return $this->field(Hidden::class, $formModel, $attribute, $config);
47
    }
48
49 10
    public function text(FormModelInterface $formModel, string $attribute, array $config = []): Text
50
    {
51 10
        return $this->field(Text::class, $formModel, $attribute, $config);
52
    }
53
54 4
    public function label(FormModelInterface $formModel, string $attribute, array $config = []): Label
55
    {
56 4
        $widgetConfig = array_merge(
57 4
            $this->makeLabelConfig(),
58
            $config,
59
        );
60 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

60
        return Label::widget($widgetConfig)->/** @scrutinizer ignore-call */ attribute($formModel, $attribute);
Loading history...
61
    }
62
63 3
    public function hint(FormModelInterface $formModel, string $attribute, array $config = []): Hint
64
    {
65 3
        $widgetConfig = array_merge(
66 3
            $this->hintConfig,
67
            $config,
68
        );
69 3
        return Hint::widget($widgetConfig)->attribute($formModel, $attribute);
70
    }
71
72 3
    public function error(FormModelInterface $formModel, string $attribute, array $config = []): Error
73
    {
74 3
        $widgetConfig = array_merge(
75 3
            $this->errorConfig,
76
            $config,
77
        );
78 3
        return Error::widget($widgetConfig)->attribute($formModel, $attribute);
79
    }
80
81
    /**
82
     * @psalm-template T
83
     * @psalm-param class-string<T> $class
84
     * @psalm-return T
85
     */
86 11
    public function field(string $class, FormModelInterface $formModel, string $attribute, array $config = []): object
87
    {
88 11
        $traits = class_uses($class);
89 11
        if ($traits === false) {
90
            throw new RuntimeException('Invalid field class.');
91
        }
92
93 11
        $supports = [];
94 11
        if (in_array(PlaceholderTrait::class, $traits, true)) {
95 10
            $supports[] = self::SUPPORT_PLACEHOLDER;
96
        }
97
98 11
        $config = array_merge(
99 11
            $this->makeFieldConfig($supports),
100 11
            $this->fieldConfigs[$class] ?? [],
101
            $config,
102 11
            ['class' => $class],
103
        );
104
105
        /** @psalm-var T&AbstractField $widget */
106 11
        $widget = WidgetFactory::createWidget($config);
107
108 11
        return $widget->attribute($formModel, $attribute);
109
    }
110
111
    /**
112
     * @param int[] $supports
113
     */
114 11
    private function makeFieldConfig(array $supports): array
115
    {
116 11
        $config = $this->makeBaseFieldConfig();
117 11
        foreach ($supports as $support) {
118
            switch ($support) {
119 10
                case self::SUPPORT_PLACEHOLDER:
120 10
                    if ($this->usePlaceholder !== null) {
121 2
                        $config['usePlaceholder()'] = [$this->usePlaceholder];
122
                    }
123 10
                    break;
124
            }
125
        }
126 11
        return $config;
127
    }
128
129 11
    private function makeBaseFieldConfig(): array
130
    {
131 11
        if ($this->baseFieldConfig === null) {
132 10
            $this->baseFieldConfig = [];
133
134 10
            if ($this->containerTag !== null) {
135 2
                $this->baseFieldConfig['containerTag()'] = [$this->containerTag];
136
            }
137
138 10
            if ($this->containerTagAttributes !== []) {
139 2
                $this->baseFieldConfig['containerTagAttributes()'] = [$this->containerTagAttributes];
140
            }
141
142 10
            if ($this->useContainer !== null) {
143 1
                $this->baseFieldConfig['useContainer()'] = [$this->useContainer];
144
            }
145
146 10
            if ($this->template !== null) {
147 1
                $this->baseFieldConfig['template()'] = [$this->template];
148
            }
149
150 10
            if ($this->setInputIdAttribute !== null) {
151 1
                $this->baseFieldConfig['setInputIdAttribute()'] = [$this->setInputIdAttribute];
152
            }
153
154 10
            if ($this->inputTagAttributes !== []) {
155 2
                $this->baseFieldConfig['inputTagAttributes()'] = [$this->inputTagAttributes];
156
            }
157
158 10
            $labelConfig = $this->makeLabelConfig();
159 10
            if ($labelConfig !== []) {
160 2
                $this->baseFieldConfig['labelConfig()'] = [$labelConfig];
161
            }
162
163 10
            if ($this->hintConfig !== []) {
164 1
                $this->baseFieldConfig['hintConfig()'] = [$this->hintConfig];
165
            }
166
167 10
            if ($this->errorConfig !== []) {
168 1
                $this->baseFieldConfig['errorConfig()'] = [$this->errorConfig];
169
            }
170
        }
171 11
        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...
172
    }
173
174 14
    private function makeLabelConfig(): array
175
    {
176 14
        $config = [];
177
178 14
        if ($this->setInputIdAttribute === false) {
179 2
            $config['useInputIdAttribute()'] = [false];
180
        }
181
182 14
        return array_merge($config, $this->labelConfig);
183
    }
184
}
185