bentools / doctrine-safe-events
Fires postPersist / postUpdate / postRemove events AFTER the transaction has completed.
Installs: 6 991
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 3
Forks: 0
Open Issues: 0
Requires
- php: >=7.4
- doctrine/orm: ~2.0
Requires (Dev)
- doctrine/annotations: ~1.0
- matthiasnoback/doctrine-orm-test-service-provider: ^3.0
- pestphp/pest: ^1.22
- phpstan/phpstan: ^1.8
- squizlabs/php_codesniffer: ^3.7
- symfony/cache: ~5.4|~6.2
- symfony/var-dumper: @stable
README
Doctrine safe post* events
Doctrine's postPersist, postUpdate and postRemove events are fired when the corresponding SQL queries (INSERT / UPDATE / DELETE) have been performed against the database server.
What happens under the hood is that Doctrine creates a wrapping transaction, runs SQL queries, then commits the transaction.
However, these events are fired immediately, e.g. not once the transaction is complete, which means:
- If the wrapping transaction fails, events have already been fired anyway (meaning you trusted generated primary key values, although they're going to be rolled back)
- If the wrapping transaction takes some time (typically during row locks), you get the inserted / updated / deleted information before it's actually done (meaning if you run some async process once those events are triggered, you end up in processing not data which is not up-to-date)
Background
The idea of this repository indeed came up with the following issue:
- An entity is persisted, then
$em->flush()
is called - A
postPersist
event listener gets the entity's id, then asks a worker to do some async processing through Symfony Messenger - The worker queries database against the entity's id, and gets an
EntityNotFound
exception (theCOMMIT
did not happen yet) - The flush operation on the main thread completes, and the
postFlush
event is fired (but it does not contain the inserted / updated / deleted entities)
Our solution
If you run into the same kind of issues, you can replace your listeners' listened events in favor of:
Bentools\DoctrineSafeEvents\SafeEvents::POST_PERSIST
(and implementsafePostPersist
as a replacement ofpostPersist
)Bentools\DoctrineSafeEvents\SafeEvents::POST_UPDATE
(and implementsafePostUpdate
as a replacement ofpostUpdate
)Bentools\DoctrineSafeEvents\SafeEvents::POST_REMOVE
(and implementsafePostRemove
as a replacement ofpostRemove
)
Basically, this library will collect entities which are scheduled for insertion / update / deletion, except it will delay event firing until the postFlush
occurs.
Installation
composer require bentools/doctrine-safe-events
Usage in Symfony
Although this library has no dependency on Symfony, you can easily use it in your Symfony project:
Bentools\DoctrineSafeEvents\SafeEventsDispatcher: tags: - { name: 'doctrine.event_subscriber' } - { name: 'kernel.reset', method: 'reset' }
Example usage
declare(strict_types=1); namespace App; use Bentools\DoctrineSafeEvents\SafeEvents; use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\Persistence\Event\LifecycleEventArgs; #[AsDoctrineListener(SafeEvents::POST_PERSIST)] final class SomeListener { public function safePostPersist(LifecycleEventArgs $eventArgs): void { // ... } }
Tests
composer test
License
MIT.