Commit 5c77b6a6 authored by i.vasilenko@iq-adv.ru's avatar i.vasilenko@iq-adv.ru
Browse files

Merge branch 'criteria' into 'main'

add criteria

See merge request !13
parents b9f46ef4 ff24ab56
Loading
Loading
Loading
Loading
+31 −1
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@ namespace App\Messenger\Handler;
use App\Entity\Quest;
use App\Messenger\Message\QuestMessage;
use App\Messenger\Objects\QuestsEnd;
use DateInterval;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\MessageBusInterface;
@@ -29,7 +31,7 @@ class QuestEndMessageHandler
     */
    public function __invoke(QuestsEnd $message): void
    {
        $quests = $this->doctrine->getRepository(Quest::class)->getEndQuests();
        $quests = $this->doctrine->getRepository(Quest::class)->getByCriteria($this->getCriteria());

        foreach ($quests as $quest) {
            $appointments = $quest->getAppointments();
@@ -59,4 +61,32 @@ class QuestEndMessageHandler
            }
        }
    }

    /**
     * Фильтр квестов
     *
     * @return Criteria
     */
    public function getCriteria(): Criteria
    {
        $criteria = Criteria::create();
        $expr = Criteria::expr();

        if (!$expr) {
            return $criteria;
        }

        $startDate = new \DateTime();
        $startDate->setTime(0,0);
        $startDate->sub(new DateInterval('P1D'));
        $endDate = new \DateTime();
        $endDate->setTime(23,59, 59);
        $endDate->sub(new DateInterval('P1D'));

        $criteria
            ->andWhere($expr->gte('date', $startDate))
            ->andWhere($expr->lte('date', $endDate));

        return $criteria;
    }
}
 No newline at end of file
+31 −1
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@ namespace App\Messenger\Handler;
use App\Entity\Quest;
use App\Messenger\Message\QuestMessage;
use App\Messenger\Objects\QuestsStart;
use DateInterval;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\MessageBusInterface;
@@ -29,7 +31,7 @@ class QuestStartMessageHandler
     */
    public function __invoke(QuestsStart $message): void
    {
        $quests = $this->doctrine->getRepository(Quest::class)->getStartQuests();
        $quests = $this->doctrine->getRepository(Quest::class)->getByCriteria($this->getCriteria());

        foreach ($quests as $quest) {
            $appointments = $quest->getAppointments();
@@ -59,4 +61,32 @@ class QuestStartMessageHandler
            }
        }
    }

    /**
     * Фильтр квестов
     *
     * @return Criteria
     */
    public function getCriteria(): Criteria
    {
        $criteria = Criteria::create();
        $expr = Criteria::expr();

        if (!$expr) {
            return $criteria;
        }

        $startDate = new \DateTime();
        $startDate->setTime(0,0);
        $startDate->add(new DateInterval('P3D'));
        $endDate = new \DateTime();
        $endDate->setTime(23,59, 59);
        $endDate->add(new DateInterval('P3D'));

        $criteria
            ->andWhere($expr->gte('date', $startDate))
            ->andWhere($expr->lte('date', $endDate));

        return $criteria;
    }
}
 No newline at end of file
+88 −93
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@ use App\Service\Dto\Classes\FilterDto;
use App\Service\Response\Classes\Data\Pagination;
use DateInterval;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Doctrine\Persistence\ManagerRegistry;
@@ -17,27 +19,33 @@ use Doctrine\Persistence\ManagerRegistry;
 */
class QuestRepository extends ServiceEntityRepository
{
    public const SORT_TYPES = [
        'По возрастанию' => 'ASC',
        'По убыванию' => 'DESC'
    ];
    public const SORT_FIELDS = [
        'Название' => 'name',
        'Дата проведения' => 'date',
        'Дата финальной записи' => 'final_date'
    ];

    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Quest::class);
    }

    /**
     * Получение всех квестов по фильтру
     *
     * @param int $userId
     *
     * @return array
     */
    public function findAllByFilter(int $userId): array
    {
        $queryBuilder = $this->getFilterQuery($userId);
        return $queryBuilder->getQuery()->getResult();
    }

    /**
     * Получение всех квестов по фильтру постранично
     *
     * @param int $userId
     * @param int $page
     * @param int $limit
     *
     * @return Pagination
     */
    public function findAllByFilterPaged(int $userId, int $page = 1, int $limit = 10): Pagination
    {
        $queryBuilder = $this->getFilterQuery($userId);
@@ -53,6 +61,7 @@ class QuestRepository extends ServiceEntityRepository
        if ($page > $maxPage) {
            $page = (int)$maxPage;
        }
        if ($page > 0) {
            $result->page = $page;
            $result->maxPage = $maxPage;
            $result->limit = $limit;
@@ -60,30 +69,55 @@ class QuestRepository extends ServiceEntityRepository
            $paginator->getQuery()
                ->setFirstResult(($page - 1) * $limit)
                ->setMaxResults($limit);
        }

        $result->quests = $paginator->getQuery()->getResult();

        return $result;
    }

    /**
     * Получение пройденных квестов
     *
     * @param int $userId
     *
     * @return array
     *
     * @throws QueryException
     */
    public function findCompletedByFilter(int $userId): array
    {
        $queryBuilder = $this->getFilterQuery($userId);
        $queryBuilder = $this->getBaseQuery();

        $criteria = Criteria::create();
        $expr = Criteria::expr();

        if (!$expr) {
            return [];
        }

        $currentDate = new \DateTime();
        $queryBuilder->setParameter('current', $currentDate)
            ->andWhere('q.date < :current');
        $criteria
            ->andWhere($expr->lt('date', $currentDate))
            ->andWhere($expr->eq('appointments.related_user', $userId));

        $queryBuilder->setParameter('user_id', $userId)
            ->leftJoin('q.appointments', 'appointments')
            ->andWhere('appointments.related_user = :user_id');
        $queryBuilder->addCriteria($criteria);

        return $queryBuilder->getQuery()->getResult();
    }

    /**
     * Получение квеста
     *
     * @param int $id
     * @param int $userId
     * @param bool $cache
     *
     * @return Quest|null
     */
    public function findOneById(int $id, int $userId, bool $cache = true): ?Quest
    {
        $queryBuilder = $this->getBaseQuery($userId);
        $queryBuilder = $this->getBaseQuery();
        $queryBuilder->setParameter('detail_id', $id)
            ->andWhere('q.id = :detail_id');
        $query = $queryBuilder->getQuery();
@@ -93,87 +127,48 @@ class QuestRepository extends ServiceEntityRepository
        return $query->getOneOrNullResult();
    }

    private function getBaseQuery(int $userId): QueryBuilder
    /**
     * Получение квестов по критерии
     *
     * @param Criteria $criteria
     *
     * @return array
     */
    public function getByCriteria(Criteria $criteria): array
    {
        return $this->createQueryBuilder('q');
        return $this->getQueryByCriteria($criteria)->getQuery()->getResult();
    }

    private function getFilterQuery(int $userId): QueryBuilder
    private function getBaseQuery(): QueryBuilder
    {
        $queryBuilder = $this->getBaseQuery($userId);

        $redisFilter = new RedisFilter($userId);
        $filter = $redisFilter->get();
        if ($filter instanceof FilterDto) {
            if (!empty($filter->search)) {
                $text = $filter->search;
                $queryBuilder->setParameter('search', "%$text%")
                    ->orWhere('q.name LIKE :search')
                    ->orWhere('q.short_description LIKE :search')
                    ->orWhere('q.full_description LIKE :search');
            }
            if ($genres = $filter->genres) {
                $queryBuilder->setParameter('genres', $genres)
        return $this->createQueryBuilder('q')
            ->leftJoin('q.genre', 'genre')
                    ->andWhere('genre.name IN (:genres)');
            }
            if ($themes = $filter->themes) {
                $queryBuilder->setParameter('themes', $themes)
            ->leftJoin('q.theme', 'theme')
                    ->andWhere('theme.name IN (:themes)');
            }
            if ($tags = $filter->tags) {
                $queryBuilder->setParameter('tags', $tags)
            ->leftJoin('q.tags', 'tags')
                    ->andWhere('tags.name IN (:tags)');
            }
            if ($filter->sort
                && $filter->sortField
                && in_array($filter->sort, self::SORT_TYPES, true)
                && in_array($filter->sortField, self::SORT_FIELDS, true)
            ) {
                $queryBuilder->orderBy('q.'.$filter->sortField, $filter->sort);
            }
        }
        return $queryBuilder;
            ->leftJoin('q.appointments', 'appointments')
            ->leftJoin('q.reviews', 'reviews');
    }

    public function getStartQuests(): array
    private function getQueryByCriteria(Criteria $criteria): QueryBuilder
    {
        $queryBuilder = $this->createQueryBuilder('q');

        $startDate = new \DateTime();
        $startDate->setTime(0,0);
        $startDate->add(new DateInterval('P3D'));
        $endDate = new \DateTime();
        $endDate->setTime(23,59, 59);
        $endDate->add(new DateInterval('P3D'));
        $queryBuilder = $this->getBaseQuery();

        $queryBuilder->setParameter('start', $startDate)
            ->setParameter('end', $endDate)
            ->andWhere('q.date >= :start')
            ->andWhere('q.date <= :end');
        $queryBuilder->addCriteria($criteria);

        return $queryBuilder->getQuery()->getResult();
        return $queryBuilder;
    }

    public function getEndQuests(): array
    private function getFilterQuery(int $userId): QueryBuilder
    {
        $queryBuilder = $this->createQueryBuilder('q');

        $startDate = new \DateTime();
        $startDate->setTime(0,0);
        $startDate->sub(new DateInterval('P1D'));
        $endDate = new \DateTime();
        $endDate->setTime(23,59, 59);
        $endDate->sub(new DateInterval('P1D'));

        $queryBuilder->setParameter('start', $startDate)
            ->setParameter('end', $endDate)
            ->andWhere('q.date >= :start')
            ->andWhere('q.date <= :end');

        return $queryBuilder->getQuery()->getResult();
        $redisFilter = new RedisFilter($userId);
        $filter = $redisFilter->get();
        if ($filter instanceof FilterDto) {
            $criteria = $filter->getCriteria();
            $queryBuilder = $this->getQueryByCriteria($criteria);
        } else {
            $queryBuilder = $this->getBaseQuery();
        }
        return $queryBuilder;
    }

    //    /**
+51 −0
Original line number Diff line number Diff line
@@ -3,12 +3,23 @@
namespace App\Service\Dto\Classes;

use App\Service\Dto\BaseDto;
use Doctrine\Common\Collections\Criteria;
use Symfony\Component\DependencyInjection\Attribute\AsAlias;
use Symfony\Component\Serializer\Annotation\Groups;

#[AsAlias(id: 'dto.filter', public: true)]
class FilterDto extends BaseDto
{
    public const SORT_TYPES = [
        'По возрастанию' => 'ASC',
        'По убыванию' => 'DESC'
    ];
    public const SORT_FIELDS = [
        'Название' => 'name',
        'Дата проведения' => 'date',
        'Дата финальной записи' => 'final_date'
    ];

    /**
     * @var string|null
     */
@@ -44,4 +55,44 @@ class FilterDto extends BaseDto
     */
    #[Groups(['data'])]
    public array $themes;

    /**
     * Получение фильтра ORM
     *
     * @return Criteria
     */
    public function getCriteria(): Criteria
    {
        $criteria = Criteria::create();
        $expr = Criteria::expr();

        if (!$expr) {
            return $criteria;
        }

        if (!empty($this->search)) {
            $text = $this->search;
            $criteria->orWhere($expr->contains('name', $text))
            ->orWhere($expr->contains('short_description', $text))
            ->orWhere($expr->contains('full_description', $text));
        }
        if ($genres = $this->genres) {
            $criteria->andWhere($expr->in('genre.name', $genres));
        }
        if ($themes = $this->themes) {
            $criteria->andWhere($expr->in('theme.name', $themes));
        }
        if ($tags = $this->tags) {
            $criteria->andWhere($expr->in('tags.name', $tags));
        }
        if ($this->sort
            && $this->sortField
            && in_array($this->sort, self::SORT_TYPES, true)
            && in_array($this->sortField, self::SORT_FIELDS, true)
        ) {
            $criteria->orderBy([$this->sortField => $this->sort]);
        }

        return $criteria;
    }
}
 No newline at end of file
+3 −3
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ namespace App\Service\Response\Classes\Data;
use App\Entity\Genre;
use App\Entity\Tag;
use App\Entity\Theme;
use App\Repository\QuestRepository;
use App\Service\Dto\Classes\FilterDto;
use Symfony\Component\Serializer\Annotation\Groups;

class Filter
@@ -32,11 +32,11 @@ class Filter
     * @var string[]
     */
    #[Groups(['filter'])]
    public array $sortFields = QuestRepository::SORT_FIELDS;
    public array $sortFields = FilterDto::SORT_FIELDS;

    /**
     * @var string[]
     */
    #[Groups(['filter'])]
    public array $sorts = QuestRepository::SORT_TYPES;
    public array $sorts = FilterDto::SORT_TYPES;
}
 No newline at end of file