-
-
Notifications
You must be signed in to change notification settings - Fork 956
Description
Hi api-platform fans!
This seems like a design issue, not necessarily with api-platform.
Here's the scenario:
- I have an entity A
- There's a UniqueEntity constraint validation defined on ManyToOne property B with EAGER fetch mode
- When I issue a PUT request to change that property with either a null or proper value the WriteListener persists data with wrong value / state
Behind the scenes
-
ReadListener loads entity and sets it in request.attributes.data
core/src/EventListener/ReadListener.php
Line 119 in d8e624b
$request->attributes->set('data', $data); -
DeserializeListener deserializes JSON payload and replaces request.attributes.data item
core/src/EventListener/DeserializeListener.php
Lines 104 to 107 in d8e624b
$request->attributes->set( 'data', $this->serializer->deserialize($request->getContent(), $context['resource_class'], $format, $context) ); -
Symfony injects request.attributes.data as $data argument in a custom controller
-
ValidateListener triggers validator on controller result from previous step and invokes UniqueEntityValidator which seems to reload the entity and there fore effectively discards deserialized data from DeserializeListener step https://github.com/symfony/doctrine-bridge/blob/ca6f8537ed349250940a58266630875faec42303/Validator/Constraints/UniqueEntityValidator.php#L138
-
WriteListener retrieves controller result that references entity that has been reloaded and persists wrong data
core/src/EventListener/WriteListener.php
Line 76 in d8e624b
$persistResult = $this->dataPersister->persist($controllerResult, $attributes);
Result
You are unable to set entity association to null if it has been previously defined and persisted in database.
There's another gotcha, this scenario occurs only when property B in entity A defines EAGER fetch mode. For LAZY and EXTRA_LAZY Doctrine will not reload and rewrite property value.
Simple solution is to not use UniqueEntity validation or EAGER fetch mode. However, I was wondering if there is a good soul to give me an alternative approach. Is there a way to somehow prevent UniqueEntityValidator and Doctrine to fully reload entity state per API request operation?
Tried to pass a cloned entity to validator but that seems to brake down the UniqueEntityValidator
| $this->validator->validate($controllerResult, ['groups' => $validationGroups]); |