Skip to content

Instantly share code, notes, and snippets.

@Airone2000
Created April 28, 2018 09:19
Show Gist options
  • Save Airone2000/cf4dcd0f6585b068a8282659cb50ae94 to your computer and use it in GitHub Desktop.
Save Airone2000/cf4dcd0f6585b068a8282659cb50ae94 to your computer and use it in GitHub Desktop.
API Platform : POST / PUT (relation)
Given I have a User entity and a Profile entity.
A User has a Profile (OneToOne).
When I send a POST request to "/users", with body:
"""
{
"username": "Erwan29",
"profile": {
"firstname": "Erwan",
"lastname": "Guillou"
}
}
"""
Then, API Platform tries to merge the JSON object with a new User entity.
Internally, it uses the PropertyAccess component to setValue() to entity's properties.
Based on Doctrine/ORM annotations, it checks whether the property it's about to fill is a relation.
If it is, still based on annotations, notably "targetEntity", it instanciates a new Entity/Collection to fill.
Then, is "username" a relation ? No ? Fill it with "Erwan29".
Is "profile" a relation ? Yes. It's a OneToOne and the targetEntity is Profile. Let's create an instance of it a fille it with sub-data.
Its the same for a PUT request except that it needs to first retrieve the Profile relation before being able to set new values to it.
How can it proceed ?
Still using the PropertyAccess component :
Is "username" a relation ? No. Fill it with "Erwan29".
Is "profile" a relation ? Yes. Check if a Profile entity is already mapped to this property. When the PropertyAccessor read from the "Profile" attribute, it will not retrieve a Profile entity.
Probably due to a matter of configuration (Doctrine lazy loading, priority ...), it will retrieve ... an ID ! The very ID that links a Profile to its User.
That makes sense. Based on it, API Platform (and the serializer), are able to retrieve the Profile entity by its ID.
If it exists, "firstname" and "lastname" are properly mapped to their respective attribut on Profile.
BUT! That works only if User is the owning side of the relation. Being so, the PropertyAccessor can read the Profile Id from User and proceed properly.
It the owning side is on Profile, trying to access the value for property "profile" on User will always return null.
On updating (sending a PUT request), API Platform will always intend to CREATE the Profile.
To conclude, in a plain Sf project, for a OneToOne / ManyToMany relation, choosing which side is the owning/inverse don't cause too much trouble and the choice can be done indifferently.
However, on doubting, the way to determine which should be the "owning side" is asking oneself : which owns the other one?
"A User has a Profile". That's right. So, the owning side is User.
This choice is really important in API Platform.
@Airone2000
Copy link
Author

@vdumontier

J'ai fait ma petite enquête qui explique pourquoi la base de données doit subir quelques adaptations, notamment au niveau de la relation sfGuardUser / sfGuardUserProfile (owning side)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment