<?php declare(strict_types=1);
namespace Wbfk\Bundles\Subscriber;
use Shopware\Core\Content\Product\ProductCollection;
use Shopware\Core\Content\Product\SalesChannel\Price\AbstractProductPriceCalculator;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductCollection;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Wbfk\Bundles\Entity\Bundle\BundleProductCollection;
use Wbfk\Bundles\Entity\Bundle\BundleProductEntity;
use Wbfk\Bundles\Struct\ProductBundlesStruct;
class AddBundleDataToProductPage implements EventSubscriberInterface
{
public function __construct(
private EntityRepository $bundleProductRepository,
private AbstractProductPriceCalculator $calculator,
private EventDispatcherInterface $eventDispatcher,
private SalesChannelProductDefinition $salesChannelProductDefinition
)
{
}
public static function getSubscribedEvents(): array
{
return [
ProductPageLoadedEvent::class => 'addBundleDataToProductPage'
];
}
public function addBundleDataToProductPage(ProductPageLoadedEvent $event): void
{
$salesChannelContext = $event->getSalesChannelContext();
/** @var ProductBundlesStruct $struct */
$struct = new ProductBundlesStruct();
$product = $event->getPage()->getProduct();
if (!$product) {
return;
}
$struct->setBundleChildren($this->getBundleChildren($product->getId(), $salesChannelContext));
$struct->setBundleParents($this->setBundleParents($product->getId(), $salesChannelContext));
$event->getPage()->addExtension('wbfkBundlesData', $struct);
}
public function getBundleChildren(string $productId, SalesChannelContext $salesChannelContext): BundleProductCollection
{
$context = $salesChannelContext->getContext();
$criteria = new Criteria();
$criteria->setTitle("Getting bundle products child products data");
$criteria->addAssociation('salesChannelChildProduct');
$criteria->addAssociation('salesChannelChildProduct.cover.media');
$criteria->addSorting(new FieldSorting('salesChannelChildProduct.price.first.gross', 'DESC'));
$criteria->addFilter(new EqualsFilter('productId', $productId));
$criteria->addFilter(new EqualsFilter('childProduct.active', true));
/** @var BundleProductCollection $bundleChildren */
$bundleChildren = $this->bundleProductRepository->search($criteria, $context)->getEntities();
$products = new SalesChannelProductCollection([]);
/** @var BundleProductEntity $bundleChild */
foreach ($bundleChildren as $bundleChild) {
$products->add($bundleChild->getSalesChannelChildProduct());
}
$this->calculator->calculate($products, $salesChannelContext);
$this->eventDispatcher->dispatch(new SalesChannelEntityLoadedEvent(
$this->salesChannelProductDefinition,
$products->getElements(),
$salesChannelContext
), 'sales_channel.product.loaded');
return $bundleChildren;
}
public function setBundleParents(string $productId, SalesChannelContext $salesChannelContext): BundleProductCollection
{
$context = $salesChannelContext->getContext();
$criteria = new Criteria();
$criteria->setTitle("Getting bundle products parent products data");
$criteria->addAssociation('salesChannelProduct');
$criteria->addAssociation('salesChannelChildProduct');
$criteria->addSorting(new FieldSorting('salesChannelProduct.price.first.gross', 'ASC'));
$criteria->addFilter(new EqualsFilter('childProduct.id', $productId));
$criteria->addFilter(new EqualsFilter('product.active', true));
/** @var BundleProductCollection $bundleParents */
$bundleParents = $this->bundleProductRepository->search($criteria, $context)->getEntities();
/** @var BundleProductEntity $bundleParent */
foreach ($bundleParents as $bundleParent) {
$bundleParent->setChildBundleProducts($this->getBundleChildren($bundleParent->getProductId(), $salesChannelContext));
}
$products = new ProductCollection([]);
/** @var BundleProductEntity $bundleParent */
foreach ($bundleParents as $bundleParent) {
$products->add($bundleParent->getSalesChannelProduct());
}
$this->calculator->calculate($products, $salesChannelContext);
return $bundleParents;
}
}