<?php
declare(strict_types=1);
namespace SchilderSysteme\Subscriber;
use SchilderSysteme\Traits\ThemeTrait;
use Shopware\Core\Content\Category\CategoryCollection;
use Shopware\Core\Content\Category\CategoryEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Storefront\Page\Navigation\NavigationPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ListingSubscriber implements EventSubscriberInterface
{
use ThemeTrait;
private $productRepository;
private $categoryRepository;
private $themeRepository;
public function __construct(
EntityRepositoryInterface $productRepository,
EntityRepositoryInterface $categoryRepository,
EntityRepositoryInterface $themeRepository
)
{
$this->productRepository = $productRepository;
$this->categoryRepository = $categoryRepository;
$this->themeRepository = $themeRepository;
}
public static function getSubscribedEvents(): array
{
return [
NavigationPageLoadedEvent::class => [
['updateProductVariants'],
['addSubcategories'],
['updateActiveCategoryAssociations']
]
];
}
/**
* Add all variants info for displayed products
*
* @param NavigationPageLoadedEvent $event
*/
public function updateProductVariants(NavigationPageLoadedEvent $event)
{
if(!$this->isCorrectTheme($event->getContext(), $event->getSalesChannelContext(), $this->themeRepository)){
return;
}
$slots = $event->getPage()->getCmsPage()->getSections()->getBlocks()->getSlots();
$context = $event->getContext();
foreach($slots as $slot){
if($slot->getType() == 'product-listing'){
$this->updateProducts($slot, $context);
}
}
}
private function updateProducts(CmsSlotEntity $slot, Context $context)
{
$products = $slot->getData()->getListing()->getEntities()->getElements();
foreach($products as $product){
if($product->getParentId()){
$this->addVariants($product, $context);
}
}
}
private function addVariants($product, Context $context)
{
$variants = $this->getVariants($product->getParentId(), $context);
$customFields = $product->getCustomFields();
$customFields['sz_variants'] = $variants;
$product->setCustomFields($customFields);
}
private function getVariants($parentId, Context $context)
{
$parentFilter = new EqualsFilter('parentId', $parentId);
$criteria = (new Criteria())
->addFilter($parentFilter)
->addAssociation('cover');
return $this->productRepository->search($criteria, $context)->getElements();
}
/**
* Add list of subcategories and subcategorie's products for current category page
*
* @param NavigationPageLoadedEvent $event
*/
public function addSubcategories(NavigationPageLoadedEvent $event)
{
if(!$this->isCorrectTheme($event->getContext(), $event->getSalesChannelContext(), $this->themeRepository)){
return;
}
$slots = $event->getPage()->getCmsPage()->getSections()->getBlocks()->getSlots();
$context = $event->getContext();
foreach($slots as $slot){
if($slot->getType() == 'product-listing'){
$this->updateSubcategories($slot, $context);
}
}
}
private function updateSubcategories(CmsSlotEntity $slot, Context $context)
{
$parentNavigationId = $slot->getData()->getListing()->getCurrentFilters()['navigationId'];
$parentCategory = $slot->getFieldConfig()->get('category');
if (isset($parentCategory)) {
$parentNavigationId = $parentCategory->getValue()[0];
}
$subcategories = $this->getSubcategories($parentNavigationId, $context);
$customFields = $slot->getCustomFields();
$customFields['sz_subcategories'] = $subcategories;
$slot->setCustomFields($customFields);
}
private function getSubcategories($parentNavigationId, Context $context)
{
$parentFilter = new EqualsFilter('parentId', $parentNavigationId);
$criteria = (new Criteria())
->addFilter($parentFilter)
->addAssociations(['products', 'products.cover']);
return $this->categoryRepository->search($criteria, $context)->getElements();
}
public function updateActiveCategoryAssociations(NavigationPageLoadedEvent $event)
{
$activeCategory = $event->getPage()->getHeader()->getNavigation()->getActive();
$category = $this->getUpdatedCategory($activeCategory->getId(), $event->getContext());
$event->getPage()->getHeader()->getNavigation()->setActive($category);
}
private function getUpdatedCategory($categoryId, $context)
{
$criteria = (new Criteria([$categoryId]))->addAssociations(['children', 'parent']);
$category = $this->categoryRepository->search($criteria, $context)->first();
if ($category->getChildren()) {
$this->sortCategoryByAutoIncrement($category);
}
if ($category->getParentId()) {
$criteria = (new Criteria([$category->getParentId()]))->addAssociation('children');
$parentCategory = $this->categoryRepository->search($criteria, $context)->first();
if ($parentCategory->getChildren()) {
$this->sortCategoryByAutoIncrement($parentCategory);
}
$category->setParent($parentCategory);
}
return $category;
}
private function sortCategoryByAutoIncrement(CategoryEntity $category)
{
$categoriesChildrensArray = $category->getChildren()->getElements();
usort($categoriesChildrensArray, function($c1, $c2) {
return $c1->getAutoIncrement() - $c2->getAutoIncrement();
});
$category->setChildren(new CategoryCollection($categoriesChildrensArray));
}
}