<?php
declare(strict_types=1);
namespace VioB2BLogin\Core\Framework\Subscriber;
use Shopware\Core\Framework\Routing\KernelListenerPriorities;
use Shopware\Core\PlatformRequest;
use Shopware\Core\SalesChannelRequest;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use VioB2BLogin\Core\Exception\NotAllowedException;
use VioB2BLogin\Core\Services\PrivilegeService;
use VioB2BLogin\Entity\Privilege\AbstractPrivilegeProvider;
use VioB2BLogin\Entity\Privilege\RoutePrivilegeMappingProviderInterface;
class RoutePrivilegeCheckSubscriber implements EventSubscriberInterface
{
/** @var iterable<AbstractPrivilegeProvider> */
private iterable $privilegeProviders;
private PrivilegeService $privilegeService;
private RouterInterface $router;
private TranslatorInterface $translator;
public function __construct(
iterable $priviligeProviders,
PrivilegeService $privilegeService,
RouterInterface $router,
TranslatorInterface $translator
)
{
$this->privilegeProviders = $priviligeProviders;
$this->privilegeService = $privilegeService;
$this->router = $router;
$this->translator = $translator;
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER => [ 'onKernelController' , KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_CONTEXT_RESOLVE_POST],
KernelEvents::EXCEPTION => 'onKernelException'
];
}
public function onKernelController(ControllerEvent $event): void
{
$context = $event->getRequest()->attributes->get( PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT );
if( !$context instanceof SalesChannelContext ) {
return;
}
foreach ($this->privilegeProviders as $privilegeProvider) {
if ($privilegeProvider instanceof RoutePrivilegeMappingProviderInterface) {
$mapping = $privilegeProvider->getRoutePrivilegeMapping();
$route = $event->getRequest()->attributes->get('_route');
if (array_key_exists($route, $mapping) ) {
$privileges = $mapping[$route];
foreach ($privileges as $privilegeNamespace => $privilegeNames) {
foreach ($privilegeNames as $privilegeName) {
if( ! $this->privilegeService->checkPrivilege($context, $privilegeNamespace, $privilegeName) )
{
throw new NotAllowedException();
}
}
}
}
}
}
}
public function onKernelException(ExceptionEvent $event): void
{
if (!$event->getRequest()->attributes->has(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
return;
}
$exception = $event->getThrowable();
if (!$exception instanceof NotAllowedException ) {
return;
}
$this->addFlashMessage($exception, $event->getRequest());
$request = $event->getRequest();
$parameters = [
'redirectTo' => $request->attributes->get('_route'),
'redirectParameters' => json_encode($request->attributes->get('_route_params')),
];
$redirectResponse = new RedirectResponse($this->router->generate('frontend.account.profile.page', $parameters));
$event->setResponse($redirectResponse);
}
private function addFlashMessage(NotAllowedException $exception, Request $request): void
{
if ($request->hasSession() === false) {
return;
}
$session = $request->getSession();
if (!method_exists($session, 'getFlashBag')) {
return;
}
$session->getFlashBag()->add('danger', $this->translator->trans('error.'.$exception->getErrorCode()) );
}
}