Skip to content

Visão Geral da Arquitetura

O middag-account segue uma arquitetura DDD Light com direção de dependência estrita. A lógica de domínio reside em PHP puro, sem nenhuma importação do WordPress. O WordPress atua como adaptador de infraestrutura.

Camadas

src/
├── Core/              # DI Container, Kernel, ServiceProvider, Middleware
├── Domain/            # PHP puro — ZERO dependências WordPress
├── WordPress/         # Camada de abstração CMS (6 adaptadores)
├── Api/V1/            # REST controllers (middag-account/v1)
├── Integration/       # HubSpot, Stripe, ISSNet, BancoInter, Cloudflare, SolidAffiliate
└── UI/                # Inertia page controllers, Router, FormPanelData

Direção de Dependência

WordPress/ ──→ Domain/
Api/       ──→ Domain/
Integration/ → Domain/
UI/        ──→ Domain/

O Domain nunca importa de WordPress, Api, Integration ou UI. Isso é garantido pela análise estática do PHPStan.

Symfony DI Container 7.4

Todas as classes utilizam injeção de construtor. Zero chamadas estáticas a serviços.

Auto-discovery por sufixo: classes com sufixo Service, Repository, Controller, Handler, Hooks ou Registrar são registradas automaticamente. Adicionar uma nova classe com o sufixo correto é suficiente -- nenhum registro manual é necessário.

O container é compilado em produção para melhor desempenho.

Mapeamento de Namespaces (PSR-4)

NamespaceDiretório
Middag\Account\Core\src/Core/
Middag\Account\Domain\{Name}\src/Domain/{Name}
Middag\Account\WordPress\src/WordPress/
Middag\Account\Api\V1\src/Api/V1/
Middag\Account\Integration\{Name}\src/Integration/
Middag\Account\UI\src/UI/

Camada de Domínio

Cada domínio segue uma estrutura padrão:

Domain/{Name}/
├── {Name}Entity.php              # Imutável (readonly), JsonSerializable
├── {Name}DTO.php                 # Data Transfer Object
├── {Name}RepositoryInterface.php # Contrato (interface)
├── {Name}Service.php             # Lógica de negócio, orquestração
├── {Name}Status.php              # Enum de status com transições
└── {Name}Exception.php           # Exceções específicas do domínio

As entidades utilizam propriedades readonly do PHP 8.4, backed enums para status e métodos factory fromArray() que aceitam tanto chaves snake_case da API quanto chaves com prefixo CCT.

Camada de Abstração WordPress (6 Adaptadores)

AdaptadorResponsabilidade
PostTypeRegistro de CPT (middag_{domain}), capabilities customizadas
DatabaseAbstração sobre wp_posts + wp_postmeta, toggle CCT
HookHookInterface com register(), prefixo middag/
RestRegistro de rotas REST com permission_callback
CronHandlers leves de WP-Cron delegando para serviços de domínio
EmailTemplates sobregraváveis pelo tema via TemplateRenderer

Padrão Repository

O código de domínio define interfaces de repositório. A camada adaptadora WordPress fornece implementações concretas usando QueryBuilder e MetaRepository. O container DI vincula a interface à implementação.

php
// Camada de domínio — interface PHP pura
namespace Middag\Account\Domain\Organization;

interface OrganizationRepositoryInterface
{
    public function findById(int $id): ?OrganizationEntity;
    public function findByOwnerId(int $ownerId): array;
    public function save(OrganizationDTO $dto): int;
}
php
// Camada WordPress — implementação concreta
namespace Middag\Account\WordPress\Repository;

final class OrganizationRepository implements OrganizationRepositoryInterface
{
    // Usa QueryBuilder + MetaRepository internamente
}

Toggle de Repositório Dual

A opção middag_migration_complete alterna entre repositórios CCT ($wpdb direto) e repositórios baseados em wp_posts. Isso permite migração gradual sem perda de dados.

Sequência de Boot

O plugin inicializa no hook plugins_loaded -- nunca imediatamente. O Kernel compila o container DI, registra hooks e carrega serviços auto-descobertos.

php
add_action('plugins_loaded', function (): void {
    $kernel = new Kernel();
    $kernel->boot();
});

Recursos do PHP 8.4+

  • Backed enums nativos para todos os tipos de status
  • Classes e propriedades readonly em todas as entidades
  • Expressões match para transições de status
  • Named arguments em toda a base de código
  • Tipagem estrita aplicada em todos os arquivos

Recursos Relacionados