FestinHegre/vendor/symfony/asset-mapper/AssetMapperRepository.php
2024-09-26 17:26:04 +02:00

199 lines
5.8 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\AssetMapper;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
/**
* Finds assets in the asset mapper.
*
* @author Ryan Weaver <ryan@symfonycasts.com>
*
* @final
*/
class AssetMapperRepository
{
private ?array $absolutePaths = null;
/**
* @param string[] $paths Array of assets paths: key is the path, value is the namespace
* (empty string for no namespace)
*/
public function __construct(
private readonly array $paths,
private readonly string $projectRootDir,
private readonly array $excludedPathPatterns = [],
private readonly bool $excludeDotFiles = true,
private readonly bool $debug = true,
) {
}
/**
* Given the logical path - styles/app.css - returns the absolute path to the file.
*/
public function find(string $logicalPath): ?string
{
foreach ($this->getDirectories() as $path => $namespace) {
$localLogicalPath = $logicalPath;
// if this path has a namespace, only look for files in that namespace
if ('' !== $namespace) {
if (!str_starts_with($logicalPath, rtrim($namespace, '/').'/')) {
continue;
}
$localLogicalPath = substr($logicalPath, \strlen($namespace) + 1);
}
$file = rtrim($path, '/').'/'.$localLogicalPath;
if (is_file($file) && !$this->isExcluded($file)) {
return realpath($file);
}
}
return null;
}
public function findLogicalPath(string $filesystemPath): ?string
{
if (!is_file($filesystemPath)) {
return null;
}
$filesystemPath = realpath($filesystemPath);
if ($this->isExcluded($filesystemPath)) {
return null;
}
foreach ($this->getDirectories() as $path => $namespace) {
if (!str_starts_with($filesystemPath, $path.\DIRECTORY_SEPARATOR)) {
continue;
}
$logicalPath = substr($filesystemPath, \strlen($path));
if ('' !== $namespace) {
$logicalPath = $namespace.'/'.ltrim($logicalPath, '/\\');
}
return $this->normalizeLogicalPath($logicalPath);
}
return null;
}
/**
* Returns an array of all files in the asset_mapper.
*
* Key is the logical path, value is the absolute path.
*
* @return string[]
*/
public function all(): array
{
$paths = [];
foreach ($this->getDirectories() as $path => $namespace) {
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
foreach ($iterator as $file) {
/** @var \SplFileInfo $file */
if (!$file->isFile()) {
continue;
}
if ($this->isExcluded($file->getPathname())) {
continue;
}
// avoid potentially exposing PHP files
if ('php' === $file->getExtension()) {
continue;
}
/** @var RecursiveDirectoryIterator $innerIterator */
$innerIterator = $iterator->getInnerIterator();
$logicalPath = ($namespace ? rtrim($namespace, '/').'/' : '').$innerIterator->getSubPathName();
$logicalPath = $this->normalizeLogicalPath($logicalPath);
$paths[$logicalPath] = $file->getPathname();
}
}
return $paths;
}
/**
* @internal
*/
public function allDirectories(): array
{
return $this->getDirectories();
}
private function getDirectories(): array
{
$filesystem = new Filesystem();
if (null !== $this->absolutePaths) {
return $this->absolutePaths;
}
$this->absolutePaths = [];
foreach ($this->paths as $path => $namespace) {
if ($filesystem->isAbsolutePath($path)) {
if (!file_exists($path) && $this->debug) {
throw new \InvalidArgumentException(sprintf('The asset mapper directory "%s" does not exist.', $path));
}
$this->absolutePaths[realpath($path)] = $namespace;
continue;
}
if (file_exists($this->projectRootDir.'/'.$path)) {
$this->absolutePaths[realpath($this->projectRootDir.'/'.$path)] = $namespace;
continue;
}
if ($this->debug) {
throw new \InvalidArgumentException(sprintf('The asset mapper directory "%s" does not exist.', $path));
}
}
return $this->absolutePaths;
}
/**
* Normalize slashes to / for logical paths.
*/
private function normalizeLogicalPath(string $logicalPath): string
{
return ltrim(str_replace('\\', '/', $logicalPath), '/\\');
}
private function isExcluded(string $filesystemPath): bool
{
// normalize Windows slashes and remove trailing slashes
$filesystemPath = rtrim(str_replace('\\', '/', $filesystemPath), '/');
foreach ($this->excludedPathPatterns as $pattern) {
if (preg_match($pattern, $filesystemPath)) {
return true;
}
}
if ($this->excludeDotFiles && str_starts_with(basename($filesystemPath), '.')) {
return true;
}
return false;
}
}