Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • i.vasilenko/symfony-trainee
1 result
Show changes
Commits on Source (2)
......@@ -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
......@@ -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
......@@ -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,37 +61,63 @@ class QuestRepository extends ServiceEntityRepository
if ($page > $maxPage) {
$page = (int)$maxPage;
}
$result->page = $page;
$result->maxPage = $maxPage;
$result->limit = $limit;
$paginator->getQuery()
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit);
if ($page > 0) {
$result->page = $page;
$result->maxPage = $maxPage;
$result->limit = $limit;
$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)
->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;
return $this->createQueryBuilder('q')
->leftJoin('q.genre', 'genre')
->leftJoin('q.theme', 'theme')
->leftJoin('q.tags', 'tags')
->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;
}
// /**
......
......@@ -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
......@@ -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