Search code examples
symfonydoctrine-ormdoctrinesingle-table-inheritancediscriminator

Sensio ParamConverter STI abstract


Given an Single Table Inheritance for Location -> A and Location -> B

 * @DiscriminatorMap({
 *     "a" = "A",
 *     "b" = "B"
 * })
 * @Discriminator(field = "discr", map = {
 *     "a" = "A",
 *     "b" = "B",
 * })
abstract class Location 

In the Controller, i will send either an A or B type extending Location.

  /**
   * @Rest\Post("", name="create_l")
   * @ParamConverter("location", converter="fos_rest.request_body")
   */
  public function insert(Location $location): JsonResponse

Doctrine tells me the obvious message it cant instaniiate an abstract class, which is true but it should instead create the subtype.

If A comes in, it should be converted to A, not instantiiate Location.

Any solutions?


Solution

  • So, after doing some research and testing i fixed it myself.

    My core problem was that i mixed two Serializers, JMS and Symfony/Serializer. So i decided to go with the Symfony/Serializer as it enabled the creation of the subtypes of abstract classes. This is my setup:

    Imports & Entity:

    use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
    use Doctrine\ORM\Mapping as ORM;
    use Doctrine\ORM\Mapping\DiscriminatorColumn;
    use Doctrine\ORM\Mapping\InheritanceType;
    
    /**
     * @ORM\Entity(repositoryClass=AbstractParent::class)
     * @InheritanceType("SINGLE_TABLE")
     * @DiscriminatorColumn(name="discr", type="string")
     * @DiscriminatorMap(typeProperty="discr", mapping = {
     *     "a"      = "App\Entity\A",
     *     "b"      = "App\Entity\B",
     * })
     * @ORM\Table(
     *    name="abstract_parent",
     * )
     */
    abstract class AbstractParent extends PlaceComputable
    

    When sending a post request to save a subtype:

    /**
     * @Rest\Post("", name="create_subtype")
     * @ParamConverter("subtype", converter="fos_rest.request_body")
     */
    public function insert(AbstractParent $subtype): JsonResponse
    {
     // $subtype is now of Either Type 'A' or 'B'
     // depending on what 'discr' member was passed to the controller
    }
    

    Its is now also documented in the Symfony/Serializer documentation as to how convert subtypes of abstract classes.