Pular para conteúdo

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: status invá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 SELECT ou INSERT. 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.

Referências