Reputation: 961
I'm struggling with this strange behavior with my API: some of the attributes are set to readOnly: true
.
EDIT: This is how my entities are defined
/**
* @ApiResource(
* normalizationContext={"groups"={"read_partenaire"}},
* denormalizationContext={"groups"={"write_partenaire"}}
* )
* @ORM\Entity(repositoryClass="App\Repository\ProfessionnelRepository")
* @ApiFilter(SearchFilter::class, properties={"nom": "partial", "id": "exact"})
*/
class Professionnel
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Groups({"read_partenaire"})
*/
private $id;
/**
* @ORM\OneToOne(targetEntity="App\Entity\Partenaire", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
* @Groups({"read_partenaire","write_partenaire"})
*
*/
private $partenaire;
/**
* @ORM\Column(type="string", length=4)
* @Groups({"read_partenaire","write_partenaire"})
*
*/
private $civilite;
/**
* @ORM\Column(type="string", length=100)
* @Groups({"read_partenaire","write_partenaire"})
*
*/
private $nom;
/**
* @ORM\Column(type="string", length=100)
* @Groups({"read_partenaire","write_partenaire"})
*
*/
private $prenom;
The second entity :
/**
* @ApiResource(
* normalizationContext={"groups"={"read_partenaire"}},
* denormalizationContext={"groups"={"write_partenaire"}}
* )
* @ApiFilter(SearchFilter::class, properties={"id": "exact"})
* @ORM\Entity(repositoryClass="App\Repository\PartenaireRepository")
*/
class Partenaire
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Groups({"read_partenaire"})
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Ban", inversedBy="partenaires", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
* @Groups({"read_partenaire","write_partenaire"})
*/
private $ban;
The third entity:
/**
* @ApiResource()
* @ORM\Entity(repositoryClass="App\Repository\BanRepository")
*/
class Ban
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Groups({"read_partenaire"})
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Groups({"read_partenaire","write_partenaire"})
*
*/
private $nom_voie;
To sum it up, my Professionnel
entity is nested to Partenaire
which is nested to Ban
. So by creating a new Professionnel
a new Partenaire
and Ban
should be created as well.
Please keep in mind that all the properties of my 3 entities have get
and set
functions (except id's of course)...but for some reason, the property nom_voie
of my third entity is set to readOnly (and because of that, the insert of all the entities fail...)
I'm not sure how exactly this two-level nesting should be expressed using Groups
I tried many combinations but no luck...
Upvotes: 1
Views: 2214
Reputation: 41
if you automatically generated getter and setter methods for $nom_voie attribute with "php bin/console make:entity" that probably would be getNomVoie() and setNomVoie() .
Api platform is looking for a setter method to decide if attribute is readonly and cannot associate $nom_voie with setNomVoie. Either rename attribute in camelCase format ($nomVoie) or rename the setter method to setNom_voie()
Upvotes: 2
Reputation: 413
You have to update your entity as follow, you cant have the same group name for normalization and denormalization, now for properties that you need to submit and read its value later add the both groups to it {"ban_read", "ban_write"}, for Id for example only "ban_read" needed because you will not submit id value.
* @ApiResource(
* normalizationContext={"groups"={"ban_read"}, "swagger_definition_name": "read"},
* denormalizationContext={"groups"={"ban_write"}, "swagger_definition_name": "write"}
* )
*/
Class Address {
//...
/**
* @ORM\Column(type="integer")
* @Groups({"ban_read"})
*/
private $numero;
/**
* @ORM\Column(type="integer")
* @Groups({"ban_write","ban_read"})
*/
private $code_insee;
//here you can see they both have identical getter and setter :
public function getNumero(): ?int
{
return $this->numero;
}
public function setNumero(int $numero): self
{
$this->numero = $numero;
return $this;
}
public function getCodeInsee(): ?int
{
return $this->code_insee;
}
public function setCodeInsee(int $code_insee): self
{
$this->code_insee = $code_insee;
return $this;
}
}
UPDATE: Create unique groups for each entity for example read_ban, write_ban then in the Professionnel entity update the denormalizationContext to include all other groups.
denormalizationContext={"groups"={"write_professionnel","write_partenaire", "write_ban"}}
Upvotes: 0
Reputation: 821
If you want to handle readonly attributes, i think you can use normalization/denormalization context instead of "getter/ no setter"
Class Address {
//...
/**
* @ORM\Column(type="integer")
* @Groups({"read", "write"})
*/
private $numero;
/**
* @ORM\Column(type="integer")
* @Groups({"read"})
*/
private $code_insee;
public function getNumero(): ?int
{
return $this->numero;
}
public function setNumero(int $numero): self
{
$this->numero = $numero;
return $this;
}
public function getCodeInsee(): ?int
{
return $this->code_insee;
}
public function setCodeInsee(int $code_insee): self
{
$this->code_insee = $code_insee;
return $this;
}
}
and
services:
# ...
resource.Address:
parent: "api.resource"
arguments: [ "AppBundle\Entity\Address" ]
calls:
- method: "initNormalizationContext"
arguments: [ { groups: [ "read" ] } ]
- method: "initDenormalizationContext"
arguments: [ { groups: [ "write" ] } ]
tags: [ { name: "api.resource" } ]
Upvotes: 0