willdurand/propel-eventdispatcher-bundle
Symfony2 bundle integrating Propel’s EventDispatcherBehavior. Adds per-model event dispatchers so you only subscribe to relevant Propel lifecycle events, improving separation of concerns and avoiding unnecessary listeners.
Installation
Add the bundle to your composer.json:
composer require willdurand/propel-eventdispatcher-bundle
Enable it in config/bundles.php:
return [
// ...
WillDurand\PropelEventDispatcherBundle\WillDurandPropelEventDispatcherBundle::class => ['all' => true],
];
Enable the Behavior
In your Propel schema XML (e.g., schema.xml), add the eventDispatcher behavior to your model:
<behavior name="eventdispatcher">
<listeners>
<listener name="preInsert" method="onPreInsert" />
<listener name="postSave" method="onPostSave" />
</listeners>
</behavior>
First Use Case
Create a listener for a model event (e.g., UserModel):
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Propel\Runtime\Event\Event;
class UserEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'user.pre-insert' => 'onUserPreInsert',
'user.post-save' => 'onUserPostSave',
];
}
public function onUserPreInsert(Event $event)
{
$user = $event->getTarget();
// Logic before insert
}
public function onUserPostSave(Event $event)
{
$user = $event->getTarget();
// Logic after save
}
}
Register the subscriber in services.yaml:
services:
App\EventSubscriber\UserEventSubscriber:
tags: ['propel.event_subscriber']
Lifecycle Hooks
Use standard Propel events (pre-insert, post-save, pre-delete, etc.) to trigger business logic:
// Example: Validate data before insert
public function onUserPreInsert(Event $event)
{
$user = $event->getTarget();
if (!$user->getEmail()) {
throw new \RuntimeException("Email is required");
}
}
Cross-Model Events Dispatch custom events between models (e.g., notify admins when a user signs up):
public function onUserPostInsert(Event $event)
{
$dispatcher = $event->getDispatcher();
$dispatcher->dispatch('user.signed_up', new UserSignedUpEvent($event->getTarget()));
}
Asynchronous Processing Use event listeners to queue jobs (e.g., send emails, log actions):
public function onOrderPostSave(Event $event)
{
$order = $event->getTarget();
$this->emailService->sendOrderConfirmation($order);
}
Symfony EventDispatcher
Leverage Symfony’s EventDispatcherInterface for complex workflows:
$dispatcher = $this->get('event_dispatcher');
$dispatcher->dispatch('app.custom_event', new CustomEvent($data));
Propel Query Events
Hook into query events (e.g., pre-select) for dynamic query modifications:
<behavior name="eventdispatcher">
<listeners>
<listener name="pre-select" method="onPreSelect" />
</listeners>
</behavior>
Dependency Injection Inject services into subscribers via Symfony’s DI container:
services:
App\EventSubscriber\OrderSubscriber:
arguments: ['@mailer', '@logger']
tags: ['propel.event_subscriber']
Event Naming Conflicts
Ensure event names match the model’s behavior configuration exactly (e.g., user.pre-insert vs. user.preInsert). Case sensitivity matters.
Circular Dependencies
Avoid recursive event dispatching (e.g., A.pre-save triggers B.pre-save, which triggers A.pre-save again). Use guards or flags:
if (!$event->getTarget()->isProcessing()) {
$event->getTarget()->setProcessing(true);
// Dispatch logic
}
Performance Overhead
Heavy logic in pre-* events can slow down Propel queries. Offload work to async tasks or post-* events where possible.
Schema Updates
After adding the eventDispatcher behavior, regenerate Propel classes:
php bin/propel-build-model
Event Not Firing? Verify:
schema.xml.propel.event_subscriber.user.pre-insert → onUserPreInsert).Logging Events Enable Symfony’s debug toolbar or log events manually:
public function onUserPreInsert(Event $event)
{
$this->logger->info('User pre-insert', ['user_id' => $event->getTarget()->getId()]);
}
Custom Event Classes
Extend Propel’s Event class for domain-specific data:
class UserSignedUpEvent extends Event
{
public function __construct(private UserModel $user) {}
public function getUser(): UserModel { return $this->user; }
}
Dynamic Listeners Register listeners dynamically via services or commands:
$container->get('propel.event_dispatcher')->addListener(
'user.pre-insert',
[$subscriber, 'onUserPreInsert']
);
Propel 2.x Compatibility If using Propel 2.x, ensure the bundle’s version matches your Propel version. The bundle is archived but may still work with older setups.
Testing Mock the event dispatcher in tests:
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$user = new UserModel();
$user->setEventDispatcher($dispatcher);
How can I help you explore Laravel packages today?