A free and open-source book on ZF3 for beginners

Translation into this language is not yet finished. You can help this project by translating the chapters and contributing your changes.

14.3. Archivo Module.php y escucha de eventos

El archivo Module.php ubicado dentro de la carpeta fuente del módulo es un tipo de punto de entrada al módulo. La clase Module que esta definida en este archivo es cargada por el componente Zend\ModuleManager cuando este carga todos los módulos de la aplicación.

Una cosa útil que podemos hacer con esta clase es registrar eventos. Si recordamos el capítulo Operación del Sitio Web, la aplicación tiene varias etapas de vida que son representadas por eventos. Podemos escribir una función o clase de escucha de eventos, event listener, y registrarla en el punto de entrada al módulo. Cuando un evento se lanza nuestro método o clase de escucha es llamado permitiendo hacer algo útil.

¿Por qué querría registrar un escucha de eventos?

Aquí están varias aplicaciones prácticas de un escucha de eventos que podríamos encontrar útiles:

  • Escuchar un evento Route para obligar a usar una conexión segura HTTPS.
  • Cuando nuestro sitio web está en modo de mantenimiento, escuchar un evento Route para capturar todas las peticiones y redirigir al usuario a una solo página.
  • Escuchar un evento Dispatch para redirigir al usuario a una página diferente. Por ejemplo, si el usuario no está autenticado él es redirigido a la página de inicio de sesión.
  • Escuchar un evento Dispatch para sobrescribir la maqueta de plantilla predeterminada en todos los controladores que pertenecen al módulo.
  • Escuchar un evento Dispatch Error para registrar o reportar cualquier excepción o error que suceda en nuestro sitio web.
  • Escuchar un evento Render para modificar el contenido de la página resultante.

Existen dos maneras de registrar un escucha de eventos, evento listener, dentro de la clase Module: con la ayuda del método init() del módulo o con la ayuda de su método onBootstrap(). La diferencia entre el método init() y el método onBootstrap() es que el método init() se llama primero que el método onBootstrap(). El método init() se llama antes de inicializar todos los otros módulos, mientras que onBootstrap() se llama una vez que todos los módulos se han inicializado. En los siguientes ejemplos usaremos el método init().

14.3.1. Ejemplo 1. Cambiar la maqueta de plantilla

Para mostrar como suscribir un evento vamos a crear un escucha de eventos que reaccionará a un evento Dispatch y colocará una maqueta de plantilla diferente para todos los controladores del módulo:

<?php
namespace YourCompanyModule;

use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;

class Module
{
    // The "init" method is called on application start-up and
    // allows to register an event listener.
    public function init(ModuleManager $manager)
    {
        // Get event manager.
        $eventManager = $manager->getEventManager();
        $sharedEventManager = $eventManager->getSharedManager();
        // Register the event listener method.
        $sharedEventManager->attach(__NAMESPACE__, 'dispatch',
                                    [$this, 'onDispatch'], 100);
    }

    // Event listener method.
    public function onDispatch(MvcEvent $event)
    {
        // Get controller to which the HTTP request was dispatched.
        $controller = $event->getTarget();
        // Get fully qualified class name of the controller.
        $controllerClass = get_class($controller);
        // Get module name of the controller.
        $moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));

        // Switch layout only for controllers belonging to our module.
        if ($moduleNamespace == __NAMESPACE__) {
            $viewModel = $event->getViewModel();
            $viewModel->setTemplate('layout/layout2');
        }
    }

    // ...
}

En el código de arriba, agregamos el método init() a la clase Module. En este método, registramos un escucha de eventos (línea 17) con la ayuda del método attach() que provee la clase Zend\EventManager\SharedEventManager. El método attach() toma cuatro argumentos: el identificador del componente emisor, el nombre del evento («dispatch»), el método de escucha de eventos (el método onDispatch() de la clase actual) y la prioridad (100).

El método onDispatch() se llama con un evento Dispatch. En este método, revisamos (línea 32) si la petición HTTP fue enviada al controlador que pertenece a nuestro módulo y de ser así cambiamos la maqueta de plantilla (línea 34).

14.3.2. Ejemplo 2. Forzar el uso con HTTPS

En este ejemplo, mostraremos como registrar un escucha de eventos que obliga al sitio web a usar siempre conexión HTTPS en todas nuestras páginas web.

<?php
namespace YourCompanyModule;

use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;

class Module
{
    // The "init" method is called on application start-up and
    // allows to register an event listener.
    public function init(ModuleManager $manager)
    {
        // Get event manager.
        $eventManager = $manager->getEventManager();
        $sharedEventManager = $eventManager->getSharedManager();
        // Register the event listener method.
        $sharedEventManager->attach(__NAMESPACE__, 'route',
                                    [$this, 'onRoute'], 100);
    }

    // Event listener method.
    public function onRoute(MvcEvent $event)
    {
        if (php_sapi_name() == "cli") {
            // Do not execute HTTPS redirect in console mode.
            return;
        }

        // Get request URI
        $uri = $event->getRequest()->getUri();
        $scheme = $uri->getScheme();
        // If scheme is not HTTPS, redirect to the same URI, but with
        // HTTPS scheme.
        if ($scheme != 'https'){
            $uri->setScheme('https');
            $response=$event->getResponse();
            $response->getHeaders()->addHeaderLine('Location', $uri);
            $response->setStatusCode(301);
            $response->sendHeaders();
            return $response;
        }
    }

    // ...
}

En el código de arriba, registramos un escucha de eventos que se llama con cada evento Route.

Dentro del escucha de eventos, primero revisamos si nuestro sitio web está trabajando en el modo de consola. No debemos redirigir a HTTPS si se está en el modo de consola.

Luego, extraemos la URI del la petición HTTP y revisar si el esquema actual es HTTPS o no. Si el esquema no es HTTPS, redirigimos al usuario a la misma URL pero con el esquema HTTPS.

14.3.3. Ejemplo 3. Reportar todas las excepciones de nuestro sitio web

Con esta técnica, podemos fácilmente rastrear todas las excepciones que ocurren en nuestro sitio web. Reportar excepciones y errores es una tarea importante, porque permite hacer a nuestro sitio web más estable, seguro y mejorar la experiencia del usuario.

<?php
namespace YourCompanyModule;

use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;

class Module
{
    // The "init" method is called on application start-up and
    // allows to register an event listener.
    public function init(ModuleManager $manager)
    {
        // Get event manager.
        $eventManager = $manager->getEventManager();
        $sharedEventManager = $eventManager->getSharedManager();
        // Register the event listener method.
        $sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH_ERROR,
                                    [$this, 'onError'], 100);
        $sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_RENDER_ERROR,
                                    [$this, 'onError'], 100);
    }

    // Event listener method.
    public function onError(MvcEvent $event)
    {
        // Get the exception information.
        $exception = $event->getParam('exception');
        if ($exception!=null) {
            $exceptionName = $exception->getMessage();
            $file = $exception->getFile();
            $line = $exception->getLine();
            $stackTrace = $exception->getTraceAsString();
        }
        $errorMessage = $event->getError();
        $controllerName = $event->getController();

        // Prepare email message.
        $to = 'admin@yourdomain.com';
        $subject = 'Your Website Exception';

        $body = '';
        if(isset($_SERVER['REQUEST_URI'])) {
            $body .= "Request URI: " . $_SERVER['REQUEST_URI'] . "\n\n";
        }
        $body .= "Controller: $controllerName\n";
        $body .= "Error message: $errorMessage\n";
        if ($exception!=null) {
            $body .= "Exception: $exceptionName\n";
            $body .= "File: $file\n";
            $body .= "Line: $line\n";
            $body .= "Stack trace:\n\n" . $stackTrace;
        }

        $body = str_replace("\n", "<br>", $body);

        // Send an email about the error.
        mail($to, $subject, $body);
    }

    // ...
}

En el código de arriba, registramos un escucha de eventos que se llamará en cada error Dispatch (ruta no encontrada o una excepción) y cada error para mostrar la página. Dentro del método de escucha onError(), extraemos alguna información sobre la excepción o error y lo enviamos como un mensaje de correo electrónico a una dirección de correo electrónico.


Top