<?php declare(strict_types=1);
namespace Websignaal\Goesting\Subscriber;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Shopware\Core\Framework\Context;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\SalesChannel\CrossSelling\CrossSellingElementCollection;
class StorefrontRenderSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private $categoryRepository;
/**
* @var EntityRepositoryInterface
*/
private $productRepository;
/**
* @var EntityRepositoryInterface
*/
private $propertyGroupOptionRepository;
public function __construct(
EntityRepositoryInterface $categoryRepository,
EntityRepositoryInterface $productRepository,
EntityRepositoryInterface $propertyGroupOptionRepository
)
{
$this->categoryRepository = $categoryRepository;
$this->productRepository = $productRepository;
$this->propertyGroupOptionRepository = $propertyGroupOptionRepository;
}
public static function getSubscribedEvents(): array
{
return[
StorefrontRenderEvent::class => 'onStorefrontRender',
ProductListingCriteriaEvent::class => 'addAssociationsToProductListing',
ProductSearchCriteriaEvent::class => 'addAssociationsToProductSearch'
];
}
public function onStorefrontRender(StorefrontRenderEvent $event)
{
$route = $event->getRequest()->get('_route');
//only execute the code if the route is the detail page
if($route == 'frontend.detail.page'){
$page = $event->getParameters()['page'];
$crossSellings= $page->getCrossSellings();
$this->getCrossSellingsWithAssociations($crossSellings,$event->getContext());
//check if page is set and of the right entityType
if($page && is_a($page, 'Shopware\Storefront\Page\Product\ProductPage'))
{
//get product from page
$product= $page->getProduct();
if($product)
{
$categoryCollection= $this->getCategoryCollectionByIds($product->getCategoryIds(), $event->getContext());
$propertyGroupCollection = $this->getPropertGroupOption($product->getId(), $event->getContext());
if ($categoryCollection) {
//add categoryCollection to product entity on detail page
$page->getProduct()->setCategories($categoryCollection);
//add propertyGroupCollection to product entity on detail page
$page->getProduct()->setProperties($propertyGroupCollection);
$page->setProduct($product);
//set newly updated page to event
$event->setParameter('page', $page);
}
}
}
}
}
public function getCrossSellingsWithAssociations($crossSellings,$context)
{
$crossSellingWithAssociations = new CrossSellingElementCollection();
$crossSellProductsIds= [];
//get CrossSellings ProductCollections
foreach($crossSellings as $crossSelling)
{
$crossSellProducts= $crossSelling->getProducts();
//check each products in crossSell if they are found in allowed products (matching to the current model).
foreach($crossSellProducts as $crossSellProduct)
{
$crossSellProductsIds[] = $crossSellProduct->getId();
}
$crossSellProducts = $this->getCrossSellingProductCollection($crossSellProductsIds, $context);
$crossSelling->setProducts($crossSellProducts);
// add the crossSelling to the allowed CrossSellings
$crossSellingWithAssociations->add($crossSelling);
}
return $crossSellingWithAssociations;
}
private function getCrossSellingProductCollection($productIds,$context)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsAnyFilter('id', $productIds));
$criteria->addAssociation('categories');
$criteria->addAssociation('properties');
$criteria->addAssociation('properties.group');
$criteria->addAssociation('properties.media');
$criteria->addAssociation('cover');
$productCollection = $this->productRepository->search($criteria, $context)->getEntities();
return $productCollection;
}
public function addAssociationsToProductListing(ProductListingCriteriaEvent $event)
{
$criteria = $event->getCriteria();
$criteria->addAssociation('categories');
$criteria->addAssociation('properties');
$criteria->addAssociation('properties.group');
$criteria->addAssociation('properties.media');
}
public function addAssociationsToProductSearch(ProductSearchCriteriaEvent $event)
{
$criteria = $event->getCriteria();
$criteria->addAssociation('categories');
$criteria->addAssociation('properties');
$criteria->addAssociation('properties.group');
$criteria->addAssociation('properties.media');
}
private function getCategoryCollectionByIds($categoryIds, $context)
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsAnyFilter('id', $categoryIds));
//removes the Products category
$criteria->addFilter(
new RangeFilter('level', [
RangeFilter::GT => 2
])
);
$criteria->addAssociation('seoUrls');
$criteria->addAssociation('media');
$categoryCollection = $this->categoryRepository->search($criteria, $context)->getEntities();
return $categoryCollection;
}
private function getPropertGroupOption($productId,$context)
{
$criteria = new Criteria();
$criteria->addAssociation('productProperties');
$criteria->addAssociation('group');
$criteria->addFilter(new EqualsFilter('productProperties.id', $productId));
$criteria->addAssociation('media');
$propertyGroupOptionCollection = $this->propertyGroupOptionRepository->search($criteria, $context)->getEntities();
return $propertyGroupOptionCollection;
}
}