THtmlElement   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 38
eloc 53
c 4
b 0
f 0
dl 0
loc 208
ccs 67
cts 67
cp 1
rs 9.36

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __call() 0 8 3
A __get() 0 3 2
A __isset() 0 3 1
A setChildren() 0 10 5
A lastChild() 0 4 2
A removeChild() 0 4 2
A getChildren() 0 3 1
A renderChildren() 0 3 1
A __empty() 0 3 1
A renderChild() 0 3 1
B addChild() 0 21 10
A __set() 0 3 1
A merge() 0 4 1
A checkAlias() 0 3 4
A getAlias() 0 3 1
A render() 0 3 1
A inherit() 0 6 1
1
<?php
2
3
namespace kalanis\kw_templates\HtmlElement;
4
5
6
use kalanis\kw_templates\Interfaces\IHtmlElement;
7
use Traversable;
8
9
10
/**
11
 * Abstraction of HTML element - trait which can be used
12
 * Each HTML element must have a few following things
13
 * 1. must be able to render self
14
 * 2. must can tell what children have
15
 *    it's possible to have 0 - n children
16
 * 3. must know its parent
17
 *    can have 0 or 1 parent
18
 * 4. must know its attributes
19
 *    can have 0 - n attributes
20
 * @author Adam Dornak original
21
 * @author Petr Plsek refactored
22
 */
23
trait THtmlElement
24
{
25
    use TAttributes;
26
    use TParent;
27
28
    protected string $template = '';
29
    /** @var IHtmlElement[] */
30
    protected array $children = [];
31
    protected string $childDelimiter = PHP_EOL;
32
    protected ?string $alias = null;
33
34
    /**
35
     * Returns object alias
36
     * @return string|null
37
     */
38 5
    public function getAlias(): ?string
39
    {
40 5
        return $this->alias;
41
    }
42
43
    /**
44
     * Render element
45
     * @return string
46
     */
47 1
    public function render(): string
48
    {
49 1
        return sprintf($this->template, $this->renderAttributes(), $this->renderChildren());
50
    }
51
52
    /**
53
     * render children into serialized strings
54
     * @return string
55
     */
56 1
    public function renderChildren(): string
57
    {
58 1
        return implode($this->childDelimiter, array_map([$this, 'renderChild'], $this->children));
59
    }
60
61 1
    protected function renderChild(IHtmlElement $child): string
62
    {
63 1
        return $child->render();
64
    }
65
66
    /**
67
     * Add child on stack end or replace the current one (if they have same alias)
68
     * @param IHtmlElement|string $child
69
     * @param int|string|null $alias - key for lookup; beware of empty strings
70
     * @param bool $merge merge with original element if already exists
71
     * @param bool $inherit inherit properties from current element
72
     */
73 3
    public function addChild($child, $alias = null, bool $merge = false, bool $inherit = false): void
74
    {
75 3
        if ($child instanceof IHtmlElement) {
76 3
            if (!$this->checkAlias($alias)) {
77 3
                $alias = $child->getAlias();
78
            }
79
        } else {
80 1
            $alias = $this->checkAlias($alias) ? strval($alias) : null ;
81 1
            $child = new Text(strval($child), $alias);
82
        }
83 3
        if (method_exists($child, 'setParent') && $this instanceof IHtmlElement) {
84 3
            $child->setParent($this);
85
        }
86
87 3
        if ($this->checkAlias($alias)) {
88 2
            if ($merge && $this->__isset(strval($alias))) {
89 1
                $this->children[strval($alias)]->merge($child);
90
            }
91 2
            $this->children[strval($alias)] = $inherit ? $this->inherit($child) : $child ;
92
        } else {
93 2
            $this->children[] = $child;
94
        }
95
96 3
    }
97
98
    /**
99
     * @param mixed $alias
100
     * @return bool
101
     */
102 3
    protected function checkAlias($alias): bool
103
    {
104 3
        return !(is_null($alias) || ('' === $alias) || (is_object($alias)) || is_resource($alias) );
105
    }
106
107
    /**
108
     * Merge this element with child and its attributes
109
     * @param IHtmlElement $child
110
     */
111 2
    public function merge(IHtmlElement $child): void
112
    {
113 2
        $this->setChildren($child->getChildren());
114 2
        $this->setAttributes($child->getAttributes());
115 2
    }
116
117
    /**
118
     * Inheritance - set properties of this object into the child
119
     * @param IHtmlElement $child
120
     * @return IHtmlElement
121
     */
122 1
    public function inherit(IHtmlElement $child): IHtmlElement
123
    {
124 1
        $element = clone $child;
125 1
        $element->addAttributes($this->getAttributes());
126 1
        $element->setChildren($this->getChildren());
127 1
        return $element;
128
    }
129
130
    /**
131
     * Remove child by key
132
     * @param string|int $childAlias
133
     */
134 1
    public function removeChild($childAlias): void
135
    {
136 1
        if (isset($this->children[$childAlias])) {
137 1
            unset($this->children[$childAlias]);
138
        }
139 1
    }
140
141
    /**
142
     * Return last child
143
     * @return IHtmlElement|null
144
     */
145 1
    public function lastChild(): ?IHtmlElement
146
    {
147 1
        $last = end($this->children);
148 1
        return (false === $last) ? null : $last ;
149
    }
150
151
    /**
152
     * Set children of element
153
     * @param iterable|string[]|IHtmlElement[] $children
154
     */
155 4
    public function setChildren(iterable $children = []): void
156
    {
157 4
        foreach ($children as $alias => $child) {
158 1
            $xChild = $child instanceof IHtmlElement
159 1
                ? $child->getAlias()
160 1
                : strval($child)
161
            ;
162 1
            $this->addChild(
163 1
                $child,
164 1
                is_numeric($alias) && $this->checkAlias($xChild) ? $xChild : $alias
165
            );
166
        }
167 4
    }
168
169
    /**
170
     * Return all children as iterator
171
     * @return Traversable<IHtmlElement>
172
     */
173 4
    public function getChildren(): Traversable
174
    {
175 4
        yield from $this->children;
176 4
    }
177
178
    /**
179
     * Automatic access to child via Element->childAlias()
180
     * @param string|int $alias
181
     * @return IHtmlElement|null
182
     */
183 1
    public function __get($alias): ?IHtmlElement
184
    {
185 1
        return $this->__isset($alias) ? $this->children[$alias] : null ;
186
    }
187
188
    /**
189
     * Set child directly by setting a property of this class
190
     * @param string|int $alias
191
     * @param IHtmlElement|string $value
192
     */
193 1
    public function __set($alias, $value): void
194
    {
195 1
        $this->addChild($value, $alias);
196 1
    }
197
198
    /**
199
     * Call isset() for protected or private variables
200
     * @param string|int $alias
201
     * @return bool
202
     */
203 2
    public function __isset($alias): bool
204
    {
205 2
        return isset($this->children[$alias]);
206
    }
207
208
    /**
209
     * Call empty() for protected or private variables
210
     * @param string|int $alias
211
     * @return bool
212
     */
213 1
    public function __empty($alias): bool
214
    {
215 1
        return empty($this->children[$alias]);
216
    }
217
218
    /**
219
     * @param string $method
220
     * @param array<string, string> $args
221
     * @return mixed
222
     */
223 1
    public function __call($method, $args)
224
    {
225 1
        if (0 == count($args)) {
226 1
            return $this->getAttribute(strval($method));
227 1
        } elseif (1 == count($args)) {
228 1
            $this->setAttribute(strval($method), strval(reset($args)));
229
        }
230 1
        return $this;
231
    }
232
}
233