PHPackages                             starker-xp/cqrses-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. starker-xp/cqrses-bundle

ActiveSymfony-bundle[Utility &amp; Helpers](/categories/utility)

starker-xp/cqrses-bundle
========================

A demo bundle

07PHP

Since Feb 12Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/starker-xp/cqrses-bundle)[ Packagist](https://packagist.org/packages/starker-xp/cqrses-bundle)[ RSS](/packages/starker-xp-cqrses-bundle/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependenciesVersions (1)Used By (0)

StarkerxpCQRSESBundle
=====================

[](#starkerxpcqrsesbundle)

> **Archive** — Ce projet est un bundle Symfony expérimental développé dans le cadre d'une démarche de R&amp;D personnelle autour du **Domain-Driven Design (DDD)**, du **CQRS** (Command Query Responsibility Segregation) et de l'**Event Sourcing**. Il n'est plus maintenu et est conservé à titre de référence.

Contexte
--------

[](#contexte)

Ce bundle a été conçu à une époque où je me formais au DDD en lisant des ouvrages de référence (notamment ceux d'Eric Evans et de Vaughn Vernon) tout en travaillant sous **Symfony 2.x/3.x**. L'objectif était double :

1. **Apprendre par la pratique** — Implémenter de A à Z les patterns CQRS et Event Sourcing pour en comprendre les mécanismes internes.
2. **Fournir un scaffolding** — Générer automatiquement la structure de code CQRS/ES pour un domaine métier donné, afin de réduire le boilerplate.

> *Analyse rétrospective réalisée en 2026 dans le cadre d'un nettoyage et d'une mise en archive de mes dépôts GitHub/GitLab.*

Architecture
------------

[](#architecture)

Le bundle implémente le cycle complet CQRS/Event Sourcing :

```
                    ┌─────────────────────────────────────────────┐
                    │                 WRITE SIDE                  │
                    │                                             │
  Requête ──► CommandBus ──► CommandHandler ──► Domain Aggregate  │
                    │                              │              │
                    │                         DomainEvent(s)      │
                    │                              │              │
                    │                    ┌─────────┴─────────┐    │
                    │                    ▼                   ▼    │
                    │              EventStore          Projection  │
                    │           (append-only)       (read model)  │
                    └─────────────────────────────────────────────┘

                    ┌─────────────────────────────────────────────┐
                    │                 READ SIDE                   │
                    │                                             │
  Requête ──► QueryBus ──► QueryHandler ──► ReadRepository ──► DB │
                    └─────────────────────────────────────────────┘

```

### Structure du code

[](#structure-du-code)

```
├── Command/                        # Commandes Symfony (CLI) pour le scaffolding
│   ├── GenererBaseCQRSCommand.php   # Génère la structure CQRS/ES complète d'un domaine
│   └── GenererCommandeCommand.php   # Génère une commande CQRS individuelle
│
├── DependencyInjection/            # Intégration Symfony (chargement config/services)
│
├── Generator/
│   └── CQRSESGenerator.php         # Moteur de génération basé sur les templates Twig
│
├── Resources/
│   ├── config/services.yml          # Déclaration de l'EventStore comme service
│   └── views/                       # 21 templates Twig pour le scaffolding
│       ├── Services/Command/        # Templates Command + Handler (Créer, Modifier, Supprimer)
│       ├── Services/Domain/         # Templates Agrégat, Events, DTO, Collection
│       ├── Services/Persistence/    # Templates Repository (écriture) + Projection
│       ├── Services/Query/          # Templates Query + QueryHandler
│       └── Resources/config/        # Template de déclaration de services YAML
│
└── Services/                        # Le framework CQRS/ES réutilisable
    ├── Bus/                         # Bus abstrait + interface Handler
    ├── Command/                     # CommandBus, CommandInterface, CommandHandlerInterface
    ├── Domain/                      # DomainEvents (agrégat), AbstractEvent, EventInterface, etc.
    ├── Persistence/                 # EventStore, AbstractProjection, AggregateHistorique
    └── Query/                       # QueryBus, QueryInterface, QueryHandlerInterface

```

Patterns et concepts implémentés
--------------------------------

[](#patterns-et-concepts-implémentés)

### CQRS — Séparation Lecture / Écriture

[](#cqrs--séparation-lecture--écriture)

- **CommandBus** : dispatche une commande vers son handler via une convention de nommage (`XxxCommand` → `XxxHandler`)
- **QueryBus** : dispatche une query vers son handler pour la lecture
- Séparation des connexions BDD : `write_connection`, `read_connection`, `event_connection`

### Event Sourcing

[](#event-sourcing)

- **DomainEvents** (agrégat) : accumule les events en mémoire, les applique pour muter l'état interne
- **EventStore** : persiste les events dans une table `events` (append-only)
- **Reconstitution** : reconstruit un agrégat en rejouant ses events depuis l'EventStore
- **Snapshots** : sauvegarde périodique de l'état de l'agrégat (tous les 5 events) pour optimiser la reconstitution
- **Projections** : met à jour un read model dénormalisé de manière synchrone après chaque commit

### Scaffolding

[](#scaffolding)

Pour un domaine `Produit`, la commande génère automatiquement :

```
php bin/console starkerxp:cqrs:generer:structure MonBundle Produit
```

Fichiers générés :

- `Command/Produit/` — CreerProduitCommand, CreerProduitHandler, ModifierProduitCommand/Handler, SupprimerProduitCommand/Handler
- `Domain/Produit/` — ProduitDomain (agrégat), ProduitDTO, ProduitPOPO, ProduitCollection, Events (AEteCree, AEteModifie, AEteSupprime)
- `Persistence/Ecriture/Produit/` — ProduitRepository, ProduitProjection
- `Persistence/Lecture/` — ProduitRepository (read-only)
- `Query/Produit/` — ProduitQuery, ProduitQueryHandler, ProduitListerQuery, ProduitListerQueryHandler
- `Resources/config/` — services.produit.yml (déclaration DI complète)

Compétences démontrées
----------------------

[](#compétences-démontrées)

- **Domain-Driven Design** : agrégats, domain events, value objects, repositories
- **CQRS** : séparation stricte des responsabilités lecture/écriture avec bus dédiés
- **Event Sourcing** : persistance par events, reconstitution, snapshots, projections
- **Symfony** : création de bundle, DependencyInjection, commandes console, générateur de code
- **Architecture logicielle** : interfaces, classes abstraites, conventions, séparation en couches

Limitations connues
-------------------

[](#limitations-connues)

Ce projet étant un exercice de R&amp;D, certaines limitations ont été identifiées avec le recul :

LimitationDétail**Pas de tests**Aucun test unitaire ou fonctionnel n'accompagne le code**Sérialisation PHP**L'EventStore utilise `serialize()`/`unserialize()` au lieu de JSON, ce qui pose des problèmes de sécurité et d'interopérabilité**Pas de gestion de concurrence**Absence d'optimistic locking sur l'EventStore (pas de vérification de version au commit)**Projections synchrones**Les projections sont exécutées de manière synchrone dans la même transaction, ce qui ne scale pas**Convention de nommage fragile**Le mapping Command→Handler repose sur un remplacement de chaîne dans le nom de classe**Compatibilité Symfony**Conçu pour Symfony 2.x/3.x — incompatible avec Symfony 4.2+ (ContainerAwareCommand déprécié, SensioGeneratorBundle abandonné, TreeBuilder API modifiée)Prérequis (historiques)
-----------------------

[](#prérequis-historiques)

- PHP &gt;= 5.3
- Symfony 2.x ou 3.x
- Doctrine DBAL
- SensioGeneratorBundle
- rhumsaa/uuid (aujourd'hui ramsey/uuid)

Licence
-------

[](#licence)

Projet personnel — usage libre à titre de référence.

###  Health Score

19

—

LowBetter than 9% of packages

Maintenance51

Moderate activity, may be stable

Popularity4

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity12

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/b003a9e7699087cfedb3cd73ffee89fc6107e2446f48a909a2ef12472bc99e36?d=identicon)[starker-xp](/maintainers/starker-xp)

---

Top Contributors

[![starker-xp](https://avatars.githubusercontent.com/u/514436?v=4)](https://github.com/starker-xp "starker-xp (11 commits)")

### Embed Badge

![Health badge](/badges/starker-xp-cqrses-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/starker-xp-cqrses-bundle/health.svg)](https://phpackages.com/packages/starker-xp-cqrses-bundle)
```

###  Alternatives

[streamcommon/promise

PHP-CLI promise implementation

142.0k](/packages/streamcommon-promise)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
