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