2

I use a platform to develop rest API, now when I have serialized data in normalize and denormalize I found an error . I use doctrine inheritance for entities, I have class person abstract class content commons attributes and I create class Partner, Participant, and declarant, all classes extend for person class, now when I add groups in Participant class I found error, the error is when I add a group in partner and declarant attributes it displays but when I add also a group in attributes class Person, attributes in class Participant is not display

Person entity:

<?php

    namespace App\Entity;

    use App\Repository\PersonRepository;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
    use Symfony\Component\Serializer\Annotation\Groups;

    /**
     * @ORM\Entity(repositoryClass=PersonRepository::class)
     * @ORM\InheritanceType("JOINED")
     * @ORM\DiscriminatorColumn(name="discr", type="string")
     * @ORM\DiscriminatorMap({"partner" = "Partner", "supplier" = "Supplier", "declaring"= "Declaring", "particpant"= "Particpant"})
     */
    abstract class Person
    {
       use ResourceId;
       use AbstractEntity;

        /**
         * @ORM\Column(type="string", length=255)
         * @Groups({"readPartner","writePartner","readDeclaring",
         * "writeDeclaring","readSupplier","writeSupplier","readParticpant","writeParticpant"})
         */
        private $firstName;

        /**
         * @ORM\Column(type="string", length=255)
         * @Groups({"readPartner","writePartner","readDeclaring",
         * "writeDeclaring","readSupplier","writeSupplier","readParticpant","writeParticpant"})
         */
        private $lastName;

        /**
         * @ORM\Column(type="string", length=255)
         * @Groups({"readPartner","writePartner","readDeclaring",
         * "writeDeclaring","readSupplier","writeSupplier"})
         */
        private $personalPhone;

        /**
         * @ORM\Column(type="string", length=255,nullable=true)
         * @Groups({"readPartner","writePartner","readDeclaring"
         * ,"writeDeclaring","readSupplier","writeSupplier"})
         */
        private $professionalPhone;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         * @Assert\Email(
         *     message = "The email '{{ value }}' is not a valid email."
         * )
         * @Groups({"readPartner","writePartner","readDeclaring",
         * "writeDeclaring","readSupplier","writeSupplier"})
         */
        private $email;

        /**
         * @ORM\Column(type="string", length=255)
         * @Groups({"readPartner","writePartner","readDeclaring"
         * ,"writeDeclaring","readSupplier","writeSupplier"})
         */
        private $organization;

        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 getPersonalPhone(): ?string
        {
        return $this->personalPhone;
        }

        public function setPersonalPhone(string $personalPhone): self
        {
        $this->personalPhone = $personalPhone;

        return $this;
        }

        public function getProfessionalPhone(): ?string
        {
        return $this->professionalPhone;
        }

        public function setProfessionalPhone(string $professionalPhone): self
        {
        $this->professionalPhone = $professionalPhone;

        return $this;
        }

        public function getEmail(): ?string
        {
        return $this->email;
        }

        public function setEmail(?string $email): self
        {
        $this->email = $email;

        return $this;
        }

        public function getOrganization(): ?string
        {
        return $this->organization;
        }

        public function setOrganization(string $organization): self
        {
        $this->organization = $organization;

        return $this;
        }

    }

Particpant entity:

<?php

    namespace App\Entity;

    use ApiPlatform\Core\Annotation\ApiResource;
    use App\Repository\ParticpantRepository;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Serializer\Annotation\Groups;
    /**
     * @ApiResource(
     *    normalizationContext={"groups"={"readParticpant"}},
     *    denormalizationContext={"groups"={"writeParticpant"}},
     * )
     * @ORM\Entity(repositoryClass=ParticpantRepository::class)
     */
    class Particpant extends Person
    {
       /**
        * @ORM\ManyToOne(targetEntity=Partner::class)
        * @ORM\JoinColumn(name="partner_id", referencedColumnName="id", nullable=true)
        * @Groups({"readParticpant","writeParticpant"})
        */
        protected $partner;

        /**
        * @ORM\ManyToOne(targetEntity=Declaring::class)
        * @ORM\JoinColumn(name="declaring_id", referencedColumnName="id", nullable=true)
        * @Groups({"readParticpant","writeParticpant"})
        */
        protected $declaring;


        /**
         * Get the value of partner
         */ 
        public function getPartner(): ?Partner
        {
        return $this->partner;
        }

        /**
         * Set the value of partner
         * @param Partner $partner
         * @return  self
         */ 
        public function setPartner(Partner $partner): self
        {
        $this->partner = $partner;

        return $this;
        }

        /**
         * Get the value of declaring
         */ 
        public function getDeclaring(): ?Declaring
        {
        return $this->declaring;
        }

        /**
         * Set the value of declaring
         * @param Declaring $declaring
         * @return  self
         */ 
        public function setDeclaring(Declaring $declaring): self
        {
        $this->declaring = $declaring;

        return $this;
        }
    }

How to display attributes of person entity and attribute of Participant also ..

3
  • Any help please Commented Jul 19, 2020 at 20:20
  • The given answer got an upvote, but there's actually a bug in ApiPlatform when it comes to handling inheritance through discriminated objects. See: github.com/api-platform/api-platform/issues/726 Commented Feb 3, 2021 at 7:30
  • Why are your Person properties private and your Particpant properties protected? I think you have them reversed so that reflection on Particpant can see the Person properties. Commented Mar 14, 2021 at 22:30

1 Answer 1

1

Even if doctrine supports inheritance very well , api-platform does not.

Deserialization ignore either parent class properties or child class properties.

The real question is why do you need inheritance ?

  1. to add a new entity class linked to Person ?
  2. to use polymorphism, like public function heal(Person $person): void {} ?
  3. to gather common properties ?

If it's the 1., you're quite screwed up. For example, suppose you want to add a Dog class:

/*
 * @ApiResource
 * @ORM\Entity
 */
class Dog
{
    /*
     * @Column
     */
    private $name;

    /*
     * @var Person
     * @ManyToOne(class="Person")
     */
    private $owner;
}

Even with a concrete Person class, the serialization won't work as expected, the IRI generation does not detects the child class. You won't see several Dog instances like this:

{"name": "Bar", "owner": "/participants/1"}
{"name": "Foo", "owner": "/partners/2"}
{"name": "Dummy", "owner": "/declarants/4"}

Api-platform will try to create IRIs containing the /persons string. Fetching a /persons retrieve Person properties only.

If it's the 2., your entities just need to implement a common interface, or you can use a visitor pattern.

If it's the 3., the common way is to use doctrine embeddable objects. They supports the @Groups annotation.

Sign up to request clarification or add additional context in comments.

2 Comments

my case is to add a new entity class linked to Person but i have error serializer , also in case 3 i found duplicate attirubtes in multiple table
For the linked class, you have to find by yourself the best way to do it. About duplicate attributes in multiple table, first this is the expected behaviour, second i think you misunderstand something. You are using Doctrine. Your database is driven by your entities. Embeddable objects allow you to declare once and only once your so called duplicated columns. Whenever you change something within the embeddable php class, those changes will be reproduced to all your tables with the next migration. In most case you have to ignore the database implementation using doctrine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.