Observer Endpoints

Observer endpoints let plugins dispatch named events that any active module can subscribe to, without creating a direct dependency between them.

1. Define a Listener Interface

Create the interface in the dispatching plugin's domain/listener/ (or domain/event/) folder:

namespace plugin\TestPlugin\domain\event;

use plugin\TestPlugin\domain\model\TestValuesObject;

interface ITestListener
{
    public function onTestHandler(TestValuesObject $testValuesObject): void;
}

2. Dispatch the Event

Call dispatchObserverEndpoint() with the interface and a closure, or use dispatchObserverEndpointByMethodName() as a shorthand:

use plugin\Modules\ModulesManager;
use plugin\TestPlugin\domain\event\ITestListener;

// Explicit closure — use when you need to control argument passing
ModulesManager::getInstance()->dispatchObserverEndpoint(
    ITestListener::class,
    function (ITestListener $instance, ...$args) {
        $instance->onTestHandler(...$args);
    },
    $testValuesObject
);

// Shorthand — use when the method signature maps directly to the extra args
ModulesManager::getInstance()->dispatchObserverEndpointByMethodName(
    ITestListener::class,
    'onTestHandler',
    $testValuesObject
);

All extra arguments beyond the closure are passed by reference. Mutating them inside the closure affects the original data.

3. Subscribe in a Module

Implement the listener interface in any module that needs to handle the event:

use DisplayPlugin;
use plugin\Modules\IModule;
use plugin\TestPlugin\domain\event\ITestListener;
use plugin\TestPlugin\domain\model\TestValuesObject;

class TestModulePlugin extends DisplayPlugin implements IModule, ITestListener
{
    public function onTestHandler(TestValuesObject $testValuesObject): void
    {
        // Handle the event
    }
}

New listener interfaces belong in domain/listener/ of the plugin that owns the event.