custom/plugins/TrustedShops/src/Subscriber/FrontendSubscriber.php line 105

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace TrustedShops\Subscriber;
  3. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
  4. use Shopware\Core\Checkout\Order\OrderEntity;
  5. use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
  6. use Shopware\Core\Content\Product\ProductEntity;
  7. use Shopware\Core\Framework\Context;
  8. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  10. use Shopware\Core\Framework\Struct\ArrayEntity;
  11. use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
  12. use Shopware\Storefront\Page\Product\QuickView\MinimalQuickViewPageCriteriaEvent;
  13. use Shopware\Core\System\SystemConfig\SystemConfigService;
  14. use Shopware\Storefront\Event\StorefrontRenderEvent;
  15. use Shopware\Storefront\Page\Product\ProductPageCriteriaEvent;
  16. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. class FrontendSubscriber implements EventSubscriberInterface
  19. {
  20.     /**
  21.      * @var SystemConfigService
  22.      */
  23.     private $systemConfigService;
  24.     private $productRepository;
  25.     private $trustedshopProductRatingRepository;
  26.     /**
  27.      * @var string
  28.      */
  29.     private $shopReviewsApiUrl = 'https://api.trustedshops.com/rest/public/v2/shops/{{tsId}}/reviews';
  30.     /**
  31.      * @var int
  32.      */
  33.     private $shopReviewsCheckInterval = 3600;
  34.     public function __construct(SystemConfigService $systemConfigService, EntityRepositoryInterface $productRepository, EntityRepositoryInterface $trustedshopProductRatingRepository)
  35.     {
  36.         $this->systemConfigService = $systemConfigService;
  37.         $this->productRepository = $productRepository;
  38.         $this->trustedshopProductRatingRepository = $trustedshopProductRatingRepository;
  39.     }
  40.     public static function getSubscribedEvents(): array
  41.     {
  42.         $listeners = [
  43.             StorefrontRenderEvent::class => 'onStoreFrontRender',
  44.             MinimalQuickViewPageCriteriaEvent::class => 'onMinimalQuickViewPageCriteria',
  45.             ProductPageCriteriaEvent::class => 'onProductPageCriteria',
  46.             ProductPageLoadedEvent::class=>'onProductPageLoaded',
  47.             ProductListingCriteriaEvent::class => 'onProductListingCriteria',
  48.             CheckoutFinishPageLoadedEvent::class => 'onCheckoutFinishPageLoaded',
  49.         ];
  50.         if( class_exists( 'Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent' ) ) {
  51.             $listeners[ Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent::class ] = 'onLineItemAdded';
  52.         } else {
  53.             $listeners[ Shopware\Core\Checkout\Cart\Event\LineItemAddedEvent::class ] = 'onLineItemAdded';
  54.         }
  55.         return $listeners;
  56.     }
  57.     public function onStoreFrontRender(StorefrontRenderEvent $event): void
  58.     {
  59.         $isAjax = $event->getRequest()->isXmlHttpRequest();
  60.         if (!$isAjax) {
  61.             $this->initTrustedShopsShopReviews();
  62.         }
  63.         $config = $this->systemConfigService->get( 'TrustedShops.config', $event->getSalesChannelContext()->getSalesChannel()->getId() );
  64.         $event->setParameter( 'trustedshops', $config );
  65.     }
  66.     public function onMinimalQuickViewPageCriteria(MinimalQuickViewPageCriteriaEvent $event): void
  67.     {
  68.         $event->getCriteria()->addAssociation('extensions.trustedshopsRatings');
  69.     }
  70.     public function onProductPageCriteria(ProductPageCriteriaEvent $event): void
  71.     {
  72.         $event->getCriteria()->addAssociation('extensions.trustedshopsRatings');
  73.     }
  74.     public function onProductPageLoaded(ProductPageLoadedEvent $event){
  75.         $product = $event->getPage()->getProduct();
  76.         if( ( $parentId = $product->getParentId()) ) {
  77.             $parent = $this->productRepository->search(new Criteria([$parentId]), $event->getContext())->first();
  78.             $sku = new ArrayEntity();
  79.             $sku->set('sku', $parent->getProductNumber());
  80.             $product->addExtension("parentProduct", $sku);
  81.         }
  82.     }
  83.     public function onProductListingCriteria(ProductListingCriteriaEvent $event): void
  84.     {
  85.         $event->getCriteria()->addAssociation('extensions.trustedshopsRatings');
  86.     }
  87.     public function onLineItemAdded(BeforeLineItemAddedEvent $event): void
  88.     {
  89.         $lineItem = $event->getLineItem();
  90.         if( $lineItem->getType() === 'product' ) {
  91.             $context = Context::createDefaultContext();
  92.             /** @var ProductEntity $product */
  93.             $product = $this->productRepository->search((new Criteria([$lineItem->getReferencedId()])),$context)->first();
  94.             if( ( $parentId = $product->getParentId()) ) {
  95.                 /** @var ProductEntity $parent */
  96.                 $parent = $this->productRepository->search((new Criteria([$parentId]))->addAssociation('cover'),$context)->first();
  97.                 $lineItem->setPayloadValue('parent',[
  98.                     'productId' => $parent->getId(),
  99.                     'productNumber' => $parent->getProductNumber(),
  100.                     'label' => $parent->getTranslation('name'),
  101.                     'cover' => ( $parent->getCover() ? $parent->getCover()->getMedia() : null )
  102.                 ]);
  103.             }
  104.         }
  105.     }
  106.     public function onCheckoutFinishPageLoaded(CheckoutFinishPageLoadedEvent $event): void {
  107.         $page = $event->getPage();
  108.         $page->assign(['tsDeliveryTime' => $this->getTrustedShopsDeliveryTime( $page->getOrder() ) ] );
  109.     }
  110.     protected function getTrustedShopsDeliveryTime( OrderEntity $order )
  111.     {
  112.         $customAvailableDeliverTime = ( $this->systemConfigService->get( 'TrustedShops.config.tsAvailableProductDeliveryTime' ) === 'custom' );
  113.         $customUnavailableDeliverTime = ( $this->systemConfigService->get( 'TrustedShops.config.tsNotAvailableProductDeliveryTime' ) === 'custom' );
  114.         $availableDeliveryTimeDays = $this->systemConfigService->get( 'TrustedShops.config.tsAvailableProductDeliveryTimeDays' );
  115.         $unavailableDeliveryTimeDays = $this->systemConfigService->get( 'TrustedShops.config.tsNotAvailableProductDeliveryTimeDays' );
  116.         if( $this->orderContainsUnavailableProducts( $order ) ) {
  117.             if( $customUnavailableDeliverTime && $unavailableDeliveryTimeDays > 0 ) {
  118.                 $deliveryTimeDays = $unavailableDeliveryTimeDays;
  119.             } else {
  120.                 return $order->getDeliveries()->first()->getShippingDateLatest();
  121.             }
  122.         } else {
  123.             if( $customAvailableDeliverTime && $availableDeliveryTimeDays > 0 ) {
  124.                 $deliveryTimeDays = $availableDeliveryTimeDays;
  125.             } else {
  126.                 return $order->getDeliveries()->first()->getShippingDateLatest();
  127.             }
  128.         }
  129.         switch (date('N')) {
  130.             case 5: //freitag
  131.                 $deliveryTimeDays += 2;
  132.                 break;
  133.             case 6: //samstag
  134.                 $deliveryTimeDays += 1;
  135.                 break;
  136.         }
  137.         if( date( 'N', strtotime( '+' . $deliveryTimeDays . 'days' ) ) === 7 ) {
  138.             $deliveryTimeDays++;
  139.         }
  140.         return (new \DateTime())->add(new \DateInterval('P' . $deliveryTimeDays . 'D'));
  141.     }
  142.     protected function orderContainsUnavailableProducts( OrderEntity $order ): bool
  143.     {
  144.         $context = Context::createDefaultContext();
  145.         /** @var OrderLineItemEntity $lineItem */
  146.         foreach( $order->getLineItems() as $lineItem ) {
  147.             if( $lineItem->getType() === 'product' ) {
  148.                 /** @var ProductEntity $product */
  149.                 $product = $this->productRepository->search((new Criteria([$lineItem->getProductId()])),$context)->first();
  150.                 if( !$product->getAvailable() ) {
  151.                     return true;
  152.                 }
  153.             }
  154.         }
  155.         return false;
  156.     }
  157.     protected function initTrustedShopsShopReviews(): void
  158.     {
  159.         $domain = 'TrustedShops.config.';
  160.         $tsId = $this->systemConfigService->get( $domain . 'tsId' );
  161.         if( $tsId ) {
  162.             $lastCheck = $this->systemConfigService->get( $domain . 'tsShopRatingLastCheck' );
  163.             if( empty( $lastCheck ) || ( $lastCheck+$this->shopReviewsCheckInterval ) < time() ) {
  164.                 $apiUrl = str_replace( '{{tsId}}', $tsId, $this->shopReviewsApiUrl );
  165.                 $ch = curl_init();
  166.                 curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json' ] );
  167.                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  168.                 curl_setopt($ch, CURLOPT_URL, $apiUrl);
  169.                 $result = curl_exec($ch);
  170.                 curl_close($ch);
  171.                 if( $result ) {
  172.                     $shopReviews = json_decode($result);
  173.                     if ($shopReviews && $shopReviews->response && $shopReviews->response->data && $shopReviews->response->data->shop->reviews) {
  174.                         $bestRating = 0;
  175.                         $_ratings = [];
  176.                         foreach ($shopReviews->response->data->shop->reviews as $review) {
  177.                             $_rating = (float)$review->mark;
  178.                             $_ratings[] = $_rating;
  179.                             if ($_rating > $bestRating) {
  180.                                 $bestRating = $_rating;
  181.                             }
  182.                         }
  183.                         $ratingCount = count($shopReviews->response->data->shop->reviews);
  184.                         $avgRating = array_sum($_ratings) / $ratingCount;
  185.                         $this->systemConfigService->set($domain . 'tsShopAvgRating', $avgRating);
  186.                         $this->systemConfigService->set($domain . 'tsShopBestRating', $bestRating);
  187.                         $this->systemConfigService->set($domain . 'tsShopRatingCount', $ratingCount);
  188.                         $this->systemConfigService->set($domain . 'tsShopRatingLastCheck', time());
  189.                     }
  190.                 }
  191.             }
  192.         }
  193.     }
  194. }