Symfony - Api-Platform - subresource error - php

I have a problem on Symfony5 - apiPlatform, when I request a subresource I have an answer in Json but with an error.
Symfony \ Component \ VarDumper \ Cloner \ Data objects are immutable
my code:
entity\Customer
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM; use
App\Repository\CustomerRepository; use
ApiPlatform\Core\Annotation\ApiFilter; use
Doctrine\Common\Collections\Collection; use
ApiPlatform\Core\Annotation\ApiResource; use
ApiPlatform\Core\Annotation\ApiSubresource; use
Doctrine\Common\Collections\ArrayCollection; use
Symfony\Component\Serializer\Annotation\Groups;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter; use
ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
/** * #ORM\Entity(repositoryClass=CustomerRepository::class) *
#ApiResource( * normalizationContext={ *
"groups"={"customers_read"} * }, * collectionOperations={"GET",
"POST"}, * itemOperations={"GET","PUT","DELETE","PATCH"}, *
subresourceOperations={ *
"invoices_get_subresource"={"path"="/customers/{id}/invoices"} * }
* ) * #ApiFilter(SearchFilter::class, properties={"firstName":"partial","lastName","company"}) *
#ApiFilter(OrderFilter::class) */ class Customer {
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"customers_read","invoices_read"})
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"customers_read","invoices_read"})
*/
private $firstName;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"customers_read","invoices_read"})
*/
private $lastName;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"customers_read","invoices_read"})
*/
private $email;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"customers_read","invoices_read"})
*/
private $company;
/**
* #ORM\OneToMany(targetEntity=Invoice::class, mappedBy="customer")
* #Groups({"customers_read"})
* #ApiSubresource
*/
private $invoices;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="customers")
* #ORM\JoinColumn(nullable=false)
* #Groups({"customers_read"})
*/
private $user;
public function __construct()
{
$this->invoices = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* #Groups({"customers_read"})
*
* #return float|null
*/
public function getTotalAmount(): ?float
{
return array_reduce($this->invoices->toArray(), function($total,$invoice){
return $total + $invoice->getAmount();
}, 0);
}
/**
* #Groups({"customers_read"})
*
* #return float|null
*/
public function getUnpaidAmount(): ?float
{
return array_reduce($this->invoices->toArray(), function($total,$invoice){
return $total + ($invoice->getStatus() === "PAID" || $invoice->getStatus() === "CANCELLED" ? 0 : $invoice->getAmount());
} , 0);
}
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName;
}
public function setLastName(string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getCompany(): ?string
{
return $this->company;
}
public function setCompany(?string $company): self
{
$this->company = $company;
return $this;
}
/**
* #return Collection|Invoice[]
*/
public function getInvoices(): Collection
{
return $this->invoices;
}
public function addInvoice(Invoice $invoice): self
{
if (!$this->invoices->contains($invoice)) {
$this->invoices[] = $invoice;
$invoice->setCustomer($this);
}
return $this;
}
public function removeInvoice(Invoice $invoice): self
{
if ($this->invoices->removeElement($invoice)) {
// set the owning side to null (unless already changed)
if ($invoice->getCustomer() === $this) {
$invoice->setCustomer(null);
}
}
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
} }
entity\invoice
<?php
namespace App\Entity;
use App\Entity\User; use Doctrine\ORM\Mapping as ORM; use
App\Repository\InvoiceRepository; use
ApiPlatform\Core\Annotation\ApiFilter; use
ApiPlatform\Core\Annotation\ApiResource; use
Symfony\Component\Serializer\Annotation\Groups; use
ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
/** * #ORM\Entity(repositoryClass=InvoiceRepository::class) *
#ApiResource( * subresourceOperations={ *
"api_customers_invoices_get_subresource"={ *
"normalization_context"={"groups"={"invoices_subresource"}} * }
* }, * itemOperations={"GET","PUT","DELETE","increment"={ * "method"="post", * "path"="/invoices/{id}/increment", *
"controller"="App\Controller\InvoiceIncrementationController", *
"openapi_context"={ * "summary"="Incrémente une
facture", * "description"="Incrémente le chrono d'une
facture donnée" * } * }}, * attributes={ *
"pagination_enabled"=true, * "pagination_items_per_page"=20, *
"order": {"sentAt":"desc"} * }, *
normalizationContext={"groups"={"invoices_read"}} * ) *
#ApiFilter(OrderFilter::class, properties={"amount","sentAt"}) */
class Invoice {
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"invoices_read","customers_read","invoices_subresource"})
*/
private $id;
/**
* #ORM\Column(type="float")
* #Groups({"invoices_read","customers_read","invoices_subresource"})
*/
private $amount;
/**
* #ORM\Column(type="datetime")
* #Groups({"invoices_read","customers_read","invoices_subresource"})
*/
private $sentAt;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"invoices_read","customers_read","invoices_subresource"})
*/
private $status;
/**
* #ORM\ManyToOne(targetEntity=Customer::class, inversedBy="invoices")
* #ORM\JoinColumn(nullable=false)
* #Groups({"invoices_read"})
*/
private $customer;
/**
* #ORM\Column(type="integer")
* #Groups({"invoices_read"})
* #Groups({"invoices_read","customers_read","invoices_subresource"})
*/
private $chrono;
public function getId(): ?int
{
return $this->id;
}
/**
* Permet de récupérer le User à qui appartient finalement la facture
* #Groups({"invoices_read","invoices_subresource"})
*
* #return User
*/
public function getUser(): ?User
{
return $this->customer->getUser();
}
public function getAmount(): ?float
{
return $this->amount;
}
public function setAmount(float $amount): self
{
$this->amount = $amount;
return $this;
}
public function getSentAt(): ?\DateTimeInterface
{
return $this->sentAt;
}
public function setSentAt(\DateTimeInterface $sentAt): self
{
$this->sentAt = $sentAt;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer(?Customer $customer): self
{
$this->customer = $customer;
return $this;
}
public function getChrono(): ?int
{
return $this->chrono;
}
public function setChrono(int $chrono): self
{
$this->chrono = $chrono;
return $this;
} }
Thank you for your help

Related

API Platform Many to One not expecting IRI

I am using API Platform with Symfony for my backend.
I have 2 entities linked with a ManyToOne relationship, Booking and User.
A user can have one or many bookings.
I also have another entity Service, with a OneToMany relationship with Booking.
When I try to test the POST for Bookings on the Swagger interface I get an error on the IRI format for services but not for the others.
Nothing works as input for the fields related to User (provider, client).
I don't understand why it doesn't work. I only get a 400 error.
Here are my entities :
Booking:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\BookingRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={"groups"={"booking:read"}},
* denormalizationContext={"groups"={"booking:write"}},
* collectionOperations={
* "get",
* "post"={"security"="is_granted('ROLE_USER')"}
* },
* itemOperations={
* "get",
* "put"={"security"="is_granted('edit', object)"},
* "patch"={"security"="is_granted('edit', object)"},
* "delete"={"security"="is_granted('delete', object)"}
* }
* )
* #ORM\Entity(repositoryClass=BookingRepository::class)
*/
class Booking
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*
* #Groups("booking:read")
*/
private $id;
/**
* #ORM\Column(type="date")
*
* #Groups({"booking:read","booking:write"})
*/
private $bookingDate;
/**
* #ORM\Column(type="datetime_immutable")
*
* #Groups("booking:read")
*/
private $reservedAt;
/**
* #ORM\Column(type="string", length=255)
*
* #Groups({"booking:read","booking:write"})
*/
private $location;
/**
* #ORM\Column(type="time")
*
* #Groups({"booking:read","booking:write"})
*/
private $startTime;
/**
* #ORM\Column(type="time")
*
* #Groups({"booking:read","booking:write"})
*/
private $endTime;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="bookingsAsProvider")
* #ORM\JoinColumn(nullable=false)
*
* #Groups({"booking:read","booking:write"})
*/
private $provider;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="bookingsAsClient")
* #ORM\JoinColumn(nullable=false)
*
* #Groups({"booking:read","booking:write"})
*/
private $client;
/**
* #ORM\ManyToOne(targetEntity=Service::class, inversedBy="bookings")
* #ORM\JoinColumn(nullable=false)
* #Groups({"booking:read","booking:write"})
*/
private $service;
/**
* #ORM\Column(type="integer")
* #Groups({"booking:read","booking:write"})
*/
private $state;
/**
* #ORM\Column(type="boolean")
* #Groups({"booking:read","booking:write"})
*/
private $read;
public function getId(): ?int
{
return $this->id;
}
public function getBookingDate(): ?\DateTimeInterface
{
return $this->bookingDate;
}
public function setBookingDate(\DateTimeInterface $bookingDate): self
{
$this->bookingDate = $bookingDate;
return $this;
}
public function getReservedAt(): ?\DateTimeImmutable
{
return $this->reservedAt;
}
public function setReservedAt(\DateTimeImmutable $reservedAt): self
{
$this->reservedAt = $reservedAt;
return $this;
}
public function getLocation(): ?string
{
return $this->location;
}
public function setLocation(string $location): self
{
$this->location = $location;
return $this;
}
public function getStartTime(): ?\DateTimeInterface
{
return $this->startTime;
}
public function setStartTime(\DateTimeInterface $startTime): self
{
$this->startTime = $startTime;
return $this;
}
public function getEndTime(): ?\DateTimeInterface
{
return $this->endTime;
}
public function setEndTime(\DateTimeInterface $endTime): self
{
$this->endTime = $endTime;
return $this;
}
public function getProvider(): ?User
{
return $this->provider;
}
public function setProvider(?User $provider): self
{
$this->provider = $provider;
return $this;
}
public function getClient(): ?User
{
return $this->client;
}
public function setClient(?User $client): self
{
$this->client = $client;
return $this;
}
public function getService(): ?Service
{
return $this->service;
}
public function setService(?Service $service): self
{
$this->service = $service;
return $this;
}
public function getState(): ?int
{
return $this->state;
}
public function setState(int $state): self
{
$this->state = $state;
return $this;
}
public function getRead(): ?bool
{
return $this->read;
}
public function setRead(bool $read): self
{
$this->read = $read;
return $this;
}
}
User:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
*
* #ApiResource(
* normalizationContext={"groups"={"user:read"}},
* denormalizationContext={"groups"={"user:write"}},
* collectionOperations={
* "get"={"security"="is_granted('ROLE_ADMIN') or object == user"},
* "post"={"security"="is_granted('ROLE_ADMIN_FRONTEND')"}
* },
* itemOperations={
* "get",
* "put"={"security"="is_granted('ROLE_ADMIN') or object == user"},
* "patch"={"security"="is_granted('ROLE_ADMIN') or object == user"},
* "delete"={"security"="is_granted('ROLE_ADMIN')"},
* "get_by_role" = {
* "method" = "GET",
* "path" = "/user/{role}",
* "controller" = User::class,
* "read"=false,
* "openapi_context" = {
* "parameters" = {
* {
* "name" = "role",
* "in" = "path",
* "description" = "The role of a user",
* "type" = "string",
* "required" = true,
* "example"= "ROLE_PARENT",
* },
* },
* },
* },
* },
* )
*
* #ORM\Table(name="`user`")
*/
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*
* #Groups({"user:read","service:read","booking:read"})
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $email;
/**
* #ORM\Column(type="json")
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password;
/**
* #Groups("user:write")
*
* #SerializedName("password")
*/
private $plainPassword;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read","booking:read"})
*/
private $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read","booking:read"})
*/
private $firstname;
/**
* #ORM\Column(type="string", length=255, unique=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $username;
/**
* #ORM\Column(type="string", length=50, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $phone;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $facebook;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $instagram;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $linkedin;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $twitter;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $pinterest;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $website;
/**
* #ORM\Column(type="text", nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $tagline;
/**
* #ORM\Column(type="text", nullable=true)
*
* #Groups({"user:read", "user:write","businessRelationship:read","service:read"})
*/
private $description;
/**
* #ORM\OneToMany(targetEntity=Address::class, mappedBy="client",cascade={"persist"})
*
* #Groups({"user:read", "user:write"})
* #ApiSubresource
*/
private $addresses;
/**
* #ORM\ManyToMany(targetEntity=Service::class, mappedBy="performer")
* #ApiSubresource
*/
private $servicesAsPerformer;
/**
* #ORM\OneToMany(targetEntity=Service::class, mappedBy="owner")
* #ApiSubresource
*/
private $servicesAsOwner;
/**
* #ORM\OneToMany(targetEntity=BusinessRelationship::class, mappedBy="partnerA")
* #ApiSubresource
*/
private $businessRelationshipsPartnerA;
/**
* #ORM\OneToMany(targetEntity=BusinessRelationship::class, mappedBy="partnerB")
* #ApiSubresource
*/
private $businessRelationshipsPartnerB;
/**
* #ORM\OneToMany(targetEntity=Booking::class, mappedBy="provider")
* #ApiSubresource
*/
private $bookingsAsProvider;
/**
* #ORM\OneToMany(targetEntity=Booking::class, mappedBy="client")
* #ApiSubresource
*/
private $bookingsAsClient;
/**
* #ORM\OneToMany(targetEntity=Schedule::class, mappedBy="provider")
* #ApiSubresource
*/
private $schedules;
/**
* #ORM\OneToMany(targetEntity=UserCategory::class, mappedBy="provider")
* #ApiSubresource
*
* #Groups({"user:read", "user:write"})
*/
private $userCategories;
/**
* #ORM\Column(type="text", nullable=true)
* #Groups({"user:read", "user:write"})
*/
private $profilePicture;
/**
* #ORM\Column(type="text", length=16777215, nullable=true)
* #Groups({"user:read", "user:write"})
*/
private $gallery;
/**
* #ORM\OneToMany(targetEntity=Notification::class, mappedBy="userOrigin")
* #ApiSubresource
*
* #Groups({"user:read", "user:write"})
*/
private $notificationsUserOrigin;
/**
* #ORM\OneToMany(targetEntity=Notification::class, mappedBy="userTarget")
* #ApiSubresource
*
* #Groups({"user:read", "user:write"})
*/
private $notificationsUserTarget;
/**
* #ORM\Column(type="string", length=100, nullable=true)
*/
private $resetToken;
public function __construct()
{
$this->addresses = new ArrayCollection();
$this->servicesAsPerformer = new ArrayCollection();
$this->servicesAsOwner = new ArrayCollection();
$this->businessRelationshipsPartnerA = new ArrayCollection();
$this->businessRelationshipsPartnerB = new ArrayCollection();
$this->bookingsAsProvider = new ArrayCollection();
$this->bookingsAsClient = new ArrayCollection();
$this->schedules = new ArrayCollection();
$this->userCategories = new ArrayCollection();
$this->notificationsUserOrigin = new ArrayCollection();
$this->notificationsUserTarget = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
/**
* #deprecated since Symfony 5.3, use getUserIdentifier instead
*/
// public function getUsername(): string
// {
// return (string) $this->email;
// }
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* Returning a salt is only needed, if you are not using a modern
* hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
*
* #see UserInterface
*/
public function getSalt(): ?string
{
return null;
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
$this->plainPassword = null;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getFirstname(): ?string
{
return $this->firstname;
}
public function setFirstname(?string $firstname): self
{
$this->firstname = $firstname;
return $this;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): self
{
$this->phone = $phone;
return $this;
}
public function getFacebook(): ?string
{
return $this->facebook;
}
public function setFacebook(?string $facebook): self
{
$this->facebook = $facebook;
return $this;
}
public function getInstagram(): ?string
{
return $this->instagram;
}
public function setInstagram(?string $instagram): self
{
$this->instagram = $instagram;
return $this;
}
public function getLinkedin(): ?string
{
return $this->linkedin;
}
public function setLinkedin(?string $linkedin): self
{
$this->linkedin = $linkedin;
return $this;
}
public function getTwitter(): ?string
{
return $this->twitter;
}
public function setTwitter(?string $twitter): self
{
$this->twitter = $twitter;
return $this;
}
public function getPinterest(): ?string
{
return $this->pinterest;
}
public function setPinterest(?string $pinterest): self
{
$this->pinterest = $pinterest;
return $this;
}
public function getWebsite(): ?string
{
return $this->website;
}
public function setWebsite(?string $website): self
{
$this->website = $website;
return $this;
}
public function getTagline(): ?string
{
return $this->tagline;
}
public function setTagline(?string $tagline): self
{
$this->tagline = $tagline;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getPlainPassword(): ?string
{
return $this->plainPassword;
}
public function setPlainPassword(?string $plainPassword): self
{
$this->plainPassword = $plainPassword;
return $this;
}
/**
* #return Collection|Address[]
*/
public function getAddresses(): Collection
{
return $this->addresses;
}
public function addAddress(Address $address): self
{
if (!$this->addresses->contains($address)) {
$this->addresses[] = $address;
$address->setClient($this);
}
return $this;
}
public function removeAddress(Address $address): self
{
if ($this->addresses->removeElement($address)) {
// set the owning side to null (unless already changed)
if ($address->getClient() === $this) {
$address->setClient(null);
}
}
return $this;
}
public function hasRoles(string $roles): bool
{
return in_array($roles, $this->roles);
}
/**
* #return Collection|Service[]
*/
public function getServicesAsPerformer(): Collection
{
return $this->servicesAsPerformer;
}
public function addServicesAsPerformer(Service $servicesAsPerformer): self
{
if (!$this->servicesAsPerformer->contains($servicesAsPerformer)) {
$this->servicesAsPerformer[] = $servicesAsPerformer;
$servicesAsPerformer->addPerformer($this);
}
return $this;
}
public function removeServicesAsPerformer(Service $servicesAsPerformer): self
{
if ($this->servicesAsPerformer->removeElement($servicesAsPerformer)) {
$servicesAsPerformer->removePerformer($this);
}
return $this;
}
/**
* #return Collection|Service[]
*/
public function getServicesAsOwner(): Collection
{
return $this->servicesAsOwner;
}
public function addServicesAsOwner(Service $servicesAsOwner): self
{
if (!$this->servicesAsOwner->contains($servicesAsOwner)) {
$this->servicesAsOwner[] = $servicesAsOwner;
$servicesAsOwner->setOwner($this);
}
return $this;
}
public function removeServicesAsOwner(Service $servicesAsOwner): self
{
if ($this->servicesAsOwner->removeElement($servicesAsOwner)) {
// set the owning side to null (unless already changed)
if ($servicesAsOwner->getOwner() === $this) {
$servicesAsOwner->setOwner(null);
}
}
return $this;
}
/**
* #return Collection|BusinessRelationship[]
*/
public function getBusinessRelationshipsPartnerA(): Collection
{
return $this->businessRelationshipsPartnerA;
}
public function addBusinessRelationshipsPartnerA(BusinessRelationship $businessRelationshipsPartnerA): self
{
if (!$this->businessRelationshipsPartnerA->contains($businessRelationshipsPartnerA)) {
$this->businessRelationshipsPartnerA[] = $businessRelationshipsPartnerA;
$businessRelationshipsPartnerA->setPartnerA($this);
}
return $this;
}
public function removeBusinessRelationshipsPartnerA(BusinessRelationship $businessRelationshipsPartnerA): self
{
if ($this->businessRelationshipsPartnerA->removeElement($businessRelationshipsPartnerA)) {
// set the owning side to null (unless already changed)
if ($businessRelationshipsPartnerA->getPartnerA() === $this) {
$businessRelationshipsPartnerA->setPartnerA(null);
}
}
return $this;
}
/**
* #return Collection|BusinessRelationship[]
*/
public function getBusinessRelationshipsPartnerB(): Collection
{
return $this->businessRelationshipsPartnerB;
}
public function addBusinessRelationshipsPartnerB(BusinessRelationship $businessRelationshipsPartnerB): self
{
if (!$this->businessRelationshipsPartnerB->contains($businessRelationshipsPartnerB)) {
$this->businessRelationshipsPartnerB[] = $businessRelationshipsPartnerB;
$businessRelationshipsPartnerB->setPartnerB($this);
}
return $this;
}
public function removeBusinessRelationshipsPartnerB(BusinessRelationship $businessRelationshipsPartnerB): self
{
if ($this->businessRelationshipsPartnerB->removeElement($businessRelationshipsPartnerB)) {
// set the owning side to null (unless already changed)
if ($businessRelationshipsPartnerB->getPartnerB() === $this) {
$businessRelationshipsPartnerB->setPartnerB(null);
}
}
return $this;
}
/**
* #return Collection|Booking[]
*/
public function getBookingsAsProvider(): Collection
{
return $this->bookingsAsProvider;
}
public function addBookingsAsProvider(Booking $bookingsAsProvider): self
{
if (!$this->bookingsAsProvider->contains($bookingsAsProvider)) {
$this->bookingsAsProvider[] = $bookingsAsProvider;
$bookingsAsProvider->setProvider($this);
}
return $this;
}
public function removeBookingsAsProvider(Booking $bookingsAsProvider): self
{
if ($this->bookingsAsProvider->removeElement($bookingsAsProvider)) {
// set the owning side to null (unless already changed)
if ($bookingsAsProvider->getProvider() === $this) {
$bookingsAsProvider->setProvider(null);
}
}
return $this;
}
/**
* #return Collection|Booking[]
*/
public function getBookingsAsClient(): Collection
{
return $this->bookingsAsClient;
}
public function addBookingsAsClient(Booking $bookingsAsClient): self
{
if (!$this->bookingsAsClient->contains($bookingsAsClient)) {
$this->bookingsAsClient[] = $bookingsAsClient;
$bookingsAsClient->setClient($this);
}
return $this;
}
public function removeBookingsAsClient(Booking $bookingsAsClient): self
{
if ($this->bookingsAsClient->removeElement($bookingsAsClient)) {
// set the owning side to null (unless already changed)
if ($bookingsAsClient->getClient() === $this) {
$bookingsAsClient->setClient(null);
}
}
return $this;
}
[...]
}
Service:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use App\Repository\ServiceRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={"groups"={"service:read"}},
* denormalizationContext={"groups"={"service:write"}},
* collectionOperations={
* "get",
* "post"={"security"="is_granted('ROLE_USER')"}
* },
* itemOperations={
* "get",
* "put"={"security"="is_granted('edit', object)"},
* "patch"={"security"="is_granted('edit', object)"},
* "delete"={"security"="is_granted('delete', object)"}
* }
* )
* #ORM\Entity(repositoryClass=ServiceRepository::class)
*/
class Service
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*
* #Groups({"service:read","schedule:read"})
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*
* #Groups({"service:read", "service:write","schedule:read"})
*/
private $name;
/**
* #ORM\Column(type="float")
*
* #Groups({"service:read", "service:write","schedule:read"})
*/
private $price;
/**
* #ORM\Column(type="text", nullable=true)
*
* #Groups({"service:read", "service:write","schedule:read"})
*/
private $description;
/**
* #ORM\ManyToMany(targetEntity=Address::class, inversedBy="services")
*
* #Groups({"service:read", "service:write"})
* #ApiSubresource
*/
private $addresses;
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="servicesAsPerformer")
* #Groups({"service:read", "service:write","schedule:read"})
*/
private $performer;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="servicesAsOwner")
* #Groups({"service:read", "service:write","schedule:read"})
*/
private $owner;
/**
* #ORM\ManyToMany(targetEntity=Schedule::class, mappedBy="services")
* #Groups({"service:read", "service:write"})
* #ApiSubresource
*/
private $schedules;
/**
* #ORM\OneToMany(targetEntity=Booking::class, mappedBy="service")
*/
private $bookings;
public function __construct()
{
$this->addresses = new ArrayCollection();
$this->performer = new ArrayCollection();
$this->schedules = new ArrayCollection();
$this->bookings = new ArrayCollection();
}
[...]
}
Here are the JSON inputs I tried with the response I get :
Error 400 "Syntax Error"
{
"bookingDate": "2022-11-14T14:59:49.322Z",
"location": "string",
"startTime": "2022-11-14T14:59:49.322Z",
"endTime": "2022-11-14T14:59:49.322Z",
"provider": "string",
"client": "string",
"service": "\api\services\725",
"state": 0,
"read": true
}
Error 400 "Invalid IRI "string"."
{
"bookingDate": "2022-11-14T14:59:49.322Z",
"location": "string",
"startTime": "2022-11-14T14:59:49.322Z",
"endTime": "2022-11-14T14:59:49.322Z",
"provider": "string",
"client": "string",
"service": "string",
"state": 0,
"read": true
}
I really don't see why for service it expects an IRI format, while not for client and provider.

SQLSTATE[42S22]: Column not found: 1054 Champ 't0.id' inconnu dans where clause ( Symfony 5 , API Platform )

I have 2 classes , Class Child "Livreur" inherite from Class Parent "Users" .
Problem in return data after insert by API Plateform . (it inserted by success but data deosn't returned + doesn't insert in table Users, before that it inserted in Users+Livreur but now no ).
Class "Users" (parent) :
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\UsersRepository;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping ;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass=UsersRepository::class)
* #ApiResource(
* normalizationContext={"groups"={"read"}},
* collectionOperations={"post"={},"get"={}},
* itemOperations={"get","put"={"denormalization_Context"={"groups"={"put"}}}}
* )
*/
class Users implements UserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180)
* #Groups({"read"})
*/
private $email;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=255)
* #Groups({"read"})
* #Groups({"put"})
*/
private $password;
/**
* #Assert\NotBlank()
* #Assert\Expression("this.getPassword() == this.getRepassword()",message="Mot de pass doit etre le meme dans les 2 deux champs")
*/
private $repassword;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=30)
* #Groups({"read"})
* #Groups({"put"})
*/
private $username;
/**
* #Assert\NotBlank()
* #ORM\Column(type="text")
* #Groups({"read"})
* #Groups({"put"})
*/
private $roles;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=20)
* #Groups({"read"})
*/
private $cin;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=20)
* #Groups({"read"})
*/
private $nom;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=20)
* #Groups({"read"})
*/
private $prenom;
/**
* #Assert\NotBlank()
* #ORM\Column(type="date")
* #Groups({"read"})
*/
private $dtn;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"read"})
*/
private $dtype;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"read"})
*/
private $img;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=30, nullable=true)
* #Groups({"read"})
* #Groups({"put"})
*/
private $rib;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"read"})
* #Groups({"put"})
*/
private $adresse;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string", length=20)
* #Groups({"read"})
* #Groups({"put"})
*/
private $tel;
protected function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getRoles(): array
{
return array('ROLE_USER');
}
public function setRoles(string $roles): self
{
$this->roles = $roles;
return $this;
}
public function getCin(): ?string
{
return $this->cin;
}
public function setCin(string $cin): self
{
$this->cin = $cin;
return $this;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
public function getPrenom(): ?string
{
return $this->prenom;
}
public function setPrenom(string $prenom): self
{
$this->prenom = $prenom;
return $this;
}
public function getDtn(): ?\DateTimeInterface
{
return $this->dtn;
}
public function setDtn(\DateTimeInterface $dtn): self
{
$this->dtn = $dtn;
return $this;
}
public function getDtype(): ?string
{
return $this->dtype;
}
public function setDtype(?string $dtype): self
{
$this->dtype = $dtype;
return $this;
}
public function getImg(): ?string
{
return $this->img;
}
public function setImg(?string $img): self
{
$this->img = $img;
return $this;
}
public function getRib(): ?string
{
return $this->rib;
}
public function setRib(?string $rib): self
{
$this->rib = $rib;
return $this;
}
public function getAdresse(): ?string
{
return $this->adresse;
}
public function setAdresse(?string $adresse): self
{
$this->adresse = $adresse;
return $this;
}
public function getTel(): ?string
{
return $this->tel;
}
public function setTel(string $tel): self
{
$this->tel = $tel;
return $this;
}
public function getSalt()
{
// TODO: Implement getSalt() method.
}
public function eraseCredentials()
{
// TODO: Implement eraseCredentials() method.
}
public function getRepassword()
{
return $this->repassword;
}
public function setRepassword($repassword): void
{
$this->repassword = $repassword;
}
}
Class Livreur (child) :
<?php
namespace App\Entity;
use App\Repository\LivreurRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiResource;
/**
* #ORM\Entity(repositoryClass=LivreurRepository::class)
* #ApiResource()
*/
class Livreur extends Users
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=20)
*/
private $type_vehicule;
/**
* #ORM\Column(type="string", length=20)
*/
private $permis;
/**
* #ORM\Column(type="boolean")
*/
private $disponibilite;
/**
* #ORM\Column(type="float")
*/
private $coffre;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $log;
/**
* #ORM\OneToMany(targetEntity=Commande::class, mappedBy="livreur")
*/
private $commandes;
/**
* #ORM\OneToMany(targetEntity=Conge::class, mappedBy="livreur")
*/
private $conges;
/**
* #ORM\ManyToOne(targetEntity=Agence::class, inversedBy="livreurs")
* #ORM\JoinColumn(nullable=false)
*/
private $agence;
/**
* #ORM\OneToOne(targetEntity=SalaireEmp::class, inversedBy="livreur", cascade={"persist", "remove"})
*/
private $salaire_emp;
/**
* #ORM\ManyToOne(targetEntity=Ville::class, inversedBy="livreurs")
* #ORM\JoinColumn(nullable=false)
*/
private $ville;
public function __construct()
{
$this->commandes = new ArrayCollection();
$this->conges = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTypeVehicule(): ?string
{
return $this->type_vehicule;
}
public function setTypeVehicule(string $type_vehicule): self
{
$this->type_vehicule = $type_vehicule;
return $this;
}
public function getPermis(): ?string
{
return $this->permis;
}
public function setPermis(string $permis): self
{
$this->permis = $permis;
return $this;
}
public function getDisponibilite(): ?int
{
return $this->disponibilite;
}
public function setDisponibilite(int $disponibilite): self
{
$this->disponibilite = $disponibilite;
return $this;
}
public function getCoffre(): ?float
{
return $this->coffre;
}
public function setCoffre(float $coffre): self
{
$this->coffre = $coffre;
return $this;
}
public function getLog(): ?string
{
return $this->log;
}
public function setLog(?string $log): self
{
$this->log = $log;
return $this;
}
/**
* #return Collection|Commande[]
*/
public function getCommandes(): Collection
{
return $this->commandes;
}
public function addCommande(Commande $commande): self
{
if (!$this->commandes->contains($commande)) {
$this->commandes[] = $commande;
$commande->setLivreur($this);
}
return $this;
}
public function removeCommande(Commande $commande): self
{
if ($this->commandes->removeElement($commande)) {
// set the owning side to null (unless already changed)
if ($commande->getLivreur() === $this) {
$commande->setLivreur(null);
}
}
return $this;
}
/**
* #return Collection|Conge[]
*/
public function getConges(): Collection
{
return $this->conges;
}
public function addConge(Conge $conge): self
{
if (!$this->conges->contains($conge)) {
$this->conges[] = $conge;
$conge->setLivreur($this);
}
return $this;
}
public function removeConge(Conge $conge): self
{
if ($this->conges->removeElement($conge)) {
// set the owning side to null (unless already changed)
if ($conge->getLivreur() === $this) {
$conge->setLivreur(null);
}
}
return $this;
}
public function getAgence(): ?Agence
{
return $this->agence;
}
public function setAgence(?Agence $agence): self
{
$this->agence = $agence;
return $this;
}
public function getSalaireEmp(): ?SalaireEmp
{
return $this->salaire_emp;
}
public function setSalaireEmp(?SalaireEmp $salaire_emp): self
{
$this->salaire_emp = $salaire_emp;
return $this;
}
public function getVille(): ?Ville
{
return $this->ville;
}
public function setVille(?Ville $ville): self
{
$this->ville = $ville;
return $this;
}
}
Looks like you forgot to set an inheritance mapping strategy. Here is an example:
// (..)
/**
* #ORM\Entity(repositoryClass=UsersRepository::class)
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"users" = "Users", "livreur" = "Livreur"})
* #ApiResource(
* normalizationContext={"groups"={"read"}},
* collectionOperations={"post"={},"get"={}},
* itemOperations={"get","put"={"denormalization_Context"={"groups"={"put"}}}}
* )
*/
class Users implements UserInterface
{
// (..)
This will add an extra field "discr" to the tables of both your classes so you will have to update their table configurations, for example with:
bin/console doctrine:schema:update --force
or if you use migrations:
bin/console doctrine:migrations:diff
bin/console doctrine:migrations:migrate
For explanation of Mapping Strategies and their alternatives see the Inheritance Mapping page on doctrine-project.org

Set default role for User Entity

When new user register, if there is no role set, automatically to set default role (the lowest in hierarchy). I already created relation "Many to Many" via migrations and have three tables: users, roles, user_roles. So the main goal is to have at least one relation in user_roles for every user.
Below are listed both entities of Users and Roles
Users Entity
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={
* "groups"={"read"}
* }
* )
* #ORM\Entity(repositoryClass=UserRepository::class)
* #UniqueEntity("username")
* #UniqueEntity("email")
*/
class User implements UserInterface
{
public function __construct()
{
$this->roles = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read"})
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
* #Groups({"read"})
* #Assert\NotBlank()
* #Assert\Length(min=3, max=100)
*/
private $username;
/**
* #ORM\Column(type="string", length=150)
* #Assert\NotBlank()
* #Assert\Length(min=3, max=100)
*/
private $password;
/**
* #ORM\Column(type="string", length=150)
* #Groups({"read"})
* #Assert\NotBlank()
* #Assert\Email()
*/
private $email;
/**
* #ORM\Column(type="string", length=150)
* #Groups({"read"})
* #Assert\NotBlank()
* #Assert\Length(min=3, max=100)
*/
private $firstname;
/**
* #ORM\Column(type="string", length=150)
* #Groups({"read"})
* #Assert\NotBlank()
* #Assert\Length(min=3, max=100)
*/
private $lastname;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Roles", inversedBy="users")
* #Groups({"read"})
*/
private $roles;
public function getId(): ?int
{
return $this->id;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getFirstname(): ?string
{
return $this->firstname;
}
public function setFirstname(string $firstname): self
{
$this->firstname = $firstname;
return $this;
}
public function getLastname(): string
{
return $this->lastname;
}
public function setLastname(string $lastname): self
{
$this->lastname = $lastname;
return $this;
}
/**
* #return array
*/
public function getRoles(): array
{
return $this->roles->toArray();
}
/**
* #param Roles $role
* #return $this
*/
public function addRole(Roles $role) : self
{
if(!$this->roles->contains($role)) {
$this->roles[] = $role;
}
return $this;
}
/**
* #param Roles $role
* #return $this
*/
public function deleteRole(Roles $role) : self
{
if($this->roles->contains($role)) {
$this->roles->removeElement($role);
}
return $this;
}
}
Roles Entity:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\RolesRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={
* "groups"={"read"}
* }
* )
* #ORM\Entity(repositoryClass=RolesRepository::class)
*/
class Roles
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
* #Groups({"read"})
*/
private $sysName;
/**
* #ORM\Column(type="string", length=50)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User", mappedBy="roles")
*/
private $users;
public function getId(): ?int
{
return $this->id;
}
public function getSysName(): ?string
{
return $this->sysName;
}
public function setSysName(string $sysName): self
{
$this->sysName = $sysName;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}
If you don't want to have a relation for every default user<->role you could extend the getRoles() method by adding your default role.
I did something similar in one of my projects, it looked like this:
public function getRoles()
{
if (count($this->getRole())) {
foreach ($this->getRole() as $role) {
$roles[] = $role->getRole();
}
} else {
$roles = ['ROLE_USER'];
}
return $roles;
}

Api plateform denormalization custom operation with relation

I have 2 entities Voucher and Client (which extend User entity) with a OneToOne relation, I have a custom operation in the voucher entity, I want to denormalize the the client entity in this operation ( to be able to validate the properties later) but it won't show in the swagger documentation
Voucher Entity :
<?php
/**
* #ApiResource(
* collectionOperations={
* "add_voucher"={
* "access_control"="is_granted('ROLE_COMMERCIAL')",
* "method"="POST",
* "path"="/vouchers/add-new",
* "controller"=AddVoucherAction::class,
* "security_post_denormalize_message"="Sorry, Only Commercials can Generate Vouchers",
* "denormalization_context"={
* "groups"={"add_new_voucher"}
* },
* "validation_groups"={"Default", "add_voucher_validation"}
* },
* }
* )
* #ORM\Entity(repositoryClass="App\Repository\VoucherRepository", repositoryClass=VoucherRepository::class)
*/
class Voucher
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #Groups("add_new_voucher")
* #ORM\Column(type="string", length=255, unique=true)
*/
private $code;
/**
* #Groups("add_new_voucher")
* #ORM\Column(type="integer")
*/
private $discount;
/**
* #Groups("add_new_voucher")
* #OneToOne(targetEntity="App\Entity\Client")
* #JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
public function getDiscount()
{
return $this->discount;
}
public function setDiscount($discount): void
{
$this->discount = $discount;
}
public function getClient()
{
return $this->client;
}
public function setClient($client): void
{
$this->client = $client;
}
public function getId(): ?int
{
return $this->id;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
}
Client Entity :
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\ClientRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use App\Entity\Language;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ApiResource(
* collectionOperations={
* "post"={
* "method"="POST",
* "validation_groups"={"registerValidation"},
* }
* },
* denormalizationContext={"groups"={"register"}}
* )
* #ORM\Entity(repositoryClass=ClientRepository::class)
*/
class Client extends User
{
/**
* #Groups("register")
* #ORM\ManyToOne(targetEntity=Language::class, inversedBy="client")
*/
private $language;
/**
* #Groups({"register","add_new_voucher"})
* #Assert\NotBlank(groups="registerValidation")
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $country;
/**
* #Groups("register")
* #Assert\NotBlank(groups="registerValidation")
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $currency;
/**
* #Groups("register")
* #Assert\NotBlank(groups="registerValidation")
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $timezone;
/**
* #Groups("register")
* #Assert\NotBlank(groups="registerValidation")
* #ORM\Column(type="integer", nullable=true)
*/
private $phone;
/**
* Client constructor.
* #param $language
* #param $country
* #param $currency
* #param $timezone
* #param $phone
*/
public function __construct($language, $country, $currency, $timezone, $phone)
{
parent:: __construct();
$this->language = $language;
$this->country = $country;
$this->currency = $currency;
$this->timezone = $timezone;
$this->phone = $phone;
}
public function getLanguage()
{
return $this->language;
}
public function setLanguage($language): void
{
$this->language = $language;
}
public function getCountry(): ?string
{
return $this->country;
}
public function setCountry(?string $country): self
{
$this->country = $country;
return $this;
}
public function getCurrency(): ?string
{
return $this->currency;
}
public function setCurrency(?string $currency): self
{
$this->currency = $currency;
return $this;
}
public function getTimezone(): ?string
{
return $this->timezone;
}
public function setTimezone(?string $timezone): self
{
$this->timezone = $timezone;
return $this;
}
public function getPhone(): ?int
{
return $this->phone;
}
public function setPhone(?int $phone): self
{
$this->phone = $phone;
return $this;
}
}
I tried to add the denormalization group to the client relation and to the country property in client entity but in swagger the operation show only the code and discount property

I have an error when using API platform SWAGGER on Symfony4 project

I made this for GET statement in the controller
<?php
namespace App\Controller\Api;
use App\Entity\Article;
use App\Factory\EntityFactory;
use App\Repository\ArticleRepository;
use Swagger\Annotations as SWG;
use Nelmio\ApiDocBundle\Annotation\Model;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Routing\Annotation\Route;
class ArticlesController
{
private $repository;
private $factory;
private $serializer;
public function __construct(ArticleRepository $repository, EntityFactory $entityFactory, SerializerInterface $serializer)
{
$this->repository = $repository;
$this->factory = $entityFactory;
$this->serializer = $serializer;
}
/**
* #Route(path="/articles/{article}", methods={"GET"}, name="article_get")
*
* #SWG\Get(
* tags={"Articles"},
* #SWG\Parameter(
* name="article",
* in="path",
* type="integer",
* description="Article ID",
* ),
* )
* #SWG\Response(
* response=200,
* description="Article fetched",
* #Model(type=Article::class, groups={"article:get", "article:category", "category:index"})
* )
*/
public function get(Article $article): JsonResponse
{
$data = $this->serializer->serialize($article, 'json', ['groups' => ['article:get', 'article:category', 'category:index']]);
return new JsonResponse($data, JsonResponse::HTTP_OK, [], true);
}
}
The entity from the article looks like this:
<?php
namespace App\Entity;
use App\Entity\User\User;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Swagger\Annotations as SWG;
/**
* #ORM\Entity(repositoryClass="App\Repository\ArticleRepository")
* #ORM\Table(name="articles")
* #ORM\HasLifecycleCallbacks
*/
class Article implements EntityInterface
{
/**
* #var int
*
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
* #Groups({"article:id", "article:get", "article:index"})
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"article:category"})
*
*/
private $title;
/**
* #ORM\Column(type="string", length=255)
* #Groups({"article:create", "article:get", "article:index", "article:update"})
*/
private $lead;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"article:create", "article:get", "article:index", "article:update"})
*/
private $slug;
/**
* #ORM\Column(type="text", nullable=true)
* #Groups({"article:create", "article:get", "article:index", "article:update"})
*/
private $content;
/**
* #ORM\Column(type="datetime")
* #Groups({"article:create", "article:get", "article:index", "article:update"})
* #SWG\Property(property="updated_at")
*/
private $publishedAt;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="articles")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
* #Groups({"article:category"})
*
*/
private $category;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User\User", inversedBy="articles")
* #ORM\JoinColumn(nullable=false)
* #Groups({"article:user"})
*/
private $author;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $articleFilename;
/**
* #ORM\Column(type="json_array", nullable=true)
*/
private $marking;
/**
* #ORM\Column(type="json_array", nullable=true)
*/
private $transitionContexts;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getLead(): ?string
{
return $this->lead;
}
public function setLead(string $lead): self
{
$this->lead = $lead;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getPublishedAt(): ?\DateTimeInterface
{
return $this->publishedAt;
}
public function setPublishedAt(\DateTimeInterface $publishedAt): self
{
$this->publishedAt = $publishedAt;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
public function getArticleFilename(): ?string
{
return $this->articleFilename;
}
public function setArticleFilename(?string $articleFilename): self
{
$this->articleFilename = $articleFilename;
return $this;
}
public function getImagePath()
{
return 'images/'.$this->getImageFilename();
}
public function getMarking()
{
return $this->marking;
}
public function setMarking($marking, $context = [])
{
$this->marking = $marking;
$this->transitionContexts[] = [
'new_marking' => $marking,
'context' => $context,
'time' => (new \DateTime())->format('c'),
];
}
public function getTransitionContexts()
{
return $this->transitionContexts;
}
public function setTransitionContexts($transitionContexts): self
{
$this->transitionContexts = $transitionContexts;
}
}
And when I go to http://localhost/docs I become this error. That my annotations are not enabled or installed. Thank you for your help.
Error message:
Exception thrown when handling an exception
(Symfony\Component\Config\Exception\LoaderLoadException: [Syntax
Error] Expected
Doctrine\Common\Annotations\DocLexer::T_CLOSE_CURLY_BRACES, got
'article' at position 179 in method
App\Controller\Api\ArticlesController::get() in
/app/config/routes/../../src/Controller/Api (which is being imported
from "/app/config/routes/annotations.yaml"). Make sure annotations are
installed and enabled.)

Categories