custom/plugins/EsmComputer/src/Storefront/Subscriber/TemplateSubscriber.php line 147

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace EsmComputer\Storefront\Subscriber;
  4. use Shopware\Core\Checkout\Promotion\PromotionEntity;
  5. use Shopware\Core\Content\Category\CategoryCollection;
  6. use Shopware\Core\Content\Category\CategoryEntity;
  7. use Shopware\Core\Content\Category\Service\NavigationLoader;
  8. use Shopware\Core\Content\Category\Tree\Tree;
  9. use Shopware\Core\Content\Category\Tree\TreeItem;
  10. use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
  11. use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
  12. use Shopware\Core\Content\Product\ProductEvents;
  13. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  14. use Shopware\Core\Framework\Context;
  15. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  20. use Shopware\Core\Framework\Struct\ArrayStruct;
  21. use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
  22. use Shopware\Storefront\Page\Navigation\NavigationPageLoadedEvent;
  23. use Shopware\Storefront\Pagelet\Footer\FooterPageletLoadedEvent;
  24. use Shopware\Storefront\Pagelet\Header\HeaderPageletLoadedEvent;
  25. use Shopware\Storefront\Theme\ThemeEntity;
  26. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  27. use function array_key_exists;
  28. use function array_merge;
  29. use function is_array;
  30. class TemplateSubscriber implements EventSubscriberInterface
  31. {
  32.     protected EntityRepository $themeRepository;
  33.     protected EntityRepository $manufacturerRepository;
  34.     protected EntityRepository $productRepository;
  35.     protected EntityRepository $categoryRepository;
  36.     protected EntityRepository $productReviewRepository;
  37.     protected EntityRepository $promotionRepository;
  38.     protected NavigationLoader $navigationLoader;
  39.     public function __construct(
  40.         EntityRepository $themeRepository,
  41.         EntityRepository $manufacturerRepository,
  42.         EntityRepository $productRepository,
  43.         EntityRepository $categoryRepository,
  44.         EntityRepository $productReviewRepository,
  45.         EntityRepository $promotionRepository,
  46.         NavigationLoader $navigationLoader
  47.     )
  48.     {
  49.         $this->themeRepository $themeRepository;
  50.         $this->manufacturerRepository $manufacturerRepository;
  51.         $this->productRepository $productRepository;
  52.         $this->categoryRepository $categoryRepository;
  53.         $this->productReviewRepository $productReviewRepository;
  54.         $this->promotionRepository $promotionRepository;
  55.         $this->navigationLoader $navigationLoader;
  56.     }
  57.     public static function getSubscribedEvents(): array
  58.     {
  59.         return [
  60.             HeaderPageletLoadedEvent::class => 'onHeaderPageletLoaded',
  61.             FooterPageletLoadedEvent::class => 'onFooterPageletLoaded',
  62.             NavigationPageLoadedEvent::class => 'onNavigationPageLoaded',
  63.             ProductListingResultEvent::class => 'onProductListingResult',
  64.             'sales_channel.product.loaded' => ['onProductLoaded', -70],
  65.             ProductEvents::PRODUCT_LISTING_CRITERIA => 'onProductListingLoaded'
  66.         ];
  67.     }
  68.     public function onHeaderPageletLoaded(HeaderPageletLoadedEvent $event): void
  69.     {
  70.         $criteria = new Criteria();
  71.         $criteria->addFilter(new EqualsFilter('technicalName''EsmComputer'));
  72.         /** @var ThemeEntity $theme */
  73.         $theme $this->themeRepository->search($criteriaContext::createDefaultContext())->getEntities()->first();
  74.         $themeConfig $theme->getBaseConfig();
  75.         $themeConfig['fields'] = array_merge($themeConfig['fields'], $theme->getConfigValues() ?? []);
  76.         $leftCategory $themeConfig['fields']['sw-topbar-menu-category-left']['value'];
  77.         if($leftCategory) {
  78.             $leftCategory $this->loadCategory($leftCategory);
  79.             $event->getPagelet()->addExtension('leftCategory'$leftCategory);
  80.         }
  81.         $rightCategory $themeConfig['fields']['sw-topbar-menu-category-right']['value'];
  82.         if($rightCategory) {
  83.             $rightCategory $this->loadCategory($rightCategory);
  84.             $event->getPagelet()->addExtension('rightCategory'$rightCategory);
  85.         }
  86.         $navigation $event->getPagelet()->getNavigation();
  87.         $treeItems $navigation->getTree();
  88.         foreach($treeItems as $category) {
  89.             $groupChildren = [];
  90.             foreach ($category->getChildren() as $child) {
  91.                 if($child->getCategory()->getCustomFields() && array_key_exists('custom_category_menu_group'$child->getCategory()->getCustomFields()) && ($group $child->getCategory()->getCustomFields()['custom_category_menu_group'])) {
  92.                     $groupChildren[$group][] = $child;
  93.                 }
  94.             }
  95.             $groupChildren = new ArrayStruct($groupChildren);
  96.             $category->getCategory()->addExtension('groupChildren'$groupChildren);
  97.         }
  98.     }
  99.     public function onNavigationPageLoaded(NavigationPageLoadedEvent $event): void
  100.     {
  101.         $navigationId $event->getRequest()->attributes->get('navigationId');
  102.         if(!$navigationId) {
  103.             return;
  104.         }
  105.         $criteria = new Criteria();
  106.         $criteria->addFilter(new EqualsFilter('id'$navigationId));
  107.         $criteria->addAssociation('customFields');
  108.         /** @var CategoryEntity $category */
  109.         $category $this->categoryRepository->search($criteria$event->getContext())->getEntities()->first();
  110.         // Use parent header background if no background image is defined in current category
  111.         if($category && is_array($category->getCustomFields()) && !array_key_exists('custom_category_background'$category->getCustomFields())) {
  112.             $criteria = new Criteria();
  113.             $criteria->addFilter(new EqualsFilter('id'$category->getParentId()));
  114.             $criteria->addAssociation('customFields');
  115.             $parentCategory $this->categoryRepository->search($criteria$event->getContext())->getEntities()->first();
  116.             if($parentCategory->getCustomFields() && array_key_exists('custom_category_background'$parentCategory->getCustomFields())) {
  117.                 $customFields $category->getCustomFields();
  118.                 $customFields['custom_category_background'] = $parentCategory->getCustomFields()['custom_category_background'];
  119.                 $category->setCustomFields($customFields);
  120.             }
  121.         }
  122.         $event->getPage()->addExtension('category'$category);
  123.     }
  124.     public function onProductLoaded(SalesChannelEntityLoadedEvent $event): void
  125.     {
  126.         $products $event->getEntities();
  127.         /** @var SalesChannelProductEntity $product */
  128.         foreach($products as $product) {
  129.             $this->addRatingToProduct($product$event);
  130.             $this->addBadgeToProduct($product$event);
  131.         }
  132.     }
  133.     // Used to add category on category pages
  134.     public function onProductListingResult(ProductListingResultEvent $event): void
  135.     {
  136.         if($event->getRequest()->attributes->get('navigationId')) {
  137.             $category $this->getCategoryByNavigation($event->getRequest()->attributes->get('navigationId'), $event->getContext());
  138.             /** @var SalesChannelProductEntity $product */
  139.             foreach ($event->getResult() as $product) {
  140.                 $product->addExtension('category'$category);
  141.             }
  142.         }
  143.     }
  144.     private function getCategoryByNavigation(string $navigationIdContext $context): ?CategoryEntity
  145.     {
  146.         if(!$navigationId) {
  147.             return null;
  148.         }
  149.         $criteria = new Criteria();
  150.         $criteria->addFilter(new EqualsFilter('id'$navigationId));
  151.         $criteria->addAssociation('customFields');
  152.         /** @var CategoryEntity $category */
  153.         $category $this->categoryRepository->search($criteria$context)->getEntities()->first();
  154.         // Use parent hint if no hint is defined in current category
  155.         if($category && is_array($category->getCustomFields()) && !array_key_exists('custom_category_single_item'$category->getCustomFields())) {
  156.             $criteria = new Criteria();
  157.             $criteria->addFilter(new EqualsFilter('id'$category->getParentId()));
  158.             $criteria->addAssociation('customFields');
  159.             $parentCategory $this->categoryRepository->search($criteria$context)->getEntities()->first();
  160.             if($parentCategory && $parentCategory->getCustomFields() && array_key_exists('custom_category_single_item'$parentCategory->getCustomFields())) {
  161.                 $customFields $category->getCustomFields();
  162.                 $customFields['custom_category_single_item'] = $parentCategory->getCustomFields()['custom_category_single_item'];
  163.                 $category->setCustomFields($customFields);
  164.             }
  165.         }
  166.         return $category;
  167.     }
  168.     // Used for listing pages
  169.     public function onProductListingLoaded(ProductListingCriteriaEvent $event): void
  170.     {
  171.         // Manufacturer image is displayed in listing
  172.         $event->getCriteria()->addAssociation('manufacturer.media');
  173.         // A-/B-Ware is displayed in listing
  174.         $event->getCriteria()->addAssociation('properties');
  175.     }
  176.     private function addRatingToProduct($product$event): void
  177.     {
  178.         $criteria = new Criteria();
  179.         $criteria->addFilter(new EqualsFilter('productId'$product->getId()));
  180.         $criteria->addFilter(new RangeFilter('points', [RangeFilter::GTE => 4]));
  181.         $criteria->addFilter(new EqualsFilter('status'1));
  182.         $criteria->addSorting(new FieldSorting('points'FieldSorting::DESCENDING));
  183.         $criteria->setLimit(1);
  184.         $rating $this->productReviewRepository->search($criteria$event->getContext())->getEntities()->first();
  185.         $product->addExtension('rating'$rating);
  186.     }
  187.     private function addBadgeToProduct(SalesChannelProductEntity $product$event): void
  188.     {
  189.         if($product->getExtension('acrisPromotion')) {
  190.             $promotions = [];
  191.             $uvp = [];
  192.             foreach ($product->getExtension('acrisPromotion')['promotionIds'] as $promotionId) {
  193.                 $criteria = new Criteria([$promotionId]);
  194.                 /** @var PromotionEntity $promotion */
  195.                 $promotion $this->promotionRepository->search($criteria$event->getContext())->first();
  196.                 if($promotion) {
  197.                     $promotions[] = $promotion->getName();
  198.                     if($promotion->getCustomFields() && array_key_exists('custom_promotion_show_discount'$promotion->getCustomFields()) && $promotion->getCustomFields()['custom_promotion_show_discount']) {
  199.                         $uvp[] = true;
  200.                     }
  201.                 }
  202.             }
  203.             $product->addExtension('customBadges', new ArrayStruct($promotions));
  204.             $product->addExtension('displayUVP', new ArrayStruct($uvp));
  205.         }
  206.     }
  207.     public function onFooterPageletLoaded(FooterPageletLoadedEvent $event): void
  208.     {
  209.         $criteria = new Criteria();
  210.         $criteria->addFilter(new EqualsFilter('technicalName''EsmComputer'));
  211.         /** @var ThemeEntity $theme */
  212.         $theme $this->themeRepository->search($criteriaContext::createDefaultContext())->getEntities()->first();
  213.         $themeConfig $theme->getBaseConfig();
  214.         if($themeConfig['fields'] && $theme->getConfigValues()) {
  215.             $themeConfig['fields'] = array_merge($themeConfig['fields'], $theme->getConfigValues());
  216.         }
  217.         $leftCategory $themeConfig['fields']['sw-footer-menu-category-left']['value'];
  218.         if($leftCategory) {
  219.             $leftCategory $this->loadCategory($leftCategory);
  220.             $event->getPagelet()->addExtension('leftCategory'$leftCategory);
  221.         }
  222.         $rightCategory $themeConfig['fields']['sw-footer-menu-category-right']['value'];
  223.         if($rightCategory) {
  224.             $rightCategory $this->loadCategory($rightCategory);
  225.             $event->getPagelet()->addExtension('rightCategory'$rightCategory);
  226.         }
  227.     }
  228.     private function loadCategory($categoryId): Tree
  229.     {
  230.         $criteria = new Criteria();
  231.         $criteria->addFilter(new EqualsFilter('id'$categoryId));
  232.         $criteria->addAssociation('children');
  233.         $criteria->addSorting(new FieldSorting('autoIncrement'));
  234.         /** @var CategoryEntity $category */
  235.         $category $this->categoryRepository->search($criteriaContext::createDefaultContext())->getEntities()->first();
  236.         if($category) {
  237.             $parent = new TreeItem(null, []);
  238.             $parent->setCategory($category);
  239.             $parent->setChildren(
  240.                 $this->buildTree($categoryId$category->getChildren()->getElements())
  241.             );
  242.             $tree = [];
  243.             $tree[$categoryId] = $parent;
  244.             return new Tree(null$tree);
  245.         }
  246.         return new Tree(null, []);
  247.     }
  248.     /**
  249.      * From: Shopware\Core\Content\Category\Service\NavigationLoader
  250.      *
  251.      * @param CategoryEntity[] $categories
  252.      *
  253.      * @return TreeItem[]
  254.      */
  255.     private function buildTree(?string $parentId, array $categories): array
  256.     {
  257.         $children = new CategoryCollection();
  258.         foreach ($categories as $key => $category) {
  259.             if ($category->getParentId() !== $parentId) {
  260.                 continue;
  261.             }
  262.             unset($categories[$key]);
  263.             $children->add($category);
  264.         }
  265.         $children->sortByPosition();
  266.         $items = [];
  267.         foreach ($children as $child) {
  268.             if (!$child->getActive() || !$child->getVisible()) {
  269.                 continue;
  270.             }
  271.             $item = new TreeItem(null, []);
  272.             $item->setCategory($child);
  273.             $item->setChildren(
  274.                 $this->buildTree($child->getId(), $categories)
  275.             );
  276.             $items[$child->getId()] = $item;
  277.         }
  278.         return $items;
  279.     }
  280. }