Pular para conteúdo

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?

  1. Tipagem Forte: Sabemos exatamente que $dto->courseid é um int ou null, e não uma string ou booleano acidental.
  2. Contrato Claro: O DTO define explicitamente quais campos são aceitos para criação ou atualização.
  3. 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:

  1. Identifica o type do registro (ex: 'course').
  2. Consulta o item_types Registry para saber qual classe instanciar (course_item).
  3. Combina os dados da tabela principal com os metadados.
  4. Retorna uma Entidade completa e pronta para uso.

2. Persistência (Domain → DB)

Quando salvamos (save), o Mapper:

  1. Extrai os valores da Entidade.
  2. Separa o que vai para a tabela middag_items e o que vai para middag_itemmeta.
  3. 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 instancia local_middag\extensions\learning\domain\course_item.
  • Registro B (type='subscription'): O Mapper instancia local_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 stdClass ou array direto 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.