diff --git a/composer.json b/composer.json
index d83f641aff1..0ec779faf8f 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,7 @@
"doctrine/inflector": "^1.4 || ^2.0",
"doctrine/instantiator": "^1.3 || ^2",
"doctrine/lexer": "^3",
- "doctrine/persistence": "^3.3.1 || ^4",
+ "doctrine/persistence": "^4",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/var-exporter": "^6.3.9 || ^7.0"
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index b14bbc6c1d8..4fde4cbf5e5 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -48,8 +48,6 @@
- src/Mapping/Driver/LoadMappingFileImplementation.php
- src/Mapping/GetReflectionClassImplementation.php
tests/*
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index bf151dcafba..ec90fc88cbe 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -304,9 +304,6 @@
declaredField]]]>
-
-
-
@@ -323,6 +320,7 @@
+
@@ -442,14 +440,6 @@
name)]]>
-
-
-
-
-
-
-
-
@@ -502,14 +492,6 @@
-
-
-
-
-
-
-
-
diff --git a/psalm.xml b/psalm.xml
index 533016ce379..ddb88d51c20 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -41,7 +41,6 @@
-
diff --git a/src/Mapping/ClassMetadata.php b/src/Mapping/ClassMetadata.php
index fc79b2195d4..6ec95bf58ee 100644
--- a/src/Mapping/ClassMetadata.php
+++ b/src/Mapping/ClassMetadata.php
@@ -76,8 +76,6 @@
*/
class ClassMetadata implements PersistenceClassMetadata, Stringable
{
- use GetReflectionClassImplementation;
-
/* The inheritance mapping types */
/**
* NONE means the class does not participate in an inheritance hierarchy
@@ -519,9 +517,9 @@ class ClassMetadata implements PersistenceClassMetadata, Stringable
/**
* The ReflectionClass instance of the mapped class.
*
- * @var ReflectionClass|null
+ * @var ReflectionClass
*/
- public ReflectionClass|null $reflClass = null;
+ public ReflectionClass $reflClass;
/**
* Is this entity marked as "read-only"?
@@ -934,6 +932,11 @@ public function validateLifecycleCallbacks(ReflectionService $reflService): void
}
}
+ public function getReflectionClass(): ReflectionClass
+ {
+ return $this->reflClass;
+ }
+
/** @psalm-param array{usage?: mixed, region?: mixed} $cache */
public function enableCache(array $cache): void
{
@@ -1098,8 +1101,7 @@ public function getFieldName(string $columnName): string
*/
private function isTypedProperty(string $name): bool
{
- return isset($this->reflClass)
- && $this->reflClass->hasProperty($name)
+ return $this->reflClass->hasProperty($name)
&& $this->reflClass->getProperty($name)->hasType();
}
@@ -2579,8 +2581,6 @@ public function inlineEmbeddable(string $property, ClassMetadata $embeddable): v
if (! empty($this->embeddedClasses[$property]->columnPrefix)) {
$fieldMapping['columnName'] = $this->embeddedClasses[$property]->columnPrefix . $fieldMapping['columnName'];
} elseif ($this->embeddedClasses[$property]->columnPrefix !== false) {
- assert($this->reflClass !== null);
- assert($embeddable->reflClass !== null);
$fieldMapping['columnName'] = $this->namingStrategy
->embeddedFieldToColumnName(
$property,
diff --git a/src/Mapping/ClassMetadataFactory.php b/src/Mapping/ClassMetadataFactory.php
index 8690d4ea17f..f2bd3717d02 100644
--- a/src/Mapping/ClassMetadataFactory.php
+++ b/src/Mapping/ClassMetadataFactory.php
@@ -256,11 +256,6 @@ protected function doLoadMetadata(
*/
protected function validateRuntimeMetadata(ClassMetadata $class, ClassMetadataInterface|null $parent): void
{
- if (! $class->reflClass) {
- // only validate if there is a reflection class instance
- return;
- }
-
$class->validateIdentifier();
$class->validateAssociations();
$class->validateLifecycleCallbacks($this->getReflectionService());
diff --git a/src/Mapping/Driver/LoadMappingFileImplementation.php b/src/Mapping/Driver/LoadMappingFileImplementation.php
deleted file mode 100644
index df351889ba2..00000000000
--- a/src/Mapping/Driver/LoadMappingFileImplementation.php
+++ /dev/null
@@ -1,35 +0,0 @@
-doLoadMappingFile($file);
- }
- }
-} else {
- /** @internal */
- trait LoadMappingFileImplementation
- {
- /**
- * {@inheritDoc}
- */
- protected function loadMappingFile($file)
- {
- return $this->doLoadMappingFile($file);
- }
- }
-}
diff --git a/src/Mapping/Driver/XmlDriver.php b/src/Mapping/Driver/XmlDriver.php
index e11b6b61d6f..9ea73869d71 100644
--- a/src/Mapping/Driver/XmlDriver.php
+++ b/src/Mapping/Driver/XmlDriver.php
@@ -43,8 +43,6 @@
*/
class XmlDriver extends FileDriver
{
- use LoadMappingFileImplementation;
-
public const DEFAULT_FILE_EXTENSION = '.dcm.xml';
/**
@@ -880,8 +878,12 @@ private function getCascadeMappings(SimpleXMLElement $cascadeElement): array
return $cascades;
}
- /** @return array */
- private function doLoadMappingFile(string $file): array
+ /**
+ * {@inheritDoc}
+ *
+ * @return array
+ */
+ protected function loadMappingFile(string $file): array
{
$this->validateMapping($file);
$result = [];
diff --git a/src/Mapping/GetReflectionClassImplementation.php b/src/Mapping/GetReflectionClassImplementation.php
deleted file mode 100644
index 780015c3680..00000000000
--- a/src/Mapping/GetReflectionClassImplementation.php
+++ /dev/null
@@ -1,33 +0,0 @@
-reflClass;
- }
- }
-} else {
- trait GetReflectionClassImplementation
- {
- /**
- * {@inheritDoc}
- *
- * Can return null when using static reflection, in violation of the LSP
- */
- public function getReflectionClass(): ReflectionClass|null
- {
- return $this->reflClass;
- }
- }
-}
diff --git a/src/Tools/SchemaValidator.php b/src/Tools/SchemaValidator.php
index fdfc00390c8..f47563f7283 100644
--- a/src/Tools/SchemaValidator.php
+++ b/src/Tools/SchemaValidator.php
@@ -281,7 +281,7 @@ public function validateClass(ClassMetadata $class): array
if (
! $class->isInheritanceTypeNone()
&& ! $class->isRootEntity()
- && ($class->reflClass !== null && ! $class->reflClass->isAbstract())
+ && ! $class->reflClass->isAbstract()
&& ! $class->isMappedSuperclass
&& array_search($class->name, $class->discriminatorMap, true) === false
) {
diff --git a/tests/Tests/ORM/Functional/Ticket/DDC2359Test.php b/tests/Tests/ORM/Functional/Ticket/DDC2359Test.php
index 7e8a753d53d..873cbcf7fd5 100644
--- a/tests/Tests/ORM/Functional/Ticket/DDC2359Test.php
+++ b/tests/Tests/ORM/Functional/Ticket/DDC2359Test.php
@@ -8,13 +8,13 @@
use Doctrine\DBAL\Connection;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
-use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
+use Doctrine\Persistence\Mapping\RuntimeReflectionService;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
@@ -28,12 +28,13 @@ class DDC2359Test extends TestCase
public function testIssue(): void
{
$mockDriver = $this->createMock(MappingDriver::class);
- $mockMetadata = $this->createMock(ClassMetadata::class);
$entityManager = $this->createMock(EntityManager::class);
- $metadataFactory = $this->getMockBuilder(ClassMetadataFactory::class)
- ->onlyMethods(['newClassMetadataInstance', 'wakeupReflection'])
+ $metadataFactory = $this->getMockBuilder(ClassMetadataFactory::class)
+ ->onlyMethods(['wakeupReflection', 'validateRuntimeMetadata'])
->getMock();
+ $reflectionService = new RuntimeReflectionService();
+ $metadataFactory->expects(self::once())->method('wakeupReflection');
$configuration = $this->getMockBuilder(Configuration::class)
->onlyMethods(['getMetadataDriverImpl'])
@@ -45,29 +46,22 @@ public function testIssue(): void
->method('getMetadataDriverImpl')
->willReturn($mockDriver);
- $entityManager->expects(self::any())->method('getConfiguration')->willReturn($configuration);
- $entityManager->expects(self::any())->method('getConnection')->willReturn($connection);
+ $entityManager->method('getConfiguration')->willReturn($configuration);
+ $entityManager->method('getConnection')->willReturn($connection);
$entityManager
->method('getEventManager')
->willReturn($this->createMock(EventManager::class));
- $metadataFactory->method('newClassMetadataInstance')->willReturn($mockMetadata);
- $metadataFactory->expects(self::once())->method('wakeupReflection');
-
$metadataFactory->setEntityManager($entityManager);
-
- $mockMetadata->method('getName')->willReturn(DDC2359Foo::class);
-
- self::assertSame($mockMetadata, $metadataFactory->getMetadataFor(DDC2359Foo::class));
+ $metadataFactory->getMetadataFor(DDC2359Foo::class);
}
}
#[Entity]
class DDC2359Foo
{
- /** @var int */
#[Id]
#[Column(type: 'integer')]
#[GeneratedValue]
- public $id;
+ public int $id;
}
diff --git a/tests/Tests/ORM/Functional/Ticket/DDC3103Test.php b/tests/Tests/ORM/Functional/Ticket/DDC3103Test.php
deleted file mode 100644
index 5ead8d58698..00000000000
--- a/tests/Tests/ORM/Functional/Ticket/DDC3103Test.php
+++ /dev/null
@@ -1,55 +0,0 @@
-createAttributeDriver()->loadMetadataForClass(DDC3103ArticleId::class, $classMetadata);
-
- self::assertTrue(
- $classMetadata->isEmbeddedClass,
- 'The isEmbeddedClass property should be true from the mapping data.',
- );
-
- self::assertTrue(
- unserialize(serialize($classMetadata))->isEmbeddedClass,
- 'The isEmbeddedClass property should still be true after serialization and unserialization.',
- );
- }
-}
-
-#[Embeddable]
-class DDC3103ArticleId
-{
- #[Column(name: 'name', type: 'string', length: 255)]
- protected string $nameValue;
-}
diff --git a/tests/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Tests/ORM/Mapping/ClassMetadataTest.php
index 85474acb2b5..77b8ab42bf2 100644
--- a/tests/Tests/ORM/Mapping/ClassMetadataTest.php
+++ b/tests/Tests/ORM/Mapping/ClassMetadataTest.php
@@ -21,7 +21,6 @@
use Doctrine\ORM\Mapping\OneToManyAssociationMapping;
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
use Doctrine\Persistence\Mapping\RuntimeReflectionService;
-use Doctrine\Persistence\Mapping\StaticReflectionService;
use Doctrine\Tests\DbalTypes\CustomIdObject;
use Doctrine\Tests\DbalTypes\CustomIdObjectType;
use Doctrine\Tests\DbalTypes\CustomIntType;
@@ -56,7 +55,6 @@
use stdClass;
use function assert;
-use function class_exists;
use function count;
use function serialize;
use function str_contains;
@@ -531,9 +529,12 @@ public function testDefaultJoinColumnName(): void
#[TestGroup('DDC-559')]
public function testUnderscoreNamingStrategyDefaults(): void
{
+ $reflService = new RuntimeReflectionService();
$namingStrategy = new UnderscoreNamingStrategy(CASE_UPPER);
$oneToOneMetadata = new ClassMetadata(CmsAddress::class, $namingStrategy);
$manyToManyMetadata = new ClassMetadata(CmsAddress::class, $namingStrategy);
+ $oneToOneMetadata->initializeReflection($reflService);
+ $manyToManyMetadata->initializeReflection($reflService);
$oneToOneMetadata->mapOneToOne(
[
@@ -569,6 +570,7 @@ public function testUnderscoreNamingStrategyDefaults(): void
self::assertEquals('ID', $manyToManyMetadata->associationMappings['user']->joinTable->inverseJoinColumns[0]->referencedColumnName);
$cm = new ClassMetadata('DoctrineGlobalArticle', $namingStrategy);
+ $cm->initializeReflection(new RuntimeReflectionService());
$cm->mapManyToMany(['fieldName' => 'author', 'targetEntity' => CmsUser::class]);
self::assertEquals('DOCTRINE_GLOBAL_ARTICLE_CMS_USER', $cm->associationMappings['author']->joinTable->name);
}
@@ -861,6 +863,7 @@ public function testInvalidOverrideAttributeFieldTypeException(): void
public function testAttributeOverrideKeepsDeclaringClass(): void
{
$cm = new ClassMetadata(Directory::class);
+ $cm->initializeReflection(new RuntimeReflectionService());
$cm->mapField(['fieldName' => 'id', 'type' => 'integer', 'declared' => AbstractContentItem::class]);
$cm->setAttributeOverride('id', ['columnName' => 'new_id']);
@@ -872,6 +875,7 @@ public function testAttributeOverrideKeepsDeclaringClass(): void
public function testAssociationOverrideKeepsDeclaringClass(): void
{
$cm = new ClassMetadata(Directory::class);
+ $cm->initializeReflection(new RuntimeReflectionService());
$cm->mapManyToOne(['fieldName' => 'parentDirectory', 'targetEntity' => Directory::class, 'cascade' => ['remove'], 'declared' => Directory::class]);
$cm->setAssociationOverride('parentDirectory', ['cascade' => ['remove']]);
@@ -883,6 +887,7 @@ public function testAssociationOverrideKeepsDeclaringClass(): void
public function testAssociationOverrideCanOverrideCascade(): void
{
$cm = new ClassMetadata(Directory::class);
+ $cm->initializeReflection(new RuntimeReflectionService());
$cm->mapManyToOne(['fieldName' => 'parentDirectory', 'targetEntity' => Directory::class, 'cascade' => ['remove'], 'declared' => Directory::class]);
$cm->setAssociationOverride('parentDirectory', ['cascade' => ['all']]);
@@ -988,36 +993,6 @@ public function testCanInstantiateInternalPhpClassSubclassFromUnserializedMetada
self::assertInstanceOf(MyArrayObjectEntity::class, $classMetadata->newInstance());
}
- public function testWakeupReflectionWithEmbeddableAndStaticReflectionService(): void
- {
- if (! class_exists(StaticReflectionService::class)) {
- self::markTestSkipped('This test is not supported by the current installed doctrine/persistence version');
- }
-
- $classMetadata = new ClassMetadata(TestEntity1::class);
-
- $classMetadata->mapEmbedded(
- [
- 'fieldName' => 'test',
- 'class' => TestEntity1::class,
- 'columnPrefix' => false,
- ],
- );
-
- $field = [
- 'fieldName' => 'test.embeddedProperty',
- 'type' => 'string',
- 'originalClass' => TestEntity1::class,
- 'declaredField' => 'test',
- 'originalField' => 'embeddedProperty',
- ];
-
- $classMetadata->mapField($field);
- $classMetadata->wakeupReflection(new StaticReflectionService());
-
- self::assertEquals(['test' => null, 'test.embeddedProperty' => null], $classMetadata->getReflectionProperties());
- }
-
public function testGetColumnNamesWithGivenFieldNames(): void
{
$metadata = new ClassMetadata(CmsUser::class);
@@ -1077,6 +1052,7 @@ public function testItAddingLifecycleCallbackOnEmbeddedClassIsIllegal(): void
public function testItThrowsOnInvalidCallToGetAssociationMappedByTargetField(): void
{
$metadata = new ClassMetadata(self::class);
+ $metadata->initializeReflection(new RuntimeReflectionService());
$metadata->mapOneToOne(['fieldName' => 'foo', 'targetEntity' => 'bar']);
$this->expectException(LogicException::class);
diff --git a/tests/Tests/ORM/Mapping/FieldBuilderTest.php b/tests/Tests/ORM/Mapping/FieldBuilderTest.php
index 5d47f6b3c36..039e65481ab 100644
--- a/tests/Tests/ORM/Mapping/FieldBuilderTest.php
+++ b/tests/Tests/ORM/Mapping/FieldBuilderTest.php
@@ -6,6 +6,7 @@
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata;
+use Doctrine\Persistence\Mapping\RuntimeReflectionService;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\OrmTestCase;
use stdClass;
@@ -14,7 +15,8 @@ class FieldBuilderTest extends OrmTestCase
{
public function testCustomIdGeneratorCanBeSet(): void
{
- $cmBuilder = new ClassMetadataBuilder(new ClassMetadata(CmsUser::class));
+ $cmBuilder = new ClassMetadataBuilder($cm = new ClassMetadata(CmsUser::class));
+ $cm->initializeReflection(new RuntimeReflectionService());
$fieldBuilder = $cmBuilder->createField('aField', 'string');
diff --git a/tests/Tests/ORM/Mapping/XmlMappingDriverTest.php b/tests/Tests/ORM/Mapping/XmlMappingDriverTest.php
index 5426da45c91..921734dddfd 100644
--- a/tests/Tests/ORM/Mapping/XmlMappingDriverTest.php
+++ b/tests/Tests/ORM/Mapping/XmlMappingDriverTest.php
@@ -73,6 +73,7 @@ public function testFailingSecondLevelCacheAssociation(): void
$mappingDriver = $this->loadDriver();
$class = new ClassMetadata(XMLSLC::class);
+ $class->initializeReflection(new RuntimeReflectionService());
$mappingDriver->loadMetadataForClass(XMLSLC::class, $class);
}