diff --git a/src/Persistence/Mapping/Driver/MappingDriverChain.php b/src/Persistence/Mapping/Driver/MappingDriverChain.php index 8563dd23..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, '\\'); + } } diff --git a/tests/Persistence/Mapping/DriverChainTest.php b/tests/Persistence/Mapping/DriverChainTest.php index 3199bc74..dcd60316 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()) @@ -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