En el artículo anterior sobre observers en Moodle explicábamos cómo un plugin puede reaccionar cuando ocurre algo en la plataforma.

En este artículo vamos a mirar el otro lado del mecanismo: cómo se generan y se distribuyen esos eventos dentro del sistema.

Los observers reaccionan a esos eventos, pero el sistema que permite describirlos, generarlos y distribuirlos es el Event API de Moodle. A través de este subsistema la plataforma comunica internamente acciones relevantes y permite que otros componentes reaccionen a ellas sin depender directamente unos de otros.

Desde el punto de vista arquitectónico, este mecanismo introduce dentro de Moodle un modelo basado en eventos que recuerda a lo que en arquitectura de software se conoce como Event-Driven Architecture, aunque aquí aparece aplicado principalmente como mecanismo interno de comunicación entre componentes.

Qué es realmente un evento en Moodle

Un evento representa que ha ocurrido algo relevante en el sistema. Los eventos son principalmente el resultado de acciones de una persona usuaria, aunque también pueden generarse como resultado de procesos ejecutados por cron o de operaciones administrativas realizadas desde línea de comandos.

En la práctica esto puede traducirse en situaciones como la creación de un curso, la visualización de informe, la finalización de una tarea programada o la ejecución de una operación administrativa desde CLI.

Cuando esa acción termina, el código crea un evento y lo distribuye dentro del sistema. A partir de ese momento cualquier componente que haya declarado interés en ese evento (esté suscrito) puede reaccionar a él.

El resultado es un mecanismo de comunicación interno donde una parte del sistema publica un hecho y otras partes deciden si necesitan actuar en consecuencia.

Cómo se define un evento

Los eventos en Moodle se implementan como clases PHP que extienden la clase abstracta \core\event\base.

Cada evento vive en su propia clase y normalmente en su propio fichero dentro del plugin, siguiendo la estructura: plugindir/classes/event/something_happened.php

Los namespaces utilizados son \core\event y \frankenstyle_component\event. El primero corresponde a eventos definidos por el propio core, el segundo es el utilizado por cualquier plugin que quiera declarar eventos propios, por ejemplo \gradereport_user\event o \tool_usertours\event.

Las clases de evento siguen además una convención bastante clara para nombrar los eventos basada en el patrón: object_action. Ejemplos habituales del core son nombres como course_created, grade_report_viewed o field_updated.

La documentación oficial recoge estas reglas de nomenclatura en https://docs.moodle.org/dev/Events_API#Events_naming_convention

Cómo se dispara un evento

Cuando la acción correspondiente ocurre en el código, el evento se instancia y se dispara explícitamente.

Un patrón típico sería algo como esto:

$event = \local_example\event\item_completed::create([
    'context' => $context,
    'objectid' => $itemid,
]);

$event->trigger();

El momento en el que se ejecuta trigger() es cuando el evento entra en el sistema de eventos de Moodle. A partir de ahí el core se encarga de distribuirlo a todos los observers registrados para ese tipo de evento.

Este mecanismo forma parte del propio flujo de ejecución de la aplicación.

Qué información contiene un evento

Los eventos deben contener tanta información como sea posible, siempre que hacerlo no afecte negativamente al rendimiento del sistema.

La documentación describe un conjunto de propiedades que el desarrollador debe proporcionar al crear el evento, así como otras que pueden generarse automáticamente cuando es posible hacerlo sin coste adicional.

Algunas de estas propiedades no son obligatorias, pero forman parte del modelo de información que permite describir correctamente lo ocurrido.

La lista completa de propiedades está documentada en https://docs.moodle.org/dev/Events_API#Properties

El objetivo es que los observers dispongan de suficiente contexto para reaccionar al evento sin necesidad de realizar consultas innecesarias a la base de datos.

Snapshots y estado del sistema

En algunos casos el observer necesita acceder al estado exacto que tenía un registro cuando ocurrió el evento.

Para eso existen los record snapshots. Un snapshot es una copia del estado de un registro de base de datos en el momento en que se dispara el evento.

Estos snapshots están pensados exclusivamente para ser utilizados desde observers. No deben utilizarse en, por ejemplo, reports o en el propio evento, ya que representan el estado de los datos en el momento en que se generó el evento y no necesariamente el estado actual de la base de datos.

Esto significa que, cuando el observer se ejecuta, el registro original puede haber cambiado o incluso haber desaparecido de las tablas del sistema. Un ejemplo típico aparece en eventos de borrado, donde el snapshot permite acceder a información que ya no existe en la base de datos.

Eventos en operaciones masivas

Cuando una operación afecta a múltiples objetos, los eventos deben generarse de forma individual.

Una operación bulk que modifique varios registros debería generar un evento por cada objeto afectado. En algunos casos también puede tener sentido emitir eventos adicionales para describir el inicio y el final de esa operación bulk.

Este enfoque permite que observers, sistemas de logging o integraciones externas reaccionen con precisión a cada cambio concreto dentro del sistema.

El sistema de logging también escucha eventos

El sistema de logging de Moodle funciona internamente como un observer que se suscribe a todos los eventos. En la práctica esto significa que el subsistema de logging escucha el evento '*', registrando cualquier evento que se dispare dentro de la plataforma.

Este detalle muestra bien cómo se utiliza el Event API dentro del propio core. El mismo mecanismo que permite reaccionar a eventos en plugins sirve también para registrar actividad, construir auditorías o alimentar integraciones externas.

Monitorización de eventos desde la interfaz de Moodle

Existe una funcionalidad interesante dentro de la propia interfaz de Moodle: el Event Monitoring.

Desde la UI se pueden definir reglas que reaccionen cuando ocurre un evento concreto, lo que permite monitorizar determinadas acciones dentro de la plataforma sin necesidad de escribir código.

La posibilidad de suscribirse a estos eventos depende de la capability: tool/monitor:subscribe

En la práctica esta funcionalidad permite observar determinados eventos desde la interfaz administrativa y recibir notificaciones cuando se producen, lo que resulta útil en contextos de supervisión o auditoría.

Descubrir quién escucha un evento

Cuando trabajas con eventos, en ocasiones, puede ser útil identificar qué observers están escuchando un evento concreto.

Las herramientas modernas de desarrollo ayudan bastante en esta tarea. Por ejemplo, si utilizas MDLCode (de LMSCloud) en su versión de pago, podrás navegar desde la definición de un evento hasta los observers que están suscritos a él directamente desde el IDE (VSCode o PhpStorm).

Esto facilita entender cómo se conecta el comportamiento de distintos plugins dentro de una instalación Moodle compleja.

Eventos como parte del diseño del sistema

Cuando un plugin define y dispara eventos propios está declarando qué hechos del dominio considera relevantes dentro de la plataforma. Cada evento introduce un punto explícito del sistema donde otros componentes pueden reaccionar, integrarse o ampliar ese comportamiento sin necesidad de modificar el código original.

Con el tiempo, en una instalación Moodle compleja, la red de eventos termina describiendo cómo evoluciona el estado del sistema y cómo se coordinan entre sí sus distintos componentes. Observers, logging, monitorización o integraciones externas operan sobre ese mismo mecanismo, reaccionando a los eventos que atraviesan la plataforma y utilizando ese flujo como base para extender su comportamiento.