diff --git a/composer.json b/composer.json index 2f9e1d19b3a..969ce5ad9c0 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "require-dev": { "doctrine/coding-standard": "^10.0", "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "1.8.8", + "phpstan/phpstan": "1.8.11", "phpunit/phpunit": "^9.5", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.1", diff --git a/docs/en/reference/query-builder.rst b/docs/en/reference/query-builder.rst index 50a1b8dc73c..7e3e3fff363 100644 --- a/docs/en/reference/query-builder.rst +++ b/docs/en/reference/query-builder.rst @@ -434,6 +434,12 @@ complete list of supported helper methods available: // Example - $qb->expr()->isNotNull('u.id') => u.id IS NOT NULL public function isNotNull($x); // Returns string + // Example - $qb->expr()->isMemberOf('?1', 'u.groups') => ?1 MEMBER OF u.groups + public function isMemberOf($x, $y); // Returns Expr\Comparison instance + + // Example - $qb->expr()->isInstanceOf('u', Employee::class) => u INSTANCE OF Employee + public function isInstanceOf($x, $y); // Returns Expr\Comparison instance + /** Arithmetic objects **/ diff --git a/docs/en/reference/working-with-objects.rst b/docs/en/reference/working-with-objects.rst index f592810d789..129de4510fe 100644 --- a/docs/en/reference/working-with-objects.rst +++ b/docs/en/reference/working-with-objects.rst @@ -305,7 +305,7 @@ as follows: - A removed entity X will be removed from the database as a result of the flush operation. -After an entity has been removed its in-memory state is the same as +After an entity has been removed, its in-memory state is the same as before the removal, except for generated identifiers. Removing an entity will also automatically delete any existing diff --git a/docs/en/tutorials/ordered-associations.rst b/docs/en/tutorials/ordered-associations.rst index e24abe3cea7..e03eb45bf7a 100644 --- a/docs/en/tutorials/ordered-associations.rst +++ b/docs/en/tutorials/ordered-associations.rst @@ -43,7 +43,7 @@ The DQL Snippet in OrderBy is only allowed to consist of unqualified, unquoted field names and of an optional ASC/DESC positional statement. Multiple Fields are separated by a comma (,). The referenced field names have to exist on the ``targetEntity`` -class of the ``#[ManyToMany]`` or ``#[OneToMany]`` annotation. +class of the ``#[ManyToMany]`` or ``#[OneToMany]`` attribute. The semantics of this feature can be described as follows: diff --git a/lib/Doctrine/ORM/Events.php b/lib/Doctrine/ORM/Events.php index 89aadbd6ab4..adc486ee066 100644 --- a/lib/Doctrine/ORM/Events.php +++ b/lib/Doctrine/ORM/Events.php @@ -82,7 +82,7 @@ private function __construct() /** * The loadClassMetadata event occurs after the mapping metadata for a class - * has been loaded from a mapping source (annotations/xml). + * has been loaded from a mapping source (attributes/xml). */ public const loadClassMetadata = 'loadClassMetadata'; diff --git a/lib/Doctrine/ORM/Tools/AttachEntityListenersListener.php b/lib/Doctrine/ORM/Tools/AttachEntityListenersListener.php index 59cd77eb8f7..c7b7d300e42 100644 --- a/lib/Doctrine/ORM/Tools/AttachEntityListenersListener.php +++ b/lib/Doctrine/ORM/Tools/AttachEntityListenersListener.php @@ -5,6 +5,7 @@ namespace Doctrine\ORM\Tools; use Doctrine\ORM\Event\LoadClassMetadataEventArgs; +use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; use function ltrim; @@ -17,11 +18,11 @@ class AttachEntityListenersListener private array $entityListeners = []; /** - * Adds a entity listener for a specific entity. + * Adds an entity listener for a specific entity. * * @param string $entityClass The entity to attach the listener. * @param string $listenerClass The listener class. - * @param string $eventName The entity lifecycle event. + * @param string|null $eventName The entity lifecycle event. * @param string|null $listenerCallback The listener callback method or NULL to use $eventName. */ public function addEntityListener( @@ -49,7 +50,11 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $event): void } foreach ($this->entityListeners[$metadata->name] as $listener) { - $metadata->addEntityListener($listener['event'], $listener['class'], $listener['method']); + if ($listener['event'] === null) { + EntityListenerBuilder::bindEntityListener($metadata, $listener['class']); + } else { + $metadata->addEntityListener($listener['event'], $listener['class'], $listener['method']); + } } unset($this->entityListeners[$metadata->name]); diff --git a/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php b/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php index 01d0a2ee46e..ab99a13ad91 100644 --- a/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php @@ -110,6 +110,31 @@ public function testDuplicateEntityListenerException(): void $this->factory->getMetadataFor(AttachEntityListenersListenerTestFooEntity::class); } + + public function testAttachWithoutSpecifyingAnEventName(): void + { + $this->listener->addEntityListener( + AttachEntityListenersListenerTestFooEntity::class, + AttachEntityListenersListenerTestListener::class, + null + ); + + $metadata = $this->factory->getMetadataFor(AttachEntityListenersListenerTestFooEntity::class); + + self::assertCount(2, $metadata->entityListeners); + + self::assertArrayHasKey('prePersist', $metadata->entityListeners); + self::assertArrayHasKey('postPersist', $metadata->entityListeners); + + self::assertCount(1, $metadata->entityListeners['prePersist']); + self::assertCount(1, $metadata->entityListeners['postPersist']); + + self::assertEquals('prePersist', $metadata->entityListeners['prePersist'][0]['method']); + self::assertEquals(AttachEntityListenersListenerTestListener::class, $metadata->entityListeners['prePersist'][0]['class']); + + self::assertEquals('postPersist', $metadata->entityListeners['postPersist'][0]['method']); + self::assertEquals(AttachEntityListenersListenerTestListener::class, $metadata->entityListeners['postPersist'][0]['class']); + } } #[Entity]