Skip to main content
CQRS — Command Query Responsibility Segregation — é o princípio de separar a intenção de uma operação (o que você quer fazer) da sua execução (como isso é feito) e do seu resultado (o que aconteceu). Nos SDKs SUOT, isso se traduz em três peças: o Command ou Query declara o que a aplicação quer, o Handler executa, e o Result encapsula o que o serviço externo respondeu. O resultado é uma integração previsível, testável e compreensível por qualquer ferramenta — humana ou de IA.

Commands são intenções, não ações

Um Command não faz nada por si mesmo. Ele é um objeto imutável que diz: “quero executar esta operação, com estes dados”. A execução de fato só ocorre quando o Command é passado ao Handler correspondente. Essa separação tem uma consequência importante: você pode construir, inspecionar, serializar e até registrar em log um Command sem que nenhuma operação de rede aconteça.

Handlers são executores

O Handler tem uma única responsabilidade: receber um Command, chamar o serviço externo e devolver um Result. Ele não decide se a operação deve ser feita — apenas como fazê-la. Cada Handler é especializado em um tipo de Command. O CteAutorizacaoHandler trata apenas CteAutorizacaoCommand; o ConsultaRntrcHandler trata apenas ConsultaRntrcCommand. Essa especialização garante que o PHPStan possa verificar a compatibilidade entre Command e Handler em tempo de análise estática.

Queries

Nem toda operação muda estado — algumas apenas consultam. Para essas, os SDKs SUOT usam Queries em vez de Commands. A forma é idêntica: Query → Handler → Result. A diferença é semântica: uma Query nunca produz efeitos colaterais no serviço externo.
A distinção entre Command e Query é intencional: ao ler o código, qualquer desenvolvedor (ou agente de IA) sabe imediatamente se uma operação é uma leitura ou uma escrita — sem precisar abrir a implementação do Handler.

Results são tipados e imutáveis

Todo Handler devolve um Result concreto e tipado para aquela operação específica. Não existe um Result genérico — existe CteAutorizacaoResult, ConsultaCteResult, ConsultaRntrcResult etc. Cada um expõe exatamente os métodos relevantes para aquela operação.
Results são imutáveis: lê-los quantas vezes quiser não produz chamadas adicionais ao serviço externo nem altera o estado do objeto.

Testabilidade

Como o Handler é uma dependência injetada, ele pode ser substituído por um mock nos testes unitários. Você testa a lógica da sua aplicação — o que ela faz com um sucesso, o que ela faz com uma rejeição — sem fazer nenhuma chamada real a SEFAZ ou ANTT.
Escreva um teste para cada estado do Result — isSuccess() e isRejected() — e um terceiro que verifica como a aplicação reage a uma InfrastructureException. Esses três casos cobrem o comportamento completo da integração.

Jornada do desenvolvedor

Esta é a jornada típica de um desenvolvedor ao implementar uma nova operação com os SDKs SUOT:
1

Identificar a operação

Você precisa autorizar um CT-e. A documentação indica CteAutorizacaoCommand e CteAutorizacaoHandler.
2

Autocomplete e PHPDoc

Ao digitar new CteAutorizacaoCommand(, a IDE exibe todos os parâmetros com seus tipos e descrições em português. Nenhum argumento ambíguo — cada um é um Value Object com nome significativo.
3

Construir o Command com Value Objects

Você constrói os Value Objects (Cnpj, ChaveCTe, etc.) com os dados validados. Erros de formato são detectados aqui, antes de qualquer I/O.
4

Chamar o Handler

O Handler é injetado via construtor no seu serviço. Você chama handle(command: $command) envolto em try/catch para InfrastructureException.
5

Tratar o Result

Você verifica isSuccess() e isRejected() e age de acordo — persiste o protocolo, registra o motivo da rejeição ou notifica o operador.
6

Configurar a Retry Policy

Para operações críticas, você configura uma RetryPolicy no Handler para lidar automaticamente com falhas de infraestrutura transientes — sem alterar a lógica de negócio.
7

Reconstruir o Command se necessário

Como o Command é imutável e não tem estado de execução, você pode reconstruí-lo com os mesmos dados e passar a um novo Handler após um failover ou mudança de ambiente — sem efeitos colaterais.