1<?php
2
3
4namespace ComboStrap;
5
6/**
7 * Class ImageSvg
8 * @package ComboStrap
9 * A svg image
10 *
11 * TODO: implements {@link CachedDocument} ? to not cache the optimization in {@link ImageSvg::getSvgFile()}
12 */
13class ImageSvg extends Image
14{
15
16    const EXTENSION = "svg";
17    const CANONICAL = "svg";
18
19
20    public function __construct($path, $tagAttributes = null)
21    {
22
23        parent::__construct($path, $tagAttributes);
24
25    }
26
27
28    /**
29     * @var SvgDocument
30     */
31    private $svgDocument;
32
33    /**
34     *
35     * @throws ExceptionCombo
36     */
37    public function getIntrinsicWidth(): int
38    {
39        return $this->getSvgDocument()->getMediaWidth();
40    }
41
42    /**
43     * @throws ExceptionCombo
44     */
45    public function getIntrinsicHeight(): int
46    {
47        return $this->getSvgDocument()->getMediaHeight();
48    }
49
50
51    /**
52     * @throws ExceptionCombo
53     */
54    protected function getSvgDocument(): SvgDocument
55    {
56        /**
57         * We build the svg document later because the file may not exist
58         * (Case with icon for instance where they are downloaded if they don't exist)
59         *
60         */
61        if ($this->svgDocument === null) {
62            /**
63             * The svg document throw an error if the file does not exist or is not valid
64             */
65            $this->svgDocument = SvgDocument::createSvgDocumentFromPath($this->getPath());
66        }
67        return $this->svgDocument;
68    }
69
70    /**
71     *
72     * @return string|null
73     *
74     * At contrary to {@link RasterImageLink::getUrl()} this function does not need any width parameter
75     */
76    public function getUrl(): ?string
77    {
78
79
80        if (!$this->exists()) {
81            LogUtility::msg("The svg media does not exist ({$this})", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
82            return "";
83        }
84
85        /**
86         * We remove align and linking because,
87         * they should apply only to the img tag
88         */
89
90
91        /**
92         *
93         * Create the array $att that will cary the query
94         * parameter for the URL
95         */
96        $att = array();
97        $attributes = $this->getAttributes();
98        $componentAttributes = $attributes->getComponentAttributes();
99        foreach ($componentAttributes as $name => $value) {
100
101            if (!in_array(strtolower($name), MediaLink::NON_URL_ATTRIBUTES)) {
102                $newName = $name;
103
104                /**
105                 * Width and Height
106                 * permits to create SVG of the asked size
107                 *
108                 * This is a little bit redundant with the
109                 * {@link Dimension::processWidthAndHeight()}
110                 * `max-width and width` styling property
111                 * but you may use them outside of HTML.
112                 */
113                switch ($name) {
114                    case Dimension::WIDTH_KEY:
115                        $newName = "w";
116                        /**
117                         * We don't remove width because,
118                         * the sizing should apply to img
119                         */
120                        break;
121                    case Dimension::HEIGHT_KEY:
122                        $newName = "h";
123                        /**
124                         * We don't remove height because,
125                         * the sizing should apply to img
126                         */
127                        break;
128                }
129
130                if ($newName == CacheMedia::CACHE_KEY && $value == CacheMedia::CACHE_DEFAULT_VALUE) {
131                    // This is the default
132                    // No need to add it
133                    continue;
134                }
135
136                if (!empty($value)) {
137                    $att[$newName] = trim($value);
138                }
139            }
140
141        }
142
143        /**
144         * Cache bursting
145         */
146        $this->addCacheBusterToQueryParameters($att);
147
148        $direct = true;
149
150        if ($this->getPath() === null) {
151            LogUtility::msg("The Url of a image not in the media library is not yet supported", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
152            return "";
153        }
154
155        /**
156         * Old model where all parameters are parsed
157         * and src is not given entirely to the renderer
158         * path may be still present
159         */
160        if (isset($att[PagePath::PROPERTY_NAME])) {
161            unset($att[PagePath::PROPERTY_NAME]);
162        }
163
164        return ml($this->getPath()->getDokuwikiId(), $att, $direct, DokuwikiUrl::AMPERSAND_CHARACTER, true);
165
166
167    }
168
169    public function getAbsoluteUrl(): ?string
170    {
171
172        return $this->getUrl();
173
174    }
175
176    /**
177     * Return the svg file transformed by the attributes
178     * from cache if possible. Used when making a fetch with the URL
179     * @return LocalPath
180     * @throws ExceptionCombo
181     */
182    public function getSvgFile(): LocalPath
183    {
184
185        $cache = new CacheMedia($this->getPath(), $this->getAttributes());
186        global $ACT;
187        if (PluginUtility::isDev() && $ACT === "preview") {
188            // in dev mode, don't cache
189            $isCacheUsable = false;
190        } else {
191            $isCacheUsable = $cache->isCacheUsable();
192        }
193        if (!$isCacheUsable) {
194            $svgDocument = $this->getSvgDocument();
195            $content = $svgDocument->getXmlText($this->getAttributes());
196            $cache->storeCache($content);
197        }
198        return $cache->getFile();
199
200    }
201
202    /**
203     * The buster is not based on file but the cache file
204     * because the cache is configuration dependent
205     * It the user changes the configuration, the svg file is generated
206     * again and the browser cache should be deleted (ie the buster regenerated)
207     * {@link ResourceCombo::getBuster()}
208     * @return string
209     * @throws ExceptionCombo
210     */
211    public
212    function getBuster(): string
213    {
214        $time = FileSystems::getModifiedTime($this->getSvgFile());
215        return strval($time->getTimestamp());
216    }
217
218
219}
220