DTOs e Data Mappers¶
Em sistemas PHP legados (como o próprio Moodle), é comum o uso excessivo de arrays associativos (['key' => 'value']) ou objetos genéricos (stdClass) para transportar dados. Isso gera código frágil, sem type hinting e difícil de refatorar.
O MIDDAG resolve isso introduzindo DTOs (Data Transfer Objects) para entrada de dados e Mappers para tradução entre o banco e o domínio.
DTOs (Objetos de Transferência de Dados)¶
Um DTO é um objeto simples, sem comportamento ou lógica de negócio, cuja única finalidade é transportar dados de um ponto a outro (ex: do Formulário para o Controller, ou do Controller para o Service).
Por que usar DTOs?¶
- Tipagem Forte: Sabemos exatamente que
$dto->courseidé umintounull, e não uma string ou booleano acidental. - Contrato Claro: O DTO define explicitamente quais campos são aceitos para criação ou atualização.
- Separação da Entidade: As Entidades de Domínio (
item) são imutáveis e protegem suas regras. O DTO é mutável e permissivo, servindo como um "rascunho" dos dados antes de serem validados e persistidos.
Estrutura do item_dto¶
<?php
// Exemplo de uso no Controller
$dto = item_dto::from_array([
'fullname' => 'Curso de PHP',
'status' => 'draft',
'metadata' => ['sku' => '123']
]);
// Acesso seguro e com autocomplete na IDE
echo $dto->fullname;
O DTO suporta atualizações parciais. Se um campo for null, o Mapper entenderá que aquele campo não deve ser alterado no banco de dados durante um update.
Data Mapper¶
O Mapper (local_middag\core\repository\mapper\item_mapper) é o componente responsável por converter dados entre o formato de armazenamento (Banco de Dados Relacional) e o formato de memória (Objetos de Domínio).
Ele isola a Entidade de saber como ela é salva.
O Fluxo de Tradução¶
O diagrama abaixo mostra como os dados mudam de forma durante o ciclo de vida:
flowchart LR
Input[Input / Form] -->|from_array| DTO[DTO (ItemDto)]
subgraph Service Layer
DTO -->|Validar| DTO
end
subgraph Repository Layer
DTO --> Mapper
DB[(Banco Moodle)] -->|stdClass| Mapper
Mapper -->|Hidratação| Entity[Domain Entity]
Entity -->|Extração| Mapper
Mapper -->|stdClass| DB
end
1. Hidratação (DB → Domain)¶
Quando buscamos dados (find_by_id), o Moodle retorna um stdClass plano e arrays de metadados separados. O Mapper:
- Identifica o
typedo registro (ex: 'course'). - Consulta o
item_typesRegistry para saber qual classe instanciar (course_item). - Combina os dados da tabela principal com os metadados.
- Retorna uma Entidade completa e pronta para uso.
2. Persistência (Domain → DB)¶
Quando salvamos (save), o Mapper:
- Extrai os valores da Entidade.
- Separa o que vai para a tabela
middag_itemse o que vai paramiddag_itemmeta. - Serializa valores complexos (arrays/objetos em metadados) para JSON, se necessário.
Polimorfismo e Registry¶
Uma das funções mais importantes do Mapper no MIDDAG é suportar Polimorfismo.
Embora todos os dados estejam na mesma tabela SQL (middag_items), eles podem representar objetos PHP totalmente diferentes.
Exemplo:
- Registro A (
type='course'): O Mapper instancialocal_middag\extensions\learning\domain\course_item. - Registro B (
type='subscription'): O Mapper instancialocal_middag\extensions\management\domain\subscription_item.
Isso permite que course_item tenha métodos como get_teachers() e subscription_item tenha get_expiration_date(), mesmo vindo do mesmo lugar.
Boas Práticas¶
✅ O que fazer:¶
- Use
item_dto::from_array($data)para capturar dados de formulários ou APIs. - Confie no Mapper para tratar a serialização JSON de metadados.
- Adicione novos campos no DTO se criar uma extensão que precisa transportar dados específicos.
❌ O que não fazer:¶
- Nunca passe um
stdClassouarraydireto para um Service ou Repository. Converta para DTO primeiro. - Não coloque lógica de validação complexa no DTO (use Services para isso).
- Não use o Mapper manualmente em Controllers. Ele é uma ferramenta interna dos Repositórios.