<?php declare(strict_types=1);
namespace Ngs\ShopRestrict\Subscriber;
use Ngs\ShopRestrict\Core\Struct\AllowedRouteStruct;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\GenericPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
class GenericPageSubscriber implements EventSubscriberInterface
{
const PREFIX_STOREFRONT = 'frontend';
const NOT_FOUND_MESSAGE = 'This page is not allowed';
const ROUTE_QUICKVIEW_MINIMAL = 'widgets.quickview.minimal';
const ROUTE_CMS_PAGE = 'frontend.cms.page';
private $routeList = [
'account' => [
'frontend.account.order.page',
'frontend.account.order.cancel',
'frontend.account.order.single.page',
'frontend.account.edit-order.page',
'frontend.account.edit-order.change-payment-method',
'frontend.account.edit-order.update-order',
'frontend.account.payment.page',
'frontend.account.payment.save',
'frontend.account.home.page',
'frontend.account.profile.page',
'frontend.account.profile.save',
'frontend.account.profile.email.save',
'frontend.account.profile.password.save',
'frontend.account.profile.delete',
'frontend.account.address.page',
'frontend.account.address.create.page',
'frontend.account.address.edit.page',
'frontend.account.address.set-default-address',
'frontend.account.address.delete',
'frontend.account.address.create',
'frontend.account.address.edit.save',
'frontend.account.addressbook',
'frontend.account.login.page',
'frontend.account.guest.login.page',
'frontend.account.logout.page',
'frontend.account.login',
'frontend.account.recover.page',
'frontend.account.recover.request',
'frontend.account.recover.password.page',
'frontend.account.recover.password.reset',
'frontend.account.order.single.document',
'frontend.account.order.single.download',
'frontend.account.newsletter',
'frontend.account.register.page',
'frontend.account.customer-group-registration.page',
'frontend.account.register.save',
'frontend.account.register.mail',
'frontend.well-known.change-password',
'frontend.newsletter.subscribe',
'frontend.form.newsletter.register.handle',
'frontend.checkout.register.page',
],
'checkout' => [
'frontend.checkout.line-item.delete',
'frontend.checkout.line-items.delete',
'frontend.checkout.promotion.add',
'frontend.checkout.line-item.change-quantity',
'frontend.checkout.line-items.update',
'frontend.checkout.product.add-by-number',
'frontend.checkout.line-item.add',
'frontend.checkout.cart.page',
'frontend.checkout.cart.json',
'frontend.checkout.confirm.page',
'frontend.checkout.finish.page',
'frontend.checkout.finish.order',
'frontend.checkout.info',
'frontend.checkout.configure',
'frontend.checkout.switch-language',
'frontend.checkout.register.page',
'frontend.cart.offcanvas',
//payment routes
'frontend.account.payment.page',
'frontend.account.payment.save',
//address routes
'frontend.account.address.page',
'frontend.account.address.create.page',
'frontend.account.address.edit.page',
'frontend.account.address.set-default-address',
'frontend.account.address.delete',
'frontend.account.address.create',
'frontend.account.address.edit.save',
//account order
'frontend.account.order.page',
'frontend.account.order.cancel',
'frontend.account.order.single.page',
'frontend.account.edit-order.page',
'frontend.account.edit-order.change-payment-method',
'frontend.account.edit-order.update-order',
//account payment
'frontend.account.payment.page',
'frontend.account.payment.save',
],
'wishlist' => [
'frontend.wishlist.page',
'frontend.wishlist.guestPage.pagelet',
'frontend.wishlist.product.list',
'frontend.wishlist.product.delete',
'frontend.wishlist.product.add',
'frontend.wishlist.product.remove',
'frontend.wishlist.add.after.login',
'frontend.wishlist.product.merge',
'frontend.wishlist.product.merge.pagelet',
],
'cms' => [
'frontend.cms.page',
'frontend.cms.buybox.switch',
],
'legal_pages' => [
'frontend.cms.page',
],
'sorting_and_filter' => [
'frontend.cms.navigation.page',
'frontend.cms.navigation.filter',
],
'search' => [
'frontend.search.page',
'frontend.search.suggest',
],
'review' => [
'frontend.detail.review.save',
'frontend.product.reviews',
],
'support' => [
'frontend.form.contact.send',
],
'newsletter' => [
'frontend.newsletter.subscribe',
'frontend.form.newsletter.register.handle',
'frontend.account.newsletter',
],
//TODO other routes
// 'other' => [
// 'frontend.captcha.basic-captcha.load',
// 'frontend.captcha.basic-captcha.validate',
// 'frontend.country.country.data',
// 'frontend.landing.page',
// 'frontend.maintenance.page',
// 'frontend.maintenance.singlepage',
// 'frontend.navigation.page',
// 'frontend.menu.offcanvas',
// 'frontend.script_endpoint',
// ],
'cookie' => [
'frontend.cookie.offcanvas',
'frontend.cookie.permission',
],
'product_detail' => [
'frontend.detail.page',
'frontend.detail.switch',
'widgets.quickview.minimal'
],
'description' => [],
'frontend.home.page',
'frontend.sitemap.xml',
];
private SystemConfigService $systemConfigService;
private $entityRepository;
/**
* @param SystemConfigService $systemConfigService
*/
public function __construct(SystemConfigService $systemConfigService, EntityRepository $entityRepository)
{
$this->systemConfigService = $systemConfigService;
$this->entityRepository = $entityRepository;
}
/**
* @return string[]
*/
public static function getSubscribedEvents(): array
{
// Return the events to listen to as array like this: <event to listen to> => <method to execute>
return [
GenericPageLoadedEvent::class => 'allowedRoutes',
KernelEvents::REQUEST => 'requestEvent',
];
}
/**
* @param GenericPageLoadedEvent $event
* @return void
*/
public function allowedRoutes(GenericPageLoadedEvent $event)
{
$notAllowedArray = $this->getNotAllowedRoutes();
$struct = new AllowedRouteStruct();
$struct->setRoutes($notAllowedArray);
$entityData = $this->getNotAllowedPages();
$notAllowedPages = array_filter($entityData, function ($item) {
return $item === false;
});
$struct->setPages($notAllowedPages);
$event->getPage()->addExtension('notAllowedRoutes', $struct);
$event->getPage()->addExtension('notAllowedPages', $struct);
}
/**
* @param RequestEvent $event
* @return void
*/
public function requestEvent(RequestEvent $event)
{
$route = $event->getRequest()->attributes->get('_route');
if (!$this->isStoreFront($route)) {
return;
}
$notAllowedArray = $this->getNotAllowedRoutes();
if (!in_array($route, $notAllowedArray)) {
return;
}
if ($route == self::ROUTE_CMS_PAGE) {
$routeParamId = $event->getRequest()->attributes->get('_route_params')['id'];
if (!($routeParamId == $this->systemConfigService->get('core.basicInformation.privacyPage')
|| $routeParamId == $this->systemConfigService->get('core.basicInformation.tosPage')
|| $routeParamId == $this->systemConfigService->get('core.basicInformation.imprintPage')
|| $routeParamId == $this->systemConfigService->get('core.basicInformation.shippingPaymentInfoPage')
|| $routeParamId == $this->systemConfigService->get('core.basicInformation.revocationPage'))
) {
return;
}
}
throw new NotFoundHttpException(self::NOT_FOUND_MESSAGE);
}
/**
* @param $route
* @return bool
*/
public function isStoreFront($route)
{
if ($route) {
if (explode('.', $route)[0] == self::PREFIX_STOREFRONT || $route === self::ROUTE_QUICKVIEW_MINIMAL) {
return true;
}
}
return false;
}
/**
* @return array
*/
public function getNotAllowedRoutes()
{
// $configs = $this->systemConfigService->all()['NgsShopRestrict']['config']; TODO data from config
$notAllowedArray = [];
$configs = $this->getEntityData();
$struct = new AllowedRouteStruct();
$struct->setPages($configs);
array_filter($configs, function ($item, $key) use (&$notAllowedArray) {
if ($item === false) {
$notAllowedArray = array_merge($notAllowedArray, $this->routeList[$key]);
}
}, ARRAY_FILTER_USE_BOTH);
return $notAllowedArray;
}
/**
* @return array
*/
public function getNotAllowedPages()
{
return $this->getEntityData();
}
/**
* @return array
*/
public function getEntityData()
{
$restrictedPages = $this->entityRepository->search((new Criteria()), Context::createDefaultContext())->getEntities();
$configs = [];
foreach ($restrictedPages->getElements() as $element) {
$configs[$element->title] = $element->is_allowed;
}
return $configs;
}
}