DEV Community

loading...
Cover image for Managing the Cart Storage | Building a Shopping Cart with Symfony

Managing the Cart Storage | Building a Shopping Cart with Symfony

Quentin Ferrer
I’m a french web developer. I develop in PHP with the popular Symfony framework.
・3 min read

Each user will have their own cart. As soon as a product is added to the cart, an Order is created in a database and then associated with the user via an Order ID in the session.

We will not manage user accounts, so the cart will be always associated with an anonymous user - a user who does not have a user account.

Creating the Session Storage

The cart has to be stored in the session to keep the items in the user's cart during their visit. Once the session has expired, the cart will be cleared. A new cart will be created and stored when the user adds a product to the cart.

Create a CartSessionStorage service to manage the cart in the session and add the following operations:

  • Add a setCart() method to save the cart in the cart_id session key by using the cart ID,
  • Add a getCart() method to retrieve the cart in the session. Get the cart ID from the cart_id session key, fetch the cart object by using the OrderRepository repository, and return it.
<?php

namespace App\Storage;

use App\Entity\Order;
use App\Repository\OrderRepository;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

/**
 * Class CartSessionStorage
 * @package App\Storage
 */
class CartSessionStorage
{
    /**
     * The session storage.
     *
     * @var SessionInterface
     */
    private $session;

    /**
     * The cart repository.
     *
     * @var OrderRepository
     */
    private $cartRepository;

    /**
     * @var string
     */
    const CART_KEY_NAME = 'cart_id';

    /**
     * CartSessionStorage constructor.
     *
     * @param SessionInterface $session
     * @param OrderRepository $cartRepository
     */
    public function __construct(SessionInterface $session, OrderRepository $cartRepository) 
    {
        $this->session = $session;
        $this->cartRepository = $cartRepository;
    }

    /**
     * Gets the cart in session.
     *
     * @return Order|null
     */
    public function getCart(): ?Order
    {
        return $this->cartRepository->findOneBy([
            'id' => $this->getCartId(),
            'status' => Order::STATUS_CART
        ]);
    }

    /**
     * Sets the cart in session.
     *
     * @param Order $cart
     */
    public function setCart(Order $cart): void
    {
        $this->session->set(self::CART_KEY_NAME, $cart->getId());
    }

    /**
     * Returns the cart id.
     *
     * @return int|null
     */
    private function getCartId(): ?int
    {
        return $this->session->get(self::CART_KEY_NAME);
    }
}
Enter fullscreen mode Exit fullscreen mode

Creating the Cart Manager

Create the CartManager class that helps us retrieve the current cart of a user and saving the cart.

<?php

namespace App\Manager;

/**
 * Class CartManager
 * @package App\Manager
 */
class CartManager
{
}
Enter fullscreen mode Exit fullscreen mode

Retrieving the current cart

For each action performed on the cart, we will need to retrieve the current cart:

  • If the cart is already associated with the user in the session, it's the current cart,
  • If the cart does not exist in the session, a new cart is created and becomes the current cart. It will be associated with the user in the session after being persisted in the database.

Add a getCurrentCart() method to the CartManager and retrieve the current cart. Get the cart already associated with the user using the CartSessionStorage. If the cart does not exist, create a new cart by using the OrderFactory factory. Finally, return the cart.

<?php

namespace App\Manager;

use App\Entity\Order;
use App\Factory\OrderFactory;
use App\Storage\CartSessionStorage;

/**
 * Class CartManager
 * @package App\Manager
 */
class CartManager
{
    /**
     * @var CartSessionStorage
     */
    private $cartSessionStorage;

    /**
     * @var OrderFactory
     */
    private $cartFactory;

    /**
     * CartManager constructor.
     *
     * @param CartSessionStorage $cartStorage
     * @param OrderFactory $orderFactory
     */
    public function __construct(
        CartSessionStorage $cartStorage,
        OrderFactory $orderFactory
    ) {
        $this->cartSessionStorage = $cartStorage;
        $this->cartFactory = $orderFactory;
    }

    /**
     * Gets the current cart.
     * 
     * @return Order
     */
    public function getCurrentCart(): Order
    {
        $cart = $this->cartSessionStorage->getCart();

        if (!$cart) {
            $cart = $this->cartFactory->create();
        }

        return $cart;
    }
}

Enter fullscreen mode Exit fullscreen mode

Saving the Cart

Rather than storing the whole object in the session, we will persist the cart in the database to associate it with the user by using the Order ID.

Add a save() method to the CartManager, persist the cart in the database by using the EntityManager service, and store the cart in session by using the CartSessionStorage service.

<?php

namespace App\Manager;

use App\Entity\Order;
use App\Factory\OrderFactory;
use App\Storage\CartSessionStorage;
use Doctrine\ORM\EntityManagerInterface;

/**
 * Class CartManager
 * @package App\Manager
 */
class CartManager
{
    /**
     * @var CartSessionStorage
     */
    private $cartSessionStorage;

    /**
     * @var OrderFactory
     */
    private $cartFactory;

    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    /**
     * CartManager constructor.
     *
     * @param CartSessionStorage $cartStorage
     * @param OrderFactory $orderFactory
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(
        CartSessionStorage $cartStorage,
        OrderFactory $orderFactory,
        EntityManagerInterface $entityManager
    ) {
        $this->cartSessionStorage = $cartStorage;
        $this->cartFactory = $orderFactory;
        $this->entityManager = $entityManager;
    }

    // ...

    /**
     * Persists the cart in database and session.
     *
     * @param Order $cart
     */
    public function save(Order $cart): void
    {
        // Persist in database
        $this->entityManager->persist($cart);
        $this->entityManager->flush();
        // Persist in session
        $this->cartSessionStorage->setCart($cart);
    }
}
Enter fullscreen mode Exit fullscreen mode

With this approach, you will be able to associate a cart with a database user if you want to have a cart for logged in users. It is also a good way to let the user manage their cart on different devices and create an abandoned cart workflow.

Now that we can save carts and retrieve the current cart of the visitor, we are ready to add products to the cart.

Discussion (0)