custom/plugins/CioCustomerPermissionGroups/src/Subscriber/CategoriesPermissionsSubscriber.php line 105

Open in your IDE?
  1. <?php
  2. namespace CioCustomerPermissionGroups\Subscriber;
  3. use CioCustomerPermissionGroups\Service\CustomerPermissionService;
  4. use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
  5. use Shopware\Core\Checkout\Customer\CustomerEntity;
  6. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLoginRoute;
  7. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
  8. use Shopware\Core\Checkout\Customer\SalesChannel\LogoutRoute;
  9. use Shopware\Core\Content\Category\CategoryEntity;
  10. use Shopware\Core\Content\Category\Event\CategoryRouteCacheKeyEvent;
  11. use Shopware\Core\Content\Category\Event\NavigationLoadedEvent;
  12. use Shopware\Core\Content\Category\Exception\CategoryNotFoundException;
  13. use Shopware\Core\Content\Category\Tree\TreeItem;
  14. use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
  15. use Shopware\Core\Content\Product\Events\ProductListingRouteCacheKeyEvent;
  16. use Shopware\Core\Content\Product\Events\ProductSuggestCriteriaEvent;
  17. use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
  18. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  19. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  22. use Shopware\Core\Framework\Validation\DataBag\DataBag;
  23. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  24. use Shopware\Storefront\Event\StorefrontRenderEvent;
  25. use Shopware\Storefront\Page\Navigation\NavigationPageLoadedEvent;
  26. use Shopware\Storefront\Page\Product\ProductPage;
  27. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  28. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  29. class CategoriesPermissionsSubscriber implements EventSubscriberInterface
  30. {
  31.     private EntityRepository $categoryRepository;
  32.     private EventDispatcherInterface $eventDispatcher;
  33.     private CustomerPermissionService $customerPermissionService;
  34.     private AbstractLogoutRoute $logoutRoute;
  35.     public function __construct(EntityRepository $categoryRepositoryEventDispatcherInterface $eventDispatcherCustomerPermissionService $customerPermissionServiceAbstractLogoutRoute $logoutRoute)
  36.     {
  37.         $this->categoryRepository $categoryRepository;
  38.         $this->eventDispatcher $eventDispatcher;
  39.         $this->customerPermissionService $customerPermissionService;
  40.         $this->logoutRoute $logoutRoute;
  41.     }
  42.     public static function getSubscribedEvents(): array
  43.     {
  44.         // Return the events to listen to as array like this:  <event to listen to> => <method to execute>
  45.         return [
  46.             NavigationLoadedEvent::class => 'onNavigationLoadedEvent',
  47.             NavigationPageLoadedEvent::class => 'onNavigationPageLoadedEvent',
  48.             StorefrontRenderEvent::class => 'onSalesChannelProductLoaded',
  49.             CategoryRouteCacheKeyEvent::class => 'onCategoryRouteCacheKey',
  50.             ProductListingRouteCacheKeyEvent::class => 'onProductListingRouteCacheKey',
  51.             ProductSuggestCriteriaEvent::class => 'onProductSuggestCriteriaEvent'
  52.         ];
  53.     }
  54.     public function onProductListingRouteCacheKey(ProductListingRouteCacheKeyEvent $event)
  55.     {
  56.         $event->addPart(session_id());
  57.     }
  58.     public function onCategoryRouteCacheKey(CategoryRouteCacheKeyEvent $categoryRouteCacheKeyEvent)
  59.     {
  60.         $categoryRouteCacheKeyEvent->addPart(session_id());
  61.     }
  62.     public function onNavigationLoadedEvent(NavigationLoadedEvent $event)
  63.     {
  64.         $event->getNavigation()->setTree(array_filter($event->getNavigation()->getTree(), function (TreeItem $treeItem) use ($event) {
  65.             $category $treeItem->getCategory();
  66.             if ($this->categoryAccessAllowedByEntities($category$event->getSalesChannelContext()->getCustomer())) {
  67.                 $this->filterTreeChilds($treeItem$event->getSalesChannelContext()->getCustomer());
  68.                 return true;
  69.             }
  70.             return false;
  71.         }));
  72.     }
  73.     public function onNavigationPageLoadedEvent(NavigationPageLoadedEvent $event)
  74.     {
  75.         $customer $event->getSalesChannelContext()->getCustomer();
  76.         if ($customer === null) {
  77.             throw new CustomerNotLoggedInException();
  78.         }
  79.         if (!$this->categoryAccessAllowed($event->getSalesChannelContext()->getSalesChannel()->getNavigationCategoryId(), $event->getSalesChannelContext()->getCustomer(), $event->getContext())) {
  80.             $this->logoutRoute->logout($event->getSalesChannelContext(), new RequestDataBag());
  81.             throw new CustomerNotLoggedInException();
  82.         }
  83.         if (!$this->categoryAccessAllowed($event->getPage()->getNavigationId(), $customer$event->getContext())) {
  84.             throw new CategoryNotFoundException($event->getPage()->getNavigationId());
  85.         }
  86.     }
  87.     public function onSalesChannelProductLoaded(StorefrontRenderEvent $event)
  88.     {
  89.         if ($event->getSalesChannelContext()->getCustomer() !== null) {
  90.             if (!$this->categoryAccessAllowed($event->getSalesChannelContext()->getSalesChannel()->getNavigationCategoryId(), $event->getSalesChannelContext()->getCustomer(), $event->getContext())) {
  91.                 $this->logoutRoute->logout($event->getSalesChannelContext(), new RequestDataBag());
  92.                 throw new CustomerNotLoggedInException();
  93.             }
  94.         }
  95.         $page array_key_exists('page'$event->getParameters()) ? $event->getParameters()['page'] : null;
  96.         if ($page instanceof ProductPage) {
  97.             $product $page->getProduct();
  98.             if ($product instanceof SalesChannelProductEntity) {
  99.                 if ($event->getSalesChannelContext()->getCustomer() === null) {
  100.                     throw new CustomerNotLoggedInException();
  101.                 }
  102.                 foreach ($product->getCategoryIds() as $id) {
  103.                     if ($this->categoryAccessAllowed($id$event->getSalesChannelContext()->getCustomer(), $event->getContext())) {
  104.                         return;
  105.                     }
  106.                 }
  107.                 throw new ProductNotFoundException($page->getProduct()->getId());
  108.             }
  109.         }
  110.     }
  111.     protected function categoryAccessAllowed(string $categoryId$customer$context): bool
  112.     {
  113.         $customerGroups = [];
  114.         if ($customer instanceof CustomerEntity) {
  115.             $customerGroups $this->customerPermissionService->getCustomerPermissionGroupIds($customer);
  116.         }
  117.         if ($categoryId) {
  118.             $categoryCriteria = new Criteria([$categoryId]);
  119.             $category $this->categoryRepository->search($categoryCriteria$context);
  120.             /** @var CategoryEntity $category */
  121.             if ($category $category->first()) {
  122.                 $categoryGroups is_array($category->getCustomFields()) && array_key_exists('custom_acl_groups'$category->getCustomFields()) ? $category->getCustomFields()['custom_acl_groups'] : [];
  123.                 if (count(array_intersect($customerGroups$categoryGroups)) < && count($categoryGroups) > 0) {
  124.                     return false;
  125.                 }
  126.             }
  127.         }
  128.         return true;
  129.     }
  130.     protected function categoryAccessAllowedByEntities($category$customer): bool
  131.     {
  132.         $customerGroups = [];
  133.         if ($customer instanceof CustomerEntity) {
  134.             $customerGroups $this->customerPermissionService->getCustomerPermissionGroupIds($customer);
  135.         }
  136.         if ($category) {
  137.             $categoryGroups is_array($category->getCustomFields()) && array_key_exists('custom_acl_groups'$category->getCustomFields()) ? $category->getCustomFields()['custom_acl_groups'] : [];
  138.             if (count(array_intersect($customerGroups$categoryGroups)) < && count($categoryGroups) > 0) {
  139.                 return false;
  140.             }
  141.         }
  142.         return true;
  143.     }
  144.     protected function filterTreeChilds(TreeItem $treeItem$customer)
  145.     {
  146.         if (is_null($treeItem->getChildren()) || count($treeItem->getChildren()) < 1) {
  147.             return;
  148.         }
  149.         $treeItem->setChildren(array_filter($treeItem->getChildren(), function (TreeItem $treeItem) use ($customer) {
  150.             $category $treeItem->getCategory();
  151.             if ($this->categoryAccessAllowedByEntities($category$customer)) {
  152.                 $this->filterTreeChilds($treeItem$customer);
  153.                 return true;
  154.             }
  155.             return false;
  156.         }));
  157.     }
  158.     public function onProductListingResultEvent(ProductListingResultEvent $event)
  159.     {
  160.         $customerRoleGroups = [];
  161.         $removedProducts = [];
  162.         $customer $event->getSalesChannelContext()->getCustomer();
  163.         if ($customer instanceof CustomerEntity) {
  164.             $customerRoleGroups $this->customerPermissionService->getCustomerPermissionGroupIds($customer);
  165.         }
  166.         /** @var SalesChannelProductEntity $product */
  167.         foreach ($event->getResult()->getElements() as $key => $product) {
  168.             //dd($product->getCategoryIds());
  169.             $categoryIds $product->getCategoryIds();
  170.             /** @var CategoryEntity $lowestCategory */
  171.             //$lowestCategory = $this->categoryRepository->search(new Criteria([$lowestCategoryId]), $event->getContext())->first();
  172.             if ($this->removeProductFromResult($categoryIds$customerRoleGroups$event->getContext())) {
  173.                 $removedProducts[] = $key;
  174.             }
  175.         }
  176.         foreach ($removedProducts as $removedProduct) {
  177.             //$event->getResult()->remove($removedProduct);
  178.         }
  179.     }
  180.     protected function removeProductFromResult(array $categoryIds, array $customerRoleGroups$context)
  181.     {
  182.         foreach ($categoryIds as $categoryId) {
  183.             $category $this->categoryRepository->search(new Criteria([$categoryId]), $context)->first();
  184.             if ($category && is_array($category->getCustomFields()) && array_key_exists('custom_acl_groups'$category->getCustomFields()) && is_array($category->getCustomFields()['custom_acl_groups'])) {
  185.                 if (count(array_intersect($category->getCustomFields()['custom_acl_groups'], $customerRoleGroups)) !== || count($category->getCustomFields()['custom_acl_groups']) === 0) {
  186.                     return false;
  187.                 }
  188.             }
  189.         }
  190.         return true;
  191.     }
  192.     public function onProductSuggestCriteriaEvent(ProductSuggestCriteriaEvent $event)
  193.     {
  194.         $event->getCriteria()->setTitle('search::product::suggestion');
  195.     }
  196. }