happyr/doctrine-specification
Reusable Doctrine query Specifications for PHP. Replace messy repositories and huge QueryBuilder methods with small, composable, testable spec classes. Reduce duplication, avoid methods with many arguments, and extend queries cleanly as your app grows.
QueryBuilder logic.AdvertsWeShouldClose) as first-class citizens, improving collaboration between devs and non-technical stakeholders.Adopt if:
QueryBuilder logic or duplicate conditions.QueryBuilder).Look elsewhere if:
"This library lets us write database queries like Lego blocks—reusable, testable, and aligned with business rules. Instead of copying/pasting messy QueryBuilder code across repositories, we’ll encapsulate logic (e.g., ‘active users,’ ‘expired subscriptions’) into clean, shareable classes. This reduces bugs, speeds up development, and makes it easier to add new filters (e.g., for admin dashboards). Think of it as moving from spaghetti queries to a structured, scalable system—saving time and money long-term."
ROI:
QueryBuilder spaghetti).*"This implements the Specification pattern for Doctrine, solving three key problems:
findActiveUsers(), findActiveUsersWithPhotos(), etc., with composable specs like ActiveUserSpec + HasPhotoSpec.QueryBuilder which requires DB connections).Spec::andX(new PremiumUser(), new ActiveThisMonth())) without procedural duplication.Example:
// Before: Monolithic repository method
public function getActivePremiumUsers() {
return $this->createQueryBuilder('u')
->where('u.active = 1')
->andWhere('u.subscription_end > :now')
->setParameter('now', new \DateTime())
->getQuery()
->getResult();
}
// After: Composable specs
$spec = Spec::andX(
new ActiveUserSpec(),
new PremiumSubscriptionSpec(new \DateTime())
);
return $this->repository->match($spec);
Tradeoffs:
Next Steps:
Spec namespace and naming conventions (e.g., *Spec.php)./users?spec=active&spec=premium)."*How can I help you explore Laravel packages today?