<?php
namespace LoyxxRichBreadcrumb\Subscriber;
use Doctrine\DBAL\Connection;
use LoyxxRichBreadcrumb\Struct\Breadcrumb;
use LoyxxRichBreadcrumb\Struct\Data;
use LoyxxRichBreadcrumb\Traits\Microdata;
use Shopware\Core\Content\Seo\SeoUrl\SeoUrlEntity;
use Shopware\Core\Content\Seo\SeoUrlPlaceholderHandlerInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Framework\Routing\RequestTransformer;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class ProductPageLoadedEvent
* @package LoyxxRichBreadcrumb\Subscriber
*/
class ProductPageLoadedEvent implements EventSubscriberInterface
{
use Microdata;
/**
* @var SeoUrlPlaceholderHandlerInterface
*/
private $seoUrlPlaceholderHandler;
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* @var EntityRepositoryInterface
*/
private $seoUrlRepository;
/**
* @var Connection
*/
private $connection;
/**
* ProductPageLoadedEvent constructor.
* @param SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler
* @param SystemConfigService $systemConfigService
* @param EntityRepositoryInterface $seoUrlRepository
* @param Connection $connection
*/
public function __construct(
SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler,
SystemConfigService $systemConfigService,
EntityRepositoryInterface $seoUrlRepository,
Connection $connection
)
{
$this->seoUrlPlaceholderHandler = $seoUrlPlaceholderHandler;
$this->systemConfigService = $systemConfigService;
$this->seoUrlRepository = $seoUrlRepository;
$this->connection = $connection;
}
/**
* @return array|string[]
*/
public static function getSubscribedEvents()
{
return [
\Shopware\Storefront\Page\Product\ProductPageLoadedEvent::class => 'onProductPageLoadedEvent'
];
}
/**
* @param \Shopware\Storefront\Page\Product\ProductPageLoadedEvent $event
*/
public function onProductPageLoadedEvent(\Shopware\Storefront\Page\Product\ProductPageLoadedEvent $event)
{
// create microdata for breadcrumb
$host = $event->getRequest()->attributes->get(RequestTransformer::SALES_CHANNEL_ABSOLUTE_BASE_URL) .
$event->getRequest()->attributes->get(RequestTransformer::SALES_CHANNEL_BASE_URL);
$uri = $event->getRequest()->getRequestUri();
if ( $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.modifyProductDetailBreadcrumb')){
$this->checkAndUpdateSeoBreadcrumbNavigation($event, $host);
}
$navigationTree = $event->getPage()->getHeader()->getNavigation()->getTree();
$product = $event->getPage()->getProduct();
$productBreadcrumb = [];
$this->createBreadcrumbTree($navigationTree, $product, $productBreadcrumb);
/**
* Hide breadcrumb on home page
*
* $breadcrumbIsVisible = $this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME.'.config.isInvisible');
* if ($this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.isHiddenOnHomePage') && $event->getRequest()->attributes->get('_route') === 'frontend.home.page'){
* $breadcrumbIsVisible = false;
* }
* */
$breadcrumbStruct = new Breadcrumb(
$this->createMicrodata(
$event,
$productBreadcrumb,
$host,
$event->getSalesChannelContext(),
$uri
),
$this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.isInvisible'),
$this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.showProductTitle'),
$this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.separator'),
$this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.isVisibleHomeLink'),
$this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.isHiddenOnHomePage'),
$this->systemConfigService->get(PageLoadedEventSubscriber::BUNDLE_NAME . '.config.homeLabel'),
$host,
$uri
);
$event->getPage()->addExtension('breadcrumb', $breadcrumbStruct);
$event->getPage()->getProduct()->addExtension('breadcrumb', $breadcrumbStruct);
}
private function checkAndUpdateSeoBreadcrumbNavigation(\Shopware\Storefront\Page\Product\ProductPageLoadedEvent $event, string $host)
{
$referer = $event->getRequest()->server->get('HTTP_REFERER');
if ($referer && $referer !== $host) {
$referer = str_replace($host, "", $referer);
// remove ? and # from fragment from the URI
$referer = ltrim(substr(substr($referer, 0, strrpos($referer, '?') ?: strlen($referer)), 0, strrpos($referer, '#') ?: strlen($referer)), "/");
if ($referer){
// get the navigation id if it present in the seoUrl page
$criteria = new Criteria();
$criteria->setLimit(1);
$criteria->setTotalCountMode(1);
$criteria->addFilter(new ContainsFilter('seoPathInfo', "$referer"));
/** @var SeoUrlEntity $seoUrl */
$seoUrl = $this->seoUrlRepository->search($criteria, $event->getContext())->first();
if(is_null($seoUrl)){
// the received $lastPart was a uuid
$criteria = new Criteria();
$criteria->setLimit(1);
$criteria->setTotalCountMode(1);
$criteria->addFilter(new ContainsFilter('pathInfo', $referer));
$seoUrl = $this->seoUrlRepository->search($criteria, $event->getContext())->first();
}
if ($seoUrl){
$categoryId = $seoUrl->getForeignKey();
// check existence of the category
$rows = $this->connection->executeQuery("SELECT count(id) as row_count FROM category WHERE hex(id) = ?", [$categoryId]);
$row = $rows->fetch(\PDO::FETCH_ASSOC);
if (isset($row['row_count']) && $row['row_count']){
$event->getPage()->getProduct()->addExtension('seoBreadcrumbActiveCategory', new Data(['id' => $categoryId]));
}
}
}
}
}
/**
* @param array $navigationTree
* @param \Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity $product
* @param $productBreadcrumb
*/
private function createBreadcrumbTree(array $navigationTree, \Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity $product, &$productBreadcrumb)
{
if ($navigationTree) {
$productCategoryTree = $product->getCategoryTree();
if ($productCategoryTree){
$lastProductCategoryTree = end($productCategoryTree);
foreach ($navigationTree as $item) {
if ($item->getCategory()->getId() == $lastProductCategoryTree) {
$breadcrumb = $item->getCategory()->getPlainBreadcrumb($item->getCategory()->getId());
$breadcrumb = array_slice($breadcrumb, 1);
if ($breadcrumb) {
foreach ($breadcrumb as $key => $item) {
$productBreadcrumb[$key] = $item;
}
}
} else if ($item->getChildren()) {
$this->createBreadcrumbTree($item->getChildren(), $product, $productBreadcrumb);
}
}
}
}
}
}