Symfony2: how to create a custom Response using an event listener

Posted on by Matthias Noback

In some cases you want to return a very specific Response in case the Request has some properties like a certain response format.

This situation calls for an event listener, which listens to the kernel.request event. The listener itself should be a service with some special characteristics: it has the tag "kernel.event_listener" and some extra attributes, i.e. the name of the event to which it listens and the method of the service that should be called when this event occurs. When you want to return a very specific Response, you should listen to the kernel.request event. We want the kernel to call the method onKernelRequest(), which we will define later.

<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    <services>

        <service id="acme.request_listener" class="Acme\DemoBundle\EventListener\RequestListener">
            <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
        </service>

    </services>
</services>

Now, let's create the event listener itself. The listener is a plain old PHP object, so it doesn't have to inherit from anything. At least we should create the method onKernelRequest(). This method receives one argument, which is an instance of GetResponseEvent. This object has a few methods that are relevant for us: getRequest() and setResponse(), though there is more (see the API documentation).

namespace Acme\DemoBundle\EventListener;

use \Symfony\Component\HttpKernel\Event\GetResponseEvent;
use \Symfony\Component\HttpFoundation\Response;

class RequestListener
{
    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        /* @var $request \Symfony\Component\HttpFoundation\Request */

        if ($request->getRequestFormat() == 'json') {
            $event->setResponse(new Response('We have no response for a JSON request', 501));
        }
    }
}

The kernel loops through all event listeners and stops the propagation of the event when any listener sets a Response. So when our RequestListener is called and the request format is JSON, no other request listeners will be called and the Response we set, will be the Response that the kernel sends to the client.

Of course, the code in this example isn't really necessary, but it's just to get the idea. Adding requirements to your routes would accomplish the same thing:

MatthiasTestBundle_noJson:
    pattern: /noJson.{_format}
    defaults: { _controller: MatthiasTestBundle:Default:noJson }
    requirements: { _format: (html|xml) }
PHP Symfony2 events request response
Comments
This website uses MailComments: you can send your comments to this post by email. Read more about MailComments, including suggestions for writing your comments (in HTML or Markdown).
Nezar Fadle

if ($request->getRequestFormat() == 'json') {
$event->setResponse(new Response('We have no response for a JSON request', 501));

How to pass the Response Object to the onKernelRequest method ?

Nezar Fadle

Maybe someone is gonna be interested ,, This is how I did it in Silex:

// index.php

$app['dispatcher']->addSubscriber(new HelloServiceProvider("Pass what ever you want here"));

// HelloServiceProvider.php

use Silex\Application;

use Silex\ServiceProviderInterface;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

use Symfony\Component\HttpKernel\KernelEvents;

class HelloServiceProvider implements ServiceProviderInterface, EventSubscriberInterface

{

private $dependency ;

public function __construct($dependency)

{

$this->dependency = $dependency;

}

public function register(Application $app)

{

// Code goes here

}

public function boot(Application $app)

{

// Code goes here

}

public static function getSubscribedEvents()

{

return array(

KernelEvents::REQUEST => array('check')

);

}

public function check(GetResponseEvent $event)

{

echo $this->dependency;

}

}

Tjorriemorrie

Is if ($request->isXmlHttpRequest()) { not recommended?

Matthias Noback

Yes, you could use it. But this does not tell you what the accepted/expected format of the response is. And keep in mind that it is just a user-defined request header.

Pierre du Plessis

Never mind, I just set the priority of my listener to -10, then it picked up the route

Pierre du Plessis

Thanx this helped me a lot!

How do I get the route name of the request?
This doesn't work:
$event->getRequest()->get('_route')

I'm using Symfony 2.1 Beta1