<?php declare(strict_types=1);
namespace Proc\DisableCategories\Decorator;
use Shopware\Core\Content\Category\CategoryCollection;
use Shopware\Core\Content\Category\CategoryEntity;
use Shopware\Core\Content\Category\SalesChannel\AbstractNavigationRoute;
use Shopware\Core\Content\Category\SalesChannel\NavigationRouteResponse;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\Routing\Annotation\Entity;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route(defaults={"_routeScope"={"store-api"}})
*/
class NavigationRouteDecorator extends AbstractNavigationRoute
{
/**
* @var SalesChannelRepositoryInterface
*/
protected SalesChannelRepositoryInterface $categoryRepository;
private AbstractNavigationRoute $decorated;
private SystemConfigService $systemConfigService;
public function __construct(SalesChannelRepositoryInterface $categoryRepository, AbstractNavigationRoute $navigationRoute, SystemConfigService $systemConfigService)
{
$this->categoryRepository = $categoryRepository;
$this->decorated = $navigationRoute;
$this->systemConfigService = $systemConfigService;
}
public function getDecorated(): AbstractNavigationRoute
{
return $this->decorated;
}
/**
* @Entity("category")
* @Route("/store-api/navigation/{activeId}/{rootId}", name="store-api.navigation", methods={"GET", "POST"})
*/
public function load(string $activeId,
string $rootId,
Request $request,
SalesChannelContext $context,
Criteria $criteria): NavigationRouteResponse
{
$this->decorated->load($activeId, $rootId, $request, $context, $criteria);
$criteria->addAssociation('products');
if (!$context->getCustomer()) {
if ($categoriesIds = $this->systemConfigService->get('ProcDisableCategories.config.categoriesGuestsConfig'))
$criteria->addFilter(new NotFilter(NotFilter::CONNECTION_AND, [new EqualsAnyFilter('category.id', $categoriesIds)]));
if ($productIds = $this->systemConfigService->get('ProcDisableCategories.config.productsGuestsConfig')) {
$criteria->getAssociation('products')->addFilter(new NotFilter(NotFilter::CONNECTION_AND, [new EqualsAnyFilter('product.id', $productIds)]));
}
} elseif (isset($context->getCustomer()->getCustomFields()['custom_product_listing_numbers'])) {
$productArray = explode(',', $context->getCustomer()->getCustomFields()['custom_product_listing_numbers']);
} else {
$productArray = null;
}
$criteria->addAssociation('children');
$criteria->addAssociation('cmsPage');
$context->addState('noLivePrice');
$categories = $this->categoryRepository->search($criteria, $context)->getEntities()->getElements();
$context->removeState('noLivePrice');
if ($this->getEmptyCategoryConfig()) {
$categoriesResponse = new CategoryCollection();
/**
* @var CategoryEntity $category
*/
$depth = $context->getSalesChannel()->getNavigationCategoryDepth();
$hasProducts = $this->getCategoriesHasProducts($categories, $depth)['hasProducts'];
$parentIds = $this->getCategoriesHasProducts($categories, $depth)['parentIds'];
if ($context->getCustomer()) $showCategoryIds = $this->setCategoriesForCustomer($categories, $hasProducts, $productArray);
else $showCategoryIds = (array_unique(array_merge($hasProducts, $parentIds)));
foreach ($categories as $category) {
if (!$this->isCategoryTypePage($category) || $this->isCategoryTypePage($category) && $category->getCmsPage() !== null && $category->getCmsPage()->getType() !== "product_list") {
$categoriesResponse->add($category);
continue;
}
if (in_array($category->getId(), $showCategoryIds)) $categoriesResponse->add($category);
}
} else {
$categoriesResponse = new CategoryCollection($categories);
}
$this->setVisibleChildCountForOffcanvasNavigation($categoriesResponse);
return new NavigationRouteResponse($categoriesResponse);
}
private function getCategoriesHasProducts($categories, $depth): array
{
$hasProducts = null;
$parentIds = null;
for ($lvl = $depth + 1; $lvl >= 2; $lvl--) {
$currentHasProducts = null;
$currentLevel = null;
$currentLevel = $this->getCategoriesByLevel($categories, $lvl);
$currentHasProducts = $this->hasProducts($currentLevel);
if ($currentHasProducts != null) {
$hasProducts = array_merge_recursive($this->getCategoryIds($currentHasProducts), (array)$hasProducts);
$parentIds = array_merge_recursive($this->getCategoryParentId($currentHasProducts), (array)$parentIds);
}
}
return [
'hasProducts' => $hasProducts,
'parentIds' => $parentIds
];
}
private function setCategoriesForCustomer($categories, $hasProducts, $productArray = null): array
{
$hasProductsCategories = $this->getCategoryByIds($categories, $hasProducts);
$customerHasProducts = [];
$parentIds = [];
foreach ($hasProductsCategories as $category) {
$categoryProducts = $category->getProducts()->getElements();
//DH: add filter also for products state....
$categoryProducts= array_filter($categoryProducts, function($v, $k) {
return $v->getActive()== 1;
}, ARRAY_FILTER_USE_BOTH);
if ($productArray != null AND !empty(array_intersect(array_column($categoryProducts, 'productNumber'), $productArray)))
{
$customerHasProducts[] = $category->getId();
$parentIds[] = $category->getParentId();
}
}
return array_unique(array_merge($customerHasProducts, $parentIds));
}
private function getCategoryParentId($categories): array
{
$parentId = [];
foreach ($categories as $category) {
$parentId[] = $category->getParentId();
}
return $parentId;
}
private function getCategoriesByLevel($categories, $lvl): array
{
$categoriesByLevel = [];
foreach ($categories as $category) {
if ($category->getLevel() == $lvl) {
$categoriesByLevel[] = $category;
}
}
return $categoriesByLevel;
}
private function getCategoryIds($categories): array
{
$categoryIds = [];
foreach ($categories as $category) {
$categoryIds[] = $category->getId();
}
return $categoryIds;
}
private function getCategoryByIds($categories, $categoryIds): array
{
$currentCategories = [];
foreach ($categories as $category) {
if (in_array($category->getId(), $categoryIds)) {
$currentCategories[] = $category;
}
}
return $currentCategories;
}
private function hasProducts($categories): array
{
$categoriesHaveProducts = [];
foreach ($categories as $category) {
if ($category->getProducts()->getElements()) $categoriesHaveProducts[] = $category;
}
return $categoriesHaveProducts;
}
private function isCategoryTypePage($category): ?bool
{
if ($category->get('type') == 'page')
return true;
else return null;
}
private function getEmptyCategoryConfig()
{
return $this->systemConfigService->get('ProcDisableCategories.config.emptyCategoriesConfig');
}
private function setVisibleChildCountForOffcanvasNavigation(CategoryCollection $categoriesResponse)
{
foreach ($categoriesResponse->getElements() as $element) {
$childCount = 0;
foreach ($element->getChildren() as $child) {
if ($child->getVisible()) {
$childCount++;
}
}
$element->setVisibleChildCount($childCount);
}
}
}