Skip to content

Cross Module API

Ray Fung edited this page Feb 26, 2026 · 4 revisions

Cross-Module API

The Cross-Module API allows modules to expose and consume typed commands through a provider/consumer handshake. This enables service-style communication between independent modules without tight coupling.

How It Works

The flow is:

  1. Provider registers API commands via Agent::addAPICommand() in __onInit().
  2. Consumer requests an API handle via $this->api() in __onReady() (after all modules are loaded).
  3. Framework performs a handshake: calls the provider's __onAPICall() with the consumer's ModuleInfo.
  4. If the provider grants access, the consumer receives an Emitter object and can invoke commands.

Defining an API Provider

// In controller __onInit()
public function __onInit(Agent $agent): bool
{
    // Register API commands ??second argument is a closure file path (without .php)
    $agent->addAPICommand('getVersion', 'api/getVersion');
    $agent->addAPICommand('processData', 'api/processData');

    return true;
}

Then create the closure files:

// controller/api/getVersion.php
return function(): string {
    return '1.0.0';
};
// controller/api/processData.php
return function(string $data): string {
    return strtoupper($data);
};

Authorizing the Handshake

// Provider's controller
public function __onAPICall(ModuleInfo $module, string $method, string $fqdn = ''): bool
{
    // Grant access to specific modules
    return in_array($module->getCode(), [
        'demo/consumer_module',
        'demo/another_module',
    ]);
}

? ï? Warning: Security: Always validate the caller in __onAPICall(). Returning true unconditionally allows any module to call your API.

Consuming an API

// Consumer's controller __onReady()
public function __onReady(): void
{
    $api = $this->api('demo/provider_module');

    if ($api) {
        // Invoke the provider's command
        $version = $api->getVersion();
        $result  = $api->processData('hello');
    }
}

API Class Reference

Method Return Description
__call(string $command, array $args) mixed Invoke a registered API command via magic method
has(string $command) bool Check if a command exists
getModuleCode() string Get the provider's module code

Agent API Methods

Method Context Description
addAPICommand(mixed $command, ?string $path = null) Provider (__onInit) Register an API command mapped to a closure file path (without .php)
getAPI(string $moduleCode) Consumer Request API handle from another module

Best Practices

  • Register API commands in __onInit(), where the Agent is available. Use __onReady() to consume APIs.
  • Use __onAPICall() to whitelist consumers by module code.
  • Always check the return value of getAPI() or $this->api() ??it returns null if the handshake is denied.
  • Keep API commands focused and well-named to serve as a stable contract between modules.

??PreviousEvent System Next ?’Database

Clone this wiki locally