<?php
namespace App\Repository\App;
use App\Entity\Notification;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Notification|null find($id, $lockMode = null, $lockVersion = null)
* @method Notification|null findOneBy(array $criteria, array $orderBy = null)
* @method Notification[] findAll()
* @method Notification[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class NotificationRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Notification::class);
}
public function findActiveNotificationsByUser(User $user, bool $unreadOnly = false)
{
$qb = $this->createQueryBuilder('n');
$qb = $this->_joinStatisticsTable($qb);
$qb->select('n', 's');
$qb = $this->_filterOngoingPublishedNotificationsByUser($qb, $user->getCustomerNumber());
if ($unreadOnly === true) {
$qb = $this->_filterOnlyUnreadNotification($qb);
}
return $qb
->orderBy('n.createdAt', 'DESC')
->getQuery()
->getResult();
}
private function _joinStatisticsTable(QueryBuilder $qb): QueryBuilder
{
return $qb->join('n.notificationStatistics', 's');
}
private function _filterOngoingPublishedNotificationsByUser(QueryBuilder $qb, $customerNumber): QueryBuilder
{
$qb = $this->_filterNotificationByCustomerNumber($qb, $customerNumber);
$qb = $this->_filterNotificationByStartAndEndAt($qb);
$qb = $this->_filterNotificationWhereUserIsActivated($qb);
$qb = $this->_filterPublishedNotification($qb);
return $qb;
}
private function _filterNotificationByCustomerNumber(QueryBuilder $qb, $customerNumber): QueryBuilder
{
return $qb
->andWhere('s.customerNumber = :customer')
->setParameter('customer', $customerNumber);
}
private function _filterNotificationByStartAndEndAt(QueryBuilder $qb): QueryBuilder
{
return $qb
->andWhere('n.startAt <= :now')
->andWhere('n.endAt > :now')
->setParameter('now', new \DateTime());
}
private function _filterNotificationWhereUserIsActivated(QueryBuilder $qb): QueryBuilder
{
return $qb
->andWhere('s.desactivatedDate is NULL')
->setParameter('now', new \DateTime());
}
private function _filterPublishedNotification(QueryBuilder $qb): QueryBuilder
{
return $qb
->andWhere('n.published = true');
}
private function _filterOnlyUnreadNotification(QueryBuilder $qb): QueryBuilder
{
return $qb->andWhere($qb->expr()->orX(
$qb->expr()->isNull('s.lastSeenDate'),
$qb->expr()->eq('s.readLater', 1)
));
}
public function findPopUpNotificationsByUser(User $user, array $seenPopUps)
{
$qb = $this->createQueryBuilder('n');
$qb = $this->_joinStatisticsTable($qb);
$qb->select('n', 's');
$qb = $this->_filterOngoingPublishedNotificationsByUser($qb, $user->getCustomerNumber());
$qb = $this->_filterNotAnsweredOnlyNotification($qb);
$qb = $this->_filterPopUpNotification($qb);
$qb = $this->_filterPopUpNotificationFromSeenArray($qb, $seenPopUps);
$qb = $this->_filterPopUpNotificationWhereCountReadIsNotReached($qb);
return $qb->getQuery()->getResult();
}
private function _filterNotAnsweredOnlyNotification(QueryBuilder $qb): QueryBuilder
{
return $qb
->andWhere('s.answer is NULL');
}
private function _filterPopUpNotification(QueryBuilder $qb): QueryBuilder
{
return $qb
->andWhere('n.setPopUp = true');
}
private function _filterPopUpNotificationFromSeenArray(QueryBuilder $qb, array $seenPopUps): QueryBuilder
{
// Remove null values from the array (they would trigger a doctrine error)
$filteredSeenPopUps = array_filter($seenPopUps, function($value) { return $value !== null; });
// No seen popups to exclude -> return qb without adding restrictions
if (!$filteredSeenPopUps) {
return $qb;
}
return $qb->andWhere($qb->expr()->notIn('n.id', $filteredSeenPopUps));
}
private function _filterPopUpNotificationWhereCountReadIsNotReached(QueryBuilder $qb): QueryBuilder
{
return $qb
->andWhere($qb->expr()->orX(
$qb->expr()->eq('s.readLater', 1),
$qb->expr()->orX(
$qb->expr()->andX(
$qb->expr()->isNotNull('n.insistenceCoefficient'),
$qb->expr()->gt('n.insistenceCoefficient', 's.countRead')
),
$qb->expr()->andX(
$qb->expr()->isNull('n.insistenceCoefficient'),
$qb->expr()->eq('s.countRead', 0)
),
)
));
}
public function countUnreadByUser(User $user)
{
$qb = $this->createQueryBuilder('n');
$qb = $this->_joinStatisticsTable($qb);
$qb->select('count(s.id)');
$qb = $this->_filterOngoingPublishedNotificationsByUser($qb, $user->getCustomerNumber());
$qb = $this->_filterOnlyUnreadNotification($qb);
return $qb
->getQuery()
->getSingleScalarResult();
}
/**
* @param User $user
* @param string[] $notifications Ids of the notifications to exclude from the query
* @return mixed
*/
public function findUnreadByUserWithoutGivenArray(User $user, array $notifications = [])
{
$qb = $this->createQueryBuilder('n');
$qb = $this->_joinStatisticsTable($qb);
$qb->select('n.id, n.messageName');
// Remove null values from the array (they would trigger a doctrine error)
$filteredNotifications = array_filter($notifications, function($value) { return $value !== null; });
if ($filteredNotifications) {
$qb->andWhere($qb->expr()->notIn('n.id', $filteredNotifications));
}
$qb = $this->_filterOngoingPublishedNotificationsByUser($qb, $user->getCustomerNumber());
$qb = $this->_filterOnlyUnreadNotification($qb);
return $qb
->getQuery()
->getResult();
}
public function findNewWithEmail()
{
$qb = $this->createQueryBuilder('n');
$qb = $qb->where('n.startAt = :todayStart')
->andWhere('n.sendEmail = true')
->setParameter('todayStart', new \DateTime('today'));
$qb = $this->_filterPublishedNotification($qb);
return $qb
->getQuery()
->getResult();
}
}