<?php
declare(strict_types=1);
namespace TT\PropertyCategory\Subscriber;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductListingCollectFilterEvent;
use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MaxAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\StatsAggregation;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Content\Category\CategoryEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Symfony\Component\HttpFoundation\Request;
class FrontendListingSubscriber implements EventSubscriberInterface
{
protected EntityRepositoryInterface $categoryRepository;
protected EntityRepositoryInterface $propertyGroupRepository;
protected EntityRepositoryInterface $customFieldRepository;
public function __construct(
EntityRepositoryInterface $categoryRepository,
EntityRepositoryInterface $propertyGroupRepository,
EntityRepositoryInterface $customFieldRepository
) {
$this->categoryRepository = $categoryRepository;
$this->propertyGroupRepository = $propertyGroupRepository;
$this->customFieldRepository = $customFieldRepository;
}
public static function getSubscribedEvents()
{
return [
ProductListingCriteriaEvent::class => 'handleListingRequest',
ProductSearchCriteriaEvent::class => 'handleListingRequest',
CategoryEvents::CATEGORY_WRITTEN_EVENT => 'checkPropertiesLimitValid',
ProductListingCollectFilterEvent::class => 'handleAddFilter'
];
}
public function handleListingRequest(ProductListingCriteriaEvent $event): void
{
$event->getCriteria()->addAssociation('properties.group');
}
public function checkPropertiesLimitValid(EntityWrittenEvent $event): void
{
$catId = null;
foreach ($event->getWriteResults() as $result) {
$catId = $result->getPrimaryKey();
}
if (!empty($catId)) {
$categoryCriteria = new Criteria([$catId]);
$category = $this->categoryRepository->search($categoryCriteria, $event->getContext())->first();
if ($category) {
$customFields = $category->getCustomFields();
if (isset($customFields['tt_category_property_limitation'])) {
$propertiesIds = explode('|', $customFields['tt_category_property_limitation']);
$propertiesIds = array_filter($propertiesIds);
if (!empty($propertiesIds)) {
$propertiesFilterIds = $this->propertyGroupRepository->searchIds(new Criteria($propertiesIds), $event->getContext())->getIds();
//Update list property limit when list id property difference list id in custom_field
if ($propertiesIds != $propertiesFilterIds) {
$saveData = [
'tt_category_property_limitation' => implode('|', $propertiesFilterIds)
];
$this->categoryRepository->update([
[
'id' => $catId,
'customFields' => $saveData
]
], $event->getContext());
}
}
}
if (isset($customFields['tt_category_custom_field_limitation'])) {
$customFieldIds = explode('|', $customFields['tt_category_custom_field_limitation']);
$customFieldIds = array_filter($customFieldIds);
if (!empty($customFieldIds)) {
$customFieldFilterIds = $this->customFieldRepository->searchIds(new Criteria($customFieldIds), $event->getContext())->getIds();
if ($customFieldFilterIds != $customFieldIds) {
$saveData = [
'tt_category_property_limitation' => implode('|', $customFieldFilterIds)
];
$this->categoryRepository->update([
[
'id' => $catId,
'customFields' => $saveData
]
], $event->getContext());
}
}
}
}
}
}
public function handleAddFilter(ProductListingCollectFilterEvent $event): void
{
// fetch existing filters
$filters = $event->getFilters();
$request = $event->getRequest();
$filterName = 'masse-lxbxh';
$filters->add($this->getFilter($filterName, $request));
if (!$request->request->get($filterName, true)) {
$filters->remove($filterName);
}
}
private function getFilter(string $name, Request $request): Filter
{
$queryString = $request->get($name);
$length = [];
$width = [];
$height = [];
if (!empty($queryString)) {
if (strpos($queryString, "|") !== false) {
$listMasse = explode('|', $queryString);
} else {
$listMasse = explode(',', $queryString);
}
foreach ($listMasse as $masse) {
$masse = str_replace(['-', 'mm', ' '], '', $masse);
$arr = explode('x', $masse);
$length[] = $arr[0];
$width[] = $arr[1];
$height[] = $arr[2];
}
}
$filter = [];
if(!empty($length)) {
$filter[] = new EqualsAnyFilter('product.length', $length);
}
if(!empty($width)) {
$filter[] = new EqualsAnyFilter('product.width', $width);
}
if(!empty($height)) {
$filter[] = new EqualsAnyFilter('product.height', $height);
}
return new Filter(
$name,
!empty($queryString),
[],
new MultiFilter(
MultiFilter::CONNECTION_AND,
$filter
),
$queryString
);
}
}