Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Repenser les filtres API Platform: une nouvelle...

Repenser les filtres API Platform: une nouvelle syntaxe

Talk donné à l'API Platform Conference 2025

API Platform 4.1 est sorti en mars avec un nouveau système de filtres, dont une syntaxe inspirée des avancées introduites précédemment, lors de la prise en charge de Laravel dans la version 4.0 du framework. Dans ce talk, nous verrons ma contribution à cette transformation, de l’identification des limites de l’approche précédente, en passant par la conception et la mise en œuvre d’une solution simplifiée pour les développeurs API Platform.

À l’aide d’exemples pratiques, nous explorerons comment ces mises à jour peuvent simplifier vos projets en réduisant la complexité à l’usage et à l’extension. Que vous soyez un nouvel utilisateur·ice d’API Platform ou expérimenté·e, cette session vous fournira des éléments pour vous aider à tirer parti de ces améliorations au sein de vos APIs.

Avatar for Vincent Amstoutz

Vincent Amstoutz

September 19, 2025
Tweet

More Decks by Vincent Amstoutz

Other Decks in Programming

Transcript

  1. Vincent Amstoutz 💻 Développeur senior @ Les-Tilleuls.coop 🌍 Contributions OSS

    à API Platform, FrankenPHP, Symfony, AFUP website, Sulu ... vinceAmstoutz
  2. Dev PHP, JS, GO, Rust, C DevOps, SRE Maintenance de

    vos applicatifs Management Agile, UX design, UI design @vinceAmstoutz API, Web & Cloud experts
  3. À Quoi Ça Sert ? 🤔 @vinceAmstoutz { "@context": "/contexts/Book",

    "@id": "/books", "@type": "hydra:Collection", "hydra:totalItems": 2, "hydra:member": [ { "id": 1, "title": "L'Écume des jours", "author": "Boris Vian", "publicationDate": "1947-03-20T00:00:00+00:00", "genre": "Roman" }, { "id": 2, "title": "Dune", "author": "Frank Herbert", "publicationDate": "1965-08-01T00:00:00+00:00", "genre": "Science-Fiction" } ], } /books
  4. À Quoi Ça Sert ? 🤔 @vinceAmstoutz Filtrer des resources

    { "@context": "/contexts/Book", "@id": "/books", "@type": "hydra:Collection", "hydra:totalItems": 2, "hydra:member": [ { "id": 1, "title": "L'Écume des jours", "author": "Boris Vian", "publicationDate": "1947-03-20T00:00:00+00:00", "genre": "Roman" }, { "id": 2, "title": "Dune", "author": "Frank Herbert", "publicationDate": "1965-08-01T00:00:00+00:00", "genre": "Science-Fiction" } ], } /books
  5. À Quoi Ça Sert ? 🤔 @vinceAmstoutz Filtrer des resources

    { "@context": "/contexts/Book", "@id": "/books", "@type": "hydra:Collection", "hydra:totalItems": 2, "hydra:member": [ { "id": 1, "title": "L'Écume des jours", "author": "Boris Vian", "publicationDate": "1947-03-20T00:00:00+00:00", "genre": "Roman" }, { "id": 2, "title": "Dune", "author": "Frank Herbert", "publicationDate": "1965-08-01T00:00:00+00:00", "genre": "Science-Fiction" } ], } /books?publicationDate[after]=1950-01-01 /books
  6. À Quoi Ça Sert ? 🤔 @vinceAmstoutz Filtrer des resources

    { "@context": "/contexts/Book", "@id": "/books", "@type": "hydra:Collection", "hydra:totalItems": 2, "hydra:member": [ { "id": 1, "title": "L'Écume des jours", "author": "Boris Vian", "publicationDate": "1947-03-20T00:00:00+00:00", "genre": "Roman" }, { "id": 2, "title": "Dune", "author": "Frank Herbert", "publicationDate": "1965-08-01T00:00:00+00:00", "genre": "Science-Fiction" } ], } /books?publicationDate[after]=1950-01-01 { "@context": "/contexts/Book", "@id": "/books", "@type": "hydra:Collection", "hydra:totalItems": 1, "hydra:member": [ { "id": 2, "title": "Dune", "author": "Frank Herbert", "publicationDate": "1965-08-01T00:00:00+00:00", "genre": "Science-Fiction" } ], } SELECT * FROM book WHERE publication_date > '1950-01-01'; /books
  7. Comment Ça Marche ? 🤔 @vinceAmstoutz <?php // src/Entity/Book.php namespace

    App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Book { #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; #[ORM\Column(type: 'datetime_immutable')] private ?\DateTimeImmutable $publicationDate = null; // ... Autres propriétés, Getters et Setters } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Metadata\ApiResource; 7 use ApiPlatform\Doctrine\Orm\Filter\DateFilter; 8 9 10 11 #[ApiResource] 12 #[ApiFilter(DateFilter::class, properties: ['publicationDate'])] 13 14 15 16 17 18 19 20 21 22 23
  8. Comment Ça Marche ? 🤔 @vinceAmstoutz <?php // src/Entity/Book.php namespace

    App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Book { #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; #[ORM\Column(type: 'datetime_immutable')] private ?\DateTimeImmutable $publicationDate = null; // ... Autres propriétés, Getters et Setters } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Metadata\ApiResource; 7 use ApiPlatform\Doctrine\Orm\Filter\DateFilter; 8 9 10 11 #[ApiResource] 12 #[ApiFilter(DateFilter::class, properties: ['publicationDate'])] 13 14 15 16 17 18 19 20 21 22 23 use ApiPlatform\Metadata\ApiResource; #[ApiResource] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 use ApiPlatform\Metadata\ApiFilter; 6 7 use ApiPlatform\Doctrine\Orm\Filter\DateFilter; 8 use Doctrine\ORM\Mapping as ORM; 9 10 #[ORM\Entity] 11 12 #[ApiFilter(DateFilter::class, properties: ['publicationDate'])] 13 class Book 14 { 15 #[ORM\Id, ORM\Column, ORM\GeneratedValue] 16 private ?int $id = null; 17 18 #[ORM\Column(type: 'datetime_immutable')] 19 private ?\DateTimeImmutable $publicationDate = null; 20 21 // ... Autres propriétés, Getters et Setters 22 } 23
  9. Comment Ça Marche ? 🤔 @vinceAmstoutz <?php // src/Entity/Book.php namespace

    App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Book { #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; #[ORM\Column(type: 'datetime_immutable')] private ?\DateTimeImmutable $publicationDate = null; // ... Autres propriétés, Getters et Setters } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Metadata\ApiResource; 7 use ApiPlatform\Doctrine\Orm\Filter\DateFilter; 8 9 10 11 #[ApiResource] 12 #[ApiFilter(DateFilter::class, properties: ['publicationDate'])] 13 14 15 16 17 18 19 20 21 22 23 use ApiPlatform\Metadata\ApiResource; #[ApiResource] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 use ApiPlatform\Metadata\ApiFilter; 6 7 use ApiPlatform\Doctrine\Orm\Filter\DateFilter; 8 use Doctrine\ORM\Mapping as ORM; 9 10 #[ORM\Entity] 11 12 #[ApiFilter(DateFilter::class, properties: ['publicationDate'])] 13 class Book 14 { 15 #[ORM\Id, ORM\Column, ORM\GeneratedValue] 16 private ?int $id = null; 17 18 #[ORM\Column(type: 'datetime_immutable')] 19 private ?\DateTimeImmutable $publicationDate = null; 20 21 // ... Autres propriétés, Getters et Setters 22 } 23 use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Doctrine\Orm\Filter\DateFilter; #[ApiFilter(DateFilter::class, properties: ['publicationDate'])] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use ApiPlatform\Metadata\ApiResource; 7 8 use Doctrine\ORM\Mapping as ORM; 9 10 #[ORM\Entity] 11 #[ApiResource] 12 13 class Book 14 { 15 #[ORM\Id, ORM\Column, ORM\GeneratedValue] 16 private ?int $id = null; 17 18 #[ORM\Column(type: 'datetime_immutable')] 19 private ?\DateTimeImmutable $publicationDate = null; 20 21 // ... Autres propriétés, Getters et Setters 22 } 23
  10. Exemple : BooleanFilter @vinceAmstoutz #[ApiFilter(BooleanFilter::class, properties: ['isAvailable'])] <?php 1 //

    api/src/ApiResource/Product.php 2 namespace App\ApiResource; 3 4 use ApiPlatform\Metadata\ApiFilter; 5 use ApiPlatform\Metadata\ApiResource; 6 use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter; 7 8 #[ApiResource] 9 10 class Product 11 { 12 // ... 13 } 14 /products?isAvailable=true Syntaxe : ?property=<true|false|1|0>
  11. Exemple : StartSearchFilter @vinceAmstoutz #[QueryParameter(filter: new StartSearchFilter(), property: 'isbn')] <?php

    1 // api/src/ApiResource/Book.php 2 namespace App\ApiResource; 3 4 5 use ApiPlatform\Laravel\Eloquent\Filter\StartSearchFilter; 6 7 #[ApiResource] 8 9 class Book 10 { 11 // ... 12 } 13 /books?isbn=978 Syntaxe : ?property=<true|false|1|0>
  12. Amélioration DX et Simplification @vinceAmstoutz Et aussi les PRs #6749,

    #7079, #6865 et #6775 Merci à Antoine Bluchet (@soyuka) 🙏
  13. Tableaux VS Objets @vinceAmstoutz <?php // api/src/Entity/Offer.php namespace App\Entity; use

    ApiPlatform\Metadata\ApiResource; #[ApiResource] class Offer { // ... } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; 7 8 9 #[ApiFilter(SearchFilter::class, properties: [ 10 'id' => 'exact', 11 'price' => 'exact', 12 'description' => 'partial' 13 ])] 14 15 16 17 18
  14. Tableaux VS Objets @vinceAmstoutz <?php // api/src/Entity/Offer.php namespace App\Entity; use

    ApiPlatform\Metadata\ApiResource; #[ApiResource] class Offer { // ... } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; 7 8 9 #[ApiFilter(SearchFilter::class, properties: [ 10 'id' => 'exact', 11 'price' => 'exact', 12 'description' => 'partial' 13 ])] 14 15 16 17 18 /offers?id=9b1febd5-48ff-4a30-a63d-92d5d96020d8 Syntaxe : ?property[]=foo&property[]=bar /offers?price=10&description=cheap
  15. Tableaux VS Objets @vinceAmstoutz <?php // api/src/Entity/Offer.php namespace App\Entity; use

    ApiPlatform\Metadata\ApiResource; #[ApiResource] class Offer { // ... } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; 7 8 9 #[ApiFilter(SearchFilter::class, properties: [ 10 'id' => 'exact', 11 'price' => 'exact', 12 'description' => 'partial' 13 ])] 14 15 16 17 18 use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; #[ApiFilter(SearchFilter::class, properties: [ 'id' => 'exact', 'price' => 'exact', 'description' => 'partial' ])] <?php 1 // api/src/Entity/Offer.php 2 namespace App\Entity; 3 4 use ApiPlatform\Metadata\ApiResource; 5 6 7 8 #[ApiResource] 9 10 11 12 13 14 class Offer 15 { 16 // ... 17 } 18 /offers?id=9b1febd5-48ff-4a30-a63d-92d5d96020d8 Syntaxe : ?property[]=foo&property[]=bar /offers?price=10&description=cheap
  16. Tableaux VS Objets @vinceAmstoutz <?php // api/src/Entity/Offer.php namespace App\Entity; use

    ApiPlatform\Metadata\ApiResource; #[ApiResource] class Offer { // ... } 1 2 3 4 5 use ApiPlatform\Metadata\ApiFilter; 6 use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; 7 8 9 #[ApiFilter(SearchFilter::class, properties: [ 10 'id' => 'exact', 11 'price' => 'exact', 12 'description' => 'partial' 13 ])] 14 15 16 17 18 use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; #[ApiFilter(SearchFilter::class, properties: [ 'id' => 'exact', 'price' => 'exact', 'description' => 'partial' ])] <?php 1 // api/src/Entity/Offer.php 2 namespace App\Entity; 3 4 use ApiPlatform\Metadata\ApiResource; 5 6 7 8 #[ApiResource] 9 10 11 12 13 14 class Offer 15 { 16 // ... 17 } 18 /offers?id=9b1febd5-48ff-4a30-a63d-92d5d96020d8 Syntaxe : ?property[]=foo&property[]=bar <?php // api/src/Entity/Offer.php namespace App\Entity; use ApiPlatform\Metadata\ApiResource; #[ApiResource] class Offer { // ... } 1 2 3 4 5 use ApiPlatform\Metadata\QueryParameter; 6 use ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter; 7 8 9 #[QueryParameter(filter: new ExactSearchFilter(), property: 'id')] 10 #[QueryParameter(filter: new ExactSearchFilter(), property: 'price')] 11 #[QueryParameter(filter: new PartialSearchFilter(), property: 'description')] 12 13 14 15 16 use ApiPlatform\Metadata\QueryParameter; use ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter; #[QueryParameter(filter: new ExactSearchFilter(), property: 'id')] #[QueryParameter(filter: new ExactSearchFilter(), property: 'price')] #[QueryParameter(filter: new PartialSearchFilter(), property: 'description')] <?php 1 // api/src/Entity/Offer.php 2 namespace App\Entity; 3 4 use ApiPlatform\Metadata\ApiResource; 5 6 7 8 #[ApiResource] 9 10 11 12 class Offer 13 { 14 // ... 15 } 16 /offers?price=10&description=cheap
  17. QueryParameter @vinceAmstoutz <?php /* * This file is part of

    the API Platform project. * * (c) Kévin Dunglas <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace ApiPlatform\Metadata; /** * @experimental */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] class QueryParameter extends Parameter implements QueryParameterInterface { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  18. QueryParameter @vinceAmstoutz <?php /* This file is part of the

    API Platform project.*/ namespace ApiPlatform\Metadata; // ... abstract class Parameter { public function __construct( protected ?string $key = null, protected ?array $schema = null, protected OpenApiParameter|array|false|null $openApi = null, protected mixed $provider = null, protected mixed $filter = null, protected ?string $property = null, protected ?string $description = null, protected ?array $properties = null, protected ?bool $required = null, protected ?int $priority = null, protected ?false $hydra = null, protected mixed $constraints = null, protected string|\Stringable|null $security = null, protected ?string $securityMessage = null, protected ?array $extraProperties = [], protected array|string|null $filterContext = null, protected ?Type $nativeType = null, protected ?bool $castToArray = null, protected ?bool $castToNativeType = null, protected mixed $castFn = null, ) {...} } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
  19. ApiFilter (ancienne méthode) @vinceAmstoutz <?php /* * This file is

    part of the API Platform project. */ namespace ApiPlatform\Metadata; // ... #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] final class ApiFilter { /* ... */ public function __construct( public string $filterClass, public ?string $id = null, public ?string $strategy = null, public array $properties = [], public array $arguments = [], public ?string $alias = null, ) {...} } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  20. Bénéfices @vinceAmstoutz Filtres plus simples à créer (en interne et

    pour vous) Maintenabilité Usage d'objets à la place de tableaux (autocomplétion)
  21. Bénéfices @vinceAmstoutz Filtres plus simples à créer (en interne et

    pour vous) Plus flexible Maintenabilité Usage d'objets à la place de tableaux (autocomplétion)
  22. Des Filtres Dédiés au Search @vinceAmstoutz 🆕 IriFilter GET /products?factory=/factory/1

    🆕 ExactFilter GET /books?name=Gertrude 🆕 PartialSearchFilter GET /books?namePartial=de 🆕 OrFilter GET /books?q[]=97815&q[]=978036940 🆕 FreeTextQueryFilter GET books?autocomplete=chaise ✨ Support d'ORM et d'ODM
  23. Exemple : ExactFilter @vinceAmstoutz /products?name=brosse Syntaxe : ?property=value <?php //

    src/ApiResource/Product.php namespace App\ApiResource; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\QueryParameter; use ApiPlatform\Doctrine\Orm\Filter\ExactFilter; #[ApiResource] #[QueryParameter(filter: new ExactSearchFilter(), property: 'name')] class Product { // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  24. Exemple 2 : ExactFilter @vinceAmstoutz <?php // src/ApiResource/Product.php namespace App\Entity;

    use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\QueryParameter; use ApiPlatform\Laravel\Eloquent\Filter\ExactSearchFilter; #[GetCollection( parameters: ['name' => new QueryParameter(filter: new ExactSearchFilter())] )] class Product { // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /products?name=brosse Syntaxe : ?property=value
  25. Créer Ses Filtres Personnalisés 🚀 ✅ FilterInterface implémentable rapidement @vinceAmstoutz

    ❌ Plus besoin d'étendre AbstractFilter et ses multiples implémentations
  26. Créer Ses Filtres Personnalisés 🚀 ✅ FilterInterface implémentable rapidement @vinceAmstoutz

    ✅ Complexité gérée sous le capot ❌ Plus besoin d'étendre AbstractFilter et ses multiples implémentations
  27. Créer Ses Filtres Personnalisés 🚀 ✅ FilterInterface implémentable rapidement @vinceAmstoutz

    ✅ Complexité gérée sous le capot ❌ Plus besoin d'étendre AbstractFilter et ses multiples implémentations ✅ Extension
  28. @vinceAmstoutz use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; final class MonthFilter implements FilterInterface public function

    apply(...): void <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 6 // ... 7 8 9 { 10 11 { 12 $parameter = $context['parameter']; 13 $monthValue = $parameter->getValue(); 14 15 $parameterName = $queryNameGenerator->generateParameterName($property); 16 $alias = $queryBuilder->getRootAliases()[0]; 17 18 $queryBuilder 19 ->andWhere(sprintf('MONTH(%s.%s) = :%s', $alias, $property, $parameterName)) 20 ->setParameter($parameterName, $monthValue); 21 } 22 } 23 Créer Ses Filtres Personnalisés 🚀
  29. @vinceAmstoutz use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; final class MonthFilter implements FilterInterface public function

    apply(...): void <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 6 // ... 7 8 9 { 10 11 { 12 $parameter = $context['parameter']; 13 $monthValue = $parameter->getValue(); 14 15 $parameterName = $queryNameGenerator->generateParameterName($property); 16 $alias = $queryBuilder->getRootAliases()[0]; 17 18 $queryBuilder 19 ->andWhere(sprintf('MONTH(%s.%s) = :%s', $alias, $property, $parameterName)) 20 ->setParameter($parameterName, $monthValue); 21 } 22 } 23 { $parameter = $context['parameter']; $monthValue = $parameter->getValue(); <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; 6 // ... 7 8 final class MonthFilter implements FilterInterface 9 { 10 public function apply(...): void 11 12 13 14 15 $parameterName = $queryNameGenerator->generateParameterName($property); 16 $alias = $queryBuilder->getRootAliases()[0]; 17 18 $queryBuilder 19 ->andWhere(sprintf('MONTH(%s.%s) = :%s', $alias, $property, $parameterName)) 20 ->setParameter($parameterName, $monthValue); 21 } 22 } 23 Créer Ses Filtres Personnalisés 🚀
  30. @vinceAmstoutz use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; final class MonthFilter implements FilterInterface public function

    apply(...): void <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 6 // ... 7 8 9 { 10 11 { 12 $parameter = $context['parameter']; 13 $monthValue = $parameter->getValue(); 14 15 $parameterName = $queryNameGenerator->generateParameterName($property); 16 $alias = $queryBuilder->getRootAliases()[0]; 17 18 $queryBuilder 19 ->andWhere(sprintf('MONTH(%s.%s) = :%s', $alias, $property, $parameterName)) 20 ->setParameter($parameterName, $monthValue); 21 } 22 } 23 { $parameter = $context['parameter']; $monthValue = $parameter->getValue(); <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; 6 // ... 7 8 final class MonthFilter implements FilterInterface 9 { 10 public function apply(...): void 11 12 13 14 15 $parameterName = $queryNameGenerator->generateParameterName($property); 16 $alias = $queryBuilder->getRootAliases()[0]; 17 18 $queryBuilder 19 ->andWhere(sprintf('MONTH(%s.%s) = :%s', $alias, $property, $parameterName)) 20 ->setParameter($parameterName, $monthValue); 21 } 22 } 23 $parameterName = $queryNameGenerator->generateParameterName($property); $alias = $queryBuilder->getRootAliases()[0]; $queryBuilder ->andWhere(sprintf('MONTH(%s.%s) = :%s', $alias, $property, $parameterName)) ->setParameter($parameterName, $monthValue); } } <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Doctrine\Orm\Filter\FilterInterface; 6 // ... 7 8 final class MonthFilter implements FilterInterface 9 { 10 public function apply(...): void 11 { 12 $parameter = $context['parameter']; 13 $monthValue = $parameter->getValue(); 14 15 16 17 18 19 20 21 22 23 Créer Ses Filtres Personnalisés 🚀
  31. Ajouter La Validation Du Filtre @vinceAmstoutz use ApiPlatform\Metadata\JsonSchemaFilterInterface; final class

    MonthFilter implements FilterInterface, JsonSchemaFilterInterface public function getSchema(Parameter $parameter): array <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 6 // ... 7 8 9 { 10 public function apply(...): void 11 {...} 12 13 14 { 15 return [ 16 'type' => 'integer', 17 18 // <=> Symfony\Component\Validator\Constraints\Range 19 'minimum' => 1, 20 'maximum' => 12, 21 ]; 22 } 23 } 24
  32. Ajouter La Validation Du Filtre @vinceAmstoutz use ApiPlatform\Metadata\JsonSchemaFilterInterface; final class

    MonthFilter implements FilterInterface, JsonSchemaFilterInterface public function getSchema(Parameter $parameter): array <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 6 // ... 7 8 9 { 10 public function apply(...): void 11 {...} 12 13 14 { 15 return [ 16 'type' => 'integer', 17 18 // <=> Symfony\Component\Validator\Constraints\Range 19 'minimum' => 1, 20 'maximum' => 12, 21 ]; 22 } 23 } 24 return [ 'type' => 'integer', // <=> Symfony\Component\Validator\Constraints\Range 'minimum' => 1, 'maximum' => 12, ]; <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Metadata\JsonSchemaFilterInterface; 6 // ... 7 8 final class MonthFilter implements FilterInterface, JsonSchemaFilterInterface 9 { 10 public function apply(...): void 11 {...} 12 13 public function getSchema(Parameter $parameter): array 14 { 15 16 17 18 19 20 21 22 } 23 } 24
  33. Exemple d'Usage Du Filtre @vinceAmstoutz #[GetCollection( parameters: [ 'createdAt' =>

    new QueryParameter( filter: new MonthFilter(), castToNativeType => true ), )] <?php 1 2 // src/ApiResource/Invoice.php 3 4 namespace App\ApiResource; 5 6 use ApiPlatform\Metadata\QueryParameter; 7 use App\Filter\MonthFilter; 8 9 10 11 12 13 14 15 'createdAtCustomName' => new QueryParameter( 16 filter: new MonthFilter(), 17 property: 'createdAt', 18 castToNativeType => true 19 ) 20 ] 21 22 class Invoice 23 { 24 // ... 25 } 26 GET /invoices?createdAt=7
  34. Exemple d'Usage Du Filtre @vinceAmstoutz #[GetCollection( parameters: [ 'createdAt' =>

    new QueryParameter( filter: new MonthFilter(), castToNativeType => true ), )] <?php 1 2 // src/ApiResource/Invoice.php 3 4 namespace App\ApiResource; 5 6 use ApiPlatform\Metadata\QueryParameter; 7 use App\Filter\MonthFilter; 8 9 10 11 12 13 14 15 'createdAtCustomName' => new QueryParameter( 16 filter: new MonthFilter(), 17 property: 'createdAt', 18 castToNativeType => true 19 ) 20 ] 21 22 class Invoice 23 { 24 // ... 25 } 26 #[GetCollection( parameters: [ 'createdAtCustomName' => new QueryParameter( filter: new MonthFilter(), property: 'createdAt', castToNativeType => true ) ] )] <?php 1 2 // src/ApiResource/Invoice.php 3 4 namespace App\ApiResource; 5 6 use ApiPlatform\Metadata\QueryParameter; 7 use App\Filter\MonthFilter; 8 9 10 11 'createdAt' => new QueryParameter( 12 filter: new MonthFilter(), 13 castToNativeType => true 14 ), 15 16 17 18 19 20 21 22 class Invoice 23 { 24 // ... 25 } 26 GET /invoices?createdAt=7
  35. Exemple d'Usage Du Filtre @vinceAmstoutz #[GetCollection( parameters: [ 'createdAt' =>

    new QueryParameter( filter: new MonthFilter(), castToNativeType => true ), )] <?php 1 2 // src/ApiResource/Invoice.php 3 4 namespace App\ApiResource; 5 6 use ApiPlatform\Metadata\QueryParameter; 7 use App\Filter\MonthFilter; 8 9 10 11 12 13 14 15 'createdAtCustomName' => new QueryParameter( 16 filter: new MonthFilter(), 17 property: 'createdAt', 18 castToNativeType => true 19 ) 20 ] 21 22 class Invoice 23 { 24 // ... 25 } 26 #[GetCollection( parameters: [ 'createdAtCustomName' => new QueryParameter( filter: new MonthFilter(), property: 'createdAt', castToNativeType => true ) ] )] <?php 1 2 // src/ApiResource/Invoice.php 3 4 namespace App\ApiResource; 5 6 use ApiPlatform\Metadata\QueryParameter; 7 use App\Filter\MonthFilter; 8 9 10 11 'createdAt' => new QueryParameter( 12 filter: new MonthFilter(), 13 castToNativeType => true 14 ), 15 16 17 18 19 20 21 22 class Invoice 23 { 24 // ... 25 } 26 <?php // src/ApiResource/Invoice.php namespace App\ApiResource; use ApiPlatform\Metadata\QueryParameter; use App\Filter\MonthFilter; #[GetCollection( parameters: [ 'createdAt' => new QueryParameter( filter: new MonthFilter(), castToNativeType => true ), 'createdAtCustomName' => new QueryParameter( filter: new MonthFilter(), property: 'createdAt', castToNativeType => true ) ] )] class Invoice { // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 GET /invoices?createdAt=7
  36. Documenter un Filtre Personnalisé @vinceAmstoutz use ApiPlatform\Doctrine\Common\Filter\OpenApiFilterTrait; use ApiPlatform\Metadata\OpenApiParameterFilterInterface; final

    class MonthFilter implements FilterInterface, JsonSchemaFilterInterface, OpenApiParameterFilterInterface { use OpenApiFilterTrait; <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Metadata\JsonSchemaFilterInterface; 6 7 8 // ... 9 10 11 12 13 14 // ... 15 } 16 Si la valeur du paramètre est un scalaire ou un tableau d'1 scalaire
  37. @vinceAmstoutz use ApiPlatform\Metadata\OpenApiParameterFilterInterface; final class MonthFilter implements FilterInterface, JsonSchemaFilterInterface, OpenApiParameterFilterInterface

    public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null { // TODO: change default implementation return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true); } } <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Metadata\JsonSchemaFilterInterface; 6 7 // ... 8 9 10 { 11 public function apply(...): void {} 12 13 14 15 16 17 18 19 Documenter un Filtre Personnalisé Si la valeur du paramètre n'est pas un scalaire ou un tableau d'1 scalaire https://api- platform.com/docs/core/filters/#customizing-the- openapi-parameter
  38. @vinceAmstoutz use ApiPlatform\Metadata\OpenApiParameterFilterInterface; final class MonthFilter implements FilterInterface, JsonSchemaFilterInterface, OpenApiParameterFilterInterface

    public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null { // TODO: change default implementation return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true); } } <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Metadata\JsonSchemaFilterInterface; 6 7 // ... 8 9 10 { 11 public function apply(...): void {} 12 13 14 15 16 17 18 19 // TODO: change default implementation return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true); <?php 1 2 // api/src/Filter/MonthFilter.php 3 namespace App\Filter; 4 5 use ApiPlatform\Metadata\JsonSchemaFilterInterface; 6 use ApiPlatform\Metadata\OpenApiParameterFilterInterface; 7 // ... 8 9 final class MonthFilter implements FilterInterface, JsonSchemaFilterInterface, OpenApiParameterFilterInterface 10 { 11 public function apply(...): void {} 12 13 public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null 14 { 15 16 17 } 18 } 19 Documenter un Filtre Personnalisé Si la valeur du paramètre n'est pas un scalaire ou un tableau d'1 scalaire https://api- platform.com/docs/core/filters/#customizing-the- openapi-parameter
  39. @vinceAmstoutz use Rector\ApiPlatform\ApiPlatform50\Rector\Function\ApiFilterToQueryParameters; ->withRules([ ApiFilterToQueryParameters::class, ]); <?php 1 2 //rector.php

    3 4 use Rector\Config\RectorConfig; 5 6 7 return RectorConfig::configure() 8 9 10 11 Migrer Nos ApiFilter Avec Rector vendor/bin/rector
  40. Parameter Providers @vinceAmstoutz “ ... peuvent aussi modifier les métadonnées

    actuelles de l'opération “ Transforment ou fournissent des valeurs pour les paramètres.
  41. Parameter Providers @vinceAmstoutz “ ... implémentent l'interface `ApiPlatform\State\ParameterProviderInterface`. “ ...

    peuvent aussi modifier les métadonnées actuelles de l'opération “ Transforment ou fournissent des valeurs pour les paramètres.
  42. IriConverterParameterProvider @vinceAmstoutz <?php // api/src/Resource/Foo.php use ApiPlatform\State\ParameterProviderInterface; use ApiPlatform\State\ParameterProvider\IriConverterParameterProvider; //

    ... #[ApiResource(operations: [ new Get( parameters: [ 'dummy' => new QueryParameter(provider: IriConverterParameterProvider::class), 'related' => new QueryParameter( extraProperties: ['fetch_data' => true] // Forces fetching the entity data ), ], ) ])] class Foo { // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  43. IriConverterParameterProvider @vinceAmstoutz <?php use ApiPlatform\State\ParameterProviderInterface; use ApiPlatform\Metadata\ParameterProviderFilterInterface; // ... final

    class CustomFilter implements FilterInterface, ParameterProviderFilterInterface { use BackwardCompatibleFilterDescriptionTrait; public function apply(...): void {} public static function getParameterProvider(): string { return IriConverterParameterProvider::class; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  44. @vinceAmstoutz <?php // api/src/Resource/Foo.php use ApiPlatform\State\ParameterProviderInterface; use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider; // ...

    #[ApiResource(operations: [ new Get( parameters: [ 'dummy' => new QueryParameter( provider: ReadLinkParameterProvider::class, extraProperties: [ 'resource_class' => Dummy::class, 'uri_template' => '/dummies/{id}' // Optional: specify the template for the linked resource ] ) ], ) ])] class Foo {...} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ReadLinkParameterProvider
  45. @vinceAmstoutz <?php // ... use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider; use ApiPlatform\State\ParameterProviderInterface; final class

    CustomFilter implements FilterInterface, ParameterProviderFilterInterface { use BackwardCompatibleFilterDescriptionTrait; public function apply(...): void {} public static function getParameterProvider(): string { return ReadLinkParameterProvider::class; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ReadLinkParameterProvider
  46. @vinceAmstoutz Parameter Provider Personnalisé use ApiPlatform\State\ParameterProviderInterface; final class FullViewProvider implements

    ParameterProviderInterface public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 6 // ... 7 8 9 { 10 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25
  47. @vinceAmstoutz Parameter Provider Personnalisé use ApiPlatform\State\ParameterProviderInterface; final class FullViewProvider implements

    ParameterProviderInterface public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 6 // ... 7 8 9 { 10 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 $operation = $context['operation']; $viewMode = $uriVariables['view'] ?? null; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 13 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25
  48. @vinceAmstoutz Parameter Provider Personnalisé use ApiPlatform\State\ParameterProviderInterface; final class FullViewProvider implements

    ParameterProviderInterface public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 6 // ... 7 8 9 { 10 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 $operation = $context['operation']; $viewMode = $uriVariables['view'] ?? null; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 13 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 if ('full' === $viewMode) { } return $operation; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 21 22 23 } 24 } 25
  49. @vinceAmstoutz Parameter Provider Personnalisé use ApiPlatform\State\ParameterProviderInterface; final class FullViewProvider implements

    ParameterProviderInterface public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 6 // ... 7 8 9 { 10 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 $operation = $context['operation']; $viewMode = $uriVariables['view'] ?? null; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 13 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 if ('full' === $viewMode) { } return $operation; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 21 22 23 } 24 } 25 $normalizationContext = $operation->getNormalizationContext() ?? []; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25
  50. @vinceAmstoutz Parameter Provider Personnalisé use ApiPlatform\State\ParameterProviderInterface; final class FullViewProvider implements

    ParameterProviderInterface public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 6 // ... 7 8 9 { 10 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 $operation = $context['operation']; $viewMode = $uriVariables['view'] ?? null; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 13 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 if ('full' === $viewMode) { } return $operation; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 21 22 23 } 24 } 25 $normalizationContext = $operation->getNormalizationContext() ?? []; <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 17 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; 18 19 return $operation->withNormalizationContext($normalizationContext); 20 } 21 22 return $operation; 23 } 24 } 25 $normalizationContext[AbstractNormalizer::GROUPS][] = 'book:read:full'; return $operation->withNormalizationContext($normalizationContext); <?php 1 2 // src/State/UpperCaseNameProvider.php 3 namespace App\State; 4 5 use ApiPlatform\State\ParameterProviderInterface; 6 // ... 7 8 final class FullViewProvider implements ParameterProviderInterface 9 { 10 public function provide(Parameter $parameter, array $uriVariables = [], array $context = []): Operation 11 { 12 $operation = $context['operation']; 13 $viewMode = $uriVariables['view'] ?? null; 14 15 if ('full' === $viewMode) { 16 $normalizationContext = $operation->getNormalizationContext() ?? []; 17 18 19 20 } 21 22 return $operation; 23 } 24 } 25
  51. @vinceAmstoutz #[ApiResource( normalizationContext: ['groups' => ['book:read']] // Groupe par défaut

    )] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use App\State\FullViewProvider; 7 // ... 8 9 10 11 12 #[Get(parameters: ['view' => new QueryParameter(provider: FullViewProvider::class)])] 13 class Book 14 { 15 // ... 16 17 #[Groups(['book:read:full'])] 18 public string $summary = 'Un long résumé du contenu du livre...'; 19 } 20 Parameter Provider Personnalisé
  52. @vinceAmstoutz #[ApiResource( normalizationContext: ['groups' => ['book:read']] // Groupe par défaut

    )] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use App\State\FullViewProvider; 7 // ... 8 9 10 11 12 #[Get(parameters: ['view' => new QueryParameter(provider: FullViewProvider::class)])] 13 class Book 14 { 15 // ... 16 17 #[Groups(['book:read:full'])] 18 public string $summary = 'Un long résumé du contenu du livre...'; 19 } 20 #[Get(parameters: ['view' => new QueryParameter(provider: FullViewProvider::class)])] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use App\State\FullViewProvider; 7 // ... 8 9 #[ApiResource( 10 normalizationContext: ['groups' => ['book:read']] // Groupe par défaut 11 )] 12 13 class Book 14 { 15 // ... 16 17 #[Groups(['book:read:full'])] 18 public string $summary = 'Un long résumé du contenu du livre...'; 19 } 20 Parameter Provider Personnalisé
  53. @vinceAmstoutz #[ApiResource( normalizationContext: ['groups' => ['book:read']] // Groupe par défaut

    )] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use App\State\FullViewProvider; 7 // ... 8 9 10 11 12 #[Get(parameters: ['view' => new QueryParameter(provider: FullViewProvider::class)])] 13 class Book 14 { 15 // ... 16 17 #[Groups(['book:read:full'])] 18 public string $summary = 'Un long résumé du contenu du livre...'; 19 } 20 #[Get(parameters: ['view' => new QueryParameter(provider: FullViewProvider::class)])] <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use App\State\FullViewProvider; 7 // ... 8 9 #[ApiResource( 10 normalizationContext: ['groups' => ['book:read']] // Groupe par défaut 11 )] 12 13 class Book 14 { 15 // ... 16 17 #[Groups(['book:read:full'])] 18 public string $summary = 'Un long résumé du contenu du livre...'; 19 } 20 #[Groups(['book:read:full'])] public string $summary = 'Un long résumé du contenu du livre...'; } <?php 1 // src/Entity/Book.php 2 3 namespace App\Entity; 4 5 6 use App\State\FullViewProvider; 7 // ... 8 9 #[ApiResource( 10 normalizationContext: ['groups' => ['book:read']] // Groupe par défaut 11 )] 12 #[Get(parameters: ['view' => new QueryParameter(provider: FullViewProvider::class)])] 13 class Book 14 { 15 // ... 16 17 18 19 20 Parameter Provider Personnalisé
  54. @vinceAmstoutz ✅ GET /api/books/1 { "id": 1, "title": "Le Seigneur

    des Anneaux", "author": "J.R.R. Tolkien" } 1 2 3 4 5 Parameter Provider Personnalisé
  55. @vinceAmstoutz ✅ GET /api/books/1?view=full ✅ GET /api/books/1 { "id": 1,

    "title": "Le Seigneur des Anneaux", "author": "J.R.R. Tolkien" } 1 2 3 4 5 { "id": 1, "title": "Le Seigneur des Anneaux", "author": "J.R.R. Tolkien", "summary": "Un long résumé du contenu du livre..." } 1 2 3 4 5 6 Parameter Provider Personnalisé
  56. @vinceAmstoutz Ajout De Nouveaux Filtres GeoSpatialFilter(s) MongoDB ? - cc

    @GromNaN Filtres spécifiques PostgreSQL comme un FullTextSearchFilter ? NotEqualsFilter ?
  57. @vinceAmstoutz Ajout De Nouveaux Filtres GeoSpatialFilter(s) MongoDB ? - cc

    @GromNaN Filtres spécifiques PostgreSQL comme un FullTextSearchFilter ? NotEqualsFilter ? Vos propositions via une PR 😀
  58. @vinceAmstoutz Réécriture Des Anciens Filtres Natifs BackedEnumFilter BooleanFilter DateFilter ExistsFilter

    NumericFilter OrderFilter RangeFilter Et les Elasticsearch ? En interne https://www.flaticon.com/fr/icones- gratuites/ecrire