Pular para conteúdo

Comandos

Um command é a unidade arquitetural de trabalho executavel no MIDDAG. Ele carrega o payload necessário para que um handler realize uma ação discreta.

O bus resolve o handler automaticamente por convenção de nome, sem middleware nem hooks.


Criar um command

Um command é um value object imutavel que estende base\command. Deve implementar to_payload() e from_payload() para suportar serialização (necessária para dispatch async).

namespace local_meuplugin\extensions\catalogo\item;

use local_middag\base\command;

final class publish_item_command extends command
{
    public function __construct(
        public readonly int $item_id,
        public readonly int $user_id,
    ) {}

    public function to_payload(): array
    {
        return [
            'item_id' => $this->item_id,
            'user_id' => $this->user_id,
        ];
    }

    public static function from_payload(array $payload): static
    {
        return new static(
            item_id: (int) ($payload['item_id'] ?? 0),
            user_id: (int) ($payload['user_id'] ?? 0),
        );
    }
}

Criar um handler

O handler é resolvido automaticamente por convenção: o bus concatena _handler ao FQCN do command. O handler deve estar no mesmo namespace e implementar __invoke().

namespace local_meuplugin\extensions\catalogo\item;

use local_middag\base\command_handler;

final class publish_item_command_handler extends command_handler
{
    public function __construct(
        private readonly item_service_interface $items,
    ) {}

    public function __invoke(publish_item_command $command): void
    {
        $this->items->publish($command->item_id, $command->user_id);
    }
}

O handler é resolvido do container DI, portanto pode receber qualquer dependência injetavel no construtor.

Convencao de nome

publish_item_commandpublish_item_command_handler (mesmo namespace, sufixo _handler).


Dispatch síncrono

Resolve o handler e executa imediatamente:

use local_middag\facade\command_bus;

command_bus::handle(new publish_item_command(
    item_id: 42,
    user_id: 1,
));

Dispatch assíncrono

Serializa o command via to_payload() e enfileira como Moodle adhoc task. O handler sera executado pelo cron:

use local_middag\facade\command_bus;

command_bus::dispatch_async(new publish_item_command(
    item_id: 42,
    user_id: 1,
));

O adhoc task reconstroi o command via from_payload() e executa o handler normalmente.


Ciclo de vida

sequenceDiagram
    participant C as Controller/Service
    participant B as command_bus
    participant H as Handler
    C ->> B: handle(command)
    B ->> B: Resolve handler (FQCN + _handler)
    B ->> H: __invoke(command)
    H ->> H: Executa lógica

Para dispatch async, o bus serializa e delega ao cron:

sequenceDiagram
    participant C as Controller/Service
    participant B as command_bus
    participant Q as adhoc_task (cron)
    participant H as Handler
    C ->> B: dispatch_async(command)
    B ->> Q: Serializa (to_payload) e enfileira
    Q ->> B: Reconstroi (from_payload) e handle()
    B ->> H: __invoke(command)

Quando usar jobs

Se você precisa de retry, correlação ou observabilidade, não use dispatch_async diretamente. Use o job_service:

use local_middag\facade\job_service;

$job = job_service::dispatch(new \local_middag\framework\domain\job\job_dto(
    command: new publish_item_command(42, 1),
    // ... opções de retry, correlation_id, etc.
));

O job governa a execução, registra tentativas e permite acompanhamento.

Cenario Mecanismo
Execução imediata command_bus::handle()
Background simples command_bus::dispatch_async()
Retry, correlação, observabilidade job_service::dispatch()

Regras

  • Um command carrega apenas dados (value object). Nenhuma lógica de negocio.
  • Um handler realiza a ação. Pode depender de services, repositories, etc.
  • O handler deve estar no mesmo namespace que o command.
  • to_payload() e from_payload() são obrigatorios (contract command_interface).
  • Estender base\command e base\command_handler é recomendado, mas não estritamente obrigatório para o bus funcionar.

Referencias