I can't wrap my head on how the order
data is saved from the storefront controller frontend.checkout.finish.order
@ Shopware\vendor\shopware\storefront\Controller\CheckoutController.php
Below is the code
/**
* @Since("6.0.0.0")
* @Route("/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', function () use ($data, $context) {
return $this->orderService->createOrder($data, $context);
});
} catch (ConstraintViolationException $formViolations) {
return $this->forwardToRoute('frontend.checkout.confirm.page', ['formViolations' => $formViolations]);
} catch (InvalidCartException | Error | EmptyCartException $error) {
$this->addCartErrors(
$this->cartService->getCart($context->getToken(), $context)
);
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', function () use ($orderId, $data, $context, $finishUrl, $errorUrl): ?RedirectResponse {
return $this->paymentService->handlePaymentByOrder($orderId, $data, $context, $finishUrl, $errorUrl);
});
return $response ?? new RedirectResponse($finishUrl);
} catch (PaymentProcessException | InvalidOrderException | UnknownPaymentMethodException $e) {
return $this->forwardToRoute('frontend.checkout.finish.page', ['orderId' => $orderId, 'changedPayment' => false, 'paymentFailed' => true]);
}
}
Help me explain how it works. I have traced some functions used in the API but can't find where the data is saved.
I also found Shopware\vendor\shopware\core\Checkout\Cart\Order\OrderPersister.php
with the code below. But I can't place the connection with the frontend.checkout.finish.order
API
<?php declare(strict_types=1);
namespace Shopware\Core\Checkout\Cart\Order;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartException;
use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
use Shopware\Core\Checkout\Cart\Exception\InvalidCartException;
use Shopware\Core\Checkout\Order\Exception\DeliveryWithoutAddressException;
use Shopware\Core\Checkout\Order\Exception\EmptyCartException;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
use Shopware\Core\Framework\Log\Package;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
#[Package('checkout')]
class OrderPersister implements OrderPersisterInterface
{
private EntityRepositoryInterface $orderRepository;
private OrderConverter $converter;
/**
* @internal
*/
public function __construct(
EntityRepositoryInterface $repository,
OrderConverter $converter
) {
$this->orderRepository = $repository;
$this->converter = $converter;
}
/**
* @throws CustomerNotLoggedInException
* @throws DeliveryWithoutAddressException
* @throws EmptyCartException
* @throws InvalidCartException
* @throws InconsistentCriteriaIdsException
*/
public function persist(Cart $cart, SalesChannelContext $context): string
{
if ($cart->getErrors()->blockOrder()) {
throw CartException::invalidCart($cart->getErrors());
}
if (!$context->getCustomer()) {
throw CartException::customerNotLoggedIn();
}
if ($cart->getLineItems()->count() <= 0) {
throw new EmptyCartException();
}
$order = $this->converter->convertToOrder($cart, $context, new OrderConversionContext());
$context->getContext()->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($order): void {
$this->orderRepository->create([$order], $context);
});
return $order['id'];
}
}
Here is a basic trace of the method calls that happen:
The current cart is converted to an array for the order data and saved via the order repository, take a look at my comments in the persist method:
public function persist(Cart $cart, SalesChannelContext $context): string
{
if ($cart->getErrors()->blockOrder()) {
throw CartException::invalidCart($cart->getErrors());
}
if (!$context->getCustomer()) {
throw CartException::customerNotLoggedIn();
}
if ($cart->getLineItems()->count() <= 0) {
throw new EmptyCartException();
}
// Cart is converted to an array
$order = $this->converter->convertToOrder($cart, $context, new OrderConversionContext());
$context->getContext()->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($order): void {
// The array is saved to the database
$this->orderRepository->create([$order], $context);
});
return $order['id'];
}