<?php
namespace App\Repository;
use App\Entity\Booking;
use App\Entity\Offer;
use App\Services\Utils;
use DateInterval;
use DatePeriod;
use DateTime;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\DBAL\Exception;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Query;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Offer|null find($id, $lockMode = null, $lockVersion = null)
* @method Offer|null findOneBy(array $criteria, array $orderBy = null)
* @method Offer[] findAll()
* @method Offer[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class OfferRepository extends ServiceEntityRepository
{
private Utils $utils;
public function __construct(ManagerRegistry $registry, Utils $utils)
{
$this->utils = $utils;
parent::__construct($registry, Offer::class);
}
/**
* @param Offer $entity
* @param bool $flush
* @return void
*/
public function add(Offer $entity, bool $flush = true): void
{
$this->_em->persist($entity);
if ($flush) {
$this->_em->flush();
}
}
/**
* @param Offer $entity
* @param bool $flush
* @return void
*/
public function remove(Offer $entity, bool $flush = true): void
{
$this->_em->remove($entity);
if ($flush) {
$this->_em->flush();
}
}
public function englishDateToFrenchDate(DateTime $date) : string
{
$englishDay = $date->format('D');
switch($englishDay) {
case 'Mon':
$frenchDay = 'lundi';
break;
case 'Tue':
$frenchDay = 'mardi';
break;
case 'Wed':
$frenchDay = 'mercredi';
break;
case 'Thu':
$frenchDay = 'jeudi';
break;
case 'Fri':
$frenchDay = 'vendredi';
break;
case 'Sat':
$frenchDay = 'samedi';
break;
case 'Sun':
$frenchDay = 'dimanche';
break;
default:
$frenchDay = 'Jour inconnu';
}
return $frenchDay;
}
/**
* @param array|null $params
* @return Query
* @throws \Exception
*/
public function search(?array $params)
{
$qb = $this->createQueryBuilder('o')
->leftJoin('o.territory','t')
->leftJoin('o.weapons','w')
//->innerJoin('o.gibiers','og')
->andWhere('o.status IN (:status)')
->setParameter('status', [Offer::STATUS_ACTIVE, Offer::STATUS_FINISHED]);
if(isset($params['huntingMode']) && count($params['huntingMode']) > 0) {
$ids = [];
foreach($params['huntingMode'] as $mode) {
$ids[] = $mode->getId();
}
$qb->join('o.huntingMode', 'a');
$qb->andWhere('a.id IN (:mode)');
$qb->setParameter('mode',$ids);
}
if(isset($params['type']) && count($params['type']) > 0) {
$qb->andWhere('o.type IN (:type)');
$qb->setParameter('type', $params['type']);
}
if(isset($params['dates']) && !is_null($params['dates']) && $params['dates'] != '') {
$dates = explode('-',$params['dates']);
$dates[0] = str_replace(" ", "", $dates[0]);
$dates[1] = str_replace(" ", "", $dates[1]);
if ($dates[0] !== $dates[1]) {
$period = new DatePeriod(
DateTime::createFromFormat('d/m/Y', $dates[0])->modify('midnight'),
new DateInterval('P1D'),
DateTime::createFromFormat('d/m/Y', $dates[1])->modify('midnight')
);
$datesQuery = '';
$i = 0;
foreach ($period as $date) {
$datesQuery .= 'JSON_CONTAINS(o.disponibilities, :date'.$i.') = 1';
$datesQuery .= ' OR o.startAt = :date'.$i.' OR o.endAt = :date'.$i.' OR ';
$qb->setParameter('date'.$i, '{"date":"'.$date->format('d/m/Y').'"}');
$i++;
}
$datesQuery = mb_substr($datesQuery, 0, -3);
if($dates[0] != $dates[1]) {
$qb->andWhere('(o.startAt <= :startAt AND o.endAt >= :endAt) OR (o.startAt >= :startAt AND o.endAt <= :endAt) OR (' . $datesQuery . ')');
$qb->setParameter('startAt',DateTime::createFromFormat('d/m/Y', $dates[0])->modify('midnight'));
$qb->setParameter('endAt', DateTime::createFromFormat('d/m/Y', $dates[1])->modify('midnight'));
}
} else {
$datetime = DateTime::createFromFormat('d/m/Y', $dates[0])->modify('midnight');
$datesQuery = 'JSON_CONTAINS(o.disponibilities, :dateContains) = 1';
$datesExceptionsQuery = 'JSON_CONTAINS(o.recurrenceException, :dateContains) = 0';
$qb->andWhere('(o.startAt <= :date AND o.endAt >= :date AND o.recurrence LIKE :dateDay' . ' AND ' . $datesExceptionsQuery . ') OR (' . $datesQuery . ')');
$qb->setParameter('dateContains', '{"date":"'.$dates[0].'"}');
$qb->setParameter('date', $datetime);
$qb->setParameter('dateDay', '%"'.$this->englishDateToFrenchDate($datetime).'"%');
}
}
if(isset($params['startDate']) && !is_null($params['startDate']) && $params['startDate'] != '') {
$qb->andWhere('o.startAt >= :startAt');
$qb->setParameter('startAt', $params['startDate']);
}
if(isset($params['endDate']) && !is_null($params['endDate']) && $params['endDate'] != '') {
$qb->andWhere('o.endAt >= :endAt');
$qb->setParameter('endAt', $params['endDate']);
}
if(isset($params['animals']) && count($params['animals']) > 0) {
$ids = [];
foreach($params['animals'] as $animal) {
$ids[] = $animal->getId();
}
$qb->andWhere($qb->expr()->isMemberOf(':animals', 'o.animals'))
->setParameter(':animals', $ids);
}
if(isset($params['departement']) && count($params['departement']) > 0) {
$departements = $params['departement'];
$qb->andWhere('t.department IN (:departments)');
$qb->setParameter('departments', $departements);
}
if(isset($params['region']) && count($params['region']) > 0) {
$regions = [];
foreach ($params['region'] as $region)
$regions[] = $this->utils->slugify(Utils::sRegionList()[$region]);
$qb->andWhere('t.region IN (:regions)');
$qb->setParameter('regions', $regions);
}
if(isset($params['gibier']) && count($params['gibier']) > 0) {
// $qb->andWhere('og.title IN (:gibiers)');
// $qb->setParameter('gibiers', $params['gibier']);
$gibiersIds = [];
foreach($params['gibier'] as $gibier) {
$gibiersIds[] = $gibier->getId();
}
$qb->andWhere($qb->expr()->isMemberOf(':gibiers', 'o.gibiers'))
->setParameter(':gibiers', $gibiersIds);
}
if(isset($params['weapons']) && count($params['weapons']) > 0) {
$ids = [];
foreach($params['weapons'] as $weapon) {
$ids[] = $weapon->getId();
}
$qb->andWhere($qb->expr()->isMemberOf(':weapons', 'o.weapons'))
->setParameter(':weapons', $ids);
}
if(isset($params['priceMin'])) {
$qb->andWhere('o.price >= :priceMin');
$qb->setParameter('priceMin', $params['priceMin']);
}
if(isset($params['priceMax'])) {
$qb->andWhere('o.price <= :priceMax');
$qb->setParameter('priceMax', $params['priceMax']);
}
if(isset($params['orderSort']) && isset($params['orderBy'])) {
$qb->addOrderBy('o.'.$params['orderBy'], $params['orderSort']);
} else {
$qb->addOrderBy('o.id', 'DESC')
->addOrderBy('o.isTuchassouSelected', 'DESC');
}
$qb->addGroupBy('o.id');
return $qb->getQuery()->getResult();
}
/**
* @return float|int|mixed|string|null
* @throws NonUniqueResultException
*/
public function getPriceBornes()
{
$query = $this->createQueryBuilder('o');
$query->select('MAX(o.price) AS maxPrice, MIN(o.price) AS minPrice');
$query->where('o.status = true');
$query->setMaxResults(1);
return $query->getQuery()->getOneOrNullResult();
}
/**
* @param int|null $userId
* @return float|int|mixed|string
*/
public function getHoteOffers(?int $userId)
{
$query = $this->createQueryBuilder('o');
$query->where('o.status != :status')
->setParameter('status', Offer::STATUS_DELETED)
->andWhere('o.createdBy = :userId')
->setParameter('userId', $userId)
;
return $query->getQuery()->getResult();
}
/**
* @param Offer $offer
* @param int $radius
* @return float|int|mixed|string
*/
public function getOffersByDistance(Offer $offer, int $radius)
{
$lat = $offer->getTerritory()->getLatitude();
$long = $offer->getTerritory()->getLongitude();
$type = $offer->getType();
$id = $offer->getId();
$q = $this->createQueryBuilder('o')
->select("o, (3959 * acos(cos(radians('".$lat."')) * cos(radians(t.latitude)) * cos(radians(t.longitude) - radians('".$long."')) + sin(radians('".$lat."')) * sin(radians(t.latitude)))) AS distance")
->innerJoin('o.territory', 't')
;
$q->where('o.id != :id')->setParameter('id', $id);
if($type && $type != '') {
$q->andWhere('o.type = :type')->setParameter('type', $type);
}
$q->having("distance <= :distance")->setParameter('distance', $radius)
->orderBy("distance", "ASC");
return $q->getQuery()->getResult();
}
/**
* @return array|null
*/
public function getMostBookedOffers($request = null): ?array
{
/*$conn = $this->getEntityManager()->getConnection();
$sql = "SELECT o.id , o.title , SUM(b.total_ttc) , COUNT(b.user_id)
FROM booking b
LEFT JOIN offer o ON b.offer_id = o.id
WHERE b.status = :status
GROUP BY offer_id
ORDER BY COUNT(b.user_id) DESC , SUM(b.total_ttc) DESC";
$stmt = $conn->prepare($sql);
$resultSet = $stmt->executeQuery(['status' => 'in_progress']);
$most_booked_offers = [];
foreach ($resultSet->fetchAllAssociative() as $item) {
$most_booked_offers[] = array_values($item);
}
return $most_booked_offers;*/
$query = $this->createQueryBuilder('o');
$query->select('o.id, o.title, SUM(b.totalTtc) AS totalTtc, COUNT(b.id) AS totalBookings')
->leftJoin('o.bookings', 'b')
->where('b.status = :status')
->setParameter('status', Booking::STATUS_ACCEPTED)
//->addOrderBy('totalTtc', 'DESC')
;
if (isset($request['startDate'])) {
$query->andWhere('b.createdAt >= :startDate')
->setParameter('startDate', $request['startDate'])
;
}
if (isset($request['endDate'])) {
$query->andWhere('b.createdAt <= :endDate')
->setParameter('endDate', $request['endDate'])
;
}
if (isset($request['departement'])) {
$query->join('o.territory', 't')
->andWhere('t.department = :department')
->setParameter('department', $request['departement']);
}
if (isset($request['type'])) {
$query->andWhere('o.type = :type')
->setParameter('type', $request['type']);
}
$query->groupBy('o.id')
->orderBy('totalBookings', 'DESC');
return $query->setMaxResults(5)->getQuery()->getResult();
}
public function findOffersDashboard($request = null) {
$qb = $this->createQueryBuilder('o');
if ($request['startDate']) {
$qb->andWhere('o.createdAt >= :startDate')
->setParameter('startDate', $request['startDate']);
}
if ($request['endDate']) {
$qb->andWhere('o.createdAt <= :endDate')
->setParameter('endDate', $request['endDate']);
}
if ($request['departement']) {
$qb->join('o.territory', 't')
->andWhere('t.department = :department')
->setParameter('department', $request['departement']);
}
if ($request['typeOffer']) {
$qb->andWhere('o.type = :type')
->setParameter('type', $request['typeOffer']);
}
return $qb->getQuery()->getResult();
}
}