Search code examples
phpshopwareshopware6

Get Shopware 6 properties options name in criteria Filter


Can someone give an advice on disabling/ including Shopware 6 properties options in criteria?

I'm able to reach properties names (though filter works a bit not correct in this case, as we need to disable options, not properties) using this filtering:

new PrefixFilter('product.properties.name', 'OptionName1')

But how can I reach options names to disable some of them in this case? Here the Subscriber I have:

namespace CustomFilterBasedOnSelectedOptions\Subscriber;

use ..

class Subscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            ProductListingCriteriaEvent::class => [
                ['onListingCriteria', -200],
            ],
        ];
    }

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

        $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();

        $criteria = $event->getCriteria();

        if (in_array('c0d02d1738fd4293a489695787e06b5c', $currentPropertyOptions)) {

            $criteria->addFilter(
                new NotFilter(
                    NotFilter::CONNECTION_OR,
                    [
                        new PrefixFilter('product.properties.name', 'OptionName1'), //can get, but we need disable some options
                        new PrefixFilter('product.options.name', 'OptionName2') // can't get
                    ]
                )
            );
        }
    }
}

Furthermore we are going to set this selection available for admin backend setting. So I think, this eventually should be done using IDs? Can someone give a tip on where to move on to set this up to be adjustable via the backend? I mean to assign some options of one property to be available only for some selected options of another property.

P.S. No, this doesn't work using standard features like Variants.


Solution

  • First of all, product.options.name should be the correct accessor in this case.

    I think you might have a misconception in your filter. You're using NotFilter::CONNECTION_OR as your operator for your NotFilter. That means either one of the conditions has not to be met. So if product.properties.name doesn't match, it doesn't matter if product.options.name matches or not. I think for your use case you might want to use NotFilter::CONNECTION_AND instead, so both expressions need to not hold true.

    new NotFilter(
        NotFilter::CONNECTION_AND,
        [
            new PrefixFilter('product.properties.name', 'OptionName1'),
            new PrefixFilter('product.options.name', 'OptionName2'),
        ]
    )
    

    To make this configurable via the administration there are various different approaches. You might want to introduce a custom entity, that has a one-to-one association to an option and a many-to-many association to multiple other options to be excluded. Create a custom module in the administration where you manage your custom entities and set the option with their respective excludes. Then in your listing criteria listener, you could fetch your custom entity by the options included in the filter and set the excludes dynamically from the fetched results.