From a8daee4289e9d9b0be12669be839137636a62ad7 Mon Sep 17 00:00:00 2001 From: janpalen Date: Tue, 17 Dec 2024 09:31:12 +0100 Subject: [PATCH] OP-550 - Fix displaying products in shop page --- .../Product/AddToCartFormComponent.php | 130 ++++++++++++++ src/Controller/OrderItemController.php | 169 ------------------ src/EventListener/CartItemAddListener.php | 34 ++++ .../AddProductBundleToCartDtoFactory.php | 8 +- src/Resources/config/services.xml | 1 + .../config/services/event_listener.xml | 8 + src/Resources/config/services/product.xml | 32 ++++ .../config/twig_hooks/product/shop/show.yaml | 7 +- .../addProductBundleToCart.html.twig | 41 ++--- src/Validator/HasProductBundleValidator.php | 6 - .../Product/Show/_inventory.html.twig | 9 - 11 files changed, 232 insertions(+), 213 deletions(-) create mode 100644 src/Component/Product/AddToCartFormComponent.php delete mode 100644 src/Controller/OrderItemController.php create mode 100644 src/EventListener/CartItemAddListener.php create mode 100644 src/Resources/config/services/product.xml delete mode 100644 tests/Application/templates/bundles/SyliusShopBundle/Product/Show/_inventory.html.twig diff --git a/src/Component/Product/AddToCartFormComponent.php b/src/Component/Product/AddToCartFormComponent.php new file mode 100644 index 00000000..36d12082 --- /dev/null +++ b/src/Component/Product/AddToCartFormComponent.php @@ -0,0 +1,130 @@ + $cartItemFactory + * @param class-string $formClass + * @param ProductRepositoryInterface $productRepository + * @param ProductVariantRepositoryInterface $productVariantRepository + */ + public function __construct( + private readonly FormFactoryInterface $formFactory, + private readonly ObjectManager $manager, + private readonly RouterInterface $router, + private readonly RequestStack $requestStack, + private readonly EventDispatcherInterface $eventDispatcher, + private readonly CartContextInterface $cartContext, + private readonly AddToCartCommandFactory $addToCartCommandFactory, + private readonly CartItemFactoryInterface $cartItemFactory, + private readonly string $formClass, + ProductRepositoryInterface $productRepository, + ProductVariantRepositoryInterface $productVariantRepository, + private readonly AddProductBundleToCartDtoFactory $addProductBundleToCartDtoFactory, + + ) { + $this->initializeProduct($productRepository); + $this->initializeProductVariant($productVariantRepository); + + parent::__construct($this->formFactory, + $this->manager, + $this->router, + $this->requestStack, + $this->eventDispatcher, + $this->cartContext, + $this->addToCartCommandFactory, + $this->cartItemFactory, + $this->formClass, + $this->productRepository, + $this->productVariantRepository, + ); + } + + #[LiveAction] + public function addToCart(): RedirectResponse + { + $this->submitForm(); + $addToCartCommand = $this->getForm()->getData(); + + $this->eventDispatcher->dispatch(new GenericEvent($addToCartCommand), SyliusCartEvents::CART_ITEM_ADD); + $this->manager->persist($addToCartCommand->getCart()); + $this->manager->flush(); + + FlashBagProvider + ::getFlashBag($this->requestStack) + ->add('success', 'sylius.cart.add_item'); + + return new RedirectResponse($this->router->generate( + $this->routeName, + $this->routeParameters, + )); + } + + protected function instantiateForm(): FormInterface + { + /** @var OrderItemInterface $orderItem */ + $orderItem = $this->cartItemFactory->createForProduct($this->product); + /** @var null|ProductInterface $orderProduct */ + $orderProduct = $orderItem->getProduct(); + + $addToCartCommand = $this->addProductBundleToCartDtoFactory->createNew( + $this->cartContext->getCart(), + $orderItem, + $orderProduct, + ); + + return $this->formFactory->create($this->formClass, $addToCartCommand, ['product' => $this->product]); + } +} diff --git a/src/Controller/OrderItemController.php b/src/Controller/OrderItemController.php deleted file mode 100644 index 386a0fbc..00000000 --- a/src/Controller/OrderItemController.php +++ /dev/null @@ -1,169 +0,0 @@ -getCurrentCart(); - $configuration = $this->requestConfigurationFactory->create($this->metadata, $request); - - $this->isGrantedOr403($configuration, CartActions::ADD); - - /** @var OrderItemInterface $orderItem */ - $orderItem = $this->newResourceFactory->create($configuration, $this->factory); - - $this->getQuantityModifier()->modify($orderItem, 1); - - /** @var ProductInterface $product */ - $product = $orderItem->getProduct(); - assert(null !== $configuration->getFormType()); - - $addProductBundleToCartDto = $this->addProductBundleToCartDtoFactory->createNew($cart, $orderItem, $product); - $form = $this->getFormFactory()->create( - $configuration->getFormType(), - $addProductBundleToCartDto, - $configuration->getFormOptions(), - ); - - if ($request->isMethod(Request::METHOD_POST) && $form->handleRequest($request)->isValid()) { - return $this->handleForm($form, $configuration, $orderItem, $request); - } - - if (!$configuration->isHtmlRequest()) { - return $this->handleBadAjaxRequestView($configuration, $form); - } - - return $this->render( - $configuration->getTemplate(CartActions::ADD . '.html'), - [ - 'configuration' => $configuration, - $this->metadata->getName() => $orderItem, - 'form' => $form->createView(), - ], - ); - } - - private function handleForm( - FormInterface $form, - Controller\RequestConfiguration $configuration, - OrderItemInterface $orderItem, - Request $request, - ): ?Response { - /** @var AddProductBundleToCartDto $addProductBundleToCartDto */ - $addProductBundleToCartDto = $form->getData(); - - $errors = $this->getCartItemErrors($addProductBundleToCartDto->getCartItem()); - if (0 < count($errors)) { - $form = $this->getAddToCartFormWithErrors($errors, $form); - - return $this->handleBadAjaxRequestView($configuration, $form); - } - $event = $this->eventDispatcher->dispatchPreEvent(CartActions::ADD, $configuration, $orderItem); - if ($event->isStopped() && !$configuration->isHtmlRequest()) { - throw new HttpException($event->getErrorCode(), $event->getMessage()); - } - if ($event->isStopped()) { - $this->flashHelper->addFlashFromEvent($configuration, $event); - - return $this->redirectHandler->redirectToIndex($configuration, $orderItem); - } - - $cart = $addProductBundleToCartDto->getCart(); - if (null === $cart->getId()) { - $this->orderRepository->add($cart); - } - - $addProductBundleToCartCommand = $this->addProductBundleToCartCommandFactory->createFromDto($addProductBundleToCartDto); - $this->messageBus->dispatch($addProductBundleToCartCommand); - - $resourceControllerEvent = $this->eventDispatcher->dispatchPostEvent(CartActions::ADD, $configuration, $orderItem); - if ($resourceControllerEvent->hasResponse()) { - return $resourceControllerEvent->getResponse(); - } - $this->flashHelper->addSuccessFlash($configuration, CartActions::ADD, $orderItem); - - if ($request->isXmlHttpRequest()) { - assert(null !== $this->viewHandler); - $response = $this->viewHandler->handle($configuration, View::create([], Response::HTTP_CREATED)); - } else { - $response = $this->redirectHandler->redirectToResource($configuration, $orderItem); - } - - return $response; - } -} diff --git a/src/EventListener/CartItemAddListener.php b/src/EventListener/CartItemAddListener.php new file mode 100644 index 00000000..f7c0e426 --- /dev/null +++ b/src/EventListener/CartItemAddListener.php @@ -0,0 +1,34 @@ +getSubject(); + + Assert::isInstanceOf($addToCartCommand, AddProductBundleToCartDtoInterface::class); + + $this->orderModifier->addToOrder($addToCartCommand->getCart(), $addToCartCommand->getCartItem()); + } +} diff --git a/src/Factory/AddProductBundleToCartDtoFactory.php b/src/Factory/AddProductBundleToCartDtoFactory.php index b98af5d6..93184a29 100644 --- a/src/Factory/AddProductBundleToCartDtoFactory.php +++ b/src/Factory/AddProductBundleToCartDtoFactory.php @@ -41,12 +41,14 @@ public function createNew( /** * @return AddProductBundleItemToCartCommand[] */ - private function getProcessedProductBundleItems(ProductBundleInterface $productBundle): array + private function getProcessedProductBundleItems(?ProductBundleInterface $productBundle): array { $addProductBundleItemToCartCommands = []; - foreach ($productBundle->getProductBundleItems() as $bundleItem) { - $addProductBundleItemToCartCommands[] = $this->addProductBundleItemToCartCommandFactory->createNew($bundleItem); + if (null !== $productBundle) { + foreach ($productBundle->getProductBundleItems() as $bundleItem) { + $addProductBundleItemToCartCommands[] = $this->addProductBundleItemToCartCommandFactory->createNew($bundleItem); + } } return $addProductBundleItemToCartCommands; diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 0c4f960c..84881c38 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -12,5 +12,6 @@ + diff --git a/src/Resources/config/services/event_listener.xml b/src/Resources/config/services/event_listener.xml index 797d027c..d144ab7f 100644 --- a/src/Resources/config/services/event_listener.xml +++ b/src/Resources/config/services/event_listener.xml @@ -6,5 +6,13 @@ + + + + + diff --git a/src/Resources/config/services/product.xml b/src/Resources/config/services/product.xml new file mode 100644 index 00000000..b299279e --- /dev/null +++ b/src/Resources/config/services/product.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + BitBag\SyliusProductBundlePlugin\Form\Type\AddProductBundleToCartType + + + + + + + + + + + + + + diff --git a/src/Resources/config/twig_hooks/product/shop/show.yaml b/src/Resources/config/twig_hooks/product/shop/show.yaml index d8b9d997..1aaea89b 100644 --- a/src/Resources/config/twig_hooks/product/shop/show.yaml +++ b/src/Resources/config/twig_hooks/product/shop/show.yaml @@ -2,5 +2,8 @@ sylius_twig_hooks: hooks: 'sylius_shop.product.show.content.info.summary.add_to_cart': bundle: - template: "@BitBagSyliusProductBundlePlugin/Shop/product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig" - priority: 20 + component: 'sylius_shop:product:add_to_cart_form' + props: + product: '@=_context.product' + template: '@BitBagSyliusProductBundlePlugin/Shop/product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig' + priority: 20 diff --git a/src/Resources/views/Shop/Product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig b/src/Resources/views/Shop/Product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig index 89831d37..e2ad2ba3 100644 --- a/src/Resources/views/Shop/Product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig +++ b/src/Resources/views/Shop/Product/show/page/info/summary/add_to_cart/addProductBundleToCart.html.twig @@ -1,29 +1,22 @@ -{#{% if hookable_metadata.context.resource is defined %}#} -{{ dump() }} - {% set product = hookable_metadata.context.resource %} - {% if product.isBundle %} - {% set form = hookable_metadata.context.form %} - {% set configuration = hookable_metadata.context.configuration %} - {% set product_bundle_items = form.productBundleItems %} +{% form_theme form '@SyliusShop/Form/theme.html.twig' %} - {% form_theme form '@SyliusShop/Form/theme.html.twig' %} - -
-

{{ 'bitbag_sylius_product_bundle.ui.products_in_bundle'|trans }}

- {% for item in product_bundle_items %} - {% set data = item.vars.data %} -
-
- - {{ data.quantity }} x {{ data.productVariant.product.name }} - +{% if product.isBundle %} + {% set product_bundle_items = form.productBundleItems %} +
+

{{ 'bitbag_sylius_product_bundle.ui.products_in_bundle'|trans }}

+ {% for item in product_bundle_items %} + {% set data = item.vars.data %} +
+
+ + {{ data.quantity }} x {{ data.productVariant.product.name }} + {% if item.productVariant is defined %} {{ form_row(item.productVariant) }} {% endif %} -
- {% endfor %} -
-
- {% endif %} -{#{% endif %}#} +
+ {% endfor %} +
+
+{% endif %} diff --git a/src/Validator/HasProductBundleValidator.php b/src/Validator/HasProductBundleValidator.php index 50f79d32..083f82d6 100644 --- a/src/Validator/HasProductBundleValidator.php +++ b/src/Validator/HasProductBundleValidator.php @@ -46,11 +46,5 @@ public function validate($value, Constraint $constraint): void return; } - - if (!$product->isBundle()) { - $this->context->addViolation(HasProductBundle::NOT_A_BUNDLE_MESSAGE); - - return; - } } } diff --git a/tests/Application/templates/bundles/SyliusShopBundle/Product/Show/_inventory.html.twig b/tests/Application/templates/bundles/SyliusShopBundle/Product/Show/_inventory.html.twig deleted file mode 100644 index 31efa961..00000000 --- a/tests/Application/templates/bundles/SyliusShopBundle/Product/Show/_inventory.html.twig +++ /dev/null @@ -1,9 +0,0 @@ -{% if product.variants.empty() or product.simple and not sylius_inventory_is_available(product.variants.first) %} - {% include '@SyliusShop/Product/Show/_outOfStock.html.twig' %} -{% else %} - {% if product.isBundle %} - {{ render(url('bitbag_sylius_product_bundle_shop_partial_cart_add_product_bundle', {'template': '@BitBagSyliusProductBundlePlugin/Shop/Product/_addProductBundleToCart.html.twig', 'productId': product.id})) }} - {% else %} - {{ render(url('sylius_shop_partial_cart_add_item', {'template': '@SyliusShop/Product/Show/_addToCart.html.twig', 'productId': product.id})) }} - {% endif %} -{% endif %}