Repository navigation
Expand file tree
/
Copy pathAbstractSvg.php
More file actions
199 lines (168 loc) · 4.82 KB
/
Copy pathAbstractSvg.php
File metadata and controls
199 lines (168 loc) · 4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<?php
declare(strict_types=1);
namespace PHPForge\Html\Base;
use DOMDocument;
use DOMElement;
use enshrined\svgSanitize\Sanitizer;
use InvalidArgumentException;
use PHPForge\Html\{
Attribute\Custom\HasAttributes,
Attribute\Custom\HasContent,
Attribute\HasClass,
Attribute\HasId,
Attribute\HasLang,
Attribute\HasTitle,
Attribute\Input\HasHeight,
Attribute\Input\HasName,
Attribute\Input\HasWidth,
Tag
};
use PHPForge\Widget\Element;
use RuntimeException;
use function file_get_contents;
/**
* Provides a foundation for creating HTML `svg` elements with various attributes and content.
*/
abstract class AbstractSvg extends Element
{
use HasAttributes;
use HasClass;
use HasContent;
use HasHeight;
use HasId;
use HasLang;
use HasName;
use HasTitle;
use HasWidth;
protected array $attributes = [];
private string $filePath = '';
/**
* Returns a new instance with the file path of the SVG.
*
* @param string $value The file path.
*/
public function filePath(string $value): static
{
$new = clone $this;
$new->filePath = $value;
return $new;
}
/**
* Returns a new instance with the fill attribute of the SVG.
*
* @param string $value The fill value.
*/
public function fill(string $value): static
{
$new = clone $this;
$new->attributes['fill'] = $value;
return $new;
}
/**
* Returns a new instance with the stroke attribute of the SVG.
*
* @param string $value The stroke value.
*/
public function stroke(string $value): static
{
$new = clone $this;
$new->attributes['stroke'] = $value;
return $new;
}
/**
* Returns a new instance with the viewBox attribute of the SVG.
*
* @param string $value The viewBox value.
*/
public function viewBox(string $value): static
{
$new = clone $this;
$new->attributes['viewBox'] = $value;
return $new;
}
/**
* Returns a new instance with the xmlns attribute of the SVG.
*
* @param string $value The xmlns value.
*/
public function xmlns(string $value): static
{
$new = clone $this;
$new->attributes['xmlns'] = $value;
return $new;
}
/**
* Validates the file path and content before running the widget.
*
* @throws InvalidArgumentException If both a file path and content are empty.
*
* @return bool Whether the widget should be executed.
*/
protected function beforeRun(): bool
{
if ($this->filePath === '' && $this->content === '') {
throw new InvalidArgumentException('File path and content cannot be empty at the same time for SVG widget.');
}
return parent::beforeRun();
}
/**
* Renders the SVG widget.
*
* @return string The rendered SVG.
*/
protected function run(): string
{
return match ($this->content) {
'' => $this->renderSvg(),
default => Tag::widget()
->attributes($this->attributes)
->content(PHP_EOL, $this->content, PHP_EOL)
->id($this->id)
->tagName('svg')
->render(),
};
}
/**
* Loads the SVG file and returns the SVG element.
*
* @param DOMDocument $svg The DOMDocument instance.
*
* @throws RuntimeException If failed to load the SVG file.
*
* @return DOMElement The SVG element.
*/
private function loadSvgFile(DOMDocument $svg): DOMElement
{
$sanitizer = new Sanitizer();
$fileSvg = @file_get_contents($this->filePath);
if ($fileSvg === false) {
throw new RuntimeException('Failed to read SVG file: ' . $this->filePath);
}
$cleanedSvg = $sanitizer->sanitize($fileSvg);
if ($cleanedSvg === false || $cleanedSvg === '') {
throw new RuntimeException('Failed to sanitize SVG file: ' . $this->filePath);
}
$svg->loadXML($cleanedSvg, LIBXML_NOBLANKS);
return $svg->getElementsByTagName('svg')->item(0);
}
/**
* Renders the SVG element with attributes.
*
* @return string The rendered SVG.
*/
private function renderSvg(): string
{
/** @psalm-var array<string, mixed> $attributes */
$attributes = $this->attributes;
$attributes['id'] = $this->id;
$svg = new DOMDocument();
$renderedSvg = $this->loadSvgFile($svg);
/** @psalm-var mixed $value */
foreach ($attributes as $name => $value) {
if ($name !== '' && $value !== '' && $value !== null) {
$renderedSvg->setAttribute($name, (string) $value);
}
}
return $svg->saveXML($renderedSvg);
}
}