'API Platform return deep association data

I would like to request data from API Platform such as I can get a list of book categories when I request a list of shops.

So I have 3 entities with ManyToMany associations: Shop <--> Book <--> Category

When I call the GET /shops endpoint, I'd like to get a list of shops and for each shop, a list of categories (depending on the books available in the shop). Something like:

{
  "@context": "/contexts/Shop",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/shops/1",
      "@type": "Shop",
      "name": "Shop 1",
      "categories": [
        {
          "id": "/categories/12"
          "@type": "Category"
          "name": "Novel"
        },
        {
          "id": "/categories/15"
          "@type": "Category"
          "name": "SF"
        }
      ]
    }
  ]
}

For now, I did it with a calculated field on the Shop entity:

#[Groups(['shop:collection:get'])]
public function getCategories(): array
{
    $categories = [];
    foreach ($this->getBooks() as $book) {
        foreach ($book->getCategories() as $category) {
            $categories[$category->getId()] = $category;
        }
    }

    return array_values($categories);
}

I also created a Doctrine Extension to add joins to the SQL query when I request a collection of shops to improve performance but I am not sure if that's a good practice...

Is there any other way to get the same JSON result?

I also tried to use addSelect() with the QueryBuilder inside the Doctrine Extension but then the shop data are stored as a sub object:

{
  "@context": "/contexts/Shop",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "0": {
        "@id": "/shops/1",
        "@type": "Shop",
        "name": "Shop 1",
      }
    }
  ]
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source