<?php declare(strict_types=1);
namespace Uandi\UandiEfbDownloadCenter\MediaListing;
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\Media\Aggregate\MediaFolder\MediaFolderDefinition;
use Shopware\Core\Content\Media\Aggregate\MediaFolder\MediaFolderEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\HttpFoundation\Request;
class MediaListingElementResolver extends AbstractCmsElementResolver
{
private const FOLDER_PERMISSIONS_CUSTOM_FIELD = 'folderPermissions';
private const FOLDER_KEY_PRICE_LISTS = 'priceLists';
private const FOLDER_KEY_E_CATALOGS = 'eCatalogs';
private const FOLDER_ROOT_CONFIG_KEY_PRICE_LISTS = 'UandiEfbDownloadCenter.config.rootFolderPriceLists';
private const FOLDER_ROOT_CONFIG_KEY_E_CATALOGS = 'UandiEfbDownloadCenter.config.rootFolderECatalogs';
private MediaListingLoader $loader;
private EntityRepositoryInterface $mediaFolderRepository;
private SystemConfigService $systemConfigService;
public function __construct(
EntityRepositoryInterface $mediaFolderRepository,
MediaListingLoader $loader,
SystemConfigService $systemConfigService
) {
$this->mediaFolderRepository = $mediaFolderRepository;
$this->loader = $loader;
$this->systemConfigService = $systemConfigService;
}
public function getType(): string
{
return 'media-listing';
}
public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
{
$config = $slot->getFieldConfig();
if (false === $config->has('mediaFolder')) {
return null;
}
$criteria = new CriteriaCollection();
$criteria->add(
$slot->getUniqueIdentifier(),
MediaFolderDefinition::class,
new Criteria([$config->get('mediaFolder')->getStringValue()])
);
return $criteria;
}
public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
{
$context = $resolverContext->getSalesChannelContext();
$request = $resolverContext->getRequest();
$result = $result->get($slot->getUniqueIdentifier());
if (null === $result) {
return;
}
$mediaFolder = $this->resolveMediaFolder(
$result->first(),
$context
);
$criteria = new Criteria();
$criteria->setTitle('cms::media-listing');
$this->handleSorting($request, $criteria);
$this->handlePagination($request, $criteria, $context);
$searchResult = $this->loader->load($mediaFolder, $criteria, $context);
$searchResult->setSorting($request->get('order'));
$searchResult->addCurrentFilters('navigationId', $this->getNavigationId($request, $context));
$slot->setData($searchResult);
}
private function resolveMediaFolder(
?MediaFolderEntity $mediaFolder,
SalesChannelContext $context
): array {
if (null === $mediaFolder) {
return [];
}
$path[] = $mediaFolder->getId();
if ($mediaFolder->getPath()) {
$path = array_merge($path, array_filter(explode('|', $mediaFolder->getPath())));
}
if (in_array($this->systemConfigService->get(self::FOLDER_ROOT_CONFIG_KEY_E_CATALOGS), $path)) {
$folderKey = self::FOLDER_KEY_E_CATALOGS;
} elseif (in_array($this->systemConfigService->get(self::FOLDER_ROOT_CONFIG_KEY_PRICE_LISTS), $path)) {
$folderKey = self::FOLDER_KEY_PRICE_LISTS;
}
if (false === isset($folderKey)) {
return [$mediaFolder->getId()];
}
$customer = $context->getCustomer();
if (null === $customer) {
return [];
}
try {
$permittedFolders = $customer->getCustomFields()[self::FOLDER_PERMISSIONS_CUSTOM_FIELD][$folderKey];
} catch (\Throwable $e) {
unset($permittedFolders);
}
$permittedFolders[] = $customer->getCustomerNumber();
$parentCriteria = (new Criteria())
->addFilter(new EqualsFilter('parentId', $mediaFolder->getId()))
->addFilter(new EqualsAnyFilter('name', $permittedFolders));
return $this->mediaFolderRepository->searchIds($parentCriteria, $context->getContext())->getIds();
}
private function handleSorting(Request $request, Criteria $criteria): void
{
list($field, $order) = explode('-', $this->getOrder($request));
$order = strtoupper($order) === FieldSorting::DESCENDING ? FieldSorting::DESCENDING : FieldSorting::ASCENDING;
$criteria->addSorting(new FieldSorting($field, $order));
if ('title' === $field) {
$criteria->addSorting(new FieldSorting('fileName', $order));
}
}
private function handlePagination(Request $request, Criteria $criteria, SalesChannelContext $context): void
{
$limit = $this->getLimit($request, $context);
$page = $this->getPage($request);
$criteria->setOffset(($page - 1) * $limit);
$criteria->setLimit($limit);
$criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);
}
private function getOrder(Request $request): string
{
$order = $request->query->get('order');
if ($request->isMethod(Request::METHOD_POST)) {
$order = $request->request->get('order', $order);
}
return $order ?? 'uandiMediaExtension.priority-desc';
}
private function getLimit(Request $request, SalesChannelContext $context): int
{
$limit = $request->query->getInt('limit');
if ($request->isMethod(Request::METHOD_POST)) {
$limit = $request->request->getInt('limit', $limit);
}
$limit = $limit > 0 ? $limit : $this->systemConfigService->getInt('core.listing.productsPerPage', $context->getSalesChannel()->getId());
return $limit <= 0 ? 24 : $limit;
}
private function getPage(Request $request): int
{
$page = $request->query->getInt('p', 1);
if ($request->isMethod(Request::METHOD_POST)) {
$page = $request->request->getInt('p', $page);
}
return $page <= 0 ? 1 : $page;
}
private function getNavigationId(Request $request, SalesChannelContext $context): string
{
if ($navigationId = $request->get('navigationId')) {
return $navigationId;
}
$params = $request->attributes->get('_route_params');
if ($params && isset($params['navigationId'])) {
return $params['navigationId'];
}
return $context->getSalesChannel()->getNavigationCategoryId();
}
}