Skip to content

Commit

Permalink
Merge pull request #14 from RadnoK/clear-wishlists-on-login
Browse files Browse the repository at this point in the history
Clear wishlists on login
  • Loading branch information
bitbager authored Mar 14, 2019
2 parents 9f5cd7b + 7aff60f commit 5bc6c3c
Show file tree
Hide file tree
Showing 10 changed files with 565 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/vendor/
/node_modules/
/composer.lock
/phpspec.yml

/etc/build/*
!/etc/build/.gitignore
Expand Down
17 changes: 17 additions & 0 deletions features/clearing_wishlist_on_logout.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@wishlist
Feature: Clearing wishlist on logout
In order to not see other users wishlists
As a Visitor
I want to have cleared wishlist after logout

Background:
Given the store operates on a single channel in "United States"

@ui
Scenario: Clearing wishlist on logout
Given the store has a product "Jack Daniels Gentleman" priced at "$10.00"
And I have this product in my wishlist
When I log in
And I log out
And I go to the wishlist page
And I should have 0 products in my wishlist
43 changes: 38 additions & 5 deletions spec/Controller/Action/AddProductToWishlistActionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use BitBag\SyliusWishlistPlugin\Entity\WishlistInterface;
use BitBag\SyliusWishlistPlugin\Entity\WishlistProductInterface;
use BitBag\SyliusWishlistPlugin\Factory\WishlistProductFactoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
Expand All @@ -26,7 +26,7 @@ function let(
ProductRepositoryInterface $productRepository,
WishlistContextInterface $wishlistContext,
WishlistProductFactoryInterface $wishlistProductFactory,
EntityManagerInterface $wishlistManager,
ObjectManager $wishlistManager,
FlashBagInterface $flashBag,
TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator
Expand All @@ -48,28 +48,61 @@ function it_is_initializable(): void
$this->shouldHaveType(AddProductToWishlistAction::class);
}

function it_throws_404_if_product_was_not_found(Request $request, ProductRepositoryInterface $productRepository): void
function it_throws_404_when_product_is_not_found(Request $request, ProductRepositoryInterface $productRepository): void
{
$request->get('productId')->willReturn(1);
$productRepository->find(1)->willReturn(null);

$this->shouldThrow(NotFoundHttpException::class)->during('__invoke', [$request]);
}

function it_handles_the_request_and_persist_new_wishlist_if_needed(
function it_handles_the_request_and_persist_new_wishlist_for_logged_shop_user(
Request $request,
ProductRepositoryInterface $productRepository,
ProductInterface $product,
WishlistContextInterface $wishlistContext,
WishlistInterface $wishlist,
WishlistProductFactoryInterface $wishlistProductFactory,
WishlistProductInterface $wishlistProduct,
EntityManagerInterface $wishlistManager,
ObjectManager $wishlistManager,
TranslatorInterface $translator,
FlashBagInterface $flashBag,
UrlGeneratorInterface $urlGenerator
): void {
$request->get('productId')->willReturn(1);
$request->getUser()->willReturn('shop_user');

$productRepository->find(1)->willReturn($product);
$wishlistContext->getWishlist($request)->willReturn($wishlist);
$wishlistProductFactory->createForWishlistAndProduct($wishlist, $product)->willReturn($wishlistProduct);
$wishlist->getId()->willReturn(null);
$translator->trans('bitbag_sylius_wishlist_plugin.ui.added_wishlist_item')->willReturn('Product has been added to your wishlist.');
$urlGenerator->generate('bitbag_sylius_wishlist_plugin_shop_wishlist_list_products')->willReturn('/wishlist');

$wishlist->addWishlistProduct($wishlistProduct)->shouldBeCalled();
$wishlistManager->persist($wishlist)->shouldBeCalled();
$wishlistManager->flush()->shouldBeCalled();
$flashBag->add('success', 'Product has been added to your wishlist.')->shouldBeCalled();
$wishlist->getToken()->shouldNotBeCalled();

$this->__invoke($request)->shouldHaveType(RedirectResponse::class);
}

function it_handles_the_request_and_persist_new_wishlist_for_anonymous_user(
Request $request,
ProductRepositoryInterface $productRepository,
ProductInterface $product,
WishlistContextInterface $wishlistContext,
WishlistInterface $wishlist,
WishlistProductFactoryInterface $wishlistProductFactory,
WishlistProductInterface $wishlistProduct,
ObjectManager $wishlistManager,
TranslatorInterface $translator,
FlashBagInterface $flashBag,
UrlGeneratorInterface $urlGenerator
): void {
$request->get('productId')->willReturn(1);
$request->getUser()->willReturn(null);
$productRepository->find(1)->willReturn($product);
$wishlistContext->getWishlist($request)->willReturn($wishlist);
$wishlistProductFactory->createForWishlistAndProduct($wishlist, $product)->willReturn($wishlistProduct);
Expand Down
62 changes: 62 additions & 0 deletions spec/EventListener/ClearCookieWishlistItemsListenerSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace spec\BitBag\SyliusWishlistPlugin\EventListener;

use BitBag\SyliusWishlistPlugin\Entity\WishlistInterface;
use BitBag\SyliusWishlistPlugin\Entity\WishlistProductInterface;
use BitBag\SyliusWishlistPlugin\EventListener\ClearCookieWishlistItemsListener;
use BitBag\SyliusWishlistPlugin\Repository\WishlistRepositoryInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\Resource\Storage\StorageInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

final class ClearCookieWishlistItemsListenerSpec extends ObjectBehavior
{
public function let(StorageInterface $cookieStorage): void
{
$this->beConstructedWith($cookieStorage, 'bitbag_sylius_wishlist');
}

function it_is_initializable(): void
{
$this->shouldHaveType(ClearCookieWishlistItemsListener::class);
}

function it_does_nothing_if_not_shop_user(
InteractiveLoginEvent $interactiveLoginEvent,
TokenInterface $token,
AdminUserInterface $adminUser,
StorageInterface $cookieStorage
): void {
$interactiveLoginEvent->getAuthenticationToken()->willReturn($token);
$token->getUser()->willReturn($adminUser);

$cookieStorage->set('bitbag_sylius_wishlist', null)->shouldNotBeCalled();

$this->onInteractiveLogin($interactiveLoginEvent);
}

function it_adds_cookie_items_to_user_items_if_both_exist(
InteractiveLoginEvent $interactiveLoginEvent,
TokenInterface $token,
ShopUserInterface $shopUser,
StorageInterface $cookieStorage
): void {
$interactiveLoginEvent->getAuthenticationToken()->willReturn($token);
$token->getUser()->willReturn($shopUser);

$cookieStorage->set('bitbag_sylius_wishlist', null)->shouldBeCalled();

$this->onInteractiveLogin($interactiveLoginEvent);
}
}
1 change: 1 addition & 0 deletions src/Context/WishlistContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public function __construct(
public function getWishlist(Request $request): WishlistInterface
{
$cookieWishlistToken = $request->cookies->get($this->wishlistCookieToken);

$token = $this->tokenStorage->getToken();
$user = $token ? $token->getUser() : null;

Expand Down
24 changes: 19 additions & 5 deletions src/Controller/Action/AddProductToWishlistAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
namespace BitBag\SyliusWishlistPlugin\Controller\Action;

use BitBag\SyliusWishlistPlugin\Context\WishlistContextInterface;
use BitBag\SyliusWishlistPlugin\Entity\WishlistInterface;
use BitBag\SyliusWishlistPlugin\Entity\WishlistProductInterface;
use BitBag\SyliusWishlistPlugin\Factory\WishlistProductFactoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
use Symfony\Component\HttpFoundation\Cookie;
Expand All @@ -38,7 +39,7 @@ final class AddProductToWishlistAction
/** @var WishlistProductFactoryInterface */
private $wishlistProductFactory;

/** @var EntityManagerInterface */
/** @var ObjectManager */
private $wishlistManager;

/** @var FlashBagInterface */
Expand All @@ -57,7 +58,7 @@ public function __construct(
ProductRepositoryInterface $productRepository,
WishlistContextInterface $wishlistContext,
WishlistProductFactoryInterface $wishlistProductFactory,
EntityManagerInterface $wishlistManager,
ObjectManager $wishlistManager,
FlashBagInterface $flashBag,
TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator,
Expand All @@ -83,6 +84,7 @@ public function __invoke(Request $request): Response
}

$wishlist = $this->wishlistContext->getWishlist($request);

/** @var WishlistProductInterface $wishlistProduct */
$wishlistProduct = $this->wishlistProductFactory->createForWishlistAndProduct($wishlist, $product);

Expand All @@ -93,12 +95,24 @@ public function __invoke(Request $request): Response
}

$this->wishlistManager->flush();

$this->flashBag->add('success', $this->translator->trans('bitbag_sylius_wishlist_plugin.ui.added_wishlist_item'));

$cookie = new Cookie($this->wishlistCookieToken, $wishlist->getToken(), strtotime('+1 year'));
$response = new RedirectResponse($this->urlGenerator->generate('bitbag_sylius_wishlist_plugin_shop_wishlist_list_products'));
$response->headers->setCookie($cookie);

$this->addWishlistToResponseCookie($wishlist, $response, $request->getUser());

return $response;
}

private function addWishlistToResponseCookie(WishlistInterface $wishlist, Response $response, ?string $user): void
{
if (null !== $user) {
return;
}

$cookie = new Cookie($this->wishlistCookieToken, $wishlist->getToken(), strtotime('+1 year'));

$response->headers->setCookie($cookie);
}
}
43 changes: 43 additions & 0 deletions src/EventListener/ClearCookieWishlistItemsListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/*
* This file has been created by developers from BitBag.
* Feel free to contact us once you face any issues or want to start
* another great project.
* You can find more information about us on https://bitbag.shop and write us
* an email on [email protected].
*/

declare(strict_types=1);

namespace BitBag\SyliusWishlistPlugin\EventListener;

use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\Resource\Storage\StorageInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

final class ClearCookieWishlistItemsListener
{
/** @var StorageInterface */
private $cookieStorage;

/** @var string */
private $wishlistCookieToken;

public function __construct(StorageInterface $cookieStorage, string $wishlistCookieToken)
{
$this->cookieStorage = $cookieStorage;
$this->wishlistCookieToken = $wishlistCookieToken;
}

public function onInteractiveLogin(InteractiveLoginEvent $interactiveLoginEvent): void
{
$user = $interactiveLoginEvent->getAuthenticationToken()->getUser();

if (!$user instanceof ShopUserInterface) {
return;
}

$this->cookieStorage->set($this->wishlistCookieToken, null);
}
}
11 changes: 7 additions & 4 deletions src/EventListener/MergeUserWishlistItemsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use BitBag\SyliusWishlistPlugin\Entity\WishlistInterface;
use BitBag\SyliusWishlistPlugin\Factory\WishlistFactoryInterface;
use BitBag\SyliusWishlistPlugin\Repository\WishlistRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Sylius\Component\Core\Model\ShopUserInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
Expand All @@ -28,7 +28,7 @@ final class MergeUserWishlistItemsListener
/** @var WishlistFactoryInterface */
private $wishlistFactory;

/** @var EntityManagerInterface */
/** @var ObjectManager */
private $wishlistManager;

/** @var string */
Expand All @@ -37,7 +37,7 @@ final class MergeUserWishlistItemsListener
public function __construct(
WishlistRepositoryInterface $wishlistRepository,
WishlistFactoryInterface $wishlistFactory,
EntityManagerInterface $wishlistManager,
ObjectManager $wishlistManager,
string $wishlistCookieToken
) {
$this->wishlistRepository = $wishlistRepository;
Expand All @@ -49,6 +49,7 @@ public function __construct(
public function onInteractiveLogin(InteractiveLoginEvent $interactiveLoginEvent): void
{
$user = $interactiveLoginEvent->getAuthenticationToken()->getUser();

if (!$user instanceof ShopUserInterface) {
return;
}
Expand All @@ -59,14 +60,16 @@ public function onInteractiveLogin(InteractiveLoginEvent $interactiveLoginEvent)
private function resolveWishlist(Request $request, ShopUserInterface $shopUser): void
{
$cookieWishlistToken = $request->cookies->get($this->wishlistCookieToken, '');

/** @var WishlistInterface|null $cookieWishlist */
$cookieWishlist = $this->wishlistRepository->findByToken($cookieWishlistToken);
$userWishlist = $this->wishlistRepository->findByShopUser($shopUser);

if (null === $cookieWishlist) {
return;
}

$userWishlist = $this->wishlistRepository->findByShopUser($shopUser);

if (null !== $cookieWishlist && null !== $userWishlist) {
foreach ($cookieWishlist->getWishlistProducts() as $wishlistProduct) {
$userWishlist->addWishlistProduct($wishlistProduct);
Expand Down
8 changes: 8 additions & 0 deletions src/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ services:
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onInteractiveLogin }

bitbag_sylius_wishlist_plugin.event_listener.clear_cookie_wishlist_items:
class: BitBag\SyliusWishlistPlugin\EventListener\ClearCookieWishlistItemsListener
arguments:
- "@sylius.storage.cookie"
- "%wishlist_cookie_token%"
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onInteractiveLogin }

bitbag_sylius_wishlist_plugin.form.type.add_products_to_cart:
class: BitBag\SyliusWishlistPlugin\Form\Type\AddProductsToCartType
arguments:
Expand Down
Loading

0 comments on commit 5bc6c3c

Please sign in to comment.