vendor/happyr/doctrine-specification/src/Logic/LogicX.php line 96

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * This file is part of the Happyr Doctrine Specification package.
  5.  *
  6.  * (c) Tobias Nyholm <tobias@happyr.com>
  7.  *     Kacper Gunia <kacper@gunia.me>
  8.  *     Peter Gribanov <info@peter-gribanov.ru>
  9.  *
  10.  * For the full copyright and license information, please view the LICENSE
  11.  * file that was distributed with this source code.
  12.  */
  13. namespace Happyr\DoctrineSpecification\Logic;
  14. use Doctrine\ORM\QueryBuilder;
  15. use Happyr\DoctrineSpecification\Filter\Filter;
  16. use Happyr\DoctrineSpecification\Filter\Satisfiable;
  17. use Happyr\DoctrineSpecification\Query\QueryModifier;
  18. use Happyr\DoctrineSpecification\Specification\Specification;
  19. /**
  20.  * This class should be used when you combine two or more Expressions.
  21.  */
  22. abstract class LogicX implements Specification
  23. {
  24.     public const AND_X 'andX';
  25.     public const OR_X 'orX';
  26.     /**
  27.      * @var string
  28.      */
  29.     private $expression;
  30.     /**
  31.      * @var Filter[]|QueryModifier[]
  32.      */
  33.     private $children;
  34.     /**
  35.      * Take two or more Expression as parameters.
  36.      *
  37.      * @param string               $expression
  38.      * @param Filter|QueryModifier ...$children
  39.      */
  40.     public function __construct(string $expression, ...$children)
  41.     {
  42.         $this->expression $expression;
  43.         $this->children $children;
  44.     }
  45.     /**
  46.      * @param QueryBuilder $qb
  47.      * @param string       $context
  48.      *
  49.      * @return string
  50.      */
  51.     public function getFilter(QueryBuilder $qbstring $context): string
  52.     {
  53.         $children = [];
  54.         foreach ($this->children as $spec) {
  55.             if ($spec instanceof Filter) {
  56.                 $filter $spec->getFilter($qb$context);
  57.                 if ($filter) {
  58.                     $children[] = $filter;
  59.                 }
  60.             }
  61.         }
  62.         if (!$children) {
  63.             return '';
  64.         }
  65.         $expression = [$qb->expr(), $this->expression];
  66.         if (!is_callable($expression)) {
  67.             throw new \InvalidArgumentException(
  68.                 sprintf('Undefined "%s" method in "%s" class.'$this->expressionget_class($qb->expr()))
  69.             );
  70.         }
  71.         return (string) call_user_func_array($expression$children);
  72.     }
  73.     /**
  74.      * @param QueryBuilder $qb
  75.      * @param string       $context
  76.      */
  77.     public function modify(QueryBuilder $qbstring $context): void
  78.     {
  79.         foreach ($this->children as $child) {
  80.             if ($child instanceof QueryModifier) {
  81.                 $child->modify($qb$context);
  82.             }
  83.         }
  84.     }
  85.     /**
  86.      * {@inheritdoc}
  87.      */
  88.     public function filterCollection(iterable $collection, ?string $context null): iterable
  89.     {
  90.         foreach ($collection as $candidate) {
  91.             if ($this->isSatisfiedBy($candidate$context)) {
  92.                 yield $candidate;
  93.             }
  94.         }
  95.     }
  96.     /**
  97.      * {@inheritdoc}
  98.      */
  99.     public function isSatisfiedBy($candidate, ?string $context null): bool
  100.     {
  101.         $has_satisfiable_children false;
  102.         foreach ($this->children as $child) {
  103.             if (!$child instanceof Satisfiable) {
  104.                 continue;
  105.             }
  106.             $has_satisfiable_children true;
  107.             $satisfied $child->isSatisfiedBy($candidate$context);
  108.             if ($satisfied && self::OR_X === $this->expression) {
  109.                 return true;
  110.             }
  111.             if (!$satisfied && self::AND_X === $this->expression) {
  112.                 return false;
  113.             }
  114.         }
  115.         return !$has_satisfiable_children || self::AND_X === $this->expression;
  116.     }
  117.     /**
  118.      * Add another child to this logic tree.
  119.      *
  120.      * @param Filter|QueryModifier $child
  121.      */
  122.     protected function append($child): void
  123.     {
  124.         $this->children[] = $child;
  125.     }
  126. }