From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Mapping/Driver/ColocatedMappingDriver.php | 212 +++++++++++++++++ .../Mapping/Driver/DefaultFileLocator.php | 175 ++++++++++++++ .../src/Persistence/Mapping/Driver/FileDriver.php | 213 +++++++++++++++++ .../src/Persistence/Mapping/Driver/FileLocator.php | 52 ++++ .../Persistence/Mapping/Driver/MappingDriver.php | 43 ++++ .../Mapping/Driver/MappingDriverChain.php | 142 +++++++++++ .../src/Persistence/Mapping/Driver/PHPDriver.php | 49 ++++ .../Persistence/Mapping/Driver/StaticPHPDriver.php | 132 ++++++++++ .../Mapping/Driver/SymfonyFileLocator.php | 265 +++++++++++++++++++++ 9 files changed, 1283 insertions(+) create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php (limited to 'vendor/doctrine/persistence/src/Persistence/Mapping/Driver') diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php new file mode 100644 index 0000000..e85ba70 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php @@ -0,0 +1,212 @@ + + */ + protected $paths = []; + + /** + * The paths excluded from path where to look for mapping files. + * + * @var array + */ + protected $excludePaths = []; + + /** + * The file extension of mapping documents. + * + * @var string + */ + protected $fileExtension = '.php'; + + /** + * Cache for getAllClassNames(). + * + * @var array|null + * @psalm-var list|null + */ + protected $classNames; + + /** + * Appends lookup paths to metadata driver. + * + * @param array $paths + * + * @return void + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * Retrieves the defined metadata lookup paths. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Append exclude lookup paths to metadata driver. + * + * @param string[] $paths + * + * @return void + */ + public function addExcludePaths(array $paths) + { + $this->excludePaths = array_unique(array_merge($this->excludePaths, $paths)); + } + + /** + * Retrieve the defined metadata lookup exclude paths. + * + * @return array + */ + public function getExcludePaths() + { + return $this->excludePaths; + } + + /** + * Gets the file extension used to look for mapping files under. + * + * @return string + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Sets the file extension used to look for mapping files under. + * + * @return void + */ + public function setFileExtension(string $fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + * + * Returns whether the class with the specified name is transient. Only non-transient + * classes, that is entities and mapped superclasses, should have their metadata loaded. + * + * @psalm-param class-string $className + * + * @return bool + */ + abstract public function isTransient(string $className); + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return string[] The names of all mapped classes known to this driver. + * @psalm-return list + */ + public function getAllClassNames() + { + if ($this->classNames !== null) { + return $this->classNames; + } + + if ($this->paths === []) { + throw MappingException::pathRequiredForDriver(static::class); + } + + $classes = []; + $includedFiles = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RegexIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::LEAVES_ONLY + ), + '/^.+' . preg_quote($this->fileExtension) . '$/i', + RecursiveRegexIterator::GET_MATCH + ); + + foreach ($iterator as $file) { + $sourceFile = $file[0]; + + if (preg_match('(^phar:)i', $sourceFile) === 0) { + $sourceFile = realpath($sourceFile); + } + + foreach ($this->excludePaths as $excludePath) { + $realExcludePath = realpath($excludePath); + assert($realExcludePath !== false); + $exclude = str_replace('\\', '/', $realExcludePath); + $current = str_replace('\\', '/', $sourceFile); + + if (strpos($current, $exclude) !== false) { + continue 2; + } + } + + require_once $sourceFile; + + $includedFiles[] = $sourceFile; + } + } + + $declared = get_declared_classes(); + + foreach ($declared as $className) { + $rc = new ReflectionClass($className); + + $sourceFile = $rc->getFileName(); + + if (! in_array($sourceFile, $includedFiles, true) || $this->isTransient($className)) { + continue; + } + + $classes[] = $className; + } + + $this->classNames = $classes; + + return $classes; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php new file mode 100644 index 0000000..9b00e74 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php @@ -0,0 +1,175 @@ + + */ + protected $paths = []; + + /** + * The file extension of mapping documents. + * + * @var string|null + */ + protected $fileExtension; + + /** + * Initializes a new FileDriver that looks in the given path(s) for mapping + * documents and operates in the specified operating mode. + * + * @param string|array $paths One or multiple paths where mapping documents + * can be found. + * @param string|null $fileExtension The file extension of mapping documents, + * usually prefixed with a dot. + */ + public function __construct($paths, ?string $fileExtension = null) + { + $this->addPaths((array) $paths); + $this->fileExtension = $fileExtension; + } + + /** + * Appends lookup paths to metadata driver. + * + * @param array $paths + * + * @return void + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * Retrieves the defined metadata lookup paths. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Gets the file extension used to look for mapping files under. + * + * @return string|null + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Sets the file extension used to look for mapping files under. + * + * @param string|null $fileExtension The file extension to set. + * + * @return void + */ + public function setFileExtension(?string $fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + */ + public function findMappingFile(string $className) + { + $fileName = str_replace('\\', '.', $className) . $this->fileExtension; + + // Check whether file exists + foreach ($this->paths as $path) { + if (is_file($path . DIRECTORY_SEPARATOR . $fileName)) { + return $path . DIRECTORY_SEPARATOR . $fileName; + } + } + + throw MappingException::mappingFileNotFound($className, $fileName); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames(string $globalBasename) + { + if ($this->paths === []) { + return []; + } + + $classes = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + $fileName = $file->getBasename($this->fileExtension); + + if ($fileName === $file->getBasename() || $fileName === $globalBasename) { + continue; + } + + // NOTE: All files found here means classes are not transient! + + assert(is_string($fileName)); + /** @psalm-var class-string */ + $class = str_replace('.', '\\', $fileName); + $classes[] = $class; + } + } + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function fileExists(string $className) + { + $fileName = str_replace('\\', '.', $className) . $this->fileExtension; + + // Check whether file exists + foreach ($this->paths as $path) { + if (is_file($path . DIRECTORY_SEPARATOR . $fileName)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php new file mode 100644 index 0000000..c116233 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php @@ -0,0 +1,213 @@ +|null + */ + protected $classCache; + + /** @var string */ + protected $globalBasename = ''; + + /** + * Initializes a new FileDriver that looks in the given path(s) for mapping + * documents and operates in the specified operating mode. + * + * @param string|array|FileLocator $locator A FileLocator or one/multiple paths + * where mapping documents can be found. + */ + public function __construct($locator, ?string $fileExtension = null) + { + if ($locator instanceof FileLocator) { + $this->locator = $locator; + } else { + $this->locator = new DefaultFileLocator((array) $locator, $fileExtension); + } + } + + /** + * Sets the global basename. + * + * @return void + */ + public function setGlobalBasename(string $file) + { + $this->globalBasename = $file; + } + + /** + * Retrieves the global basename. + * + * @return string|null + */ + public function getGlobalBasename() + { + return $this->globalBasename; + } + + /** + * Gets the element of schema meta data for the class from the mapping file. + * This will lazily load the mapping file if it is not loaded yet. + * + * @psalm-param class-string $className + * + * @return T The element of schema meta data. + * + * @throws MappingException + */ + public function getElement(string $className) + { + if ($this->classCache === null) { + $this->initialize(); + } + + if (isset($this->classCache[$className])) { + return $this->classCache[$className]; + } + + $result = $this->loadMappingFile($this->locator->findMappingFile($className)); + + if (! isset($result[$className])) { + throw MappingException::invalidMappingFile( + $className, + str_replace('\\', '.', $className) . $this->locator->getFileExtension() + ); + } + + $this->classCache[$className] = $result[$className]; + + return $result[$className]; + } + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + if ($this->classCache === null) { + $this->initialize(); + } + + if (isset($this->classCache[$className])) { + return false; + } + + return ! $this->locator->fileExists($className); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames() + { + if ($this->classCache === null) { + $this->initialize(); + } + + if ($this->classCache === []) { + return $this->locator->getAllClassNames($this->globalBasename); + } + + /** @psalm-var array> $classCache */ + $classCache = $this->classCache; + + /** @var list $keys */ + $keys = array_keys($classCache); + + return array_values(array_unique(array_merge( + $keys, + $this->locator->getAllClassNames($this->globalBasename) + ))); + } + + /** + * Loads a mapping file with the given name and returns a map + * from class/entity names to their corresponding file driver elements. + * + * @param string $file The mapping file to load. + * + * @return mixed[] + * @psalm-return array + */ + abstract protected function loadMappingFile(string $file); + + /** + * Initializes the class cache from all the global files. + * + * Using this feature adds a substantial performance hit to file drivers as + * more metadata has to be loaded into memory than might actually be + * necessary. This may not be relevant to scenarios where caching of + * metadata is in place, however hits very hard in scenarios where no + * caching is used. + * + * @return void + */ + protected function initialize() + { + $this->classCache = []; + if ($this->globalBasename === '') { + return; + } + + foreach ($this->locator->getPaths() as $path) { + $file = $path . '/' . $this->globalBasename . $this->locator->getFileExtension(); + if (! is_file($file)) { + continue; + } + + $this->classCache = array_merge( + $this->classCache, + $this->loadMappingFile($file) + ); + } + } + + /** + * Retrieves the locator used to discover mapping files by className. + * + * @return FileLocator + */ + public function getLocator() + { + return $this->locator; + } + + /** + * Sets the locator used to discover mapping files by className. + * + * @return void + */ + public function setLocator(FileLocator $locator) + { + $this->locator = $locator; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php new file mode 100644 index 0000000..e57d539 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php @@ -0,0 +1,52 @@ + + * @psalm-return list + */ + public function getAllClassNames(string $globalBasename); + + /** + * Checks if a file can be found for this class name. + * + * @return bool + */ + public function fileExists(string $className); + + /** + * Gets all the paths that this file locator looks for mapping files. + * + * @return array + */ + public function getPaths(); + + /** + * Gets the file extension that mapping files are suffixed with. + * + * @return string|null + */ + public function getFileExtension(); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php new file mode 100644 index 0000000..9b6f0c8 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php @@ -0,0 +1,43 @@ + $className + * @psalm-param ClassMetadata $metadata + * + * @return void + * + * @template T of object + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata); + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return array The names of all mapped classes known to this driver. + * @psalm-return list + */ + public function getAllClassNames(); + + /** + * Returns whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped as an Entity or a MappedSuperclass. + * + * @psalm-param class-string $className + * + * @return bool + */ + public function isTransient(string $className); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php new file mode 100644 index 0000000..8563dd2 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php @@ -0,0 +1,142 @@ + */ + private $drivers = []; + + /** + * Gets the default driver. + * + * @return MappingDriver|null + */ + public function getDefaultDriver() + { + return $this->defaultDriver; + } + + /** + * Set the default driver. + * + * @return void + */ + public function setDefaultDriver(MappingDriver $driver) + { + $this->defaultDriver = $driver; + } + + /** + * Adds a nested driver. + * + * @return void + */ + public function addDriver(MappingDriver $nestedDriver, string $namespace) + { + $this->drivers[$namespace] = $nestedDriver; + } + + /** + * Gets the array of nested drivers. + * + * @return array $drivers + */ + public function getDrivers() + { + return $this->drivers; + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata) + { + foreach ($this->drivers as $namespace => $driver) { + if (strpos($className, $namespace) === 0) { + $driver->loadMetadataForClass($className, $metadata); + + return; + } + } + + if ($this->defaultDriver !== null) { + $this->defaultDriver->loadMetadataForClass($className, $metadata); + + return; + } + + throw MappingException::classNotFoundInNamespaces($className, array_keys($this->drivers)); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames() + { + $classNames = []; + $driverClasses = []; + + foreach ($this->drivers as $namespace => $driver) { + $oid = spl_object_hash($driver); + + if (! isset($driverClasses[$oid])) { + $driverClasses[$oid] = $driver->getAllClassNames(); + } + + foreach ($driverClasses[$oid] as $className) { + if (strpos($className, $namespace) !== 0) { + continue; + } + + $classNames[$className] = true; + } + } + + if ($this->defaultDriver !== null) { + foreach ($this->defaultDriver->getAllClassNames() as $className) { + $classNames[$className] = true; + } + } + + return array_keys($classNames); + } + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + foreach ($this->drivers as $namespace => $driver) { + if (strpos($className, $namespace) === 0) { + return $driver->isTransient($className); + } + } + + if ($this->defaultDriver !== null) { + return $this->defaultDriver->isTransient($className); + } + + return true; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php new file mode 100644 index 0000000..1c1ab9c --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php @@ -0,0 +1,49 @@ +> + */ +class PHPDriver extends FileDriver +{ + /** + * @var ClassMetadata + * @psalm-var ClassMetadata + */ + protected $metadata; + + /** @param string|array|FileLocator $locator */ + public function __construct($locator) + { + parent::__construct($locator, '.php'); + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata) + { + $this->metadata = $metadata; + + $this->loadMappingFile($this->locator->findMappingFile($className)); + } + + /** + * {@inheritDoc} + */ + protected function loadMappingFile(string $file) + { + $metadata = $this->metadata; + include $file; + + return [$metadata->getName() => $metadata]; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php new file mode 100644 index 0000000..bbcff75 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php @@ -0,0 +1,132 @@ + + */ + private $paths = []; + + /** + * Map of all class names. + * + * @var array + * @psalm-var list + */ + private $classNames; + + /** @param array|string $paths */ + public function __construct($paths) + { + $this->addPaths((array) $paths); + } + + /** + * @param array $paths + * + * @return void + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata) + { + $className::loadMetadata($metadata); + } + + /** + * {@inheritDoc} + * + * @todo Same code exists in ColocatedMappingDriver, should we re-use it + * somehow or not worry about it? + */ + public function getAllClassNames() + { + if ($this->classNames !== null) { + return $this->classNames; + } + + if ($this->paths === []) { + throw MappingException::pathRequiredForDriver(static::class); + } + + $classes = []; + $includedFiles = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + if ($file->getBasename('.php') === $file->getBasename()) { + continue; + } + + $sourceFile = realpath($file->getPathName()); + require_once $sourceFile; + $includedFiles[] = $sourceFile; + } + } + + $declared = get_declared_classes(); + + foreach ($declared as $className) { + $rc = new ReflectionClass($className); + + $sourceFile = $rc->getFileName(); + + if (! in_array($sourceFile, $includedFiles, true) || $this->isTransient($className)) { + continue; + } + + $classes[] = $className; + } + + $this->classNames = $classes; + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + return ! method_exists($className, 'loadMetadata'); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php new file mode 100644 index 0000000..428d5fb --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php @@ -0,0 +1,265 @@ + + */ + protected $paths = []; + + /** + * A map of mapping directory path to namespace prefix used to expand class shortnames. + * + * @var array + */ + protected $prefixes = []; + + /** + * File extension that is searched for. + * + * @var string|null + */ + protected $fileExtension; + + /** + * Represents PHP namespace delimiters when looking for files + * + * @var string + */ + private $nsSeparator; + + /** + * @param array $prefixes + * @param string $nsSeparator String which would be used when converting FQCN + * to filename and vice versa. Should not be empty + */ + public function __construct( + array $prefixes, + string $fileExtension = '', + string $nsSeparator = '.' + ) { + $this->addNamespacePrefixes($prefixes); + $this->fileExtension = $fileExtension; + + if ($nsSeparator === '') { + throw new InvalidArgumentException('Namespace separator should not be empty'); + } + + $this->nsSeparator = $nsSeparator; + } + + /** + * Adds Namespace Prefixes. + * + * @param array $prefixes + * + * @return void + */ + public function addNamespacePrefixes(array $prefixes) + { + $this->prefixes = array_merge($this->prefixes, $prefixes); + $this->paths = array_merge($this->paths, array_keys($prefixes)); + } + + /** + * Gets Namespace Prefixes. + * + * @return string[] + */ + public function getNamespacePrefixes() + { + return $this->prefixes; + } + + /** + * {@inheritDoc} + */ + public function getPaths() + { + return $this->paths; + } + + /** + * {@inheritDoc} + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Sets the file extension used to look for mapping files under. + * + * @param string $fileExtension The file extension to set. + * + * @return void + */ + public function setFileExtension(string $fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + */ + public function fileExists(string $className) + { + $defaultFileName = str_replace('\\', $this->nsSeparator, $className) . $this->fileExtension; + foreach ($this->paths as $path) { + if (! isset($this->prefixes[$path])) { + // global namespace class + if (is_file($path . DIRECTORY_SEPARATOR . $defaultFileName)) { + return true; + } + + continue; + } + + $prefix = $this->prefixes[$path]; + + if (strpos($className, $prefix . '\\') !== 0) { + continue; + } + + $filename = $path . '/' . strtr(substr($className, strlen($prefix) + 1), '\\', $this->nsSeparator) . $this->fileExtension; + + if (is_file($filename)) { + return true; + } + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames(?string $globalBasename = null) + { + if ($this->paths === []) { + return []; + } + + $classes = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + $fileName = $file->getBasename($this->fileExtension); + + if ($fileName === $file->getBasename() || $fileName === $globalBasename) { + continue; + } + + // NOTE: All files found here means classes are not transient! + if (isset($this->prefixes[$path])) { + // Calculate namespace suffix for given prefix as a relative path from basepath to file path + $nsSuffix = strtr( + substr($this->realpath($file->getPath()), strlen($this->realpath($path))), + $this->nsSeparator, + '\\' + ); + + /** @psalm-var class-string */ + $class = $this->prefixes[$path] . str_replace(DIRECTORY_SEPARATOR, '\\', $nsSuffix) . '\\' . str_replace($this->nsSeparator, '\\', $fileName); + } else { + /** @psalm-var class-string */ + $class = str_replace($this->nsSeparator, '\\', $fileName); + } + + $classes[] = $class; + } + } + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function findMappingFile(string $className) + { + $defaultFileName = str_replace('\\', $this->nsSeparator, $className) . $this->fileExtension; + foreach ($this->paths as $path) { + if (! isset($this->prefixes[$path])) { + if (is_file($path . DIRECTORY_SEPARATOR . $defaultFileName)) { + return $path . DIRECTORY_SEPARATOR . $defaultFileName; + } + + continue; + } + + $prefix = $this->prefixes[$path]; + + if (strpos($className, $prefix . '\\') !== 0) { + continue; + } + + $filename = $path . '/' . strtr(substr($className, strlen($prefix) + 1), '\\', $this->nsSeparator) . $this->fileExtension; + if (is_file($filename)) { + return $filename; + } + } + + $pos = strrpos($className, '\\'); + assert(is_int($pos)); + + throw MappingException::mappingFileNotFound( + $className, + substr($className, $pos + 1) . $this->fileExtension + ); + } + + private function realpath(string $path): string + { + $realpath = realpath($path); + + if ($realpath === false) { + throw new RuntimeException(sprintf('Could not get realpath for %s', $path)); + } + + return $realpath; + } +} -- cgit v1.2.3