Esperto in sviluppo web e gestione di team tecnici, mi specializzo nella creazione e ottimizzazione di soluzioni digitali performanti. Grazie a una profonda padronanza di tecnologie moderne come React.js, Node.js, TypeScript, Symfony, Docker e FrankenPHP, garantisco il successo di progetti SaaS complessi, dalla progettazione alla messa in produzione, per aziende di diversi settori.
Senti parlare di CQRS ovunque ma ti chiedi come applicarlo senza tirare fuori Symfony o Laravel? Buone notizie: possiamo esplorare la Command Query Responsibility Segregation in PHP puro con una semplice organizzazione e poche classi ben pensate. Apri l’editor, gettiamo insieme le fondamenta.
Prerequisiti: PHP 8.4 e configurazione minima
PHP 8.4 installato (CLI o server web). Verifica la tua versione con per sfruttare le proprietà , i tipi strict e il supporto nativo ai first-class callables.
Composer (opzionale ma comodo per l’autoloading) e un server web leggero ( è sufficiente per fare prove).
Se devi restare su una versione precedente, assicurati che le funzionalità utilizzate (promozione del costruttore, proprietà , ecc.) siano disponibili oppure adatta gli snippet.
1. CQRS in due minuti
CQRS significa separare la lettura (Query) dalla scrittura (Command). Ottieni così due percorsi ottimizzati:
I comandi modificano lo stato (creare un account, pubblicare un articolo) e non restituiscono dati applicativi.
Le query leggono lo stato (elenco degli articoli, dettaglio di un account) senza effetti collaterali.
Questa separazione nasce dalla filosofia del DDD, ma puoi adottarla senza eccessivo formalismo. Benefici immediati:
Test più semplici: testi i handler in maniera unitaria.
Codice più leggibile: ogni handler fa una sola cosa.
Scalabilità progressiva: puoi far evolvere il lato lettura in modo indipendente dal lato scrittura.
Ricorda però che CQRS introduce un po’ di complessità strutturale. Su un semplice CRUD potrebbe essere eccessivo. Usalo quando le regole di business o le esigenze di scalabilità lo richiedono.
2. Struttura di cartelle minimale in PHP nativo
Possiamo restare leggeri con un albero molto semplice:
Separiamo chiaramente Domain (regole di business), Application (casi d’uso) e Infrastructure (implementazioni concrete).
3. Modello di dominio minimalista
Creiamo un aggregato e il suo repository:
4. Lato Command: creare un articolo
Il comando trasporta l’intenzione. L’handler orchestra la logica di business.
Nota importante: l’handler non restituisce nulla. Se vuoi leggere di nuovo l’articolo, passerai da una Query.
5. Lato Query: elencare gli articoli
Esporre un array già pronto per la serializzazione evita di legare la presentazione al modello di dominio.
6. Un repository in memoria per partire
Potrai sostituire questa implementazione con Doctrine, PDO o un’API esterna in seguito senza toccare gli handler.
7. Mettere in piedi bus ultraleggeri
Il pattern CQRS diventa piacevole quando centralizzi la risoluzione degli handler:
php
php
Questi bus restano basilari ma bastano per comprendere la meccanica. In un progetto reale potresti collegarli a un contenitore di dependency injection (PHP-DI, Symfony DI, ecc.).
8. Esempio di bootstrap in public/index.php
php
L’operatore (...) (first-class callable), disponibile da PHP 8.1, è pienamente supportato in PHP 8.4. Se devi supportare una versione precedente (8.0 o inferiore), sostituiscilo con fn ($command) => $createHandler($command).
9. Progredire passo dopo passo
Una volta gettate le basi, puoi arricchire la soluzione:
Validazione: aggiungi Value Object (Titolo, Contenuto) o una validazione con Symfony Validator prima di creare l’aggregato.
Persistenza reale: implementa un repository MySQL (PDO) o PostgreSQL senza toccare gli handler.
Eventi di dominio: pubblica un ArticlePublished quando il comando va a buon fine e consumalo in un altro livello.
Proiezione dedicata: crea una tabella ottimizzata per la lettura per query esigenti (paginazione, ricerca full-text).
Test: scrivi test unitari per ogni handler e test funzionali per i bus.
10. Checklist per la prima messa in produzione
[ ] Ogni comando ha un handler dedicato che non restituisce nulla.
[ ] Ogni query è isolata e formatta i dati per il front-end.
[ ] Le dipendenze tecniche vengono iniettate dall’esterno.
[ ] Gli errori di business sono gestiti nel dominio (eccezioni specializzate, Value Object, ecc.).
[ ] I test coprono comandi, query e bus.
Con questo scheletro puoi introdurre CQRS gradualmente in un progetto esistente o avviare un nuovo servizio senza framework. La chiave è mantenere chiaro il confine tra lettura e scrittura e far evolvere l’architettura per iterazioni. Buona sperimentazione!