Passed
Push — master ( 6b3bd5...b249fa )
by Sergei
05:31 queued 02:48
created

BaseField::render()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.0072

Importance

Changes 0
Metric Value
cc 4
eloc 12
c 0
b 0
f 0
nc 4
nop 0
dl 0
loc 23
ccs 12
cts 13
cp 0.9231
crap 4.0072
rs 9.8666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Field\Base;
6
7
use InvalidArgumentException;
8
use Yiisoft\Form\ThemeContainer;
9
use Yiisoft\Html\Html;
10
use Yiisoft\Html\Tag\CustomTag;
11
use Yiisoft\Widget\Widget;
12
13
abstract class BaseField extends Widget
14
{
15
    /**
16
     * @psalm-var non-empty-string
17
     */
18
    protected string $containerTag = 'div';
19
    protected array $containerAttributes = [];
20
    protected bool $useContainer = true;
21
    protected array $enrichment = [];
22
23
    private bool $isStartedByBegin = false;
24
25 5
    final public function containerTag(string $tag): static
26
    {
27 5
        if ($tag === '') {
28 1
            throw new InvalidArgumentException('Tag name cannot be empty.');
29
        }
30
31 4
        $new = clone $this;
32 4
        $new->containerTag = $tag;
33 4
        return $new;
34
    }
35
36 8
    final public function containerAttributes(array $attributes): static
37
    {
38 8
        $new = clone $this;
39 8
        $new->containerAttributes = $attributes;
40 8
        return $new;
41
    }
42
43 1
    final public function addContainerAttributes(array $attributes): static
44
    {
45 1
        $new = clone $this;
46 1
        $new->containerAttributes = array_merge($new->containerAttributes, $attributes);
47 1
        return $new;
48
    }
49
50
    /**
51
     * Set container tag ID.
52
     *
53
     * @param string|null $id Container tag ID.
54
     */
55 3
    final public function containerId(?string $id): static
56
    {
57 3
        $new = clone $this;
58 3
        $new->containerAttributes['id'] = $id;
59 3
        return $new;
60
    }
61
62
    /**
63
     * Replace container tag CSS classes with a new set of classes.
64
     *
65
     * @param string|null ...$class One or many CSS classes.
66
     */
67 10
    final public function containerClass(?string ...$class): static
68
    {
69 10
        $new = clone $this;
70 10
        $new->containerAttributes['class'] = array_filter($class, static fn ($c) => $c !== null);
71 10
        return $new;
72
    }
73
74
    /**
75
     * Add one or more CSS classes to the container tag.
76
     *
77
     * @param string|null ...$class One or many CSS classes.
78
     */
79 9
    final public function addContainerClass(?string ...$class): static
80
    {
81 9
        $new = clone $this;
82 9
        Html::addCssClass($new->containerAttributes, $class);
83 9
        return $new;
84
    }
85
86 142
    final public function useContainer(bool $use): static
87
    {
88 142
        $new = clone $this;
89 142
        $new->useContainer = $use;
90 142
        return $new;
91
    }
92
93 5
    final public function begin(): ?string
94
    {
95 5
        parent::begin();
96 5
        $this->isStartedByBegin = true;
97
98 5
        $this->beforeRender();
99
100 5
        $content = $this->generateBeginContent();
101
102 5
        return $this->renderOpenContainerAndContent($content);
103
    }
104
105 463
    final public function render(): string
106
    {
107 463
        if ($this->isStartedByBegin) {
108 5
            $this->isStartedByBegin = false;
109 5
            return $this->renderEnd();
110
        }
111
112 459
        $this->beforeRender();
113
114 459
        $content = $this->generateContent();
115 444
        if ($content === null) {
116
            return '';
117
        }
118
119 444
        $result = $this->renderOpenContainerAndContent($content);
120
121 444
        if ($this->useContainer) {
122 303
            $result .= "\n" . Html::closeTag($this->containerTag);
123
        }
124
125 444
        $this->enrichment = [];
126
127 444
        return $result;
128
    }
129
130 463
    protected function beforeRender(): void
131
    {
132 463
    }
133
134
    abstract protected function generateContent(): ?string;
135
136 2
    protected function generateBeginContent(): string
137
    {
138 2
        return '';
139
    }
140
141 2
    protected function generateEndContent(): string
142
    {
143 2
        return '';
144
    }
145
146 133
    protected function prepareContainerAttributes(array &$attributes): void
147
    {
148 133
    }
149
150 490
    final protected static function getThemeConfig(?string $theme): array
151
    {
152 490
        return ThemeContainer::getTheme($theme)?->getFieldConfig(static::class) ?? [];
153
    }
154
155 5
    private function renderEnd(): string
156
    {
157 5
        $content = $this->generateEndContent();
158
159 5
        if (!$this->useContainer) {
160 1
            return $content;
161
        }
162
163 4
        $containerTag = CustomTag::name($this->containerTag);
164
165 4
        return ($content !== '' ? $content . "\n" : '') . $containerTag->close();
166
    }
167
168 448
    private function renderOpenContainerAndContent(string $content): string
169
    {
170 448
        if (!$this->useContainer) {
171 143
            return $content;
172
        }
173
174 307
        $containerTag = CustomTag::name($this->containerTag);
175
176 307
        $attributes = $this->containerAttributes;
177 307
        $this->prepareContainerAttributes($attributes);
178 307
        if ($attributes !== []) {
179 27
            $containerTag = $containerTag->addAttributes($attributes);
180
        }
181
182 307
        return $containerTag->open()
183 307
            . ($content === '' ? '' : ("\n" . $content));
184
    }
185
}
186