Laravents
Eloquent for events. Modules for Laravel. Commands, queries and events with conventions, attributes and an outbox, so modules talk through a public API and never through each other's models.Eloquent para eventos. Módulos para Laravel. Comandos, consultas y eventos con convenciones, atributos y un outbox, para que los módulos hablen a través de una API pública y nunca a través de los modelos de otro.Eloquent per gli eventi. Moduli per Laravel. Comandi, query ed eventi con convenzioni, attributi e un outbox, così i moduli parlano attraverso un'API pubblica e mai attraverso i modelli degli altri.
Built from Laravel's own piecesConstruido con las piezas de LaravelCostruito con i pezzi di Laravel
What Eloquent is to your database, Laravents is to your messages. Where Laravel already has a shape for something, Laravents takes that shape and invents nothing of its own, so Laravel's own documentation keeps working for you.Lo que Eloquent es para tu base de datos, Laravents lo es para tus mensajes. Donde Laravel ya tiene una forma para algo, Laravents toma esa forma y no inventa nada propio, así que la documentación de Laravel te sigue sirviendo.Ciò che Eloquent è per il tuo database, Laravents lo è per i tuoi messaggi. Dove Laravel ha già una forma per qualcosa, Laravents prende quella forma e non inventa nulla di suo, così la documentazione di Laravel continua a valere per te.
| Laravents | Laravel's pieceLa pieza de LaravelIl pezzo di Laravel |
|---|---|
| Dispatching commands, queries and eventsDespachar comandos, consultas y eventosInviare comandi, query ed eventi | The Bus dispatcher and PipelineEl dispatcher del Bus y el PipelineIl dispatcher del Bus e la Pipeline |
| Message metadata: ids and the actorMetadatos del mensaje: ids y el actorMetadati del messaggio: id e l'attore | Context |
| Asynchronous handlersHandlers asíncronosHandler asincroni | The queue, its retries and failed_jobsLa cola, sus reintentos y failed_jobsLa coda, i suoi tentativi e failed_jobs |
#[Authorize] | The Gate, with the routing key as the abilityEl Gate, con la routing key como abilityIl Gate, con la routing key come ability |
| Handlers and their dependenciesLos handlers y sus dependenciasGli handler e le loro dipendenze | The container, contextual attributes includedEl contenedor, atributos contextuales incluidosIl container, attributi contestuali inclusi |
rules() at the HTTP gatewayrules() en el gateway HTTPrules() nel gateway HTTP | The validator, with Laravel's 422El validador, con el 422 de LaravelIl validatore, con il 422 di Laravel |
Laravents::fake() | The shape of Event::fake()La forma de Event::fake()La forma di Event::fake() |
| GeneratorsGeneradoresGeneratori | GeneratorCommand, with publishable stubsGeneratorCommand, con stubs publicablesGeneratorCommand, con stub pubblicabili |
| The registry cacheLa caché del registroLa cache del registro | php artisan optimize and optimize:clearphp artisan optimize y optimize:clearphp artisan optimize e optimize:clear |
| Outbox pruningLimpieza del outboxPulizia dell'outbox | MassPrunable and model:pruneMassPrunable y model:pruneMassPrunable e model:prune |
The modules at a glanceLos módulos de un vistazoI moduli a colpo d'occhio
Real output from the example application: its handlers, its model publications, its modules and the outbox connections, in Laravel's own about command.Salida real de la aplicación de ejemplo: sus handlers, sus publicaciones de modelos, sus módulos y las conexiones del outbox, en el propio comando about de Laravel.Output reale dell'applicazione di esempio: i suoi handler, le sue pubblicazioni di modelli, i suoi moduli e le connessioni dell'outbox, nel comando about di Laravel.
$ php artisan about --only=laravents
And the boundaries, checked in CI: modules use each other only through their Api, with no cycles.Y los límites, verificados en CI: los módulos se usan entre sí solo a través de su Api, sin ciclos.E i confini, verificati in CI: i moduli si usano tra loro solo attraverso la loro Api, senza cicli.
$ php artisan laravents:verify Module graph ..................................................... 3 modules FanClub Press -> Band INFO 3 modules verified, no violations.
A command, its handler, an event, a listenerUn comando, su handler, un evento, un listenerUn comando, il suo handler, un evento, un listener
Every sample is from the example application in workbench/, which the test suite runs: a Beatles fan-club site, built by Luciano, a fan and a developer.Cada ejemplo viene de la aplicación de ejemplo en workbench/, que ejecuta la suite de pruebas: un sitio de fans de los Beatles, hecho por Luciano, fan y desarrollador.Ogni esempio viene dall'applicazione di esempio in workbench/, che la suite di test esegue: un sito di fan dei Beatles, costruito da Luciano, fan e sviluppatore.
Sendable; its routing key, band.give_nickname, comes from its module and its nameUn objeto simple con Sendable; su routing key, band.give_nickname, sale de su módulo y su nombreUn oggetto semplice con Sendable; la sua routing key, band.give_nickname, viene dal suo modulo e dal suo nome
final readonly class GiveNickname implements ValidatesPayload
{
use Sendable;
public function __construct(public int $memberId, public string $nickname) {}
public static function rules(): array
{
return [
'memberId' => 'required|integer|min:1',
'nickname' => 'required|string|max:40',
];
}
}
#[Authorize] asks the Gate, #[Transactional] wraps it in a transaction, #[Expose] serves it over HTTPEncontrado por atributo; #[Authorize] consulta el Gate, #[Transactional] lo envuelve en una transacción, #[Expose] lo sirve por HTTPTrovato tramite attributo; #[Authorize] interroga il Gate, #[Transactional] lo avvolge in una transazione, #[Expose] lo serve via HTTP
#[CommandHandler]
#[Authorize]
#[Transactional]
#[Expose]
public function give(GiveNickname $command, #[CurrentUser] Authenticatable $actor): int
{
return Nickname::query()->create([
'given_by' => $actor->getAuthIdentifier(),
'member_id' => $command->memberId,
'nickname' => $command->nickname,
])->id;
}
#[Publishes(NicknameGiven::class, on: 'created')]
final class Nickname extends Model
{
protected $fillable = ['given_by', 'member_id', 'nickname'];
}
#[EventHandler]
#[Asynchronous('press')]
public function __invoke(NicknameGiven $event, CommandBus $commands, #[Header('publication_id')] string $publicationId): void
{
$commands->dispatch(new PrintHeadline($event->nicknameId, $event->memberId, $publicationId));
}
$id = GiveNickname::send(memberId: 2, nickname: 'The Quiet One');
$id = Laravents::command('band.give_nickname', ['memberId' => 2, 'nickname' => 'The Quiet One']);
Use casesCasos de usoCasi d'uso
Drag or scroll sideways.Arrastra o desplázate lateralmente.Trascina o scorri lateralmente.
How it worksCómo funcionaCome funziona
Four steps, all of them Laravel's own commands or shaped like them.Cuatro pasos, todos comandos propios de Laravel o con su forma.Quattro passaggi, tutti comandi di Laravel o con la loro forma.
InstallInstalarInstalla
composer require laravents/laravents: package discovery registers the provider and the facade.composer require laravents/laravents: el package discovery registra el provider y la facade.composer require laravents/laravents: il package discovery registra il provider e la facade.
MigrateMigrarMigra
php artisan migrate creates the outbox table; vendor:publish --tag=laravents-config publishes the config.php artisan migrate crea la tabla del outbox; vendor:publish --tag=laravents-config publica la configuración.php artisan migrate crea la tabella dell'outbox; vendor:publish --tag=laravents-config pubblica la configurazione.
Create a moduleCrear un móduloCrea un modulo
php artisan laravents:module Band writes the module and registers its provider, as make:provider does.php artisan laravents:module Band escribe el módulo y registra su provider, como lo hace make:provider.php artisan laravents:module Band scrive il modulo e registra il suo provider, come fa make:provider.
SendEnviarInvia
php artisan laravents:command GiveNickname --module=Band, then GiveNickname::send().php artisan laravents:command GiveNickname --module=Band, y luego GiveNickname::send().php artisan laravents:command GiveNickname --module=Band, poi GiveNickname::send().
php artisan about has a Laravents section: the registry, the modules, the handlers by kind, the HTTP gateway and the outbox connections. php artisan laravents:list prints every handler.¿No estás seguro de que esté conectado? php artisan about tiene una sección de Laravents: el registro, los módulos, los handlers por tipo, el gateway HTTP y las conexiones del outbox. php artisan laravents:list imprime cada handler.Non sei sicuro che sia collegato? php artisan about ha una sezione Laravents: il registro, i moduli, gli handler per tipo, il gateway HTTP e le connessioni dell'outbox. php artisan laravents:list stampa ogni handler.Quick startInicio rápidoAvvio rapido
PHP 8.3 or newer and Laravel 13. Require the package, publish the config and run the outbox migration:PHP 8.3 o más reciente y Laravel 13. Requiere el paquete, publica la configuración y ejecuta la migración del outbox:PHP 8.3 o più recente e Laravel 13. Richiedi il pacchetto, pubblica la configurazione ed esegui la migrazione dell'outbox:
composer require laravents/laravents php artisan vendor:publish --tag=laravents-config php artisan migrate
Modules live in modules/ under the Modules\ namespace. Autoload that directory in your application's composer.json:Los módulos viven en modules/ bajo el namespace Modules\. Carga ese directorio con el autoload del composer.json de tu aplicación:I moduli vivono in modules/ sotto il namespace Modules\. Carica quella cartella con l'autoload del composer.json della tua applicazione:
"autoload": {
"psr-4": {
"App\\": "app/",
"Modules\\": "modules/"
}
}
Create a module and its first command. Then read the manual, from installation to the reference:Crea un módulo y su primer comando. Después lee el manual, de la instalación a la referencia:Crea un modulo e il suo primo comando. Poi leggi il manuale, dall'installazione al riferimento:
php artisan laravents:module Band php artisan laravents:command GiveNickname --module=Band
ConsoleConsolaConsole
Every command, as route:list and model:show would have it. Their options and output are on the console page:Cada comando, como lo harían route:list y model:show. Sus opciones y su salida están en la página de la consola:Ogni comando, come farebbero route:list e model:show. Le loro opzioni e il loro output sono nella pagina della console:
| CommandComandoComando | What it doesQué haceCosa fa |
|---|---|
laravents:list | Every handler: kind, routing key, message, handler, mode, queue, HTTP route.Cada handler: tipo, routing key, mensaje, handler, modo, cola, ruta HTTP.Ogni handler: tipo, routing key, messaggio, handler, modalità, coda, rotta HTTP. |
laravents:show | One module's canvas: commands, queries, events published and consumed, model publications, HTTP endpoints, dependencies.El mapa de un módulo: comandos, consultas, eventos publicados y consumidos, publicaciones de modelos, endpoints HTTP, dependencias.La mappa di un modulo: comandi, query, eventi pubblicati e consumati, pubblicazioni di modelli, endpoint HTTP, dipendenze. |
laravents:verify | Module direction, Api purity, cycles and the registry; exit 1 on a violation.La dirección entre módulos, la pureza de la Api, los ciclos y el registro; sale con 1 ante una violación.La direzione tra moduli, la purezza della Api, i cicli e il registro; esce con 1 in caso di violazione. |
laravents:docs | A Markdown page per module and a Mermaid dependency graph; --check exits 1 when they are stale.Una página Markdown por módulo y un grafo de dependencias en Mermaid; --check sale con 1 cuando están desactualizadas.Una pagina Markdown per modulo e un grafo delle dipendenze in Mermaid; --check esce con 1 quando non sono aggiornate. |
laravents:cache | Cache the handler registry, as part of php artisan optimize.Guarda en caché el registro de handlers, como parte de php artisan optimize.Mette in cache il registro degli handler, come parte di php artisan optimize. |
laravents:republish | Re-dispatch outbox rows that were never picked up.Vuelve a despachar las filas del outbox que nunca se tomaron.Rispedisce le righe dell'outbox mai prese in carico. |
laravents:module | A module, its provider and its first test; laravents:command, :query, :event and :interceptor write the rest.Un módulo, su provider y su primera prueba; laravents:command, :query, :event y :interceptor escriben el resto.Un modulo, il suo provider e il suo primo test; laravents:command, :query, :event e :interceptor scrivono il resto. |
Why LaraventsPor qué LaraventsPerché Laravents
Laravel's shape firstPrimero, la forma de LaravelPrima di tutto, la forma di Laravel
A Laravel developer should be able to guess the API before reading it: the facade, the fake, the generators and about work as Laravel's own do.Quien desarrolla con Laravel debería poder adivinar la API antes de leerla: la facade, el fake, los generadores y about funcionan como los de Laravel.Chi sviluppa con Laravel dovrebbe poter indovinare l'API prima di leggerla: la facade, il fake, i generatori e about funzionano come quelli di Laravel.
The actor is never a headerEl actor nunca es un headerL'attore non è mai un header
#[Authorize] trusts only a user the guard holds, and an asynchronous handler runs as its publication's actor, rebuilt through the guard's UserProvider.#[Authorize] solo confía en un usuario que el guard tiene, y un handler asíncrono se ejecuta como el actor de su publicación, reconstruido con el UserProvider del guard.#[Authorize] si fida solo di un utente che il guard ha, e un handler asincrono viene eseguito come l'attore della sua pubblicazione, ricostruito tramite lo UserProvider del guard.
Committed or not at allConfirmado o nadaConfermato o niente
One outbox row per event and asynchronous listener, in the publisher's transaction: a rolled-back command never reaches a listener.Una fila del outbox por evento y listener asíncrono, en la transacción del publicador: un comando revertido nunca llega a un listener.Una riga dell'outbox per evento e listener asincrono, nella transazione di chi pubblica: un comando annullato non raggiunge mai un listener.
Boundaries are checkedLos límites se verificanI confini vengono verificati
laravents:verify reads the source, not a manifest: a module that reaches into another's internals fails CI.laravents:verify lee el código, no un manifiesto: un módulo que entra en los internos de otro hace fallar la CI.laravents:verify legge il codice, non un manifest: un modulo che entra negli interni di un altro fa fallire la CI.
Standards at the boundaryEstándares en el bordeStandard al confine
HTTP statuses and error bodies come from your exception handler. A message's fields are the module's own, and no standard adds an envelope to them.Los estados HTTP y los cuerpos de error vienen de tu exception handler. Los campos de un mensaje son del módulo, y ningún estándar les agrega un sobre.Gli stati HTTP e i corpi d'errore vengono dal tuo exception handler. I campi di un messaggio sono del modulo, e nessuno standard aggiunge loro una busta.
Tests prove every claimLas pruebas respaldan cada afirmaciónI test dimostrano ogni affermazione
A rule in the manual has a test that holds it, named in a "Proven by" line, and every code sample is an excerpt of a file the suite runs.Cada regla del manual tiene una prueba que la sostiene, nombrada en una línea "Proven by", y cada ejemplo de código es un extracto de un archivo que ejecuta la suite.Ogni regola del manuale ha un test che la sostiene, indicato in una riga "Proven by", e ogni esempio di codice è un estratto di un file che la suite esegue.
FAQPreguntas frecuentesDomande frequenti
The short answers — the manual has the long ones.Las respuestas breves — el manual tiene las largas.Le risposte brevi — il manuale ha quelle lunghe.
No. An #[EventHandler] of a framework, package or application event is subscribed with Event::listen(), so Laravel's events come in. The other way there is no bridge: a Laravents event is not dispatched to Laravel's dispatcher.No. Un #[EventHandler] de un evento del framework, de un paquete o de la aplicación se suscribe con Event::listen(), así que los eventos de Laravel entran. En sentido contrario no hay puente: un evento de Laravents no se despacha al dispatcher de Laravel.No. Un #[EventHandler] di un evento del framework, di un pacchetto o dell'applicazione viene registrato con Event::listen(), quindi gli eventi di Laravel entrano. Nel senso opposto non c'è un ponte: un evento di Laravents non viene inviato al dispatcher di Laravel.
No. Commands and queries are always synchronous, because a caller waits for their answer. Event handlers can be asynchronous, with #[Asynchronous], or run after the response, with #[Deferred].No. Los comandos y las consultas son siempre síncronos, porque quien llama espera su respuesta. Los handlers de eventos pueden ser asíncronos, con #[Asynchronous], o ejecutarse después de la respuesta, con #[Deferred].No. I comandi e le query sono sempre sincroni, perché chi chiama aspetta la loro risposta. Gli handler di eventi possono essere asincroni, con #[Asynchronous], o essere eseguiti dopo la risposta, con #[Deferred].
No. The Band, Press and FanClub modules live in workbench/, for the tests and the documentation. composer require laravents/laravents ships src/, config/, database/, routes/ and stubs/ only.No. Los módulos Band, Press y FanClub viven en workbench/, para las pruebas y la documentación. composer require laravents/laravents instala solo src/, config/, database/, routes/ y stubs/.No. I moduli Band, Press e FanClub vivono in workbench/, per i test e la documentazione. composer require laravents/laravents installa solo src/, config/, database/, routes/ e stubs/.
The row stores the event as Laravel's queue stores a job, serialized inside JSON, so it fits a text column on every driver. The test suite runs on SQLite, and the payload format is built so PostgreSQL accepts it too.La fila guarda el evento como la cola de Laravel guarda un job, serializado dentro de JSON, así que entra en una columna de texto con cualquier driver. La suite de pruebas corre sobre SQLite, y el formato del payload está pensado para que PostgreSQL también lo acepte.La riga salva l'evento come la coda di Laravel salva un job, serializzato dentro JSON, quindi sta in una colonna di testo con qualsiasi driver. La suite di test gira su SQLite, e il formato del payload è pensato perché anche PostgreSQL lo accetti.
Only the handlers marked #[Expose], at POST /laravents/commands/{key} and GET|POST /laravents/queries/{key}. Anything else is one identical 404, whether the key exists or not, and #[Authorize] still applies.Solo los handlers marcados con #[Expose], en POST /laravents/commands/{key} y GET|POST /laravents/queries/{key}. Todo lo demás es un único 404 idéntico, exista la clave o no, y #[Authorize] sigue aplicándose.Solo gli handler marcati con #[Expose], su POST /laravents/commands/{key} e GET|POST /laravents/queries/{key}. Tutto il resto è un unico 404 identico, che la chiave esista o no, e #[Authorize] continua ad applicarsi.
Laravents is MIT-licensed.Laravents tiene licencia MIT.Laravents ha licenza MIT.