custom/plugins/EsmComputer/src/Storefront/Subscriber/SeoSubscriber.php line 51

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace EsmComputer\Storefront\Subscriber;
  4. use Shopware\Core\Content\Category\CategoryEntity;
  5. use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
  6. use Shopware\Core\Content\Product\ProductEntity;
  7. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  10. use Shopware\Core\Framework\Struct\ArrayStruct;
  11. use Shopware\Storefront\Page\Navigation\NavigationPageLoadedEvent;
  12. use Shopware\Storefront\Page\Page;
  13. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  17. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  18. use function array_key_exists;
  19. use function array_values;
  20. use function date;
  21. use function header;
  22. use function html_entity_decode;
  23. use function implode;
  24. use function str_ends_with;
  25. use function var_dump;
  26. class SeoSubscriber implements EventSubscriberInterface
  27. {
  28.     private CONST CUSTOM_FIELD_NOODP 'custom_category_noodp';
  29.     private EntityRepository $categoryRepository;
  30.     private ?EntityRepository $ratingRepository;
  31.     public function __construct(EntityRepository $categoryRepository, ?EntityRepository $ratingRepository)
  32.     {
  33.         $this->categoryRepository $categoryRepository;
  34.         $this->ratingRepository $ratingRepository;
  35.     }
  36.     public static function getSubscribedEvents(): array
  37.     {
  38.         return [
  39.             NavigationPageLoadedEvent::class => 'onNavigationPageLoaded',
  40.             ProductPageLoadedEvent::class => 'onProductPageLoaded',
  41.             ExceptionEvent::class => 'redirectToPageWithSlash'
  42.         ];
  43.     }
  44.     public function redirectToPageWithSlash(ExceptionEvent $event): void
  45.     {
  46.         $path 'https://' $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  47.         if($event->getThrowable() instanceof NotFoundHttpException && substr($path, -1) !== '/') {
  48.             header("Location: " $path '/'true302);
  49.             exit;
  50.         }
  51.     }
  52.     public function onNavigationPageLoaded(NavigationPageLoadedEvent $event): void
  53.     {
  54.         $this->setMetaInformation($event->getPage(), $event->getRequest());
  55.         $this->loadReviews($event);
  56.     }
  57.     public function onProductPageLoaded(ProductPageLoadedEvent $event): void
  58.     {
  59.         $this->setMetaInformation($event->getPage(), $event->getRequest());
  60.         $this->loadExpertRating($event);
  61.         $this->loadEnvironmentSavings($event);
  62.     }
  63.     protected function setMetaInformation(Page $pageRequest $request): void
  64.     {
  65.         $metaInformation $page->getMetaInformation();
  66.         if($metaInformation) {
  67.             $metaInformation->setRobots($this->getRobots($page$request));
  68.             $metaInformation->setMetaTitle($this->getTitle($page$request));
  69.             $metaInformation->setMetaDescription(html_entity_decode($metaInformation->getMetaDescription()));
  70.             $metaInformation->setCopyrightYear(date('Y'));
  71.             $page->setMetaInformation($metaInformation);
  72.         }
  73.     }
  74.     private function getRobots(Page $pageRequest $request): string
  75.     {
  76.         $robots = ['index' => 'index''follow' => 'follow'];
  77.         /** @var CategoryEntity $category */
  78.         $category $page->getExtension('category');
  79.         if($category && $category->getCustomFields() && array_key_exists(self::CUSTOM_FIELD_NOODP$category->getCustomFields()) && $category->getCustomFields()[self::CUSTOM_FIELD_NOODP] === true) {
  80.             $robots['noodp'] = 'noodp';
  81.         }
  82.         if($request->get('p')) {
  83.             $robots['index'] = 'noindex';
  84.         }
  85.         return implode(','array_values($robots));
  86.     }
  87.     private function getTitle(Page $pageRequest $request): string
  88.     {
  89.         return html_entity_decode($page->getMetaInformation()->getMetaTitle()) . ($request->getRequestUri() !== '/' ' | ESM Computer' '');
  90.     }
  91.     private function loadReviews(NavigationPageLoadedEvent $event): void
  92.     {
  93.         $navigationId $event->getRequest()->attributes->get('navigationId');
  94.         if(!$navigationId || ($event->getPage()->getCmsPage() && $event->getPage()->getCmsPage()->getType() !== 'product_list')) {
  95.             return;
  96.         }
  97.         $apiUrl 'https://api.trustedshops.com/rest/public/v2/shops/XE152DC4802D12725E85E22A77A76A902/quality/reviews.json';
  98.         $tmpFolder sys_get_temp_dir();
  99.         $tmpFile $tmpFolder '/reviews.json';
  100.         $timeOut 86400;
  101.         if(!file_exists($tmpFile) || time() - filemtime($tmpFile) > $timeOut) {
  102.             $ch curl_init();
  103.             curl_setopt($chCURLOPT_HEADERfalse);
  104.             curl_setopt($chCURLOPT_RETURNTRANSFER1);
  105.             curl_setopt($chCURLOPT_POSTfalse);
  106.             curl_setopt($chCURLOPT_URL$apiUrl);
  107.             $output curl_exec($ch); curl_close($ch);
  108.             // Write the contents back to the file
  109.             // Make sure you can write to file's destination
  110.             file_put_contents($tmpFile$output);
  111.         }
  112.         $trustedShopMarkup '';
  113.         if ($jsonObject json_decode(file_get_contents($tmpFile), true)) {
  114.             $result $jsonObject['response']['data']['shop']['qualityIndicators']['reviewIndicator']['overallMark'];
  115.             $count $jsonObject['response']['data'] ['shop']['qualityIndicators']['reviewIndicator']['activeReviewCount'];
  116.             $shopName $jsonObject['response']['data']['shop']['name'];
  117.             $max "5.00";
  118.             if ($count 0) {
  119.                 $trustedShopMarkup '<script type="application/ld+json">';
  120.                 $trustedShopMarkup .= '{';
  121.                 $trustedShopMarkup .= '"@context": "http://schema.org",';
  122.                 $trustedShopMarkup .= '"@type": "Organization",';
  123.                 $trustedShopMarkup .= '"name": "'.$shopName.'",';
  124.                 $trustedShopMarkup .= '"aggregateRating" : {';
  125.                 $trustedShopMarkup .= '"@type": "AggregateRating",';
  126.                 $trustedShopMarkup .= '"ratingValue" : "'.$result.'",';
  127.                 $trustedShopMarkup .= '"bestRating" : "'.$max.'",';
  128.                 $trustedShopMarkup .= '"ratingCount" : "'.$count.'"';
  129.                 $trustedShopMarkup .= '}}';
  130.                 $trustedShopMarkup .= '</script>';
  131.             }
  132.         }
  133.         $event->getPage()->addExtension('trustedShopsRating', new ArrayStruct([$trustedShopMarkup]));
  134.     }
  135.     public function loadExpertRating(ProductPageLoadedEvent $event)
  136.     {
  137.         $product $event->getPage()->getProduct();
  138.         if($product->hasExtension('esm_expertrating') || !array_key_exists('custom_product_model'$product->getCustomFields())) {
  139.             return;
  140.         }
  141.         $model $product->getCustomFields()['custom_product_model'];
  142.         if(!$model) {
  143.             return;
  144.         }
  145.         $criteria = new Criteria();
  146.         $criteria->addFilter(new EqualsFilter('product.customFields.custom_product_model'$model));
  147.         $rating $this->ratingRepository->search($criteria$event->getContext())->first();
  148.         $product->addExtension('esm_expertrating'$rating);
  149.     }
  150.     public function loadEnvironmentSavings(ProductPageLoadedEvent $event)
  151.     {
  152.         $category $event->getPage()->getProduct()->getSeoCategory();
  153.         if(!$category) {
  154.             return;
  155.         }
  156.         if(!array_key_exists('custom_category_co2_saving'$category->getCustomFields()) || !array_key_exists('custom_category_water_saving'$category->getCustomFields())) {
  157.             $category $this->categoryRepository->search(new Criteria([$category->getParentId()]), $event->getContext())->first();
  158.         }
  159.         $customFields $category->getCustomFields();
  160.         if(array_key_exists('custom_category_co2_saving'$customFields) && array_key_exists('custom_category_water_saving'$customFields)) {
  161.             $event->getPage()->addExtension('savings', new ArrayStruct(['co2' => $customFields['custom_category_co2_saving'] ?? 0'water' => $customFields['custom_category_water_saving'] ?? 0]));
  162.         }
  163.     }
  164. }