src/Core/Content/Sitemap/Provider/CategoryUrlProvider.php line 57
<?php declare(strict_types=1);
namespace Shopware\Core\Content\Sitemap\Provider;
use Doctrine\DBAL\Connection;
use Shopware\Core\Content\Category\CategoryDefinition;
use Shopware\Core\Content\Category\CategoryEntity;
use Shopware\Core\Content\Sitemap\Service\ConfigHandler;
use Shopware\Core\Content\Sitemap\Struct\Url;
use Shopware\Core\Content\Sitemap\Struct\UrlResult;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\DataAbstractionLayer\Dbal\Common\IteratorFactory;
use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\FetchModeHelper;
use Shopware\Core\Framework\Log\Package;
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
#[Package('sales-channel')]
class CategoryUrlProvider extends AbstractUrlProvider
{
final public const CHANGE_FREQ = 'daily';
/**
* @internal
*/
public function __construct(private readonly ConfigHandler $configHandler, private readonly Connection $connection, private readonly CategoryDefinition $definition, private readonly IteratorFactory $iteratorFactory, private readonly RouterInterface $router)
{
}
public function getDecorated(): AbstractUrlProvider
{
throw new DecorationPatternException(self::class);
}
public function getName(): string
{
return 'category';
}
/**
* {@inheritdoc}
*
* @throws \Exception
*/
public function getUrls(SalesChannelContext $context, int $limit, ?int $offset = null): UrlResult
{
$categories = $this->getCategories($context, $limit, $offset);
if (empty($categories)) {
return new UrlResult([], null);
}
$keys = FetchModeHelper::keyPair($categories);
$seoUrls = $this->getSeoUrls(array_values($keys), 'frontend.navigation.page', $context, $this->connection);
$seoUrls = FetchModeHelper::groupUnique($seoUrls);
$urls = [];
$url = new Url();
foreach ($categories as $category) {
if (!isset($seoUrls[$category['id']])) {
continue;
}
$lastMod = $category['updated_at'] ?: $category['created_at'];
$lastMod = (new \DateTime($lastMod))->format(Defaults::STORAGE_DATE_TIME_FORMAT);
$newUrl = clone $url;
if (isset($seoUrls[$category['id']])) {
$newUrl->setLoc($seoUrls[$category['id']]['seo_path_info']);
} else {
$newUrl->setLoc($this->router->generate('frontend.navigation.page', ['navigationId' => $category->getId()], UrlGeneratorInterface::ABSOLUTE_PATH));
}
$newUrl->setLastmod(new \DateTime($lastMod));
$newUrl->setChangefreq(self::CHANGE_FREQ);
$newUrl->setResource(CategoryEntity::class);
$newUrl->setIdentifier($category['id']);
$urls[] = $newUrl;
}
$keys = array_keys($keys);
/** @var int|null $nextOffset */
$nextOffset = array_pop($keys);
return new UrlResult($urls, $nextOffset);
}
private function getCategories(SalesChannelContext $context, int $limit, ?int $offset): array
{
$lastId = null;
if ($offset) {
$lastId = ['offset' => $offset];
}
$iterator = $this->iteratorFactory->createIterator($this->definition, $lastId);
$query = $iterator->getQuery();
$query->setMaxResults($limit);
$query->addSelect([
'`category`.created_at',
'`category`.updated_at',
]);
$wheres = [];
$categoryIds = array_filter([
$context->getSalesChannel()->getNavigationCategoryId(),
$context->getSalesChannel()->getFooterCategoryId(),
$context->getSalesChannel()->getServiceCategoryId(),
]);
foreach ($categoryIds as $id) {
$wheres[] = '`category`.path LIKE ' . $query->createNamedParameter('%|' . $id . '|%');
}
$query->andWhere('(' . implode(' OR ', $wheres) . ')');
$query->andWhere('`category`.version_id = :versionId');
$query->andWhere('`category`.active = 1');
$query->andWhere('`category`.type != :linkType');
$excludedCategoryIds = $this->getExcludedCategoryIds($context);
if (!empty($excludedCategoryIds)) {
$query->andWhere('`category`.id NOT IN (:categoryIds)');
$query->setParameter('categoryIds', Uuid::fromHexToBytesList($excludedCategoryIds), Connection::PARAM_STR_ARRAY);
}
$query->setParameter('versionId', Uuid::fromHexToBytes(Defaults::LIVE_VERSION));
$query->setParameter('linkType', CategoryDefinition::TYPE_LINK);
return $query->executeQuery()->fetchAllAssociative();
}
private function getExcludedCategoryIds(SalesChannelContext $salesChannelContext): array
{
$salesChannelId = $salesChannelContext->getSalesChannel()->getId();
$excludedUrls = $this->configHandler->get(ConfigHandler::EXCLUDED_URLS_KEY);
if (empty($excludedUrls)) {
return [];
}
$excludedUrls = array_filter($excludedUrls, static function (array $excludedUrl) use ($salesChannelId) {
if ($excludedUrl['resource'] !== CategoryEntity::class) {
return false;
}
if ($excludedUrl['salesChannelId'] !== $salesChannelId) {
return false;
}
return true;
});
return array_column($excludedUrls, 'identifier');
}
}