From c6017031c1382084ead2098c54abfdcb4e539df5 Mon Sep 17 00:00:00 2001 From: Tom Kaminski Date: Thu, 14 Dec 2023 17:07:06 -0600 Subject: [PATCH 1/5] Update DriverChainTest to trigger bugs --- tests/Persistence/Mapping/DriverChainTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Persistence/Mapping/DriverChainTest.php b/tests/Persistence/Mapping/DriverChainTest.php index 3199bc74..11cf5973 100644 --- a/tests/Persistence/Mapping/DriverChainTest.php +++ b/tests/Persistence/Mapping/DriverChainTest.php @@ -37,7 +37,7 @@ public function testDelegateToMatchingNamespaceDriver(): void ->with(self::equalTo($className)) ->willReturn(true); - $chain->addDriver($driver1, 'Doctrine\Tests\Models\Company'); + $chain->addDriver($driver1, 'Doctrine\Tests\Persistence\Map'); $chain->addDriver($driver2, 'Doctrine\Tests\Persistence\Mapping'); $chain->loadMetadataForClass($className, $classMetadata); @@ -63,7 +63,7 @@ public function testGatherAllClassNames(): void $driver1 = $this->createMock(MappingDriver::class); $driver1->expects(self::once()) ->method('getAllClassNames') - ->will(self::returnValue(['Doctrine\Tests\Models\Company\Foo'])); + ->will(self::returnValue(['Doctrine\Tests\Models\Company\Foo','Doctrine\Tests\Models\Company2\Foo'])); $driver2 = $this->createMock(MappingDriver::class); $driver2->expects(self::once()) From 9d3f15a298e150755212753d4a56e698c2c58693 Mon Sep 17 00:00:00 2001 From: Tom Kaminski Date: Thu, 14 Dec 2023 17:07:54 -0600 Subject: [PATCH 2/5] Fix namespace check in MappingDriverChain --- src/Persistence/Mapping/Driver/MappingDriverChain.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Persistence/Mapping/Driver/MappingDriverChain.php b/src/Persistence/Mapping/Driver/MappingDriverChain.php index 8563dd23..8b319e08 100644 --- a/src/Persistence/Mapping/Driver/MappingDriverChain.php +++ b/src/Persistence/Mapping/Driver/MappingDriverChain.php @@ -73,7 +73,7 @@ public function getDrivers() public function loadMetadataForClass(string $className, ClassMetadata $metadata) { foreach ($this->drivers as $namespace => $driver) { - if (strpos($className, $namespace) === 0) { + if (strpos($className, $namespace . '\\') === 0) { $driver->loadMetadataForClass($className, $metadata); return; @@ -105,7 +105,7 @@ public function getAllClassNames() } foreach ($driverClasses[$oid] as $className) { - if (strpos($className, $namespace) !== 0) { + if (strpos($className, $namespace . '\\') !== 0) { continue; } @@ -128,7 +128,7 @@ public function getAllClassNames() public function isTransient(string $className) { foreach ($this->drivers as $namespace => $driver) { - if (strpos($className, $namespace) === 0) { + if (strpos($className, $namespace . '\\') === 0) { return $driver->isTransient($className); } } From 06b12f1f8c64a53e4014af4d9e8e2e1c95d17b6e Mon Sep 17 00:00:00 2001 From: Tom Kaminski Date: Fri, 15 Dec 2023 09:51:41 -0600 Subject: [PATCH 3/5] Fix whitespace --- tests/Persistence/Mapping/DriverChainTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Persistence/Mapping/DriverChainTest.php b/tests/Persistence/Mapping/DriverChainTest.php index 11cf5973..c752b1fb 100644 --- a/tests/Persistence/Mapping/DriverChainTest.php +++ b/tests/Persistence/Mapping/DriverChainTest.php @@ -63,7 +63,7 @@ public function testGatherAllClassNames(): void $driver1 = $this->createMock(MappingDriver::class); $driver1->expects(self::once()) ->method('getAllClassNames') - ->will(self::returnValue(['Doctrine\Tests\Models\Company\Foo','Doctrine\Tests\Models\Company2\Foo'])); + ->will(self::returnValue(['Doctrine\Tests\Models\Company\Foo', 'Doctrine\Tests\Models\Company2\Foo'])); $driver2 = $this->createMock(MappingDriver::class); $driver2->expects(self::once()) From 2f8e14fa11cd1e5bfe49640400bedb9e628a8bff Mon Sep 17 00:00:00 2001 From: Tom Kaminski Date: Tue, 19 Dec 2023 11:08:14 -0600 Subject: [PATCH 4/5] Refactor namespace check into a separate function --- .../Mapping/Driver/MappingDriverChain.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Persistence/Mapping/Driver/MappingDriverChain.php b/src/Persistence/Mapping/Driver/MappingDriverChain.php index 8b319e08..ff247b3e 100644 --- a/src/Persistence/Mapping/Driver/MappingDriverChain.php +++ b/src/Persistence/Mapping/Driver/MappingDriverChain.php @@ -8,8 +8,9 @@ use Doctrine\Persistence\Mapping\MappingException; use function array_keys; +use function dirname; use function spl_object_hash; -use function strpos; +use function trim; /** * The DriverChain allows you to add multiple other mapping drivers for @@ -73,7 +74,7 @@ public function getDrivers() public function loadMetadataForClass(string $className, ClassMetadata $metadata) { foreach ($this->drivers as $namespace => $driver) { - if (strpos($className, $namespace . '\\') === 0) { + if (self::isMatchingNamespace($className, $namespace)) { $driver->loadMetadataForClass($className, $metadata); return; @@ -105,7 +106,7 @@ public function getAllClassNames() } foreach ($driverClasses[$oid] as $className) { - if (strpos($className, $namespace . '\\') !== 0) { + if (! self::isMatchingNamespace($className, $namespace)) { continue; } @@ -128,7 +129,7 @@ public function getAllClassNames() public function isTransient(string $className) { foreach ($this->drivers as $namespace => $driver) { - if (strpos($className, $namespace . '\\') === 0) { + if (self::isMatchingNamespace($className, $namespace)) { return $driver->isTransient($className); } } @@ -139,4 +140,12 @@ public function isTransient(string $className) return true; } + + /** + * Checks if the given class name matches the namespace. + */ + protected static function isMatchingNamespace(string $className, string $namespace): bool + { + return dirname($className) === trim($namespace, '\\'); + } } From 16329d619e13f906ae27a88958a69bdd8e95cb31 Mon Sep 17 00:00:00 2001 From: Tom Kaminski Date: Tue, 19 Dec 2023 11:08:31 -0600 Subject: [PATCH 5/5] Add unit test for namespace check --- tests/Persistence/Mapping/DriverChainTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Persistence/Mapping/DriverChainTest.php b/tests/Persistence/Mapping/DriverChainTest.php index c752b1fb..dcd60316 100644 --- a/tests/Persistence/Mapping/DriverChainTest.php +++ b/tests/Persistence/Mapping/DriverChainTest.php @@ -147,6 +147,24 @@ public function testDefaultDriverGetAllClassNames(): void self::assertSame(['Doctrine\Tests\Models\Company\Foo', 'Other\Class'], $classNames); } + + public function testMatchingNamespace(): void + { + // Expose the protected method as public + $mdc = new class extends MappingDriverChain { + public static function isMatchingNamespace(string $className, string $namespace): bool + { + return parent::isMatchingNamespace($className, $namespace); + } + }; + + $className = DriverChainEntity::class; + + self::assertTrue($mdc::isMatchingNamespace($className, 'Doctrine\Tests\Persistence\Mapping\\')); + self::assertTrue($mdc::isMatchingNamespace($className, 'Doctrine\Tests\Persistence\Mapping')); + self::assertFalse($mdc::isMatchingNamespace($className, 'Doctrine\Tests\Persistence\Map')); + self::assertFalse($mdc::isMatchingNamespace($className, 'Doctrine\Tests\Persistence')); + } } class DriverChainEntity