Passed
Push — master ( 46e4e2...118217 )
by Rustam
02:47
created

BaseField::render()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

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