-
Notifications
You must be signed in to change notification settings - Fork 0
Cross Module API
Ray Fung edited this page Feb 26, 2026
·
4 revisions
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.
The flow is:
-
Provider registers API commands via
Agent::addAPICommand()in__onInit(). -
Consumer requests an API handle via
$this->api()in__onReady()(after all modules are loaded). - Framework performs a handshake: calls the provider's
__onAPICall()with the consumer'sModuleInfo. - If the provider grants access, the consumer receives an
Emitterobject and can invoke commands.
// 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);
};// 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(). Returningtrueunconditionally allows any module to call your 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');
}
}| 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 |
| 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 |
- Register API commands in
__onInit(), where theAgentis 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 returnsnullif the handshake is denied. - Keep API commands focused and well-named to serve as a stable contract between modules.