1
votes

I need to display the "skill" of the "drivers" of specific "cars", which comes from a relational table "Relation_Car_Driver", this field should only appear for sub-resources calls "/cars/:id/drivers" and "/drivers/:id/cars"

I have 3 Tables :

  • Car (id, model)
  • Driver (id, name)
  • Relation_Car_Driver (id, car_id, driver_id, skill)

My main API resources are :

  • GET /cars
  • GET /cars/:id
  • GET /drivers
  • GET /drivers/id

My API sub resources are :

  • GET /drivers/:id/cars (list cars used by a specific driver)
  • GET /cars/:id/drivers (list drivers for a specific car)

For those sub-resources calls i want to return the "skill" value coming from their relation !

Entity Car :

# src/Entity/Car.php
namespace App\Entity;

/**
 * @ORM\Table(name="Car")
 * @ORM\Entity
 *
 * @ApiResource(
 *     subresourceOperations={
 *          "drivers_get_subresource"={
 *              "method"="GET",
 *              "path"="/cars/{id}/drivers"
 *          }
 *      }
 * )
 */
class Car
{
// ...
    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Driver", inversedBy="cars")
     * @JoinTable(name="Relation_Car_Driver",
     *      joinColumns={@JoinColumn(name="car_id", referencedColumnName="id")},
     *     inverseJoinColumns={@JoinColumn(name="driver_id", referencedColumnName="id")}
     * )
     * @ApiSubresource(maxDepth=1)
     */
    private $drivers;
}

Entity Driver :

# src/Entity/Driver.php
namespace App\Entity;

/**
 * @ORM\Table(name="Driver")
 * @ORM\Entity
 *
 * @ApiResource(
 *     subresourceOperations={
 *          "cars_get_subresource"={
 *              "method"="GET",
 *              "path"="/drivers/{id}/cars"
 *          }
 *      }
 * )
 */
class Driver
{
// ...
    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Car", inversedBy="drivers")
     * @JoinTable(name="Relation_Car_Driver",
     *      joinColumns={@JoinColumn(name="driver_id", referencedColumnName="id")},
     *     inverseJoinColumns={@JoinColumn(name="car_id", referencedColumnName="id")}
     * )
     * @ApiSubresource(maxDepth=1)
     */
    private $cars;
}

Entity Relation_Car_Driver :

<?php

namespace App\Entity;


/**
 * RelationCarDriver
 *
 * @ORM\Table(name="Relation_Car_Driver")
 * @ORM\Entity
 */
class RelationCarDriver
{
// ..
    /**
     * @var int|null
     *
     * @ORM\Column(name="skill", type="int", nullable=true)
     */
    private $skill;
}

Actual result from GET /drivers/:id/cars:

{
  "@context": "/api/contexts/Car",
  "@id": "/api/drivers/1/cars",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/api/cars/1",
      "@type": "Car",
      "id": 1,
      "model": "Mustang"
    },
    {
      "@id": "/api/cars/2",
      "@type": "Car",
      "id": 2,
      "model": "Chevrolet"
    }
  ],
  "hydra:totalItems": 2
}

Expected result from GET /drivers/:id/cars:

{
  "@context": "/api/contexts/Car",
  "@id": "/api/drivers/1/cars",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/api/cars/1",
      "@type": "Car",
      "id": 1,
      "model": "Mustang",
      "skill": 63
    },
    {
      "@id": "/api/cars/2",
      "@type": "Car",
      "id": 2,
      "model": "Chevrolet",
      "skill": 13
    }
  ],
  "hydra:totalItems": 2
}

I have no clue how to achieve that ? Thanks

1
doctrine can't handle adding an entity "as the many-to-many relation entity", instead, the relation entity (RelationCarDriver) must have two many-to-one relations, one to car, one to driver (and the many-to-many turn into one-to-many relations with the relation entity on both car and driver), then you probably have to add some logic to flatten that again... unless of course, api-platform has some logic that I don't know about, because I don't know api-platformJakumi

1 Answers

0
votes

I had a similar issue and just found your post. I managed to solve this using a group (eg: api_read) defined on the "Driver" entity, and adding that group to the "skill" property wil print it flattend out with "car" entity, thus achieving what u were looking for