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