Filtering the menu

Exercise 5 of 6 in chapter 5 · 240 XP · 5 objectives checked by tests

Topics covered: #[MapQueryString]EnumQueryBuildervalidationFailedStatusCode

The Circle of Mages is on a diet: “Nothing above 4 gold pieces, and only drinks, thank you.” Rather than downloading the whole menu and sorting it themselves, the scrolls want to filter:

/api/dishes?categorie=Drinks&prixMax=4&tri=nom

Your mission

  1. Complete the FiltreCarte DTO (menu filter), with three optional parameters:
    • categorie: the exact name of a category;
    • prixMax: the maximum price, inclusive, and greater than zero;
    • tri (sort): prix (price, the default) or nom (name). The Tri enum is provided.
  2. Add PlatRepository::findAvecFiltre(FiltreCarte $filtre) (find with filter), which applies the filters that are set and the requested order.
  3. In GET /api/dishes, receive the filters with #[MapQueryString]. Without any parameter, the menu stays complete, sorted by price.
  4. An invalid filter (?prixMax=-3, ?prixMax=lots, ?tri=color) must give 400 Bad Request.

#[MapQueryString]

It's the cousin of #[MapRequestPayload], but for the query string. Symfony converts each parameter to the property's type ("4" → 4.0, "nom" → Tri::Nom), then validates the DTO.

Watch out for the error code: by default, an invalid query string gives 404, like a page that can't be found. For an API, 400 is more accurate: set it with validationFailedStatusCode.

What about SQL injection?

The sort ends up in the query (orderBy('p.'.…)). Thanks to the enum, its value can only be prix or nom: Symfony rejects everything else before your code is even called.