Description
I want to use Doctrine's functionality called Entity Listener for tracking some entity changes. I have two entities named Sensors and Parameters. Each Sensor can have multiple Parameters and same Parameters can be also used with different Sensors, so i use many-to-many association between them. Next, i would like to allow add/remove some/all Parameters from Sensor any time and track history of these associations. Entity Listener is perfect solution in this situation.
For this i've created Entity Listener called SensorsListener and added event preUpdate for catching changes made to Sensor entity. But... many-to-many association is collection type and if it has field property named "multiple" set to true, then Symfony's MergeDoctrineCollectionListener is added as event subcriber (DoctrineType class):
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['multiple']) {
$builder
->addEventSubscriber(new MergeDoctrineCollectionListener())
->addViewTransformer(new CollectionToArrayTransformer(), true)
;
}
}
It checks if all items from collections were removed, and if yes, then instead of "raw" deleting of items, calls clear method for optimization purposes:
class MergeDoctrineCollectionListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
// Higher priority than core MergeCollectionListener so that this one
// is called before
return array(FormEvents::SUBMIT => array('onBind', 10));
}
public function onBind(FormEvent $event)
{
$collection = $event->getForm()->getData();
$data = $event->getData();
// If all items were removed, call clear which has a higher
// performance on persistent collections
if ($collection instanceof Collection && count($data) === 0) {
$collection->clear();
}
}
}
If i have for example some Sensor with associated 5 Parameters and i delete 3 of them, it's all ok, but when i remove all Parameters then preUpdate event isn't triggered. Because of clearing collection, Doctrine doesn't know what changes are truly made and doesn't qualify Sensor entity in unit of work as updated.
Workaround for this issue is to add postLoad event for grabbing actual associations and compare them with associations in preFlush state, but in optimization view, it doesn't make sense, because now in whole application where Sensors are used - all of associated Parameters are loaded also.
If i comment line $collection->clear();
then preUpdate is triggered properly.
I would like to suggest to add some new boolean option to EntityType field, like raw_update or no_optimizations, that will block static usage of clear collection when deleting all associations. It will make Entity Listeners to work with collection types correctly without any workarounds.