Wie kann man die Sales Channel ID auf Produkt-Detailseiten auslesen?

Hallo,

derzeit entwickle ich ein „Also Purchased“ Plugin für die Produkt-Detailseite. Das Plugin funktioniert schon so weit, dass unterhalb einem aufgerufenen Produkt weitere Produkte angezeigt werden, die Kunden zuvor zusammen mit dem Produkt erworben haben.

… so weit so gut.

Nun ist es jedoch leider noch so, dass auch Produkte angezeigt werden, die dem Verkaufskanal nicht zugewiesen sind.
Es muss also noch geprüft werden, ob die „Also Purchased“ Produkte dem Verkaufskanal zugewiesen sind.
Leider bekomme ich es bisher nicht hin, im Subscriber des Plugins eine Abfrage zu implementieren, welche die ID des Sales Channel ermittelt, um diese dann in der SQL-Abfrage, die die auch gekauften Produkte ermittelt, zu verwenden.

Wie löst man das?

Danke

Die meisten (wenn nicht alle) storefront Events liefern auch den sales channel context und da findest du die sales channel id.

Viele Grüße

Angepasster Minimaler Subscriber zum Auslesen der Sales Channel ID:

<?php declare(strict_types=1);

namespace AlsoPurchased\Subscriber;

use Psr\Log\LoggerInterface;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AlsoPurchasedSubscriber implements EventSubscriberInterface
{
    private LoggerInterface $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            StorefrontRenderEvent::class => 'onStorefrontRender',
        ];
    }

    public function onStorefrontRender(StorefrontRenderEvent $event): void
    {
        $salesChannelContext = $event->getSalesChannelContext();
        $salesChannelId = $salesChannelContext->getSalesChannel()->getId();

        $this->logger->info('Sales Channel ID from StorefrontRenderEvent: ' . $salesChannelId);
    }
}

Leider führt das im Frontend zur Meldung ERR_TOO_MANY_REDIRECTS.

Vielleicht über ProductEvents?

ProductEvents::PRODUCT_LOADED_EVENT
<?php declare(strict_types=1);

namespace AlsoPurchased\Subscriber;

use Psr\Log\LoggerInterface;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;

class AlsoPurchasedSubscriber implements EventSubscriberInterface
{
    private LoggerInterface $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

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

    public function onProductLoaded(EntityLoadedEvent $event): void
    {
        $products = $event->getEntities();

        foreach ($products as $product) {
            if ($product instanceof SalesChannelProductEntity) {
                $salesChannelId = $product->getSalesChannelId();

                if ($salesChannelId !== null) {
                    $this->logger->info('Sales Channel ID for product ' . $product->getId() . ': ' . $salesChannelId);
                } else {
                    $this->logger->warning('Sales Channel ID not found for product: ' . $product->getId());
                }
            }
        }
    }
}

Das führt zu einem Redirect auf die Startseite inkl. einer Endlosschleife.

Nicht so kompliziert (foreach), es genügt ein

$event->getSalesChannelContext()->getSalesChannelId()

So?

<?php declare(strict_types=1);

namespace AlsoPurchased\Subscriber;

use Psr\Log\LoggerInterface;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AlsoPurchasedSubscriber implements EventSubscriberInterface
{
    private LoggerInterface $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

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

    public function onProductLoaded(EntityLoadedEvent $event): void
    {
        $salesChannelId = $event->getSalesChannelContext()->getSalesChannelId();

        if ($salesChannelId !== null) {
            $this->logger->info('Sales Channel ID: ' . $salesChannelId);
        } else {
            $this->logger->warning('Sales Channel ID not found.');
        }
    }
}

Der Code führt auch zum gleichen Redirect mit loop.

Merkwürdig, da ist eigentlich nix drin, was einen Loop auslösen könnte. Ich probier das mal so bei mir.

Mit folgender Lösung bin ich nun schon mal ein Stück weiter:

<?php declare(strict_types=1);

namespace AlsoPurchased\Service;

use Shopware\Core\Framework\Context;
use Shopware\Core\System\SalesChannel\Context\SalesChannelContextFactory;
use Shopware\Core\System\SalesChannel\SalesChannelContext;

class SalesChannelContextService
{
    private SalesChannelContextFactory $salesChannelContextFactory;

    public function __construct(SalesChannelContextFactory $salesChannelContextFactory)
    {
        $this->salesChannelContextFactory = $salesChannelContextFactory;
    }

    public function getSalesChannelContext(string $salesChannelId, Context $context): SalesChannelContext
    {
        return $this->salesChannelContextFactory->create('', $salesChannelId, $context);
    }
}

Mit dem Code wird die ID des Verkaufskanals und die ID der Sprache im Log ausgegeben.

Wenn ich das ganze nun mit der Abfrage für die „Also Purchased Products“ im Subscriber kombiniere, führt es dann aber wieder zum Redirect auf die Startseite.

Beide Subscriber Codes funktioniern für sich alleine ohne Probleme.