<?php /** @noinspection PhpMultipleClassDeclarationsInspection */
declare(strict_types=1);
namespace VioRepresentativeLogin\Storefront\Subscriber;
use JsonException;
use Shopware\Core\Framework\Routing\Annotation\LoginRequired;
use Shopware\Core\Framework\Routing\KernelListenerPriorities;
use Shopware\Core\Framework\Util\Random;
use Shopware\Core\PlatformRequest;
use Shopware\Core\SalesChannelRequest;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Controller\AccountProfileController;
use Shopware\Storefront\Framework\Routing\StorefrontSubscriber as CoreStorefrontSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RouterInterface;
use VioRepresentativeLogin\Core\Checkout\Customer\Event\AgentCustomerLogoutEvent;
use VioRepresentativeLogin\Core\Checkout\Customer\Event\AgentLoginEvent;
use VioRepresentativeLogin\Core\Checkout\Customer\Event\AgentLogoutEvent;
use VioRepresentativeLogin\Core\Exception\AgentNotLoggedInException;
use VioRepresentativeLogin\Core\Framework\Routing\Annotation\RepresentativeLoginRequired;
use VioRepresentativeLogin\Core\System\SalesChannel\Context\SalesChannelContextFactory;
use VioRepresentativeLogin\Entity\Agent\AgentEntity;
class StorefrontSubscriber implements EventSubscriberInterface
{
private RouterInterface $router;
private CoreStorefrontSubscriber $storefrontSubscriber;
private SystemConfigService $systemConfigService;
public function __construct(
RouterInterface $router,
CoreStorefrontSubscriber $storefrontSubscriber,
SystemConfigService $systemConfigService
)
{
$this->router = $router;
$this->storefrontSubscriber = $storefrontSubscriber;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::EXCEPTION => 'agentNotLoggedInHandler',
AgentLoginEvent::class => 'updateSessionAfterLogin',
AgentLogoutEvent::class => 'updateSessionAfterLogout',
AgentCustomerLogoutEvent::class => 'updateSessionAfterCustomerLogout',
KernelEvents::CONTROLLER => [
['onKernelControllerPreContextResolve', KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_CONTEXT_RESOLVE_PRE],
['onKernelControllerPostContextResolve', KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_CONTEXT_RESOLVE_POST]
],
];
}
public function onKernelControllerPostContextResolve(ControllerEvent $event): void
{
$request = $event->getRequest();
if ($request->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT)
&& strpos($request->attributes->get('_route'), 'frontend.account') === 0) {
/** @var AccountProfileController $controller */
$controller = $event->getController();
/** @var SalesChannelContext $salesChannelContext */
$salesChannelContext = $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);
if ($controller
&& $salesChannelContext->getCustomer() === null
&& $salesChannelContext->getExtensionOfType(SalesChannelContextFactory::AGENT_KEY, AgentEntity::class) !== null) {
// redirect to different Route
$event->setController(function () use ($salesChannelContext) {
return new RedirectResponse($this->router->generate($this->getRedirectRoute($salesChannelContext)));
});
}
}
}
public function onKernelControllerPreContextResolve(ControllerEvent $event): void
{
$request = $event->getRequest();
if ($request->attributes->has(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED)) {
// decorate class
/** @var LoginRequired $loginRequiredAnnotation */
$loginRequiredAnnotation = $request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED);
if( $loginRequiredAnnotation instanceof LoginRequired ) {
$loginRequiredAnnotationAllowGuests = $loginRequiredAnnotation->isAllowGuest();
}
else {
$loginRequiredAnnotationAllowGuests = $request->attributes->get(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED_ALLOW_GUEST);
}
$RepresentativeLoginRequired = new RepresentativeLoginRequired(['allowGuest' => $loginRequiredAnnotationAllowGuests]);
$request->attributes->set(PlatformRequest::ATTRIBUTE_LOGIN_REQUIRED, $RepresentativeLoginRequired);
}
}
public function updateSessionAfterCustomerLogout(AgentCustomerLogoutEvent $event): void
{
$token = $event->getSalesChannelContext()->getToken();
$this->storefrontSubscriber->updateSession($token);
}
public function updateSessionAfterLogin(AgentLoginEvent $event): void
{
$token = $event->getContextToken();
$this->storefrontSubscriber->updateSession($token);
}
public function updateSessionAfterLogout(): void
{
$newToken = Random::getAlphanumericString(32);
$this->storefrontSubscriber->updateSession($newToken, true);
}
/**
* @throws JsonException
*/
public function agentNotLoggedInHandler(ExceptionEvent $event): void
{
if (!$event->getRequest()->attributes->has(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
return;
}
if (!$event->getThrowable() instanceof AgentNotLoggedInException) {
return;
}
$request = $event->getRequest();
/** @noinspection PhpComposerExtensionStubsInspection */
$parameters = [
'redirectTo' => $request->attributes->get('_route'),
'redirectParameters' => json_encode($request->attributes->get('_route_params'), JSON_THROW_ON_ERROR),
];
$redirectResponse = new RedirectResponse($this->router->generate('frontend.account.login.page', $parameters));
$event->setResponse($redirectResponse);
}
private function getRedirectRoute(SalesChannelContext $salesChannelContext): string
{
$redirectToCustomerList = (bool)$this->systemConfigService->get('VioRepresentativeLogin.config.redirectToCustomerList', $salesChannelContext->getSalesChannel()->getId());
if ($redirectToCustomerList) {
return 'frontend.representative.customer.list.page';
}
return 'frontend.representative.agent.home.page';
}
}