Skip to content

Commit ea60888

Browse files
committed
HM-1: Fix for adding product variant
1 parent d37d53e commit ea60888

38 files changed

+655
-113
lines changed

config/app/twig_hooks/base.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ sylius_twig_hooks:
22
hooks:
33
'sylius_shop.base.header.content':
44
wishlist_header:
5-
template: '@SyliusWishlistPlugin/_wishlist_header.html.twig'
5+
template: '@SyliusWishlistPlugin/wishlist_header.html.twig'
66
priority: 150

config/app/twig_hooks/product/show.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ sylius_twig_hooks:
22
hooks:
33
'sylius_shop.product.show.content.info.summary':
44
add_to_wishlist:
5-
template: '@SyliusWishlistPlugin/Common/_addToWishlist.html.twig'
5+
component: 'sylius_shop:product:add_to_wishlist'
6+
props:
7+
product: '@=_context.product'
8+
template: '@SyliusWishlistPlugin/product/show/add_to_wishlist.html.twig'
69
priority: 10
7-
'sylius_shop.product.show.content.info.summary.add_to_wishlist':
8-
add_to_wishlist:
9-
template: '@SyliusWishlistPlugin/Common/AddToWishlist/_button.html.twig'

config/routes/shop.yaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ wishlist_remove_selected_products:
2525
defaults:
2626
_controller: sylius_wishlist_plugin.controller.action.remove_selected_products_from_wishlist
2727

28-
wishlist_add_product_variant:
29-
path: /wishlist/{wishlistId}/add/variant/{variantId}
30-
defaults:
31-
_controller: sylius_wishlist_plugin.controller.action.add_product_variant_to_wishlist
32-
3328
wishlist_add_selected_products:
3429
path: /wishlist/{wishlistId}/products/add
3530
defaults:

config/services/form.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,10 @@
2626
<argument type="service" id="sylius_wishlist_plugin.processor.selected_wishlist_products_processor"/>
2727
<tag name="form.type"/>
2828
</service>
29+
30+
<service id="sylius.wishlist_plugin.form.type.add_to_wishlist_type" class="Sylius\WishlistPlugin\Form\Type\AddToWishlistType">
31+
<argument type="service" id="sylius_wishlist_plugin.resolver.wishlists_resolver"/>
32+
<tag name="form.type"/>
33+
</service>
2934
</services>
3035
</container>

config/services/processor.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,16 @@
1212
<service id="sylius_wishlist_plugin.processor.variant_pdf_model_processor" class="Sylius\WishlistPlugin\Processor\VariantPdfModelProcessor">
1313
<argument type="service" id="sylius_wishlist_plugin.services.generator.model_creator"/>
1414
</service>
15+
16+
<service id="sylius.wishlist_plugin.processor.add_product_variant_to_wishlist" class="Sylius\WishlistPlugin\Processor\AddProductVariantToWishlistProcessor">
17+
<argument type="service" id="security.helper"/>
18+
<argument type="service" id="sylius_wishlist_plugin.twig.extension.wishlist_extension"/>
19+
<argument type="service" id="sylius.context.channel"/>
20+
<argument type="service" id="sylius_wishlist_plugin.factory.wishlist_product"/>
21+
<argument type="service" id="request_stack"/>
22+
<argument type="service" id="translator"/>
23+
<argument type="service" id="router"/>
24+
<argument type="service" id="sylius_wishlist_plugin.repository.wishlist"/>
25+
</service>
1526
</services>
1627
</container>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<!--
4+
~ This file is part of the Sylius package.
5+
~
6+
~ (c) Sylius Sp. z o.o.
7+
~
8+
~ For the full copyright and license information, please view the LICENSE
9+
~ file that was distributed with this source code.
10+
-->
11+
12+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
13+
<services>
14+
<service
15+
id="sylius.wishlist_plugin.twig.component.product.add_to_wishlist"
16+
class="Sylius\WishlistPlugin\Twig\Component\Product\AddToWishlistComponent"
17+
>
18+
<argument type="service" id="sylius.wishlist_plugin.processor.add_product_variant_to_wishlist" />
19+
<argument type="service" id="form.factory" />
20+
<argument type="service" id="sylius.resolver.product_variant.default" />
21+
<argument type="service" id="sylius.repository.product" />
22+
<argument type="service" id="sylius.repository.product_variant" />
23+
24+
<tag name="sylius.live_component.shop" key="sylius_shop:product:add_to_wishlist"/>
25+
</service>
26+
</services>
27+
</container>

spec/Controller/Action/ListWishlistProductsActionSpec.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function it_lists_wishlist_items(
9595
$form->createView()->willReturn($formView);
9696
$twigEnvironment
9797
->render(
98-
'@SyliusWishlistPlugin/WishlistDetails/index.html.twig',
98+
'@SyliusWishlistPlugin/wishlist_details/index.html.twig',
9999
[
100100
'wishlist' => $wishlist,
101101
'form' => $formView,

spec/Controller/Action/RenderHeaderTemplateActionSpec.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function it_renders_header_template(
4444
): void {
4545
$wishlists = [];
4646
$wishlistsResolver->resolve()->willReturn($wishlists);
47-
$twigEnvironment->render('@SyliusWishlistPlugin/Common/widget.html.twig', [
47+
$twigEnvironment->render('@SyliusWishlistPlugin/common/widget.html.twig', [
4848
'wishlists' => $wishlists,
4949
])->willReturn('TEMPLATE');
5050
$this->__invoke($request)->shouldImplement(Response::class);

spec/Exporter/DomPdfWishlistExporterSpec.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function it_returns_pdf_as_attachment(
5454

5555
$html = '';
5656

57-
$twigEnvironment->render('@SyliusWishlistPlugin/_wishlist_pdf.html.twig', [
57+
$twigEnvironment->render('@SyliusWishlistPlugin/wishlist_pdf.html.twig', [
5858
'title' => 'My wishlist products',
5959
'date' => date('d.m.Y'),
6060
'products' => $data,
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace spec\Sylius\WishlistPlugin\Processor;
15+
16+
use PhpSpec\ObjectBehavior;
17+
use Sylius\Component\Channel\Context\ChannelContextInterface;
18+
use Sylius\Component\Core\Model\ChannelInterface;
19+
use Sylius\Component\Core\Model\ProductInterface;
20+
use Sylius\Component\Core\Model\ProductVariantInterface;
21+
use Sylius\Component\User\Model\UserInterface;
22+
use Sylius\WishlistPlugin\Entity\WishlistInterface;
23+
use Sylius\WishlistPlugin\Entity\WishlistProductInterface;
24+
use Sylius\WishlistPlugin\Factory\WishlistProductFactoryInterface;
25+
use Sylius\WishlistPlugin\Processor\AddProductVariantToWishlistProcessor;
26+
use Sylius\WishlistPlugin\Repository\WishlistRepositoryInterface;
27+
use Sylius\WishlistPlugin\Twig\WishlistExtension;
28+
use Symfony\Bundle\SecurityBundle\Security;
29+
use Symfony\Component\HttpFoundation\RedirectResponse;
30+
use Symfony\Component\HttpFoundation\RequestStack;
31+
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
32+
use Symfony\Component\HttpFoundation\Session\Session;
33+
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
34+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
35+
use Symfony\Contracts\Translation\TranslatorInterface;
36+
37+
final class AddProductVariantToWishlistProcessorSpec extends ObjectBehavior
38+
{
39+
public function let(
40+
Security $security,
41+
WishlistExtension $wishlistExtension,
42+
ChannelContextInterface $channelContext,
43+
WishlistProductFactoryInterface $wishlistProductFactory,
44+
RequestStack $requestStack,
45+
TranslatorInterface $translator,
46+
UrlGeneratorInterface $urlGenerator,
47+
WishlistRepositoryInterface $wishlistRepository,
48+
): void {
49+
$this->beConstructedWith(
50+
$security,
51+
$wishlistExtension,
52+
$channelContext,
53+
$wishlistProductFactory,
54+
$requestStack,
55+
$translator,
56+
$urlGenerator,
57+
$wishlistRepository,
58+
);
59+
}
60+
61+
public function it_is_initializable(): void
62+
{
63+
$this->shouldHaveType(AddProductVariantToWishlistProcessor::class);
64+
}
65+
66+
public function it_throws_resource_not_found_exception_when_wishlist_is_not_found_for_specific_id(
67+
Security $security,
68+
UserInterface $user,
69+
WishlistExtension $wishlistExtension,
70+
WishlistRepositoryInterface $wishlistRepository,
71+
ProductVariantInterface $productVariant,
72+
WishlistInterface $firstWishlist,
73+
WishlistInterface $secondWishlist,
74+
): void {
75+
$wishlistIdToFind = 999;
76+
77+
$security->getUser()->willReturn($user);
78+
$wishlistExtension->findAllByShopUserAndToken()->willReturn([$firstWishlist, $secondWishlist]);
79+
80+
$wishlistRepository->find($wishlistIdToFind)->willReturn(null);
81+
82+
$this->shouldThrow(ResourceNotFoundException::class)
83+
->during('process', [$productVariant, $wishlistIdToFind]);
84+
}
85+
86+
public function it_throws_error_if_no_wishlists_are_found_for_single_wishlist_scenario(
87+
Security $security,
88+
UserInterface $user,
89+
WishlistExtension $wishlistExtension,
90+
ProductVariantInterface $productVariant,
91+
): void {
92+
$security->getUser()->willReturn($user);
93+
94+
$wishlistExtension->findAllByShopUserAndToken()->willReturn([]);
95+
96+
$this->shouldThrow(ResourceNotFoundException::class)
97+
->during('process', [$productVariant, null]);
98+
}
99+
100+
public function it_adds_product_to_the_single_wishlist_for_logged_in_user(
101+
Security $security,
102+
UserInterface $user,
103+
WishlistExtension $wishlistExtension,
104+
WishlistProductFactoryInterface $wishlistProductFactory,
105+
RequestStack $requestStack,
106+
TranslatorInterface $translator,
107+
UrlGeneratorInterface $urlGenerator,
108+
WishlistRepositoryInterface $wishlistRepository,
109+
ProductVariantInterface $productVariant,
110+
WishlistInterface $wishlist,
111+
WishlistProductInterface $wishlistProduct,
112+
Session $session,
113+
FlashBagInterface $flashBag,
114+
): void {
115+
$wishlistId = 123;
116+
$wishlist->getId()->willReturn($wishlistId);
117+
118+
$security->getUser()->willReturn($user);
119+
$wishlistExtension->findAllByShopUserAndToken()->willReturn([$wishlist]);
120+
121+
$wishlist->hasProductVariant($productVariant)->willReturn(false);
122+
$wishlistProductFactory->createForWishlistAndVariant($wishlist, $productVariant)->willReturn($wishlistProduct);
123+
124+
$requestStack->getSession()->willReturn($session);
125+
$session->getFlashBag()->willReturn($flashBag);
126+
$translator->trans('sylius_wishlist_plugin.ui.added_wishlist_item')->willReturn('Product added.');
127+
$flashBag->add('success', 'Product added.')->shouldBeCalled();
128+
129+
$wishlist->addWishlistProduct($wishlistProduct)->shouldBeCalled();
130+
$wishlistRepository->add($wishlist)->shouldBeCalled();
131+
132+
$urlGenerator->generate('sylius_wishlist_plugin_shop_locale_wishlist_show_chosen_wishlist', ['wishlistId' => $wishlistId])
133+
->willReturn('/wishlist/' . $wishlistId);
134+
135+
$response = $this->process($productVariant);
136+
$response->shouldHaveType(RedirectResponse::class);
137+
$response->getTargetUrl()->shouldReturn('/wishlist/' . $wishlistId);
138+
}
139+
140+
public function it_adds_product_to_a_specific_wishlist_for_logged_in_user_with_multiple_wishlists(
141+
Security $security,
142+
UserInterface $user,
143+
WishlistExtension $wishlistExtension,
144+
WishlistProductFactoryInterface $wishlistProductFactory,
145+
RequestStack $requestStack,
146+
TranslatorInterface $translator,
147+
UrlGeneratorInterface $urlGenerator,
148+
WishlistRepositoryInterface $wishlistRepository,
149+
ProductVariantInterface $productVariant,
150+
WishlistInterface $targetWishlist,
151+
WishlistInterface $otherWishlist,
152+
WishlistProductInterface $wishlistProduct,
153+
Session $session,
154+
FlashBagInterface $flashBag,
155+
): void {
156+
$targetWishlistId = 789;
157+
$targetWishlist->getId()->willReturn($targetWishlistId);
158+
159+
$security->getUser()->willReturn($user);
160+
$wishlistExtension->findAllByShopUserAndToken()->willReturn([$otherWishlist, $targetWishlist]);
161+
162+
$wishlistRepository->find($targetWishlistId)->willReturn($targetWishlist);
163+
164+
$targetWishlist->hasProductVariant($productVariant)->willReturn(false);
165+
$wishlistProductFactory->createForWishlistAndVariant($targetWishlist, $productVariant)->willReturn($wishlistProduct);
166+
167+
$requestStack->getSession()->willReturn($session);
168+
$session->getFlashBag()->willReturn($flashBag);
169+
$translator->trans('sylius_wishlist_plugin.ui.added_wishlist_item')->willReturn('Product added to specific list.');
170+
$flashBag->add('success', 'Product added to specific list.')->shouldBeCalled();
171+
172+
$targetWishlist->addWishlistProduct($wishlistProduct)->shouldBeCalled();
173+
$wishlistRepository->add($targetWishlist)->shouldBeCalled();
174+
175+
$urlGenerator->generate('sylius_wishlist_plugin_shop_locale_wishlist_show_chosen_wishlist', ['wishlistId' => $targetWishlistId])
176+
->willReturn('/wishlist/' . $targetWishlistId);
177+
178+
$response = $this->process($productVariant, $targetWishlistId);
179+
$response->shouldHaveType(RedirectResponse::class);
180+
$response->getTargetUrl()->shouldReturn('/wishlist/' . $targetWishlistId);
181+
}
182+
183+
public function it_adds_product_to_the_single_wishlist_for_anonymous_user(
184+
Security $security,
185+
ChannelContextInterface $channelContext,
186+
ChannelInterface $channel,
187+
WishlistExtension $wishlistExtension,
188+
WishlistProductFactoryInterface $wishlistProductFactory,
189+
RequestStack $requestStack,
190+
TranslatorInterface $translator,
191+
UrlGeneratorInterface $urlGenerator,
192+
WishlistRepositoryInterface $wishlistRepository,
193+
ProductVariantInterface $productVariant,
194+
WishlistInterface $wishlist,
195+
WishlistProductInterface $wishlistProduct,
196+
Session $session,
197+
FlashBagInterface $flashBag,
198+
): void {
199+
$wishlistId = 456;
200+
$wishlist->getId()->willReturn($wishlistId);
201+
202+
$security->getUser()->willReturn(null);
203+
$channelContext->getChannel()->willReturn($channel);
204+
$wishlistExtension->findAllByAnonymousAndChannel($channel)->willReturn([$wishlist]);
205+
206+
$wishlist->hasProductVariant($productVariant)->willReturn(false);
207+
$wishlistProductFactory->createForWishlistAndVariant($wishlist, $productVariant)->willReturn($wishlistProduct);
208+
209+
$requestStack->getSession()->willReturn($session);
210+
$session->getFlashBag()->willReturn($flashBag);
211+
$translator->trans('sylius_wishlist_plugin.ui.added_wishlist_item')->willReturn('Product added (anonymous).');
212+
$flashBag->add('success', 'Product added (anonymous).')->shouldBeCalled();
213+
214+
$wishlist->addWishlistProduct($wishlistProduct)->shouldBeCalled();
215+
$wishlistRepository->add($wishlist)->shouldBeCalled();
216+
217+
$urlGenerator->generate('sylius_wishlist_plugin_shop_locale_wishlist_show_chosen_wishlist', ['wishlistId' => $wishlistId])
218+
->willReturn('/wishlist/anon/' . $wishlistId);
219+
220+
$response = $this->process($productVariant, null);
221+
$response->shouldHaveType(RedirectResponse::class);
222+
$response->getTargetUrl()->shouldReturn('/wishlist/anon/' . $wishlistId);
223+
}
224+
225+
public function it_adds_flash_error_if_product_variant_is_already_in_wishlist(
226+
Security $security,
227+
UserInterface $user,
228+
WishlistExtension $wishlistExtension,
229+
WishlistProductFactoryInterface $wishlistProductFactory,
230+
RequestStack $requestStack,
231+
TranslatorInterface $translator,
232+
UrlGeneratorInterface $urlGenerator,
233+
ProductVariantInterface $productVariant,
234+
ProductInterface $product,
235+
WishlistInterface $wishlist,
236+
WishlistProductInterface $wishlistProduct,
237+
Session $session,
238+
FlashBagInterface $flashBag,
239+
): void {
240+
$wishlistId = 123;
241+
$productName = 'Awesome T-Shirt';
242+
$wishlist->getId()->willReturn($wishlistId);
243+
$productVariant->getProduct()->willReturn($product);
244+
$wishlistProduct->getProduct()->willReturn($product);
245+
$product->getName()->willReturn($productName);
246+
247+
$security->getUser()->willReturn($user);
248+
$wishlistExtension->findAllByShopUserAndToken()->willReturn([$wishlist]);
249+
250+
$wishlist->hasProductVariant($productVariant)->willReturn(true);
251+
$wishlistProductFactory->createForWishlistAndVariant($wishlist, $productVariant)->willReturn($wishlistProduct);
252+
253+
$requestStack->getSession()->willReturn($session);
254+
$session->getFlashBag()->willReturn($flashBag);
255+
$translator->trans(
256+
'sylius_wishlist_plugin.ui.wishlist_has_product_variant',
257+
['%productName%' => $productName],
258+
)->willReturn('Product already in wishlist.');
259+
$flashBag->add('error', 'Product already in wishlist.')->shouldBeCalled();
260+
261+
$wishlist->addWishlistProduct($wishlistProduct)->shouldNotBeCalled();
262+
263+
$urlGenerator->generate('sylius_wishlist_plugin_shop_locale_wishlist_show_chosen_wishlist', ['wishlistId' => $wishlistId])
264+
->willReturn('/wishlist/' . $wishlistId);
265+
266+
$response = $this->process($productVariant, null);
267+
$response->shouldHaveType(RedirectResponse::class);
268+
$response->getTargetUrl()->shouldReturn('/wishlist/' . $wishlistId);
269+
}
270+
}

0 commit comments

Comments
 (0)