repository = $em->getRepository(AccompanyingPeriodWork::class); } public function countByAccompanyingPeriod(AccompanyingPeriod $period): int { return $this->repository->countByAccompanyingPeriod($period); } public function countBySocialActionWithDescendants(SocialAction $action): int { $qb = $this->buildQueryBySocialActionWithDescendants($action); $qb->select('COUNT(g)'); return $qb ->getQuery() ->getSingleScalarResult(); } public function countNearEndDateByUser(User $user, \DateTimeImmutable $since, \DateTimeImmutable $until): int { return $this->buildQueryNearEndDateByUser($user, $since, $until) ->select('count(w)')->getQuery()->getSingleScalarResult(); } public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder { return $this->repository->createQueryBuilder($alias, $indexBy); } public function find($id): ?AccompanyingPeriodWork { return $this->repository->find($id); } public function findAll(): array { return $this->repository->findAll(); } public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } /** * @param mixed|null $orderBy * @param mixed|null $limit * @param mixed|null $offset * * @return AccompanyingPeriodWork[] */ public function findByAccompanyingPeriod(AccompanyingPeriod $period, $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset); } /** * Return a list of accompanying period with a defined order:. * * * first, opened works * * then, closed works * * @param array{types?: list, user?: list, after?: \DateTimeImmutable|null, before?: \DateTimeImmutable|null} $filters * * @return AccompanyingPeriodWork[] */ public function findByAccompanyingPeriodOpenFirst(AccompanyingPeriod $period, array $filters, int $limit = 10, int $offset = 0): array { $rsm = new ResultSetMappingBuilder($this->em); $rsm->addRootEntityFromClassMetadata(AccompanyingPeriodWork::class, 'w'); $sql = "SELECT {$rsm} FROM chill_person_accompanying_period_work w LEFT JOIN chill_person_accompanying_period_work_referrer AS rw ON accompanyingperiodwork_id = w.id WHERE accompanyingPeriod_id = :periodId"; // implement filters if ([] !== ($filters['types'] ?? [])) { $sql .= ' AND w.socialaction_id IN (:types)'; } if ([] !== ($filters['user'] ?? [])) { $sql .= ' AND rw.user_id IN (' .implode( ', ', // we add a user_xx for each key of the 'user' list array_map(fn (User $u, int $idx) => ':user_'.$idx, $filters['user'], array_keys($filters['user'])) ) .')'; } $sql .= " AND daterange(:after::date, :before::date) && daterange(w.startDate, w.endDate, '[]')"; // if the start and end date were inversed, we inverse the order to avoid an error if (null !== ($filters['after'] ?? null) && null !== $filters['before'] && $filters['after'] > $filters['before']) { $before = $filters['after']; $after = $filters['before']; } else { $before = $filters['before']; $after = $filters['after']; } // set limit and offset $sql .= " ORDER BY CASE WHEN w.enddate IS NULL THEN '-infinity'::timestamp ELSE 'infinity'::timestamp END ASC, w.startdate DESC, w.enddate DESC, w.id DESC"; $sql .= ' LIMIT :limit OFFSET :offset'; $typeIds = []; foreach ($filters['types'] as $type) { $typeIds[] = $type->getId(); } $nq = $this->em->createNativeQuery($sql, $rsm) ->setParameter('periodId', $period->getId(), Types::INTEGER) ->setParameter('types', $typeIds) ->setParameter('after', $after) ->setParameter('before', $before) ->setParameter('limit', $limit, Types::INTEGER) ->setParameter('offset', $offset, Types::INTEGER); foreach ($filters['user'] as $key => $user) { $nq->setParameter('user_'.$key, $user); } return $nq->getResult(); } /** * Return a list of types of social actions associated to the accompanying period. * * @return array */ public function findActionTypeByPeriod(AccompanyingPeriod $period): array { $in = $this->em->createQueryBuilder(); $in ->select('1') ->from(AccompanyingPeriodWork::class, 'apw'); $in->andWhere('apw.accompanyingPeriod = :period')->setParameter('period', $period); // join between the embedded exist query and the main query $in->andWhere('apw.socialAction = sa'); $qb = $this->em->createQueryBuilder()->setParameters($in->getParameters()); $qb ->select('sa') ->from(SocialAction::class, 'sa') ->where( $qb->expr()->exists($in->getDQL()) ); return $qb->getQuery()->getResult(); } public function findNearEndDateByUser(User $user, \DateTimeImmutable $since, \DateTimeImmutable $until, int $limit = 20, int $offset = 0): array { return $this->buildQueryNearEndDateByUser($user, $since, $until) ->select('w') ->setFirstResult($offset) ->setMaxResults($limit) ->getQuery() ->getResult(); } public function findOneBy(array $criteria): ?AccompanyingPeriodWork { return $this->repository->findOneBy($criteria); } public function getClassName() { return AccompanyingPeriodWork::class; } private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder { $actions = $action->getDescendantsWithThis(); $qb = $this->repository->createQueryBuilder('g'); $orx = $qb->expr()->orX(); $i = 0; foreach ($actions as $a) { $orx->add(":action_{$i} MEMBER OF g.socialActions"); $qb->setParameter("action_{$i}", $a); } $qb->where($orx); return $qb; } private function buildQueryNearEndDateByUser(User $user, \DateTimeImmutable $since, \DateTimeImmutable $until): QueryBuilder { $qb = $this->repository->createQueryBuilder('w'); $qb ->join('w.accompanyingPeriod', 'period') ->where( $qb->expr()->andX( $qb->expr()->gte('w.endDate', ':since'), $qb->expr()->lte('w.startDate', ':until'), $qb->expr()->orX( $qb->expr()->eq('period.user', ':user'), $qb->expr()->exists( 'SELECT 1 FROM '.AccompanyingPeriodWork::class.' subw JOIN subw.referrersHistory subw_ref_history WHERE subw.id = w.id AND subw_ref_history.user = :user and subw.ref_history.endDate IS NULL' ) ) ) ) ->setParameters([ 'user' => $user, 'since' => $since, 'until' => $until, ]); return $qb; } }