devouted / symfony-as-cached-attribute
About
Package info
github.com/devouted/symfony-as-cached-attribute
pkg:composer/devouted/symfony-as-cached-attribute
1.1.0
2026-03-26 19:46 UTC
Requires
- php: ^8.2
- psr/cache: ^3.0
- psr/log: ^3.0
- symfony/http-foundation: ^6.4|^7.0
- symfony/http-kernel: ^6.4|^7.0
Requires (Dev)
- pestphp/pest: ^2.0
- pestphp/pest-plugin-drift: ^2.6
- symfony/browser-kit: ^6.4|^7.0
- symfony/cache: ^6.4|^7.0
- symfony/config: ^6.4|^7.0
- symfony/console: ^6.4|^7.0
- symfony/css-selector: ^6.4|^7.0
- symfony/dependency-injection: ^6.4|^7.0
- symfony/framework-bundle: ^6.4|^7.0
- symfony/phpunit-bridge: ^6.4|^7.0
- symfony/routing: ^6.4|^7.0
- symfony/runtime: ^6.4|^7.0
- symfony/serializer-pack: ^1.3
- symfony/test-pack: ^1.0
- symfony/var-dumper: ^6.4|^7.0
- symfony/yaml: ^6.4|^7.0
README
Symfony attribute-based HTTP response caching. Mark controller actions with #[AsCachedResponse] to automatically cache responses.
Installation
composer require devouted/symfony-as-cached-attribute
Usage
Service configuration
Add to your services.yaml:
services: Devouted\AsCachedAttribute\Listener\CachedResponseListener: arguments: $cache: '@cache.app' $logger: '@monolog.logger' # optional, set to ~ to disable $modifyResponseCacheHeaders: true # optional, set to false to skip Cache-Control headers tags: - { name: kernel.event_listener, event: kernel.controller_arguments, priority: -1 } - { name: kernel.event_listener, event: kernel.response, priority: 1000 }
Basic usage
#[AsCachedResponse] public function __invoke(): Response { return new Response('cached content'); }
or on a regular controller action:
#[AsCachedResponse] public function someAction(Request $request): Response { return new Response('cached content'); }
Cache key parametrization
Use #[AsCachedRequestParameter] on method parameters or DTO properties to build unique cache keys per request:
On method parameters:
#[AsCachedResponse] public function show( #[AsCachedRequestParameter] int $id, #[AsCachedRequestParameter] string $slug ): Response { return new Response("id={$id}, slug={$slug}"); }
On DTO properties (e.g. with #[MapQueryString] or #[MapRequestPayload]):
#[AsCachedResponse] public function list(#[MapQueryString] ProductFilter $filter): Response { return new Response("filtered list"); } class ProductFilter { public function __construct( #[AsCachedRequestParameter] public int $categoryId, #[AsCachedRequestParameter] public ?string $sort = null, ) {} }
AsCachedResponse options
#[AsCachedResponse(
ttl: 3600, // cache lifetime in seconds (default: 3600)
etag: 'my-etag', // optional ETag header value
expires: 'tomorrow', // optional Expires header (any strtotime-compatible string)
isPublic: true, // public (shared) or private cache (default: true)
)]
Response headers
Cached responses include an X-Cache header:
Miss— response was generated and stored in cacheHit— response was served from cache