Reputation: 515
Is there a way to dispatch a custom event every time a certain entity setter is called ?
I actually need to change some value of an unrelated entity, every time a certain entity property is changed. So in order to separate concerns and to decouple objects, I wanted to do this with the observer pattern. I don't want to do this in some doctrine event like 'preUpdate' or similar, as they only fire when the entity is flushed, but I need this value to change immediately to assure these two values are always in sync.
As it is bad practice to inject any service into the entity, I don't see how I could do that ?
Any suggestions ?
Upvotes: 1
Views: 3261
Reputation: 1440
If you wish to use the observer pattern, you will have to implement it yourself in some way. As you pointed out, Doctrine will compute the changeset of your entity only when a flush operation is triggered and not before. That being said, it happens that Doctrine proposes alternative tracking policies. The NOTIFY
tracking policy behaviour relies exactly on what you wish to achieve.
I am not suggesting that you should change the tracking policy of your entity but you could take advantage of the existing interfaces to implement your observer pattern. To do so, as explained in this section of the documentation, your entity being observed needs to implement the NotifyPropertyChanged interface.
From there you could implement the PropertyChangedListener interface directly in the other entity (or use a specific service that would add itself as listener of your entity in the postLoad
event for example ?). Here it mainly depends on the relation between your entities and how you can attach your listener to the entity implementing NotifyPropertyChanged
.
Note that if you do this, the UnitOfWork
of Doctrine will automatically hook itself as a listener of your entity but it will still rely on automatic changeset computation as long as you don't add the @ChangeTrackingPolicy("NOTIFY")
annotation.
Upvotes: 1
Reputation: 8162
Using the event dispatcher:
The Event that will carry your information
class UpdateEntityEvent extends Event {
private $myEntity;
private $newValue;
public function __construct(Entity $entity, Whatever $newValue){
$this->myEntity = $entity;
$this->newValue = $newValue;
}
// [...] getters
}
Your Listener
class UpdateMyEntityEventListener
{
public function updateCertainProperty(UpdateMyEntityEvent $event)
{
// Do what you want here :D
}
}
Some configuration
kernel.listener.updateMyEntity:
class: Acme\AppBundle\EventListener\UpdateMyEntityEventListener
tags:
- { name: kernel.event_listener, event: updateMyEntity, method: updateCertainProperty }
We avoid using some hardcoded string, let's put the event name in a constant
class MyEntityEvents
{
const UPDATE = 'updateMyEntity';
}
Then in your Controller
public function updateAction()
{
// [...]
$event = new UpdateMyEntityEvent($entity, $whatever);
$dispatcher = $this->get('event_dispatcher')->dispatch( MyEntityEvents::UPDATE, $event);
Upvotes: 1