createQueryBuilder('st') ->select('COUNT(st)'); $this->buildQuery($qb, $params, $currentUser); return (int) $qb ->getQuery() ->getSingleScalarResult(); } /** * Find task for given parameters. * * Available parameters: * * - `person` : filter by person associated with the task ; * - `user` : filter by user that created the task ; * - `scope` : filter by scope associated with the task ; * - `date_status`: type of task. To choose between : * `ended`, `warning`, `current`, `not_started` ; * - `is_closed`: boolean. Indicate if the tasks must be closed (true) or * opened * - `types`: string[] an array of task types * * @param type $params * * @return type */ public function findByParameters($params, User $currentUser, int $firstResult = 0, int $maxResults = 50) { $qb = $this->createQueryBuilder('st'); $this->buildQuery($qb, $params, $currentUser); $qb ->setMaxResults($maxResults) ->setFirstResult($firstResult); return $qb ->getQuery() ->getResult(); } public function setAuthorizationHelper(AuthorizationHelper $authorizationHelper) { $this->authorizationHelper = $authorizationHelper; } protected function addTypeFilter(QueryBuilder $qb, $params) { $andWhere = $qb->expr()->andX(); switch ($params['date_status']) { case self::DATE_STATUS_ENDED: $andWhere ->add($this->buildNowIsAfterEndDate($qb)); break; case self::DATE_STATUS_WARNING: $andWhere ->add($this->buildNowIsAfterEndDate($qb, true)) ->add($this->buildNowIsAfterWarningDate($qb)); break; case self::DATE_STATUS_CURRENT: // st.endDate is NULL or (st.endDate is not null and st.endDate < now)) $andWhere ->add($this->buildNowIsAfterEndDate($qb, true)) ->add($this->buildNowIsAfterWarningDate($qb, true)) ->add($this->buildNowIsAfterStartDate($qb, false)); break; case self::DATE_STATUS_NOT_STARTED: $andWhere ->add($this->buildNowIsAfterEndDate($qb, true)) ->add($this->buildNowIsAfterWarningDate($qb, true)) ->add($this->buildNowIsAfterStartDate($qb, true)); } $qb->setParameter('now', new DateTime('today'), Types::DATE_MUTABLE); $qb->andWhere($andWhere); } protected function buildACLQuery(QueryBuilder $qb, User $currentUser) { if (null === $this->authorizationHelper) { throw new LogicException('Injecting the authorization helper is ' . 'required to run this query. Please use dependency injection ' . 'to initialize this repository or use the method ' . '`setAuthorizationHelper`'); } $role = new Role(TaskVoter::SHOW); $qb->join('st.person', 'p'); $centers = $this->authorizationHelper ->getReachableCenters($currentUser, $role); $i = 0; $where = $qb->expr()->orX(); foreach ($centers as $center) { $circles = $this->authorizationHelper ->getReachableCircles($currentUser, $role, $center); $centerWhere = $qb->expr()->andX(); $centerWhere->add($qb->expr()->eq('p.center', ':center_' . $i)); $qb->setParameter('center_' . $i, $center); $centerWhere->add($qb->expr()->in('st.circle', ':circles_' . $i)); $qb->setParameter('circles_' . $i, $circles); $where->add($centerWhere); ++$i; } $qb->where($where); } protected function buildQuery(QueryBuilder $qb, $params, ?User $currentUser = null) { if (null !== $currentUser) { $this->buildACLQuery($qb, $currentUser); } if (array_key_exists('person', $params) and !empty($params['person'])) { $qb->andWhere($qb->expr()->eq('st.person', ':person')); $qb->setParameter('person', $params['person']); } elseif (array_key_exists('center', $params)) { if ($params['center'] instanceof Center) { $qb->join('st.person', 'person'); $qb->andWhere($qb->expr()->eq('person.center', ':center')); $qb->setParameter('center', $params['center']); } else { throw new UnexpectedValueException("params 'center' should be an instance of " . Center::class); } } if (array_key_exists('unassigned', $params) and true === $params['unassigned']) { if (array_key_exists('user', $params) and !empty($params['user'])) { throw new UnexpectedValueException('You should not require for ' . 'unassigned tasks and tasks assigned to some user.'); } $qb->andWhere($qb->expr()->isNull('st.assignee')); } if (array_key_exists('user', $params) and !empty($params['user'])) { $qb->andWhere($qb->expr()->eq('st.assignee', ':user')); $qb->setParameter('user', $params['user']); } if (array_key_exists('scope', $params) and !empty($params['scope'])) { $qb->andWhere($qb->expr()->eq('st.circle', ':scope')); $qb->setParameter('scope', $params['scope']); } if (array_key_exists('types', $params) && null !== $params['types']) { if (count($params['types']) > 0) { $qb->andWhere($qb->expr()->in('st.type', ':types')); $qb->setParameter('types', $params['types']); } } if (array_key_exists('date_status', $params) and !empty($params['date_status'])) { $this->addTypeFilter($qb, $params); } if (array_key_exists('is_closed', $params)) { $qb->andWhere($this->buildIsClosed($qb, !$params['is_closed'])); } } private function buildIsClosed(QueryBuilder $qb, bool $negative = false) { if (false === $negative) { return $qb->expr()->eq('st.closed', "'TRUE'"); } return $qb->expr()->eq('st.closed', "'FALSE'"); } private function buildNowIsAfterEndDate(QueryBuilder $qb, $negative = false) { if (false === $negative) { return $qb->expr()->andX() ->add($qb->expr()->isNotNull('st.endDate')) ->add($qb->expr()->lte('st.endDate', ':now')); } return $qb->expr()->orX() ->add( $qb->expr()->andX() ->add($qb->expr()->isNotNull('st.endDate')) ->add($qb->expr()->gt('st.endDate', ':now')) ) ->add($qb->expr()->isNull('st.endDate')); } private function buildNowIsAfterStartDate(QueryBuilder $qb, bool $negative = false) { if (false === $negative) { return $qb->expr()->orX() ->add($qb->expr()->lte('st.startDate', ':now')) ->add($qb->expr()->isNull('st.startDate')); } return $qb->expr()->andX() ->add($qb->expr()->gt('st.startDate', ':now')) ->add($qb->expr()->isNotNull('st.startDate')); } private function buildNowIsAfterWarningDate(QueryBuilder $qb, bool $negative = false) { if (false === $negative) { return $qb->expr()->andX() ->add( $qb->expr()->lte( $qb->expr()->diff('st.endDate', 'st.warningInterval'), ':now' ) ); } return $qb->expr()->orX() ->add( $qb->expr()->andX() ->add($qb->expr()->isNotNull('st.endDate')) ->add($qb->expr()->isNotNull('st.warningInterval')) ->add( $qb->expr()->gt( $qb->expr()->diff('st.endDate', 'st.warningInterval'), ':now' ) ) ) ->add($qb->expr()->isNull('st.endDate')) ->add($qb->expr()->isNull('st.warningInterval')); } }