Visão Geral da Arquitetura¶
O MIDDAG adota uma arquitetura inspirada em conceitos de DDD (Domain-Driven Design) e Arquitetura Hexagonal (Ports and Adapters), adaptada para conviver dentro do ecossistema procedural do Moodle.
O objetivo principal é desacoplar a lógica de negócio (Regras Educacionais, Gestão de Itens, Extensões) da infraestrutura do Moodle (Banco de Dados global, Globals $DB, $CFG, Output Buffers).
Fluxo de Requisição (Request Lifecycle)¶
Diferente de plugins tradicionais que misturam HTML, SQL e lógica em arquivos .php soltos, o MIDDAG centraliza o fluxo de execução através de um Kernel.
O diagrama abaixo ilustra como uma requisição sai do Moodle e trafega pelas camadas do plugin até retornar uma resposta:
graph TD
subgraph Moodle_Environment [Ambiente Moodle]
User((Usuário)) -->|Requisição HTTP| MoodleCore[Moodle Core / Lib.php]
MoodleCore -->|Hook / Entry Point| Facade[Facade Estática: middag::class]
end
subgraph MIDDAG_Core [Camada de Aplicação]
Facade -->|init & handle| Kernel[Kernel]
Kernel -->|Boot| Container[DI Container]
Kernel -->|Match Route| Router[Route Manager]
Router -->|Dispatch| Controller[Base Controller]
Controller -->|Call| Service[Service Layer]
end
subgraph Domain_Layer [Camada de Domínio]
Service -->|Orchestrate| DomainEntity["Domain Entity (Item)"]
Service -->|Use| QueryBuilder[Query Builder]
end
subgraph Infrastructure_Layer [Camada de Infraestrutura]
QueryBuilder -->|Build SQL| Repository[Repository]
Repository -->|Hydrate| Mapper[Data Mapper]
Repository -->|Execute SQL| MoodleDB[(Moodle Database)]
end
Repository -->|Return Entity| Service
Service -->|Return DTO/Result| Controller
Controller -->|Return Response| MoodleCore
Camadas da Aplicação¶
A arquitetura é dividida em 4 camadas estritas. Uma camada superior pode depender das inferiores, mas o inverso é proibido (ex: o Domínio nunca deve saber sobre o Controller).
1. Camada de Interface (Platform)¶
Responsável por receber a entrada do usuário (HTTP, CLI, Ajax) e converte-la para comandos que a aplicação entende.
- Controllers: Recebem
Request, validam permissões (Auth) e delegam para Services. - API: Endpoints REST/Ajax que retornam JSON estrito.
- Console/CLI: Comandos de terminal para manutenção.
2. Camada de Aplicação (Service)¶
É a "cola" do sistema. Contém a lógica de orquestração, mas não a lógica de negócio pura.
- Services: Coordenam operações (ex: "Criar um item e notificar o usuário").
- Extension Service: Gerencia o ciclo de vida dos módulos adicionais.
3. Camada de Domínio (Core Domain)¶
O coração do software. Aqui residem as regras de negócio, invariantes e a representação dos dados. Esta camada ignora a existência de banco de dados ou HTML.
- Entities: Objetos com identidade única (ex:
item). São imutáveis ou controlados. - Value Objects: Objetos definidos por seus atributos (ex:
pagination,sorting). - Registry: Mapeamento de tipos e relações.
4. Camada de Infraestrutura (Infrastructure)¶
Implementa os detalhes técnicos para persistir e recuperar dados.
- Repositories: Traduzem comandos de domínio para SQL do Moodle.
- Mappers: Convertem
stdClass(banco) paraEntity(domínio). - Query Engine: Construtor fluente de SQL complexo.
Princípios de Engenharia¶
Para manter a sanidade do código em um projeto desta escala, seguimos regras rígidas:
Imutabilidade (Immutability)¶
Objetos de Domínio e Query Builders são imutáveis. Métodos que alteram estado retornam novas instâncias (Wither Pattern).
- Por que? Previne efeitos colaterais indesejados onde um serviço altera um objeto que está sendo usado por outro.
Fail-Fast¶
Não silenciamos erros. Se uma classe é instanciada incorretamente ou um serviço não existe, lançamos uma coding_exception ou RuntimeException imediatamente.
- Por que? Erros silenciosos no Moodle (ex: null returns) causam bugs difíceis de rastrear em produção.
Injeção de Dependência (DI)¶
Não usamos new Class() dentro de serviços. Todas as dependências são injetadas via construtor e gerenciadas pelo ContainerBuilder (Symfony DI).
- Por que? Facilita testes unitários (Mocking) e troca de implementações.
Segregação de Interfaces (ISP)¶
Preferimos interfaces pequenas e específicas (extension_interface, event_service_interface) a classes gigantescas.
Padrões de Projeto Utilizados¶
| Padrão | Onde é usado | Objetivo |
|---|---|---|
| Singleton | Kernel, middag (Facade) |
Garantir ponto único de entrada e boot. |
| Facade | middag::class |
Simplificar o acesso à API complexa do Kernel para o dev Moodle. |
| Builder | Query, DiffBuilder |
Construir objetos complexos passo-a-passo de forma fluente. |
| Repository | item_repository |
Abstrair a camada de dados (SQL). |
| Data Mapper | item_mapper |
Converter dados relacionais em objetos. |
| Strategy | Extensions |
Permitir que comportamentos variados sejam plugados no Core. |