Search code examples
phpsymfonyeventsshopwareshopware6

Filter ListingCriteria using ListingResult getCurrentFilter('properties') in Shopware 6


How can I make it work so that I can filter the criteria depending on the getCurrentFilter('properties') result?

So that the selected properties can be included in the criteria. Now it doesn't work because of the event sequence.

Can I tell Symfony to reload the page to get it?

Does anyone know of another Event to implement this?

<?php // declare(strict_types=1);

namespace CustomFilterBasedOnSelectedOptions\Subscriber;

class Subscriber implements EventSubscriberInterface
{
    private ?array $currentPropertyOptions = null;

    public static function getSubscribedEvents(): array
    {
        return [
            ProductListingCriteriaEvent::class => 'ListingCriteria',
            ProductListingResultEvent::class => 'ListingResult'
        ];
    }

        public function ListingResult(ProductListingResultEvent $event)
    {
        $properties = $event->getResult();
        $this->currentPropertyOptions = $properties->getCurrentFilter('properties');
    }

    public function ListingCriteria(ProductListingCriteriaEvent $event): void
   {
        $event->getCriteria()->addAssociation('properties');
        $event->getCriteria()->addAssociation('properties.group');

        $currentPropertyOptions = $this->currentPropertyOptions;

        /*
        if (in_array('c0d02d1738fd4293a489695787e06b5c', $currentPropertyOptions)) {
            $criteria = $event->getCriteria();

            $criteria->addFilter(new MultiFilter(
                MultiFilter::CONNECTION_OR,
                    [
                        new ContainsFilter('product.properties.name', 'Option1'),
                        new ContainsFilter('product.properties.name', 'Option2')
                    ]
                )
            );
        }
        */
   }
}

Solution

  • If my assumption of what you're trying to do is correct, you don't need a property to memoize filter values in between two events. When the filters are constructed, they're stored as an extension of Criteria. You just need to subscribe to ProductListingCriteriaEvent with a low enough priority, so the extension will already have been set by the time your listener is called. By setting the priority to -200 it should be low enough.

    Then it's just a matter of checking if the extension with the FilterCollection is set and includes the Filter with the key properties, to extract filter values.

    use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
    use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
    use Shopware\Core\Content\Product\SalesChannel\Listing\FilterCollection;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class Subscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents(): array
        {
            return [
                ProductListingCriteriaEvent::class => [
                    ['onListingCriteria', -200],
                ],
            ];
        }
    
        public function onListingCriteria(ProductListingCriteriaEvent $event): void
        {
            $criteria = $event->getCriteria();
            $filters = $criteria->getExtension('filters');
    
            if (!$filters instanceof FilterCollection) {
                return;
            }
    
            $propertyFilter = $filters->get('properties');
    
            if (!$propertyFilter instanceof Filter || !\is_array($propertyFilter->getValues())) {
                return;
            }
    
            $currentPropertyOptions = $propertyFilter->getValues();
    
            // ...
        }
    }