I have a problem with ApiPlatform that I would like to be able to understand and solve easily.
Context: I want to update an address fields with this instruction:
curl --request PUT \
--url http://localhost/api/users/25 \
--header 'authorization: Bearer xxx' \
--header 'content-type: application/json' \
--data '{
"lastName" : "Bernard",
"firstName" : "Jean",
"dateBirth" : "1996-12-12",
"phone" : "0769397070",
"address" : {
"street" : "150 rue des paquerettes",
"pos": [ 66.344133 , 73.049472 ],
"city": "Paris",
"postcode": "75001"
}
}
Problem: Each PUT instruction creates a new Address instance when "address" is defined in the request.
Entities :
App/Entity/User
/**
* @ApiResource(
* attributes={
* "security"="is_granted('ROLE_ADMIN') or object == user",
* "security_message"="User does not match the authenticated user"
* },
* itemOperations={
* "get"={
* "normalization_context"={
* "groups"={"read:full:user","read:order"},
* }
* },
* "put"={
* "normalization_context"={"groups" ={ "read:full:user"}},
* "denormalization_context"={"groups" ={ "write:user:customer", "write:user:lawyer"}},
* "security"="object == user"
* }
* },
* collectionOperations={}
*)
* @UniqueEntity(
* fields={"email"},
* message="This user is already registered",
* groups={"create:customer", "create:lawyer"}
* )
* @ORM\HasLifecycleCallbacks
* @ORM\Entity
*/
class User implements UserInterface
{
use Traits\Timestampable;
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
// ...
/**
* @ORM\Column(type="string", length=255, nullable=false)
* @Assert\NotBlank
* @Groups({"create:customer","create:lawyer","read:full:user", "write:user:customer", "write:user:lawyer"})
*/
private $phone;
/**
* @ORM\OneToOne(targetEntity=Address::class, cascade={"persist"})
* @ORM\JoinColumn(nullable=true)
* @Groups({"create:customer", "create:lawyer", "read:full:user", "write:user:customer", "write:user:lawyer"})
*/
private $address;
// ...
}
App/Entity/Address
/**
* @ApiResource(
* denormalizationContext = {
* "groups" = {"create:lawyer", "create:customer", "write:user:customer", "write:user:lawyer"}
* },
* itemOperations={
* "get"={
* "normalization_context"={"groups"={"read:lawyer","create:lawyer","read:full:lawyer"}}
* },
* }
* )
* @ORM\Entity(repositoryClass=AddressRepository::class)
*/
class Address
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Groups({"read:full:lawyer", "create:customer", "create:lawyer", "read:full:user", "write:user:customer", "write:user:lawyer"})
*/
private $street;
}
I want to modify in a single instruction entities whose logical dependency is already specified (OneToOne). Do you have any idea on the best way to go about it?
Thank you!
One alternative solution is add hydra attribute "@id" for the data provider to associate the object. It's natural for multiple relationships, but it's not elegant for OneToOne relationships.