xref: /plugin/combo/ComboStrap/FileSystems.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1c3437056SNickeau<?php
2c3437056SNickeau
3c3437056SNickeau
4c3437056SNickeaunamespace ComboStrap;
5c3437056SNickeau
6c3437056SNickeau
7*04fd306cSNickeauuse renderer_plugin_combo_analytics;
8*04fd306cSNickeau
9c3437056SNickeauclass FileSystems
10c3437056SNickeau{
11c3437056SNickeau
12*04fd306cSNickeau    public const CONTAINER = "container";
13*04fd306cSNickeau    public const LEAF = "leaf";
14*04fd306cSNickeau
15c3437056SNickeau    static function exists(Path $path): bool
16c3437056SNickeau    {
17c3437056SNickeau        $scheme = $path->getScheme();
18c3437056SNickeau        switch ($scheme) {
19*04fd306cSNickeau            case LocalFileSystem::SCHEME:
20*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->exists($path);
21*04fd306cSNickeau            case WikiFileSystem::SCHEME:
22*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->exists($path);
23*04fd306cSNickeau            case MarkupFileSystem::SCHEME:
24*04fd306cSNickeau                return MarkupFileSystem::getOrCreate()->exists($path);
25c3437056SNickeau            default:
26*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
27c3437056SNickeau        }
28c3437056SNickeau    }
29c3437056SNickeau
30*04fd306cSNickeau    /**
31*04fd306cSNickeau     * @throws ExceptionNotFound - if the file does not exists or the mime is unknown
32*04fd306cSNickeau     */
33*04fd306cSNickeau    public static function getContent(Path $path): string
34c3437056SNickeau    {
35c3437056SNickeau        $scheme = $path->getScheme();
36c3437056SNickeau        switch ($scheme) {
37*04fd306cSNickeau            case LocalFileSystem::SCHEME:
38*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->getContent($path);
39*04fd306cSNickeau            case WikiFileSystem::SCHEME:
40*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->getContent($path);
41c3437056SNickeau        }
42*04fd306cSNickeau        throw new ExceptionRuntime("File system ($scheme) unknown");
43c3437056SNickeau    }
44c3437056SNickeau
45*04fd306cSNickeau    /**
46*04fd306cSNickeau     * @throws ExceptionNotFound - if the file does not exist
47*04fd306cSNickeau     */
48*04fd306cSNickeau    public static function getModifiedTime(Path $path): \DateTime
49c3437056SNickeau    {
50c3437056SNickeau        $scheme = $path->getScheme();
51c3437056SNickeau        switch ($scheme) {
52*04fd306cSNickeau            case LocalFileSystem::SCHEME:
53*04fd306cSNickeau                /** @noinspection PhpParamsInspection */
54*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->getModifiedTime($path);
55*04fd306cSNickeau            case WikiFileSystem::SCHEME:
56*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->getModifiedTime($path);
57c3437056SNickeau            default:
58*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
59c3437056SNickeau        }
60c3437056SNickeau
61c3437056SNickeau    }
62c3437056SNickeau
63*04fd306cSNickeau    /**
64*04fd306cSNickeau     * @throws ExceptionNotFound
65*04fd306cSNickeau     */
66c3437056SNickeau    public static function getCreationTime(Path $path)
67c3437056SNickeau    {
68c3437056SNickeau        $scheme = $path->getScheme();
69c3437056SNickeau        switch ($scheme) {
70*04fd306cSNickeau            case LocalFileSystem::SCHEME:
71*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->getCreationTime($path);
72*04fd306cSNickeau            case WikiFileSystem::SCHEME:
73*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->getCreationTime($path);
74c3437056SNickeau            default:
75*04fd306cSNickeau                // Internal Error: should not happen
76*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
77c3437056SNickeau        }
78c3437056SNickeau    }
79c3437056SNickeau
80c3437056SNickeau    public static function deleteIfExists(Path $path)
81c3437056SNickeau    {
82c3437056SNickeau        if (FileSystems::exists($path)) {
83c3437056SNickeau            FileSystems::delete($path);
84c3437056SNickeau        }
85c3437056SNickeau    }
86c3437056SNickeau
87*04fd306cSNickeau    /**
88*04fd306cSNickeau     * @throws ExceptionFileSystem
89*04fd306cSNickeau     */
90c3437056SNickeau    public static function delete(Path $path)
91c3437056SNickeau    {
92c3437056SNickeau        $scheme = $path->getScheme();
93c3437056SNickeau        switch ($scheme) {
94*04fd306cSNickeau            case LocalFileSystem::SCHEME:
95*04fd306cSNickeau                LocalFileSystem::getOrCreate()->delete($path);
96c3437056SNickeau                return;
97*04fd306cSNickeau            case WikiFileSystem::SCHEME:
98*04fd306cSNickeau                WikiFileSystem::getOrCreate()->delete($path);
99*04fd306cSNickeau                return;
100*04fd306cSNickeau            case MarkupFileSystem::SCHEME:
101*04fd306cSNickeau                MarkupFileSystem::getOrCreate()->delete($path);
102c3437056SNickeau                return;
103c3437056SNickeau            default:
104*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
105c3437056SNickeau        }
106c3437056SNickeau    }
107c3437056SNickeau
108c3437056SNickeau    public static function getSize(Path $path)
109c3437056SNickeau    {
110c3437056SNickeau
111c3437056SNickeau        $scheme = $path->getScheme();
112c3437056SNickeau        switch ($scheme) {
113*04fd306cSNickeau            case LocalFileSystem::SCHEME:
114*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->getSize($path);
115*04fd306cSNickeau            case WikiFileSystem::SCHEME:
116*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->getSize($path);
117c3437056SNickeau            default:
118*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
119c3437056SNickeau        }
120c3437056SNickeau    }
121c3437056SNickeau
122c3437056SNickeau
123c3437056SNickeau    /**
124*04fd306cSNickeau     * @throws ExceptionCompile
125c3437056SNickeau     */
126c3437056SNickeau    public static function createDirectory(Path $dirPath)
127c3437056SNickeau    {
128c3437056SNickeau        $scheme = $dirPath->getScheme();
129c3437056SNickeau        switch ($scheme) {
130*04fd306cSNickeau            case LocalFileSystem::SCHEME:
131*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->createDirectory($dirPath);
132*04fd306cSNickeau            case WikiFileSystem::SCHEME:
133*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->createDirectory($dirPath);
134c3437056SNickeau            default:
135*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
136*04fd306cSNickeau        }
137*04fd306cSNickeau    }
138*04fd306cSNickeau
139*04fd306cSNickeau    public static function isDirectory(Path $path): bool
140*04fd306cSNickeau    {
141*04fd306cSNickeau        $scheme = $path->getScheme();
142*04fd306cSNickeau        switch ($scheme) {
143*04fd306cSNickeau            case LocalFileSystem::SCHEME:
144*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->isDirectory($path);
145*04fd306cSNickeau            case WikiFileSystem::SCHEME:
146*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->isDirectory($path);
147*04fd306cSNickeau            default:
148*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
149*04fd306cSNickeau        }
150*04fd306cSNickeau    }
151*04fd306cSNickeau
152*04fd306cSNickeau
153*04fd306cSNickeau    /**
154*04fd306cSNickeau     * @return Path[]
155*04fd306cSNickeau     */
156*04fd306cSNickeau    public static function getChildren(Path $path, string $type = null): array
157*04fd306cSNickeau    {
158*04fd306cSNickeau        $scheme = $path->getScheme();
159*04fd306cSNickeau        switch ($scheme) {
160*04fd306cSNickeau            case LocalFileSystem::SCHEME:
161*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->getChildren($path, $type);
162*04fd306cSNickeau            case WikiFileSystem::SCHEME:
163*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->getChildren($path, $type);
164*04fd306cSNickeau            case MarkupFileSystem::SCHEME:
165*04fd306cSNickeau                return MarkupFileSystem::getOrCreate()->getChildren($path, $type);
166*04fd306cSNickeau            default:
167*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
168*04fd306cSNickeau        }
169*04fd306cSNickeau    }
170*04fd306cSNickeau
171*04fd306cSNickeau    /**
172*04fd306cSNickeau     * @param Path $namespacePath
173*04fd306cSNickeau     * @return Path[]
174*04fd306cSNickeau     */
175*04fd306cSNickeau    public static function getChildrenContainer(Path $namespacePath): array
176*04fd306cSNickeau    {
177*04fd306cSNickeau        return self::getChildren($namespacePath, FileSystems::CONTAINER);
178*04fd306cSNickeau    }
179*04fd306cSNickeau
180*04fd306cSNickeau    /**
181*04fd306cSNickeau     * @param Path $namespacePath
182*04fd306cSNickeau     * @return Path[]
183*04fd306cSNickeau     */
184*04fd306cSNickeau    public static function getChildrenLeaf(Path $namespacePath): array
185*04fd306cSNickeau    {
186*04fd306cSNickeau        try {
187*04fd306cSNickeau            return self::getChildren($namespacePath, FileSystems::LEAF);
188*04fd306cSNickeau        } catch (ExceptionBadArgument $e) {
189*04fd306cSNickeau            // as we path the type, it should not happen
190*04fd306cSNickeau            throw new ExceptionRuntime("Error getting the children. Error: {$e->getMessage()}");
191*04fd306cSNickeau        }
192*04fd306cSNickeau    }
193*04fd306cSNickeau
194*04fd306cSNickeau    /**
195*04fd306cSNickeau     * Return a cache buster
196*04fd306cSNickeau     * @throws ExceptionNotFound
197*04fd306cSNickeau     * Utility function to calculate a buster based on a path for the implementation of {@link FetchAbstract::getBuster()}
198*04fd306cSNickeau     */
199*04fd306cSNickeau    public static function getCacheBuster(Path $path): string
200*04fd306cSNickeau    {
201*04fd306cSNickeau        $time = FileSystems::getModifiedTime($path);
202*04fd306cSNickeau        return strval($time->getTimestamp());
203*04fd306cSNickeau    }
204*04fd306cSNickeau
205*04fd306cSNickeau    /**
206*04fd306cSNickeau     * @throws ExceptionNotFound
207*04fd306cSNickeau     */
208*04fd306cSNickeau    public static function closest(Path $path, string $name): Path
209*04fd306cSNickeau    {
210*04fd306cSNickeau        $scheme = $path->getScheme();
211*04fd306cSNickeau        switch ($scheme) {
212*04fd306cSNickeau            case LocalFileSystem::SCHEME:
213*04fd306cSNickeau                return LocalFileSystem::getOrCreate()->closest($path, $name);
214*04fd306cSNickeau            case WikiFileSystem::SCHEME:
215*04fd306cSNickeau                return WikiFileSystem::getOrCreate()->closest($path, $name);
216*04fd306cSNickeau            default:
217*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
218*04fd306cSNickeau        }
219*04fd306cSNickeau    }
220*04fd306cSNickeau
221*04fd306cSNickeau    public static function createRegularFile(Path $path)
222*04fd306cSNickeau    {
223*04fd306cSNickeau        $scheme = $path->getScheme();
224*04fd306cSNickeau        switch ($scheme) {
225*04fd306cSNickeau            case LocalFileSystem::SCHEME:
226*04fd306cSNickeau                LocalFileSystem::getOrCreate()->createRegularFile($path);
227*04fd306cSNickeau                break;
228*04fd306cSNickeau            case WikiFileSystem::SCHEME:
229*04fd306cSNickeau                WikiFileSystem::getOrCreate()->createRegularFile($path);
230*04fd306cSNickeau                break;
231*04fd306cSNickeau            default:
232*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
233*04fd306cSNickeau        }
234*04fd306cSNickeau    }
235*04fd306cSNickeau
236*04fd306cSNickeau    /**
237*04fd306cSNickeau     * @throws ExceptionNotFound - if the mime is unknown and was not found
238*04fd306cSNickeau     */
239*04fd306cSNickeau    public static function getMime(Path $path): Mime
240*04fd306cSNickeau    {
241*04fd306cSNickeau        $extension = $path->getExtension();
242*04fd306cSNickeau        try {
243*04fd306cSNickeau            return Mime::createFromExtension($extension);
244*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
245*04fd306cSNickeau            $mime = mimetype($path->getLastName(), true)[1];
246*04fd306cSNickeau            if ($mime === null || $mime === false) {
247*04fd306cSNickeau                throw new ExceptionNotFound("No mime found for path ($path). The mime type of the media is <a href=\"https://www.dokuwiki.org/mime\">unknown (not in the configuration file)</a>");
248*04fd306cSNickeau            }
249*04fd306cSNickeau            return new Mime($mime);
250*04fd306cSNickeau        }
251*04fd306cSNickeau    }
252*04fd306cSNickeau
253*04fd306cSNickeau    public static function setContent(Path $path, string $content)
254*04fd306cSNickeau    {
255*04fd306cSNickeau        $scheme = $path->getScheme();
256*04fd306cSNickeau        switch ($scheme) {
257*04fd306cSNickeau            case LocalFileSystem::SCHEME:
258*04fd306cSNickeau                LocalFileSystem::getOrCreate()->setContent($path, $content);
259*04fd306cSNickeau                break;
260*04fd306cSNickeau            case WikiFileSystem::SCHEME:
261*04fd306cSNickeau                WikiFileSystem::getOrCreate()->setContent($path, $content);
262*04fd306cSNickeau                break;
263*04fd306cSNickeau            case MarkupFileSystem::SCHEME:
264*04fd306cSNickeau                MarkupFileSystem::getOrCreate()->setContent($path, $content);
265*04fd306cSNickeau                break;
266*04fd306cSNickeau            default:
267*04fd306cSNickeau                throw new ExceptionRuntime("File system ($scheme) unknown");
268*04fd306cSNickeau        }
269*04fd306cSNickeau    }
270*04fd306cSNickeau
271*04fd306cSNickeau    /**
272*04fd306cSNickeau     * @param Path[] $paths
273*04fd306cSNickeau     * @return Path
274*04fd306cSNickeau     * @throws ExceptionNotFound
275*04fd306cSNickeau     */
276*04fd306cSNickeau    public static function getFirstExistingPath(array $paths): Path
277*04fd306cSNickeau    {
278*04fd306cSNickeau
279*04fd306cSNickeau        foreach ($paths as $path) {
280*04fd306cSNickeau            if (FileSystems::exists($path)) {
281*04fd306cSNickeau                return $path;
282*04fd306cSNickeau            }
283*04fd306cSNickeau        }
284*04fd306cSNickeau        throw new ExceptionNotFound("Existing file could be found");
285*04fd306cSNickeau
286*04fd306cSNickeau    }
287*04fd306cSNickeau
288*04fd306cSNickeau    public static function getTree(Path $path): PathTreeNode
289*04fd306cSNickeau    {
290*04fd306cSNickeau        return PathTreeNode::buildTreeViaFileSystemChildren($path);
291*04fd306cSNickeau    }
292*04fd306cSNickeau
293*04fd306cSNickeau    /**
294*04fd306cSNickeau     * @throws ExceptionBadArgument - if they are not local path
295*04fd306cSNickeau     */
296*04fd306cSNickeau    public static function copy(Path $source, Path $destination)
297*04fd306cSNickeau    {
298*04fd306cSNickeau        $sourceLocal = LocalPath::createFromPathObject($source);
299*04fd306cSNickeau        $destinationLocal = LocalPath::createFromPathObject($destination);
300*04fd306cSNickeau        copy($sourceLocal->toAbsoluteId(), $destinationLocal->toAbsoluteId());
301*04fd306cSNickeau
302*04fd306cSNickeau        // D:\dokuwiki\lib\plugins\combo\_test\resources\bootstrapLocal.json
303*04fd306cSNickeau    }
304*04fd306cSNickeau
305*04fd306cSNickeau    /**
306*04fd306cSNickeau     * Debug
307*04fd306cSNickeau     * @param Path $mediaFile
308*04fd306cSNickeau     * @return void
309*04fd306cSNickeau     * Unfortunately, due to php, the time may be not use
310*04fd306cSNickeau     * at the second
311*04fd306cSNickeau     * as for the same file, we may end up in the same
312*04fd306cSNickeau     * process to two differents modified time.
313*04fd306cSNickeau     * ie
314*04fd306cSNickeau     * Fri, 10 Feb 2023 18:22:09 +0000
315*04fd306cSNickeau     * Fri, 10 Feb 2023 18:22:30 +0000
316*04fd306cSNickeau     */
317*04fd306cSNickeau    public static function printModificationTimeToConsole(Path $mediaFile, string $log)
318*04fd306cSNickeau    {
319*04fd306cSNickeau        fputs(STDOUT, "ModificationTime of {$mediaFile->toAbsoluteId()}" . PHP_EOL);
320*04fd306cSNickeau        $filename = $mediaFile->toAbsolutePath()->toAbsoluteId();
321*04fd306cSNickeau        fputs(STDOUT, "ModificationTime of $filename at $log ");
322*04fd306cSNickeau        $timestamp = filemtime($filename);
323*04fd306cSNickeau        fputs(STDOUT, " $timestamp" . PHP_EOL);
324*04fd306cSNickeau    }
325*04fd306cSNickeau
326*04fd306cSNickeau    public static function clearStatCache(Path $path)
327*04fd306cSNickeau    {
328*04fd306cSNickeau        try {
329*04fd306cSNickeau            $pathString = $path->toLocalPath()->toCanonicalAbsolutePath()->toAbsoluteId();
330*04fd306cSNickeau            clearstatcache(true, $pathString);
331*04fd306cSNickeau        } catch (ExceptionCast $e) {
332*04fd306cSNickeau            throw new ExceptionRuntimeInternal("The cache can be clear only for local path");
333*04fd306cSNickeau        }
334*04fd306cSNickeau
335*04fd306cSNickeau    }
336*04fd306cSNickeau
337*04fd306cSNickeau
338*04fd306cSNickeau    /**
339*04fd306cSNickeau     * @throws ExceptionBadSyntax
340*04fd306cSNickeau     * @throws ExceptionBadArgument
341*04fd306cSNickeau     */
342*04fd306cSNickeau    public static function createPathFromUri($uri): Path
343*04fd306cSNickeau    {
344*04fd306cSNickeau        $firstColon = strpos($uri, ":");
345*04fd306cSNickeau        if ($firstColon === false) {
346*04fd306cSNickeau            throw new ExceptionBadSyntax("$uri is not a valid uri");
347*04fd306cSNickeau        }
348*04fd306cSNickeau        $scheme = substr($uri, 0, $firstColon);
349*04fd306cSNickeau        switch ($scheme) {
350*04fd306cSNickeau            case WikiFileSystem::SCHEME:
351*04fd306cSNickeau                return WikiPath::createFromUri($uri);
352*04fd306cSNickeau            case LocalFileSystem::SCHEME:
353*04fd306cSNickeau                return LocalPath::createFromUri($uri);
354*04fd306cSNickeau            default:
355*04fd306cSNickeau                throw new ExceptionRuntimeInternal("The scheme ($scheme) is not yet supported");
356*04fd306cSNickeau        }
357*04fd306cSNickeau
358*04fd306cSNickeau    }
359*04fd306cSNickeau
360*04fd306cSNickeau    /**
361*04fd306cSNickeau     * @throws ExceptionCompile
362*04fd306cSNickeau     */
363*04fd306cSNickeau    public static function createDirectoryIfNotExists(Path $directoryPath)
364*04fd306cSNickeau    {
365*04fd306cSNickeau        if (!self::exists($directoryPath)){
366*04fd306cSNickeau            self::createDirectory($directoryPath);
367c3437056SNickeau        }
368c3437056SNickeau    }
369c3437056SNickeau}
370