Pular para conteúdo

title: Camada: Infraestrutura description: Implementação técnica, detalhes de banco de dados, adapters Moodle e persistência organizada em famílias.


Camada: Infraestrutura

A Camada de Infraestrutura (framework\infrastructure) é onde os conceitos abstratos do framework ganham vida tecnológica. É aqui que o código "suja as mãos" com SQL, queries do Moodle, caching e integrações externas.


O que é

É a camada que implementa os Contracts definidos pelo Domínio e pela Aplicação. Se o Domínio diz "eu preciso salvar um Item", a Infraestrutura diz "eu vou salvar este dado na tabela middag_items usando o $DB do Moodle".

Principais componentes: * Repositories: Fronteira oficial de acesso a dados (SQL/MUC Cache). * Mappers: Tradutores que convertem registros brutos (stdClass) em Entities ricas do Domínio. * Moodle Adapters: Wrappers para APIs do Moodle (DB, User, Course, Config, Files). * Transaction Managers: Coordinadores de transações de banco de dados. * Authorizers: Implementação técnica das checagens de permissão.

Por que existe

O Moodle possui um banco de dados relacional e APIs procedurais globais. O local_middag vive e respira a partir desses recursos, mas não deve se fundir a eles. A Infraestrutura existe para: 1. Encapsulamento Técnica: Proteger as camadas superiores da complexidade do SQL e das mudanças de schema (install.xml). 2. Organização de Famílias: Centralizar o acesso a dados em quatro naturezas distintas de persistência. 3. Substitutibilidade: Permitir trocar uma implementação real por um "mock" durante testes unitários.

Sem esta camada, o código ficaria repleto de $DB->get_record('middag_items', ...) misturado com regras de negócio, tornando o sistema impossível de manter.

Famílias de Persistência

A infraestrutura organiza a persistência do framework em quatro famílias arquiteturais independentes, cada uma com seu próprio Repository e política de escrita:

graph TD
    INF[Camada de Infraestrutura]

    subgraph "Famílias de Persistência"
        IT[Item Repository: Estado Atual]
        RV[Revision Repository: Histórico Imutável]
        AU[Audit Repository: Log de Rastreabilidade]
        JB[Job Repository: Governança de Execução]
    end

    MAP[Mappers: SQL para Domínio]
    MUC[Cache MUC Decorator]
    MOD[Moodle $DB Boundary]

    IT --> MAP
    RV --> MAP
    AU --> MOD
    JB --> MOD
    MAP --> MOD
    IT -.-> MUC
  • Item Repository: Gerencia o estado operacional atual (EAV: itens e metadados).
  • Revision Repository: Gerencia snapshots históricos (revisões vinculadas ao item).
  • Audit Repository: Gerencia o log de trilha de auditoria (quem, quando e o que mudou).
  • Job Repository: Gerencia a governança e status de execuções assíncronas.

Decisões de design

  • Mappers Fortes: O framework não usa ORMs genéricos (como Eloquent ou Doctrine) por ser acoplado ao Moodle. Usamos Mappers manuais que garantem a reconstrução perfeita do objeto de Domínio a partir do SQL híbrido (Item/Meta).
  • Cache via Decorator: O cache (MUC - Moodle Universal Cache) é anexado aos repositories via Decorator. Isso significa que o repository original não "sabe" que está sendo cacheado, mantendo a responsabilidade única de persistência.
  • Transação Graceful: O Moodle 4.x introduziu mudanças que dificultam o uso de transações com Throwable. A infraestrutura fornece o moodle_transaction_manager e o método execute_graceful para contornar essa limitação técnica de forma segura.

O que não é

  • Não contém Regra de Negócio: A Infraestrutura não decide se um status pode mudar; ela apenas realiza a mudança que a camada superior solicitou.
  • Não contém Orquestração: Ela não decide "se salvar o item, disparar o signal". Ela apenas salva o item.
  • Não é Lugar de Validação de Domínio: Dados salvos na infraestrutura já devem vir validados pelas camadas de Domínio e Aplicação.

Perspectiva para builders de extensions

Para extensions que precisam de persistência: 1. Use os Repositories do Core: Na maioria dos casos, seu TYPE de Item deve ser salvo via item_repository global. Não crie tabelas SQL locais sem necessidade arquitetural comprovada. 2. Injete Contracts: Seua extension deve depender de item_repository_interface, não da classe concreta item_repository. Isso mantém seu código testável e desacoplado. 3. Aproveite o MUC Cache: Ao usar o repository oficial, sua extension ganha automaticamente o suporte ao MUC Cache configurado pelo administrador do Moodle.

Exemplo ilustrativo

Implementação de um Repository na Infraestrutura (Mapeamento SQL -> Domínio):

namespace local_middag\framework\infrastructure\persistence\repository;

final class item_repository implements item_repository_interface {
    public function find_by_id(int $id): item_entity {
        // Acesso técnico ao Moodle $DB
        $record = $this->db->get_record('middag_items', ['id' => $id]);
        $metadata = $this->db->get_records('middag_itemmeta', ['itemid' => $id]);

        // Tradução via Mapper (Fronteira Física -> Domínio)
        return $this->mapper->map_to_entity($record, $metadata);
    }
}

Neste exemplo, a item_repository absorve o custo de acessar duas tabelas diferentes e devolver um único objeto limpo para o restante do framework.