Reusing Filters Across Multiple Entities in API Platform 3 and Symfony

Title: Reusing Filters Across Multiple Entities in API Platform 3 and Symfony

Hello everyone,

I’m working on a project using API Platform 3 with Symfony, and I’m looking for an effective way to factorize and reuse filters across multiple entities. Here’s a summary of my use case and the challenges I’ve encountered:

  1. Objective: I have common filters (for example, filters on fields like name, createdAt, and updatedAt) that I want to reuse across several entities without duplicating the filter configuration.

  2. Current Configuration: I’ve defined my common filters in a YAML services file. Then, I use the ApiFilter attribute to declare specific filters directly on the entities. However, this forces me to repeat the configuration of common filters for each entity.

  3. Constraint: API Platform’s filter classes are declared as final, preventing me from directly extending them to create “wrapper” classes for the filters. Additionally, the ApiFilter attribute does not accept a service identifier as an argument, limiting my ability to reference the filters defined in the YAML file.

Here’s a snippet of the YAML configuration for the common filters:

services:
  app.api.filter.name_order:
    parent: 'api_platform.doctrine.orm.order_filter'
    arguments: [ { name: ~ } ]
    tags: [ 'api_platform.filter' ]

  app.api.filter.lifecycle_date:
    parent: 'api_platform.doctrine.orm.date_filter'
    arguments: [ { createdAt: ~, updatedAt: ~ } ]
    tags: [ 'api_platform.filter' ]

And an example of using PHP 8 attributes on an entity:

#[ApiResource(
    // Other configurations...
    filters: [
        'hl.name.order_filter',
        'hl.lifecycle.date_filter',
        // Other filters...
    ]
)]
#[ApiFilter(SearchFilter::class, properties: ['name' => 'partial'])]
class SomeEntity {
    // Entity definition...
}

I’ve explored several avenues, like using traits to mark entities or centralizing filter configuration, but none of these solutions seem to offer the flexibility and reusability I’m looking for.

I’m reaching out best practices in this context. Here are some specific points I’d like to clarify:

  • #[ApiFilter('hl.name.order_filter')]: I tried but the ApiFilter is configured to receive a class name only.
  • So I tried to extend default filter like MyFilter extends OrderFilter but they are all final…
  • Is there a recommended approach to reuse filters among different entities in API Platform while adhering to DRY principles?
  • Is there a way to work around the final class constraint to extend or reuse API Platform’s filter logic?
  • Are there any alternative design patterns or strategies for elegantly handling this issue within the Symfony/API Platform ecosystem?

I’m open to any suggestions, even those that might involve reconsidering the current architecture, if it leads to a cleaner and more maintainable solution.