Shopware 6: Easy errors/validation on checkout and flash message

One of our customers needs sometimes a file uploaded on the checkout. In our other checkout posts, we explained, how to change the checkout and why it is so easy in Shopware <3

I don’t want to dive into details of the upload, if you want to read about it, leave a comment or drop us an email! I want to write about errors and validation, after diving with my colleague Bruno into it.

Create order

To create an order on Shopware, we have the CheckoutController::order, the important part of the method looks like this:

//    \Shopware\Storefront\Controller\CheckoutController::order
    #[Route(path: '/checkout/order', name: 'frontend.checkout.finish.order', options: ['seo' => false], methods: ['POST'])]
    public function order(RequestDataBag $data, SalesChannelContext $context, Request $request): Response
    {
        if (!$context->getCustomer()) {
            return $this->redirectToRoute('frontend.checkout.register.page');
        }

        try {
            $this->addAffiliateTracking($data, $request->getSession());

            $orderId = Profiler::trace('checkout-order', fn () => $this->orderService->createOrder($data, $context));
        } catch (ConstraintViolationException $formViolations) {
            return $this->forwardToRoute('frontend.checkout.confirm.page', ['formViolations' => $formViolations]);
        } catch (InvalidCartException|Error|EmptyCartException) {
            $this->addCartErrors(
                $this->cartService->getCart($context->getToken(), $context)
            );

            return $this->forwardToRoute('frontend.checkout.confirm.page');
        } catch (UnknownPaymentMethodException|CartException $e) {
            if ($e->getErrorCode() === CartException::CART_PAYMENT_INVALID_ORDER_STORED_CODE && $e->getParameter('orderId')) {
                return $this->forwardToRoute('frontend.checkout.finish.page', ['orderId' => $e->getParameter('orderId'), 'changedPayment' => false, 'paymentFailed' => true]);
            }
            $message = $this->trans('error.' . $e->getErrorCode());
            $this->addFlash('danger', $message);

            return $this->forwardToRoute('frontend.checkout.confirm.page');
        }

        try {
            $finishUrl = $this->generateUrl('frontend.checkout.finish.page', ['orderId' => $orderId]);
            $errorUrl = $this->generateUrl('frontend.account.edit-order.page', ['orderId' => $orderId]);

            $response = Profiler::trace('handle-payment', fn (): ?RedirectResponse => $this->paymentService->handlePaymentByOrder($orderId, $data, $context, $finishUrl, $errorUrl));

            return $response ?? new RedirectResponse($finishUrl);
        } catch (PaymentProcessException|InvalidOrderException|PaymentException|UnknownPaymentMethodException) {
            return $this->forwardToRoute('frontend.checkout.finish.page', ['orderId' => $orderId, 'changedPayment' => false, 'paymentFailed' => true]);
        }
    }

As you can see you have three catch blocks. The third is the important and interesting for us. But to use it, we need to make sure to NOT throw a

- ConstraintViolationException
- InvalidCartException
- EmptyCartException
- \Error

But throw a CartException!

} catch (UnknownPaymentMethodException|CartException $e) {
    if ($e->getErrorCode() === CartException::CART_PAYMENT_INVALID_ORDER_STORED_CODE && $e->getParameter('orderId')) {
        return $this->forwardToRoute('frontend.checkout.finish.page', ['orderId' => $e->getParameter('orderId'), 'changedPayment' => false, 'paymentFailed' => true]);
    }
    $message = $this->trans('error.' . $e->getErrorCode());
    $this->addFlash('danger', $message);

    return $this->forwardToRoute('frontend.checkout.confirm.page');
}

The easiest way to achieve the above conditions is to implement your own CartException.

<?php

namespace Agency\Project\Exception;

class SomethingWentWrongOnCartValidationException extends \Shopware\Core\Checkout\Cart\CartException
{
    public function __construct()
    {
        parent::__construct(0, 'SOMETHING_WENT_WRONG', 'Something went wrong.');
    }

}

This way you can easily throw new SomethingWentWrongOnCartValidationException() anywhere during order creation in our case during CartConvertedEvent.

Lost in Translation

As you can see above, then your exception is catch, the error code (in our example SOMETHING_WENT_WRONG) is run through translation as error.SOMETHING_WENT_WRONG, then added as flash message and the visitor is redirected back to the last step of the checkout.

One thought on “Shopware 6: Easy errors/validation on checkout and flash message

Leave a Reply

Discover more from Winkelwagen

Subscribe now to keep reading and get access to the full archive.

Continue reading