custom/plugins/AcrisFaqCS/src/Storefront/Subscriber/ProductLoadedSubscriber.php line 170

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Acris\Faq\Storefront\Subscriber;
  3. use Acris\Faq\Components\Faq\FaqCmsPageService;
  4. use Acris\Faq\Components\Faq\FaqGateway;
  5. use Acris\Faq\Components\Faq\FaqService;
  6. use Acris\Faq\Core\Content\Cms\SalesChannel\Struct\FaqSingleStruct;
  7. use Acris\Faq\Core\Content\Cms\SalesChannel\Struct\FaqStruct;
  8. use Acris\Faq\Core\Framework\DataAbstractionLayer\Cache\FaqEntityCacheKeyGenerator;
  9. use Acris\Faq\Custom\FaqDefinition;
  10. use Acris\Faq\Custom\FaqEntity;
  11. use Acris\Faq\Custom\FaqGroupCollection;
  12. use Acris\Faq\Custom\FaqGroupEntity;
  13. use Shopware\Core\Content\Category\Event\CategoryRouteCacheTagsEvent;
  14. use Shopware\Core\Content\Category\SalesChannel\CategoryRouteResponse;
  15. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
  16. use Shopware\Core\Content\Cms\CmsPageCollection;
  17. use Shopware\Core\Content\Cms\CmsPageEntity;
  18. use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
  19. use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageLoaderInterface;
  20. use Shopware\Core\Content\Product\SalesChannel\Detail\CachedProductDetailRoute;
  21. use Shopware\Core\Framework\Adapter\Cache\CacheInvalidator;
  22. use Shopware\Core\Framework\Context;
  23. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  24. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  25. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  26. use Shopware\Core\Framework\Struct\ArrayEntity;
  27. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  28. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  29. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  30. use Symfony\Component\HttpFoundation\Request;
  31. class ProductLoadedSubscriber implements EventSubscriberInterface
  32. {
  33.     public const ACRIS_STREAM_IDS_EXTENSION 'acrisStreamIds';
  34.     /**
  35.      * @var FaqService
  36.      */
  37.     private FaqService $faqService;
  38.     /**
  39.      * @var FaqGateway
  40.      */
  41.     private FaqGateway $faqGateway;
  42.     /**
  43.      * @var CacheInvalidator
  44.      */
  45.     private CacheInvalidator $logger;
  46.     private FaqCmsPageService $faqCmsPageService;
  47.     public function __construct(
  48.         FaqService       $faqService,
  49.         FaqGateway       $faqGateway,
  50.         CacheInvalidator $logger,
  51.         FaqCmsPageService $faqCmsPageService
  52.     )
  53.     {
  54.         $this->faqService $faqService;
  55.         $this->faqGateway $faqGateway;
  56.         $this->logger $logger;
  57.         $this->faqCmsPageService $faqCmsPageService;
  58.     }
  59.     public static function getSubscribedEvents()
  60.     {
  61.         return [
  62.             ProductPageLoadedEvent::class => [
  63.                 ['productLoaded'200]
  64.             ],
  65.             'acris_faq.written' => [
  66.                 ['onFaqWritten'200]
  67.             ],
  68.             'acris_faq_group.written' => [
  69.                 ['onFaqGroupWritten'200]
  70.             ],
  71.             CategoryRouteCacheTagsEvent::class => [
  72.                 ['onCategoryRouteCacheTags'200]
  73.             ]
  74.         ];
  75.     }
  76.     public function productLoaded(ProductPageLoadedEvent $event): void
  77.     {
  78.         $request $event->getRequest();
  79.         if(empty($request) === true) {
  80.             return;
  81.         }
  82.         if (empty($event->getPage()) || empty($event->getPage()->getProduct()) || empty($event->getContext()->getLanguageId())) return;
  83.         $languageId $event->getContext()->getLanguageId();
  84.         $product $event->getPage()->getProduct();
  85.         if ($product->hasExtension(self::ACRIS_STREAM_IDS_EXTENSION) && !empty($product->getExtension(self::ACRIS_STREAM_IDS_EXTENSION))) {
  86.             $productStreamIds $product->getExtension(self::ACRIS_STREAM_IDS_EXTENSION)->get('ids');
  87.         } else {
  88.             $productStreamIds $this->faqGateway->getProductStreamIds($product->getId(), $event->getSalesChannelContext()->getContext());
  89.             $product->addExtension(self::ACRIS_STREAM_IDS_EXTENSION, new ArrayEntity(['ids' => $productStreamIds]));
  90.         }
  91.         if (empty($productStreamIds)) return;
  92.         $faqGroupResult $this->faqGateway->getProductDetailFaqGroup($productStreamIds$event->getContext());
  93.         if ($faqGroupResult->count() === 0) {
  94.             return;
  95.         }
  96.         $faqGroupCollection $faqGroupResult->getEntities();
  97.         $faqGroups $this->faqService->checkLanguage($faqGroupCollection->getElements(), $languageId);
  98.         $this->assignFaqsVideos($faqGroupCollection$event->getSalesChannelContext());
  99.         $this->assignFaqsCmsPage($request$faqGroupCollection$event->getSalesChannelContext());
  100.         $this->faqService->assignPreviewImage($faqGroupCollection$event->getSalesChannelContext());
  101.         $product->addExtension('acrisFaq'$faqGroupCollection);
  102.     }
  103.     public function onFaqWritten(EntityWrittenEvent $event): void
  104.     {
  105.         $results $event->getWriteResults();
  106.         $faqIds = [];
  107.         foreach ($results as $result) {
  108.             $payload $result->getPayload();
  109.             if (!empty($payload) && array_key_exists('id'$payload) && !empty($payload['id'])) {
  110.                 $faqIds[] = $payload['id'];
  111.             }
  112.         }
  113.         if (!empty($faqIds)) {
  114.             $this->clearCacheForFaq($faqIds$event->getContext());
  115.             $this->upsertMetaDataWithFaqIds($faqIds$event->getContext());
  116.         }
  117.     }
  118.     public function onFaqGroupWritten(EntityWrittenEvent $event): void
  119.     {
  120.         $results $event->getWriteResults();
  121.         $faqIds = [];
  122.         $faqGroupIds = [];
  123.         foreach ($results as $result) {
  124.             $payload $result->getPayload();
  125.             if (!empty($payload) && array_key_exists('id'$payload) && !empty($payload['id'])) {
  126.                 $faqGroupIds[] = $payload['id'];
  127.             }
  128.         }
  129.         if (!empty($faqGroupIds)) {
  130.             $faqSearchResult $this->faqService->getFaqGroups($faqGroupIds$event->getContext());
  131.             if ($faqSearchResult->count() === 0) return;
  132.             $faqIds $this->clearCacheForFaqGroup($faqSearchResult->getEntities(), $event->getContext());
  133.         }
  134.         if (!empty($faqIds)) {
  135.             // invalidates all routes which loads faqs
  136.             $this->logger->invalidate(
  137.                 array_map([FaqEntityCacheKeyGenerator::class, 'buildFaqTag'], $faqIds)
  138.             );
  139.         }
  140.     }
  141.     public function onCategoryRouteCacheTags(CategoryRouteCacheTagsEvent $event): void
  142.     {
  143.         $event->addTags(
  144.             $this->extractFaqIds($event->getResponse())
  145.         );
  146.     }
  147.     public function extractFaqIds(CategoryRouteResponse $response): array
  148.     {
  149.         $page $response->getCategory()->getCmsPage();
  150.         if ($page === null) {
  151.             return [];
  152.         }
  153.         $ids = [];
  154.         $slots $page->getElementsOfType('acris-faq');
  155.         /** @var CmsSlotEntity $slot */
  156.         foreach ($slots as $slot) {
  157.             $faqStruct $slot->getData();
  158.             if (!$faqStruct instanceof FaqStruct) {
  159.                 continue;
  160.             }
  161.             if ($faqStruct->getFaq()->count() === 0) {
  162.                 continue;
  163.             }
  164.             foreach ($faqStruct->getFaq()->getElements() as $faqGroup) {
  165.                 if ($faqGroup->getFaqs()->count() === 0) continue;
  166.                 foreach ($faqGroup->getFaqs()->getElements() as $faq) {
  167.                     $ids[] = $faq->getId();
  168.                 }
  169.             }
  170.         }
  171.         $slots $page->getElementsOfType('acris-faq-single');
  172.         /** @var CmsSlotEntity $slot */
  173.         foreach ($slots as $slot) {
  174.             $faqSingleStruct $slot->getData();
  175.             if (!$faqSingleStruct instanceof FaqSingleStruct) {
  176.                 continue;
  177.             }
  178.             if ($faqSingleStruct->getFaqSingle()->count() === 0) {
  179.                 continue;
  180.             }
  181.             foreach ($faqSingleStruct->getFaqSingle()->getElements() as $faq) {
  182.                 $ids[] = $faq->getId();
  183.             }
  184.         }
  185.         $ids array_values(array_unique(array_filter($ids)));
  186.         return array_merge(
  187.             array_map([FaqEntityCacheKeyGenerator::class, 'buildFaqTag'], $ids),
  188.         );
  189.     }
  190.     private function assignFaqsVideos(FaqGroupCollection $faqGroupCollectionSalesChannelContext $context): void
  191.     {
  192.         if ($faqGroupCollection->count() === 0) return;
  193.         /** @var FaqGroupEntity $faqGroup */
  194.         foreach ($faqGroupCollection->getElements() as $faqGroup) {
  195.             if (empty($faqGroup->getFaqs()) || $faqGroup->getFaqs()->count() === 0) continue;
  196.             foreach ($faqGroup->getFaqs()->getElements() as $faq) {
  197.                 if (!empty($faq->getTranslation('embedCode')) && $faq->getVideoType() === FaqService::DEFAULT_FAQ_VIDEO_YOUTUBE_TYPE) {
  198.                     $this->faqService->loadFaqVideo($faq$context);
  199.                 }
  200.             }
  201.         }
  202.     }
  203.     private function assignFaqsCmsPage(Request $requestFaqGroupCollection $faqGroupCollectionSalesChannelContext $context): void
  204.     {
  205.         if ($faqGroupCollection->count() === 0) return;
  206.         /** @var FaqGroupEntity $faqGroup */
  207.         foreach ($faqGroupCollection->getElements() as $faqGroup) {
  208.             if (empty($faqGroup->getFaqs()) || $faqGroup->getFaqs()->count() === 0) continue;
  209.             foreach ($faqGroup->getFaqs()->getElements() as $faq) {
  210.                 if (!empty($faq->getLayout()) && $faq->getLayout() === 'cms') {
  211.                     $cmsPages $this->faqCmsPageService->getCmsPages($request$context$faq);
  212.                     $faq->setCmsPage($cmsPages->first());
  213.                 }
  214.             }
  215.         }
  216.     }
  217.     private function clearCacheForFaq(array $faqIdsContext $context): void
  218.     {
  219.         // invalidates all routes which loads faqs
  220.         $this->logger->invalidate(
  221.             array_map([FaqEntityCacheKeyGenerator::class, 'buildFaqTag'], $faqIds)
  222.         );
  223.         $faqSearchResult $this->faqService->getFaqs($faqIds$context);
  224.         if ($faqSearchResult->count() === 0) return;
  225.         $productIds = [];
  226.         $faqGroupIds = [];
  227.         /** @var FaqEntity $faq */
  228.         foreach ($faqSearchResult->getEntities()->getElements() as $faq) {
  229.             if (empty($faq->getGroups()) || $faq->getGroups()->count() === 0) continue;
  230.             foreach ($faq->getGroups()->getElements() as $faqGroup) {
  231.                 if (empty($faqGroup->getProductStreams()) || $faqGroup->getProductStreams()->count() === || in_array($faqGroup->getId(), $faqGroupIds)) continue;
  232.                 $faqGroupIds[] = $faqGroup->getId();
  233.                 $productStreamIds = [];
  234.                 foreach ($faqGroup->getProductStreams()->getElements() as $productStream) {
  235.                     $productStreamIds[] = $productStream->getId();
  236.                 }
  237.                 if (!empty($productStreamIds)) {
  238.                     $productIds array_unique(array_merge($productIds$this->faqService->getProductIdsFromProductStreams($productStreamIds$context)));
  239.                 }
  240.             }
  241.         }
  242.         if (!empty($productIds)) {
  243.             $this->logger->invalidate(
  244.                 array_map([CachedProductDetailRoute::class, 'buildName'], $productIds)
  245.             );
  246.         }
  247.     }
  248.     private function clearCacheForFaqGroup(FaqGroupCollection $faqGroupCollectionContext $context): array
  249.     {
  250.         $faqIds = [];
  251.         $productIds = [];
  252.         foreach ($faqGroupCollection->getElements() as $faqGroup) {
  253.             if (!empty($faqGroup->getFaqs()) && $faqGroup->getFaqs()->count() > 0) {
  254.                 foreach ($faqGroup->getFaqs()->getElements() as $faq) {
  255.                     if (in_array($faq->getId(), $faqIds)) continue;
  256.                     $faqIds[] = $faq->getId();
  257.                 }
  258.             }
  259.             if (empty($faqGroup->getProductStreams()) || $faqGroup->getProductStreams()->count() === 0) continue;
  260.             $productStreamIds = [];
  261.             foreach ($faqGroup->getProductStreams()->getElements() as $productStream) {
  262.                 $productStreamIds[] = $productStream->getId();
  263.             }
  264.             if (!empty($productStreamIds)) {
  265.                 $productIds array_unique(array_merge($productIds$this->faqService->getProductIdsFromProductStreams($productStreamIds$context)));
  266.             }
  267.         }
  268.         if (!empty($productIds)) {
  269.             $this->logger->invalidate(
  270.                 array_map([CachedProductDetailRoute::class, 'buildName'], $productIds)
  271.             );
  272.         }
  273.         return $faqIds;
  274.     }
  275.     private function upsertMetaDataWithFaqIds(array $faqIdsContext $context): void
  276.     {
  277.         $criteria $this->faqService->loadCriteria(new Criteria([$faqIds]));
  278.         $this->faqService->upsertYoutubeMetaDataWithFaqIds($criteria$context);
  279.     }
  280. }