Passed
Pull Request — master (#159)
by Alexander
04:51 queued 02:29
created

AbstractField   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 96
dl 0
loc 239
ccs 104
cts 104
cp 1
rs 9.92
c 2
b 0
f 0
wmc 31

20 Methods

Rating   Name   Duplication   Size   Complexity  
A containerTagAttributes() 0 5 1
A containerTag() 0 9 2
A useContainer() 0 5 1
A getInputName() 0 3 1
A formElementTagAttributes() 0 5 1
A hintConfig() 0 5 1
A setInputIdAttribute() 0 5 1
A inputId() 0 5 1
A hint() 0 5 1
A labelConfig() 0 5 1
A template() 0 5 1
A errorConfig() 0 5 1
A label() 0 5 1
A generateContent() 0 10 1
A run() 0 16 3
A getFormElementTagAttributes() 0 11 2
A generateError() 0 5 1
A generateLabel() 0 16 4
A generateHint() 0 5 1
A prepareIdInFormElementTagAttributes() 0 13 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Field\Base;
6
7
use InvalidArgumentException;
8
use Yiisoft\Form\Field\Part\Error;
9
use Yiisoft\Form\Field\Part\Hint;
10
use Yiisoft\Form\Field\Part\Label;
11
use Yiisoft\Form\Helper\HtmlForm;
12
use Yiisoft\Html\Tag\CustomTag;
13
use Yiisoft\Widget\Widget;
14
15
abstract class AbstractField extends Widget
16
{
17
    use FormAttributeTrait;
18
19
    /**
20
     * @psalm-var non-empty-string
21
     */
22
    private string $containerTag = 'div';
23
    private array $containerTagAttributes = [];
24
    private bool $useContainer = true;
25
26
    private string $template = "{label}\n{input}\n{hint}\n{error}";
27
28
    private ?string $inputId = null;
29
    private ?string $inputIdFromTag = null;
30
    private bool $setInputIdAttribute = true;
31
32
    private array $formElementTagAttributes = [];
33
34
    private array $labelConfig = [];
35
    private array $hintConfig = [];
36
    private array $errorConfig = [];
37
38
    /**
39
     * @return static
40
     */
41 5
    final public function containerTag(string $tag): self
42
    {
43 5
        if ($tag === '') {
44 1
            throw new InvalidArgumentException('Tag name cannot be empty.');
45
        }
46
47 4
        $new = clone $this;
48 4
        $new->containerTag = $tag;
49 4
        return $new;
50
    }
51
52
    /**
53
     * @return static
54
     */
55 4
    final public function containerTagAttributes(array $attributes): self
56
    {
57 4
        $new = clone $this;
58 4
        $new->containerTagAttributes = $attributes;
59 4
        return $new;
60
    }
61
62 2
    final public function useContainer(bool $use): self
63
    {
64 2
        $new = clone $this;
65 2
        $new->useContainer = $use;
66 2
        return $new;
67
    }
68
69
    /**
70
     * Set layout template for render a field.
71
     *
72
     * @param string $template
73
     *
74
     * @return static
75
     */
76 2
    final public function template(string $template): self
77
    {
78 2
        $new = clone $this;
79 2
        $new->template = $template;
80 2
        return $new;
81
    }
82
83
    /**
84
     * @return static
85
     */
86 2
    final public function inputId(?string $inputId): self
87
    {
88 2
        $new = clone $this;
89 2
        $new->inputId = $inputId;
90 2
        return $new;
91
    }
92
93
    /**
94
     * @return static
95
     */
96 2
    final public function setInputIdAttribute(bool $value): self
97
    {
98 2
        $new = clone $this;
99 2
        $new->setInputIdAttribute = $value;
100 2
        return $new;
101
    }
102
103 6
    final public function formElementTagAttributes(array $attributes): self
104
    {
105 6
        $new = clone $this;
106 6
        $new->formElementTagAttributes = $attributes;
107 6
        return $new;
108
    }
109
110
    /**
111
     * @return static
112
     */
113 3
    final public function labelConfig(array $config): self
114
    {
115 3
        $new = clone $this;
116 3
        $new->labelConfig = $config;
117 3
        return $new;
118
    }
119
120
    /**
121
     * @return static
122
     */
123 1
    final public function label(?string $content): self
124
    {
125 1
        $new = clone $this;
126 1
        $new->labelConfig['content()'] = [$content];
127 1
        return $new;
128
    }
129
130
    /**
131
     * @return static
132
     */
133 2
    final public function hintConfig(array $config): self
134
    {
135 2
        $new = clone $this;
136 2
        $new->hintConfig = $config;
137 2
        return $new;
138
    }
139
140 1
    final public function hint(?string $content): self
141
    {
142 1
        $new = clone $this;
143 1
        $new->hintConfig['content()'] = [$content];
144 1
        return $new;
145
    }
146
147
    /**
148
     * @return static
149
     */
150 2
    final public function errorConfig(array $config): self
151
    {
152 2
        $new = clone $this;
153 2
        $new->errorConfig = $config;
154 2
        return $new;
155
    }
156
157 29
    final protected function getInputName(): string
158
    {
159 29
        return HtmlForm::getInputName($this->getFormModel(), $this->attribute);
160
    }
161
162 29
    final protected function getFormElementTagAttributes(): array
163
    {
164 29
        $attributes = $this->formElementTagAttributes;
165
166 29
        $this->prepareIdInFormElementTagAttributes($attributes);
167
168 29
        if ($this instanceof PlaceholderInterface) {
169 29
            $this->preparePlaceholderInFormElementTagAttributes($attributes);
0 ignored issues
show
Bug introduced by
The method preparePlaceholderInFormElementTagAttributes() does not exist on Yiisoft\Form\Field\Base\AbstractField. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Form\Field\Base\AbstractField. ( Ignorable by Annotation )

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

169
            $this->/** @scrutinizer ignore-call */ 
170
                   preparePlaceholderInFormElementTagAttributes($attributes);
Loading history...
Bug introduced by
The method preparePlaceholderInFormElementTagAttributes() does not exist on Yiisoft\Form\Field\Base\PlaceholderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Form\Field\Base\PlaceholderInterface. ( Ignorable by Annotation )

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

169
            $this->/** @scrutinizer ignore-call */ 
170
                   preparePlaceholderInFormElementTagAttributes($attributes);
Loading history...
170
        }
171
172 29
        return $attributes;
173
    }
174
175 29
    final protected function prepareIdInFormElementTagAttributes(array &$attributes): void
176
    {
177
        /** @var mixed $idFromTag */
178 29
        $idFromTag = $attributes['id'] ?? null;
179 29
        if ($idFromTag !== null) {
180 2
            $this->inputIdFromTag = (string) $idFromTag;
181
        }
182
183 29
        if ($this->setInputIdAttribute) {
184 27
            if ($this->inputId !== null) {
185 2
                $attributes['id'] = $this->inputId;
186 25
            } elseif ($idFromTag === null) {
187 24
                $attributes['id'] = $this->getInputId();
188
            }
189
        }
190 29
    }
191
192 29
    final protected function run(): string
193
    {
194 29
        if (!$this->useContainer) {
195 2
            return $this->generateContent();
196
        }
197
198 27
        $containerTag = CustomTag::name($this->containerTag);
199 27
        if ($this->containerTagAttributes !== []) {
200 4
            $containerTag = $containerTag->attributes($this->containerTagAttributes);
201
        }
202
203 27
        return $containerTag->open()
204 27
            . PHP_EOL
205 27
            . $this->generateContent()
206 27
            . PHP_EOL
207 27
            . $containerTag->close();
208
    }
209
210
    abstract protected function generateInput(): string;
211
212 29
    private function generateContent(): string
213
    {
214 29
        $parts = [
215 29
            '{input}' => $this->generateInput(),
216 29
            '{label}' => $this->generateLabel(),
217 29
            '{hint}' => $this->generateHint(),
218 29
            '{error}' => $this->generateError(),
219
        ];
220
221 29
        return preg_replace('/^\h*\v+/m', '', trim(strtr($this->template, $parts)));
222
    }
223
224 29
    private function generateLabel(): string
225
    {
226 29
        $label = Label::widget($this->labelConfig)
227 29
            ->attribute($this->getFormModel(), $this->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

227
            ->/** @scrutinizer ignore-call */ attribute($this->getFormModel(), $this->attribute);
Loading history...
228
229 29
        if ($this->setInputIdAttribute === false) {
230 2
            $label = $label->useInputIdAttribute(false);
231
        }
232
233 29
        if ($this->inputId !== null) {
234 2
            $label = $label->forId($this->inputId);
235 27
        } elseif ($this->inputIdFromTag !== null) {
236 1
            $label = $label->forId($this->inputIdFromTag);
237
        }
238
239 29
        return $label->render();
240
    }
241
242 29
    private function generateHint(): string
243
    {
244 29
        return Hint::widget($this->hintConfig)
245 29
            ->attribute($this->getFormModel(), $this->attribute)
246 29
            ->render();
247
    }
248
249 29
    private function generateError(): string
250
    {
251 29
        return Error::widget($this->errorConfig)
252 29
            ->attribute($this->getFormModel(), $this->attribute)
253 29
            ->render();
254
    }
255
}
256