Your repository has 47 methods. That's the problem.
Repository Pattern PHP usually ends up as a God Class with findAll, findByUser, findActiveByMonth and dozens more methods. Jardis generates a 4-stage pipeline per aggregate instead: Query, Transform, Validate, Persist. Each stage with one clear responsibility, structurally enforced rather than by convention.
PHP repositories keep growing. Until they become unmanageable.
The pattern is correct. Implementation fails not from lack of intent, but from missing boundaries.
Repositories turn into God Classes
Every new requirement lands as another method on the repository. findAll, findByUser, findActiveByMonth, findByStatusAndDate. After two years, the repository has 60 methods. No structure, no boundary, no end in sight.
Too tightly coupled to Eloquent or Doctrine
Laravel repositories return Eloquent collections. Symfony repositories return Doctrine entities directly. The domain is tied to the persistence layer. Swapping an ORM or adding a caching layer means rebuilding code across the entire application.
Read and write without separation
The same repository interface handles both read and write operations. Queries trigger unnecessary eager loading, commands run into caching logic that was never meant for them. Responsibilities are mixed, side effects become unpredictable.
4 Stages. One Responsibility Each. No God Class.
Jardis does not generate generic repository classes. It generates a complete pipeline with clearly defined responsibilities at every stage.
Repository Pattern PHP as a structured pipeline
Jardis generates four clearly separated stages per aggregate: Query, Transform, Validate, and Persist. Each stage has its own file, its own namespace, and exactly one responsibility. Data access is a structured pipeline, not a repository with dozens of methods.
Reads and writes run through different stages
The Query stage is the read path, Persist the write path. Together with the CQRS separation of commands and queries, reads and writes never run through the same God Class method. The separation lives in the structure, not in a code review rule.
No ORM types in the domain layer
The generated repository interfaces work with Domain Entities, not with Eloquent models or Doctrine entities. The persistence layer is replaceable. Switching from MySQL to PostgreSQL or adding a Redis cache layer does not touch the domain.
Why the pipeline beats a single repository.
Because a repository that can do everything eventually communicates nothing clearly.
Every data access has a defined path
Read operations go through the Query stage, writes through Persist. The entry point is unambiguous. Side effects from misused repositories disappear.
Repositories do not grow without limit
The 4-stage pipeline has clear boundaries per stage. Data access follows the sequence Query, Transform, Validate, Persist instead of piling up as another findBy method. No single repository accumulates all methods of an aggregate.
ORM changes do not touch the domain
Repository interfaces work with Domain Entities. Eloquent, Doctrine, raw PDO: the implementation is isolated. A caching layer can be added without touching domain logic.
Repository Pattern PHP without God Classes or convention debates?
Join the WaitlistFrequently Asked Questions
Answers about the repository pipeline with Jardis.
Jardis generates four stages per aggregate: Query, Transform, Validate, and Persist. Query builds and runs the data retrieval, Transform maps between raw database data and typed domain objects, Validate checks the data against the aggregate rules, Persist writes the changes to the database. Each stage is a separate PHP class in its own namespace, identical across every Bounded Context.