Extensions: Registro e Lifecycle¶
Esta página detalha a direção arquitetural esperada pelo ADR-0004.
O objetivo é separar com clareza:
- register(): declaração estrutural;
- boot(): integração de runtime;
- metadata: identidade e dependências da extension;
- interfaces públicas: como uma extension expõe capacidades para outras extensions e terceiros.
Estrutura e metadata¶
O padrão atual de diretório e metadata é contrato do framework.
Exemplo educacional:
<?php
namespace local_middag\extensions\ecommerce;
use local_middag\base\extension;
final class ecommerce_extension extends extension
{
public const EXTENSION_IDNUMBER = 'ecommerce';
public const GROUP = 'integrations';
public const PRIORITY = 20;
public const REQUIRES = ['webhooks'];
}
Quando usar register()¶
Use register() para declarar bindings e parâmetros.
Exemplo educacional:
<?php
public function register(ContainerInterface $container): void
{
$container->register(store_sync_service::class, store_sync_service::class);
}
Não use register() para:
- acessar DB;
- ler config operacional do Moodle;
- resolver serviços;
- chamar outra extension.
Quando usar boot()¶
Use boot() para integração de runtime.
Exemplo educacional:
<?php
public function boot(): void
{
middag::add_action('middag/extension/ecommerce/order_processed', static function (object $payload): void {
// reação pública
});
}
Também é válido registrar listeners de signals, filters públicos e outros pontos reativos da extension nessa fase.
Como uma extension expõe capacidade¶
Facade própria da extension¶
Quando a integração for simples e estática, a extension pode expor facade própria.
<?php
namespace local_middag\extensions\sentry\facade;
use local_middag\base\facade;
use local_middag\extensions\sentry\service\sentry_service;
final class sentry extends facade
{
public static function get_facade_accessor(): string
{
return sentry_service::class;
}
}
Estabilidade
A facade da extension pode ser pública. A estabilidade dela pertence à própria extension, não ao core do MIDDAG.
Contract @api e DI¶
Quando a integração for estrutural, prefira contract @api e DI.
<?php
namespace local_middag\extensions\reports\service;
use local_middag\extensions\ecommerce\contract\store_report_provider_interface;
final class report_service
{
public function __construct(
private store_report_provider_interface $provider,
) {}
}
Hook público ou dispatch()¶
Quando a integração for reativa, prefira hooks públicos, filters ou dispatch().
<?php
middag::add_action('middag/extension/ecommerce/order_processed', static function (object $payload): void {
// integração reativa
});
Como uma extension não deve consumir outra extension¶
Evite chamar regra de negócio interna de outra extension por classe concreta ou via extension_service.
Exemplo a evitar:
Prefira uma interface pública:
ou:
<?php
middag::dispatch(new \local_middag\extensions\ecommerce\signal\order_processed_signal(
order_id: 10,
customer_id: 99,
status: 'processed',
));
Regra prática¶
- quero declarar estrutura ->
register() - quero integrar runtime ->
boot() - quero expor consumo simples -> facade própria
- quero expor integração estrutural -> contract
@api - quero expor integração reativa ->
dispatch(), action hook ou filter