<?php
namespace CioItpThemeFilters\Subscriber;
use CioItpThemeFilters\CioItpThemeFilters;
use Shopware\Administration\Framework\Routing\AdministrationRouteScope;
use Shopware\Core\Content\Category\CategoryEvents;
use Shopware\Core\Content\Product\Events\ProductListingCollectFilterEvent;
use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\AndFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Shopware\Storefront\Framework\Routing\StorefrontRouteScope;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class CioItpThemeFiltersSubscriber implements EventSubscriberInterface
{
public const NUMBER_FILTERS = [
'itp_product_attributes_dk', 'itp_product_attributes_ml', 'itp_product_attributes_l'
];
// CIO-AI-Driven: boolean listing filters (custom fields)
public const BOOLEAN_FILTERS = [
'itp_product_attributes_compatible_with_cnc',
];
public function onProductListingCollectFilterEvent(ProductListingCollectFilterEvent $event): void
{
foreach (self::NUMBER_FILTERS as $filter) {
$this->newFilterNumber($event, $filter);
}
foreach (self::BOOLEAN_FILTERS as $filter) {
$this->newFilterBoolean($event, $filter);
}
}
private function newFilterNumber(ProductListingCollectFilterEvent $event, $name)
{
$filters = $event->getFilters();
$request = $event->getRequest();
$values = explode('-', $request->get($name));
$valueFrom = floatval($values[0]);
$valueTo = array_key_exists(1, $values) ? floatval($values[1]) : $valueFrom;
$filterFiltered = $valueFrom > 0.01;
$filter = new Filter(
$name,
$filterFiltered,
[],
new AndFilter(
[
new RangeFilter('customFields.' . $name, [RangeFilter::GTE => $valueFrom]),
new RangeFilter('customFields.' . $name, [RangeFilter::LTE => $valueTo]),
]
),
$valueFrom
);
$filters->add($filter);
}
private function newFilterBoolean(ProductListingCollectFilterEvent $event, string $name): void
{
$filters = $event->getFilters();
$request = $event->getRequest();
// checkbox sends e.g. "on" when checked
$isFiltered = (bool) $request->get($name);
$filter = new Filter(
$name,
$isFiltered,
[],
new EqualsFilter('customFields.' . $name, true),
$isFiltered
);
$filters->add($filter);
}
public function onKernelResponse(ResponseEvent $event): void
{
$request = $event->getRequest();
$response = $event->getResponse();
if ($request->getMethod() !== 'GET' || $request->isXmlHttpRequest()) {
return;
}
$scope = $request->attributes->get('_routeScope');
if (!($scope instanceof RouteScope)) {
return;
}
$scopes = $scope->getScopes();
if (empty($scopes) || !in_array(StorefrontRouteScope::ID, $scopes, true)) {
return;
}
$propertyId = $request->cookies->get(CioItpThemeFilters::FILTER_COOKIE_NAME);
if (!$propertyId) {
return;
}
$originalUri = $_SERVER['REQUEST_URI'];
$parsedUrl = parse_url($originalUri);
$path = $parsedUrl['path'] ?? '/';
parse_str($parsedUrl['query'] ?? '', $queryParams);
if (isset($queryParams['properties']) && str_contains($queryParams['properties'], $propertyId)) {
return;
}
if (!isset($queryParams['properties'])) {
$queryParams['properties'] = $propertyId;
} else {
$queryParams['properties'] .= "|$propertyId";
}
$newUrl = $path . '?' . http_build_query($queryParams);
$response->headers->set('Location', $newUrl);
$response->setStatusCode(302);
}
public static function getSubscribedEvents(): array
{
return [
ProductListingCollectFilterEvent::class => 'onProductListingCollectFilterEvent',
KernelEvents::RESPONSE => ['onKernelResponse', -11000]
];
}
}