Reputation: 403
We have four specific products with a massive amount of variants. When running the Product Indexer we run out of memory because of these products. So we want to exclude these specific products from the Product Indexer Job.
My first approach was to use the ProductIndexerEvent
, but the event is dispatched at the end of the handle()
method :
(vendor/shopware/core/Content/Product/DataAbstractionLayer/ProductIndexer.php:187
),
which is probably too late.
What is the best approach to implement that behaviour?
Upvotes: 0
Views: 544
Reputation: 13161
I would advise against excluding products from being indexed. There's business logic relying on the data being indexed.
If you're confident in what you're doing and know about the consequences, you could decorate the ProductIndexer
service.
<service id="Foo\MyPlugin\ProductIndexerDecorator" decorates="Shopware\Core\Content\Product\DataAbstractionLayer\ProductIndexer">
<argument type="service" id="Foo\MyPlugin\ProductIndexerDecorator.inner"/>
</service>
In the decorator you would have to deconstruct the original event, filter the WriteResult
instances by excluded IDs and then pass the reconstructed event to the decorated service.
class ProductIndexerDecorator extends EntityIndexer
{
const FILTERED_IDS = ['9b180c61ddef4dad89e9f3b9fa13f3be'];
private EntityIndexer $decorated;
public function __construct(EntityIndexer $decorated)
{
$this->decorated = $decorated;
}
public function getDecorated(): EntityIndexer
{
return $this->decorated;
}
public function getName(): string
{
return $this->getDecorated()->getName();
}
public function iterate($offset): ?EntityIndexingMessage
{
return $this->getDecorated()->iterate($offset);
}
public function update(EntityWrittenContainerEvent $event): ?EntityIndexingMessage
{
$originalEvents = clone $event->getEvents();
if (!$originalEvents) {
return $this->getDecorated()->update($event);
}
$event->getEvents()->clear();
/** @var EntityWrittenEvent $writtenEvent */
foreach ($originalEvents as $writtenEvent) {
if ($writtenEvent->getEntityName() !== 'product') {
$event->getEvents()->add($writtenEvent);
continue;
}
$results = [];
foreach ($writtenEvent->getWriteResults() as $result) {
if (\in_array($result->getPrimaryKey(), self::FILTERED_IDS, true)) {
continue;
}
$results[] = $result;
}
$event->getEvents()->add(new EntityWrittenEvent('product', $results, $event->getContext()));
}
return $this->getDecorated()->update($event);
}
public function handle(EntityIndexingMessage $message): void
{
$data = array_diff($message->getData(), self::FILTERED_IDS);
$newMessage = new ProductIndexingMessage($data, $message->getOffset(), $message->getContext(), $message->forceQueue());
$this->getDecorated()->handle($newMessage);
}
public function getTotal(): int
{
return $this->getDecorated()->getTotal();
}
public function getOptions(): array
{
return $this->getDecorated()->getOptions();
}
}
Upvotes: 1