1<?php 2 3 4namespace ComboStrap; 5 6use ComboStrap\Web\Url; 7use ComboStrap\Web\UrlEndpoint; 8 9/** 10 * Class Media 11 * @package ComboStrap 12 * 13 * 14 * This is why there is a cache attribute - this is the cache of the generated file 15 * if any 16 */ 17abstract class IFetcherAbs implements IFetcher 18{ 19 20 public const NOCACHE_VALUE = "nocache"; 21 const RECACHE_VALUE = "recache"; 22 private ?string $requestedCache = null; 23 24 /** 25 * Doc: https://www.dokuwiki.org/images#caching 26 * Cache 27 * values: 28 * * cache 29 * * nocache 30 * * recache 31 */ 32 public const CACHE_KEY = 'cache'; 33 public const CACHE_DEFAULT_VALUE = "cache"; 34 35 36 private string $requestedUrlFragment; 37 38 39 /** 40 * @param Url|null $url 41 * @return Url 42 */ 43 function getFetchUrl(Url $url = null): Url 44 { 45 46 if ($url === null) { 47 $url = UrlEndpoint::createFetchUrl(); 48 } 49 50 try { 51 $url->setFragment($this->getRequestedUrlFragment()); 52 } catch (ExceptionNotFound $e) { 53 // no fragment 54 } 55 56 /** 57 * The cache 58 */ 59 try { 60 $value = $this->getRequestedCache(); 61 if ($value !== self::CACHE_DEFAULT_VALUE) { 62 $url->setQueryParameter(self::CACHE_KEY, $value); 63 } 64 } catch (ExceptionNotFound $e) { 65 // ok 66 } 67 68 /** 69 * The buster 70 */ 71 try { 72 $buster = $this->getBuster(); 73 if ($buster !== "") { 74 $url->setQueryParameter(IFetcher::CACHE_BUSTER_KEY, $buster); 75 } 76 } catch (ExceptionNotFound $e) { 77 // 78 } 79 80 81 /** 82 * The fetcher name 83 */ 84 $fetcherName = $this->getFetcherName(); 85 $url->setQueryParameter(IFetcher::FETCHER_KEY, $fetcherName); 86 87 return $url; 88 } 89 90 91 /** 92 * @throws ExceptionBadArgument 93 */ 94 public function buildFromUrl(Url $url): IFetcher 95 { 96 $query = $url->getQueryProperties(); 97 $tagAttributes = TagAttributes::createFromCallStackArray($query); 98 $this->buildFromTagAttributes($tagAttributes); 99 try { 100 $this->setRequestedUrlFragment($url->getFragment()); 101 } catch (ExceptionNotFound $e) { 102 // no fragment 103 } 104 return $this; 105 } 106 107 /** 108 * @throws ExceptionBadArgument 109 */ 110 public function buildFromTagAttributes(TagAttributes $tagAttributes): IFetcher 111 { 112 113 $cache = $tagAttributes->getValueAndRemove(self::CACHE_KEY); 114 if ($cache !== null) { 115 $this->setRequestedCache($cache); 116 } 117 118 return $this; 119 120 } 121 122 /** 123 * @return string $cache - one of {@link FetcherCache::CACHE_KEY} 124 * @throws ExceptionNotFound 125 */ 126 public function getRequestedCache(): string 127 { 128 if ($this->requestedCache === null) { 129 throw new ExceptionNotFound("No cache was requested"); 130 } 131 return $this->requestedCache; 132 } 133 134 /** 135 * 136 * @throws ExceptionBadArgument 137 */ 138 public function setRequestedCache(string $requestedCache) 139 { 140 /** 141 * Cache transformation 142 * From Image cache value (https://www.dokuwiki.org/images#caching) 143 * to {@link FetcherCache::setMaxAgeInSec()} 144 */ 145 switch ($requestedCache) { 146 case "nocache": 147 case self::RECACHE_VALUE: 148 case "cache": 149 $this->requestedCache = $requestedCache; 150 break; 151 default: 152 throw new ExceptionBadArgument("The cache value ($requestedCache) is unknown"); 153 } 154 } 155 156 /** 157 * Get cache age from cache property 158 * 159 * to {@link FetcherCache::setMaxAgeInSec()} 160 */ 161 public function getCacheMaxAgeInSec(string $cacheValue): int 162 { 163 /** 164 * From the Dokuwiki Rule 165 * From Image cache value (https://www.dokuwiki.org/images#caching) 166 * and https://www.dokuwiki.org/devel:event:fetch_media_status 167 * 168 * Not if a value is passed numerically inside dokuwiki, this rule applies 169 * $maxAge < 0 // cache forever 170 * $maxAge === 0 // never cache 171 * $maxAge > 0 // cache for a number of seconds 172 */ 173 switch ($cacheValue) { 174 case "nocache": 175 case "no": 176 // never cache 177 return 0; 178 case self::RECACHE_VALUE: 179 case "re": 180 return Site::getXhtmlCacheTime(); 181 case "cache": 182 default: 183 // cache forever 184 return PHP_INT_MAX; 185 186 } 187 188 189 } 190 191 /** 192 * 193 * The fragment may be used by plugin to jump into a media. 194 * This is the case of the PDF plugin 195 * @param string $urlFragment a fragment added to the {@link IFetcher::getFetchUrl() fetch URL} 196 */ 197 public function setRequestedUrlFragment(string $urlFragment): IFetcher 198 { 199 $this->requestedUrlFragment = $urlFragment; 200 return $this; 201 } 202 203 /** 204 * @throws ExceptionNotFound 205 */ 206 public function getRequestedUrlFragment(): string 207 { 208 209 if (!isset($this->requestedUrlFragment)) { 210 throw new ExceptionNotFound("No url fragment was requested"); 211 } 212 return $this->requestedUrlFragment; 213 214 } 215 216 public function getContentCachePath(): LocalPath 217 { 218 throw new ExceptionNotSupported("No cache support by default, overwrite this function to give access to your cache path"); 219 } 220 221 public function process(): IFetcher 222 { 223 throw new ExceptionNotSupported("The fetcher ($this) does not support to feed the cache, overwrite this function to give access to this functionality"); 224 } 225 226 public function __toString() 227 { 228 return get_class($this); 229 } 230 231 232} 233