SVG Dateien als eigene Twig-Funktion nutzen

In webbasierten Projekten ist es für die Benutzerführung essentiell, Icons und kleine Grafiken zu verwenden. Sie machen Funktionen für den Nutzer besser kenntlich, mit den Augen leichter zu verfolgen und werten die Seite zudem optisch auf. Projekt, die mit der Hilfe von Bootstrap entworfen werden, können dabei leicht auf die Glyphicons zurückgreifen (Bootstrap 3.*). Für ein aktuelles Projekt wünscht der Kunde die Nutzung einer Sammlung SVG Dateien, die wir mit einer eigenen Twig-Funktion in Symfony nutzen.

Eine eigene Bibliothek erstellen

Zuerst haben wir die einzelnen SVG-Dateien gesammelt und in einer einzelnen Datei gebündelt. Das praktische an SVG ist, dass die Angaben für Punkte und Pfade sehr gut in XML Strukturen geschrieben werden können. Jedes Icon ist so mit einer ID versehen und in einem verschachtelten <symbol> Tag abgelegt. All unsere Symbole sind in einem <svg> Tag zusammengefasst.

<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <symbol id="icon-play" viewBox="0 0 25 32">
            <path class="path1" d="M24.714 16.554l-23.714 13.179q-0.411 0.232-0.705 0.054t-0.295-0.643v-26.286q0-0.464 0.295-0.643t0.705 0.054l23.714 13.179q0.411 0.232 0.411 0.554t-0.411 0.554z" />
        </symbol>
        // ...
    </defs>
</svg>

Für die Anzeige nutzt man eine <svg><use/></svg> Kombination in HTML. Hierbei wird der Pfad zur SVG-Sammlung angegeben und das betreffende Icon als ID angegeben.

<svg>
    <use xlink:href="/link/to/my/font-awesome.svg#icon-play"></use>
</svg>

Eigentlich sind wir auch schon fertig. Das ist zwar ganz nett, aber keine wirkliche Arbeitserleichterung. Eine Menge Text für so ein kleines Icon und je öfter man sie benutzt, desto unübersichtlicher wird der Quelltext, dabei ist die Syntax doch immer gleich.

Ausgabe mit Twig vereinfachen

Da wir Twig für das Projekt verwenden, haben wir uns das Leben natürlich einfacher gemacht. Hier können wir eigene Funktionen deklarieren, die immer wiederkehrende Abläufe vereinfachen und dabei jede menge Potential für eigene Anpassungen bieten. Das sieht dann so aus:

use Symfony\Component\Asset\Packages;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class SvgFilter extends Twig_Extension
{
    private $packages;

    public function __construct(Packages $packages)
    {
        $this->packages = $packages;
    }

    public function getFunctions(): array
    {
        return [
            new Twig_SimpleFunction('svg', [$this, 'svgFilter'], [
                'is_safe' => ['html'],
            ]),
        ];
    }

    /**
     * @param string      $imageName
     * @param string|null $class
     *
     * @return string
     */
    public function svgFilter($imageName, $class = null)
    {
        if (empty($imageName)) {
            return '';
        }

        if (null === $class) {
            $wrapped = '<svg>';
        } else {
            $wrapped = '<svg class="' . $class . '">';
        }

        $svgLink = $this->packages->getUrl('path/to/my/font-awesome.svg', null);
        $wrapped .= '<use xlink:href="' . $svgLink . '#icon-' . $imageName . '"></use></svg>';

        return $wrapped;
    }
}

Die Packages sind in unserer Klasse, damit wir – ähnlich wie die asset() Funktion in Twig – auf eine Datei im /web Ordner zugreifen können. Als nächstes muss die Funktion noch als Service in der services.yml registrieren werden. Ab Symfony 4 und Symfony-Flex, ist dies nicht mehr notwendig.

services:
    # ...

    my_twig_extension:
        class: Namespace\to\my\SvgFilter
        public: false
        arguments: ["@assets.packages"]
        tags:
            - { name: twig.extension }

Um nun ein Icon im Template auszugeben genügt:

{{ svg('check', 'medium green') }}

Fazit

Mit unserer Methode lässt sich eine schöne Bibliothek aufbauen, um auf die Icons zuzugreifen. Die Twig-Kompatibilität macht uns den Umgang in Symfony und Twig-Templates einfach. Es gibt aber noch andere Bibliotheken für Icons, die auf Schriftarten und CSS basieren und damit noch viel schlanker sind. Die Font Awesome Icons sind ein gutes Beispiel.

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert