SvgRuntime   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Test Coverage

Coverage 97.87%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 12
eloc 47
c 2
b 0
f 0
dl 0
loc 98
ccs 46
cts 47
cp 0.9787
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A embedSvg() 0 15 3
B convertToSymbols() 0 69 8
1
<?php
2
3
/*
4
 * This file is part of ocubom/twig-svg-extension
5
 *
6
 * © Oscar Cubo Medina <https://ocubom.github.io>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ocubom\Twig\Extension;
13
14
use Ocubom\Twig\Extension\Svg\Exception\LoaderException;
15
use Ocubom\Twig\Extension\Svg\Loader\LoaderInterface;
16
use Ocubom\Twig\Extension\Svg\Symbol;
17
use Ocubom\Twig\Extension\Svg\Util\DomUtil;
18
use Ocubom\Twig\Extension\Svg\Util\Html5Util;
19
use Psr\Log\LoggerInterface;
20
use Psr\Log\NullLogger;
21
use Twig\Environment;
22
use Twig\Extension\RuntimeExtensionInterface;
23
24
class SvgRuntime implements RuntimeExtensionInterface
25
{
26
    private LoaderInterface $loader;
27
28
    private LoggerInterface $logger;
29
30 11
    public function __construct(LoaderInterface $loader, LoggerInterface $logger = null)
31
    {
32 11
        $this->loader = $loader;
33 11
        $this->logger = $logger ?? new NullLogger();
34
    }
35
36 6
    public function convertToSymbols(Environment $twig, string $html): string
37
    {
38
        // Load HTML
39 6
        $doc = Html5Util::loadHtml($html);
40
41
        /** @var \DOMElement[] $elements */
42 5
        $elements = [];
43
44
        /** @var \DOMElement[] $symbols */
45 5
        $symbols = [];
46
47
        /** @var \DOMElement $svg */
48 5
        foreach ($doc->getElementsByTagName('svg') as $svg) {
49 4
            $symbol = new Symbol($svg, [
50 4
                'debug' => $twig->isDebug(),
51 4
            ]);
52
53
            // Replace the SVG with reference
54 4
            DomUtil::replaceNode($svg, $symbol->getReference());
55
56
            // Index symbol by id
57 4
            $symbols[$symbol->getId()] = $symbols[$symbol->getId()] ?? $symbol->getElement();
58 4
            $elements[] = $svg;
59
        }
60
61
        // Dump all symbols
62 5
        if (count($symbols) > 0) {
63
            // Create symbols container element before the end of body tag or DOM
64 4
            $node = DomUtil::createElement('svg', '', $doc
65 4
                ->getElementsByTagName('body')
66 4
                ->item(0) ?? $doc
67 4
            );
68 4
            $node->setAttribute('style', 'display:none');
69
70
            // Add format (duplicate previous node space) on debug mode
71 4
            if ($twig->isDebug()) {
72
                assert($node->previousSibling instanceof \DOMNode);
73 3
                DomUtil::appendChildNode($node->previousSibling, $node);
74
            }
75
76 4
            uksort($symbols, 'strnatcasecmp');
77 4
            foreach ($symbols as $symbol) {
78 4
                DomUtil::appendChildNode($symbol, $node);
79
80 4
                if ($twig->isDebug()) {
81
                    assert($node->previousSibling instanceof \DOMNode);
82 3
                    DomUtil::appendChildNode($node->previousSibling, $node);
83
                }
84
            }
85
86 4
            if ($twig->isDebug()) {
87
                assert($node->parentNode instanceof \DOMNode);
88
89 3
                DomUtil::appendChildNode(
90 3
                    $doc->createTextNode("\n"),
91 3
                    $node->parentNode
92 3
                );
93
94 3
                $this->logger->info('Converted {element_count} SVG elements into {symbol_count} SVG symbols', [
95 3
                    'element_count' => count($elements),
96 3
                    'symbol_count' => count($symbols),
97 3
                ]);
98
            }
99 1
        } elseif ($twig->isDebug()) {
100 1
            $this->logger->debug('No SVG found');
101
        }
102
103
        // Generate normalized HTML
104 5
        return Html5Util::toHtml($doc);
105
    }
106
107 5
    public function embedSvg(Environment $twig, string $ident, array $options = []): string
108
    {
109
        try {
110 5
            $svg = $this->loader->resolve($ident, $options);
111
112 3
            return $svg->toXml(!$twig->isDebug());
113 2
        } catch (LoaderException $err) {
114 1
            $this->logger->error($err->getMessage(), ['exception' => $err]);
115
116 1
            if ($twig->isDebug()) {
117 1
                return sprintf('<!--{{ svg("%s") }}-->', $ident);
118
            }
119
        }
120
121
        return '';
122
    }
123
}
124