<?php declare(strict_types=1);
namespace TigerMedia\WoodRepair\Subscriber;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\SalesChannel\SalesChannelEntity;
use Shopware\Storefront\Page\GenericPageLoadedEvent;
use Shopware\Storefront\Page\PageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class SalesChannelsSubscriber implements EventSubscriberInterface {
private EntityRepositoryInterface $salesChannelsRepository;
private RequestStack $requestStack;
private EntityRepository $productRepository;
private Context $context;
public function __construct
(
EntityRepositoryInterface $salesChannelsRepository,
RequestStack $requestStack,
EntityRepository $productRepository,
) {
$this->salesChannelsRepository = $salesChannelsRepository;
$this->requestStack = $requestStack;
$this->productRepository = $productRepository;
$this->context = Context::createDefaultContext();
}
public static function getSubscribedEvents(): array
{
return [
GenericPageLoadedEvent::class => 'assignVariables',
];
}
/**
* @param string $route
* @return string
*/
private function getMethodNameFromRoute(string $route): string
{
$output = 'get';
$split = explode('.', $route);
foreach ($split as $item) {
$output .= ucfirst(strtolower($item));
}
return $output;
}
/**
* @param string $productId
* @return ProductEntity|null
*/
private function getProductById(string $productId): ?ProductEntity
{
$criteria = new Criteria();
$criteria
->addAssociation('seoUrls')
->addFilter(new EqualsFilter('id', $productId));
return $this->productRepository->search($criteria, $this->context)->first();
}
/**
* @param string $entityId
* @param string $languageId
* @param string $salesChannelId
* @param string $domain
* @return string
*/
public function getFrontendDetailPage(
string $entityId,
string $languageId,
string $salesChannelId,
string $domain
): string {
$_product = $this->getProductById($entityId);
$productId = $_product?->getId();
/**
* If we don't have the product in this specific sales channel,
* just link to homepage.
*/
if (is_null($productId) || !$_product->getActive()) {
return $domain;
}
$seoUrls = $_product->getSeoUrls();
if (is_null($seoUrls)) {
return $domain . '/details/' . $_product->getId();
}
$seoUrls = $seoUrls->jsonSerialize();
$seo = array_filter($seoUrls, function ($seoUrl) use ($salesChannelId, $languageId) {
return ($seoUrl->getSalesChannelId() == $salesChannelId && $seoUrl->getLanguageId() == $languageId);
});
$seo = end($seo); // getting the latest url.
if (!$seo) {
return $domain;
}
return $domain . '/' . $seo->getSeoPathInfo();
}
/**
* @param string|null $domain
* @return string
*/
private function getFrontendNavigationPage(?string $domain = null): string /** @phpstan-ignore-line */
{
return ($domain ?? '/');
}
/**
* @param string|null $domain
* @return string
*/
public function getFrontendHomePage(?string $domain = null): string
{
return ($domain ?? '/');
}
/**
* @param array $params
* @return array
*/
public function getParams(array $params = []): array /** @phpstan-ignore-line */
{
$output = [];
$route = $this->requestStack->getCurrentRequest()->attributes->get('_route');
switch ($route) {
case 'frontend.detail.page':
$output['entityId'] = $this->requestStack->getCurrentRequest()->get('productId');
break;
case 'frontend.navigation.page':
case 'frontend.home.page':
unset($params['languageId']);
unset($params['salesChannelId']);
break;
}
return array_merge($output, $params);
}
/**
* @return array
*/
private function getSalesChannelsPageLinks(): array /** @phpstan-ignore-line */
{
$output = [];
$currentRoute = $this->requestStack->getCurrentRequest()->attributes->get('_route');
$method = $this->getMethodNameFromRoute($currentRoute);
/** @var SalesChannelEntity $salesChannel */
foreach ($this->getSalesChannels() as $salesChannelId => $salesChannel) {
$url = $salesChannel->getDomains()?->first()?->getUrl();
if ($url === null || str_contains($url, 'headless')) {
continue;
}
$domain = $salesChannel->getDomains()->first();
if (is_null($domain)) {
continue;
}
$language = $salesChannel->getLanguage();
$languageId = $domain->getLanguageId();
$languageName = $language->getName();
$locale = $language->getLocale()->getCode();
$locale = strtolower(explode('-', $locale)[1]);
$locale = str_replace('gb', 'en', $locale);
$params = $this->getParams([
'languageId' => $languageId,
'salesChannelId' => $salesChannelId,
'domain' => $domain->getUrl(),
]);
if (method_exists($this, $method)) {
$link = call_user_func_array([$this, $method], $params);
if ($link) {
$output[$languageId] = [
'link' => $link,
'languageName' => $languageName,
'locale' => $locale
];
}
}
}
return $output;
}
/**
* @return EntitySearchResult
*/
private function getSalesChannels(): EntitySearchResult
{
$criteria = new Criteria();
$criteria->addAssociations(['domains', 'language', 'language.locale']);
return $this->salesChannelsRepository->search($criteria, Context::createDefaultContext());
}
public function assignVariables(PageLoadedEvent $event): void
{
$event->getPage()->assign([
'salesChannels' => $this->getSalesChannelsPageLinks(),
'contextTest' => Context::createDefaultContext(),
]);
}
}