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

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