diff --git a/CHANGELOG.md b/CHANGELOG.md index ab235e62..9100f761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## 4.6.1 +## [4.6.1](https://github.com/userfrosting/framework/compare/4.6.0...4.6.1) + - Fix issue with location outside of the main path not returning the correct relative path. - Update php-cs-fixer to V3 ## 4.6.0 diff --git a/src/UniformResourceLocator/Normalizer.php b/src/UniformResourceLocator/Normalizer.php index 9736de35..1ca5bce1 100644 --- a/src/UniformResourceLocator/Normalizer.php +++ b/src/UniformResourceLocator/Normalizer.php @@ -72,9 +72,9 @@ public static function normalize($uri, $throwException = false, $splitStream = f } /** - * Normalise a path: + * Normalize a path: * - Make sure all `\` (from a Windows path) are changed to `/` - * - Make sure a trailling slash is present + * - Make sure a trailing slash is present * - Doesn't change the beginning of the path (don't change absolute / relative path), but will change `C:\` to `C:/`. * * @param string $path diff --git a/src/UniformResourceLocator/Resource.php b/src/UniformResourceLocator/Resource.php index af2c1d07..9db78003 100644 --- a/src/UniformResourceLocator/Resource.php +++ b/src/UniformResourceLocator/Resource.php @@ -19,8 +19,8 @@ * paths of the file. Using this information, we can later rebuilt the URI used * to find this file. Since the full path will contains the relative location of * the stream and location inside the filesystem, this information will be - * removed to recrete the relative 'basepath' of the file, allowing the - * recreatation of the uri (scheme://basePath). + * removed to recreate the relative 'basepath' of the file, allowing the + * recreation of the uri (scheme://basePath). * * @author Louis Charette */ @@ -64,7 +64,7 @@ public function __construct(ResourceStreamInterface $stream, ResourceLocationInt /** * Get Resource URI - * Also adds the prefix stream prefix if it existprefix. + * Also adds the prefix stream prefix if it exist. * * @return string */ @@ -83,7 +83,7 @@ public function getUri(): string $parts[] = $this->getBasePath(); } - // Glue parts togeter. + // Glue parts together. $path = implode('/', $parts); return $this->stream->getScheme().'://'.$path; diff --git a/src/UniformResourceLocator/ResourceLocator.php b/src/UniformResourceLocator/ResourceLocator.php index 36a95155..6977121d 100644 --- a/src/UniformResourceLocator/ResourceLocator.php +++ b/src/UniformResourceLocator/ResourceLocator.php @@ -135,7 +135,7 @@ protected function setupStreamWrapper(string $scheme): void return; } - // First unset the sheme. Prevent issue if someone else already registered it + // First unset the scheme. Prevent issue if someone else already registered it $this->unsetStreamWrapper($scheme); // register the scheme as a stream wrapper @@ -189,7 +189,9 @@ public function registerStream(string $scheme, string $prefix = '', $paths = nul */ public function registerSharedStream(string $scheme, string $prefix = '', $paths = null): self { - return $this->registerStream($scheme, $prefix, $paths, true); + $this->registerStream($scheme, $prefix, $paths, true); + + return $this; } /** @@ -347,7 +349,7 @@ public function listResources(string $uri, bool $all = false, bool $sort = true) { $list = []; - // Get all directory where we can find this ressource. Will be returned with the priority order + // Get all directory where we can find this resource. Will be returned with the priority order $directories = $this->getResources($uri); foreach ($directories as $directory) { @@ -355,7 +357,7 @@ public function listResources(string $uri, bool $all = false, bool $sort = true) // Use Filesystem to list all file in the directory $files = $this->filesystem->allFiles($directory->getAbsolutePath()); - // Sort files. Filesystem can return inconsistant order sometime + // Sort files. Filesystem can return inconsistent order sometime // Files will be sorted alphabetically inside a location even if don't resort later across all sprinkles $files = Arr::sort($files, function ($resource) { return $resource->getRealPath(); @@ -367,10 +369,15 @@ public function listResources(string $uri, bool $all = false, bool $sort = true) $basePath = rtrim($this->getBasePath(), $this->separator).$this->separator; $fullPath = $file->getPathname(); $relPath = str_replace($basePath, '', $fullPath); - $relPath = ltrim($relPath, $this->separator); - // Create the ressource and add it to the list - $resource = new Resource($directory->getStream(), $directory->getLocation(), $relPath, $basePath); + // Create the resource and add it to the list + // Handle relPath that is an absolute outside the basePath + // This can happen when the location has an absolute path outside the locator base path. + if ($fullPath == $relPath) { + $resource = new Resource($directory->getStream(), $directory->getLocation(), $fullPath); + } else { + $resource = new Resource($directory->getStream(), $directory->getLocation(), $relPath, $basePath); + } if ($all) { // Add all files to the list @@ -428,7 +435,7 @@ public function isStream($uri): bool /** * Find highest priority instance from a resource. Return the path for said resource - * For example, if looking for a `test.json` ressource, only the top priority + * For example, if looking for a `test.json` resource, only the top priority * instance of `test.json` found will be returned. * * @param string $uri Input URI to be searched (can be a file or directory) @@ -437,7 +444,7 @@ public function isStream($uri): bool * * @throws \BadMethodCallException * - * @return string|bool The ressource path, or false if not found resource + * @return string|bool The resource path, or false if not found resource */ public function findResource($uri, $absolute = true, $first = false) { @@ -456,14 +463,14 @@ public function findResource($uri, $absolute = true, $first = false) /** * Find all instances from a resource. Return an array of paths for said resource - * For example, if looking for a `test.json` ressource, all instance + * For example, if looking for a `test.json` resource, all instance * of `test.json` found will be listed. * * @param string $uri Input URI to be searched (can be a file or directory) * @param bool $absolute Whether to return absolute path. * @param bool $all Whether to return all paths even if they don't exist. * - * @return string[] An array of all the ressources path + * @return string[] An array of all the resources path */ public function findResources($uri, $absolute = true, $all = false) { @@ -488,7 +495,7 @@ public function findResources($uri, $absolute = true, $all = false) * @param bool $array Return an array or a single path * @param bool $all Whether to return all paths even if they don't exist. * - * @return ResourceInterface[]|ResourceInterface|false The ressource path or an array of all the ressources path or false if not resource can be found + * @return ResourceInterface[]|ResourceInterface|false The resource path or an array of all the resources path or false if not resource can be found */ protected function findCached(string $uri, bool $array, bool $all) { @@ -510,7 +517,7 @@ protected function findCached(string $uri, bool $array, bool $all) } /** - * Build the search path out of the defined strean and locations. + * Build the search path out of the defined stream and locations. * If the scheme is shared, we don't need to involve locations and can return it's path directly. * * @param ResourceStreamInterface $stream The stream to search for @@ -597,7 +604,15 @@ protected function find(string $scheme, string $file, bool $array, bool $all) // Add the result to the list if the path exist, unless we want all results if ($all || $this->filesystem->exists($fullPath)) { - $currentResource = new Resource($stream, $location, $relPath, $basePath); + + // Handle relpath that is an absolute outside the basePath + // This can happen when the location has an absolute path outside the locator base path. + if ($fullPath == $relPath) { + $currentResource = new Resource($stream, $location, $fullPath); + } else { + $currentResource = new Resource($stream, $location, $relPath, $basePath); + } + if (!$array) { return $currentResource; } diff --git a/src/UniformResourceLocator/ResourceLocatorInterface.php b/src/UniformResourceLocator/ResourceLocatorInterface.php index dc0084fc..df8ba27e 100644 --- a/src/UniformResourceLocator/ResourceLocatorInterface.php +++ b/src/UniformResourceLocator/ResourceLocatorInterface.php @@ -45,7 +45,7 @@ public function addStream(ResourceStreamInterface $stream); * @param string $scheme * @param string $prefix (default '') * @param string|string[]|null $paths (default null). When using null path, the scheme will be used as a path - * @param bool $shared (default false) Shared resoureces are not affected by locations + * @param bool $shared (default false) Shared resources are not affected by locations * * @return static */ @@ -61,7 +61,7 @@ public function registerStream(string $scheme, string $prefix = '', $paths = nul public function removeStream(string $scheme); /** - * Return information about a specfic stream. + * Return information about a specific stream. * Return value is an array of ResourceStreamInterface, for each prefix * For example : * $array = array( @@ -111,7 +111,7 @@ public function listStreams(); public function schemeExists(string $scheme): bool; /** - * Add an existing RessourceLocation instance to the location list. + * Add an existing ResourceLocation instance to the location list. * * @param ResourceLocationInterface $location * @@ -193,15 +193,15 @@ public function getResource(string $uri, bool $first = false); public function getResources(string $uri, bool $all = false): array; /** - * List all ressources found at a given uri. + * List all resources found at a given uri. * Same as listing all file in a directory, except here all topmost - * ressources will be returned when considering all locations. + * resources will be returned when considering all locations. * * @param string $uri Input URI to be searched (can be a uri/path ONLY) * @param bool $all If true, all resources will be returned, not only topmost ones * @param bool $sort Set to true to sort results alphabetically by absolute path. Set to false to sort by absolute priority, higest location first. Default to true. * - * @return ResourceInterface[] The ressources list + * @return ResourceInterface[] The resources list */ public function listResources(string $uri, bool $all = false, bool $sort = true); diff --git a/tests/UniformResourceLocator/ResourceLocatorTest.php b/tests/UniformResourceLocator/ResourceLocatorTest.php index 0461acd8..709fdd08 100644 --- a/tests/UniformResourceLocator/ResourceLocatorTest.php +++ b/tests/UniformResourceLocator/ResourceLocatorTest.php @@ -439,7 +439,7 @@ public function testStreamWithEmptyPath(): void } /** - * With stream poiting to `app/uploads/profile`, we make sure we can't access `app/uploads/MyFile.txt`. + * With stream pointing to `app/uploads/profile`, we make sure we can't access `app/uploads/MyFile.txt`. */ public function testFindResourceWithBackPath(): void { @@ -451,4 +451,32 @@ public function testFindResourceWithBackPath(): void $this->assertFalse($result); } + + /** + * Test a location outside of the main path produce the correct relative path. + */ + public function testFindResourceOutsideMainPath(): void + { + $locator = new ResourceLocator(__DIR__.'/Building/Floors'); + $locator->registerStream('files'); + $locator->registerLocation('Garage', __DIR__.'/Building/Garage'); + + $resource = $locator->findResource('files://blah.json'); + + $this->assertSame(__DIR__.'/Building/Garage/files/blah.json', $resource); + } + + /** + * Test a location outside of the main path produce the correct relative path. + */ + public function testListResourceOutsideMainPath(): void + { + $locator = new ResourceLocator(__DIR__.'/Building/Floors'); + $locator->registerStream('files'); + $locator->registerLocation('Garage', __DIR__.'/Building/Garage'); + + $resources = $locator->listResources('files://', true); + + $this->assertSame(__DIR__.'/Building/Garage/files/blah.json', $resources[0]->getAbsolutePath()); + } }