API Pública e Camada de Extensão¶
O MIDDAG não trata toda classe reutilizável como API pública. A arquitetura separa explicitamente o que é estável para consumo externo, o que é estável apenas para extensão controlada e o que permanece interno por padrão.
Três zonas de consumo¶
| Zona | Público principal | Objetivo | Estabilidade esperada |
|---|---|---|---|
| API pública estável | plugins externos, integrações e extensões consumidoras | acesso seguro a capacidades públicas | alta |
| Camada de extensão controlada | extensões e integrações que seguem o modelo do framework | herança, estruturação e composição guiada | alta, mas com escopo controlado |
| Interno por padrão | core do framework | liberdade de implementação e refatoração | sem garantia externa |
Facades¶
Facades existem para reduzir acoplamento de consumidores externos com classes internas, caminhos de arquivo e detalhes de wiring.
Use facade quando:
- houver necessidade de acesso estático simples;
- a capacidade já for tratada como pública pelo core;
- o objetivo for proteger consumidores contra reorganização interna do framework.
Não use facade como regra universal:
- nem toda capacidade pública precisa de facade;
- código interno do framework deve preferir DI;
- integrações mais estruturadas podem depender de contracts
@apiou classes-base.
Quando uma facade existir, ela deve apontar para um accessor estável governado pelo framework, normalmente baseado em resolução pelo container.
Quando preferir facade ou contract @api¶
Use facade quando:
- o consumo for externo e simples;
- a chamada puder ser estática e direta;
- o objetivo principal for ergonomia e desacoplamento de wiring interno.
Use contract @api quando:
- a integração exigir DI;
- o consumidor precisar compor um service próprio;
- houver necessidade de substituição, implementação alternativa ou decoração suportada.
<?php
use local_middag\middag;
middag::init();
// consumo simples por facade principal
middag::add_action('middag/matricula/created', static function (array $payload): void {
// reacao simples
});
<?php
namespace local_vendor\local_partner\service;
use local_middag\framework\contract\repository\item_repository_interface;
final class partner_sync_service
{
public function __construct(
private item_repository_interface $item_repository,
) {}
}
Contracts¶
Contracts em classes/framework/contract/ não são públicos por localização. O critério real é a anotação e a intenção arquitetural.
@api: contract estável para consumo externo, type-hint, DI ou implementação alternativa suportada.@internal: contract interno, livre para reorganização.
Promover um contract para @api faz sentido quando:
- consumidores externos precisam tipar contra ele;
- extensões precisam fornecer implementação alternativa suportada;
- o core quer preservar esse ponto como contrato estável.
Classes-base¶
As classes em classes/base/ formam a camada de extensão controlada.
Elas existem para:
- abrir pontos seguros de herança;
- evitar que extensões dependam de classes internas do framework;
- padronizar como extensions, controllers, repositories, services, DTOs e outros tipos se conectam ao núcleo.
Elas não significam "liberdade total" sobre o framework inteiro. São pontos de abertura deliberados.
Plugins terceiros também podem adotá-las quando quiserem seguir o modelo arquitetural do MIDDAG de forma mais próxima.
<?php
namespace local_vendor\local_partner\repository;
use local_middag\base\repository;
final class partner_order_repository extends repository
{
// implementação própria aderente ao modelo do framework
}
Regras por público¶
Framework interno¶
- usa DI e contracts internos;
- trata facades como interface voltada a consumo externo, não como atalho padrão interno;
- pode reorganizar internals sem comprometer a API pública.
<?php
namespace local_middag\framework\application\service\revision;
use local_middag\framework\contract\repository\item_repository_interface;
final class revision_capture_service
{
public function __construct(
private item_repository_interface $item_repository,
) {}
}
Extensions do ecossistema MIDDAG¶
- devem preferir classes-base para herança;
- devem usar contracts
@apiquando a integração exigir DI; - devem preferir facades públicas quando consumirem capacidades já expostas estaticamente.
<?php
namespace local_middag\extensions\ecommerce;
use local_middag\base\extension;
final class ecommerce_extension extends extension
{
public const EXTENSION_IDNUMBER = 'ecommerce';
}
<?php
namespace local_middag\extensions\ecommerce\service;
use local_middag\framework\contract\repository\item_repository_interface;
final class order_sync_service
{
public function __construct(
private item_repository_interface $item_repository,
private store_client_factory $store_client_factory,
) {}
}
<?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;
}
}
Facade de extension
Uma facade de extension pode ser pública e consumida livremente. A estabilidade dela, porém, pertence à própria extension que a expõe, não ao core do local_middag.
Plugins e integrações de terceiros¶
- devem preferir facades quando elas existirem;
- podem usar contracts
@apiquando precisarem integrar por DI; - não devem depender de classes internas do framework nem inferir publicidade por caminho de arquivo.
<?php
use local_middag\framework\contract\repository\item_repository_interface;
use local_middag\middag;
middag::init();
$item_repository = middag::get(item_repository_interface::class);
$item = $item_repository->find_by_id(42);
Uso fora da API pública
Resolver classes concretas internas do framework ou depender de caminhos como classes/framework/... não é integração estável. Isso pode funcionar tecnicamente, mas não é uma garantia do produto.
<?php
use local_middag\framework\infrastructure\persistence\repository\item_repository;
// Evite este padrão em plugins terceiros.
$item_repository = new item_repository(/* dependencias internas */);
Regra prática¶
Se um tipo não estiver explicitamente exposto como facade pública, contract @api ou classe-base, trate-o como interno por padrão.