Pular para conteúdo

title: Camada: Kernel description: O coração do framework responsável pelo bootstrap, descoberta de recursos e ciclo de vida do container.


Camada: Kernel

O Kernel é o coordenador central do local_middag. Ele faz a ponte operacional entre o ciclo de vida procedimental do Moodle LMS e a arquitetura orientada a objetos (OO) do framework, garantindo que todas as dependências estejam prontas para uso.


O que é

É a camada que governa o Bootstrap (inicialização) e o Ciclo de Vida do sistema. Ela descobre quais Extensions estão instaladas, registra seus serviços no Container de Injeção de Dependência (DI) e compila o grafo de objetos que sustenta todo o framework.

No código, o Kernel é acessado através do ponto de entrada global middag::init(), mas suas responsabilidades internas são distribuídas entre carregadores (loaders), fábricas de containers (container_factory) e serviços de extensão (extension_service).

Por que existe

Sem um Kernel centralizado: 1. Dificuldade de Descoberta: Seria necessário incluir arquivos PHP manualmente em todos os pontos do Moodle. 2. Order de Carregamento: Não haveria garantia de que um serviço da Extension A estaria disponível para a Extension B. 3. Burocracia de DI: O desenvolvedor teria que instanciar manualmente dezenas de classes (new ...) para cada pequena tarefa.

O Kernel centraliza o conhecimento de "como montar o framework" em um único lugar, permitindo que o restante do código foque em regras de negócio e não em wiring estrutural.

Sequência de Boot

O boot ocorre uma única vez por requisição HTTP (ou execução de Cron) e segue quatro fases determinísticas:

sequenceDiagram
    participant Facade as middag::init()
    participant Kernel as kernel
    participant Loader as loaders
    participant Extensions as extension_service
    participant Container as ContainerBuilder

    Facade->>Kernel: init()
    Kernel->>Loader: Descoberta (Fase 1)
    Loader-->>Container: Registra services, facades e types
    Kernel->>Extensions: Boot de Extensions (Fase 2)
    Extensions-->>Container: register() e boot() em ordem topological
    Kernel->>Container: Compilação (Fase 3)
    Container-->>Container: Resolve grafo e congela definições
    Kernel->>Container: Injeção Sintética (Fase 4)
    Container-->>Kernel: Container pronto

As quatro fases explicadas:

  1. Descoberta: O framework varre os diretórios para localizar Services, Facades geradas e definições de Types de Item.
  2. Boot de Extensions: O extension_service executa os métodos register() e boot() de cada módulo. A ordem é definida pelas dependências declaradas em REQUIRES.
  3. Compilação: O ContainerBuilder do Symfony é compilado e congelado. Após este ponto, nenhuma definição de serviço pode ser alterada.
  4. Injeção Sintética: Objetos que precisam participar do container, mas que foram criados pelo Moodle (como a conexão global de DB), são injetados.

Decisões de design

  • Container como Motor Oficial: O framework desencoraja o uso de Singletons clássicos (getInstance()). Se um objeto precisa ser único, ele deve ser registrado como shared no container.
  • Isolamento de Falhas: Se o boot() de uma Extension falhar, o Kernel captura a exceção, loga o erro e permite que o restante do sistema (e o próprio Moodle) continue funcionando.
  • Configuração via Código: Diferente do Core do Moodle (baseado em arquivos XML e config globais), o Kernel do framework é configurado via código (PHP), permitindo maior flexibilidade e tipagem.

O que não é

  • Não é um Local de Regra de Negócio: O Kernel não sabe o que é um "Curso" ou uma "Empresa". Ele só sabe como carregar as classes que sabem disso.
  • Não é Global Accessor: Embora ele coordene tudo, o Kernel não deve ser usado como um dicionário global de variáveis. Use Injeção de Dependência nos seus componentes.
  • Não deve ser instanciado manualmente: O acesso deve ser feito sempre via Facade principal (middag).

Perspectiva para builders de extensions

Ao herdar de local_middag\base\extension, você ganha acesso ao lifecycle coordenado pelo Kernel: * register(): Use para registrar seus bindings no container. O container ainda não está compilado. * boot(): Use para resolver serviços e realizar ações que dependem de outras extensions já estarem registradas.

O Kernel garante que, se você declarar REQUIRES = ['outra_ext'], aquela extension terá seu boot concluído antes da sua começar.

Exemplo ilustrativo

A regra de ouro do Kernel para criação de objetos:

// ❌ ANTI-PATTERN: Criar manualmente (fora da governança)
$service = new my_service($db, $cache, $logger);

// ❌ ANTI-PATTERN: Usar o Kernel como Service Locator
$service = middag::get(my_service::class); // Evite em classes estruturais

// ✅ CORRETO: Declarar dependência e deixar o Kernel resolver
final class my_controller {
    public function __construct(
        private my_service $service // O Kernel injeta automaticamente via DI
    ) {}
}

Referências