Test Setup Failed
Pull Request — latest (#3)
by Mark
34:22
created

HtmlElement::setAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 5
c 1
b 0
f 1
dl 0
loc 9
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file was originally part of the league/commonmark package.
7
 *
8
 * (c) Colin O'Dell <[email protected]>
9
 *
10
 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
11
 *  - (c) John MacFarlane
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
17
namespace UnicornFail\Emoji\Util;
18
19
class HtmlElement implements \Stringable
20
{
21
    /** @var string */
22
    protected $tagName;
23
24
    /** @var array<string, string|bool> */
25
    protected $attributes = [];
26
27
    /** @var HtmlElement|HtmlElement[]|string */
28
    protected $contents;
29
30
    /** @var bool */
31
    protected $selfClosing = false;
32
33
    /**
34
     * @param string                                $tagName     Name of the HTML tag
35
     * @param array<string, mixed>                  $attributes  Array of attributes (values should be unescaped)
36
     * @param HtmlElement|HtmlElement[]|string|null $contents    Inner contents, pre-escaped if needed
37
     * @param bool                                  $selfClosing Whether the tag is self-closing
38
     */
39
    public function __construct(string $tagName, array $attributes = [], $contents = '', bool $selfClosing = false)
40
    {
41
        $this->tagName     = $tagName;
42
        $this->selfClosing = $selfClosing;
43
44
        foreach ($attributes as $name => $value) {
45
            $this->setAttribute($name, $value);
46
        }
47
48
        $this->setContents($contents ?? '');
49
    }
50
51
    public function addClass(string ...$classes): void
52
    {
53
        $existingClasses = \explode(' ', (string) ($this->getAttribute('class') ?? ''));
54
        $this->setAttribute('class', \trim(\implode(' ', \array_unique(\array_merge($existingClasses, $classes)))));
55
    }
56
57
    public function getTagName(): string
58
    {
59
        return $this->tagName;
60
    }
61
62
    /**
63
     * @return array<string, string|bool>
64
     */
65
    public function getAllAttributes(): array
66
    {
67
        return $this->attributes;
68
    }
69
70
    /**
71
     * @return string|bool|null
72
     */
73
    public function getAttribute(string $key)
74
    {
75
        if (! isset($this->attributes[$key])) {
76
            return null;
77
        }
78
79
        return $this->attributes[$key];
80
    }
81
82
    /**
83
     * @param string|string[]|bool $value
84
     */
85
    public function setAttribute(string $key, $value): self
86
    {
87
        if (\is_array($value)) {
88
            $this->attributes[$key] = \implode(' ', \array_unique($value));
89
        } else {
90
            $this->attributes[$key] = $value;
91
        }
92
93
        return $this;
94
    }
95
96
    /**
97
     * @return HtmlElement|HtmlElement[]|string
98
     */
99
    public function getContents(bool $asString = true)
100
    {
101
        if (! $asString) {
102
            return $this->contents;
103
        }
104
105
        return $this->getContentsAsString();
106
    }
107
108
    /**
109
     * Sets the inner contents of the tag (must be pre-escaped if needed)
110
     *
111
     * @param HtmlElement|HtmlElement[]|string $contents
112
     *
113
     * @return $this
114
     */
115
    public function setContents($contents): self
116
    {
117
        $this->contents = $contents ?? '';
118
119
        return $this;
120
    }
121
122
    public function __toString(): string
123
    {
124
        $result = '<' . $this->tagName;
125
126
        foreach ($this->attributes as $key => $value) {
127
            if ($value === true) {
128
                $result .= ' ' . $key;
129
            } elseif ($value === false) {
130
                continue;
131
            } else {
132
                $result .= ' ' . $key . '="' . Xml::escape($value) . '"';
133
            }
134
        }
135
136
        if ($this->contents !== '') {
137
            $result .= '>' . $this->getContentsAsString() . '</' . $this->tagName . '>';
138
        } elseif ($this->selfClosing && $this->tagName === 'input') {
139
            $result .= '>';
140
        } elseif ($this->selfClosing) {
141
            $result .= ' />';
142
        } else {
143
            $result .= '></' . $this->tagName . '>';
144
        }
145
146
        return $result;
147
    }
148
149
    private function getContentsAsString(): string
150
    {
151
        if (\is_string($this->contents)) {
152
            return $this->contents;
153
        }
154
155
        if (\is_array($this->contents)) {
156
            return \implode('', $this->contents);
157
        }
158
159
        return (string) $this->contents;
160
    }
161
}
162