<?php declare(strict_types=1);
namespace DvdwDirectory\Content\Product\Cms;
use DvdwDirectory\Content\Category\Service\ShopCategoryIdLoaderInterface;
use DvdwDirectory\Content\Product\Struct\FilterByParticipationStruct;
use DvdwDirectory\Content\Product\Struct\FilterByHasPromotionStruct;
use DvdwDirectory\Content\Product\Struct\FilterByPaidStruct;
use DvdwDirectory\Content\Product\Struct\ProductListingLimitStruct;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;
use Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductListingStruct;
use Shopware\Core\Content\Product\SalesChannel\Listing\AbstractProductListingRoute;
use Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingFeaturesSubscriber;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\Request;
class ShopDirectoryCmsElementResolver extends AbstractCmsElementResolver
{
private AbstractProductListingRoute $listingRoute;
private ShopCategoryIdLoaderInterface $categoryIdLoader;
public function __construct(
AbstractProductListingRoute $listingRoute,
ShopCategoryIdLoaderInterface $categoryIdLoader
)
{
$this->listingRoute = $listingRoute;
$this->categoryIdLoader = $categoryIdLoader;
}
public function getType(): string
{
return 'shop-directory';
}
public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
{
return null;
}
public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
{
$data = new ProductListingStruct();
$slot->setData($data);
$request = $resolverContext->getRequest();
$this->restrictFilters($slot, $request);
if ($this->isCustomSorting($slot)) {
$this->restrictSortings($request, $slot);
$this->addDefaultSorting($request, $slot);
}
$context = $resolverContext->getSalesChannelContext();
$category = $this->categoryIdLoader->load($request, $context);
$navigationId = $category['categoryId'];
$requestedSlot = $category['slotConfig'] !== null ? $category['slotConfig'] : $slot;
$this->extendContext($requestedSlot, $context);
$listing = $this->listingRoute
->load($navigationId, $request, $context, new Criteria())
->getResult();
$data->setListing($listing);
}
private function isCustomSorting(CmsSlotEntity $slot): bool
{
$config = $slot->getTranslation('config');
return $config['useCustomSorting']['value'] ?? false;
}
private function addDefaultSorting(Request $request, CmsSlotEntity $slot): void
{
if ($request->get('order')) {
return;
}
$config = $slot->getTranslation('config');
if (isset($config['defaultSorting']['value'])) {
$request->request->set('order', $config['defaultSorting']['value']);
return;
}
// if we have no specific order given at this point, set the order to be the highest priority available sorting
if ($request->get('availableSortings')) {
$availableSortings = $request->get('availableSortings');
arsort($availableSortings, SORT_DESC | SORT_NUMERIC);
$request->request->set('order', array_key_first($availableSortings));
}
}
private function restrictSortings(Request $request, CmsSlotEntity $slot): void
{
$config = $slot->getTranslation('config');
if (!isset($config['availableSortings']['value'])) {
return;
}
$request->request->set('availableSortings', $config['availableSortings']['value']);
}
private function restrictFilters(CmsSlotEntity $slot, Request $request): void
{
// set up the default behavior
$defaults = ['manufacturer-filter', 'rating-filter', 'shipping-free-filter', 'price-filter', 'property-filter'];
$request->request->set(ProductListingFeaturesSubscriber::PROPERTY_GROUP_IDS_REQUEST_PARAM, null);
$config = $slot->get('config');
if (isset($config['propertyWhitelist']['value']) && count($config['propertyWhitelist']['value']) > 0) {
$request->request->set(ProductListingFeaturesSubscriber::PROPERTY_GROUP_IDS_REQUEST_PARAM, $config['propertyWhitelist']['value']);
}
if (!isset($config['filters']['value'])) {
return;
}
// apply config settings
$config = explode(',', $config['filters']['value']);
foreach ($defaults as $filter) {
if (in_array($filter, $config, true)) {
continue;
}
$request->request->set($filter, false);
}
}
private function extendContext(CmsSlotEntity $slot, SalesChannelContext $context): void
{
$config = $slot->get('config');
$filterByParticipation = $config['filterByParticipation']['value'] ?? false;
$filterByHasPromotion = $config['filterByHasPromotion']['value'] ?? false;
$filterByPaid = $config['filterByPaid']['value'] ?? false;
$limit = $config['limit']['value'] ?? 25;
$context->addExtension(
FilterByParticipationStruct::KEY,
new FilterByParticipationStruct($filterByParticipation)
);
$context->addExtension(
FilterByHasPromotionStruct::KEY,
new FilterByHasPromotionStruct($filterByHasPromotion)
);
$context->addExtension(
FilterByPaidStruct::KEY,
new FilterByPaidStruct($filterByPaid)
);
$context->addExtension(
ProductListingLimitStruct::KEY,
new ProductListingLimitStruct($limit)
);
}
}