Can someone help to set and get a Symfony (Shopware 6) Subscriber class array from a function? Here is my current Subscriber:
<?php declare(strict_types=1);
namespace CustomFilter\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Context;
use Symfony\Component\HttpFoundation\Request;
use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MaxAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\Framework\Struct\ArrayEntity;
class Subscriber implements EventSubscriberInterface
{
private $currentProperty1;
public function __construct(array $currentProperty1)
{
$this->currentProperty1 = $currentProperty1;
}
public static function getSubscribedEvents(): array
{
return [
ProductListingResultEvent::class => 'handleResult',
ProductListingCriteriaEvent::class => 'handleRequest'
];
}
public function handleResult(ProductListingResultEvent $event)
{
$properties = $event->getResult();
$this->currentProperty1 = $properties->getCurrentFilter('properties');
}
public function handleRequest(ProductListingCriteriaEvent $event): void
{
$event->getCriteria()->addAssociation('properties');
$event->getCriteria()->addAssociation('properties.group');
$currentProperty1 = $this->currentProperty1;
if (in_array('c0d02d1738fd4293a489695787e06b5c', $currentProperty1)) {
$friteria = $event->getCriteria();
$friteria->addFilter(new MultiFilter(
MultiFilter::CONNECTION_OR,
[
new ContainsFilter('product.properties.name', 'PropertyNameA'),
new ContainsFilter('product.properties.name', 'PropertyNameB')
]
)
);
}
}
}
I can set and retrieve a private variable via __construct, but I can't set it from the function with $this->:
class Subscriber implements EventSubscriberInterface
{
private $currentProperty1;
public function handleRequest(ProductListingCriteriaEvent $event): void
{
// Here to get
$array1 = array ($this->currentProperty1);
}
public function handleResult(ProductListingResultEvent $event)
{
// Here to set
$this->currentProperty1 = $currentProperty1;
}
}
--
If $currentProperty1 in __construct, the URL no longer responds.
If $currentProperty1 is removed from __construct, the URL will work. Does anyone know the problem?
private $propertyGroupRepository;
private array $currentProperty1;
public function __construct(EntityRepositoryInterface $propertyGroupRepository, array $currentProperty1)
{
$this->propertyGroupRepository = $propertyGroupRepository;
$this->currentProperty1 = $currentProperty1;
}
I tried to do it like this and can't make it work:
class Subscriber implements EventSubscriberInterface {
public function setCurrent()
{
$array1 = array(1 => 'item 1', 2 => 'item 2');
return $array1;
}
private $currentProperty1;
public function __construct()
{
$this->currentProperty1 = new setCurrent();
}
}
I can access it though from another function, if use a value like '[]' instead of 'new setCurrent()'. I use $currentValue = array ($this->currentProperty1); in function for this.
Your input regarding dynamically updated array was very helpful and now my code looks like this. From it I hope you can see, that I aim to alter Criteria depending on Current selected property option.
Though I still can't get the array into onListingCriteria
<?php // declare(strict_types=1);
namespace CustomFilterBasedOnSelectedOption\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Context;
use Symfony\Component\HttpFoundation\Request;
use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MaxAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\Framework\Struct\ArrayEntity;
class Subscriber implements EventSubscriberInterface
{
private ?array $currentPropertyOptions = null;
public static function getSubscribedEvents(): array
{
return [
ProductListingCriteriaEvent::class => 'onListingCriteria',
ProductListingResultEvent::class => 'onListingResult'
];
}
public function onListingResult(ProductListingResultEvent $event)
{
$this->currentPropertyOptions = ['foo', 'bar', 'baz'];
/*
$properties = $event->getResult();
$currentPropertyOptions = $properties->getCurrentFilter('properties');
*/
}
public function onListingCriteria(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')
]
)
);
}
*/
$event->getContext()->addExtension('currentPropertyOptionsCriteria', new ArrayEntity($currentPropertyOptions));
}
}
What are you trying to achieve? Do you know what to use these events for and when they are dispatched? What is currenProperty
? Is it something you get from the event object?
First of all, if you have an argument in the constructor but don't pass it when you instantiate the class, that will cause an error. Services such as event subscribers are instantiated with the arguments defined in the service definition. That's called dependency injection. If you want to set currentProperty
dynamically based on some event, you likely don't want to set it in your constructor.
Refer to the documentation on how to listen to events properly.
You need the service definition first, that's where you define the arguments for instantiating the class. For example if you want to inject a repository:
<service id="Swag\BasicExample\Subscriber\MySubscriber">
<argument type="service" id="property_group_option.repository"/>
<tag name="kernel.event_subscriber"/>
</service>
In your example you didn't implement getSubscribedEvents
in your subscriber. Without it your subscriber does nothing, as it defines which method is called on which event. It should actually cause an error if you fail to implement the method, as it is required by the interface to do so. Not sure if you omitted it by accident or deliberately.
class Subscriber implements EventSubscriberInterface
{
private EntityRepository $repository;
private ?array $currentProperties = null;
public function __construct(EntityRepository $repository)
{
$this->repository = $repository;
}
public static function getSubscribedEvents(): array
{
return [
ProductListingCriteriaEvent::class => 'onListingCriteria',
ProductListingResultEvent::class => 'onListingResult',
];
}
public function onListingCriteria(ProductListingCriteriaEvent $event): void
{
$this->currentProperties = ['foo', 'bar', 'baz'];
}
public function onListingResult(ProductListingResultEvent $event): void
{
$currentProperties = $this->currentProperties;
// ...
}
}
When you set a property listening to one event, and get that property on another event, you also have to mind the order in which these events are dispatched. In your example, you get the property on ProductListingCriteriaEvent
and set it on ProductListingResultEvent
. However, the criteria event should always be dispatched before the result event. That would explain why the property is always uninitialized when you try to retrieve it, as it hasn't been set yet. Familiarize yourself with the existing events and choose them according to your needs.