repository = $em->getRepository(Notification::class); } public function countAllForAttendee(User $addressee): int { return $this->queryByAddressee($addressee) ->select('count(n)') ->getQuery() ->getSingleScalarResult(); } public function countAllForSender(User $sender): int { return $this->queryBySender($sender) ->select('count(n)') ->getQuery() ->getSingleScalarResult(); } /** * @param list $more * @return array{unread: int, sent: int, total: int} */ public function countNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user, array $more = []): array { $sqlParams = ['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId, 'userid' => $user->getId()]; if ([] === $more) { if (null === $this->notificationByRelatedEntityAndUserAssociatedStatement) { $sql = self::BASE_COUNTER_SQL . ' WHERE relatedentityclass = :relatedEntityClass AND relatedentityid = :relatedEntityId AND sender_id IS NOT NULL'; $this->notificationByRelatedEntityAndUserAssociatedStatement = $this->em->getConnection()->prepare($sql); } $results = $this->notificationByRelatedEntityAndUserAssociatedStatement ->executeQuery($sqlParams); $result = $results->fetchAssociative(); $results->free(); } else { $wheres = []; foreach ([ ['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId], ...$more ] as $k => ['relatedEntityClass' => $relClass, 'relatedEntityId' => $relId]) { $wheres[] = "(relatedEntityClass = :relatedEntityClass_{$k} AND relatedEntityId = :relatedEntityId_{$k})"; $sqlParams["relatedEntityClass_{$k}"] = $relClass; $sqlParams["relatedEntityId_{$k}"] = $relId; } $sql = self::BASE_COUNTER_SQL . ' WHERE sender_id IS NOT NULL AND (' . implode(' OR ', $wheres) . ')'; $result = $this->em->getConnection()->fetchAssociative($sql, $sqlParams); } return array_map(fn (?int $number) => $number ?? 0, $result); } public function countUnreadByUser(User $user): int { $sql = 'SELECT count(*) AS c FROM chill_main_notification_addresses_unread WHERE user_id = :userId'; $rsm = new Query\ResultSetMapping(); $rsm->addScalarResult('c', 'c', Types::INTEGER); $nq = $this->em->createNativeQuery($sql, $rsm) ->setParameter('userId', $user->getId()); return $nq->getSingleScalarResult(); } public function countUnreadByUserWhereAddressee(User $user): int { $qb = $this->repository->createQueryBuilder('n'); $qb ->select('count(n)') ->where($qb->expr()->isMemberOf(':user', 'n.addressees')) ->andWhere($qb->expr()->isMemberOf(':user', 'n.unreadBy')) ->setParameter('user', $user); return $qb->getQuery()->getSingleScalarResult(); } public function countUnreadByUserWhereSender(User $user): int { $qb = $this->repository->createQueryBuilder('n'); $qb ->select('count(n)') ->where($qb->expr()->eq('n.sender', ':user')) ->andWhere($qb->expr()->isMemberOf(':user', 'n.unreadBy')) ->setParameter('user', $user); return $qb->getQuery()->getSingleScalarResult(); } public function find($id, $lockMode = null, $lockVersion = null): ?Notification { return $this->repository->find($id, $lockMode, $lockVersion); } /** * @return Notification[] */ public function findAll(): array { return $this->repository->findAll(); } /** * @param mixed|null $limit * @param mixed|null $offset * * @return Notification[] */ public function findAllForAttendee(User $addressee, $limit = null, $offset = null): array { $query = $this->queryByAddressee($addressee)->select('n'); if ($limit) { $query = $query->setMaxResults($limit); } if ($offset) { $query = $query->setFirstResult($offset); } $query->addOrderBy('n.date', 'DESC'); return $query->getQuery()->getResult(); } public function findAllForSender(User $sender, $limit = null, $offset = null): array { $query = $this->queryBySender($sender)->select('n'); if ($limit) { $query = $query->setMaxResults($limit); } if ($offset) { $query = $query->setFirstResult($offset); } $query->addOrderBy('n.date', 'DESC'); return $query->getQuery()->getResult(); } /** * @param int|null $limit * @param int|null $offset * * @return Notification[] */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } /** * @param list $more * @return array|Notification[] */ public function findNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user, array $more): array { return $this->buildQueryNotificationByRelatedEntityAndUserAssociated($relatedEntityClass, $relatedEntityId, $user, $more) ->select('n') ->addOrderBy('n.date', 'DESC') ->getQuery() ->getResult(); } public function findOneBy(array $criteria, ?array $orderBy = null): ?Notification { return $this->repository->findOneBy($criteria, $orderBy); } /** * @return array|Notification[] */ public function findUnreadByUser(User $user, int $limit = 20, int $offset = 0): array { $rsm = new Query\ResultSetMappingBuilder($this->em); $rsm->addRootEntityFromClassMetadata(Notification::class, 'cmn'); $sql = 'SELECT ' . $rsm->generateSelectClause(['cmn' => 'cmn']) . ' ' . 'FROM chill_main_notification cmn ' . 'WHERE ' . 'EXISTS (select 1 FROM chill_main_notification_addresses_unread cmnau WHERE cmnau.user_id = :userId and cmnau.notification_id = cmn.id) ' . 'ORDER BY cmn.date DESC ' . 'LIMIT :limit OFFSET :offset'; $nq = $this->em->createNativeQuery($sql, $rsm) ->setParameter('userId', $user->getId()) ->setParameter('limit', $limit) ->setParameter('offset', $offset); return $nq->getResult(); } public function getClassName() { return Notification::class; } /** * @param list $more */ private function buildQueryNotificationByRelatedEntityAndUserAssociated(string $relatedEntityClass, int $relatedEntityId, User $user, array $more = []): QueryBuilder { $qb = $this->repository->createQueryBuilder('n'); // add condition for related entity (in main arguments, and in more) $or = $qb->expr()->orX($qb->expr()->andX( $qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass'), $qb->expr()->eq('n.relatedEntityId', ':relatedEntityId') )); $qb ->setParameter('relatedEntityClass', $relatedEntityClass) ->setParameter('relatedEntityId', $relatedEntityId); foreach ($more as $k => ['relatedEntityClass' => $relatedClass, 'relatedEntityId' => $relatedId]) { $or->add( $qb->expr()->andX( $qb->expr()->eq('n.relatedEntityClass', ':relatedEntityClass_'.$k), $qb->expr()->eq('n.relatedEntityId', ':relatedEntityId_'.$k) ) ); $qb ->setParameter('relatedEntityClass_'.$k, $relatedClass) ->setParameter('relatedEntityId_'.$k, $relatedId); } $qb ->andWhere($or) ->andWhere($qb->expr()->isNotNull('n.sender')) ->andWhere( $qb->expr()->orX( $qb->expr()->isMemberOf(':user', 'n.addressees'), $qb->expr()->eq('n.sender', ':user') ) ) ->setParameter('user', $user); return $qb; } private function queryByAddressee(User $addressee, bool $countQuery = false): QueryBuilder { $qb = $this->repository->createQueryBuilder('n'); $qb ->where($qb->expr()->isMemberOf(':addressee', 'n.addressees')) ->setParameter('addressee', $addressee); return $qb; } private function queryBySender(User $sender): QueryBuilder { $qb = $this->repository->createQueryBuilder('n'); $qb ->where($qb->expr()->eq('n.sender', ':sender')) ->setParameter('sender', $sender); return $qb; } }