Passed
Pull Request — master (#192)
by Alexander
04:59 queued 02:28
created

AbstractField::inputId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
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
30
    protected ?string $inputId = null;
31
    protected ?string $inputIdFromTag = null;
32
    protected bool $setInputIdAttribute = true;
33
34
    protected array $inputTagAttributes = [];
35
36
    protected array $labelConfig = [];
37
    protected array $hintConfig = [];
38
    protected array $errorConfig = [];
39
40
    /**
41
     * @return static
42
     */
43 4
    final public function containerTag(string $tag): self
44
    {
45 4
        if ($tag === '') {
46 1
            throw new InvalidArgumentException('Tag name cannot be empty.');
47
        }
48
49 3
        $new = clone $this;
50 3
        $new->containerTag = $tag;
51 3
        return $new;
52
    }
53
54
    /**
55
     * @return static
56
     */
57 3
    final public function containerTagAttributes(array $attributes): self
58
    {
59 3
        $new = clone $this;
60 3
        $new->containerTagAttributes = $attributes;
61 3
        return $new;
62
    }
63
64 2
    final public function useContainer(bool $use): self
65
    {
66 2
        $new = clone $this;
67 2
        $new->useContainer = $use;
68 2
        return $new;
69
    }
70
71
    /**
72
     * Set layout template for render a field.
73
     *
74
     * @param string $template
75
     *
76
     * @return static
77
     */
78 2
    final public function template(string $template): self
79
    {
80 2
        $new = clone $this;
81 2
        $new->template = $template;
82 2
        return $new;
83
    }
84
85
    /**
86
     * @return static
87
     */
88 2
    final public function inputId(?string $inputId): self
89
    {
90 2
        $new = clone $this;
91 2
        $new->inputId = $inputId;
92 2
        return $new;
93
    }
94
95
    /**
96
     * @return static
97
     */
98 2
    final public function setInputIdAttribute(bool $value): self
99
    {
100 2
        $new = clone $this;
101 2
        $new->setInputIdAttribute = $value;
102 2
        return $new;
103
    }
104
105 6
    final public function inputTagAttributes(array $attributes): self
106
    {
107 6
        $new = clone $this;
108 6
        $new->inputTagAttributes = $attributes;
109 6
        return $new;
110
    }
111
112
    /**
113
     * @return static
114
     */
115 3
    final public function labelConfig(array $config): self
116
    {
117 3
        $new = clone $this;
118 3
        $new->labelConfig = $config;
119 3
        return $new;
120
    }
121
122
    /**
123
     * @return static
124
     */
125 1
    final public function label(?string $content): self
126
    {
127 1
        $new = clone $this;
128 1
        $new->labelConfig['content()'] = [$content];
129 1
        return $new;
130
    }
131
132
    /**
133
     * @return static
134
     */
135 2
    final public function hintConfig(array $config): self
136
    {
137 2
        $new = clone $this;
138 2
        $new->hintConfig = $config;
139 2
        return $new;
140
    }
141
142
    /**
143
     * @return static
144
     */
145 1
    final public function hint(?string $content): self
146
    {
147 1
        $new = clone $this;
148 1
        $new->hintConfig['content()'] = [$content];
149 1
        return $new;
150
    }
151
152
    /**
153
     * @return static
154
     */
155 2
    final public function errorConfig(array $config): self
156
    {
157 2
        $new = clone $this;
158 2
        $new->errorConfig = $config;
159 2
        return $new;
160
    }
161
162 29
    final protected function getInputName(): string
163
    {
164 29
        return HtmlForm::getInputName($this->getFormModel(), $this->attribute);
165
    }
166
167 29
    final protected function getInputTagAttributes(): array
168
    {
169 29
        $attributes = $this->inputTagAttributes;
170
171 29
        $this->prepareIdInInputTagAttributes($attributes);
172
173 29
        if ($this->isUsePlaceholder()) {
174
            /** @psalm-suppress UndefinedMethod */
175 28
            $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 Yiisoft\Form\Field\Base\AbstractField such as Yiisoft\Form\Field\Text. ( Ignorable by Annotation )

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

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

233
            ->/** @scrutinizer ignore-call */ attribute($this->getFormModel(), $this->attribute);
Loading history...
234
235 29
        if ($this->setInputIdAttribute === false) {
236 2
            $label = $label->useInputIdAttribute(false);
237
        }
238
239 29
        if ($this->inputId !== null) {
240 2
            $label = $label->forId($this->inputId);
241 27
        } elseif ($this->inputIdFromTag !== null) {
242 1
            $label = $label->forId($this->inputIdFromTag);
243
        }
244
245 29
        return $label->render();
246
    }
247
248 29
    private function generateHint(): string
249
    {
250 29
        return Hint::widget($this->hintConfig)
251 29
            ->attribute($this->getFormModel(), $this->attribute)
252 29
            ->render();
253
    }
254
255 29
    private function generateError(): string
256
    {
257 29
        return Error::widget($this->errorConfig)
258 29
            ->attribute($this->getFormModel(), $this->attribute)
259 29
            ->render();
260
    }
261
262 29
    private function isUsePlaceholder(): bool
263
    {
264 29
        $traits = class_uses($this);
265 29
        return in_array(PlaceholderTrait::class, $traits, true);
266
    }
267
}
268