<?php declare(strict_types=1);
namespace ThemeOkeOnline\Storefront\Page\Checkout;
use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
use Shopware\Core\Checkout\Shipping\SalesChannel\AbstractShippingMethodRoute;
use Shopware\Core\Content\Product\ProductCollection;
use Shopware\Core\Content\Product\SalesChannel\CrossSelling\AbstractProductCrossSellingRoute;
use Shopware\Core\Content\Product\SalesChannel\CrossSelling\ProductCrossSellingRouteResponse;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
use Shopware\Storefront\Page\PageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
class CheckoutCartPageLoadedEventSubscriber implements EventSubscriberInterface
{
/** @var ProductCrossSellingRoute $crossSellLoaderRoute */
private $crossSellLoaderRoute;
private AbstractShippingMethodRoute $shippingMethodRoute;
private EntityRepository $shippingMethodRepository;
private SystemConfigService $systemConfigService;
public function __construct(
AbstractShippingMethodRoute $shippingMethodRoute,
EntityRepository $shippingMethodRepository,
AbstractProductCrossSellingRoute $crossSellLoaderRoute,
SystemConfigService $systemConfigService
)
{
$this->shippingMethodRoute = $shippingMethodRoute;
$this->shippingMethodRepository = $shippingMethodRepository;
$this->crossSellLoaderRoute = $crossSellLoaderRoute;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array
{
return [
CheckoutCartPageLoadedEvent::class => ['addCrossSellProductsToCartPage'],
CheckoutCartPageLoadedEvent::class => ['addShippingMethodsToPage']
];
}
public function addShippingMethodsToPage(PageLoadedEvent $event)
{
$request = new Request();
$request->query->set('onlyAvailable', '1');
$salesChannelContext = $event->getSalesChannelContext();
$context = $salesChannelContext->getContext();
$page = $event->getPage();
$salesChannelId = $salesChannelContext->getSalesChannel()->id;
$criteria = new Criteria();
$criteria->addAssociation('salesChannels');
$criteria->addAssociation('prices');
$criteria->addFilter(
new EqualsFilter('active', true),
new EqualsFilter('salesChannels.id', $salesChannelId)
);
$shippingMethods = $this->shippingMethodRoute->load($request, $salesChannelContext, new Criteria())->getShippingMethods();
$page->addExtension(
'shippingMethods',
$shippingMethods
);
}
public function addCrossSellProductsToCartPage(CheckoutCartPageLoadedEvent $event)
{
$salesChannelContext = $event->getSalesChannelContext();
$page = $event->getPage();
$cart = $page->getCart();
// collect all productIds of products in cart
$productIds = $this->getProductIdsFromLineItems($cart->getLineItems());
$productCollection = new ProductCollection();
$maxNumProductsInCart = $this->systemConfigService->get("ThemeOkeOnline.config.maxNumProductsInCart") ?? 6;
foreach($productIds as $productId)
{
if($productCollection->count() > $maxNumProductsInCart)
break;
// load all CrossSelling products, trough the loader, to handle normal crossselling products, but also the productstream variant
$crossSellResponse = $this->crossSellLoaderRoute->load($productId, new Request(), $salesChannelContext, new Criteria());
// merge all CrossSelling prodicts in one ProductCollection
$productCollection = $this->mergeCrossSellingProductsCollectionFromObject($crossSellResponse, $productCollection);
}
// add Extension to the page
if($productCollection->count() > 0)
{
$page->addExtension(
'crossSellProducts',
$productCollection
);
}
}
private function getProductIdsFromLineItems(LineItemCollection $lineItems): array
{
// get both normal products, and cp-products
return array_merge(
$this->getProductIdsFromProducts($lineItems),
$this->getProductIdsFromCustomizedProducts($lineItems)
);
}
private function getProductIdsFromCustomizedProducts(LineItemCollection $lineItems): array
{
$ids = array();
// loop trough the Cp's and get the ReferenceIds from there underlaying products
$lineItems->filterType('customized-products')->map(function($lineItem) use (&$ids) {
$ids = array_merge($ids, array_values($lineItem->getChildren()->filterType('product')->getReferenceIds()));
});
return $ids;
}
private function getProductIdsFromProducts(LineItemCollection $lineItems): array
{
return $lineItems->filterType('product')->getReferenceIds();
}
private function mergeCrossSellingProductsCollectionFromObject(ProductCrossSellingRouteResponse $crossSellResponse, ProductCollection $productCollection): ProductCollection
{
if($array = $crossSellResponse->getResult())
{
foreach($array as $crossSellingElement)
{
$productCollection->merge($crossSellingElement->getProducts());
}
}
return $productCollection;
}
}