API Platform : ordonner une collection au sein d'une entité sur une méthode GET

Pas Getcollection, juste Get.

Le problème exposé dans ce sujet a été résolu.

Bonjour,

J’ai un petit souci sur une entité et la bonne façon de gérer son affichage.

Soit une entité Recipe (=recette), la mère. Elle a des tas de collections, notamment Step ou encore Ingredient. Ces entités filles ont un champ "$appearingOrder" (oui order tout court n’est pas possible, mot réservé). J’utilise API Platform avec une méthode GET classique pour récupérer la recette, et je récupère avec les collections liées.

Mais je veux les classer par appearingOrder, et non par ID ASC, le choix par défaut.

Quand je regarde la page dédiée de la documentation, ils proposent bien de mettre dans chaque entité #[ApiResource(order: ['appearingOrder' => 'ASC'])] mais ça ne change strictement rien pour une raison que j’ignore.

Je peux sinon utiliser des choses comme : #[ApiFilter(OrderFilter::class, properties: [ 'appearingOrder' => 'ASC', ])] mais dans ce cas, c’est la méthode GetCollection qui est concernée (ça ouvre la possibilité de faire des get /api/ingredients?order['appearingOrder']=ASC) et ça ne m’avance en rien.

J’ai également essayé dans l’entité Mère order: ['kitchenwares.appearingOrder'], mais là pareil, aucun changement.

Est-ce que quelqu’un saurait à côté de quoi je passe pour faire ça ? Qu’est-ce que je loupe d’évident et qui va me faire me taper la tête contre les murs ? Je ne crois pas avoir oublié un "use", mais peut-être ?

Des idées ?

Merci.

Ou je dois faire une QueryExtension ? Ce serait aussi complexe que ça à faire pour un truc qui parait tout simple ? Quelqu’un saurait comment faire ça pour toute une liste de collections ?

final class OrderExtension implements QueryCollectionExtensionInterface
{
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
    {   
        if ($resourceClass !== Kitchenware::class) {
            return;
        }
        
        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->addOrderBy('k.appearingOrder', 'ASC');        
    }        
}

Pour l’instant ça ça ne marche pas. (j’imagine que ça devrait logiquement trier toujours par appearingOrder, alors que ce n’est pas le but non plus : juste la méthode GET sur le parent…)

En supposant que je réussisse à utiliser cette méthode, je dois en faire une similaire pour chaque collection ou il y a moyen de faire tout en une seule ? (il faut les étapes, les ingrédients, les accompagnements et les ustensiles : les autres collection sont appelées séparément lors de l’affichage, comme les commentaires ou les images)

J’ai trouvé une solution, mais c’est dément. Pour un truc bien pensé sur API Platform, y a au moins une usine à gaz.

/* Entité fille */
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;

#[ORM\Entity(repositoryClass: KitchenwareRepository::class)]
#[ApiResource]
#[ApiResource(
    order: ['appearingOrder'],
    uriTemplate: '/recipes/{recipe_id}/kitchenwares',
    operations: [new GetCollection()],
    uriVariables: [
        'recipe_id' => new Link(
            fromProperty: 'kitchenwares',
            fromClass: Recipe::class,
        ),
    ],
)]

Le premier ApiResource autorise les manipulations classiques. Le second crée l’url recipes/90/kitchenwares, et là, le classement par appearingOrder demandé est bien pris en compte.

Du coup, ça m’oblige à non plus faire une seule requête api/recipes/90 mais bien 4, une pour chaque collection concernée. Pour chaque recette.

Quelqu’un saurait si c’est vraiment ce qu’il y a de mieux à faire ? Ca me semble fou comme solution. o_O

Salut

Tu souhaites n’appliquer le tri que pour ce point d’entrée, ou si cela l’est partout où tu souhaites la recette et ses entités filles cela ne te gêne pas ?

Dans ce dernier cas, tu peux normalement mettre un mapping ORM\OrderBy("appearingOrder") sur les collections dans Recipe.

+1 -0

Merci pour la suggestion ! Est-ce qu’à ton avis c’est plus efficace que ce que j’ai mis en place ? je pense que oui, mais c’est au doigt mouillé…

Je ne vois pas de cas d’utilisation où j’aurais besoin des éléments des collections en dehors de l’affichage de leur recette d’appartenance, du coup ta solution doit pouvoir fonctionner. Je teste. Merci !

EDIT : je teste via l’api mais pour l’instant ça n’est pas pris en compte. Bizarre. Pas d’erreur pourtant.

    #[ORM\OneToMany(mappedBy: 'recipe', targetEntity: Kitchenware::class, orphanRemoval: true)]
    #[Groups(["recipe:post", "recipe:item"])]   
    #[OrderBy(["appearingOrder" => "ASC"])] 
    private Collection $kitchenwares;

Résultat :

"kitchenwares": [
    {
      "@id": "/api/kitchenware/248",
      "@type": "Kitchenware",
      "name": "fouet électrique",
      "appearingOrder": 2
    },
    {
      "@id": "/api/kitchenware/249",
      "@type": "Kitchenware",
      "name": "moule à fond amovible",
      "appearingOrder": 1
    }
  ],

EDIT 2 : je suis une andouille, j’ai oublié le "ORM\" devant le orderBy. Avec, ça fonctionne. Youpi.

Un avis sur l’efficacité du coup ? C’est mieux que ma solution, non ?

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte