diff --git a/app/composer.json b/app/composer.json index c4803f222e0f1cd68e54ee56f74e3f2f24780886..ef0f7655cb6b7c2182c68124960c8f0e98115d73 100644 --- a/app/composer.json +++ b/app/composer.json @@ -4,7 +4,7 @@ "minimum-stability": "stable", "prefer-stable": true, "require": { - "php": ">=8.2", + "php": ">=8.3", "ext-ctype": "*", "ext-iconv": "*", "doctrine/dbal": "^3", @@ -13,6 +13,7 @@ "doctrine/orm": "^3.1", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.28", + "ramsey/uuid": "^4.7", "ramsey/collection": "^2.0", "symfony/asset": "6.4.*", "symfony/asset-mapper": "6.4.*", diff --git a/app/migrations/Version20240427114630.php b/app/migrations/Version20240520053704.php similarity index 67% rename from app/migrations/Version20240427114630.php rename to app/migrations/Version20240520053704.php index 84378b72ef805ae806b666f1171a2a2956f7d2f8..3ba63898803868870954dc39857c3c6e3a9a98ca 100644 --- a/app/migrations/Version20240427114630.php +++ b/app/migrations/Version20240520053704.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240427114630 extends AbstractMigration +final class Version20240520053704 extends AbstractMigration { public function getDescription(): string { @@ -20,9 +20,12 @@ final class Version20240427114630 extends AbstractMigration public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE TABLE file (id UUID NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, size INT NOT NULL, type VARCHAR(255) NOT NULL, url VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE TABLE kitchens (id UUID NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE TABLE news (id UUID NOT NULL, type_id UUID DEFAULT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, sort INT NOT NULL, active BOOLEAN NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, update_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, preview_image VARCHAR(255) DEFAULT NULL, preview_text VARCHAR(1000) DEFAULT NULL, detail_image VARCHAR(255) DEFAULT NULL, detail_text VARCHAR(255) DEFAULT NULL, main_page_render BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE news (id UUID NOT NULL, type_id UUID DEFAULT NULL, detail_image_id UUID DEFAULT NULL, preview_image_id UUID DEFAULT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, sort INT NOT NULL, active BOOLEAN NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, update_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, preview_text VARCHAR(1000) DEFAULT NULL, detail_text VARCHAR(255) DEFAULT NULL, main_page_render BOOLEAN NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX IDX_1DD39950C54C8C93 ON news (type_id)'); + $this->addSql('CREATE INDEX IDX_1DD39950CB7BCCB6 ON news (detail_image_id)'); + $this->addSql('CREATE INDEX IDX_1DD39950FAE957CD ON news (preview_image_id)'); $this->addSql('COMMENT ON COLUMN news.created_at IS \'(DC2Type:datetime_immutable)\''); $this->addSql('COMMENT ON COLUMN news.update_at IS \'(DC2Type:datetime_immutable)\''); $this->addSql('CREATE TABLE news_news_categories (news_id UUID NOT NULL, news_categories_id UUID NOT NULL, PRIMARY KEY(news_id, news_categories_id))'); @@ -31,15 +34,19 @@ final class Version20240427114630 extends AbstractMigration $this->addSql('CREATE TABLE news_categories (id UUID NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE TABLE news_type (id UUID NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE TABLE restaurant_types (id UUID NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE TABLE restaurants (id UUID NOT NULL, type_id UUID DEFAULT NULL, settlement_id UUID DEFAULT NULL, active BOOLEAN NOT NULL, sort INT NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, update_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, receipt VARCHAR(255) NOT NULL, receipt_info VARCHAR(255) NOT NULL, phone VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, address VARCHAR(255) NOT NULL, tags VARCHAR(255) NOT NULL, site VARCHAR(255) NOT NULL, coordinates TEXT NOT NULL, preview_image VARCHAR(255) NOT NULL, detail_image VARCHAR(255) NOT NULL, gallery VARCHAR(255) NOT NULL, how_to_find VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE restaurants (id UUID NOT NULL, type_id UUID DEFAULT NULL, settlement_id UUID DEFAULT NULL, preview_image_id UUID DEFAULT NULL, detail_image_id UUID DEFAULT NULL, active BOOLEAN NOT NULL, sort INT NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, update_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, receipt VARCHAR(255) NOT NULL, receipt_info VARCHAR(255) NOT NULL, phone VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, address VARCHAR(255) NOT NULL, tags VARCHAR(255) NOT NULL, site VARCHAR(255) NOT NULL, coordinates VARCHAR(1000) NOT NULL, how_to_find VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX IDX_AD837724C54C8C93 ON restaurants (type_id)'); $this->addSql('CREATE INDEX IDX_AD837724C2B9C425 ON restaurants (settlement_id)'); + $this->addSql('CREATE INDEX IDX_AD837724FAE957CD ON restaurants (preview_image_id)'); + $this->addSql('CREATE INDEX IDX_AD837724CB7BCCB6 ON restaurants (detail_image_id)'); $this->addSql('COMMENT ON COLUMN restaurants.created_at IS \'(DC2Type:datetime_immutable)\''); $this->addSql('COMMENT ON COLUMN restaurants.update_at IS \'(DC2Type:datetime_immutable)\''); - $this->addSql('COMMENT ON COLUMN restaurants.coordinates IS \'(DC2Type:array)\''); $this->addSql('CREATE TABLE restaurants_kitchens (restaurants_id UUID NOT NULL, kitchens_id UUID NOT NULL, PRIMARY KEY(restaurants_id, kitchens_id))'); $this->addSql('CREATE INDEX IDX_716464694DCA160A ON restaurants_kitchens (restaurants_id)'); $this->addSql('CREATE INDEX IDX_71646469E043FCBC ON restaurants_kitchens (kitchens_id)'); + $this->addSql('CREATE TABLE restaurants_file (restaurants_id UUID NOT NULL, file_id UUID NOT NULL, PRIMARY KEY(restaurants_id, file_id))'); + $this->addSql('CREATE INDEX IDX_EBC930974DCA160A ON restaurants_file (restaurants_id)'); + $this->addSql('CREATE INDEX IDX_EBC9309793CB796C ON restaurants_file (file_id)'); $this->addSql('CREATE TABLE settlements (id UUID NOT NULL, active BOOLEAN NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, update_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, coordinates TEXT NOT NULL, PRIMARY KEY(id))'); $this->addSql('COMMENT ON COLUMN settlements.created_at IS \'(DC2Type:datetime_immutable)\''); $this->addSql('COMMENT ON COLUMN settlements.update_at IS \'(DC2Type:datetime_immutable)\''); @@ -62,12 +69,18 @@ final class Version20240427114630 extends AbstractMigration $this->addSql('DROP TRIGGER IF EXISTS notify_trigger ON messenger_messages;'); $this->addSql('CREATE TRIGGER notify_trigger AFTER INSERT OR UPDATE ON messenger_messages FOR EACH ROW EXECUTE PROCEDURE notify_messenger_messages();'); $this->addSql('ALTER TABLE news ADD CONSTRAINT FK_1DD39950C54C8C93 FOREIGN KEY (type_id) REFERENCES news_type (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE news ADD CONSTRAINT FK_1DD39950CB7BCCB6 FOREIGN KEY (detail_image_id) REFERENCES file (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE news ADD CONSTRAINT FK_1DD39950FAE957CD FOREIGN KEY (preview_image_id) REFERENCES file (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE news_news_categories ADD CONSTRAINT FK_34AB0102B5A459A0 FOREIGN KEY (news_id) REFERENCES news (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE news_news_categories ADD CONSTRAINT FK_34AB0102F7F178F1 FOREIGN KEY (news_categories_id) REFERENCES news_categories (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE restaurants ADD CONSTRAINT FK_AD837724C54C8C93 FOREIGN KEY (type_id) REFERENCES restaurant_types (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE restaurants ADD CONSTRAINT FK_AD837724C2B9C425 FOREIGN KEY (settlement_id) REFERENCES settlements (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE restaurants ADD CONSTRAINT FK_AD837724FAE957CD FOREIGN KEY (preview_image_id) REFERENCES file (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE restaurants ADD CONSTRAINT FK_AD837724CB7BCCB6 FOREIGN KEY (detail_image_id) REFERENCES file (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE restaurants_kitchens ADD CONSTRAINT FK_716464694DCA160A FOREIGN KEY (restaurants_id) REFERENCES restaurants (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE restaurants_kitchens ADD CONSTRAINT FK_71646469E043FCBC FOREIGN KEY (kitchens_id) REFERENCES kitchens (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE restaurants_file ADD CONSTRAINT FK_EBC930974DCA160A FOREIGN KEY (restaurants_id) REFERENCES restaurants (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE restaurants_file ADD CONSTRAINT FK_EBC9309793CB796C FOREIGN KEY (file_id) REFERENCES file (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } public function down(Schema $schema): void @@ -75,12 +88,19 @@ final class Version20240427114630 extends AbstractMigration // this down() migration is auto-generated, please modify it to your needs $this->addSql('CREATE SCHEMA public'); $this->addSql('ALTER TABLE news DROP CONSTRAINT FK_1DD39950C54C8C93'); + $this->addSql('ALTER TABLE news DROP CONSTRAINT FK_1DD39950CB7BCCB6'); + $this->addSql('ALTER TABLE news DROP CONSTRAINT FK_1DD39950FAE957CD'); $this->addSql('ALTER TABLE news_news_categories DROP CONSTRAINT FK_34AB0102B5A459A0'); $this->addSql('ALTER TABLE news_news_categories DROP CONSTRAINT FK_34AB0102F7F178F1'); $this->addSql('ALTER TABLE restaurants DROP CONSTRAINT FK_AD837724C54C8C93'); $this->addSql('ALTER TABLE restaurants DROP CONSTRAINT FK_AD837724C2B9C425'); + $this->addSql('ALTER TABLE restaurants DROP CONSTRAINT FK_AD837724FAE957CD'); + $this->addSql('ALTER TABLE restaurants DROP CONSTRAINT FK_AD837724CB7BCCB6'); $this->addSql('ALTER TABLE restaurants_kitchens DROP CONSTRAINT FK_716464694DCA160A'); $this->addSql('ALTER TABLE restaurants_kitchens DROP CONSTRAINT FK_71646469E043FCBC'); + $this->addSql('ALTER TABLE restaurants_file DROP CONSTRAINT FK_EBC930974DCA160A'); + $this->addSql('ALTER TABLE restaurants_file DROP CONSTRAINT FK_EBC9309793CB796C'); + $this->addSql('DROP TABLE file'); $this->addSql('DROP TABLE kitchens'); $this->addSql('DROP TABLE news'); $this->addSql('DROP TABLE news_news_categories'); @@ -89,6 +109,7 @@ final class Version20240427114630 extends AbstractMigration $this->addSql('DROP TABLE restaurant_types'); $this->addSql('DROP TABLE restaurants'); $this->addSql('DROP TABLE restaurants_kitchens'); + $this->addSql('DROP TABLE restaurants_file'); $this->addSql('DROP TABLE settlements'); $this->addSql('DROP TABLE users'); $this->addSql('DROP TABLE messenger_messages'); diff --git a/app/src/News/Controller/NewsController.php b/app/src/News/Controller/NewsController.php index 34e1dbba36c09283223134479ddea3d751b61ee3..a4bbc7f8290b9641ef8d307c07206fc4389b4465 100644 --- a/app/src/News/Controller/NewsController.php +++ b/app/src/News/Controller/NewsController.php @@ -2,14 +2,22 @@ namespace App\News\Controller; +use App\News\Request\NewsCreateRequest; use App\News\Request\NewsDetailRequest; +use App\News\Request\NewsFullUpdateRequest; use App\News\Request\NewsListingRequest; +use App\News\Request\NewsPartUpdateRequest; +use App\News\UseCase\NewsCreateUseCase; +use App\News\UseCase\NewsDeleteUseCase; +use App\News\UseCase\NewsFullUpdateUseCase; use App\News\UseCase\NewsGetDetailMainUseCase; use App\News\UseCase\NewsGetDetailUseCase; use App\News\UseCase\NewsGetListingUseUseCase; use App\News\UseCase\NewsGetMainUseCase; +use App\News\UseCase\NewsPartUpdateUseCase; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; #[Route('/api/v1/news')] @@ -17,9 +25,13 @@ class NewsController extends AbstractController { public function __construct( private readonly NewsGetListingUseUseCase $getListingUseCase, - private readonly NewsGetDetailUseCase $getDetailNews, - private readonly NewsGetMainUseCase $getMainNews, - private readonly NewsGetDetailMainUseCase $getDetailMainNews, + private readonly NewsGetDetailUseCase $getDetailUseCase, + private readonly NewsGetMainUseCase $getMainUseCase, + private readonly NewsGetDetailMainUseCase $getDetailMainUseCase, + private readonly NewsCreateUseCase $createUseCase, + private readonly NewsFullUpdateUseCase $fullUpdateUseCase, + private readonly NewsPartUpdateUseCase $partUpdateUseCase, + private readonly NewsDeleteUseCase $deleteUseCase, ) { } @@ -32,18 +44,42 @@ class NewsController extends AbstractController #[Route('/mainNews', name: 'mainNews', methods: ['GET'])] public function mainNews(): JsonResponse { - return $this->getMainNews->execute(); + return $this->getMainUseCase->execute(); } #[Route('/search', name: 'searchNews', methods: ['GET'])] public function detailMainNews(): JsonResponse { - return $this->getDetailMainNews->execute(); + return $this->getDetailMainUseCase->execute(); } #[Route('/{detailId}', name: 'oneNews', methods: ['GET'])] public function oneNews(NewsDetailRequest $request): JsonResponse { - return $this->getDetailNews->execute($request); + return $this->getDetailUseCase->execute($request); + } + + #[Route('/create', name: 'createNews', methods: ['POST'])] + public function createNews(NewsCreateRequest $request): Response + { + return $this->createUseCase->execute($request); + } + + #[Route('/update', name: 'updateNews', methods: ['PUT'])] + public function fillUpdateNews(NewsFullUpdateRequest $request): Response + { + return $this->fullUpdateUseCase->execute($request); + } + + #[Route('/partUpdate', name: 'partUpdateNews', methods: ['PATCH'])] + public function partUpdateNews(NewsPartUpdateRequest $request): Response + { + return $this->partUpdateUseCase->execute($request); + } + + #[Route('/delete/{detailId}', name: 'deleteNews', methods: ['DELETE'])] + public function deleteNews(NewsDetailRequest $request): Response + { + return $this->deleteUseCase->execute($request); } } diff --git a/app/src/News/Dto/NewsListDto.php b/app/src/News/Dto/NewsListDto.php index 833a93c6a3a508198c9f303d2bab3e082232c2c9..ddb216bbed0982abbb2c0483a09bc5ecbbe928a0 100644 --- a/app/src/News/Dto/NewsListDto.php +++ b/app/src/News/Dto/NewsListDto.php @@ -2,19 +2,19 @@ namespace App\News\Dto; -use App\Shared\Collection\ListingCollection; +use App\News\DtoCollection\NewsListingElementCollection; use App\Shared\Dto\PaginationDto; class NewsListDto { /** * @param PaginationDto $pagination - * @param ListingCollection $list + * @param NewsListingElementCollection $list * @param NewsFilterVariantsDto $filterVariants */ public function __construct( public PaginationDto $pagination, - public ListingCollection $list, + public NewsListingElementCollection $list, public NewsFilterVariantsDto $filterVariants, ) { } diff --git a/app/src/News/DtoCollection/NewsListingElementCollection.php b/app/src/News/DtoCollection/NewsListingElementCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..0c266f19c82bef4ff01267f77887ba74d16376b2 --- /dev/null +++ b/app/src/News/DtoCollection/NewsListingElementCollection.php @@ -0,0 +1,16 @@ +collectionType, $data); + } +} \ No newline at end of file diff --git a/app/src/News/DtoFactory/NewsListDtoFactory.php b/app/src/News/DtoFactory/NewsListDtoFactory.php index 25613a79836d08f7cd125ebfbb0fb34c49b35f6c..4a0efcd8a0d5984ae1a78de8de26948e12177904 100644 --- a/app/src/News/DtoFactory/NewsListDtoFactory.php +++ b/app/src/News/DtoFactory/NewsListDtoFactory.php @@ -4,14 +4,14 @@ namespace App\News\DtoFactory; use App\News\Dto\NewsFilterVariantsDto; use App\News\Dto\NewsListDto; -use App\Shared\Collection\ListingCollection; +use App\News\DtoCollection\NewsListingElementCollection; use App\Shared\Dto\PaginationDto; class NewsListDtoFactory { public function create( PaginationDto $pagination, - ListingCollection $list, + NewsListingElementCollection $list, NewsFilterVariantsDto $filters, ): NewsListDto { return new NewsListDto( diff --git a/app/src/News/DtoFactory/NewsListingElementDtoFactory.php b/app/src/News/DtoFactory/NewsListingElementDtoFactory.php index 11d4412c17436b51ae6a2a1a3b05085fd99cd93d..6837bf2c253c9c5567b9bf06d81c72d779867ef3 100644 --- a/app/src/News/DtoFactory/NewsListingElementDtoFactory.php +++ b/app/src/News/DtoFactory/NewsListingElementDtoFactory.php @@ -3,7 +3,7 @@ namespace App\News\DtoFactory; use App\News\Dto\NewsListingElementDto; -use App\Shared\Collection\ListingCollection; +use App\News\DtoCollection\NewsListingElementCollection; use App\Shared\DtoFactory\FileDtoFactory; use App\Shared\Entity\News; use Ramsey\Collection\Collection; @@ -31,11 +31,11 @@ class NewsListingElementDtoFactory /** * @param Collection $news - * @return ListingCollection + * @return NewsListingElementCollection */ - public function createCollection(Collection $news): ListingCollection + public function createCollection(Collection $news): NewsListingElementCollection { - return new ListingCollection( + return new NewsListingElementCollection( $news->map(function (News $oneNews) { return $this->create($oneNews); }) diff --git a/app/src/News/Request/NewsCreateRequest.php b/app/src/News/Request/NewsCreateRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..87298f0ec375f3402fd2c819ad5b586642c3d11a --- /dev/null +++ b/app/src/News/Request/NewsCreateRequest.php @@ -0,0 +1,47 @@ +news->getCountWithFilters( $request->news_category ); @@ -69,17 +76,21 @@ class NewsPrepareResponseService ); } - public function bornMainNews(): NewsListingElementDto + public + function bornMainNews(): NewsListingElementDto { return $this->listFactory->create($this->news->getMainNews()); } - public function bornDetailMainNews(): NewsDetailElementDto + public + function bornDetailMainNews(): NewsDetailElementDto { return $this->detailElementFactory->create($this->news->getMainNews()); } - public function bornDetailElement(NewsDetailRequest $request + public + function bornDetail( + NewsDetailRequest $request ): NewsDetailElementDto { $news = $this->news->find($request->detailId); @@ -89,4 +100,33 @@ class NewsPrepareResponseService return $this->detailElementFactory->create($news); } + + public function unbirth( + NewsDetailRequest $request + ) { + $news = $this->news->find($request->detailId); + if ($news === null) { + throw new NotFoundError('News not found'); + } + + $this->news->remove($news); + } + + public function rebirth(NewsPartUpdateRequest $request): void + { + $news = $this->entityFactory->hardUpdate($request); + $this->news->createUpdate($news); + } + + public function reborn(NewsFullUpdateRequest $request): void + { + $news = $this->entityFactory->softUpdate($request); + $this->news->createUpdate($news); + } + + public function birth(NewsCreateRequest $request): void + { + $news = $this->entityFactory->create($request); + $this->news->createUpdate($news); + } } diff --git a/app/src/News/UseCase/NewsCreateUseCase.php b/app/src/News/UseCase/NewsCreateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..28d045d168390ee70f4709789f75f321ee2a9d8f --- /dev/null +++ b/app/src/News/UseCase/NewsCreateUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->birth($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/News/UseCase/NewsDeleteUseCase.php b/app/src/News/UseCase/NewsDeleteUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..b927794aae3eb9c4bcecd4090717840b4506c712 --- /dev/null +++ b/app/src/News/UseCase/NewsDeleteUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->unbirth($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/News/UseCase/NewsFullUpdateUseCase.php b/app/src/News/UseCase/NewsFullUpdateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..2d4075cde75788f0ec7be552071818c12405e86a --- /dev/null +++ b/app/src/News/UseCase/NewsFullUpdateUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->reborn($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/News/UseCase/NewsGetDetailMainUseCase.php b/app/src/News/UseCase/NewsGetDetailMainUseCase.php index 92725a121c29184bc53d4071b17c548a4e1ec7c4..a59f9580c7baef004c90d4741f29792c8b36355a 100644 --- a/app/src/News/UseCase/NewsGetDetailMainUseCase.php +++ b/app/src/News/UseCase/NewsGetDetailMainUseCase.php @@ -14,7 +14,7 @@ class NewsGetDetailMainUseCase ) { } - public function execute(): ?JsonResponse + public function execute(): JsonResponse { try { return new JsonResponse( @@ -24,4 +24,4 @@ class NewsGetDetailMainUseCase return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); } } -} \ No newline at end of file +} diff --git a/app/src/News/UseCase/NewsGetDetailUseCase.php b/app/src/News/UseCase/NewsGetDetailUseCase.php index 2605bd94f84d89844e02a0089589e2190969bca5..0127279ce9d0789317c0ae83cd94a2463163d559 100644 --- a/app/src/News/UseCase/NewsGetDetailUseCase.php +++ b/app/src/News/UseCase/NewsGetDetailUseCase.php @@ -22,7 +22,7 @@ class NewsGetDetailUseCase { try { return new JsonResponse( - $this->responsePrepareService->bornDetailElement($request) + $this->responsePrepareService->bornDetail($request) ); } catch (NotFoundError $error) { $errorDto = $this->errorFactory->create($error); diff --git a/app/src/News/UseCase/NewsPartUpdateUseCase.php b/app/src/News/UseCase/NewsPartUpdateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..2055035916a01c8230a1adaf9af6284f257cd78f --- /dev/null +++ b/app/src/News/UseCase/NewsPartUpdateUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->rebirth($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} \ No newline at end of file diff --git a/app/src/Restaurants/Collection/RestaurantListingElementCollection.php b/app/src/Restaurants/Collection/RestaurantListingElementCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..8cc388cbd9e399889b14c198cefb6d25e8b69f2a --- /dev/null +++ b/app/src/Restaurants/Collection/RestaurantListingElementCollection.php @@ -0,0 +1,16 @@ +collectionType, $data); + } +} \ No newline at end of file diff --git a/app/src/Restaurants/Controller/RestaurantsController.php b/app/src/Restaurants/Controller/RestaurantsController.php index c589e3acfaba4a340b59a12ea0df51bafde7d192..f8a27562d51b806ec067e5d283adfe96ebc0dcf8 100644 --- a/app/src/Restaurants/Controller/RestaurantsController.php +++ b/app/src/Restaurants/Controller/RestaurantsController.php @@ -2,12 +2,20 @@ namespace App\Restaurants\Controller; +use App\Restaurants\Request\RestaurantCreateRequest; +use App\Restaurants\Request\RestaurantFullUpdateRequest; +use App\Restaurants\Request\RestaurantPartUpdateRequest; +use App\Restaurants\UseCase\RestaurantCreateUseCase; +use App\Restaurants\UseCase\RestaurantDeleteUseCase; +use App\Restaurants\UseCase\RestaurantFullUpdateUseCase; use App\Restaurants\UseCase\RestaurantGetListingUseCase; use App\Restaurants\Request\RestaurantDetailRequest; use App\Restaurants\Request\RestaurantListingRequest; use App\Restaurants\UseCase\RestaurantGetDetailUseCase; +use App\Restaurants\UseCase\RestaurantPartUpdateUseCase; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; #[Route('/api/v1/restaurants')] @@ -16,6 +24,10 @@ class RestaurantsController extends AbstractController public function __construct( private readonly RestaurantGetListingUseCase $getListingUseCase, private readonly RestaurantGetDetailUseCase $getDetailUseCase, + private readonly RestaurantCreateUseCase $createUseCase, + private readonly RestaurantFullUpdateUseCase $fullUpdateUseCase, + private readonly RestaurantDeleteUseCase $deleteUseCase, + private readonly RestaurantPartUpdateUseCase $partUpdateUseCase, ) { } @@ -30,4 +42,28 @@ class RestaurantsController extends AbstractController { return $this->getDetailUseCase->execute($request); } + + #[Route('/create', name: 'createRestaurant', methods: ['POST'])] + public function createRestaurant(RestaurantCreateRequest $request): Response + { + return $this->createUseCase->execute($request); + } + + #[Route('/update', name: 'updateRestaurant', methods: ['PUT'])] + public function fillUpdateRestaurant(RestaurantFullUpdateRequest $request + ): Response { + return $this->fullUpdateUseCase->execute($request); + } + + #[Route('/partUpdate', name: 'partUpdateRestaurant', methods: ['PATCH'])] + public function partUpdateRestaurant(RestaurantPartUpdateRequest $request + ): Response { + return $this->partUpdateUseCase->execute($request); + } + + #[Route('/delete/{detailId}', name: 'deleteRestaurant', methods: ['DELETE'])] + public function deleteRestaurant(RestaurantDetailRequest $request): Response + { + return $this->deleteUseCase->execute($request); + } } diff --git a/app/src/Restaurants/Dto/RestaurantListDto.php b/app/src/Restaurants/Dto/RestaurantListDto.php index 1e6ac5d5b995500610ab768c88fab3344a3d4e0e..8695625acc5a47986ef4a2793e57ed65e7562de6 100644 --- a/app/src/Restaurants/Dto/RestaurantListDto.php +++ b/app/src/Restaurants/Dto/RestaurantListDto.php @@ -2,19 +2,19 @@ namespace App\Restaurants\Dto; -use App\Shared\Collection\ListingCollection; +use App\Restaurants\Collection\RestaurantListingElementCollection; use App\Shared\Dto\PaginationDto; class RestaurantListDto { /** * @param PaginationDto $pagination - * @param ListingCollection $list + * @param RestaurantListingElementCollection $list * @param RestaurantFilterVariantsDto $filterVariants */ public function __construct( public PaginationDto $pagination, - public ListingCollection $list, + public RestaurantListingElementCollection $list, public RestaurantFilterVariantsDto $filterVariants, ) {} } diff --git a/app/src/Restaurants/DtoFactory/RestaurantListDtoFactory.php b/app/src/Restaurants/DtoFactory/RestaurantListDtoFactory.php index 66ca9e8754ef5fbf24e8f52d99c3dbc0669aa9a2..c28d740e162baf45709b83d1cf491aef98cb7a5f 100644 --- a/app/src/Restaurants/DtoFactory/RestaurantListDtoFactory.php +++ b/app/src/Restaurants/DtoFactory/RestaurantListDtoFactory.php @@ -2,23 +2,23 @@ namespace App\Restaurants\DtoFactory; +use App\Restaurants\Collection\RestaurantListingElementCollection; use App\Restaurants\Dto\RestaurantFilterVariantsDto; use App\Restaurants\Dto\RestaurantListDto; use App\Restaurants\Dto\RestaurantListingElementDto; -use App\Shared\Collection\ListingCollection; use App\Shared\Dto\PaginationDto; class RestaurantListDtoFactory { /** * @param PaginationDto $pagination - * @param ListingCollection $list + * @param RestaurantListingElementCollection $list * @param RestaurantFilterVariantsDto $filters * @return RestaurantListDto */ public function create( PaginationDto $pagination, - ListingCollection $list, + RestaurantListingElementCollection $list, RestaurantFilterVariantsDto $filters ): RestaurantListDto { return new RestaurantListDto( diff --git a/app/src/Restaurants/DtoFactory/RestaurantListingElementDtoFactory.php b/app/src/Restaurants/DtoFactory/RestaurantListingElementDtoFactory.php index 6fa858dd61ae612d50c08cca853daaf06681b4d0..7c0066db6ba3a0aec7f19fb1b4308df5e8e78a61 100644 --- a/app/src/Restaurants/DtoFactory/RestaurantListingElementDtoFactory.php +++ b/app/src/Restaurants/DtoFactory/RestaurantListingElementDtoFactory.php @@ -2,8 +2,8 @@ namespace App\Restaurants\DtoFactory; +use App\Restaurants\Collection\RestaurantListingElementCollection; use App\Restaurants\Dto\RestaurantListingElementDto; -use App\Shared\Collection\ListingCollection; use App\Shared\DtoFactory\FileDtoFactory; use App\Shared\Entity\Restaurants; use Ramsey\Collection\Collection; @@ -29,14 +29,14 @@ class RestaurantListingElementDtoFactory /** * @param Collection $restaurants - * @return ListingCollection + * @return RestaurantListingElementCollection */ - public function createCollection(Collection $restaurants): ListingCollection + public function createCollection(Collection $restaurants): RestaurantListingElementCollection { $restaurantsDto = $restaurants->map(function(Restaurants $restaurant) { return $this->create($restaurant); }); - return new ListingCollection($restaurantsDto->toArray()); + return new RestaurantListingElementCollection($restaurantsDto->toArray()); } } diff --git a/app/src/Restaurants/Request/RestaurantCreateRequest.php b/app/src/Restaurants/Request/RestaurantCreateRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..c35a7bf5575543c84f6740df1a470eddd7ab4178 --- /dev/null +++ b/app/src/Restaurants/Request/RestaurantCreateRequest.php @@ -0,0 +1,89 @@ +restaurants ->getCountWithFilters( @@ -86,7 +92,9 @@ class RestaurantPrepareRequestService * @throws JsonException */ public - function bornDetailElement(RestaurantDetailRequest $request): RestaurantDetailElementDto { + function bornDetailElement( + RestaurantDetailRequest $request + ): RestaurantDetailElementDto { $restaurant = $this->restaurants->find($request->detailId); if ($restaurant === null) { @@ -95,4 +103,33 @@ class RestaurantPrepareRequestService return $this->detailFactory->create($restaurant); } + + public function unbirth( + RestaurantDetailRequest $request + ) { + $restaurants = $this->restaurants->find($request->detailId); + if ($restaurants === null) { + throw new NotFoundError('Restaurant not found'); + } + + $this->restaurants->remove($restaurants); + } + + public function rebirth(RestaurantPartUpdateRequest $request): void + { + $news = $this->entityFactory->hardUpdate($request); + $this->restaurants->createUpdate($news); + } + + public function reborn(RestaurantFullUpdateRequest $request): void + { + $news = $this->entityFactory->softUpdate($request); + $this->restaurants->createUpdate($news); + } + + public function birth(RestaurantCreateRequest $request): void + { + $news = $this->entityFactory->create($request); + $this->restaurants->createUpdate($news); + } } diff --git a/app/src/Restaurants/UseCase/RestaurantCreateUseCase.php b/app/src/Restaurants/UseCase/RestaurantCreateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..4f0a2b599897158443e108fa93d22a668c82772a --- /dev/null +++ b/app/src/Restaurants/UseCase/RestaurantCreateUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->birth($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/Restaurants/UseCase/RestaurantDeleteUseCase.php b/app/src/Restaurants/UseCase/RestaurantDeleteUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..f47f24074744aae3cdab5b440208ddeeb980d00c --- /dev/null +++ b/app/src/Restaurants/UseCase/RestaurantDeleteUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->unbirth($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/Restaurants/UseCase/RestaurantFullUpdateUseCase.php b/app/src/Restaurants/UseCase/RestaurantFullUpdateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..0018b0541e2face8186942d633e40251d16b54c8 --- /dev/null +++ b/app/src/Restaurants/UseCase/RestaurantFullUpdateUseCase.php @@ -0,0 +1,27 @@ +prepareRequestService->reborn($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/Restaurants/UseCase/RestaurantGetDetailUseCase.php b/app/src/Restaurants/UseCase/RestaurantGetDetailUseCase.php index e36941547087cac0b72f8c777f3d35bfce79ebca..513478e4a4f7ac60188580b28ce5aad2c8d2d7af 100644 --- a/app/src/Restaurants/UseCase/RestaurantGetDetailUseCase.php +++ b/app/src/Restaurants/UseCase/RestaurantGetDetailUseCase.php @@ -3,7 +3,7 @@ namespace App\Restaurants\UseCase; use App\Restaurants\Request\RestaurantDetailRequest; -use App\Restaurants\Service\RestaurantPrepareRequestService; +use App\Restaurants\Service\RestaurantPrepareResponseService; use App\Shared\DtoFactory\ErrorDtoFactory; use App\Shared\Error\NotFoundError; use Symfony\Component\HttpFoundation\JsonResponse; @@ -13,7 +13,7 @@ use Throwable; class RestaurantGetDetailUseCase { public function __construct( - private readonly RestaurantPrepareRequestService $responsePrepareService, + private readonly RestaurantPrepareResponseService $responsePrepareService, private readonly ErrorDtoFactory $errorFactory, ) { } diff --git a/app/src/Restaurants/UseCase/RestaurantGetListingUseCase.php b/app/src/Restaurants/UseCase/RestaurantGetListingUseCase.php index 2b34a0318b47383f245b3f8d4b7ee87d584dc6fd..1dc52cb19b9def21aa020f8f8c10181511ce1f59 100644 --- a/app/src/Restaurants/UseCase/RestaurantGetListingUseCase.php +++ b/app/src/Restaurants/UseCase/RestaurantGetListingUseCase.php @@ -3,7 +3,7 @@ namespace App\Restaurants\UseCase; use App\Restaurants\Request\RestaurantListingRequest; -use App\Restaurants\Service\RestaurantPrepareRequestService; +use App\Restaurants\Service\RestaurantPrepareResponseService; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Throwable; @@ -11,11 +11,12 @@ use Throwable; class RestaurantGetListingUseCase { public function __construct( - private readonly RestaurantPrepareRequestService $prepareRequestService, + private readonly RestaurantPrepareResponseService $prepareRequestService, ) { } - public function execute(RestaurantListingRequest $request): JsonResponse { + public function execute(RestaurantListingRequest $request): JsonResponse + { try { return new JsonResponse( $this->prepareRequestService->bornListDto($request) diff --git a/app/src/Restaurants/UseCase/RestaurantPartUpdateUseCase.php b/app/src/Restaurants/UseCase/RestaurantPartUpdateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..38221e7555cbafe77692e52d5d2e567068df7bbe --- /dev/null +++ b/app/src/Restaurants/UseCase/RestaurantPartUpdateUseCase.php @@ -0,0 +1,29 @@ +prepareRequestService->rebirth($request); + return new Response(); + } catch (Throwable) { + return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/app/src/Shared/Abstraction/AbstractRequest.php b/app/src/Shared/Abstraction/AbstractRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..79d0051c98768a3f772ca8f6225b6526e3a7351b --- /dev/null +++ b/app/src/Shared/Abstraction/AbstractRequest.php @@ -0,0 +1,62 @@ +populate(); + + if ($this->autoValidate) { + $this->validate(); + } + } + + protected function populate(): void + { + foreach ($this->getRequest()->toArray() as $property => $value) { + if (property_exists($this, $property)) { + $this->{$property} = $value; + } + } + } + + public function validate(): void + { + $errors = $this->validator->validate($this); + + $messages = new ValidationErrorCollection(); + + foreach ($errors as $error) { + $messages->add($this->errorDtoFactory->create($error)); + } + + if ($messages->count() > 0) { + $response = new JsonResponse($messages, 422); + $response->send(); + + throw new ValidatorException('Validation failed'); + } + } + + public function getRequest(): Request + { + return Request::createFromGlobals(); + } +} \ No newline at end of file diff --git a/app/src/Shared/Collection/ListingCollection.php b/app/src/Shared/Collection/ListingCollection.php deleted file mode 100644 index 9234de7c7b0f995f6d7451149ce31f361fab1005..0000000000000000000000000000000000000000 --- a/app/src/Shared/Collection/ListingCollection.php +++ /dev/null @@ -1,15 +0,0 @@ -collectionType, $data); - } -} diff --git a/app/src/Shared/Collection/ValidationErrorCollection.php b/app/src/Shared/Collection/ValidationErrorCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..4b328ed9a5a2ad91bb39b531c8e5a2588967c813 --- /dev/null +++ b/app/src/Shared/Collection/ValidationErrorCollection.php @@ -0,0 +1,15 @@ +collectionType, $data); + } +} \ No newline at end of file diff --git a/app/src/Shared/Entity/News.php b/app/src/Shared/Entity/News.php index d88a733362e78f0119bb8c0c6f08a167f536367d..8d891bab739883933b73e7dab5885b554c588535 100644 --- a/app/src/Shared/Entity/News.php +++ b/app/src/Shared/Entity/News.php @@ -3,12 +3,14 @@ namespace App\Shared\Entity; use App\Shared\Repository\NewsRepository; +use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: NewsRepository::class)] +#[ORM\HasLifecycleCallbacks] class News { #[ORM\Id] @@ -242,4 +244,17 @@ class News return $this; } -} + + #[ORM\PrePersist] + public function setCreatedAtValue(): void + { + $this->createdAt = new DateTimeImmutable(); + $this->updateAt = new DateTimeImmutable(); + } + + #[ORM\PreUpdate] + public function setUpdateAtValue(): void + { + $this->updateAt = new DateTimeImmutable(); + } +} \ No newline at end of file diff --git a/app/src/Shared/Entity/Restaurants.php b/app/src/Shared/Entity/Restaurants.php index 11033eb315b16404f82679979c1883c6dbafa086..444ead42da26e5eb22d63034898d98955518113b 100644 --- a/app/src/Shared/Entity/Restaurants.php +++ b/app/src/Shared/Entity/Restaurants.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: RestaurantsRepository::class)] +#[ORM\HasLifecycleCallbacks] class Restaurants { #[ORM\Id] @@ -393,4 +394,17 @@ class Restaurants return $this; } + + #[ORM\PrePersist] + public function setCreatedAtValue(): void + { + $this->createdAt = new DateTimeImmutable(); + $this->updateAt = new DateTimeImmutable(); + } + + #[ORM\PreUpdate] + public function setUpdateAtValue(): void + { + $this->updateAt = new DateTimeImmutable(); + } } diff --git a/app/src/Shared/EntityFactory/NewsEntityFactory.php b/app/src/Shared/EntityFactory/NewsEntityFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..c4a84143b0b2f56400e02eea2077040e81cefe0d --- /dev/null +++ b/app/src/Shared/EntityFactory/NewsEntityFactory.php @@ -0,0 +1,120 @@ + */ + private readonly Collection $newsSetters; + + public function __construct( + private readonly NewsRepository $newsRepository, + private readonly NewsTypeRepository $newsTypeRepository, + private readonly NewsCategoriesRepository $categoriesRepository, + private readonly FileRepository $fileRepository, + ) { + $this->newsSetters = $this->setNewsSetters(); + } + + public function create(NewsCreateRequest $request): News + { + $news = new News(); + $news->setId(Uuid::uuid4()->toString()); + + foreach ($request as $key => $value) { + if ($value !== null) { + $this->newsSetters[$key]($value, $news); + } + } + + return $news; + } + + public function softUpdate(NewsFullUpdateRequest $request): News + { + $news = $this->newsRepository->find($request->id) ?? new News(); + + foreach ($request as $key => $value) { + if ($value !== null) { + $this->newsSetters[$key]($value, $news); + } + } + + return $news; + } + + public function hardUpdate(NewsPartUpdateRequest $request): News + { + $news = $this->newsRepository->find($request->id); + + if ($news === null) { + throw new NotFoundError('News entity for update not found'); + } + + foreach ($request as $key => $value) { + if ($value !== null) { + $this->newsSetters[$key]($value, $news); + } + } + + return $news; + } + + /** @return Collection */ + private function setNewsSetters(): Collection + { + $newsSetters = new Collection('callable'); + + $newsSetters['id'] = function (string $id, News $news) { + $news->setId($id); + }; + $newsSetters['name'] = function (string $value, News $news) { + $news->setName($value); + }; + $newsSetters['code'] = function (string $value, News $news) { + $news->setCode($value); + }; + $newsSetters['active'] = function (bool $value, News $news) { + $news->setActive($value); + }; + $newsSetters['main_page_render'] = function (bool $value, News $news) { + $news->setMainPageRender($value); + }; + $newsSetters['preview_text'] = function (string $value, News $news) { + $news->setPreviewText($value); + }; + $newsSetters['detail_text'] = function (string $value, News $news) { + $news->setDetailText($value); + }; + $newsSetters['type_id'] = function (string $id, News $news) { + $news->setType($this->newsTypeRepository->find($id)); + }; + $newsSetters['categories_id'] = function (Collection $ids, News $news) { + foreach ($ids as $id) { + $news->addCategory( + $this->categoriesRepository->find($id) + ); + } + }; + $newsSetters['detail_image'] = function (string $id, News $news) { + $news->setDetailImage($this->fileRepository->find($id)); + }; + $newsSetters['preview_image'] = function (string $id, News $news) { + $news->setPreviewImage($this->fileRepository->find($id)); + }; + + return $newsSetters; + } +} diff --git a/app/src/Shared/EntityFactory/RestaurantEntityFactory.php b/app/src/Shared/EntityFactory/RestaurantEntityFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..e0e8c8a8cd50371abe286fadc5b9ef609c81c516 --- /dev/null +++ b/app/src/Shared/EntityFactory/RestaurantEntityFactory.php @@ -0,0 +1,195 @@ + */ + private readonly Collection $restaurantSetters; + + public function __construct( + private readonly RestaurantsRepository $restaurantsRepository, + private readonly RestaurantTypesRepository $restaurantTypesRepository, + private readonly SettlementsRepository $settlementsRepository, + private readonly FileRepository $fileRepository, + private readonly KitchensRepository $kitchensRepository, + ) { + $this->restaurantSetters = $this->setRestaurantSetters(); + } + + public function create(RestaurantCreateRequest $request): Restaurants + { + $restaurants = new Restaurants(); + $restaurants->setId(Uuid::uuid4()->toString()); + + foreach ($request as $key => $value) { + if ($value !== null) { + $this->restaurantSetters[$key]($value, $restaurants); + } + } + + return $restaurants; + } + + public function softUpdate(RestaurantFullUpdateRequest $request + ): Restaurants { + $restaurants = $this->restaurantsRepository->find( + $request->id + ) ?? new Restaurants(); + + foreach ($request as $key => $value) { + if ($value !== null) { + $this->restaurantSetters[$key]($value, $restaurants); + } + } + + return $restaurants; + } + + public function hardUpdate(RestaurantPartUpdateRequest $request + ): Restaurants { + $restaurant = $this->restaurantsRepository->find($request->id); + + if ($restaurant === null) { + throw new NotFoundError('News entity for update not found'); + } + + foreach ($request as $key => $value) { + if ($value !== null) { + $this->restaurantSetters[$key]($value, $restaurant); + } + } + + return $restaurant; + } + + /** @return Collection */ + private function setRestaurantSetters(): Collection + { + $setters = new Collection('callable'); + + $setters['id'] = function (string $value, Restaurants $restaurant) { + $restaurant->setId($value); + }; + $setters['type_id'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setType( + $this->restaurantTypesRepository->find($value) + ); + }; + $setters['settlement_id'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setSettlement( + $this->settlementsRepository->find($value) + ); + }; + $setters['preview_image_id'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setPreviewImage($this->fileRepository->find($value)); + }; + $setters['detail_image_id'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setDetailImage($this->fileRepository->find($value)); + }; + $setters['active'] = function (bool $value, Restaurants $restaurant) { + $restaurant->setActive($value); + }; + $setters['name'] = function (string $value, Restaurants $restaurant) { + $restaurant->setName($value); + }; + $setters['code'] = function (string $value, Restaurants $restaurant) { + $restaurant->setCode($value); + }; + $setters['description'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setDescription($value); + }; + $setters['check'] = function (string $value, Restaurants $restaurant) { + $restaurant->setReceipt($value); + }; + $setters['check_info'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setReceiptInfo($value); + }; + $setters['phone'] = function (string $value, Restaurants $restaurant) { + $restaurant->setPhone($value); + }; + $setters['email'] = function (string $value, Restaurants $restaurant) { + $restaurant->setEmail($value); + }; + $setters['address'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setAddress($value); + }; + $setters['tags'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setTags($value); + }; + $setters['site'] = function (string $value, Restaurants $restaurant) { + $restaurant->setSite($value); + }; + $setters['coordinates'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setCoordinates($value); + }; + $setters['how_to_find'] = function ( + string $value, + Restaurants $restaurant + ) { + $restaurant->setHowToFind($value); + }; + $setters['kitchens_id'] = function ( + Collection $ids, + Restaurants $restaurant + ) { + foreach ($ids as $id) { + $restaurant->addKitchen( + $this->kitchensRepository->find($id) + ); + } + }; + $setters['gallery_id'] = function ( + Collection $ids, + Restaurants $restaurant + ) { + foreach ($ids as $id) { + $restaurant->addGallery( + $this->fileRepository->find($id) + ); + } + }; + + return $setters; + } +} \ No newline at end of file diff --git a/app/src/Shared/EventListener/NewsPerCreate.php b/app/src/Shared/EventListener/NewsPerCreate.php new file mode 100644 index 0000000000000000000000000000000000000000..ffb29c0e440a1804e13bce8997c9a40b70d1d029 --- /dev/null +++ b/app/src/Shared/EventListener/NewsPerCreate.php @@ -0,0 +1,28 @@ +getSort() === null) { + $news->setSort($this->newsRepository->getMaxValueSort() + 1); + } + + if ($news->isMainPageRender()) { + $mainNews = $this->newsRepository->getMainNews(); + $mainNews?->setMainPageRender(false); + } + } +} diff --git a/app/src/Shared/EventListener/RestaurantPerCreate.php b/app/src/Shared/EventListener/RestaurantPerCreate.php new file mode 100644 index 0000000000000000000000000000000000000000..72f17297dc346b94f25092da5490f58dc858291c --- /dev/null +++ b/app/src/Shared/EventListener/RestaurantPerCreate.php @@ -0,0 +1,25 @@ +getSort() === null) { + $restaurant->setSort($this->restaurantsRepository->getMaxValueSort() + 1); + } + } +} diff --git a/app/src/Shared/Repository/NewsRepository.php b/app/src/Shared/Repository/NewsRepository.php index 4dfe2295098538879780a447dec6589198550bb4..d7b05bb576403e7fae4712e5dde81a5feaf334f0 100644 --- a/app/src/Shared/Repository/NewsRepository.php +++ b/app/src/Shared/Repository/NewsRepository.php @@ -24,13 +24,42 @@ class NewsRepository extends ServiceEntityRepository parent::__construct($registry, News::class); } - public function getMainNews(): News + public function createUpdate(News $news): void + { + $entityManager = $this->getEntityManager(); + $entityManager->persist($news); + $entityManager->flush(); + $entityManager->clear(); + } + + public function remove(News $news): void + { + $this->getEntityManager()->remove($news); + $this->getEntityManager()->flush(); + $this->getEntityManager()->clear(); + } + + public function getMaxValueSort(): ?int { return $this->createQueryBuilder('n') + ->select('MAX(n.sort)') + ->getQuery() + ->getSingleScalarResult(); + } + + public function getMainNews(): ?News + { + $mainNews = $this->createQueryBuilder('n') ->andWhere('n.mainPageRender = true') ->setMaxResults(1) ->getQuery() - ->getResult()[0]; + ->getResult(); + + if ($mainNews === []) { + return null; + } + + return $mainNews[0]; } public function getCountWithFilters(?string $categoryId): int diff --git a/app/src/Shared/Repository/RestaurantsRepository.php b/app/src/Shared/Repository/RestaurantsRepository.php index 48eef29c71b89a3ab453955aaec6e357fc71e6fd..ab72e3ef43de8a159c81efe96664dc067435f88a 100644 --- a/app/src/Shared/Repository/RestaurantsRepository.php +++ b/app/src/Shared/Repository/RestaurantsRepository.php @@ -24,6 +24,28 @@ class RestaurantsRepository extends ServiceEntityRepository parent::__construct($registry, Restaurants::class); } + public function createUpdate(Restaurants $restaurants): void + { + $this->getEntityManager()->persist($restaurants); + $this->getEntityManager()->flush(); + $this->getEntityManager()->clear(); + } + + public function remove(Restaurants $restaurants): void + { + $this->getEntityManager()->remove($restaurants); + $this->getEntityManager()->flush(); + $this->getEntityManager()->clear(); + } + + public function getMaxValueSort(): ?int + { + return $this->createQueryBuilder('r') + ->select('MAX(r.sort)') + ->getQuery() + ->getSingleScalarResult(); + } + /** @return Collection */ protected function toCollection(QueryBuilder $query): Collection {