From 663763ab1ad11058cd102bf1aafc6109b162876f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 17 Jun 2023 16:16:25 +0200 Subject: [PATCH] Disallow lifecycle callbacks on embedded classes --- UPGRADE.md | 5 +++++ lib/Doctrine/ORM/Mapping/ClassMetadata.php | 8 +------- lib/Doctrine/ORM/Mapping/MappingException.php | 13 +++++++++++++ .../Tests/ORM/Mapping/ClassMetadataTest.php | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index ecc71453253..4946a9302d7 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,10 @@ # Upgrade to 3.0 +## BC BREAK: Lifecycle callback mapping on embedded classes is now explicitly forbidden + +Lifecycle callback mapping on embedded classes produced no effect, and is now +explicitly forbidden to point out mistakes. + ## BC BREAK: The `NOTIFY` change tracking policy is removed You should use `DEFERRED_EXPLICIT` instead. diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index f774fa90853..93dd965ca1c 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -2044,13 +2044,7 @@ public function getLifecycleCallbacks(string $event): array public function addLifecycleCallback(string $callback, string $event): void { if ($this->isEmbeddedClass) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/8381', - 'Registering lifecycle callback %s on Embedded class %s is not doing anything and will throw exception in 3.0', - $event, - $this->name, - ); + throw MappingException::illegalLifecycleCallbackOnEmbeddedClass($callback, $this->name); } if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event], true)) { diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index 6dddeb0dc1d..1b45aab32dc 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -498,6 +498,19 @@ public static function lifecycleCallbackMethodNotFound(string $className, string return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback."); } + /** @param class-string $className */ + public static function illegalLifecycleCallbackOnEmbeddedClass(string $event, string $className): self + { + return new self(sprintf( + <<<'EXCEPTION' + Context: Attempt to register lifecycle callback "%s" on embedded class "%s". + Problem: Registering lifecycle callbacks on embedded classes is not allowed. + EXCEPTION, + $event, + $className, + )); + } + public static function entityListenerClassNotFound(string $listenerName, string $className): self { return new self(sprintf('Entity Listener "%s" declared on "%s" not found.', $listenerName, $className)); diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 2b761ec6d8d..170f95bee6c 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -1014,6 +1014,20 @@ public function testRejectsEmbeddableWithoutValidClassName(): void 'columnPrefix' => false, ]); } + + public function testItAddingLifecycleCallbackOnEmbeddedClassIsIllegal(): void + { + $metadata = new ClassMetadata(self::class); + $metadata->isEmbeddedClass = true; + + $this->expectException(MappingException::class); + $this->expectExceptionMessage(<<<'EXCEPTION' + Context: Attempt to register lifecycle callback "foo" on embedded class "Doctrine\Tests\ORM\Mapping\ClassMetadataTest". + Problem: Registering lifecycle callbacks on embedded classes is not allowed. + EXCEPTION); + + $metadata->addLifecycleCallback('foo', 'bar'); + } } #[MappedSuperclass]