Über einen einfachen ViewHelper könnt ihr SVG künftig besser rendern. Das erspart dem Server vielleicht eine Vielzahl von unnötigen Requests, wenn ihr viele dieser Icons benutzt.
Before:
<img src="/typo3conf/ext/in2template/Resources/Public/Logo.svg" width="200" height="100" title="Logo" id="logo"/>
After:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 487.56 340.16" id="logo" width="200" height="100" title="Logo">
<g class="cls-1">
...
</g>
</svg>
Die Einbindung in Fluid könnte dann z.B. so aussehen:
<in2template:resource.svgInline src="EXT:in2template/Resources/Public/Logo-small.svg" width="200"/>
or with all attributes:
<in2template:resource.svgInline src="EXT:in2template/Resources/Public/Logo-small.svg" width="200" height="100" id="logo" title="Logo" class="className" viewBox="0 0 100 100" data="{foo:'bar'}" additionalAttributes="{onclick:'anything()'}"/>
Der ViewHelper hierzu könnte so in eurem Sitepackage liegen (bei uns EXT:in2template/Classes/ViewHelpers/Resource/SvgInlineViewHelper.php):
<?php
declare(strict_types=1);
namespace In2code\In2template\ViewHelpers\Resource;
use Closure;
use DOMDocument;
use DOMElement;
use In2code\In2template\Exception\FileException;
use SimpleXMLElement;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class SvgInlineViewHelper extends AbstractViewHelper
{
/**
* @var bool
*/
protected $escapeOutput = false;
/**
* Initializing arguments
*
* @return void
*/
public function initializeArguments(): void
{
parent::initializeArguments();
$this->registerArgument('src', 'string', 'e.g. EXT:in2template/Resources/Public/Images/any.svg', true);
$this->registerArgument('id', 'string', 'Id to set in the svg');
$this->registerArgument('class', 'string', 'Css class(es) for the svg');
$this->registerArgument('width', 'string', 'Width of the svg.');
$this->registerArgument('height', 'string', 'Height of the svg.');
$this->registerArgument('viewBox', 'string', 'Specifies the view box for the svg');
$this->registerArgument('data', 'array', 'Array of data-attributes');
$this->registerArgument('additionalAttributes', 'array', 'any attributes', false, []);
}
/**
* @param array $arguments
* @param Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return string
* @SuppressWarnings(PHPMD)
* @throws FileException
*/
public static function renderStatic(
array $arguments,
Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$imageService = GeneralUtility::makeInstance(ImageService::class);
if ((string)$arguments['src'] === '') {
throw new FileException('You must specify a string src.', 1666087832);
}
$image = $imageService->getImage($arguments['src'], null, false);
if ($image->getExtension() !== 'svg') {
throw new FileException('You must provide a svg file.', 1666087835);
}
$svgContent = $image->getContents();
if ($svgContent === '') {
throw new FileException('The svg file must not be empty.', 1666087837);
}
$attributes = [
'id' => $arguments['id'],
'class' => $arguments['class'],
'width' => $arguments['width'],
'height' => $arguments['height'],
'viewBox' => $arguments['viewBox'],
'data' => $arguments['data'],
] + $arguments['additionalAttributes'];
return self::getInlineSvg($svgContent, $attributes);
}
/**
* @param string $svgContent
* @param array $attributes
* @return string
*/
protected static function getInlineSvg(
string $svgContent,
array $attributes = []
): string {
$svgElement = simplexml_load_string($svgContent);
if (!$svgElement instanceof SimpleXMLElement) {
return '';
}
$domXml = dom_import_simplexml($svgElement);
if (!$domXml instanceof DOMElement || !$domXml->ownerDocument instanceof DOMDocument) {
return '';
}
foreach (self::updateAttributes($attributes) as $attributeKey => $attributeValue) {
if ($attributeValue !== null) {
$domXml->setAttribute($attributeKey, htmlspecialchars((string)$attributeValue));
}
}
return (string)$domXml->ownerDocument->saveXML($domXml->ownerDocument->documentElement);
}
/**
* @param array $attributes
* @return array
*/
protected static function updateAttributes(array $attributes): array
{
if ($attributes['id'] !== null) {
$attributes['id'] = htmlspecialchars(trim((string)$attributes['id']));
}
if (is_array($attributes['data'])) {
foreach ($attributes['data'] as $attributeDataKey => $attributeDataValue) {
$attributes['data-' . (string)$attributeDataKey] = htmlspecialchars((string)$attributeDataValue);
}
unset($attributes['data']);
}
return $attributes;
}
}
Wie immer setzt dieses Beispiel voraus, dass ihr ein Sitepackage benutzt. Die leere Datei FileException habe ich nicht mit angefügt. Natürlich fehlt auch noch die Namespace-Deklaration in Fluid, die es für alle ViewHelper braucht.
Inspiriert durch https://review.typo3.org/c/Packages/TYPO3.CMS/+/70798/10/typo3/sysext/fluid/Classes/ViewHelpers/SvgInlineViewHelper.php von Marcus Schwemer.