From 7be9793768491b9de883144339e69b0760c8a426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 6 Dec 2025 22:38:20 +0100 Subject: [PATCH 1/3] Support ClassLocator in StaticPHPDriver Use the ColocatedMappingDriver that provides this feature --- src/Mapping/Driver/ColocatedMappingDriver.php | 2 +- src/Mapping/Driver/StaticPHPDriver.php | 99 ++----------------- tests/Mapping/StaticPHPDriverTest.php | 9 ++ 3 files changed, 18 insertions(+), 92 deletions(-) diff --git a/src/Mapping/Driver/ColocatedMappingDriver.php b/src/Mapping/Driver/ColocatedMappingDriver.php index 745c1861..af1eb724 100644 --- a/src/Mapping/Driver/ColocatedMappingDriver.php +++ b/src/Mapping/Driver/ColocatedMappingDriver.php @@ -50,7 +50,7 @@ trait ColocatedMappingDriver */ public function addPaths(array $paths): void { - $this->paths = array_unique(array_merge($this->paths, $paths)); + $this->paths = array_unique([...$this->paths, ...$paths]); } /** diff --git a/src/Mapping/Driver/StaticPHPDriver.php b/src/Mapping/Driver/StaticPHPDriver.php index 4bf1ee45..7e7b508c 100644 --- a/src/Mapping/Driver/StaticPHPDriver.php +++ b/src/Mapping/Driver/StaticPHPDriver.php @@ -5,17 +5,8 @@ namespace Doctrine\Persistence\Mapping\Driver; use Doctrine\Persistence\Mapping\ClassMetadata; -use Doctrine\Persistence\Mapping\MappingException; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use ReflectionClass; -use function array_unique; -use function get_declared_classes; -use function in_array; -use function is_dir; use function method_exists; -use function realpath; /** * The StaticPHPDriver calls a static loadMetadata() method on your entity @@ -23,31 +14,16 @@ */ class StaticPHPDriver implements MappingDriver { - /** - * Paths of entity directories. - * - * @var array - */ - private array $paths = []; + use ColocatedMappingDriver; - /** - * Map of all class names. - * - * @var array - * @phpstan-var list - */ - private array|null $classNames = null; - - /** @param array|string $paths */ - public function __construct(array|string $paths) - { - $this->addPaths((array) $paths); - } - - /** @param array $paths */ - public function addPaths(array $paths): void + /** @param array|string|ClassLocator $paths */ + public function __construct(array|string|ClassLocator $paths) { - $this->paths = array_unique([...$this->paths, ...$paths]); + if ($paths instanceof ClassLocator) { + $this->classLocator = $paths; + } else { + $this->addPaths((array) $paths); + } } public function loadMetadataForClass(string $className, ClassMetadata $metadata): void @@ -55,65 +31,6 @@ 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(): array - { - 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; - } - public function isTransient(string $className): bool { return ! method_exists($className, 'loadMetadata'); diff --git a/tests/Mapping/StaticPHPDriverTest.php b/tests/Mapping/StaticPHPDriverTest.php index cad41e97..fee805e3 100644 --- a/tests/Mapping/StaticPHPDriverTest.php +++ b/tests/Mapping/StaticPHPDriverTest.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\Persistence\Mapping; use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\Driver\ClassNames; use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver; use PHPUnit\Framework\TestCase; @@ -26,6 +27,14 @@ public function testGetAllClassNames(): void self::assertContains(TestEntity::class, $classNames); } + + public function testGetAllClassesNamesWithClassLocator(): void + { + $driver = new StaticPHPDriver(new ClassNames([TestEntity::class])); + $classNames = $driver->getAllClassNames(); + + self::assertSame([TestEntity::class], $classNames); + } } class TestEntity From 8f22e008c1a237bee0894e62efe85d9aeb822145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 6 Dec 2025 23:02:09 +0100 Subject: [PATCH 2/3] Fix scope of scanned PHP files to not load Doctrine.Tests.Persistence.Mapping.PHPTestEntityAssert.php that asserts $metadata variable existence --- tests/Mapping/StaticPHPDriverTest.php | 22 +++++++--------------- tests/Mapping/_files/colocated/Entity.php | 7 +++++++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/Mapping/StaticPHPDriverTest.php b/tests/Mapping/StaticPHPDriverTest.php index fee805e3..baef0083 100644 --- a/tests/Mapping/StaticPHPDriverTest.php +++ b/tests/Mapping/StaticPHPDriverTest.php @@ -7,6 +7,7 @@ use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\Mapping\Driver\ClassNames; use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver; +use Doctrine\Tests\Persistence\Mapping\_files\colocated\Entity; use PHPUnit\Framework\TestCase; class StaticPHPDriverTest extends TestCase @@ -16,32 +17,23 @@ public function testLoadMetadata(): void $metadata = $this->createMock(ClassMetadata::class); $metadata->expects(self::once())->method('getFieldNames'); - $driver = new StaticPHPDriver([__DIR__]); - $driver->loadMetadataForClass(TestEntity::class, $metadata); + $driver = new StaticPHPDriver([]); + $driver->loadMetadataForClass(Entity::class, $metadata); } public function testGetAllClassNames(): void { - $driver = new StaticPHPDriver([__DIR__]); + $driver = new StaticPHPDriver([__DIR__ . '/_files/colocated/']); $classNames = $driver->getAllClassNames(); - self::assertContains(TestEntity::class, $classNames); + self::assertContains(Entity::class, $classNames); } public function testGetAllClassesNamesWithClassLocator(): void { - $driver = new StaticPHPDriver(new ClassNames([TestEntity::class])); + $driver = new StaticPHPDriver(new ClassNames([Entity::class])); $classNames = $driver->getAllClassNames(); - self::assertSame([TestEntity::class], $classNames); - } -} - -class TestEntity -{ - /** @phpstan-param ClassMetadata $metadata */ - public static function loadMetadata(ClassMetadata $metadata): void - { - $metadata->getFieldNames(); + self::assertSame([Entity::class], $classNames); } } diff --git a/tests/Mapping/_files/colocated/Entity.php b/tests/Mapping/_files/colocated/Entity.php index 0ce67cbb..b10ba07e 100644 --- a/tests/Mapping/_files/colocated/Entity.php +++ b/tests/Mapping/_files/colocated/Entity.php @@ -4,10 +4,17 @@ namespace Doctrine\Tests\Persistence\Mapping\_files\colocated; +use Doctrine\Persistence\Mapping\ClassMetadata; + /** * The driver should include this file and return its class name * from {@see \Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver::getAllClassNames()} method. */ class Entity { + /** @phpstan-param ClassMetadata $metadata */ + public static function loadMetadata(ClassMetadata $metadata): void + { + $metadata->getFieldNames(); + } } From 3c9575ea9b659f2bd5d941375a9d9e0269f38ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sat, 6 Dec 2025 23:19:42 +0100 Subject: [PATCH 3/3] Relax PHPStan type for list of directories as we don't use the key --- phpstan-baseline.neon | 12 ------------ src/Mapping/Driver/FileClassLocator.php | 6 +++--- tests/Mapping/ColocatedMappingDriverTest.php | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6e540218..f059c422 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -30,18 +30,6 @@ parameters: count: 1 path: tests/Mapping/ClassMetadataFactoryTest.php - - - message: '#^Parameter \#1 \$directories of static method Doctrine\\Persistence\\Mapping\\Driver\\FileClassLocator\:\:createFromDirectories\(\) expects list\, non\-empty\-array\ given\.$#' - identifier: argument.type - count: 1 - path: tests/Mapping/ColocatedMappingDriverTest.php - - - - message: '#^Parameter \#2 \$excludedDirectories of static method Doctrine\\Persistence\\Mapping\\Driver\\FileClassLocator\:\:createFromDirectories\(\) expects list\, array\ given\.$#' - identifier: argument.type - count: 1 - path: tests/Mapping/ColocatedMappingDriverTest.php - - message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertSame\(\) with array\{''Doctrine\\\\Tests…'', ''Doctrine\\\\Tests\\\\ORM…'', ''Doctrine\\\\Tests\\\\ORM…''\} and list\ will always evaluate to false\.$#' identifier: staticMethod.impossibleType diff --git a/src/Mapping/Driver/FileClassLocator.php b/src/Mapping/Driver/FileClassLocator.php index dae77929..49dd36e4 100644 --- a/src/Mapping/Driver/FileClassLocator.php +++ b/src/Mapping/Driver/FileClassLocator.php @@ -81,9 +81,9 @@ public function getClassNames(): array /** * Creates a FileClassLocator from an array of directories. * - * @param list $directories - * @param list $excludedDirectories Directories to exclude from the search. - * @param string $fileExtension The file extension to look for (default is '.php'). + * @param string[] $directories + * @param string[] $excludedDirectories Directories to exclude from the search. + * @param string $fileExtension The file extension to look for (default is '.php'). * * @throws MappingException if any of the directories are not valid. */ diff --git a/tests/Mapping/ColocatedMappingDriverTest.php b/tests/Mapping/ColocatedMappingDriverTest.php index 7b9eebe4..5fc52ceb 100644 --- a/tests/Mapping/ColocatedMappingDriverTest.php +++ b/tests/Mapping/ColocatedMappingDriverTest.php @@ -130,7 +130,7 @@ public function __construct(array|ClassLocator $paths) if ($paths instanceof ClassLocator) { $this->classLocator = $paths; } else { - $this->paths = $paths; + $this->addPaths($paths); } }