Search code examples
phpsymfonycachinghttp-status-codescache-control

Symfony: set cache headers through annotations only for specific status codes


Is there a way to set cache headers in symfony controller annotations only for specific status codes?

I am currently doing it like in the code below, utilizing the annotations provided by the SensioFrameworkExtraBundle:

 /**
 * @Get("", name="product.list")
 * @Cache(public=true, maxage="432000", smaxage="432000")
 */
public function listAction()
{
    // ...
}

But this annotation sets the cache headers for all responses no matter what status code. I would like to set the cache headers only for specific status codes.


Solution

  • Looking at the code in SensioFrameworkExtraBundle, the most straight-forward solution would be to either not use annotations but set the cache headers manually on the response (in the controller or an event listener for example), or create an event listener that prevents the SensioFrameworkExtraBundle to set the cache headers.

    Regarding the second option, looking at the code (https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/EventListener/HttpCacheListener.php#L86-L88), you could unset the _cache request attribute before the HttpCacheListener is triggered.

    <?php
    
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
    use Symfony\Component\HttpKernel\KernelEvents;
    
    class MyCacheListener implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return [
                KernelEvents::RESPONSE => ['onKernelResponse', 16] // use a priority higher than the HttpCacheListener
            ];
        }
    
        public function onKernelResponse(FilterResponseEvent $event)
        {
            $request = $event->getRequest();
            $response = $event->getResponse();
    
            if (!$response->isSuccessful()) {
                $request->attributes->remove('_cache');
            }
        }
    }
    

    Register your event subscriber, for example in services.yml:

    services:
        my_cache_listener:
            class: MyCacheListener
            tags:
                - { name: kernel.event_subscriber }