From ee110a9ad822c5d1fcae4a4018333d846bde24e0 Mon Sep 17 00:00:00 2001 From: "a.shamavov" <a.shamavov@iqdev.digital> Date: Fri, 26 Apr 2024 11:57:14 +0500 Subject: [PATCH] =?UTF-8?q?STA-966=20|=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB?= =?UTF-8?q?=D0=B5=D1=80=D1=8B=20=D0=B4=D0=BB=D1=8F=20News=20=D0=B8=20?= =?UTF-8?q?=D0=B4=D1=80=D1=83=D0=B3=D0=B8=D0=B5=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- docker-compose.yaml | 4 +- ...24072545.php => Version20240426064235.php} | 2 +- src/Controller/NewsController.php | 55 +++++++++++ src/Controller/RestaurantController.php | 30 ++++-- src/Entity/News.php | 2 +- src/Entity/NewsCategory.php | 3 + src/Entity/Restaurant.php | 6 +- src/Exception/NewsExceptionEnum.php | 8 ++ src/Exception/RestaurantExceptionEnum.php | 8 ++ src/Mapper/NewsMapper.php | 93 +++++++++++++++++++ src/Mapper/RestaurantMapper.php | 79 ++++++++++++++-- src/Model/NewsCategory.php | 8 +- src/Model/NewsDetailElement.php | 8 +- src/Model/NewsListingElement.php | 8 +- src/Model/RestaurantDetailElement.php | 14 +-- .../NewsCategoryRepositoryInterface.php | 8 ++ .../Interface/NewsRepositoryInterface.php | 13 +++ .../RestaurantRepositoryInterface.php | 4 +- src/Repository/NewsCategoryRepository.php | 31 ++----- src/Repository/NewsRepository.php | 59 +++++++----- src/Repository/RestaurantRepository.php | 6 +- src/Requests/NewsListRequest.php | 28 ++++++ src/Requests/RestaurantListRequest.php | 28 ++++++ src/Service/NewsService.php | 48 ++++++++++ src/Service/RestaurantService.php | 48 +++------- 26 files changed, 471 insertions(+), 134 deletions(-) rename migrations/{Version20240424072545.php => Version20240426064235.php} (99%) create mode 100644 src/Controller/NewsController.php create mode 100644 src/Exception/NewsExceptionEnum.php create mode 100644 src/Exception/RestaurantExceptionEnum.php create mode 100644 src/Mapper/NewsMapper.php create mode 100644 src/Repository/Interface/NewsCategoryRepositoryInterface.php create mode 100644 src/Repository/Interface/NewsRepositoryInterface.php create mode 100644 src/Requests/NewsListRequest.php create mode 100644 src/Requests/RestaurantListRequest.php create mode 100644 src/Service/NewsService.php diff --git a/.gitignore b/.gitignore index 930e1e2..f8810d3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ /public/assets/ /assets/vendor/ ###< symfony/asset-mapper ### -/.idea \ No newline at end of file +/.idea +.env +.env.test \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index b87becc..5548380 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,7 +9,7 @@ services: POSTGRES_PASSWORD: 12345 POSTGRES_HOST_AUTH_METHOD: trust ports: - - "5433:${DATABASE_PORT}" + - "${DATABASE_PORT}:${DATABASE_PORT}" networks: - internal nginx: @@ -33,8 +33,6 @@ services: APP_BASE_DIR: ${APP_BASE_DIR-.} volumes: - ".:/app" - ports: - - "9000:9000" restart: unless-stopped networks: - internal diff --git a/migrations/Version20240424072545.php b/migrations/Version20240426064235.php similarity index 99% rename from migrations/Version20240424072545.php rename to migrations/Version20240426064235.php index b77fac7..9142542 100644 --- a/migrations/Version20240424072545.php +++ b/migrations/Version20240426064235.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240424072545 extends AbstractMigration +final class Version20240426064235 extends AbstractMigration { public function getDescription(): string { diff --git a/src/Controller/NewsController.php b/src/Controller/NewsController.php new file mode 100644 index 0000000..ae4ea9f --- /dev/null +++ b/src/Controller/NewsController.php @@ -0,0 +1,55 @@ +<?php + +declare(strict_types=1); + +namespace App\Controller; + +use App\Requests\NewsListRequest; +use Exception; +use App\Service\NewsService; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Attribute\Route; + +#[Route("/api/v1")] +class NewsController extends AbstractController +{ + public function __construct(private NewsService $newsService) {} + + #[Route('/news', name: 'news', methods: ['GET'])] + public function news(NewsListRequest $request): Response + { + $page = $request->getRequest()->query->get('page'); + $limit = $request->getRequest()->query->get('limit'); + $newsCategory = $request->getRequest()->query->get('news_category'); + $news = $this->newsService->getNews($page, $limit, $newsCategory); + return $this->json($news); + } + + #[Route('/news/mainNews', name: 'mainNews', methods: ['GET'])] + public function mainNews(): Response + { + $mainNews = $this->newsService->getMainNews(); + return $this->json($mainNews); + } + + #[Route('/news/search', name: 'newsSearch', methods: ['GET'])] + public function newsSearch(): Response + { + $newsSearch = $this->newsService->getNewsSearch(); + return $this->json($newsSearch); + } + + #[Route('/news/{newsId}', name: 'newsOne', methods: ['GET'])] + public function newsOne(Request $request): Response + { + try { + $newsId = $request->get('newsId');; + $news = $this->newsService->getNewsOne($newsId); + return $this->json($news); + } catch (Exception $e) { + return new Response($e->getMessage(), $e->getCode()); + } + } +} diff --git a/src/Controller/RestaurantController.php b/src/Controller/RestaurantController.php index 9f665fc..d6f3983 100644 --- a/src/Controller/RestaurantController.php +++ b/src/Controller/RestaurantController.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace App\Controller; +use App\Requests\RestaurantListRequest; +use Exception; use App\Service\RestaurantService; use Nelmio\ApiDocBundle\Annotation\Model; use OpenApi\Attributes as OA; @@ -13,6 +15,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Attribute\Route; use App\Model\RestaurantList; +use Symfony\Component\Serializer\SerializerInterface; #[Route("/api/v1")] class RestaurantController extends AbstractController @@ -46,12 +49,12 @@ class RestaurantController extends AbstractController schema: new Schema(type: "integer") )] #[Model(type: RestaurantList::class)] - public function restaurants(Request $request): Response + public function restaurants(RestaurantListRequest $request): Response { - $page = $request->query->getInt('page'); - $limit = $request->query->getInt('limit'); - $restaurantTypeId = $request->query->getInt('restaurant_type_id'); - $kitchenId = $request->query->getInt('kitchen_id'); + $page = $request->getRequest()->query->get('page'); + $limit = $request->getRequest()->query->get('limit'); + $restaurantTypeId = $request->getRequest()->query->get('restaurant_type_id'); + $kitchenId = $request->getRequest()->query->get('kitchen_id'); $restaurantsList = $this->restaurantService->getRestaurants( $page, $limit, $restaurantTypeId, $kitchenId ); @@ -59,10 +62,19 @@ class RestaurantController extends AbstractController } #[Route('/restaurants/{restaurantId}', name: 'restaurant', methods: ['GET'])] - public function restaurant(Request $request): Response + public function restaurant(Request $request, SerializerInterface $serializer): Response { - $restaurantId = (int)$request->get('restaurantId'); - $restaurant = $this->restaurantService->getRestaurant($restaurantId); - return $this->json($restaurant); + try { + $restaurantId = (int)$request->get('restaurantId'); + $restaurant = $this->restaurantService->getRestaurant($restaurantId); + $json = $serializer->serialize($restaurant, 'json', [ + 'circular_reference_handler' => function ($object) { + return $object->getId(); + } + ]); + return new Response($json, Response::HTTP_OK, ['Content-Type' => 'application/json']); + } catch (Exception $e) { + return new Response($e->getMessage(), $e->getCode()); + } } } diff --git a/src/Entity/News.php b/src/Entity/News.php index 092b75e..3b588b2 100644 --- a/src/Entity/News.php +++ b/src/Entity/News.php @@ -53,7 +53,7 @@ class News /** * @var Collection<int, NewsCategory> */ - #[ORM\ManyToMany(targetEntity: NewsCategory::class)] + #[ORM\ManyToMany(targetEntity: NewsCategory::class, inversedBy: "newsCategories")] private Collection $newsCategories; public function __construct() diff --git a/src/Entity/NewsCategory.php b/src/Entity/NewsCategory.php index 6190e58..fa3a554 100644 --- a/src/Entity/NewsCategory.php +++ b/src/Entity/NewsCategory.php @@ -20,6 +20,9 @@ class NewsCategory #[ORM\Column(length: 255)] private ?string $code = null; + #[ORM\ManyToMany(targetEntity: News::class, mappedBy: 'news')] + private Collection $news; + public function getId(): ?Uuid { return $this->id; diff --git a/src/Entity/Restaurant.php b/src/Entity/Restaurant.php index 02fd3b1..a743f1b 100644 --- a/src/Entity/Restaurant.php +++ b/src/Entity/Restaurant.php @@ -41,11 +41,11 @@ class Restaurant #[ORM\Column(type: Types::ARRAY)] private array $coordinates = []; - #[ORM\ManyToOne(inversedBy: 'restaurants')] + #[ORM\ManyToOne(fetch: 'EAGER', inversedBy: 'restaurants')] #[ORM\JoinColumn(nullable: false)] private ?RestaurantType $typeId = null; - #[ORM\ManyToOne(inversedBy: 'restaurants')] + #[ORM\ManyToOne(fetch: 'EAGER', inversedBy: 'restaurants')] #[ORM\JoinColumn(nullable: false)] private ?Settlement $settlementId = null; @@ -67,7 +67,7 @@ class Restaurant /** * @var Collection<int, Phone> */ - #[ORM\OneToMany(targetEntity: Phone::class, mappedBy: 'restaurant')] + #[ORM\OneToMany(targetEntity: Phone::class, mappedBy: 'restaurant')] private Collection $phone; /** diff --git a/src/Exception/NewsExceptionEnum.php b/src/Exception/NewsExceptionEnum.php new file mode 100644 index 0000000..6535eff --- /dev/null +++ b/src/Exception/NewsExceptionEnum.php @@ -0,0 +1,8 @@ +<?php + +namespace App\Exception; + +enum NewsExceptionEnum: int +{ + case NotFound = 404; +} diff --git a/src/Exception/RestaurantExceptionEnum.php b/src/Exception/RestaurantExceptionEnum.php new file mode 100644 index 0000000..fe3469d --- /dev/null +++ b/src/Exception/RestaurantExceptionEnum.php @@ -0,0 +1,8 @@ +<?php + +namespace App\Exception; + +enum RestaurantExceptionEnum: int +{ + case NotFound = 404; +} diff --git a/src/Mapper/NewsMapper.php b/src/Mapper/NewsMapper.php new file mode 100644 index 0000000..65cf34d --- /dev/null +++ b/src/Mapper/NewsMapper.php @@ -0,0 +1,93 @@ +<?php + +namespace App\Mapper; + +use App\Entity\News; +use App\Entity\NewsCategory; +use App\Model\File; +use App\Model\NewsDetailElement; +use App\Model\NewsFilterVariants; +use App\Model\NewsList; +use App\Model\NewsListingElement; +use App\Model\NewsCategory as NewsCategoryModel; +use App\Model\Pagination; +use Ramsey\Collection\Collection; + +class NewsMapper +{ + public static function mapToNewsList( + $news, + $newsCategory, + $page, + $limit, + $count): NewsList + { + return new NewsList( + new Pagination($page, ceil($count / $limit), $limit), + new Collection(NewsListingElement::class, array_map( + function (News $newsOne) { + return self::mapToListingElement($newsOne); + }, $news) + ), + new NewsFilterVariants( + new Collection(NewsCategoryModel::class, array_map( + function (NewsCategory $newsCategoryOne) { + return self::mapToNewsCategory($newsCategoryOne); + }, $newsCategory) + ) + ) + ); + } + + public static function mapToListingElement(News $newsOne): NewsListingElement + { + $file = new File( + 1, + "asd", + "Краткое опиÑание", + 1024, + "png", + "/upload/asd.png" + ); + return new NewsListingElement( + $newsOne->getId(), + $newsOne->getPreviewText(), + $newsOne->getDetailText(), + $file, + $newsOne->getCreateAt()->format('d.m.Y'), + "/{$newsOne->getCode()}/code/" + ); + } + + public static function mapToDetailElement(News $newsOne): NewsDetailElement + { + $file = new File( + 1, + "asd", + "Краткое опиÑание", + 1024, + "png", + "/upload/asd.png" + ); + return new NewsDetailElement( + $newsOne->getId(), + $newsOne->getPreviewText(), + $newsOne->getDetailText(), + $newsOne->getDetailText(), + $file, + $newsOne->getCreateAt()->format('d.m.Y'), + "Отель «Ðрктика»", + "otel-arktika", + "otel-arktika" + ); + } + + public static function mapToNewsCategory(NewsCategory $newsCategory): NewsCategoryModel + { + return new NewsCategoryModel( + $newsCategory->getId(), + $newsCategory->getName(), + $newsCategory->getCode(), + ); + } +} \ No newline at end of file diff --git a/src/Mapper/RestaurantMapper.php b/src/Mapper/RestaurantMapper.php index 5f9b6ae..62bc18a 100644 --- a/src/Mapper/RestaurantMapper.php +++ b/src/Mapper/RestaurantMapper.php @@ -11,7 +11,10 @@ use App\Entity\RestaurantType; use App\Entity\Tags; use App\Model\File; use App\Model\KitchenType; +use App\Model\Pagination; use App\Model\RestaurantDetailElement; +use App\Model\RestaurantFilterVariants; +use App\Model\RestaurantList; use App\Model\RestaurantListingElement; use App\Model\RestaurantType as RestaurantTypeModel; use App\Model\Tag; @@ -19,17 +22,46 @@ use Ramsey\Collection\Collection; class RestaurantMapper { + public static function mapToRestaurantList( + $restaurants, + $restaurantTypes, + $kitchens, + $page, + $limit, + $count): RestaurantList + { + return new RestaurantList( + new Pagination($page, ceil($count / $limit), $limit), + new Collection(RestaurantListingElement::class, array_map( + function (Restaurant $restaurant) { + return RestaurantMapper::mapToListElement($restaurant); + }, $restaurants)), + new RestaurantFilterVariants( + new Collection( + RestaurantTypeModel::class, array_map( + function (RestaurantType $restaurantType) { + return RestaurantMapper::mapToRestaurantType($restaurantType); + }, $restaurantTypes + ) + ), + new Collection( + KitchenType::class, array_map( + function (Kitchen $kitchen) { + return RestaurantMapper::mapToKitchenType($kitchen); + }, $kitchens + ), + ) + ) + ); + } + public static function mapToListElement(Restaurant $restaurant): RestaurantListingElement { return new RestaurantListingElement( $restaurant->getId(), $restaurant->getName(), $restaurant->getCode(), - new RestaurantTypeModel( - $restaurant->getTypeId()->getId(), - $restaurant->getTypeId()->getName(), - $restaurant->getTypeId()->getCode() - ), + self::mapToRestaurantType($restaurant->getTypeId()), $restaurant->getCheckInfo(), new File( 1, @@ -58,7 +90,7 @@ class RestaurantMapper $restaurant->getName(), $restaurant->getCode(), implode(',', $restaurant->getCoordinates()), - //self::mapToRestaurantType($restaurant->getTypeId()), + self::mapToRestaurantType($restaurant->getTypeId()), $restaurant->getCheckPrice(), $restaurant->getCheckInfo(), new Collection( @@ -67,14 +99,26 @@ class RestaurantMapper return self::mapToKitchenType($kitchen); }, $restaurant->getKitchen()->toArray()), ), - new Collection(Phone::class, $restaurant->getPhone()->toArray()), - new Collection(Email::class, $restaurant->getEmail()->toArray()), - new Collection(Address::class, $restaurant->getAddress()->toArray()), + new Collection("string", array_map( + function (Phone $phone) { + return self::mapToPhone($phone); + }, $restaurant->getPhone()->toArray() + )), + new Collection("string", array_map( + function (Email $email) { + return self::mapToEmail($email); + }, $restaurant->getEmail()->toArray() + )), + new Collection("string", array_map( + function (Address $address) { + return self::mapToAddress($address); + }, $restaurant->getAddress()->toArray() + )), new Collection(Tag::class, array_map( function (Tags $tag) { return new Tag( "группа тегов 1", - new Collection($tag->getName()), + new Collection("string", [$tag->getName()]), ); }, $restaurant->getTags()->toArray() )), @@ -103,4 +147,19 @@ class RestaurantMapper $kitchen->getName() ); } + + public static function mapToPhone(Phone $phone): string + { + return $phone->getName(); + } + + public static function mapToEmail(Email $email): string + { + return $email->getName(); + } + + public static function mapToAddress(Address $address): string + { + return $address->getName(); + } } \ No newline at end of file diff --git a/src/Model/NewsCategory.php b/src/Model/NewsCategory.php index ba1e1a5..e22f456 100644 --- a/src/Model/NewsCategory.php +++ b/src/Model/NewsCategory.php @@ -2,21 +2,23 @@ namespace App\Model; +use Symfony\Component\Uid\Uuid; + class NewsCategory { - private int $id; + private Uuid $id; private string $name; private string $code; - public function __construct(int $id, string $name, string $code) + public function __construct(Uuid $id, string $name, string $code) { $this->id = $id; $this->name = $name; $this->code = $code; } - public function getId(): int + public function getId(): Uuid { return $this->id; } diff --git a/src/Model/NewsDetailElement.php b/src/Model/NewsDetailElement.php index 99b3453..c125aae 100644 --- a/src/Model/NewsDetailElement.php +++ b/src/Model/NewsDetailElement.php @@ -2,9 +2,11 @@ namespace App\Model; +use Symfony\Component\Uid\Uuid; + class NewsDetailElement { - private int $id; + private Uuid $id; private string $name; private string $description; private string $text; @@ -15,7 +17,7 @@ class NewsDetailElement private string $seoKeywords; public function __construct( - int $id, + Uuid $id, string $name, string $description, string $text, @@ -36,7 +38,7 @@ class NewsDetailElement $this->seoKeywords = $seoKeywords; } - public function getId(): int + public function getId(): Uuid { return $this->id; } diff --git a/src/Model/NewsListingElement.php b/src/Model/NewsListingElement.php index 5134307..dd1b0a0 100644 --- a/src/Model/NewsListingElement.php +++ b/src/Model/NewsListingElement.php @@ -2,9 +2,11 @@ namespace App\Model; +use Symfony\Component\Uid\Uuid; + class NewsListingElement { - private int $id; + private Uuid $id; private string $name; private string $description; private File $image; @@ -12,7 +14,7 @@ class NewsListingElement private string $detailLink; public function __construct( - int $id, + Uuid $id, string $name, string $description, File $image, @@ -27,7 +29,7 @@ class NewsListingElement $this->detailLink = $detailLink; } - public function getId(): int + public function getId(): Uuid { return $this->id; } diff --git a/src/Model/RestaurantDetailElement.php b/src/Model/RestaurantDetailElement.php index 01e3e67..face2bf 100644 --- a/src/Model/RestaurantDetailElement.php +++ b/src/Model/RestaurantDetailElement.php @@ -10,7 +10,7 @@ class RestaurantDetailElement private string $name; private string $code; private string $coordinates; - //private RestaurantType $type; + private RestaurantType $type; private string $check; private string $checkInfo; /** @@ -48,7 +48,7 @@ class RestaurantDetailElement string $name, string $code, string $coordinates, - //RestaurantType $type, + RestaurantType $type, string $check, string $checkInfo, Collection $kitchen, @@ -67,7 +67,7 @@ class RestaurantDetailElement $this->name = $name; $this->code = $code; $this->coordinates = $coordinates; - //$this->type = $type; + $this->type = $type; $this->check = $check; $this->checkInfo = $checkInfo; $this->kitchen = $kitchen; @@ -103,10 +103,10 @@ class RestaurantDetailElement return $this->coordinates; } -// public function getType(): RestaurantType -// { -// return $this->type; -// } + public function getType(): RestaurantType + { + return $this->type; + } public function getCheck(): string { diff --git a/src/Repository/Interface/NewsCategoryRepositoryInterface.php b/src/Repository/Interface/NewsCategoryRepositoryInterface.php new file mode 100644 index 0000000..c2d7e4d --- /dev/null +++ b/src/Repository/Interface/NewsCategoryRepositoryInterface.php @@ -0,0 +1,8 @@ +<?php + +namespace App\Repository\Interface; + +interface NewsCategoryRepositoryInterface +{ + public function getAll(): array; +} \ No newline at end of file diff --git a/src/Repository/Interface/NewsRepositoryInterface.php b/src/Repository/Interface/NewsRepositoryInterface.php new file mode 100644 index 0000000..7ad6644 --- /dev/null +++ b/src/Repository/Interface/NewsRepositoryInterface.php @@ -0,0 +1,13 @@ +<?php + +namespace App\Repository\Interface; + +use App\Entity\News; + +interface NewsRepositoryInterface +{ + public function getAll(int $page, int $limit, int $newsCategory): array; + public function getCount(): int; + public function getMainNews(): News; + public function getNewsById(string $newsId): News|null; +} \ No newline at end of file diff --git a/src/Repository/Interface/RestaurantRepositoryInterface.php b/src/Repository/Interface/RestaurantRepositoryInterface.php index 6bffa21..062d716 100644 --- a/src/Repository/Interface/RestaurantRepositoryInterface.php +++ b/src/Repository/Interface/RestaurantRepositoryInterface.php @@ -6,9 +6,9 @@ use App\Entity\Restaurant; interface RestaurantRepositoryInterface { - public function getAll($page, $limit, $restaurantTypeId, $kitchenId): array; + public function getAll(int $page, int $limit, int $restaurantTypeId, int $kitchenId): array; public function getCount(): int; - public function getById(int $id): Restaurant; + public function getById(int $id): Restaurant|null; } \ No newline at end of file diff --git a/src/Repository/NewsCategoryRepository.php b/src/Repository/NewsCategoryRepository.php index 3a5eeeb..0b0308b 100644 --- a/src/Repository/NewsCategoryRepository.php +++ b/src/Repository/NewsCategoryRepository.php @@ -3,6 +3,7 @@ namespace App\Repository; use App\Entity\NewsCategory; +use App\Repository\Interface\NewsCategoryRepositoryInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; @@ -14,35 +15,15 @@ use Doctrine\Persistence\ManagerRegistry; * @method NewsCategory[] findAll() * @method NewsCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ -class NewsCategoryRepository extends ServiceEntityRepository +class NewsCategoryRepository extends ServiceEntityRepository implements NewsCategoryRepositoryInterface { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, NewsCategory::class); } -// /** -// * @return NewsCategory[] Returns an array of NewsCategory objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('n') -// ->andWhere('n.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('n.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } - -// public function findOneBySomeField($value): ?NewsCategory -// { -// return $this->createQueryBuilder('n') -// ->andWhere('n.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } + public function getAll(): array + { + return $this->findAll(); + } } diff --git a/src/Repository/NewsRepository.php b/src/Repository/NewsRepository.php index 3b5d864..011be28 100644 --- a/src/Repository/NewsRepository.php +++ b/src/Repository/NewsRepository.php @@ -2,7 +2,10 @@ namespace App\Repository; +use App\Exception\NewsExceptionEnum; +use Exception; use App\Entity\News; +use App\Repository\Interface\NewsRepositoryInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; @@ -14,35 +17,43 @@ use Doctrine\Persistence\ManagerRegistry; * @method News[] findAll() * @method News[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ -class NewsRepository extends ServiceEntityRepository +class NewsRepository extends ServiceEntityRepository implements NewsRepositoryInterface { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, News::class); } -// /** -// * @return News[] Returns an array of News objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('n') -// ->andWhere('n.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('n.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } + public function getAll($page, $limit, $newsCategory): array + { + $query = $this->getEntityManager()->createQueryBuilder(); + $query->select('n')->from(News::class, 'n'); + if ($newsCategory !== null) { + $query->join('n.newsCategories', 'nc') + ->andWhere('nc.id = :newsCategory') + ->setParameter('newsCategory', $newsCategory); + } + $query->setMaxResults($limit) + ->setFirstResult(($page - 1) * $limit); + return $query->getQuery()->getResult(); + } + + public function getCount(): int + { + return $this->count(); + } -// public function findOneBySomeField($value): ?News -// { -// return $this->createQueryBuilder('n') -// ->andWhere('n.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } + public function getMainNews(): News + { + return $this->findOneBy(['mainPageRender' => true]); + } + + public function getNewsById(string $newsId): News|null + { + try { + return $this->find(['id' => $newsId]); + } catch (Exception $e) { + throw new Exception("News not found", NewsExceptionEnum::NotFound->value); + } + } } diff --git a/src/Repository/RestaurantRepository.php b/src/Repository/RestaurantRepository.php index 53c0561..0f2061e 100644 --- a/src/Repository/RestaurantRepository.php +++ b/src/Repository/RestaurantRepository.php @@ -26,11 +26,11 @@ class RestaurantRepository extends ServiceEntityRepository implements Restaurant { $query = $this->createQueryBuilder('r'); $query->select('r'); - if ($restaurantTypeId !== 0) { + if ($restaurantTypeId !== null) { $query->andWhere('r.typeId = :restaurantTypeId') ->setParameter('restaurantTypeId', $restaurantTypeId); } - if ($kitchenId !== 0) { + if ($kitchenId !== null) { $query->join('r.kitchen', 'k') ->andWhere('k.id = :kitchenId') ->setParameter('kitchenId', $kitchenId); @@ -45,7 +45,7 @@ class RestaurantRepository extends ServiceEntityRepository implements Restaurant return $this->count(); } - public function getById(int $id): Restaurant + public function getById(int $id): Restaurant|null { return $this->find($id); } diff --git a/src/Requests/NewsListRequest.php b/src/Requests/NewsListRequest.php new file mode 100644 index 0000000..914a3c8 --- /dev/null +++ b/src/Requests/NewsListRequest.php @@ -0,0 +1,28 @@ +<?php + +namespace App\Requests; + +use Symfony\Component\Form\Extension\Core\Type\UuidType; +use Symfony\Component\Uid\UuidV4; +use Symfony\Component\Validator\Constraints as Assert; + +class NewsListRequest extends BaseRequest +{ + #[Assert\Type('int')] + #[Assert\NotBlank] + public $page; + #[Assert\Type('int')] + #[Assert\NotBlank] + public $limit; + #[Assert\Uuid] + public $news_category; + + protected function populate(): void + { + foreach ($this->getRequest()->query as $property => $value) { + if (property_exists($this, $property)) { + $this->{$property} = ctype_digit($value) ? (int)$value : $value; + } + } + } +} \ No newline at end of file diff --git a/src/Requests/RestaurantListRequest.php b/src/Requests/RestaurantListRequest.php new file mode 100644 index 0000000..701674d --- /dev/null +++ b/src/Requests/RestaurantListRequest.php @@ -0,0 +1,28 @@ +<?php + +namespace App\Requests; + +use Symfony\Component\Validator\Constraints as Assert; + +class RestaurantListRequest extends BaseRequest +{ + #[Assert\Type('int')] + #[Assert\NotBlank] + public $page; + #[Assert\Type('int')] + #[Assert\NotBlank] + public $limit; + #[Assert\Type('int')] + public $restaurant_type_id; + #[Assert\Type('int')] + public $kitchen_id; + + protected function populate(): void + { + foreach ($this->getRequest()->query as $property => $value) { + if (property_exists($this, $property)) { + $this->{$property} = ctype_digit($value) ? (int)$value : $value; + } + } + } +} \ No newline at end of file diff --git a/src/Service/NewsService.php b/src/Service/NewsService.php new file mode 100644 index 0000000..043d000 --- /dev/null +++ b/src/Service/NewsService.php @@ -0,0 +1,48 @@ +<?php + +namespace App\Service; + +use Exception; +use App\Exception\NewsExceptionEnum; +use App\Mapper\NewsMapper; +use App\Model\NewsDetailElement; +use App\Model\NewsList; +use App\Model\NewsListingElement; +use App\Repository\Interface\NewsCategoryRepositoryInterface; +use App\Repository\Interface\NewsRepositoryInterface; + +class NewsService +{ + public function __construct( + private NewsRepositoryInterface $newsRepository, + private NewsCategoryRepositoryInterface $newsCategoryRepository) {} + + public function getNews($page, $limit, $newsCategory): NewsList + { + $news = $this->newsRepository->getAll($page, $limit, $newsCategory); + $newsCategories = $this->newsCategoryRepository->getAll(); + $count = $this->newsRepository->getCount(); + return NewsMapper::mapToNewsList($news, $newsCategories, $page, $limit, $count); + } + + public function getMainNews(): NewsListingElement + { + $mainNews = $this->newsRepository->getMainNews(); + return NewsMapper::mapToListingElement($mainNews); + } + + public function getNewsSearch(): NewsDetailElement + { + $mainNews = $this->newsRepository->getMainNews(); + return NewsMapper::mapToDetailElement($mainNews); + } + + public function getNewsOne($newsId): NewsDetailElement + { + $news = $this->newsRepository->getNewsById($newsId); + if ($news == null) { + throw new Exception("News not found", NewsExceptionEnum::NotFound->value); + } + return NewsMapper::mapToDetailElement($news); + } +} \ No newline at end of file diff --git a/src/Service/RestaurantService.php b/src/Service/RestaurantService.php index 7e1866d..8f1a42a 100644 --- a/src/Service/RestaurantService.php +++ b/src/Service/RestaurantService.php @@ -2,26 +2,14 @@ namespace App\Service; -use App\Entity\Address; -use App\Entity\Email; -use App\Entity\Kitchen; -use App\Entity\Phone; -use App\Entity\Restaurant; -use App\Entity\RestaurantType; -use App\Entity\Tags; +use App\Exception\RestaurantExceptionEnum; +use Exception; use App\Mapper\RestaurantMapper; -use App\Model\File; -use App\Model\KitchenType; -use App\Model\Pagination; use App\Model\RestaurantDetailElement; -use App\Model\RestaurantFilterVariants; use App\Model\RestaurantList; -use App\Model\RestaurantListingElement; -use App\Model\RestaurantType as RestaurantTypeModel; use App\Repository\Interface\KitchenRepositoryInterface; use App\Repository\Interface\RestaurantRepositoryInterface; use App\Repository\Interface\RestaurantTypeRepositoryInterface; -use Ramsey\Collection\Collection; class RestaurantService { @@ -45,34 +33,22 @@ class RestaurantService $count = $this->restaurantRepository->getCount(); $restaurantTypes = $this->restaurantTypeRepository->getAll(); $kitchens = $this->kitchenRepository->getAll(); - return new RestaurantList( - new Pagination($page, ceil($count / $limit), $limit), - new Collection(RestaurantListingElement::class, array_map( - function (Restaurant $restaurant) { - return RestaurantMapper::mapToListElement($restaurant); - }, $restaurants)), - new RestaurantFilterVariants( - new Collection( - RestaurantTypeModel::class, array_map( - function (RestaurantType $restaurantType) { - return RestaurantMapper::mapToRestaurantType($restaurantType); - }, $restaurantTypes - ) - ), - new Collection( - KitchenType::class, array_map( - function (Kitchen $kitchen) { - return RestaurantMapper::mapToKitchenType($kitchen); - }, $kitchens - ), - ) - ) + return RestaurantMapper::mapToRestaurantList( + $restaurants, + $restaurantTypes, + $kitchens, + $page, + $limit, + $count ); } public function getRestaurant(int $id): RestaurantDetailElement { $restaurant = $this->restaurantRepository->getById($id); + if ($restaurant == null) { + throw new Exception("Restaurant not found", RestaurantExceptionEnum::NotFound->value); + } return RestaurantMapper::mapToDetailElement($restaurant); } } \ No newline at end of file -- GitLab