Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
13 / 13
CRAP
100.00% covered (success)
100.00%
1 / 1
Filesystem
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
13 / 13
23
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBasePath
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 path
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 pathToAbsolute
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 pathToRelative
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 mediaPath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 sitePath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 siteMediaPath
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 vendorPath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 touch
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 unlink
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 unlinkIfExists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 smartGlob
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Hyde\Foundation\Kernel;
6
7use Hyde\Hyde;
8use Hyde\Foundation\HydeKernel;
9use Hyde\Foundation\PharSupport;
10use Illuminate\Support\Collection;
11
12use function collect;
13use function Hyde\normalize_slashes;
14use function Hyde\path_join;
15use function file_exists;
16use function str_replace;
17use function array_map;
18use function is_array;
19use function str_starts_with;
20use function Hyde\unslash;
21use function unlink;
22use function touch;
23
24/**
25 * File helper methods, bound to the HydeKernel instance, and is an integral part of the framework.
26 *
27 * All paths arguments are relative to the root of the application,
28 * and will be automatically resolved to absolute paths.
29 */
30class Filesystem
31{
32    protected HydeKernel $kernel;
33
34    public function __construct(HydeKernel $kernel)
35    {
36        $this->kernel = $kernel;
37    }
38
39    public function getBasePath(): string
40    {
41        return $this->kernel->getBasePath();
42    }
43
44    /**
45     * Get an absolute file path from a supplied relative path.
46     *
47     * The function returns the fully qualified path to your site's root directory.
48     *
49     * You may also use the function to generate a fully qualified path to a given file
50     * relative to the project root directory when supplying the path argument.
51     */
52    public function path(string $path = ''): string
53    {
54        if (empty($path)) {
55            return $this->getBasePath();
56        }
57
58        if (str_starts_with($path, 'phar://')) {
59            return $path;
60        }
61
62        $path = unslash($this->pathToRelative($path));
63
64        return path_join($this->getBasePath(), $path);
65    }
66
67    /**
68     * Get an absolute file path from a supplied relative path.
69     *
70     * Input types are matched, meaning that if the input is a string so will the output be.
71     *
72     * @param  string|array<string>  $path
73     * @return ($path is string ? string : array<string>)
74     */
75    public function pathToAbsolute(string|array $path): string|array
76    {
77        if (is_array($path)) {
78            return array_map(fn (string $path): string => $this->pathToAbsolute($path), $path);
79        }
80
81        return $this->path($path);
82    }
83
84    /**
85     * Decode an absolute path created with a Hyde::path() helper into its relative counterpart.
86     */
87    public function pathToRelative(string $path): string
88    {
89        return normalize_slashes(str_starts_with($path, $this->path())
90            ? unslash(str_replace($this->path(), '', $path))
91            : $path);
92    }
93
94    /**
95     * Get the absolute path to the media source directory, or a file within it.
96     */
97    public function mediaPath(string $path = ''): string
98    {
99        if (empty($path)) {
100            return $this->path(Hyde::getMediaDirectory());
101        }
102
103        return $this->path(path_join(Hyde::getMediaDirectory(), unslash($path)));
104    }
105
106    /**
107     * Get the absolute path to the compiled site directory, or a file within it.
108     */
109    public function sitePath(string $path = ''): string
110    {
111        if (empty($path)) {
112            return $this->path(Hyde::getOutputDirectory());
113        }
114
115        return $this->path(path_join(Hyde::getOutputDirectory(), unslash($path)));
116    }
117
118    /**
119     * Get the absolute path to the compiled site's media directory, or a file within it.
120     */
121    public function siteMediaPath(string $path = ''): string
122    {
123        if (empty($path)) {
124            return $this->sitePath(Hyde::getMediaOutputDirectory());
125        }
126
127        $path = unslash($path);
128
129        return $this->sitePath(Hyde::getMediaOutputDirectory()."/$path");
130    }
131
132    /**
133     * Works similarly to the path() function, but returns a file in the Framework package.
134     *
135     * @internal This is not intended to be used outside the HydePHP framework.
136     */
137    public function vendorPath(string $path = '', string $package = 'framework'): string
138    {
139        if (PharSupport::running() && ! PharSupport::hasVendorDirectory()) {
140            return PharSupport::vendorPath($path, $package);
141        }
142
143        return $this->path("vendor/hyde/$package/".unslash($path));
144    }
145
146    /**
147     * Touch one or more files in the project's directory.
148     *
149     * @param  string|array<string>  $path
150     */
151    public function touch(string|array $path): bool
152    {
153        return collect($path)->map(function (string $path): bool {
154            return touch($this->path($path));
155        })->contains(false) === false;
156    }
157
158    /**
159     * Unlink one or more files in the project's directory.
160     *
161     * @param  string|array<string>  $path
162     */
163    public function unlink(string|array $path): bool
164    {
165        return collect($path)->map(function (string $path): bool {
166            return unlink($this->path($path));
167        })->contains(false) === false;
168    }
169
170    /**
171     * Unlink a file in the project's directory, but only if it exists.
172     */
173    public function unlinkIfExists(string $path): bool
174    {
175        return file_exists($this->path($path)) && unlink($this->path($path));
176    }
177
178    /** @return \Illuminate\Support\Collection<int, string> */
179    public function smartGlob(string $pattern, int $flags = 0): Collection
180    {
181        /** @var \Illuminate\Support\Collection<int, string> $files */
182        $files = collect(\Hyde\Facades\Filesystem::glob($pattern, $flags));
183
184        return $files->map(fn (string $path): string => $this->pathToRelative($path));
185    }
186}