diff --git a/.gitignore b/.gitignore index f7f8ac3..7ea2c86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,14 @@ -/.idea/ +/bin/* +!/bin/.gitkeep + /vendor/ +/node_modules/ +/composer.lock + +/etc/build/* +!/etc/build/.gitkeep + +/tests/Application/yarn.lock + +/.idea/ +/tests/Application/.web-server-pid diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 189333c..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,11 +0,0 @@ -before_script: - - composer install --no-interaction --prefer-dist --no-scripts - -build: - script: - - composer validate - - vendor/bin/phpunit - cache: - paths: - - bin - - vendor diff --git a/.travis.yml b/.travis.yml index dcd85a7..7576d82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,75 @@ language: php +dist: trusty + +sudo: false + +php: + - 7.1 + - 7.2 + cache: + yarn: true directories: - - bin - - vendor + - ~/.composer/cache/files + - $SYLIUS_CACHE_DIR -php: - - 7.0 - - 5.6 - - 5.5 +env: + global: + - SYLIUS_CACHE_DIR=$HOME/.sylius-cache + - SYLIUS_BUILD_DIR=etc/build before_install: - phpenv config-rm xdebug.ini - - composer self-update - - if [[ -z "$GITHUB_OAUTH_TOKEN" ]]; then export GITHUB_OAUTH_TOKEN="66736022ed66ebbb2be87027ed45a24554cc8344"; fi - - composer config -g github-oauth.github.com "$GITHUB_OAUTH_TOKEN" >/dev/null 2>&1 + - echo "memory_limit=4096M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - mkdir -p "${SYLIUS_CACHE_DIR}" install: - - composer install --no-interaction --prefer-dist --no-scripts + - composer install --no-interaction --prefer-dist + - (cd tests/Application && yarn install) + +before_script: + - (cd tests/Application && bin/console doctrine:database:create --env=test -vvv) + - (cd tests/Application && bin/console doctrine:schema:create --env=test -vvv) + - (cd tests/Application && bin/console assets:install web --env=test -vvv) + - (cd tests/Application && yarn run gulp) + + # Configure display + - /sbin/start-stop-daemon --start --quiet --pidfile /tmp/xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1680x1050x16 + - export DISPLAY=:99 + + # Download and configure ChromeDriver + - | + if [ ! -f $SYLIUS_CACHE_DIR/chromedriver ] || [ "$($SYLIUS_CACHE_DIR/chromedriver --version | grep -c 2.34)" = "0" ]; then + curl http://chromedriver.storage.googleapis.com/2.34/chromedriver_linux64.zip > chromedriver.zip + unzip chromedriver.zip + chmod +x chromedriver + mv chromedriver $SYLIUS_CACHE_DIR + fi + + # Run ChromeDriver + - $SYLIUS_CACHE_DIR/chromedriver > /dev/null 2>&1 & + + # Download and configure Selenium + - | + if [ ! -f $SYLIUS_CACHE_DIR/selenium.jar ] || [ "$(java -jar $SYLIUS_CACHE_DIR/selenium.jar --version | grep -c 3.4.0)" = "0" ]; then + curl http://selenium-release.storage.googleapis.com/3.4/selenium-server-standalone-3.4.0.jar > selenium.jar + mv selenium.jar $SYLIUS_CACHE_DIR + fi + + # Run Selenium + - java -Dwebdriver.chrome.driver=$SYLIUS_CACHE_DIR/chromedriver -jar $SYLIUS_CACHE_DIR/selenium.jar > /dev/null 2>&1 & + + # Run webserver + - (cd tests/Application && bin/console server:run 127.0.0.1:8080 -d web --env=test --quiet > /dev/null 2>&1 &) script: - - composer validate - - vendor/bin/phpunit + - composer validate --strict + - bin/phpstan.phar analyse -c phpstan.neon -l max src/ + + - bin/phpunit + - bin/phpspec run + - bin/behat --strict -vvv --no-interaction || bin/behat --strict -vvv --no-interaction --rerun + +after_failure: + - vendor/lakion/mink-debug-extension/travis/tools/upload-textfiles "${SYLIUS_BUILD_DIR}/*.log" diff --git a/Command/CreateInitialCommand.php b/Command/CreateInitialCommand.php deleted file mode 100644 index 5e159d0..0000000 --- a/Command/CreateInitialCommand.php +++ /dev/null @@ -1,58 +0,0 @@ -setName('webburza:sylius-wishlist-bundle:create-initial') - ->setDescription("Create initial wishlists for existing users.") - ; - } - - /** - * @param InputInterface $input - * @param OutputInterface $output - * - * @return void - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $output->writeln('Creating wishlists for existing users...'); - - /** @var UserRepositoryInterface $userRepository */ - $userRepository = $this->getContainer()->get('sylius.repository.shop_user'); - - /** @var WishlistRepositoryInterface $wishlistRepository */ - $wishlistRepository = $this->getContainer()->get('webburza_wishlist.repository.wishlist'); - - /** @var WishlistFactoryInterface $wishlistFactory */ - $wishlistFactory = $this->getContainer()->get('webburza_wishlist.factory.wishlist'); - - // Get all users - $users = $userRepository->findAll(); - - // Keep track of created wishlists - $createdCount = 0; - - // For each user, check if a wishlist exists and create it if not - foreach ($users as $user) { - if ($wishlistRepository->getCountForUser($user) == 0) { - $wishlist = $wishlistFactory->createDefault($user); - $wishlistRepository->add($wishlist); - $createdCount++; - } - } - - $output->writeln('Created '. $createdCount .' wishlists.'); - } -} diff --git a/Controller/Account/WishlistController.php b/Controller/Account/WishlistController.php deleted file mode 100644 index c4a089e..0000000 --- a/Controller/Account/WishlistController.php +++ /dev/null @@ -1,190 +0,0 @@ -setContainer($container); - } - - /** - * @param Request $request - * - * @return Response - */ - public function indexAction(Request $request) - { - // Throw 404 if not in multiple wishlist mode - if (!$this->getParameter('webburza_sylius_wishlist.multiple')) { - return $this->redirectToRoute('sylius_shop_account_dashboard'); - } - - // Get all wishlists for the current user - $wishlists = $this->get('webburza_wishlist.repository.wishlist')->findBy([ - 'user' => $this->getUser() - ], [ - 'createdAt' => 'asc' - ]); - - $view = View::create([ - 'wishlists' => $wishlists - ]); - - $view->setTemplate('WebburzaSyliusWishlistBundle:Frontend/Account/Wishlist:index.html.twig'); - - return $this->handleView($view); - } - - /** - * @param Request $request - * - * @return Response - */ - public function createAction(Request $request) - { - // Throw 404 if not in multiple wishlist mode - if (!$this->getParameter('webburza_sylius_wishlist.multiple')) { - throw new NotFoundHttpException(); - } - - // Get wishlist form and handle request - $form = $this->get('form.factory')->create(WishlistType::class); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - /** @var WishlistInterface $wishlist */ - $wishlist = $form->getData(); - - // Set wishlist user - $wishlist->setUser($this->getUser()); - - // Persist changes - $this->get('webburza_wishlist.repository.wishlist')->add($wishlist); - - // If this was an AJAX request, return appropriate response - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(null, Response::HTTP_CREATED); - } - - // Set success message - $this->addFlash( - 'success', - $this->get('translator')->trans('webburza_wishlist.flash.updated') - ); - - return $this->redirectToRoute('webburza_account_wishlist_edit', [ - 'id' => $wishlist->getId() - ]); - } - - $view = View::create([ - 'form' => $form->createView() - ]); - - $view->setTemplate('WebburzaSyliusWishlistBundle:Frontend/Account/Wishlist:create.html.twig'); - - return $this->handleView($view); - } - - /** - * @param Request $request - * - * @return Response - */ - public function updateAction(Request $request) - { - // Get the wishlist - $wishlist = $this->get('webburza_wishlist.repository.wishlist')->findOneBy([ - 'id' => $request->get('id'), - 'user' => $this->getUser() - ]); - - if (!$wishlist) { - throw new NotFoundHttpException(); - } - - // Get wishlist form - $form = $this->get('form.factory')->create(WishlistType::class, $wishlist); - - if (in_array($request->getMethod(), ['PUT', 'POST'])) { - if ($form->handleRequest($request)->isValid()) { - - // Persist changes - $this->get('webburza_wishlist.repository.wishlist')->add($form->getData()); - - // If this was an AJAX request, return appropriate response - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(null, Response::HTTP_OK); - } - - // Set success message - $this->addFlash( - 'success', - $this->get('translator')->trans('webburza_wishlist.flash.updated') - ); - - return $this->redirectToRoute('webburza_account_wishlist_edit', [ - 'id' => $wishlist->getId() - ]); - } - } - - $view = View::create([ - 'form' => $form->createView(), - 'wishlist' => $wishlist - ]); - - $view->setTemplate('WebburzaSyliusWishlistBundle:Frontend/Account/Wishlist:update.html.twig'); - - return $this->handleView($view); - } - - /** - * @param Request $request - * - * @return Response - */ - public function deleteAction(Request $request) - { - $wishlist = $this->get('webburza_wishlist.repository.wishlist')->findOneBy([ - 'id' => $request->get('id'), - 'user' => $this->getUser() - ]); - - // Throw exception if not found - if (!$wishlist) { - throw new NotFoundHttpException(); - } - - // Remove the wishlist - $this->get('webburza_wishlist.repository.wishlist')->remove($wishlist); - - // If this was an AJAX request, return appropriate response - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(null, Response::HTTP_NO_CONTENT); - } - - // Set success message - $this->addFlash( - 'success', - $this->get('translator')->trans('webburza_wishlist.ui.deleted') - ); - - return $this->redirectToRoute('webburza_account_wishlist_index'); - } -} diff --git a/Controller/Frontend/WishlistController.php b/Controller/Frontend/WishlistController.php deleted file mode 100644 index 5103180..0000000 --- a/Controller/Frontend/WishlistController.php +++ /dev/null @@ -1,179 +0,0 @@ -setContainer($container); - } - - /** - * Get a publicly visible wishlist by slug. - * - * @param Request $request - * - * @return Response - */ - public function showAction(Request $request) - { - /** @var WishlistInterface $wishlist */ - $wishlist = $this->get('webburza_wishlist.repository.wishlist')->findOneBy([ - 'slug' => $request->get('slug') - ]); - - // Check if wishlist exists, and it can be accessed - if (!($wishlist && $this->userCanAccessWishlist($this->getUser(), $wishlist))) { - throw new NotFoundHttpException(); - } - - $view = View::create($wishlist); - - if ($request->getRequestFormat() == 'html') { - $view->setTemplate('WebburzaSyliusWishlistBundle:Frontend/Wishlist:show.html.twig'); - - $view->setData([ - 'wishlist' => $wishlist - ]); - } - - return $this->handleView($view); - } - - /** - * Get the first publicly visible wishlist for the current user. - * - * @param Request $request - * - * @return Response - */ - public function firstAction(Request $request) - { - if (!$this->getUser()) { - throw new NotFoundHttpException(); - } - - // Get the first wishlist for the user - $wishlist = - $this->get('webburza_wishlist.repository.wishlist')->getFirstForUser($this->getUser()); - - // Create a wishlist if none exist - if (!$wishlist) { - $wishlist = $this->get('webburza_wishlist.factory.wishlist')->createDefault($this->getUser()); - $this->get('webburza_wishlist.repository.wishlist')->add($wishlist); - } - - // If the bundle is configured to work with multiple wishlists - // Redirect to the current wishlist to update URI - if ($this->getParameter('webburza_sylius_wishlist.multiple')) { - return $this->redirectToRoute('webburza_frontend_wishlist_show', [ - 'slug' => $wishlist->getSlug() - ]); - } - - // If this was an AJAX request, return appropriate response - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(['wishlist' => $wishlist], 200); - } - - // Create the view for the wishlist - $view = View::create([ - 'wishlist' => $wishlist - ]); - - // Set view template - $view->setTemplate('WebburzaSyliusWishlistBundle:Frontend/Wishlist:show.html.twig'); - - // Handle the view - return $this->handleView($view); - } - - /** - * @param Request $request - * - * @return Response - */ - public function clearAction(Request $request) - { - /** @var WishlistInterface $wishlist */ - $wishlist = $this->get('webburza_wishlist.repository.wishlist')->findOneBy([ - 'id' => $request->get('id'), - 'user' => $this->getUser() - ]); - - // Check if wishlist found - if (!$wishlist) { - $this->createNotFoundException(); - } - - // Remove each wishlist item - foreach ($wishlist->getItems() as $wishlistItem) { - $this->get('webburza_wishlist.repository.wishlist_item')->remove($wishlistItem); - } - - // If this was an AJAX request, return appropriate response - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(null, 200); - } - - // Set success message - $this->addFlash( - 'success', - $this->get('translator')->trans('webburza_wishlist.flash.cleared') - ); - - return $this->redirectToWishlist($wishlist); - } - - /** - * Check if a wishlist is publicly available, or the - * user has special privileges to access it. - * - * @param $user - * @param $wishlist - * - * @return bool - */ - protected function userCanAccessWishlist( - UserInterface $user = null, - WishlistInterface $wishlist - ) { - return $wishlist->isPublic() || ($user && $user->getId() == $wishlist->getUser()->getId()); - } - - /** - * @param WishlistInterface $wishlist - * - * @return RedirectResponse - */ - protected function redirectToWishlist(WishlistInterface $wishlist) - { - // If the bundle is configured to work with a single wishlist, - // Redirect to the the general route (without a slug) - if (false == $this->getParameter('webburza_sylius_wishlist.multiple')) { - return $this->redirectToRoute('webburza_frontend_wishlist_first'); - } - - // Redirect back to the wishlist - return $this->redirectToRoute('webburza_frontend_wishlist_show', [ - 'slug' => $wishlist->getSlug() - ]); - } - -} diff --git a/Controller/Frontend/WishlistItemController.php b/Controller/Frontend/WishlistItemController.php deleted file mode 100644 index e6cf789..0000000 --- a/Controller/Frontend/WishlistItemController.php +++ /dev/null @@ -1,241 +0,0 @@ -setContainer($container); - } - - /** - * This action renders a partial template to be submitted to - * the default add-to-cart endpoint, as used on product page. - * - * @param Request $request - * - * @return Response - */ - public function addToCartAction(Request $request) - { - $cart = $this->get('sylius.context.cart')->getCart(); - - $variant = - $this->get('sylius.repository.product_variant')->find($request->get('variantId')); - - /** @var OrderItemInterface $orderItem */ - $orderItem = $this->get('sylius.factory.order_item') - ->createForProduct($variant->getProduct()); - - $addToCartCommand = - $this->get('sylius.factory.add_to_cart_command') - ->createWithCartAndCartItem($cart, $orderItem); - - $form = $this->get('form.factory')->create(AddToCartType::class, $addToCartCommand, [ - 'product' => $variant->getProduct() - ]); - - $form->get('cartItem')->get('quantity')->setData(1); - - if ($form->get('cartItem')->has('variant')) { - $form->get('cartItem')->get('variant')->setData($variant); - } - - $view = View::create([ - 'product' => $variant->getProduct(), - 'form' => $form->createView() - ]); - - $view->setTemplate('@WebburzaSyliusWishlist/Frontend/Wishlist/_cartForm.html.twig'); - - return $this->handleView($view); - } - - /** - * @param Request $request - * - * @return Response - */ - public function removeAction(Request $request) - { - /** @var WishlistItemInterface $wishlistItem */ - $wishlistItem = - $this->get('webburza_wishlist.repository.wishlist_item')->find($request->get('id')); - - // Check if this item belongs to the current customer trying to remove it - if ($wishlistItem->getWishlist()->getUser() != $this->getUser()) { - throw $this->createAccessDeniedException(); - } - - // Remove the item from the repository - $this->get('webburza_wishlist.repository.wishlist_item')->remove($wishlistItem); - - // If this was an AJAX request, return appropriate response - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(null, Response::HTTP_NO_CONTENT); - } - - // Set success message - $this->addFlash( - 'success', - $this->get('translator')->trans('webburza_wishlist.flash.item_removed') - ); - - return $this->redirectToWishlist($wishlistItem->getWishlist()); - } - - /** - * Add a wishlist item to a wishlist (create it). - * - * @param Request $request - * - * @return Response - */ - public function addAction(Request $request) - { - // Get the current user - if (!($user = $this->getUser())) { - throw new BadRequestHttpException(); - } - - // Get (or create) the wishlist to which the item should be added - $wishlist = $this->resolveWishlist($request, $user); - - // Get the product variant to be added to wishlist - $productVariant = $this->resolveProductVariant($request); - - // Prevent duplicates - if ($wishlist->contains($productVariant)) { - // Set flash message - $this->addFlash( - 'info', - $this->get('translator')->trans('webburza_wishlist.flash.already_on_wishlist') - ); - - // Redirect back to the wishlist - return $this->redirectToWishlist($wishlist); - } - - /** @var WishlistItemInterface $wishlistItem */ - $wishlistItem = $this->get('webburza_wishlist.factory.wishlist_item')->createNew(); - $wishlistItem->setProductVariant($productVariant); - - $wishlist->addItem($wishlistItem); - - // Persist the wishlist item - $this->get('webburza_wishlist.repository.wishlist_item')->add($wishlistItem); - - if ($request->getRequestFormat() != 'html') { - return new JsonResponse(null, Response::HTTP_CREATED); - } - - // Set success message - $this->addFlash( - 'success', - $this->get('translator')->trans('webburza_wishlist.flash.item_added') - ); - - return $this->redirectToWishlist($wishlist); - } - - /** - * Get the requested wishlist, if any, - * or the first one for the customer. - * - * @param Request $request - * @param UserInterface $user - * - * @return null|WishlistInterface - */ - protected function resolveWishlist(Request $request, UserInterface $user) - { - // Check if a specific wishlist was requested - if ($wishlistId = $request->get('wishlistId')) { - $wishlist = $this->get('webburza_wishlist.repository.wishlist') - ->findOneBy([ - 'id' => $wishlistId, - 'user' => $user - ]); - - if (!$wishlist) { - throw new BadRequestHttpException(); - } - - return $wishlist; - } - - // If not, get the first wishlist for the customer - $wishlist = $this->get('webburza_wishlist.repository.wishlist')->getFirstForUser($user); - - // If no wishlist found, create a new one - if (!$wishlist) { - $wishlist = $this->get('webburza_wishlist.factory.wishlist')->createDefault($user); - $this->get('webburza_wishlist.repository.wishlist')->add($wishlist); - } - - return $wishlist; - } - - /** - * @param Request $request - * - * @return mixed - * @throws BadRequestHttpException - */ - protected function resolveProductVariant(Request $request) - { - if ($productVariantId = $request->get('productVariantId')) { - $productVariant = $this->get('sylius.repository.product_variant') - ->find($productVariantId); - } else { - $productVariant = - $this->container->get('webburza_wishlist.resolver.product_variant_cart') - ->resolve($request); - } - - if (!$productVariant) { - throw new BadRequestHttpException(); - } - - return $productVariant; - } - - /** - * @param WishlistInterface $wishlist - * - * @return RedirectResponse - */ - protected function redirectToWishlist(WishlistInterface $wishlist) - { - // If the bundle is configured to work with a single wishlist, - // Redirect to the the general route (without a slug) - if (false == $this->getParameter('webburza_sylius_wishlist.multiple')) { - return $this->redirectToRoute('webburza_frontend_wishlist_first'); - } - - // Redirect back to the wishlist - return $this->redirectToRoute('webburza_frontend_wishlist_show', [ - 'slug' => $wishlist->getSlug() - ]); - } -} diff --git a/DependencyInjection/WebburzaSyliusWishlistExtension.php b/DependencyInjection/WebburzaSyliusWishlistExtension.php deleted file mode 100644 index 0d91084..0000000 --- a/DependencyInjection/WebburzaSyliusWishlistExtension.php +++ /dev/null @@ -1,27 +0,0 @@ -processConfiguration($configuration, $configs); - - // Set config parameters - $container->setParameter('webburza_sylius_wishlist.multiple', $config['multiple']); - $container->setParameter('webburza_sylius_wishlist.default_public', $config['default_public']); - - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('services.yml'); - } -} diff --git a/EventListener/MenuBuilderListener.php b/EventListener/MenuBuilderListener.php deleted file mode 100644 index d3702d3..0000000 --- a/EventListener/MenuBuilderListener.php +++ /dev/null @@ -1,26 +0,0 @@ -getMenu(); - - // Get or create the parent group - if (null == ($contentMenu = $menu->getChild('customers'))) { - $contentMenu = $menu->addChild('customers')->setLabel('webburza_wishlist.ui.customer'); - } - - // Add 'Wishlists' menu item - $contentMenu->addChild('webburza_wishlists', ['route' => 'webburza_wishlist_admin_wishlist_index']) - ->setLabel('webburza_wishlist.ui.wishlists') - ->setLabelAttribute('icon', 'star'); - } -} diff --git a/EventListener/UserListener.php b/EventListener/UserListener.php deleted file mode 100644 index 9df7ac1..0000000 --- a/EventListener/UserListener.php +++ /dev/null @@ -1,68 +0,0 @@ -container = $container; - $this->wishlistQueue = new ArrayCollection(); - } - - /** - * @param OnFlushEventArgs $event - */ - public function onFlush(OnFlushEventArgs $event) - { - $entities = $event->getEntityManager()->getUnitOfWork()->getScheduledEntityInsertions(); - - foreach ($entities as $entity) { - if ($entity instanceof ShopUserInterface) { - $this->wishlistQueue->add( - $this->container->get('webburza_wishlist.factory.wishlist')->createDefault($entity) - ); - } - } - } - - /** - * @param PostFlushEventArgs $event - */ - public function postFlush(PostFlushEventArgs $event) - { - if ($this->wishlistQueue->count()) { - foreach ($this->wishlistQueue as $wishlist) { - $this->container->get('doctrine.orm.entity_manager')->persist($wishlist); - } - $this->wishlistQueue->clear(); - - $event->getEntityManager()->flush(); - } - } -} diff --git a/Factory/WishlistFactoryInterface.php b/Factory/WishlistFactoryInterface.php deleted file mode 100644 index e59d3ae..0000000 --- a/Factory/WishlistFactoryInterface.php +++ /dev/null @@ -1,17 +0,0 @@ -add('user', UserChoiceType::class, [ - 'label' => 'webburza_wishlist.wishlist.label.user', - 'required' => true, - 'constraints' => [ - new NotBlank() - ] - ]); - } -} diff --git a/Form/Type/UserChoiceType.php b/Form/Type/UserChoiceType.php deleted file mode 100644 index 69ba935..0000000 --- a/Form/Type/UserChoiceType.php +++ /dev/null @@ -1,67 +0,0 @@ -repository = $repository; - } - - /** - * {@inheritdoc} - */ - public function buildForm(FormBuilderInterface $builder, array $options) - { - if ($options['multiple']) { - $builder->addModelTransformer(new CollectionToArrayTransformer()); - } - } - - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults([ - 'choices' => function (Options $options) { - return $this->repository->findAll(); - }, - 'choice_value' => 'id', - 'choice_label' => 'email' - ]); - } - - /** - * {@inheritdoc} - */ - public function getParent() - { - return ChoiceType::class; - } - - /** - * {@inheritdoc} - */ - public function getBlockPrefix() - { - return 'webburza_wishlist_user_choice'; - } -} diff --git a/Model/WishlistInterface.php b/Model/WishlistInterface.php deleted file mode 100644 index 4e62921..0000000 --- a/Model/WishlistInterface.php +++ /dev/null @@ -1,92 +0,0 @@ -

+ +--- + ## Installation 1. require the bundle with Composer: ```bash - $ composer require webburza/sylius-wishlist-bundle + $ composer require webburza/sylius-wishlist-plugin ``` 2. enable the bundle in `app/AppKernel.php`: @@ -20,7 +24,7 @@ to use single or multiple wishlists per user, which can be public or private. { $bundles = [ // ... - new \Webburza\Sylius\WishlistBundle\WebburzaSyliusWishlistBundle(), + new \Webburza\SyliusWishlistPlugin\WebburzaSyliusWishlistPlugin(), // ... ]; } @@ -30,7 +34,7 @@ to use single or multiple wishlists per user, which can be public or private. ```yaml imports: - - { resource: "@WebburzaSyliusWishlistBundle/Resources/config/config.yml" } + - { resource: "@WebburzaSyliusWishlistPlugin/Resources/config/config.yml" } ``` Among other things, this provides configuration entries which can then be overriden @@ -45,22 +49,10 @@ to use single or multiple wishlists per user, which can be public or private. 4. register routes in `app/config/routing.yml` ```yaml - webburza_wishlist: - resource: "@WebburzaSyliusWishlistBundle/Resources/config/routing.yml" - - webburza_wishlist_front: - resource: "@WebburzaSyliusWishlistBundle/Resources/config/routingFront.yml" - prefix: /wishlist - - webburza_wishlist_account: - resource: "@WebburzaSyliusWishlistBundle/Resources/config/routingAccount.yml" - prefix: /account/wishlists + webburza_sylius_wishlist: + resource: "@WebburzaSyliusWishlistPlugin/Resources/config/routing.yml" ``` - As you can see, there are three groups of routes, the main resource (administration) - routes, frontend routes, and user account routes where the user can manage their - wishlist(s), create new ones, mark them public/private, etc... - 5. The bundle should now be fully integrated, but it still requires database tables to be created. For this, we recommend using migrations. @@ -77,15 +69,7 @@ to use single or multiple wishlists per user, which can be public or private. 6. If you're integrating this bundle into an existing project, your existing users will not have any wishlists associated. This is not an issue as wishlists - are automatically created when needed. All new users will automatically have - a wishlist created for them from the start. - - If you want to make sure all your users have wishlists, you can run a command - which will create initial wishlists for all existing users which do not already have one. - - ```bash - $ bin/console webburza:sylius-wishlist-bundle:create-initial - ``` + are automatically created when needed. ## Integration on shop pages @@ -101,7 +85,7 @@ this implementation is up to you. It can be done in two ways. next to the 'Add to cart' button in the existing form. Open the template containing your 'add to cart' form, most likely in: - `app/Resources/SyliusShopBundle/Resources/views/Product/Show/_addToCart.html.twig` + `app/Resources/SyliusShopBundle/views/Product/Show/_addToCart.html.twig` Find the 'add to cart' button, by default: ``` @@ -110,7 +94,7 @@ this implementation is up to you. It can be done in two ways. And under it, add the following line. ``` - {% include '@WebburzaSyliusWishlist/Frontend/Shop/_addToWishlist.html.twig' %} + {% include '@WebburzaSyliusWishlistPlugin/Shop/Misc/_addToWishlist.html.twig' %} ``` This will include the 'Add to Wishlist' button, and all required functionality. @@ -126,7 +110,7 @@ this implementation is up to you. It can be done in two ways. ``` $.ajax({ - url: '/wishlist/item/', + url: '/wishlist/item', type: 'POST', data: { productVariantId: 123, @@ -147,25 +131,78 @@ You might also want to feature a badge in your header which links to the wishlis and shows the current number of items added, similar to the existing cart badge. To do this, just add this line to the bottom of the same file -`app/Resources/SyliusShopBundle/Resources/views/Cart/_widget.html.twig` +`app/Resources/SyliusShopBundle/views/Cart/_widget.html.twig` ``` -{% include '@WebburzaSyliusWishlist/Frontend/Shop/_badge.html.twig' %} +{% include '@WebburzaSyliusWishlistPlugin/Shop/Misc/_badge.html.twig' %} ``` ## Translations and naming The bundle has multilingual support, and language files can be overridden as with any other bundle, by creating translation files in the -`app/Resources/WebburzaSyliusWishlistBundle/translations` directory. +`app/Resources/WebburzaSyliusWishlistPlugin/translations` directory. To get started, check the bundle's main language file in: -[Resources/translations/messages.en.yml](Resources/translations/messages.en.yml) +[src/Resources/translations/messages.en.yml](src/Resources/translations/messages.en.yml) + +## Running and testing the application manually + +- Initial installation and fixtures: + + ```bash + $ composer install + + $ (cd tests/Application && yarn install) + $ (cd tests/Application && yarn run gulp) + $ (cd tests/Application && bin/console assets:install web -e dev) + + $ (cd tests/Application && bin/console doctrine:database:create -e dev) + $ (cd tests/Application && bin/console doctrine:schema:create -e dev) + $ (cd tests/Application && bin/console sylius:fixtures:load -e dev) + ``` + +- Start application: + + ```bash + $ (cd tests/Application && bin/console server:start -d web -e dev) + ``` + +- Stop application: + + ```bash + $ (cd tests/Application && bin/console server:stop) + ``` + +## Automated tests + + - Behat (non-Javascript scenarios) + + ```bash + $ bin/behat --tags="~@javascript" + ``` + + - Behat (with Javascript scenarios) + + 1. Download [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/) + + 2. Run Selenium server with previously downloaded Chromedriver: + + ```bash + $ bin/selenium-server-standalone -Dwebdriver.chrome.driver=/path/to/chromedriver + ``` + 3. Run test application's webserver on `localhost:8080`: + + ```bash + $ (cd tests/Application && bin/console server:run 127.0.0.1:8080 -d web -e test) + ``` + + 4. Run Behat: + + ```bash + $ bin/behat + ``` ## License This bundle is available under the [MIT license](LICENSE). - -## To-do - -- Tests diff --git a/Repository/WishlistRepositoryInterface.php b/Repository/WishlistRepositoryInterface.php deleted file mode 100644 index 3d72d0a..0000000 --- a/Repository/WishlistRepositoryInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - - {{ form_errors(form) }} - -
-
- {{ form_rest(form) }} -
- - {% if form.vars.data.items | length %} -
- - - - - - - - {% for item in form.vars.data.items %} - - - - {% endfor %} - -
{{ 'webburza_wishlist.ui.wishlist_items' | trans }}
- - {{ item.productVariant.product.name }} - - - {% if item.productVariant.optionValues %} -
- - {{ item.productVariant.optionValues | join(', ') }} - - {% endif %} -
-
- {% endif %} -
- diff --git a/Resources/views/Backend/grid/_title.html.twig b/Resources/views/Backend/grid/_title.html.twig deleted file mode 100644 index 03d8f29..0000000 --- a/Resources/views/Backend/grid/_title.html.twig +++ /dev/null @@ -1,5 +0,0 @@ -{% if data.public %} - {{ data.title }} -{% else %} - {{ data.title }} -{% endif %} diff --git a/Resources/views/Backend/grid/_user.html.twig b/Resources/views/Backend/grid/_user.html.twig deleted file mode 100644 index 15d4ac4..0000000 --- a/Resources/views/Backend/grid/_user.html.twig +++ /dev/null @@ -1 +0,0 @@ -{{ data.user.customer.email }} diff --git a/Resources/views/Frontend/Shop/_badge.html.twig b/Resources/views/Frontend/Shop/_badge.html.twig deleted file mode 100644 index 8c9f61c..0000000 --- a/Resources/views/Frontend/Shop/_badge.html.twig +++ /dev/null @@ -1,10 +0,0 @@ -{% if is_granted('ROLE_USER') %} - - - {{ wishlist_provider.itemCount }} - -{% endif %} diff --git a/WebburzaSyliusWishlistBundle.php b/WebburzaSyliusWishlistBundle.php deleted file mode 100644 index be4f75b..0000000 --- a/WebburzaSyliusWishlistBundle.php +++ /dev/null @@ -1,9 +0,0 @@ - + - + bootstrap="vendor/autoload.php"> - - ./Tests + + tests - - - ./ - - ./Tests - ./vendor - - - + + + + diff --git a/src/Controller/Account/WishlistController.php b/src/Controller/Account/WishlistController.php new file mode 100644 index 0000000..bd77bb5 --- /dev/null +++ b/src/Controller/Account/WishlistController.php @@ -0,0 +1,223 @@ +wishlistRepository = $wishlistRepository; + $this->loggedInUserProvider = $loggedInUserProvider; + $this->translator = $translator; + $this->formFactory = $formFactory; + $this->multipleWishlistMode = $multipleWishlistMode; + } + + /** + * @param Request $request + * + * @return Response + */ + public function indexAction(Request $request) : Response + { + // Throw 404 if not in multiple wishlist mode + if (!$this->multipleWishlistMode) { + return $this->redirectToRoute('sylius_shop_account_dashboard'); + } + + // Get all wishlists for the current user + $wishlists = $this->wishlistRepository->findBy([ + 'user' => $this->loggedInUserProvider->getUser() + ], [ + 'createdAt' => 'asc' + ]); + + // Render view + return $this->render('@WebburzaSyliusWishlistPlugin/Resources/views/Account/index.html.twig', [ + 'wishlists' => $wishlists + ]); + } + + /** + * @param Request $request + * + * @return Response + */ + public function createAction(Request $request) : Response + { + // Throw 404 if not in multiple wishlist mode + if (!$this->multipleWishlistMode) { + throw $this->createNotFoundException(); + } + + // Get wishlist form and handle request + $form = $this->formFactory->create(WishlistType::class); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /** @var WishlistInterface $wishlist */ + $wishlist = $form->getData(); + + // Set wishlist user + $wishlist->setUser($this->loggedInUserProvider->getUser()); + + // Persist changes + $this->wishlistRepository->add($wishlist); + + // If this was an AJAX request, return appropriate response + if ($request->getRequestFormat() != 'html') { + return new JsonResponse(null, Response::HTTP_CREATED); + } + + // Set success message + $this->addFlash( + 'success', $this->translator->trans('webburza_sylius_wishlist.flash.updated') + ); + + return $this->redirectToRoute('webburza_sylius_wishlist_account_wishlist_edit', [ + 'id' => $wishlist->getId() + ]); + } + + return $this->render('@WebburzaSyliusWishlistPlugin/Resources/views/Account/create.html.twig', [ + 'form' => $form->createView() + ]); + } + + /** + * @param Request $request + * + * @return Response + */ + public function updateAction(Request $request) : Response + { + // Get the wishlist + $wishlist = $this->wishlistRepository->findOneBy([ + 'id' => $request->get('id'), + 'user' => $this->loggedInUserProvider->getUser() + ]); + + if (!$wishlist) { + throw $this->createNotFoundException(); + } + + // Get wishlist form + $form = $this->formFactory->create(WishlistType::class, $wishlist); + + if (in_array($request->getMethod(), ['PUT', 'POST'])) { + if ($form->handleRequest($request)->isValid()) { + /** @var WishlistInterface $wishlist */ + $wishlist = $form->getData(); + + // Set wishlist user + $wishlist->setUser($this->loggedInUserProvider->getUser()); + + // Persist changes + $this->wishlistRepository->add($wishlist); + + // If this was an AJAX request, return appropriate response + if ($request->getRequestFormat() != 'html') { + return new JsonResponse(null, Response::HTTP_OK); + } + + // Set success message + $this->addFlash( + 'success', $this->translator->trans('webburza_sylius_wishlist.flash.updated') + ); + + return $this->redirectToRoute('webburza_sylius_wishlist_account_wishlist_edit', [ + 'id' => $wishlist->getId() + ]); + } + } + + return $this->render('@WebburzaSyliusWishlistPlugin/Resources/views/Account/update.html.twig', [ + 'form' => $form->createView(), + 'wishlist' => $wishlist + ]); + } + + /** + * @param Request $request + * + * @return Response + */ + public function deleteAction(Request $request) : Response + { + /** @var WishlistInterface $wishlist */ + $wishlist = $this->wishlistRepository->findOneBy([ + 'id' => $request->get('id'), + 'user' => $this->loggedInUserProvider->getUser() + ]); + + // Throw exception if not found + if (!$wishlist) { + throw $this->createNotFoundException(); + } + + // Remove the wishlist + $this->wishlistRepository->remove($wishlist); + + // If this was an AJAX request, return appropriate response + if ($request->getRequestFormat() != 'html') { + return new JsonResponse(null, Response::HTTP_NO_CONTENT); + } + + // Set success message + $this->addFlash( + 'success', $this->translator->trans('webburza_sylius_wishlist.ui.deleted') + ); + + return $this->redirectToRoute('webburza_sylius_wishlist_account_wishlist_index'); + } +} diff --git a/src/Controller/Shop/WishlistController.php b/src/Controller/Shop/WishlistController.php new file mode 100644 index 0000000..061e307 --- /dev/null +++ b/src/Controller/Shop/WishlistController.php @@ -0,0 +1,243 @@ +loggedInUserProvider = $loggedInUserProvider; + $this->wishlistRepository = $wishlistRepository; + $this->wishlistFactory = $wishlistFactory; + $this->translator = $translator; + $this->restViewHandler = $restViewHandler; + $this->multipleWishlistMode = $multipleWishlistMode; + } + + /** + * @param Request $request + * + * @return Response + */ + public function firstAction(Request $request) : Response + { + // Abort if no logged-in user + if (!($loggedInUser = $this->loggedInUserProvider->getUser())) { + throw $this->createNotFoundException(); + } + + // Get the first wishlist for the user + $wishlist = $this->wishlistRepository->getFirstForUser($loggedInUser); + + // Create a wishlist if none exists + if (!$wishlist) { + $wishlist = $this->wishlistFactory->createDefault($loggedInUser); + $this->wishlistRepository->add($wishlist); + } + + // If the bundle is configured to work with multiple wishlists + // Redirect to the current wishlist to update URI + if ($this->multipleWishlistMode) { + return $this->redirectToRoute('webburza_sylius_wishlist_shop_wishlist_show', [ + 'id' => $wishlist->getId(), + 'slug' => $wishlist->getSlug() + ]); + } + + return $this->handleView( + '@WebburzaSyliusWishlistPlugin/Resources/views/Shop/Wishlist/show.html.twig', [ + 'wishlist' => $wishlist + ], $request + ); + } + + /** + * @param Request $request + * + * @return Response $response + */ + public function clearAction(Request $request) : Response + { + /** @var WishlistInterface $wishlist */ + $wishlist = $this->wishlistRepository->findOneBy([ + 'id' => $request->get('id'), + 'user' => $this->getUser() + ]); + + // Check if wishlist found + if (!$wishlist) { + throw $this->createNotFoundException(); + } + + // Clear items from wishlist + $wishlist->clearItems(); + + // Persist changes + $this->wishlistRepository->add($wishlist); + + // If this was an AJAX request, return appropriate response + if ($request->isXmlHttpRequest()) { + return new JsonResponse(null, 200); + } + + // Set success message + $this->addFlash( + 'success', $this->translator->trans('webburza_sylius_wishlist.flash.cleared') + ); + + return $this->redirectToWishlist($wishlist); + } + + /** + * Get a publicly visible wishlist by id. + * + * @param Request $request + * + * @return Response + */ + public function showAction(Request $request): Response + { + /** @var WishlistInterface $wishlist */ + $wishlist = $this->wishlistRepository->findOneBy([ + 'id' => $request->get('id'), + 'slug' => $request->get('slug') + ]); + + // Check if wishlist exists, and it can be accessed + if (!($wishlist && $this->userCanAccessWishlist( + $this->loggedInUserProvider->getUser(), $wishlist) + )) { + throw $this->createNotFoundException(); + } + + return $this->handleView( + '@WebburzaSyliusWishlistPlugin/Resources/views/Shop/Wishlist/show.html.twig', [ + 'wishlist' => $wishlist + ], $request + ); + } + + /** + * Check if a wishlist is publicly available, or the + * user has special privileges to access it. + * + * @param ShopUserInterface $user + * @param WishlistInterface $wishlist + * + * @return bool + */ + protected function userCanAccessWishlist( + ShopUserInterface $user = null, + WishlistInterface $wishlist + ) : bool { + return $wishlist->isPublic() || ($user && $user->getId() === $wishlist->getUser()->getId()); + } + + /** + * @param WishlistInterface $wishlist + * + * @return RedirectResponse + */ + protected function redirectToWishlist(WishlistInterface $wishlist) : RedirectResponse + { + // If the bundle is configured to work with a single wishlist, + // Redirect to the the general route (without an id) + if (false == $this->multipleWishlistMode) { + return $this->redirectToRoute('webburza_sylius_wishlist_shop_wishlist_first'); + } + + // Redirect back to the same wishlist + return $this->redirectToRoute('webburza_sylius_wishlist_shop_wishlist_show', [ + 'id' => $wishlist->getId(), + 'slug' => $wishlist->getSlug() + ]); + } + + /** + * @param string $template + * @param array $data + * @param Request $request + * + * @return Response + */ + protected function handleView(string $template, array $data = [], Request $request) : Response + { + // Consider first item in $data as main resource + $resource = !empty($data) ? array_values($data)[0] : null; + + // Create the view + $view = View::create($resource); + + // Set template if HTML request, or serialization data and format if Ajax + if (!$request->isXmlHttpRequest()) { + $view->setTemplate($template) + ->setData($data); + } else { + $view->getContext()->enableMaxDepth(); + $view->setFormat('json'); + } + + // Handle the view and return response + return $this->restViewHandler->handle($view); + } +} diff --git a/src/Controller/Shop/WishlistItemController.php b/src/Controller/Shop/WishlistItemController.php new file mode 100644 index 0000000..7867b32 --- /dev/null +++ b/src/Controller/Shop/WishlistItemController.php @@ -0,0 +1,267 @@ +loggedInUserProvider = $loggedInUserProvider; + $this->wishlistItemRepository = $wishlistItemRepository; + $this->translator = $translator; + $this->cartContext = $cartContext; + $this->productVariantRepository = $productVariantRepository; + $this->cartItemFactory = $cartItemFactory; + $this->addToCartCommandFactory = $addToCartCommandFactory; + $this->wishlistFromRequestResolver = $wishlistFromRequestResolver; + $this->productVariantFromRequestResolver = $productVariantFromRequestResolver; + $this->wishlistItemFactory = $wishlistItemFactory; + $this->multipleWishlistMode = $multipleWishlistMode; + } + + /** + * @param Request $request + * + * @return Response + */ + public function addAction(Request $request) : Response + { + // Get (or create) the wishlist to which the item should be added + $wishlist = $this->wishlistFromRequestResolver->resolve($request); + + // Get the product variant to be added to wishlist + $productVariant = $this->productVariantFromRequestResolver->resolve($request); + + // Prevent duplicates + if ($wishlist->containsVariant($productVariant)) { + if ($request->isXmlHttpRequest()) { + return new JsonResponse(null, Response::HTTP_CONFLICT); + } + + // Set flash message + $this->addFlash( + 'info', + $this->translator->trans('webburza_sylius_wishlist.flash.already_on_wishlist') + ); + + // Redirect back to the wishlist + return $this->redirectToWishlist($wishlist); + } + + /** @var WishlistItemInterface $wishlistItem */ + $wishlistItem = $this->wishlistItemFactory->createNew(); + $wishlistItem->setProductVariant($productVariant); + + $wishlist->addItem($wishlistItem); + + // Persist the wishlist item + $this->wishlistItemRepository->add($wishlistItem); + + if ($request->isXmlHttpRequest()) { + return new JsonResponse(null, Response::HTTP_CREATED); + } + + // Set success message + $this->addFlash( + 'success', $this->translator->trans('webburza_sylius_wishlist.flash.item_added') + ); + + // Redirect back to the wishlist + return $this->redirectToWishlist($wishlist); + } + + /** + * @param Request $request + * + * @return Response + */ + public function addToCartAction(Request $request) : Response + { + // Get product variant + $variant = $this->productVariantRepository->find($request->get('variantId')); + + // Check if product variant found + if (!$variant) { + throw $this->createNotFoundException(); + } + + // Create an add-to-cart command + $addToCartCommand = $this->addToCartCommandFactory->createWithCartAndCartItem( + $this->cartContext->getCart(), + $this->cartItemFactory->createForProduct($variant->getProduct()) + ); + + // Prepare the form to be rendered for the add-to-cart command + $form = $this->get('form.factory')->create(AddToCartType::class, $addToCartCommand, [ + 'product' => $variant->getProduct() + ]); + + $form->get('cartItem')->get('quantity')->setData(1); + + if ($form->get('cartItem')->has('variant')) { + $form->get('cartItem')->get('variant')->setData($variant); + } + + // Render the view + return $this->render('@WebburzaSyliusWishlistPlugin/Resources/views/Shop/Wishlist/_cartForm.html.twig', [ + 'product' => $variant->getProduct(), + 'form' => $form->createView() + ]); + } + + /** + * @param Request $request + * + * @return Response + */ + public function removeAction(Request $request) : Response + { + /** @var WishlistItemInterface $wishlistItem */ + $wishlistItem = $this->wishlistItemRepository->find($request->get('id')); + + // Check if wishlist item found + if (!$wishlistItem) { + throw $this->createNotFoundException(); + } + + // Check if this item belongs to the current customer trying to remove it + if ($wishlistItem->getWishlist()->getUser() != $this->getUser()) { + throw $this->createAccessDeniedException(); + } + + // Remove the item from the repository + $this->wishlistItemRepository->remove($wishlistItem); + + // If this was an AJAX request, return appropriate response + if ($request->isXmlHttpRequest()) { + return new JsonResponse(null, Response::HTTP_NO_CONTENT); + } + + // Set success message + $this->addFlash( + 'success', $this->translator->trans('webburza_sylius_wishlist.flash.item_removed') + ); + + return $this->redirectToWishlist($wishlistItem->getWishlist()); + } + + /** + * @param WishlistInterface $wishlist + * + * @return RedirectResponse + */ + protected function redirectToWishlist(WishlistInterface $wishlist) : RedirectResponse + { + // If the bundle is configured to work with a single wishlist, + // Redirect to the the general route (without an id) + if (false == $this->multipleWishlistMode) { + return $this->redirectToRoute('webburza_sylius_wishlist_shop_wishlist_first'); + } + + // Redirect back to the same wishlist + return $this->redirectToRoute('webburza_sylius_wishlist_shop_wishlist_show', [ + 'id' => $wishlist->getId(), + 'slug' => $wishlist->getSlug() + ]); + } +} diff --git a/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php similarity index 53% rename from DependencyInjection/Configuration.php rename to src/DependencyInjection/Configuration.php index 9d5b624..3f09dc8 100644 --- a/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -1,24 +1,26 @@ root('webburza_sylius_wishlist'); $rootNode ->children() - ->booleanNode('multiple')->end() - ->booleanNode('default_public')->end() + ->booleanNode('multiple')->defaultFalse()->end() + ->booleanNode('default_public')->defaultFalse()->end() ->end(); return $treeBuilder; diff --git a/src/DependencyInjection/WebburzaSyliusWishlistExtension.php b/src/DependencyInjection/WebburzaSyliusWishlistExtension.php new file mode 100644 index 0000000..3ffdfbc --- /dev/null +++ b/src/DependencyInjection/WebburzaSyliusWishlistExtension.php @@ -0,0 +1,30 @@ +processConfiguration($this->getConfiguration([], $container), $config); + + // Set configuration as a parameters in the container + $container->setParameter('webburza_sylius_wishlist.config.multiple', $config['multiple']); + $container->setParameter('webburza_sylius_wishlist.config.default_public', $config['default_public']); + + $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + + $loader->load('services.yml'); + } +} diff --git a/Doctrine/ORM/WishlistRepository.php b/src/Doctrine/ORM/WishlistRepository.php similarity index 62% rename from Doctrine/ORM/WishlistRepository.php rename to src/Doctrine/ORM/WishlistRepository.php index a08120a..52c0548 100644 --- a/Doctrine/ORM/WishlistRepository.php +++ b/src/Doctrine/ORM/WishlistRepository.php @@ -1,33 +1,36 @@ createQueryBuilder('o'); $queryBuilder->innerJoin('o.user', 'user'); + $queryBuilder->innerJoin('user.customer', 'customer'); return $queryBuilder; } /** - * @param UserInterface $user + * @param ShopUserInterface $user * - * @return integer + * @return int */ - public function getCountForUser(UserInterface $user) + public function getCountForUser(ShopUserInterface $user): int { // Get query builder $queryBuilder = $this->createQueryBuilder('o'); @@ -44,11 +47,11 @@ public function getCountForUser(UserInterface $user) /** * Get the first wishlist for the user, if any. * - * @param UserInterface $user + * @param ShopUserInterface $user * * @return WishlistInterface|object|null */ - public function getFirstForUser(UserInterface $user) + public function getFirstForUser(ShopUserInterface $user): ?WishlistInterface { return $this->findOneBy([ 'user' => $user diff --git a/EventListener/AccountMenuBuilderListener.php b/src/EventListener/AccountMenuListener.php similarity index 57% rename from EventListener/AccountMenuBuilderListener.php rename to src/EventListener/AccountMenuListener.php index eb14ca8..40c4c83 100644 --- a/EventListener/AccountMenuBuilderListener.php +++ b/src/EventListener/AccountMenuListener.php @@ -1,13 +1,15 @@ translator = $translator; - $this->tokenStorage = $tokenStorage; + $this->loggedInUserProvider = $loggedInUserProvider; $this->wishlistRepository = $wishlistRepository; $this->multipleWishlistMode = $multipleWishlistMode; } @@ -55,29 +57,31 @@ public function __construct( * * @param MenuBuilderEvent $event */ - public function addAccountMenuItems(MenuBuilderEvent $event) + public function addMenuItems(MenuBuilderEvent $event) : void { // Get the menu $menu = $event->getMenu(); // Set route and label, depending on multiple wishlist mode if ($this->multipleWishlistMode) { - $route = 'webburza_account_wishlist_index'; + $route = 'webburza_sylius_wishlist_account_wishlist_index'; $routeParameters = []; - $label = $this->translate('webburza_wishlist.ui.my_wishlists'); + $label = $this->translator->trans('webburza_sylius_wishlist.ui.account_wishlists'); } else { // Get the first wishlist for the user - $wishlist = $this->wishlistRepository->getFirstForUser($this->getUser()); + $wishlist = $this->wishlistRepository->getFirstForUser( + $this->loggedInUserProvider->getUser() + ); if (!$wishlist) { return; } - $route = 'webburza_account_wishlist_edit'; + $route = 'webburza_sylius_wishlist_account_wishlist_edit'; $routeParameters = [ 'id' => $wishlist->getId() ]; - $label = $this->translate('webburza_wishlist.ui.my_wishlist'); + $label = $this->translator->trans('webburza_sylius_wishlist.ui.account_wishlist'); } // Add menu item to the menu @@ -88,29 +92,4 @@ public function addAccountMenuItems(MenuBuilderEvent $event) 'labelAttributes' => ['icon' => 'star', 'iconOnly' => false], ])->setLabel($label); } - - /** - * Translate a string using the translator. - * - * @param $string - * @return string - */ - protected function translate($string) - { - return $this->translator->trans($string); - } - - /** - * @return UserInterface - */ - protected function getUser() - { - if ($securityToken = $this->tokenStorage->getToken()) { - if (($user = $securityToken->getUser()) instanceof UserInterface) { - return $user; - } - } - - return null; - } } diff --git a/src/EventListener/AdminMenuListener.php b/src/EventListener/AdminMenuListener.php new file mode 100644 index 0000000..3c548d5 --- /dev/null +++ b/src/EventListener/AdminMenuListener.php @@ -0,0 +1,29 @@ +getMenu(); + + // Get or create the parent group + if (null === ($customerMenu = $menu->getChild('customers'))) { + $customerMenu = $menu->addChild('customers')->setLabel('sylius.ui.customer'); + } + + // Add 'Wishlists' menu item + $customerMenu + ->addChild('webburza_sylius_wishlist.wishlists', ['route' => 'webburza_sylius_wishlist_admin_wishlist_index']) + ->setLabel('webburza_sylius_wishlist.ui.wishlists') + ->setLabelAttribute('icon', 'star'); + } +} diff --git a/Factory/WishlistFactory.php b/src/Factory/WishlistFactory.php similarity index 73% rename from Factory/WishlistFactory.php rename to src/Factory/WishlistFactory.php index eb19265..4826980 100644 --- a/Factory/WishlistFactory.php +++ b/src/Factory/WishlistFactory.php @@ -1,11 +1,13 @@ factory->createNew(); } /** - * @param UserInterface $user + * @param ShopUserInterface $user * * @return WishlistInterface */ - public function createDefault(UserInterface $user) + public function createDefault(ShopUserInterface $user) : WishlistInterface { // Create a new wishlist $wishlist = $this->createNew(); // Set default title - $wishlist->setTitle($this->translator->trans('webburza_wishlist.wishlist.default_title')); + $wishlist->setTitle($this->translator->trans('webburza_sylius_wishlist.ui.default_title')); // Set default public state $wishlist->setPublic($this->defaultPublic); diff --git a/src/Factory/WishlistFactoryInterface.php b/src/Factory/WishlistFactoryInterface.php new file mode 100644 index 0000000..b00f9c4 --- /dev/null +++ b/src/Factory/WishlistFactoryInterface.php @@ -0,0 +1,19 @@ +add('title', Type\TextType::class, [ - 'label' => 'webburza_wishlist.wishlist.label.title', + 'label' => 'sylius.ui.title', 'required' => true, 'constraints' => [ new NotBlank() @@ -24,12 +26,12 @@ public function buildForm(FormBuilderInterface $builder, array $options) ]); $builder->add('description', Type\TextareaType::class, [ - 'label' => 'webburza_wishlist.wishlist.label.description', + 'label' => 'sylius.ui.description', 'required' => false ]); $builder->add('public', Type\CheckboxType::class, [ - 'label' => 'webburza_wishlist.wishlist.label.public', + 'label' => 'webburza_sylius_wishlist.ui.public', 'required' => false ]); } diff --git a/Model/Wishlist.php b/src/Model/Wishlist.php similarity index 50% rename from Model/Wishlist.php rename to src/Model/Wishlist.php index 138c259..9dcad3a 100644 --- a/Model/Wishlist.php +++ b/src/Model/Wishlist.php @@ -1,16 +1,19 @@ id; } @@ -66,7 +69,7 @@ public function getId() /** * @return string */ - public function getTitle() + public function getTitle() : ?string { return $this->title; } @@ -76,7 +79,7 @@ public function getTitle() * * @return WishlistInterface */ - public function setTitle($title) + public function setTitle(?string $title) : WishlistInterface { $this->title = $title; @@ -86,7 +89,7 @@ public function setTitle($title) /** * @return string */ - public function getSlug() + public function getSlug() : string { return $this->slug; } @@ -94,9 +97,9 @@ public function getSlug() /** * @param string $slug * - * @return Wishlist + * @return WishlistInterface */ - public function setSlug($slug) + public function setSlug(string $slug) : WishlistInterface { $this->slug = $slug; @@ -106,7 +109,7 @@ public function setSlug($slug) /** * @return string */ - public function getDescription() + public function getDescription() : ?string { return $this->description; } @@ -114,9 +117,9 @@ public function getDescription() /** * @param string $description * - * @return Wishlist + * @return WishlistInterface */ - public function setDescription($description) + public function setDescription(?string $description) : WishlistInterface { $this->description = $description; @@ -124,19 +127,19 @@ public function setDescription($description) } /** - * @return boolean + * @return bool */ - public function isPublic() + public function isPublic() : bool { return $this->public; } /** - * @param boolean $public + * @param bool $public * * @return WishlistInterface */ - public function setPublic($public) + public function setPublic(bool $public) : WishlistInterface { $this->public = $public; @@ -146,17 +149,17 @@ public function setPublic($public) /** * @return ShopUserInterface */ - public function getUser() + public function getUser() : ShopUserInterface { return $this->user; } /** - * @param UserInterface $user + * @param ShopUserInterface $user * - * @return Wishlist + * @return WishlistInterface */ - public function setUser(UserInterface $user = null) + public function setUser(ShopUserInterface $user) : WishlistInterface { $this->user = $user; @@ -164,9 +167,9 @@ public function setUser(UserInterface $user = null) } /** - * @return ArrayCollection|WishlistItemInterface[] + * @return Collection|WishlistItemInterface[] */ - public function getItems() + public function getItems() : Collection { return $this->items; } @@ -174,7 +177,7 @@ public function getItems() /** * @return bool */ - public function hasItems() + public function hasItems() : bool { return !$this->items->isEmpty(); } @@ -184,7 +187,7 @@ public function hasItems() * * @return WishlistInterface */ - public function addItem(WishlistItemInterface $item) + public function addItem(WishlistItemInterface $item) : WishlistInterface { $this->items->add($item); $item->setWishlist($this); @@ -192,15 +195,55 @@ public function addItem(WishlistItemInterface $item) return $this; } + /** + * @param WishlistItemInterface $item + * + * @return WishlistInterface + */ + public function removeItem(WishlistItemInterface $item) : WishlistInterface + { + $this->items->removeElement($item); + + return $this; + } + + /** + * @return WishlistInterface + */ + public function clearItems() : WishlistInterface + { + foreach ($this->getItems() as $item) { + $this->removeItem($item); + } + + return $this; + } + /** * @param ProductVariantInterface $productVariant * * @return bool */ - public function contains(ProductVariantInterface $productVariant) + public function containsVariant(ProductVariantInterface $productVariant) : bool + { + foreach ($this->items as $wishlistItem) { + if ($wishlistItem->getProductVariant() === $productVariant) { + return true; + } + } + + return false; + } + + /** + * @param ProductInterface $product + * + * @return bool + */ + public function containsProduct(ProductInterface $product) : bool { foreach ($this->items as $wishlistItem) { - if ($wishlistItem->getProductVariant() == $productVariant) { + if ($wishlistItem->getProductVariant()->getProduct() === $product) { return true; } } diff --git a/src/Model/WishlistInterface.php b/src/Model/WishlistInterface.php new file mode 100644 index 0000000..cb46fb7 --- /dev/null +++ b/src/Model/WishlistInterface.php @@ -0,0 +1,118 @@ +id; } @@ -38,7 +37,7 @@ public function getId() /** * @return WishlistInterface */ - public function getWishlist() + public function getWishlist() : WishlistInterface { return $this->wishlist; } @@ -48,7 +47,7 @@ public function getWishlist() * * @return WishlistItemInterface */ - public function setWishlist(WishlistInterface $wishlist) + public function setWishlist(WishlistInterface $wishlist) : WishlistItemInterface { $this->wishlist = $wishlist; @@ -58,7 +57,7 @@ public function setWishlist(WishlistInterface $wishlist) /** * @return ProductVariantInterface */ - public function getProductVariant() + public function getProductVariant() : ProductVariantInterface { return $this->productVariant; } @@ -68,7 +67,7 @@ public function getProductVariant() * * @return WishlistItemInterface */ - public function setProductVariant(ProductVariantInterface $productVariant) + public function setProductVariant(ProductVariantInterface $productVariant) : WishlistItemInterface { $this->productVariant = $productVariant; diff --git a/Model/WishlistItemInterface.php b/src/Model/WishlistItemInterface.php similarity index 53% rename from Model/WishlistItemInterface.php rename to src/Model/WishlistItemInterface.php index 6a98caa..39cb912 100644 --- a/Model/WishlistItemInterface.php +++ b/src/Model/WishlistItemInterface.php @@ -1,37 +1,36 @@ tokenStorage = $tokenStorage; + } + + /** + * @return ShopUserInterface|null + */ + public function getUser() : ?ShopUserInterface + { + if ($securityToken = $this->tokenStorage->getToken()) { + if (($user = $securityToken->getUser()) instanceof ShopUserInterface) { + return $user; + } + } + + return null; + } +} diff --git a/src/Provider/LoggedInUserProviderInterface.php b/src/Provider/LoggedInUserProviderInterface.php new file mode 100644 index 0000000..ee041a5 --- /dev/null +++ b/src/Provider/LoggedInUserProviderInterface.php @@ -0,0 +1,15 @@ +repository = $repository; - $this->tokenStorage = $tokenStorage; + $this->loggedInUserProvider = $loggedInUserProvider; } /** * @return WishlistInterface[] */ - public function getWishlists() + public function getWishlists() : array { if (null === $this->wishlists) { - if ($user = $this->getUser()) { + if ($user = $this->loggedInUserProvider->getUser()) { $this->wishlists = $this->repository->findBy(['user' => $user]); } } - return $this->wishlists; + return $this->wishlists ?: []; } /** * @return int */ - public function getItemCount() + public function getItemCount() : int { $itemCount = 0; @@ -65,18 +65,4 @@ public function getItemCount() return $itemCount; } - - /** - * @return UserInterface - */ - protected function getUser() - { - if ($securityToken = $this->tokenStorage->getToken()) { - if (($user = $securityToken->getUser()) instanceof UserInterface) { - return $user; - } - } - - return null; - } } diff --git a/src/Provider/WishlistProviderInterface.php b/src/Provider/WishlistProviderInterface.php new file mode 100644 index 0000000..9c89fa4 --- /dev/null +++ b/src/Provider/WishlistProviderInterface.php @@ -0,0 +1,20 @@ +productVariantRepository = $productVariantRepository; $this->productRepository = $productRepository; $this->addToCartCommandFactory = $addToCartCommandFactory; $this->cartContext = $cartContext; @@ -69,7 +78,27 @@ public function __construct( * * @return ProductVariantInterface */ - public function resolve(Request $request) + public function resolve(Request $request) : ProductVariantInterface + { + if ($productVariantId = $request->get('productVariantId')) { + $productVariant = $this->productVariantRepository->find($productVariantId); + } else { + $productVariant = $this->resolveViaCartForm($request); + } + + if (!$productVariant) { + throw new BadRequestHttpException(); + } + + return $productVariant; + } + + /** + * @param Request $request + * + * @return ProductVariantInterface + */ + protected function resolveViaCartForm(Request $request) : ?ProductVariantInterface { /** @var ProductInterface $product */ if (!($product = $this->productRepository->find($request->get('productId')))) { diff --git a/src/Resolver/ProductVariantFromRequestResolverInterface.php b/src/Resolver/ProductVariantFromRequestResolverInterface.php new file mode 100644 index 0000000..0bf6939 --- /dev/null +++ b/src/Resolver/ProductVariantFromRequestResolverInterface.php @@ -0,0 +1,18 @@ +loggedInUserProvider = $loggedInUserProvider; + $this->wishlistRepository = $wishlistRepository; + $this->wishlistFactory = $wishlistFactory; + } + + /** + * Get the requested wishlist, if any, or the first one for the logged-in user. + * If none exists for the user, create a new one. + * + * @param Request $request + * + * @return WishlistInterface + */ + public function resolve(Request $request) : WishlistInterface + { + // Abort if no logged-in user + if (!($user = $this->loggedInUserProvider->getUser())) { + throw new BadRequestHttpException(); + } + + // Check if a specific wishlist was requested + if ($wishlistId = $request->get('wishlistId')) { + /** @var WishlistInterface $wishlist */ + $wishlist = $this->wishlistRepository->findOneBy([ + 'id' => $wishlistId, + 'user' => $user + ]); + + if (!$wishlist) { + throw new NotFoundHttpException(); + } + + return $wishlist; + } + + // If not, get the first wishlist for the user + $wishlist = $this->wishlistRepository->getFirstForUser($user); + + // If no wishlist found, create a new one + if (!$wishlist) { + $wishlist = $this->wishlistFactory->createDefault($user); + $this->wishlistRepository->add($wishlist); + } + + return $wishlist; + } +} diff --git a/src/Resolver/WishlistFromRequestResolverInterface.php b/src/Resolver/WishlistFromRequestResolverInterface.php new file mode 100644 index 0000000..6250cc5 --- /dev/null +++ b/src/Resolver/WishlistFromRequestResolverInterface.php @@ -0,0 +1,18 @@ + - + - - + + + + + + + + + + + + + - + - - - - - - diff --git a/Resources/config/doctrine/WishlistItem.orm.xml b/src/Resources/config/doctrine/WishlistItem.orm.xml similarity index 88% rename from Resources/config/doctrine/WishlistItem.orm.xml rename to src/Resources/config/doctrine/WishlistItem.orm.xml index 3ff277e..aefb441 100644 --- a/Resources/config/doctrine/WishlistItem.orm.xml +++ b/src/Resources/config/doctrine/WishlistItem.orm.xml @@ -6,11 +6,19 @@ xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> - + + + + + + + + + @@ -19,14 +27,6 @@ - - - - - - - - diff --git a/src/Resources/config/routing.yml b/src/Resources/config/routing.yml new file mode 100644 index 0000000..60c1557 --- /dev/null +++ b/src/Resources/config/routing.yml @@ -0,0 +1,10 @@ +webburza_sylius_wishlist_admin: + resource: routing/admin.yml + +webburza_sylius_wishlist_shop: + resource: routing/shop.yml + prefix: /wishlist + +webburza_sylius_wishlist_account: + resource: routing/account.yml + prefix: /account/wishlists diff --git a/src/Resources/config/routing/account.yml b/src/Resources/config/routing/account.yml new file mode 100644 index 0000000..9e35c2c --- /dev/null +++ b/src/Resources/config/routing/account.yml @@ -0,0 +1,29 @@ +webburza_sylius_wishlist_account_wishlist_create: + path: /new + methods: [GET, POST] + defaults: + _controller: webburza_sylius_wishlist.controller.account.wishlist:createAction + +webburza_sylius_wishlist_account_wishlist_edit: + path: /{id}/edit + methods: [GET] + defaults: + _controller: webburza_sylius_wishlist.controller.account.wishlist:updateAction + +webburza_sylius_wishlist_account_wishlist_update: + path: /{id} + methods: [PUT] + defaults: + _controller: webburza_sylius_wishlist.controller.account.wishlist:updateAction + +webburza_sylius_wishlist_account_wishlist_index: + path: / + methods: [GET] + defaults: + _controller: webburza_sylius_wishlist.controller.account.wishlist:indexAction + +webburza_sylius_wishlist_account_wishlist_delete: + path: /{id} + methods: [DELETE] + defaults: + _controller: webburza_sylius_wishlist.controller.account.wishlist:deleteAction diff --git a/src/Resources/config/routing/admin.yml b/src/Resources/config/routing/admin.yml new file mode 100644 index 0000000..c0da06a --- /dev/null +++ b/src/Resources/config/routing/admin.yml @@ -0,0 +1,14 @@ +webburza_sylius_wishlist_admin_wishlist: + resource: | + alias: webburza_sylius_wishlist.wishlist + section: admin + templates: WebburzaSyliusWishlistPlugin:Admin + except: ['create', 'update'] + grid: webburza_sylius_wishlist_admin_wishlist + vars: + all: + subheader: webburza_sylius_wishlist.ui.manage_wishlists + index: + icon: 'file star' + type: sylius.resource + prefix: /admin diff --git a/src/Resources/config/routing/shop.yml b/src/Resources/config/routing/shop.yml new file mode 100644 index 0000000..3f5b44a --- /dev/null +++ b/src/Resources/config/routing/shop.yml @@ -0,0 +1,38 @@ +# Show the first wishlist for the current user, only if the bundle +# is configured for a single wishlist per user, otherwise redirect + +webburza_sylius_wishlist_shop_wishlist_first: + path: / + methods: [GET] + defaults: + _controller: webburza_sylius_wishlist.controller.shop.wishlist:firstAction + +webburza_sylius_wishlist_shop_wishlist_clear: + path: /{id}/clear + methods: [POST] + defaults: + _controller: webburza_sylius_wishlist.controller.shop.wishlist:clearAction + +webburza_sylius_wishlist_shop_wishlist_add_item: + path: /item + methods: [POST] + defaults: + _controller: webburza_sylius_wishlist.controller.shop.wishlist_item:addAction + +webburza_sylius_wishlist_shop_wishlist_remove_item: + path: /item/{id} + methods: [DELETE] + defaults: + _controller: webburza_sylius_wishlist.controller.shop.wishlist_item:removeAction + +webburza_sylius_wishlist_shop_add_to_cart: + path: /item/add-to-cart + methods: [GET] + defaults: + _controller: webburza_sylius_wishlist.controller.shop.wishlist_item:addToCartAction + +webburza_sylius_wishlist_shop_wishlist_show: + path: /{id}/{slug} + methods: [GET] + defaults: + _controller: webburza_sylius_wishlist.controller.shop.wishlist:showAction diff --git a/src/Resources/config/serializer/Model.Wishlist.yml b/src/Resources/config/serializer/Model.Wishlist.yml new file mode 100644 index 0000000..79a15e8 --- /dev/null +++ b/src/Resources/config/serializer/Model.Wishlist.yml @@ -0,0 +1,23 @@ +Webburza\SyliusWishlistPlugin\Model\Wishlist: + exclusion_policy: ALL + xml_root_name: webburza-wishlist + properties: + id: + expose: true + type: integer + xml_attribute: true + title: + expose: true + type: string + slug: + expose: true + type: string + description: + expose: true + type: string + public: + expose: true + type: bool + items: + expose: true + type: array diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml new file mode 100644 index 0000000..80b8f53 --- /dev/null +++ b/src/Resources/config/services.yml @@ -0,0 +1,6 @@ +imports: + - { resource: services/providers.yml } + - { resource: services/controllers.yml } + - { resource: services/resolvers.yml } + - { resource: services/listeners.yml } + - { resource: services/misc.yml } diff --git a/src/Resources/config/services/controllers.yml b/src/Resources/config/services/controllers.yml new file mode 100644 index 0000000..381f956 --- /dev/null +++ b/src/Resources/config/services/controllers.yml @@ -0,0 +1,34 @@ +services: + webburza_sylius_wishlist.controller.shop.wishlist: + class: Webburza\SyliusWishlistPlugin\Controller\Shop\WishlistController + arguments: + - '@webburza_sylius_wishlist.provider.logged_in_user' + - '@webburza_sylius_wishlist.repository.wishlist' + - '@webburza_sylius_wishlist.factory.wishlist' + - '@translator' + - '@fos_rest.view_handler.default' + - '%webburza_sylius_wishlist.config.multiple%' + + webburza_sylius_wishlist.controller.shop.wishlist_item: + class: Webburza\SyliusWishlistPlugin\Controller\Shop\WishlistItemController + arguments: + - '@webburza_sylius_wishlist.provider.logged_in_user' + - '@webburza_sylius_wishlist.repository.wishlist_item' + - '@translator' + - '@sylius.context.cart' + - '@sylius.repository.product_variant' + - '@sylius.custom_factory.order_item' + - '@sylius.factory.add_to_cart_command' + - '@webburza_sylius_wishlist.resolver.wishlist_from_request' + - '@webburza_sylius_wishlist.resolver.product_variant_from_request' + - '@webburza_sylius_wishlist.factory.wishlist_item' + - '%webburza_sylius_wishlist.config.multiple%' + + webburza_sylius_wishlist.controller.account.wishlist: + class: Webburza\SyliusWishlistPlugin\Controller\Account\WishlistController + arguments: + - '@webburza_sylius_wishlist.repository.wishlist' + - '@webburza_sylius_wishlist.provider.logged_in_user' + - '@translator' + - '@form.factory' + - '%webburza_sylius_wishlist.config.multiple%' diff --git a/src/Resources/config/services/listeners.yml b/src/Resources/config/services/listeners.yml new file mode 100644 index 0000000..7336b18 --- /dev/null +++ b/src/Resources/config/services/listeners.yml @@ -0,0 +1,15 @@ +services: + webburza_sylius_wishlist.event_listener.admin_menu: + class: Webburza\SyliusWishlistPlugin\EventListener\AdminMenuListener + tags: + - { name: kernel.event_listener, event: sylius.menu.admin.main, method: addMenuItems } + + webburza_sylius_wishlist.event_listener.account_menu: + class: Webburza\SyliusWishlistPlugin\EventListener\AccountMenuListener + arguments: + - '@translator' + - '@webburza_sylius_wishlist.provider.logged_in_user' + - '@webburza_sylius_wishlist.repository.wishlist' + - '%webburza_sylius_wishlist.config.multiple%' + tags: + - { name: kernel.event_listener, event: sylius.menu.shop.account, method: addMenuItems } diff --git a/src/Resources/config/services/misc.yml b/src/Resources/config/services/misc.yml new file mode 100644 index 0000000..c78d7d7 --- /dev/null +++ b/src/Resources/config/services/misc.yml @@ -0,0 +1,15 @@ +services: + webburza_sylius_wishlist.factory.decorated.wishlist: + class: Webburza\SyliusWishlistPlugin\Factory\WishlistFactory + decorates: webburza_sylius_wishlist.factory.wishlist + arguments: + - '@webburza_sylius_wishlist.factory.decorated.wishlist.inner' + - '@translator' + - '%webburza_sylius_wishlist.config.default_public%' + + webburza_sylius_wishlist.form.type.wishlist_type: + class: Webburza\SyliusWishlistPlugin\Form\Type\WishlistType + arguments: + - '%webburza_sylius_wishlist.model.wishlist.class%' + tags: + - { name: form.type } diff --git a/src/Resources/config/services/providers.yml b/src/Resources/config/services/providers.yml new file mode 100644 index 0000000..2e61e3b --- /dev/null +++ b/src/Resources/config/services/providers.yml @@ -0,0 +1,11 @@ +services: + webburza_sylius_wishlist.provider.logged_in_user: + class: Webburza\SyliusWishlistPlugin\Provider\LoggedInUserProvider + arguments: + - '@security.token_storage' + + webburza_sylius_wishlist.provider.wishlist: + class: Webburza\SyliusWishlistPlugin\Provider\WishlistProvider + arguments: + - '@webburza_sylius_wishlist.repository.wishlist' + - '@webburza_sylius_wishlist.provider.logged_in_user' diff --git a/src/Resources/config/services/resolvers.yml b/src/Resources/config/services/resolvers.yml new file mode 100644 index 0000000..bd6a1a7 --- /dev/null +++ b/src/Resources/config/services/resolvers.yml @@ -0,0 +1,17 @@ +services: + webburza_sylius_wishlist.resolver.wishlist_from_request: + class: Webburza\SyliusWishlistPlugin\Resolver\WishlistFromRequestResolver + arguments: + - '@webburza_sylius_wishlist.provider.logged_in_user' + - '@webburza_sylius_wishlist.repository.wishlist' + - '@webburza_sylius_wishlist.factory.decorated.wishlist' + + webburza_sylius_wishlist.resolver.product_variant_from_request: + class: Webburza\SyliusWishlistPlugin\Resolver\ProductVariantFromRequestResolver + arguments: + - '@sylius.repository.product_variant' + - '@sylius.repository.product' + - '@sylius.factory.add_to_cart_command' + - '@sylius.context.cart' + - '@sylius.custom_factory.order_item' + - '@form.factory' diff --git a/Resources/translations/messages.en.yml b/src/Resources/translations/messages.en.yml similarity index 70% rename from Resources/translations/messages.en.yml rename to src/Resources/translations/messages.en.yml index d387dbb..da6154f 100644 --- a/Resources/translations/messages.en.yml +++ b/src/Resources/translations/messages.en.yml @@ -1,4 +1,4 @@ -webburza_wishlist: +webburza_sylius_wishlist: ui: wishlist: Wishlist wishlists: Wishlists @@ -7,14 +7,17 @@ webburza_wishlist: wishlist_is_empty: This wishlist has no items. not_public: This wishlist is private. clear_wishlist: Clear all items - customer: Customer - add_to_cart: Add to cart add_to_wishlist: Add to wishlist - remove_from_wishlist: Remove controls: Controls - my_wishlist: Wishlist - my_wishlists: My wishlists + account_wishlist: Wishlist + account_wishlists: Wishlists + account_manage_wishlists: Manage your wishlists deleted: Wishlist deleted successfully. + default_title: Wishlist + item_count: Item count + description: Description + public: Public? + updated_at: Updated At account: update: @@ -33,14 +36,3 @@ webburza_wishlist: updated: Wishlist updated successfully. item_added: Item added to wishlist. item_removed: Item removed successfully. - - wishlist: - default_title: Wishlist - label: - id: Id - title: Title - description: Description - public: Public? - created_at: Created At - updated_at: Updated At - user: User diff --git a/Resources/views/Frontend/Account/Wishlist/create.html.twig b/src/Resources/views/Account/create.html.twig similarity index 58% rename from Resources/views/Frontend/Account/Wishlist/create.html.twig rename to src/Resources/views/Account/create.html.twig index 59131e1..0b58934 100644 --- a/Resources/views/Frontend/Account/Wishlist/create.html.twig +++ b/src/Resources/views/Account/create.html.twig @@ -8,19 +8,21 @@
/
{{ 'sylius.ui.my_account'|trans }}
/
- {{ 'webburza_wishlist.account.index.header'|trans }} + + {{ 'webburza_sylius_wishlist.account.index.header'|trans }} +
/
-
{{ 'webburza_wishlist.account.create.header'|trans }}
+
{{ 'webburza_sylius_wishlist.account.create.header'|trans }}
{% endblock %} {% block subcontent %}
- {{ form_start(form, {'action': path('webburza_account_wishlist_create'), 'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }} + {{ form_start(form, {'action': path('webburza_sylius_wishlist_account_wishlist_create'), 'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }}

- {{ 'webburza_wishlist.account.create.header'|trans }} -
{{ 'webburza_wishlist.account.create.subheader'|trans }}
+ {{ 'webburza_sylius_wishlist.account.create.header'|trans }} +
{{ 'webburza_sylius_wishlist.account.create.subheader'|trans }}

{{ form_errors(form) }} diff --git a/Resources/views/Frontend/Account/Wishlist/index.html.twig b/src/Resources/views/Account/index.html.twig similarity index 69% rename from Resources/views/Frontend/Account/Wishlist/index.html.twig rename to src/Resources/views/Account/index.html.twig index b923e80..37369fe 100644 --- a/Resources/views/Frontend/Account/Wishlist/index.html.twig +++ b/src/Resources/views/Account/index.html.twig @@ -9,7 +9,7 @@
/
{{ 'sylius.ui.my_account'|trans }}
/
-
{{ 'webburza_wishlist.account.index.header'|trans }}
+
{{ 'webburza_sylius_wishlist.account.index.header'|trans }}
{% endblock %} @@ -17,12 +17,12 @@

- {{ 'webburza_wishlist.account.index.header'|trans }} -
{{ 'webburza_wishlist.account.index.subheader'|trans }}
+ {{ 'webburza_sylius_wishlist.account.index.header'|trans }} +
{{ 'webburza_sylius_wishlist.account.index.subheader'|trans }}

- {{ buttons.create(path('webburza_account_wishlist_create')) }} + {{ buttons.create(path('webburza_sylius_wishlist_account_wishlist_create')) }}
@@ -31,8 +31,8 @@ - - + + @@ -40,7 +40,10 @@ {% for wishlist in wishlists %} @@ -49,8 +52,8 @@ diff --git a/Resources/views/Frontend/Account/Wishlist/update.html.twig b/src/Resources/views/Account/update.html.twig similarity index 56% rename from Resources/views/Frontend/Account/Wishlist/update.html.twig rename to src/Resources/views/Account/update.html.twig index 1eb3639..de2519c 100644 --- a/Resources/views/Frontend/Account/Wishlist/update.html.twig +++ b/src/Resources/views/Account/update.html.twig @@ -8,21 +8,23 @@
/
{{ 'sylius.ui.my_account'|trans }}
/
- {{ 'webburza_wishlist.account.index.header'|trans }} + {{ 'webburza_sylius_wishlist.account.index.header'|trans }}
/
-
{{ 'webburza_wishlist.account.update.header'|trans }}
+
{{ 'webburza_sylius_wishlist.account.update.header'|trans }}
{% endblock %} {% block subcontent %}
- {{ form_start(form, {'action': path('webburza_account_wishlist_update', {id: wishlist.id}), 'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }} + {{ form_start(form, {'action': path('webburza_sylius_wishlist_account_wishlist_update', {id: wishlist.id}), 'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }}

- {{ 'webburza_wishlist.account.update.header'|trans }} -
{{ 'webburza_wishlist.account.update.subheader'|trans }}
+ {{ 'webburza_sylius_wishlist.account.update.header'|trans }} +
{{ 'webburza_sylius_wishlist.account.update.subheader'|trans }}

+ + {{ form_errors(form) }} {{ form_rest(form) }} diff --git a/src/Resources/views/Admin/Grid/_count.html.twig b/src/Resources/views/Admin/Grid/_count.html.twig new file mode 100644 index 0000000..93a1412 --- /dev/null +++ b/src/Resources/views/Admin/Grid/_count.html.twig @@ -0,0 +1 @@ +{{ data.items.count }} diff --git a/src/Resources/views/Admin/Grid/_customer.html.twig b/src/Resources/views/Admin/Grid/_customer.html.twig new file mode 100644 index 0000000..4ae5d87 --- /dev/null +++ b/src/Resources/views/Admin/Grid/_customer.html.twig @@ -0,0 +1 @@ +{{ data.customer.email }} diff --git a/src/Resources/views/Admin/Show/_breadcrumb.html.twig b/src/Resources/views/Admin/Show/_breadcrumb.html.twig new file mode 100644 index 0000000..effaa93 --- /dev/null +++ b/src/Resources/views/Admin/Show/_breadcrumb.html.twig @@ -0,0 +1,10 @@ +{% import '@SyliusAdmin/Macro/breadcrumb.html.twig' as breadcrumb %} + +{% set breadcrumbs = [ + { label: 'sylius.ui.administration'|trans, url: path('sylius_admin_dashboard') }, + { label: (metadata.applicationName~'.ui.'~metadata.pluralName)|trans, url: path(configuration.getRouteName('index'), configuration.vars.route.parameters|default({})) }, + { label: resource.title|default(resource.id)} + ] +%} + +{{ breadcrumb.crumble(breadcrumbs) }} diff --git a/src/Resources/views/Admin/Show/_details.html.twig b/src/Resources/views/Admin/Show/_details.html.twig new file mode 100644 index 0000000..19910a7 --- /dev/null +++ b/src/Resources/views/Admin/Show/_details.html.twig @@ -0,0 +1,38 @@ +
+
{{ 'webburza_wishlist.wishlist.label.title' | trans }}{{ 'webburza_wishlist.wishlist.label.public' | trans }}{{ 'sylius.ui.title' | trans }}{{ 'webburza_sylius_wishlist.ui.public' | trans }} {{ 'sylius.ui.actions' | trans }}
- + {{ wishlist.title }}
- {{ buttons.edit(path('webburza_account_wishlist_edit', { id: wishlist.id })) }} - {{ buttons.delete(path('webburza_account_wishlist_delete', { id: wishlist.id })) }} + {{ buttons.edit(path('webburza_sylius_wishlist_account_wishlist_edit', { id: wishlist.id })) }} + {{ buttons.delete(path('webburza_sylius_wishlist_account_wishlist_delete', { id: wishlist.id })) }}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ 'sylius.ui.details'|trans }}
{{ 'sylius.ui.title'|trans }}{{ wishlist.title }}
{{ 'sylius.ui.description'|trans }}{{ wishlist.description }}
{{ 'sylius.ui.customer'|trans }} + {{ wishlist.user.customer.email }} +
{{ 'webburza_sylius_wishlist.ui.public'|trans }}{% include '@SyliusUi/Grid/Field/yesNo.html.twig' with {data: wishlist.public} %}
{{ 'sylius.ui.created_at' | trans }}{{ wishlist.createdAt | format_date }}
{{ 'webburza_sylius_wishlist.ui.updated_at' | trans }}{{ wishlist.updatedAt ? (wishlist.updatedAt | format_date) : '' }}
+ diff --git a/src/Resources/views/Admin/Show/_header.html.twig b/src/Resources/views/Admin/Show/_header.html.twig new file mode 100644 index 0000000..1774269 --- /dev/null +++ b/src/Resources/views/Admin/Show/_header.html.twig @@ -0,0 +1,15 @@ +
+

+ +
+ {{ wishlist.title }} +
+
+
+ {{ wishlist.user.customer.email }} +
+
+
+
+

+
diff --git a/src/Resources/views/Admin/Show/_items.html.twig b/src/Resources/views/Admin/Show/_items.html.twig new file mode 100644 index 0000000..45bf5e7 --- /dev/null +++ b/src/Resources/views/Admin/Show/_items.html.twig @@ -0,0 +1,40 @@ +{% import '@SyliusUi/Macro/messages.html.twig' as messages %} + +
+ + + + + + + + + {% if wishlist.hasItems %} + {% for item in wishlist.items %} + + + + {% endfor %} + {% else %} + + + + {% endif %} + +
{{ 'webburza_sylius_wishlist.ui.wishlist_items'|trans }}
+ + {{ item.productVariant.product.name }} + +
+ + {% if item.productVariant.optionValues is not empty %} + {% for optionValue in item.productVariant.optionValues %} + {{ optionValue.value }}{{ not loop.last ? ', ' : '' }} + {% endfor %} + {% elseif item.productVariant.name is not empty %} + {{ item.productVariant.name }} + {% endif %} + +
{{ messages.info('webburza_sylius_wishlist.ui.wishlist_is_empty') }}
+
+ diff --git a/src/Resources/views/Admin/index.html.twig b/src/Resources/views/Admin/index.html.twig new file mode 100644 index 0000000..2442b25 --- /dev/null +++ b/src/Resources/views/Admin/index.html.twig @@ -0,0 +1 @@ +{% extends 'SyliusAdminBundle:Crud:index.html.twig' %} diff --git a/src/Resources/views/Admin/show.html.twig b/src/Resources/views/Admin/show.html.twig new file mode 100644 index 0000000..61e97dd --- /dev/null +++ b/src/Resources/views/Admin/show.html.twig @@ -0,0 +1,18 @@ +{% extends 'SyliusAdminBundle::layout.html.twig' %} + +{% block title %}{{ wishlist.title ~ ' (' ~ wishlist.user.customer.email ~ ')' }} {{ parent() }}{% endblock %} + +{% block content %} +
+ {% include '@WebburzaSyliusWishlistPlugin/Resources/views/Admin/Show/_header.html.twig' %} +
+ +
+ + {% include '@WebburzaSyliusWishlistPlugin/Resources/views/Admin/Show/_breadcrumb.html.twig' %} + +
+ {% include '@WebburzaSyliusWishlistPlugin/Resources/views/Admin/Show/_details.html.twig' %} + {% include '@WebburzaSyliusWishlistPlugin/Resources/views/Admin/Show/_items.html.twig' %} +
+{% endblock %} diff --git a/Resources/views/Frontend/Shop/_addToWishlist.html.twig b/src/Resources/views/Shop/Misc/_addToWishlist.html.twig similarity index 75% rename from Resources/views/Frontend/Shop/_addToWishlist.html.twig rename to src/Resources/views/Shop/Misc/_addToWishlist.html.twig index 981e938..c588752 100644 --- a/Resources/views/Frontend/Shop/_addToWishlist.html.twig +++ b/src/Resources/views/Shop/Misc/_addToWishlist.html.twig @@ -2,7 +2,7 @@ {% if wishlist_provider.wishlists | length > 1 %}
- +