Creando un Listener en Symfony2

Español

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.

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