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