Cómo funcionan los Eventos en Magento2

Log personalizado

La semana pasada veíamos un ejemplo práctico de cómo usar Observers.

En la definición del Observer decíamos que se ejecutan cuando el evento para el cual fueron configurados a escuchar, es disparado.

Bien, los eventos son disparados por los propios módulos de Magento, pero eso no quita que nosotros podamos crear los nuestros.

Cuando se dispara un evento, no sólo podemos registrar esa acción, sino que desde el evento podemos pasar datos hacia el observer, ya sea una referencia o un objeto completo.

El componente (la clase) que nos permitirá disparar eventos es Magento\Framework\Event\Manager. A nuestra clase le inyectaremos en el constructor esta dependencia y a partir de allí tendremos disponible el objeto que nos ofrece una única acción o método: dispatch.

El método dispatch recibe dos parámetros:

  • Nombre del evento
  • Array de datos (este segundo parámetro es opcional)

Ejemplo práctico de la mano del módulo Barbanet_SampleModule.

Hace ya varias versiones habíamos creado un frontend controller: /Controller/Index/Index.php. Voy a modificar el action para que dispare un evento que luego capturará un nuevo observer. El método execute del controller quedará ahora, así:

<?php
 
namespace Barbanet\SampleModule\Controller\Index;
 
class Index extends \Barbanet\SampleModule\Controller\Index
{
 
    /**
     * Show Sample Module main page
     *
     * @return void
     */
    public function execute()
    {
        $this->_view->loadLayout();
        $this->_view->renderLayout();
 
        $sample = 'Mensaje que voy a llevarle al Observer';
 
        $this->_eventManager->dispatch('barbanet_samplemodule_controller_event_after',['sample' => $sample]);
    }
}

Como puede verse, estoy haciendo uso de $this->_eventManager que, en el caso de los controllers, lo estamos heredando.

(Si, a pesar que todos se la pasan hablando de cómo hay que programar, de las metodologías, estándares, nomenclaturas y demás, vamos a encontrar que en ciertos casos vamos a referenciar el objeto como _eventManager y en otros casos como eventManager y de otra manera, si queremos, cuando lo inyectemos en nuestras clases independientes).

Retomando el ejemplo, he disparado un evento y le he agregado un string que quiero que sea procesada por el Observer.

Ahora voy a repetir rápidamente lo aprendido en el post sobre cómo usar Observers y voy a crear uno específico para este caso (si, específico porque vamos a respetar el principio de responsabilidad única).

Entonces, creo mi nuevo obsever en Observer/Controller/Sample.php:

<?php
 
namespace Barbanet\SampleModule\Observer\Controller;
 
use Magento\Framework\Event\ObserverInterface;
 
class Sample implements ObserverInterface
{
 
    /**
     * @var
     */
    private $logger_custom;
 
    /**
     * @param \Barbanet\SampleModule\Logger\Sample $logger_custom
     */
    public function __construct(
        \Barbanet\SampleModule\Logger\Sample $logger_custom
    ) {
        $this->logger_custom = $logger_custom;
    }
 
    /**
     * @param \Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $sample = $observer->getSample();
        $this->logger_custom->info($sample);
    }
}

Si bien no es necesario, aproveché lo aprendido ayer e inyecté mi logger custom. La idea será capturar el evento, tomar la variable (que contiene un string) y enviarla a mi logger.

Ahora voy a definir en events.xml que mi observer escuche mi evento custom. Para esto agregaré un segundo evento al final del archivo:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_controller_product_view">
        <observer name="BarbanetProductData" instance="Barbanet\SampleModule\Observer\Product\Data" />
    </event>
    <event name="barbanet_samplemodule_controller_event_after">
        <observer name="BarbanetControllerSample" instance="Barbanet\SampleModule\Observer\Controller\Sample" />
    </event>
</config>

Ahora limpiamos cache y en nuestro navegador accedemos a la url del controller.

Probando controller del módulo

Reviso mi log (el de ayer, var/log/my-sample-log.log):

[2017-06-29 06:17:33] BarbanetSampleLogger.INFO: Mensaje que voy a llevarle al Observer [] []

Efectivamente, disparamos nuestro evento con datos específicos. Luego nuestro observer capturó el evento y procesó la información.

Siguiendo con este texto que copio y pego cada vez, lo comentado en el post sobre el módulo Barbanet_SampleModule está disponible en GitHub bajo el tag 2.19.0.