diff --git a/src/Phaseolies/Error/Utils/PathResolver.php b/src/Phaseolies/Error/Utils/PathResolver.php index 1845f853..7242488e 100644 --- a/src/Phaseolies/Error/Utils/PathResolver.php +++ b/src/Phaseolies/Error/Utils/PathResolver.php @@ -24,20 +24,36 @@ class PathResolver */ public static function toDisplayPath(string $absoluteFile): string { + $absoluteFile = self::normalizePath($absoluteFile); $match = self::matchPsr4Prefix($absoluteFile); if ($match === null) { - return str_replace(base_path() . '/', '', $absoluteFile); + $basePath = rtrim(self::normalizePath(base_path()), '/'); + + return str_starts_with($absoluteFile, $basePath . '/') + ? substr($absoluteFile, strlen($basePath) + 1) + : $absoluteFile; } [$prefix, $directory] = $match; $relative = substr($absoluteFile, strlen($directory)); - $namespacePath = str_replace('\\', '/', rtrim($prefix, '\\')); + $namespacePath = rtrim(self::normalizePath($prefix), '/'); return $namespacePath . '/' . ltrim($relative, '/'); } + /** + * Normalize filesystem separators for display-path comparisons. + * + * @param string $path + * @return string + */ + private static function normalizePath(string $path): string + { + return str_replace('\\', '/', $path); + } + /** * Find the longest matching PSR-4 directory for the given file. * @@ -51,9 +67,11 @@ private static function matchPsr4Prefix(string $absoluteFile): ?array $bestPrefix = null; $bestDirectory = null; + $absoluteFile = self::normalizePath($absoluteFile); + foreach ($map as $prefix => $directories) { foreach ($directories as $directory) { - $directory = rtrim($directory, '/') . '/'; + $directory = rtrim(self::normalizePath($directory), '/') . '/'; if ( str_starts_with($absoluteFile, $directory) diff --git a/tests/Error/CrossPlatformErrorPageTest.php b/tests/Error/CrossPlatformErrorPageTest.php new file mode 100644 index 00000000..cf152e2a --- /dev/null +++ b/tests/Error/CrossPlatformErrorPageTest.php @@ -0,0 +1,38 @@ +getProperty('basePath'); + $basePath->setValue($container, dirname(__DIR__, 2)); + + Container::setInstance($container); + } + + public function testErrorFilePathIsDisplayedRelativeToTheApplicationRoot(): void + { + $errorFile = base_path( + 'storage' + . DIRECTORY_SEPARATOR . 'framework' + . DIRECTORY_SEPARATOR . 'views' + . DIRECTORY_SEPARATOR . 'error.php' + ); + + $displayPath = PathResolver::toDisplayPath($errorFile); + + $this->assertSame('storage/framework/views/error.php', $displayPath); + } +}