rikbruil / doctrine-specification
Doctrine Specification 模式,用于动态构建查询并使用可复用的类进行组合。
1.2.0
2017-03-17 18:30 UTC
Requires
- php: >=5.5
- doctrine/collections: ^1.2
- doctrine/orm: ^2.2
- rikbruil/specification: 0.9.*
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.0
- henrikbjorn/phpspec-code-coverage: ^2.0
- phpspec/phpspec: ^2.0
- satooshi/php-coveralls: ^1.0
README
用于动态构建查询以及使用可复用类进行组合的 Doctrine Specification 模式。
这个库最初是 Benjamin Eberlei 的 博客文章 的改编。我也受到了 Happyr Doctrine-Specification 代码的启发,然而这个库有一些小的不同。主要的不同是 SpecificationRepository->match() 不直接返回结果,而是返回查询对象。
由于我喜欢 Doctrine 的分页对象,我希望能够将其与 Specification 模式结合使用。
注意:在 1.2 版本之前,需要扩展 SpecificationRepository 类。现在不再需要这样做,因为我们提供了一个 SpecificationRepositoryTrait,您可以用它来代替。这个类仍然提供,是为了向后兼容。还有一个 SpecificationAwareInterface,您如果需要的话也可以使用。
使用方法
使用 composer require rikbruil/doctrine-specification
安装最新版本
// Not using the lib // Note: Advertisement repository is an instance of the Doctrine default repository class $qb = $this->em->getRepository('Advertisement') ->createQueryBuilder('r'); return $qb->where('r.ended = 0') ->andWhere( $qb->expr()->orX( 'r.endDate < :now', $qb->expr()->andX( 'r.endDate IS NULL', 'r.startDate < :timeLimit' ) ) ) ->setParameter('now', new \DateTime()) ->setParameter('timeLimit', new \DateTime('-4weeks')) ->getQuery() ->getResult();
use Rb\Specification\Doctrine\Condition\Equals; use Rb\Specification\Doctrine\Condition\IsNull; use Rb\Specification\Doctrine\Condition\LessThan; use Rb\Specification\Doctrine\Logic\AndX; use Rb\Specification\Doctrine\Logic\OrX; use Rb\Specification\Doctrine\Specification; // Using the lib $spec = new Specification([ new Equals('ended', 0), new OrX( new LessThan('endDate', new \DateTime()), new AndX( new IsNull('endDate'), new LessThan('startDate', new \DateTime('-4weeks')) ) ) ]); // Note: Advertisement repository is an instance that uses the SpecificationRepositoryTrait return $this->em->getRepository('Advertisement')->match($spec)->execute();
组合
这个模式的一个优点是组合,这使得规范非常可重用
use Entity\Advertisement; class ExpiredAds extends Specification { public function __construct() { $specs = [ new Equals('ended', 0), new OrX( new LessThan('endDate', new \DateTime()), new AndX( new IsNull('endDate'), new LessThan('startDate', new \DateTime('-4weeks')) ) ) ]; parent::__construct($specs); } public function isSatisfiedBy($value) { return $value === Advertisement::class; } } use Entity\User; class AdsByUser extends Specification { public function __construct(User $user) { $specs = [ new Select('u'), new Join('user', 'u'), new Equals('id', $user->getId(), 'u'), ]; parent::__construct($specs); } public function isSatisfiedBy($value) { return $value == Advertisement::class && parent::isSatisfiedBy($value); } } class SomeService { /** * Fetch Adverts that we should close but only for a specific company */ public function myQuery(User $user) { $spec = new Specification([ new ExpiredAds(), new AdsByUser($user), ]); return $this->em->getRepository('Advertisement')->match($spec)->execute(); } /** * Fetch adverts paginated by Doctrine Paginator with joins intact. * A paginator can be iterated over like a normal array or Doctrine Collection */ public function myPaginatedQuery(User $user, $page = 1, $size = 10) { $spec = new Specification([ new ExpiredAds(), new AdsByUser($user), ]); $query = $this->em->getRepository('Advertisement')->match($spec); $query->setFirstResult(($page - 1) * $size)) ->setMaxResults($size); return new Paginator($query); } }
需求
Doctrine-Specification 需要
- PHP 5.5+
- Doctrine 2.2
许可证
Doctrine-Specification 在 MIT 许可证下发布 - 详细信息请参阅 LICENSE
文件
致谢
这个库深受 Benjamin Eberlei 的 博客文章 和 Happyr 的 Doctrine-Specification 库 的启发。