Creando un Listener en Symfony2

Este artículo forma parte de la serie Symfony2 y presupone que Ud. ha:

– Instalado y configurado Symfony2 Standard Edition, se recomienda leer: Instalando y configurando Symfony2 en un ambiente compartido

– Instalado y configurado APC se recomienda leer: Instalar Alternative PHP Cache (APC) en CentOS

Partamos de la idea de que estamos desarrollando una API Restful y que deseamos cachear las respuestas de cada acción ejecutada en los Controladores (Controller), para ello:

Configuramos el Listener en nuestro config.yml

...
services:
  # Identificador del Listener 
  request.listener:
    # Listener Namespace and nombre de la clase
    class: AcmeDemoBundleEventListenerRequestListener
    # Inyección de dependencia: Contenedor de servicios 
    calls:
        - [ setContainer, [ @service_container ] ]
    # Definición del servicio como Listener: los eventos a observar son kernel.request (cada vez que se realiza una
    # petición Http), KernelResponse (cada vez que se devuelve una respuesta a la petición Http), kernel.exception 
    # (cada vez que ocurre una excepción)
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
        - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
        - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
...

Crear dir EventListener dentro de AcmeDemoBundle

$ mkdir src/Acme/DemoBundle/EventListener

Crear Listener

Nuestra clase debe implementar la interfaz ContainerAwareInterface

class RequestListener implements ContainerAwareInterface

Inyectamos el contenedor de servicios

/**
 * @var ContainerInterface
 */
 protected $container;

 public function setContainer(ContainerInterface $container = null)
 {
     $this->container = $container;
 }

Verificamos si existe un Objeto Response cacheado para la Petición correspondiente

/**
 * This method is executed for every Http Request. If the content is found
 * in Apc Cache the execution flow is stopped and a Response is returned
 * inmediately, no controller action is executed.
 * @param GetResponseEvent $event
 * @return type
 */
public function onKernelRequest(GetResponseEvent $event)
{
    // No caching for dev enviroment
    if ($this->container->getParameter('kernel.environment') === 'dev') {
        return;
    }

    $request = $event->getRequest();

    // Cahing only for Http Get method
    if ('GET' !== $request->getMethod()) {
        return;
    }

    // Build Apc cache key
    $path = 'controller.' . $request->getPathInfo();

    $qs = $request->getQueryString();

    // For caching request with query string if you do not aware of it
    // comment out
    if (!empty($qs)) {
        $path .= '.' . sha1($qs);
    }

    if (apc_exists($path)) {
        $event->setResponse(apc_fetch($path));
    }
}

Cacheamos el Objeto Response

/**
 * This method is executed after a Controller action and before the Response
 * is returned to the Browser or to another agent. Stores the Response object,
 * If it has not been cached
 *
 * @param FilterResponseEvent $event
 * @return type
 */
public function onKernelResponse(FilterResponseEvent $event)
{
    // No caching for dev enviroment
    if ($this->container->getParameter('kernel.environment') === 'dev') {
        return;
    }

    $request = $event->getRequest();

    // Cahing only for Http Get method
    if ('GET' !== $request->getMethod()) {
        return;
    }

    // Build Apc cache key
    $path = 'controller.' . $request->getPathInfo();

    // For caching request with query string if you do not aware of it
    // comment out
    $qs = $request->getQueryString();

    if (!empty($qs)) {
        $path .= '.' . sha1($qs);
    }

    if (!apc_exists($path)) {
        apc_store($path, $event->getResponse());
    }
}

Evitamos cachear las excepciones

/*
 * This method prevent to cache Response when occurs Exceptions
 */
public function onKernelException(GetResponseForExceptionEvent $event)
{
    $event->stopPropagation();
}

Verificamos que el listener ha sido registrado

$ php app/console container:debug
...
request.listener                            container AcmeDemoBundleEventListenerRequestListener
...

Ahora si ponemos en nuestro navegador:

– http://localhost/symfony-standard/web/app.php/demo/hello/World

e inspeccionamos la cache vemos lo siguiente.

APC

Puedes obtener la clase EventListener en:
Github

Lecturas recomendadas

Proyecto oficial Symfony2

4 comentarios en “Creando un Listener en Symfony2”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.