Skip to content

Commit

Permalink
Creating the JS to handle adding/removing items from wishlist
Browse files Browse the repository at this point in the history
Starting work on interface to show wishlists
  • Loading branch information
loevgaard committed Oct 29, 2024
1 parent ba46c44 commit 91d486c
Show file tree
Hide file tree
Showing 30 changed files with 469 additions and 42 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"symfony/config": "^5.4 || ^6.4 || ^7.0",
"symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0",
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.0",
"symfony/serializer": "^5.4 || ^6.4 || ^7.0"
"symfony/serializer": "^5.4 || ^6.4 || ^7.0",
"symfony/uid": "^5.4 || ^6.4 || ^7.0"
},
"require-dev": {
"api-platform/core": "^2.7.16",
Expand Down
74 changes: 66 additions & 8 deletions src/Controller/WishlistController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
use Setono\SyliusWishlistPlugin\Controller\Command\SelectWishlistsCommand;
use Setono\SyliusWishlistPlugin\Factory\WishlistItemFactoryInterface;
use Setono\SyliusWishlistPlugin\Form\Type\SelectWishlistsType;
use Setono\SyliusWishlistPlugin\Model\WishlistInterface;
use Setono\SyliusWishlistPlugin\Provider\WishlistProviderInterface;
use Setono\SyliusWishlistPlugin\Repository\WishlistRepositoryInterface;
use Sylius\Component\Core\Model\ProductInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Expand All @@ -29,18 +32,36 @@ public function __construct(
private readonly FormFactoryInterface $formFactory,
/** @var class-string<ProductInterface> $productClass */
private readonly string $productClass,
/** @var class-string<WishlistInterface> $wishlistClass */
private readonly string $wishlistClass,
) {
$this->managerRegistry = $managerRegistry;
}

public function add(int $product): Response
public function index(): Response
{
$productEntity = $this->getManager($this->productClass)->find($this->productClass, $product);
return new Response($this->twig->render('@SetonoSyliusWishlistPlugin/shop/wishlist/index.html.twig', [
'wishlists' => $this->wishlistProvider->getWishlists(),
]));
}

public function show(string $uuid): Response
{
$wishlist = $this->getRepository($this->wishlistClass, WishlistRepositoryInterface::class)->findOneByUuid($uuid);

if (null === $productEntity) {
throw new NotFoundHttpException(sprintf('Product with id %s not found', $product));
if (null === $wishlist) {
throw new NotFoundHttpException(sprintf('Wishlist with id %s not found', $uuid));
}

return new Response($this->twig->render('@SetonoSyliusWishlistPlugin/shop/wishlist/show.html.twig', [
'wishlist' => $wishlist,
]));
}

public function add(int $product): JsonResponse
{
$productEntity = $this->getProduct($product);

$wishlistItem = $this->wishlistItemFactory->createWithProduct($productEntity);

$preSelectedWishlists = $this->wishlistProvider->getPreSelectedWishlists();
Expand All @@ -57,13 +78,50 @@ public function add(int $product): Response
'selected' => $preSelectedWishlists,
]);

return new Response($this->twig->render('@SetonoSyliusWishlistPlugin/shop/wishlist/select_wishlists.html.twig', [
'product' => $productEntity,
'form' => $form->createView(),
]));
return new JsonResponse([
'toggleButton' => $this->twig->render('@SetonoSyliusWishlistPlugin/shop/wishlist/_toggle_button.html.twig', [
'product' => $productEntity,
]),
'selectWishlistsForm' => $this->twig->render('@SetonoSyliusWishlistPlugin/shop/wishlist/_select_wishlists.html.twig', [
'product' => $productEntity,
'form' => $form->createView(),
]),
]);
}

public function remove(int $product, int $wishlist = null): JsonResponse
{
$productEntity = $this->getProduct($product);

foreach ($this->wishlistProvider->getWishlists() as $wishlistEntity) {
if (null !== $wishlist && $wishlistEntity->getId() !== $wishlist) {
continue;
}

$wishlistEntity->removeProduct($productEntity);
}

$this->getManager($wishlistEntity)->flush();

return new JsonResponse([
'toggleButton' => $this->twig->render('@SetonoSyliusWishlistPlugin/shop/wishlist/_toggle_button.html.twig', [
'product' => $productEntity,
]),
]);
}

public function selectWishlists(Request $request, int $product): Response
{
}

private function getProduct(int $id): ProductInterface
{
$product = $this->getManager($this->productClass)->find($this->productClass, $id);

if (null === $product) {
throw new NotFoundHttpException(sprintf('Product with id %s not found', $id));
}

return $product;
}
}
3 changes: 2 additions & 1 deletion src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Setono\SyliusWishlistPlugin\Model\WishlistItem;
use Setono\SyliusWishlistPlugin\Repository\GuestWishlistRepository;
use Setono\SyliusWishlistPlugin\Repository\UserWishlistRepository;
use Setono\SyliusWishlistPlugin\Repository\WishlistRepository;
use Sylius\Component\Resource\Factory\Factory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
Expand Down Expand Up @@ -47,7 +48,7 @@ private function addResourcesSection(ArrayNodeDefinition $node): void
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->defaultValue(Wishlist::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->scalarNode('repository')->defaultValue(WishlistRepository::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->end()
->end()
->end()
Expand Down
25 changes: 24 additions & 1 deletion src/DependencyInjection/SetonoSyliusWishlistExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;

final class SetonoSyliusWishlistExtension extends AbstractResourceExtension
final class SetonoSyliusWishlistExtension extends AbstractResourceExtension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container): void
{
Expand All @@ -31,4 +32,26 @@ public function load(array $configs, ContainerBuilder $container): void

$loader->load('services.xml');
}

public function prepend(ContainerBuilder $container): void
{
$container->prependExtensionConfig('sylius_ui', [
'events' => [
'sylius.shop.layout.stylesheets' => [
'blocks' => [
'setono_sylius_wishlist__styles' => [
'template' => '@SetonoSyliusWishlistPlugin/shop/_styles.html.twig',
],
],
],
'sylius.shop.layout.javascripts' => [
'blocks' => [
'setono_sylius_wishlist__javascripts' => [
'template' => '@SetonoSyliusWishlistPlugin/shop/_javascripts.html.twig',
],
],
],
],
]);
}
}
30 changes: 30 additions & 0 deletions src/Model/Wishlist.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,26 @@

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Resource\Model\TimestampableTrait;
use Symfony\Component\Uid\Uuid;

abstract class Wishlist implements WishlistInterface
{
use TimestampableTrait;

protected ?int $id = null;

protected string $uuid;

protected ?string $name = null;

/** @var Collection<array-key, WishlistItemInterface> */
protected Collection $items;

public function __construct()
{
$this->uuid = (string) Uuid::v7();
$this->items = new ArrayCollection();
}

Expand All @@ -29,6 +34,11 @@ public function getId(): ?int
return $this->id;
}

public function getUuid(): string
{
return $this->uuid;
}

public function getName(): ?string
{
return $this->name;
Expand Down Expand Up @@ -64,4 +74,24 @@ public function getItems(): Collection
{
return $this->items;
}

public function hasProduct(ProductInterface $product): bool
{
foreach ($this->items as $item) {
if ($item->getProduct()?->getId() === $product->getId()) {
return true;
}
}

return false;
}

public function removeProduct(ProductInterface $product): void
{
foreach ($this->items as $item) {
if ($item->getProduct()?->getId() === $product->getId()) {
$this->removeItem($item);
}
}
}
}
7 changes: 7 additions & 0 deletions src/Model/WishlistInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
namespace Setono\SyliusWishlistPlugin\Model;

use Doctrine\Common\Collections\Collection;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Resource\Model\ResourceInterface;
use Sylius\Resource\Model\TimestampableInterface;

interface WishlistInterface extends ResourceInterface, TimestampableInterface
{
public function getId(): ?int;

public function getUuid(): string;

public function getName(): ?string;

public function setName(?string $name): void;
Expand All @@ -26,4 +29,8 @@ public function hasItem(WishlistItemInterface $item): bool;
* @return Collection<array-key, WishlistItemInterface>
*/
public function getItems(): Collection;

public function hasProduct(ProductInterface $product): bool;

public function removeProduct(ProductInterface $product): void;
}
3 changes: 1 addition & 2 deletions src/Repository/GuestWishlistRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
namespace Setono\SyliusWishlistPlugin\Repository;

use Setono\SyliusWishlistPlugin\Model\GuestWishlistInterface;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
use Webmozart\Assert\Assert;

class GuestWishlistRepository extends EntityRepository implements GuestWishlistRepositoryInterface
class GuestWishlistRepository extends WishlistRepository implements GuestWishlistRepositoryInterface
{
public function findOneByClientId(string $clientId): ?GuestWishlistInterface
{
Expand Down
5 changes: 2 additions & 3 deletions src/Repository/GuestWishlistRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
namespace Setono\SyliusWishlistPlugin\Repository;

use Setono\SyliusWishlistPlugin\Model\GuestWishlistInterface;
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;

/**
* @extends RepositoryInterface<GuestWishlistInterface>
* @extends WishlistRepositoryInterface<GuestWishlistInterface>
*/
interface GuestWishlistRepositoryInterface extends RepositoryInterface
interface GuestWishlistRepositoryInterface extends WishlistRepositoryInterface
{
public function findOneByClientId(string $clientId): ?GuestWishlistInterface;
}
3 changes: 1 addition & 2 deletions src/Repository/UserWishlistRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
namespace Setono\SyliusWishlistPlugin\Repository;

use Setono\SyliusWishlistPlugin\Model\UserWishlistInterface;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
use Sylius\Component\User\Model\UserInterface;
use Webmozart\Assert\Assert;

class UserWishlistRepository extends EntityRepository implements UserWishlistRepositoryInterface
class UserWishlistRepository extends WishlistRepository implements UserWishlistRepositoryInterface
{
public function findByUser(UserInterface $user): array
{
Expand Down
5 changes: 2 additions & 3 deletions src/Repository/UserWishlistRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@

use Setono\SyliusWishlistPlugin\Model\UserWishlistInterface;
use Sylius\Component\User\Model\UserInterface;
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;

/**
* @extends RepositoryInterface<UserWishlistInterface>
* @extends WishlistRepositoryInterface<UserWishlistInterface>
*/
interface UserWishlistRepositoryInterface extends RepositoryInterface
interface UserWishlistRepositoryInterface extends WishlistRepositoryInterface
{
/**
* @return list<UserWishlistInterface>
Expand Down
23 changes: 23 additions & 0 deletions src/Repository/WishlistRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusWishlistPlugin\Repository;

use Setono\SyliusWishlistPlugin\Model\WishlistInterface;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
use Webmozart\Assert\Assert;

/**
* @implements WishlistRepositoryInterface<WishlistInterface>
*/
class WishlistRepository extends EntityRepository implements WishlistRepositoryInterface
{
public function findOneByUuid(string $uuid): ?WishlistInterface
{
$obj = $this->findOneBy(['uuid' => $uuid]);
Assert::nullOrIsInstanceOf($obj, WishlistInterface::class);

return $obj;
}
}
20 changes: 20 additions & 0 deletions src/Repository/WishlistRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusWishlistPlugin\Repository;

use Setono\SyliusWishlistPlugin\Model\WishlistInterface;
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;

/**
* @template T of WishlistInterface
* @extends RepositoryInterface<T>
*/
interface WishlistRepositoryInterface extends RepositoryInterface
{
/**
* @return T|null
*/
public function findOneByUuid(string $uuid): ?WishlistInterface;
}
1 change: 1 addition & 0 deletions src/Resources/config/doctrine/model/Wishlist.orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<discriminator-mapping value="user" class="Setono\SyliusWishlistPlugin\Model\UserWishlistInterface"/>
</discriminator-map>

<field name="uuid" type="string"/>
<field name="name" type="string"/>

<one-to-many field="items" target-entity="Setono\SyliusWishlistPlugin\Model\WishlistItemInterface" mapped-by="wishlist" orphan-removal="true">
Expand Down
11 changes: 8 additions & 3 deletions src/Resources/config/doctrine/model/WishlistItem.orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Setono\SyliusWishlistPlugin\Model\WishlistItem"
table="setono_sylius_wishlist__wishlist_item">
table="setono_sylius_wishlist__wishlist_item">
<id name="id" type="integer">
<generator strategy="AUTO"/>
</id>

<field name="quantity" type="integer"/>

<many-to-one field="wishlist" target-entity="Setono\SyliusWishlistPlugin\Model\WishlistInterface" inversed-by="items">
<join-column name="wishlist_id" referenced-column-name="id" nullable="false" on-delete="CASCADE" />
<many-to-one field="wishlist" target-entity="Setono\SyliusWishlistPlugin\Model\WishlistInterface"
inversed-by="items">
<join-column name="wishlist_id" referenced-column-name="id" nullable="false" on-delete="CASCADE"/>
</many-to-one>

<many-to-one field="product" target-entity="Sylius\Component\Product\Model\ProductInterface">
<join-column name="product_id" referenced-column-name="id" nullable="false" on-delete="CASCADE"/>
</many-to-one>
</entity>
</doctrine-mapping>
Loading

0 comments on commit 91d486c

Please sign in to comment.