title: Camada: Domínio description: O coração da lógica de negócio e as regras centrais e imutáveis do framework.
Camada: Domínio¶
A Camada de Domínio (framework\domain) é onde vivem as regras e os conceitos centrais do local_middag. Ela é a camada mais interna e protegida da arquitetura, projetada para ser completamente independente de tecnologias externas (como o Moodle ou o banco de dados SQL).
O que é¶
É o local onde definimos O QUE o framework faz e quais são as INVARIANTES que ele deve garantir (ex: "um Item não pode ser criado sem um TYPE válido").
Aqui encontramos: * Entities (Entidades): Objetos com identidade única que representam os conceitos de negócio (Item, Revision, Job). * Value Objects: Objetos definidos por seus atributos, sem identidade própria (ex: um endereço, um intervalo de data). Eles são inerentemente imutáveis. * Services de Domínio: Lógica que não pertence a uma única entidade, mas que expressa uma regra central (ex: cálculo de diff entre dois estados). * Contratos (Interfaces): Definições de "o que eu preciso" (ex: um Repository), sem dizer "quem vai me dar" (ex: SQL Mapper).
Por que existe¶
O Moodle sofre constantes mudanças em suas APIs internas entre versões (ex: de 3.9 para 4.4). Se a regra de negócio do MIDDAG estivesse espalhada diretamente em arquivos procedurais do Moodle: 1. Refatoração Impossível: Mudar uma regra exigiria alterar dezenas de arquivos. 2. Teste Difícil: Não seria possível testar uma regra de cálculo sem carregar todo o banco de dados do Moodle. 3. Acoplamento: A regra ficaria "suja" com detalhes técnicos de SQL e Globais do Moodle.
Ao isolar o Domínio, garantimos que a inteligência do produto permaneça estável e testável idependente da evolução da plataforma hospedeira.
Como se relaciona com outros conceitos¶
O Domínio utiliza o vocabulário do DDD (Domain-Driven Design) para organizar o código:
- Identidade e Mudança: Entidades como o Item têm identidade persistente. No framework, essas entidades são Imutáveis. Para alterar um valor, você gera uma nova instância através do Wither Pattern (
with_*). - Fronteira com Infraestrutura: O Domínio define a necessidade através de um Contract (ex:
item_repository_interface). A implementação real (SQL) vive na camada de Infraestrutura. - Fronteira com Aplicação: O Domínio define a regra; a Camada de Aplicação orquestra a regra dentro de um caso de uso específico.
Decisões de design¶
- Independência Total: O Domínio não conhece
$DB(Moodle), não conhece SQL e não conhece nomes de tabelas. Ele conhece apenas objetos e interfaces. - Híbrido EAV: Embora o banco de dados use EAV (Item/Meta), o Domínio recebe um objeto rico e hidratado. O Mapper (Infraestrutura) é quem cuida da complexidade de converter metadados em propriedades do objeto de domínio.
- Falha Explícita: Se uma regra de domínio é violada (ex:
statusinválido), a Entity deve lançar uma exceção imediatamente, impedindo que dados inconsistentes cheguem à persistência.
O que não é¶
- Não é Repositório: O código de domínio não faz
SELECTouINSERT. Ele apenas manipula os dados em memória. - Não é Controlador: O Domínio não sabe o que é uma requisição HTTP ou um formulário Web.
- Não é Moodle Support: Scripts que adaptam APIs do Moodle para o framework vivem na camada de
support\moodle, não no Domínio.
Perspectiva para builders de extensions¶
Para quem constrói extensions, o Domínio é onde você define a identidade do seu negócio:
1. Crie sua Entity: Defina os atributos estruturais e metadados que seu TYPE necessita.
2. Mantenha a Imutabilidade: Siga o padrão do framework ao criar métodos with_....
3. Não aceite lixo: Sua Entity deve validar seus próprios dados no construtor. Se o dado é inválido, o objeto nem deve ser criado.
Exemplo ilustrativo¶
Uma regra de domínio expressa em uma Entity imutável:
namespace local_middag\framework\domain\item;
final class item_entity {
// Regra de Invariante no Construtor
public function __construct(
private string $type,
private string $status,
private string $guid
) {
if (empty($type)) {
throw new \InvalidArgumentException("O TYPE do Item é obrigatório.");
}
}
// Wither Pattern (Padrão Imutável)
public function with_status(string $new_status): self {
$clone = clone $this;
$clone->status = $new_status;
return $clone;
}
}
Neste exemplo, a item_entity não sabe se será salva em SQL ou num arquivo. Ela apenas garante que a regra de TYPE obrigatório seja respeitada.