Passed
Pull Request — master (#192)
by Alexander
05:47 queued 02:55
created

PartsField::generateError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 5
ccs 3
cts 3
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 Stringable;
9
use Yiisoft\Form\Field\Part\Error;
10
use Yiisoft\Form\Field\Part\Hint;
11
use Yiisoft\Form\Field\Part\Label;
12
13
use function in_array;
14
15
abstract class PartsField extends BaseField
16
{
17
    private const BUILTIN_TOKENS = [
18
        '{input}',
19
        '{label}',
20
        '{hint}',
21
        '{error}',
22
    ];
23
24
    /**
25
     * @var string[]|Stringable[]
26
     * @psalm-var array<non-empty-string,string|Stringable>
27
     */
28
    private array $extraTokens = [];
29
30
    protected string $templateBegin = "{label}\n{input}";
31
    protected string $templateEnd = "{input}\n{hint}\n{error}";
32
    protected string $template = "{label}\n{input}\n{hint}\n{error}";
33
    protected ?bool $hideLabel = null;
34
35
    private array $labelConfig = [];
36
    private array $hintConfig = [];
37
    private array $errorConfig = [];
38
39 2
    final public function tokens(array $tokens): static
40
    {
41 2
        $new = clone $this;
42
43 2
        foreach ($tokens as $token => $value) {
44 1
            if (!is_string($token)) {
45
                throw new InvalidArgumentException(
46
                    sprintf(
47
                        'Token should be string. %s given.',
48
                        $token,
49
                    )
50
                );
51
            }
52
53 1
            if (!is_string($value) && !$value instanceof Stringable) {
54
                throw new InvalidArgumentException(
55
                    sprintf(
56
                        'Token value should be string or Stringable. %s given.',
57
                        get_debug_type($value),
58
                    )
59
                );
60
            }
61
62 1
            $this->validateToken($token);
63
64 1
            $new->extraTokens[$token] = $value;
65
        }
66
67 2
        return $new;
68
    }
69
70 4
    final public function token(string $token, string|Stringable $value): static
71
    {
72 4
        $this->validateToken($token);
73
74 2
        $new = clone $this;
75 2
        $new->extraTokens[$token] = $value;
76 2
        return $new;
77
    }
78
79
    /**
80
     * Set layout template for render a field.
81
     */
82 4
    final public function template(string $template): static
83
    {
84 4
        $new = clone $this;
85 4
        $new->template = $template;
86 4
        return $new;
87
    }
88
89 14
    final public function hideLabel(?bool $hide = true): static
90
    {
91 14
        $new = clone $this;
92 14
        $new->hideLabel = $hide;
93 14
        return $new;
94
    }
95
96 4
    final public function labelConfig(array $config): static
97
    {
98 4
        $new = clone $this;
99 4
        $new->labelConfig = $config;
100 4
        return $new;
101
    }
102
103 3
    final public function label(?string $content): static
104
    {
105 3
        $new = clone $this;
106 3
        $new->labelConfig['content()'] = [$content];
107 3
        return $new;
108
    }
109
110 3
    final public function hintConfig(array $config): static
111
    {
112 3
        $new = clone $this;
113 3
        $new->hintConfig = $config;
114 3
        return $new;
115
    }
116
117 3
    final public function hint(?string $content): static
118
    {
119 3
        $new = clone $this;
120 3
        $new->hintConfig['content()'] = [$content];
121 3
        return $new;
122
    }
123
124 3
    final public function errorConfig(array $config): static
125
    {
126 3
        $new = clone $this;
127 3
        $new->errorConfig = $config;
128 3
        return $new;
129
    }
130
131 2
    final public function error(?string $message): static
132
    {
133 2
        $new = clone $this;
134 2
        $new->errorConfig['message()'] = [$message];
135 2
        return $new;
136
    }
137
138 80
    protected function shouldHideLabel(): bool
139
    {
140 80
        return false;
141
    }
142
143 1
    protected function generateInput(): string
144
    {
145 1
        return '';
146
    }
147
148
    protected function generateBeginInput(): string
149
    {
150
        return '';
151
    }
152
153
    protected function generateEndInput(): string
154
    {
155
        return '';
156
    }
157
158 19
    protected function renderLabel(Label $label): string
159
    {
160 19
        return $label->render();
161
    }
162
163 19
    protected function renderHint(Hint $hint): string
164
    {
165 19
        return $hint->render();
166
    }
167
168 19
    protected function renderError(Error $error): string
169
    {
170 19
        return $error->render();
171
    }
172
173 112
    final protected function generateContent(): ?string
174
    {
175 111
        $parts = [
176 112
            '{input}' => $this->generateInput(),
177 111
            '{label}' => ($this->hideLabel ?? $this->shouldHideLabel()) ? '' : $this->generateLabel(),
178 111
            '{hint}' => $this->generateHint(),
179 111
            '{error}' => $this->generateError(),
180
        ];
181
182 111
        return $this->makeContent($this->template, $parts);
183
    }
184
185 1
    final protected function generateBeginContent(): string
186
    {
187 1
        $parts = [
188 1
            '{input}' => $this->generateBeginInput(),
189 1
            '{label}' => ($this->hideLabel ?? $this->shouldHideLabel()) ? '' : $this->generateLabel(),
190 1
            '{hint}' => $this->generateHint(),
191 1
            '{error}' => $this->generateError(),
192
        ];
193
194 1
        return $this->makeContent($this->templateBegin, $parts);
195
    }
196
197 1
    final protected function generateEndContent(): string
198
    {
199 1
        $parts = [
200 1
            '{input}' => $this->generateEndInput(),
201 1
            '{label}' => ($this->hideLabel ?? $this->shouldHideLabel()) ? '' : $this->generateLabel(),
202 1
            '{hint}' => $this->generateHint(),
203 1
            '{error}' => $this->generateError(),
204
        ];
205
206 1
        return $this->makeContent($this->templateEnd, $parts);
207
    }
208
209 111
    private function makeContent(string $template, array $parts): string
210
    {
211 111
        if (!empty($this->extraTokens)) {
212 1
            $parts += $this->extraTokens;
213
        }
214
215 111
        return preg_replace('/^\h*\v+/m', '', trim(strtr($template, $parts)));
216
    }
217
218 85
    private function generateLabel(): string
219
    {
220 85
        $label = Label::widget($this->labelConfig);
221
222 85
        return $this->renderLabel($label);
223
    }
224
225 111
    private function generateHint(): string
226
    {
227 111
        $hint = Hint::widget($this->hintConfig);
228
229 111
        return $this->renderHint($hint);
230
    }
231
232 111
    private function generateError(): string
233
    {
234 111
        $error = Error::widget($this->errorConfig);
235
236 111
        return $this->renderError($error);
237
    }
238
239
    /**
240
     * @psalm-assert non-empty-string $token
241
     */
242 4
    private function validateToken(string $token): void
243
    {
244 4
        if (in_array($token, self::BUILTIN_TOKENS, true)) {
245 1
            throw new InvalidArgumentException(
246 1
                sprintf(
247
                    'Token name "%s" is built-in.',
248
                    $token,
249
                )
250
            );
251
        }
252
253 3
        if ($token === '') {
254 1
            throw new InvalidArgumentException('Token must be non-empty string.');
255
        }
256
    }
257
}
258