Is it possible to enable the automatic loading of an association for products?

Viewed 81

I'm looking for a way to automatically load all streams from a product when loading a product (product/category page) but can't seem to find a way to add this. I could add it as an extended attribute, but I would rather make use of the $product->getStreams() function.

I've tried the following but I couldn't figure out how to add an association through this method:

public static function getSubscribedEvents(): array
{
    return [
        ProductEvents::PRODUCT_LOADED_EVENT => 'onLoad'
    ];
}

public function onLoad(EntityLoadedEvent $event): void
{
    $product = $event->getEntities();
}
3 Answers

You could decorate the product.repository and alter the criteria to add the association for streams before calling search of the decorated repository. You can find an example here where the media.repository used to be decorated to alter the search criteria before fetching the data.

Service definition:

<service id="MyPlugin\Core\Content\Product\ProductRepositoryDecorator" decorates="product.repository">
       <argument type="service" id="MyPlugin\Core\Content\Product\ProductRepositoryDecorator.inner"/>
</service>

In the Decorator:

public function search(Criteria $criteria, Context $context): EntitySearchResult
{
    $criteria->addAssociation('streams');

    return $this->decorated->search($criteria, $context);
}

Create your own product repository

    final class SalesChannelProductRepository implements SalesChannelRepositoryInterface
    {
        /**
         * @var SalesChannelRepositoryInterface
         */
        private $repository;
    
        public function __construct(
            SalesChannelRepositoryInterface $repository
        ) {
            $this->repository = $repository;
        }
    
        public function search(Criteria $criteria, SalesChannelContext $salesChannelContext): EntitySearchResult
        {
            $this->processCriteria($criteria);
    
            return $this->repository->search($criteria, $salesChannelContext);
        }
    
        private function processCriteria(Criteria $criteria): void
        {
            $criteria->addAssociation('streams');
        }
    }

define service decorate default product repository

<service id="my_example.sales_channel.product.repository"
                 class="MyExample\Core\Content\Product\SalesChannel\SalesChannelProductRepository"
                 decorates="sales_channel.product.repository"
                 public="false">
            <argument type="service" id="my_example.sales_channel.product.repository.inner"/>           
        </service>

Thanks to the people who reacted tho this question I've gotten to the decorated below. I'm still running into some problems related to using properties as filter in the Dynamic Product group rules. I've created a new thread for that here: Getting streams from product returns zero results with some rules

Decorator class:

class ProductRepositoryDecorator implements SalesChannelRepositoryInterface
{
    private SalesChannelRepositoryInterface $decorated;

    public function __construct(
        SalesChannelRepositoryInterface $decorated
    ) {
        $this->decorated = $decorated;
    }

    public function search(Criteria $criteria, SalesChannelContext $salesChannelContext): EntitySearchResult
    {
        $this->processCriteria($criteria);

        return $this->decorated->search($criteria, $salesChannelContext);
    }

    private function processCriteria(Criteria $criteria): void
    {
        $criteria->addAssociation('streams');
    }

    public function aggregate(Criteria $criteria, SalesChannelContext $salesChannelContext): AggregationResultCollection
    {
        return $this->decorated->aggregate($criteria, $salesChannelContext);
    }

    public function searchIds(Criteria $criteria, SalesChannelContext $salesChannelContext): IdSearchResult
    {
        return $this->decorated->searchIds($criteria, $salesChannelContext);
    }
}

services.xml:

<service id="Vendor\Base\Core\Content\Product\ProductRepositoryDecorator" decorates="sales_channel.product.repository">
        <argument type="service" id="Vendor\Base\Core\Content\Product\ProductRepositoryDecorator.inner"/>
</service>
Related