Doctrine Specification Patternまたは再利用可能なQueryBuilder

例でお気に入りのDoctrineでこのパターンをどのように使用できるか、そしてなぜそうするのか、できる限り簡潔に伝えようと思います。



基本的なケースを想像してみましょう:



1.私たちには、「家」の本質、「家のアパート」の本質、「開発者」の本質、「地域」の本質があります。

2.私たちにはタスクがあります:すべての開発者を取得できるようにすること、ビルダーが占有するすべての地域を取得できるようにすること、ビルダーに属するすべての家と、原則として家が販売されているすべての利用可能な地域を取得できるようにすることです。

3.ビジネスルールがあります。



有効なビルダーとは、管理パネルで確認したビルダーです。 $ verifed = trueを持っています



「しかし、真実は後でどうなるかわからない、多分有効性の条件はすぐに変わるだろう。」



有効な家とは、 すでに座標が入力されて おり、少なくともいくつかの説明がある家です。



「それでも、少なくとも1つのアパートが接続されているため、まだ明確ではありません。 アパートなしではどこにも表示できないと思います!1! しかし、ここでも、妥当性の概念を変更することができます-今のところ、そうです。 それを修正するのは長くはありませんか?!!! ところで、はい!! 1 $ verifed = trueのないビルダーの場合、これらの家を見せてはいけません!!! 長い間修正しますか?」



「そして、少なくとも1つの有効な家がある地域のみを表示したい!!! 1ところで、このフィルタリングはメインページと個々の開発者のページの両方で行う必要があります!!! 有効な家が私たちと一緒にいることを覚えていますか? ??? 生きていますか??」



したがって、私のリポジトリは以前のように見えます:



RegionRepository:
class RegionRepository extends \Doctrine\ORM\EntityRepository { public function findAvailableRegions() { $qb = $this->createQueryBuilder('r'); return $qb ->join('r.houses', 'h') ->join('h.developer', 'd') #   start ->innerJoin('h.apartments', 'a') //      ->where('h.longitude IS NOT NULL') //   ->andWhere('h.latitude IS NOT NULL') //,   ->andWhere('h.description IS NOT NULL') //*...   ..      .. #   end #   start ->andWhere('d.verified') //   -   ... #   end ->getQuery() ->getResult(); } public function findAvailableRegionsByDeveloper(DeveloperCompany $developerCompany) { $qb = $this->createQueryBuilder('r'); return $qb ->join('r.houses', 'h') ->join('h.developer', 'd') #   start ->innerJoin('h.apartments', 'a') //      ->where('h.longitude IS NOT NULL') //   ->andWhere('h.latitude IS NOT NULL') //,   ->andWhere('h.description IS NOT NULL') //*...   ..      .. #   end ->andWhere('d.id = :developer_id') ->setParameter('developer_id', $developerCompany->getId()) ->getQuery() ->getResult(); } }
      
      







HouseRepository:
 class HouseRepository extends \Doctrine\ORM\EntityRepository { public function findAvailableHouses() { $qb = $this->createQueryBuilder('h'); return $qb ->join('h.developer', 'd') ->innerJoin('h.apartments', 'a') //    ->where('h.longitude IS NOT NULL') // ->andWhere('h.latitude IS NOT NULL') // ->andWhere('h.description IS NOT NULL') //  #!!! ->where('d.verified') //,    .      ... ->getQuery() ->getResult(); } }
      
      







DeveloperCompanyRepository:
 class DeveloperCompanyRepository extends \Doctrine\ORM\EntityRepository { public function findAvailableDevelopers() { return $this->createQueryBuilder('d') ->where('d.verified') //........ ->getQuery() ->getResult(); } }
      
      







そのため、verified = trueによって開発者の有効性チェックを100回繰り返しました。

座標、説明などによる家の妥当性の100回の重複検証。

これら2つの条件が100倍同時に複製されました。



最初は自分自身を傷つけるだけで、コードのこの部分を思い出して眠ることができない場合があり、笑顔で仕事に行きたいという欲求はありません。 しかし、これは今のところのみです..Pet​​yaが昨日もう1つの重要な点を推測したため、マネージャーが来てこれらの「有効性」条件の1つを変更するか、JOINで選択してこのエンティティまたはそのエンティティの有効性の1つまたは別の要因を示すときにどこかを忘れたときなぜ一部の家は表示されないが、10,000のリポジトリでそれらを修正しなかったのか、今ではビルダーのページに無効な家がある地域を表示します。ペシャは検証の存在を知らなかったためです。すでに歌唱エリアで傷つき始めています ニース。



そして、美しい晴れた朝、なんらかの理由で早めに到着し、誰もいなくてもコーヒーマシンを繰り返し使用する準備ができています-同時に、待ち行列はありません。オフィスには新鮮な空気があり、同僚のコンピューターのクーラーやまだ沈黙していません。

そのような瞬間に、あなたはパターンに近づき、 仕様パターンが私にやってきたのはその瞬間でした。



最初のステップは、$ this-> createQueryBuilder( 'alias')を削除する必要があるという事実をより簡単に受け入れるために心をクリアすることです。これを何らかの革命としてではなく、未知の、しかしいずれにしても明るい未来へのパスとして認識します。

第二段階- 作曲家はより幸せ/教義仕様を要求する

3番目のステップは、最高の価値があるという事実を受け入れ、次のクラスを作成することです。



有効な開発者の選択の詳細。



CorrectDeveloperSpecification
 use Happyr\DoctrineSpecification\BaseSpecification; use Happyr\DoctrineSpecification\Spec; class CorrectDeveloperSpecification extends BaseSpecification { public function getSpec() { return Spec::eq('verified', true); } }
      
      







有効な家の選択の詳細。



CorrectHouseSpecification
 use Happyr\DoctrineSpecification\BaseSpecification; use Happyr\DoctrineSpecification\Spec; class CorrectHouseSpecification extends BaseSpecification { public function getSpec() { Spec::andX( Spec::innerJoin('apartments', 'a'), Spec::innerJoin('developer', 'd'), Spec::isNotNull('description'), Spec::isNotNull('longitude'), Spec::isNotNull('latitude'), new CorrectDeveloperSpecification('d') ); } }
      
      







有効なリージョンの選択の特異性。



CorrectRegionSpecification
 use Happyr\DoctrineSpecification\BaseSpecification; use Happyr\DoctrineSpecification\Spec; class CorrectRegionSpecification extends BaseSpecification { public function getSpec() { return Spec::andX( Spec::innerJoin('houses', 'h'), new CorrectHouseSpecification('h') ); } }
      
      







開発者に有効な選択の詳細:



CorrectOccupiedRegionByDeveloperSpecification
 use AppBundle\Entity\DeveloperCompany; use Happyr\DoctrineSpecification\BaseSpecification; use Happyr\DoctrineSpecification\Spec; class CorrectOccupiedRegionByDeveloperSpecification extends BaseSpecification { /** @var DeveloperCompany */ private $developer; public function __construct(DeveloperCompany $developerCompany, $dqlAlias = null) { parent::__construct($dqlAlias); $this->developer = $developerCompany; } public function getSpec() { return Spec::andX( new CorrectRegionSpecification(), Spec::join('developer', 'd', 'h'), Spec::eq('d.id', $this->developer->getId()) ); } }
      
      







今、最も楽しいのは、リポジトリからgovnokodを破壊、分割、焼き付けることです! ネタバレを見る前に、何かに気を取られず、コードがどれほど簡単で神聖になったかを十分に楽しむ準備ができていることを確認してください...



RegionRepository
 class RegionRepository extends EntitySpecificationRepository { public function findAvailableRegions() { return $this->match( new CorrectRegionSpecification() ); } public function findAvailableRegionsByDeveloper(DeveloperCompany $developerCompany) { return $this->match( new CorrectOccupiedRegionByDeveloperSpecification($developerCompany) ); } }
      
      







ハウスリポジトリ
 class HouseRepository extends EntitySpecificationRepository { public function findAvailableHouses() { return $this->match( new CorrectHouseSpecification() ); } }
      
      







DeveloperCompanyRepository
 class DeveloperCompanyRepository extends EntitySpecificationRepository { public function findAvailableDevelopers() { return $this->match( new CorrectDeveloperSpecification() ); } }
      
      







甘くない?



バンドルへのリンク -仕様の使用方法の詳細な説明があります。



Open Spaceでの快適なコーディング、パターン、晴れた朝、静寂の時間。



All Articles