---
title: "Dispatcher"
description: "Dispatcher"
type: "docs"
category: "doc"
tags: []
authors: [Anonymous]
date: "2026-10-08"
last_update: "2026-10-08"
time_minutes: 1
draft: false
unlisted: false
url: "https://core.libredte.cl/docs/dispatcher"
---

# Dispatcher



---

## Introducción

Dispatcher para la Biblioteca PHP

# Dispatcher para la Biblioteca PHP

[![CI](https://github.com/libredte/libredte-lib-core-dispatcher/actions/workflows/ci.yml/badge.svg?branch=main&amp;event=push)](https://github.com/libredte/libredte-lib-core-dispatcher/actions/workflows/ci.yml?query=branch%3Amain)
[![Licencia](https://poser.pugx.org/libredte/libredte-lib-core-dispatcher/license)](https://packagist.org/packages/libredte/libredte-lib-core-dispatcher)
[![Descargas totales](https://poser.pugx.org/libredte/libredte-lib-core-dispatcher/downloads)](https://packagist.org/packages/libredte/libredte-lib-core-dispatcher)

Conector que expone las operaciones de `libredte/libredte-lib-core`
de forma segura y agnóstica al transporte, usando
[`derafu/backbone-dispatcher`](https://www.derafu.dev/docs/core/backbone-dispatcher)
como base. Pensado como la capa intermedia entre LibreDTE y un
bridge hacia otro lenguaje, aunque no depende de ninguno en
particular. Repositorio:
[`libredte-lib-core-dispatcher`](https://github.com/libredte/libredte-lib-core-dispatcher).

&gt; [!IMPORTANT] Importante
&gt;
&gt; El Dispatcher corre dentro de tu propio proceso PHP (lo llamas
&gt; directo, no por red): tu software se convierte en un trabajo
&gt; derivado y queda sujeto a los términos de la
&gt; [licencia AGPL](https://www.derafu.dev/docs/lib/licencia), igual que si usaras la
&gt; [Biblioteca PHP](https://www.derafu.dev/docs/lib) directamente. Si buscas integrarte sin
&gt; ese efecto, revisa los [Servicios Web (API)](https://www.derafu.dev/docs/api), la
&gt; [Imagen Docker (API)](https://www.derafu.dev/docs/docker-api) o la
&gt; [Imagen Docker (Consola)](https://www.derafu.dev/docs/docker-console).

## Instalación

Se instala como cualquier paquete de Composer:

```shell
composer require libredte/libredte-lib-core-dispatcher
```

## Ejemplo

Un uso mínimo: arrancar el dispatcher, despachar una operación y
revisar si tuvo éxito.

```php
use libredte\lib\CoreDispatcher\Bootstrap;
use Derafu\BackboneDispatcher\ValueObject\OperationRequest;

// SafeDispatcherInterface.
$dispatcher = Bootstrap::boot();

$request = new OperationRequest(
    &#039;billing&#039;,
    &#039;identifier&#039;,
    &#039;caf_loader&#039;,
    &#039;load&#039;,
    [&#039;xml&#039; =&gt; base64_encode($cafXml)],
);

// Nunca lanza excepciones.
$result = $dispatcher-&gt;dispatch($request);

if ($result-&gt;isSuccess()) {
    // Ya serializado (array), listo para cruzar un límite de
    // proceso o lenguaje.
    $caf = $result-&gt;getValue();
} else {
    // ProblemDetail (RFC 7807-like).
    $problem = $result-&gt;getProblem();
}
```

&gt; [!NOTE] Nota
&gt;
&gt; Revisa [Uso del Dispatcher](https://www.derafu.dev/docs/dispatcher/uso) para el detalle
&gt; completo de `Bootstrap::boot()`, `OperationRequest` y el manejo de
&gt; errores.

## Términos y condiciones de uso

Licenciado bajo AGPL-3.0+. Disponible en el archivo
[COPYING](https://github.com/libredte/libredte-lib-core-dispatcher/blob/main/COPYING).




---

## Uso del Dispatcher

Uso completo del Dispatcher

# Uso del Dispatcher

Repasa en detalle cómo arrancar el dispatcher, construir una
solicitud y leer su resultado — el ejemplo de la introducción,
explicado paso a paso.

## Arrancar el dispatcher

`Bootstrap::boot()` es el único punto de entrada público del
paquete. Todo el resto del cableado (Deserializers, la cadena
`DirectDispatcher` → `TypedDispatcher` → `SafeDispatcher` de
`derafu/backbone-dispatcher`) está declarado en su
`config/services.yaml`, no en PHP.

```php
use libredte\lib\CoreDispatcher\Bootstrap;

// El entorno puede ser &#039;prod&#039; (default), &#039;dev&#039; o &#039;test&#039;.
$dispatcher = Bootstrap::boot(environment: &#039;prod&#039;, debug: false);
```

## Construir la solicitud

Con los 4 identificadores por separado:

```php
use Derafu\BackboneDispatcher\ValueObject\OperationRequest;

$request = new OperationRequest(
    &#039;billing&#039;,
    &#039;identifier&#039;,
    &#039;caf_loader&#039;,
    &#039;load&#039;,
    [&#039;xml&#039; =&gt; base64_encode($cafXml)],
);
```

O con el identificador `&quot;package.component.worker:operation&quot;` como
un solo string — la forma natural para quien llama desde el otro
lado de un límite de proceso o lenguaje, como el
[Bridge Python](https://www.derafu.dev/docs/bridge-python):

```php
$request = OperationRequest::fromId(
    &#039;billing.identifier.caf_loader::load&#039;,
    [&#039;xml&#039; =&gt; base64_encode($cafXml)],
);
```

&gt; [!NOTE] Nota
&gt;
&gt; Revisa [Funcionalidades](https://www.derafu.dev/docs/lib/funcionalidades) de la
&gt; biblioteca PHP para ver qué paquetes, componentes y workers (y por
&gt; lo tanto qué operaciones) están disponibles.

## Despachar y leer el resultado

`dispatch()` nunca lanza excepciones: siempre revisa `isSuccess()`
antes de usar el resultado.

```php
$result = $dispatcher-&gt;dispatch($request);

if ($result-&gt;isSuccess()) {
    // Ya serializado (array), listo para cruzar un límite de
    // proceso o lenguaje.
    $caf = $result-&gt;getValue();
} else {
    // ProblemDetail (RFC 7807-like).
    $problem = $result-&gt;getProblem();
}
```

## Parámetros anidados

Los parámetros que corresponden a objetos (CAF, certificados,
emisor, receptor, mandatario, etc.) se pueden pasar como arreglos: el
dispatcher los deserializa automáticamente al tipo esperado por la
operación. Revisa [Deserializadores](https://www.derafu.dev/docs/dispatcher/deserializadores)
para el detalle de qué interfaces están cubiertas.




---

## Arquitectura

Cómo está armado este paquete

# Arquitectura

Así está resuelto el cableado interno del paquete:

- `Bootstrap::boot(string $environment = &#039;prod&#039;, bool $debug = false)`
  es el único punto de entrada público. Todo el resto del cableado
  (Deserializers, la cadena `DirectDispatcher` → `TypedDispatcher` →
  `SafeDispatcher` de [`derafu/backbone-dispatcher`](https://www.derafu.dev/docs/core/backbone-dispatcher))
  está declarado en `config/services.yaml`, no en PHP.
- `config/services.yaml` importa el de `libredte-lib-core` y
  sobreescribe `libredte.lib.core.project_dir`: `kernel.project_dir`
  se resuelve contra el paquete que actúa como punto de entrada, y
  ese rol lo cumple este paquete, no `libredte-lib-core`.
- `Derafu\BackboneDispatcher\Contract\ObjectFactoryInterface` está
  registrado `lazy: true` porque `DocumentBagDeserializer`/
  `SiiRequestDeserializer` necesitan ese mismo registro (para
  deserializar sus campos anidados) y a la vez son entradas de su
  propio mapa de deserializers — una referencia circular que
  `lazy: true` rompe.

## Desarrollo

Para modificar este paquete, instala sus dependencias y corre las
validaciones antes de proponer un cambio:

```shell
composer install

# PHPUnit con cobertura.
composer tests

# Nivel 5.
composer phpstan

# php-cs-fixer (dry-run).
composer phpcs
```




---

## Deserializadores

Qué tipos cubren y cómo agregar uno nuevo

# Deserializadores

Los 9 Deserializers de este paquete cubren únicamente
interfaces/tipos de `libredte-lib-core` (o de paquetes Derafu
genéricos que Core usa): `DocumentBagInterface`,
`XmlDocumentInterface`, `CafInterface`, `CertificateInterface`,
`EmisorInterface`, `ReceptorInterface`, `MandatarioInterface`,
`DocumentEnvelopeInterface`, `SiiRequestInterface`.

## Agregar soporte a una clase nueva

Sigue este orden para decidir qué construir:

1. Revisar si la clase ya tiene un `fromArray(array $data): self`
   estático. Si lo tiene, no hace falta escribir nada:
   `FromArrayDeserializer` (el `$fallback` del registro) ya la cubre
   automáticamente, sin registrar nada en `services.yaml`.
2. Si no lo tiene, ver si ya existe una Factory a la que delegar
   (ver `EmisorDeserializer`, `ReceptorDeserializer`,
   `MandatarioDeserializer`).
3. Si no hay Factory, construir el objeto directamente, delegando
   los campos que a su vez son objetos en el
   `ObjectFactoryInterface` inyectado (ver `DocumentBagDeserializer`).
4. Si la construcción no tiene una única forma fija, decidir según
   qué claves están presentes (ver `CertificateDeserializer`, que
   elige entre `loadFromData()`/`loadFromKeys()`).
5. Todo Deserializer empieza narrowing su entrada con
   `assertArray()`/`assertString()` (heredados de
   `Abstract\AbstractDeserializer`).

`DocumentBag` no tiene Deserializer propio para sus campos
`document` y `documentType`: siempre reciben `null`. Agregar los
suyos cuando se necesiten.





---
Última actualización el 08/10/2026

