src/EventSubscriber/Shop/BeforeOrderCreateSubscriber.php line 58
<?php
declare(strict_types=1);
namespace App\EventSubscriber\Shop;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\Ledger\Account;
use App\Entity\Shop\Order;
use App\Exceptions\Shop\BuyerAlreadyHasAnyItemsException;
use App\Services\Shop\OrderItemValidator;
use App\Services\Transaction\CreateService;
use App\Services\Transaction\Types\TypeCreatorInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Workflow\WorkflowInterface;
class BeforeOrderCreateSubscriber implements EventSubscriberInterface
{
protected const COMMENT = 'Checkout order #%s';
public function __construct(
private readonly TypeCreatorInterface $payTypeCreator,
private readonly OrderItemValidator $orderItemValidator,
private readonly WorkflowInterface $orderStateMachine,
private readonly CreateService $transactionService,
private readonly Account $bankAccount,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => [
['validate', EventPriorities::PRE_WRITE + 1],
['checkout', EventPriorities::PRE_WRITE],
],
];
}
/**
* @throws BuyerAlreadyHasAnyItemsException
*/
public function validate(ViewEvent $event): void
{
if (!$this->support($event)) {
return;
}
$this->orderItemValidator->validate($this->getOrder($event));
}
/**
* @throws \Throwable
*/
public function checkout(ViewEvent $event): void
{
if (!$this->support($event)) {
return;
}
$order = $this->getOrder($event);
$payType = $this->payTypeCreator->createType(
$order->getBuyer()->getMainAccount(),
$this->bankAccount,
$order->getTotal(),
sprintf(self::COMMENT, $order->getId()),
);
try {
$this->transactionService->perform($payType);
$this->orderStateMachine->apply($order, 'pay');
} catch (\Throwable $e) {
$this->orderStateMachine->apply($order, 'reject');
throw $e;
}
}
private function support(ViewEvent $event): bool
{
$method = $event->getRequest()->getMethod();
$order = $event->getControllerResult();
return $order instanceof Order && Request::METHOD_POST === $method;
}
private function getOrder(ViewEvent $event): Order
{
return $event->getControllerResult();
}
}