DiscriminatorMap de Doctrine avec Api-platform
Tags: api, symfony, doctrine, webdev
Published: 2024-07-05 14:40:25

Le `DiscriminatorMap` de Doctrine permet une gestion efficace des entités héritées. 
Nous allons prendre l'exemple simple d'une classe `Vehicle` pour créer deux classes qui vont en hériter : `Bike` et `Car`
qui ont des attributs différents mais auront les mêmes que `Vehicle`.
Avec Api-platform, on pourra faire un `GET /vehicles` pour avoir tous les vehicules 
`GET bikes` pour tous les bikes et `GET /cars`

```php
<?php

namespace App\Entity;

use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\VehicleRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: VehicleRepository::class)]
#[ORM\InheritanceType('JOINED')]
#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
#[ORM\DiscriminatorMap([
    'car' => Car::class,
    'bike' => Bike::class
])]
#[ApiResource]
#[ApiFilter(OrderFilter::class)]
class Vehicle
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[ApiFilter(SearchFilter::class, strategy: 'partial')]
    private ?string $brand = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $createdAt = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getBrand(): ?string
    {
        return $this->brand;
    }

    public function setBrand(string $brand): static
    {
        $this->brand = $brand;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function setCreatedAt(\DateTimeImmutable $createdAt): static
    {
        $this->createdAt = $createdAt;

        return $this;
    }
}
```

```php
<?php

namespace App\Entity;

use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\BikeRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: BikeRepository::class)]
#[ApiResource]
#[ApiFilter(OrderFilter::class)]
class Bike extends Vehicle
{
    #[ORM\Column]
    private ?bool $hasCarrier = null;

    public function hasCarrier(): ?bool
    {
        return $this->hasCarrier;
    }

    public function setHasCarrier(bool $hasCarrier): static
    {
        $this->hasCarrier = $hasCarrier;

        return $this;
    }
}
```

```php
<?php

namespace App\Entity;

use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\CarRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: CarRepository::class)]
#[ApiResource]
#[ApiFilter(OrderFilter::class)]
class Car extends Vehicle
{
    #[ORM\Column]
    private ?int $numberOfDoors = null;

    public function getNumberOfDoors(): ?int
    {
        return $this->numberOfDoors;
    }

    public function setNumberOfDoors(int $numberOfDoors): static
    {
        $this->numberOfDoors = $numberOfDoors;

        return $this;
    }
}
```

Tout ce fait avec 
```php
#[ORM\InheritanceType('JOINED')]
#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
#[ORM\DiscriminatorMap([
    'car' => Car::class,
    'bike' => Bike::class
])]
```

`InheritanceType` peut également être `SINGLE_TABLE` ce qui signifie que vous n'aurez qu'une seule table pour toutes vos entités

N'oubliez pas également sur les autres classes de rajouter `extends Vehicle`

Fusée 🚀