Passed
Pull Request — master (#192)
by Alexander
02:53
created

AbstractField::generateLabel()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
nc 6
nop 0
dl 0
loc 16
ccs 10
cts 10
cp 1
crap 4
rs 9.9666
c 1
b 0
f 0
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
use function in_array;
16
17
abstract class AbstractField extends Widget
18
{
19
    use FormAttributeTrait;
20
21
    /**
22
     * @psalm-var non-empty-string
23
     */
24
    protected string $containerTag = 'div';
25
    protected array $containerTagAttributes = [];
26
    protected bool $useContainer = true;
27
28
    protected string $template = "{label}\n{input}\n{hint}\n{error}";
29
    protected ?bool $hideLabel = null;
30
31
    protected ?string $inputId = null;
32
    protected ?string $inputIdFromTag = null;
33
    protected bool $setInputIdAttribute = true;
34
35
    protected array $inputTagAttributes = [];
36
37
    protected array $labelConfig = [];
38
    protected array $hintConfig = [];
39
    protected array $errorConfig = [];
40
41
    /**
42
     * Identifies the element (or elements) that describes the object.
43
     *
44
     * @link https://w3c.github.io/aria/#aria-describedby
45
     */
46
    final public function ariaDescribedBy(string $value): static
47
    {
48
        $new = clone $this;
49
        $new->inputTagAttributes['aria-describedby'] = $value;
50
        return $new;
51
    }
52
53
    /**
54
     * Defines a string value that labels the current element.
55
     *
56
     * @link https://w3c.github.io/aria/#aria-label
57
     */
58
    final public function ariaLabel(string $value): static
59
    {
60
        $new = clone $this;
61
        $new->inputTagAttributes['aria-label'] = $value;
62
        return $new;
63
    }
64
65
    /**
66
     * Specifies the form element the tag input element belongs to. The value of this attribute must be the ID
67
     * attribute of a form element in the same document.
68
     *
69
     * @link https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fae-form
70
     */
71
    final public function form(string $value): static
72
    {
73
        $new = clone $this;
74
        $new->inputTagAttributes['form'] = $value;
75
        return $new;
76
    }
77
78 4
    final public function containerTag(string $tag): static
79
    {
80 4
        if ($tag === '') {
81 1
            throw new InvalidArgumentException('Tag name cannot be empty.');
82
        }
83
84 3
        $new = clone $this;
85 3
        $new->containerTag = $tag;
86 3
        return $new;
87
    }
88
89 3
    final public function containerTagAttributes(array $attributes): static
90
    {
91 3
        $new = clone $this;
92 3
        $new->containerTagAttributes = $attributes;
93 3
        return $new;
94
    }
95
96 2
    final public function useContainer(bool $use): static
97
    {
98 2
        $new = clone $this;
99 2
        $new->useContainer = $use;
100 2
        return $new;
101
    }
102
103
    /**
104
     * Set layout template for render a field.
105
     */
106 2
    final public function template(string $template): static
107
    {
108 2
        $new = clone $this;
109 2
        $new->template = $template;
110 2
        return $new;
111
    }
112
113 2
    final public function hideLabel(?bool $hide = true): static
114
    {
115 2
        $new = clone $this;
116 2
        $new->hideLabel = $hide;
117 2
        return $new;
118
    }
119
120 2
    final public function inputId(?string $inputId): static
121
    {
122 2
        $new = clone $this;
123 2
        $new->inputId = $inputId;
124 2
        return $new;
125
    }
126
127 2
    final public function setInputIdAttribute(bool $value): static
128
    {
129 2
        $new = clone $this;
130 2
        $new->setInputIdAttribute = $value;
131 2
        return $new;
132
    }
133
134 6
    final public function inputTagAttributes(array $attributes): static
135
    {
136 6
        $new = clone $this;
137 6
        $new->inputTagAttributes = $attributes;
138 6
        return $new;
139
    }
140
141 3
    final public function labelConfig(array $config): static
142
    {
143 3
        $new = clone $this;
144 3
        $new->labelConfig = $config;
145 3
        return $new;
146
    }
147
148 1
    final public function label(?string $content): static
149
    {
150 1
        $new = clone $this;
151 1
        $new->labelConfig['content()'] = [$content];
152 1
        return $new;
153
    }
154
155 2
    final public function hintConfig(array $config): static
156
    {
157 2
        $new = clone $this;
158 2
        $new->hintConfig = $config;
159 2
        return $new;
160
    }
161
162 1
    final public function hint(?string $content): static
163
    {
164 1
        $new = clone $this;
165 1
        $new->hintConfig['content()'] = [$content];
166 1
        return $new;
167
    }
168
169 2
    final public function errorConfig(array $config): static
170
    {
171 2
        $new = clone $this;
172 2
        $new->errorConfig = $config;
173 2
        return $new;
174
    }
175
176 65
    final protected function getInputName(): string
177
    {
178 65
        return HtmlForm::getInputName($this->getFormModel(), $this->attribute);
179
    }
180
181 65
    final protected function getInputTagAttributes(): array
182
    {
183 65
        $attributes = $this->inputTagAttributes;
184
185 65
        $this->prepareIdInInputTagAttributes($attributes);
186
187 65
        if ($this->isUsePlaceholder()) {
188
            /** @psalm-suppress UndefinedMethod */
189 40
            $this->preparePlaceholderInInputTagAttributes($attributes);
0 ignored issues
show
Bug introduced by
The method preparePlaceholderInInputTagAttributes() does not exist on Yiisoft\Form\Field\Base\AbstractField. It seems like you code against a sub-type of said class. However, the method does not exist in Yiisoft\Form\Field\Checkbox or Yiisoft\Form\Field\Base\AbstractDateTimeField or Yiisoft\Form\Field\Hidden or Yiisoft\Form\Field\Date or Yiisoft\Form\Field\DateTimeLocal. Are you sure you never get one of those? ( Ignorable by Annotation )

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

189
            $this->/** @scrutinizer ignore-call */ 
190
                   preparePlaceholderInInputTagAttributes($attributes);
Loading history...
190
        }
191
192 65
        return $attributes;
193
    }
194
195 65
    final protected function prepareIdInInputTagAttributes(array &$attributes): void
196
    {
197
        /** @var mixed $idFromTag */
198 65
        $idFromTag = $attributes['id'] ?? null;
199 65
        if ($idFromTag !== null) {
200 2
            $this->inputIdFromTag = (string)$idFromTag;
201
        }
202
203 65
        if ($this->setInputIdAttribute) {
204 63
            if ($this->inputId !== null) {
205 2
                $attributes['id'] = $this->inputId;
206 61
            } elseif ($idFromTag === null) {
207 60
                $attributes['id'] = $this->getInputId();
208
            }
209
        }
210
    }
211
212 66
    final protected function run(): string
213
    {
214 66
        if (!$this->useContainer) {
215 3
            return $this->generateContent();
216
        }
217
218 63
        $containerTag = CustomTag::name($this->containerTag);
219 63
        if ($this->containerTagAttributes !== []) {
220 3
            $containerTag = $containerTag->attributes($this->containerTagAttributes);
221
        }
222
223 63
        return $containerTag->open()
224
            . PHP_EOL
225 63
            . $this->generateContent()
226
            . PHP_EOL
227 62
            . $containerTag->close();
228
    }
229
230
    abstract protected function generateInput(): string;
231
232 45
    protected function shouldHideLabel(): bool
233
    {
234 45
        return false;
235
    }
236
237 66
    private function generateContent(): string
238
    {
239 65
        $parts = [
240 66
            '{input}' => $this->generateInput(),
241 65
            '{label}' => ($this->hideLabel ?? $this->shouldHideLabel()) ? '' : $this->generateLabel(),
242 65
            '{hint}' => $this->generateHint(),
243 65
            '{error}' => $this->generateError(),
244
        ];
245
246 65
        return preg_replace('/^\h*\v+/m', '', trim(strtr($this->template, $parts)));
247
    }
248
249 50
    private function generateLabel(): string
250
    {
251 50
        $label = Label::widget($this->labelConfig)
252 50
            ->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

252
            ->/** @scrutinizer ignore-call */ attribute($this->getFormModel(), $this->attribute);
Loading history...
253
254 50
        if ($this->setInputIdAttribute === false) {
255 2
            $label = $label->useInputIdAttribute(false);
256
        }
257
258 50
        if ($this->inputId !== null) {
259 2
            $label = $label->forId($this->inputId);
260 48
        } elseif ($this->inputIdFromTag !== null) {
261 1
            $label = $label->forId($this->inputIdFromTag);
262
        }
263
264 50
        return $label->render();
265
    }
266
267 65
    private function generateHint(): string
268
    {
269 65
        return Hint::widget($this->hintConfig)
270 65
            ->attribute($this->getFormModel(), $this->attribute)
271 65
            ->render();
272
    }
273
274 65
    private function generateError(): string
275
    {
276 65
        return Error::widget($this->errorConfig)
277 65
            ->attribute($this->getFormModel(), $this->attribute)
278 65
            ->render();
279
    }
280
281 65
    private function isUsePlaceholder(): bool
282
    {
283 65
        $traits = class_uses($this);
284 65
        return in_array(PlaceholderTrait::class, $traits, true);
285
    }
286
}
287