vendor/shopware/core/Content/Sitemap/Service/SitemapExporter.php line 72

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Sitemap\Service;
  3. use League\Flysystem\FilesystemInterface;
  4. use Psr\Cache\CacheItemPoolInterface;
  5. use Shopware\Core\Content\Sitemap\Event\SitemapGeneratedEvent;
  6. use Shopware\Core\Content\Sitemap\Exception\AlreadyLockedException;
  7. use Shopware\Core\Content\Sitemap\Provider\UrlProviderInterface;
  8. use Shopware\Core\Content\Sitemap\Struct\SitemapGenerationResult;
  9. use Shopware\Core\Content\Sitemap\Struct\Url;
  10. use Shopware\Core\Content\Sitemap\Struct\UrlResult;
  11. use Shopware\Core\Framework\Log\Package;
  12. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelDomain\SalesChannelDomainCollection;
  13. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  14. use Shopware\Core\System\SystemConfig\Exception\InvalidDomainException;
  15. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  16. #[Package('sales-channel')]
  17. class SitemapExporter implements SitemapExporterInterface
  18. {
  19.     /**
  20.      * @deprecated tag:v6.5.0 - The interface will be remove, use AbstractUrlProvider instead
  21.      *
  22.      * @var UrlProviderInterface[]
  23.      */
  24.     private $urlProvider;
  25.     private CacheItemPoolInterface $cache;
  26.     private int $batchSize;
  27.     private FilesystemInterface $filesystem;
  28.     private SitemapHandleFactoryInterface $sitemapHandleFactory;
  29.     private array $sitemapHandles;
  30.     private EventDispatcherInterface $dispatcher;
  31.     /**
  32.      * @internal
  33.      */
  34.     public function __construct(
  35.         iterable $urlProvider,
  36.         CacheItemPoolInterface $cache,
  37.         int $batchSize,
  38.         FilesystemInterface $filesystem,
  39.         SitemapHandleFactoryInterface $sitemapHandleFactory,
  40.         EventDispatcherInterface $dispatcher
  41.     ) {
  42.         $this->urlProvider $urlProvider;
  43.         $this->cache $cache;
  44.         $this->batchSize $batchSize;
  45.         $this->filesystem $filesystem;
  46.         $this->sitemapHandleFactory $sitemapHandleFactory;
  47.         $this->dispatcher $dispatcher;
  48.     }
  49.     /**
  50.      * {@inheritdoc}
  51.      */
  52.     public function generate(SalesChannelContext $contextbool $force false, ?string $lastProvider null, ?int $offset null): SitemapGenerationResult
  53.     {
  54.         $this->lock($context$force);
  55.         try {
  56.             $this->initSitemapHandles($context);
  57.             foreach ($this->urlProvider as $urlProvider) {
  58.                 do {
  59.                     $result $urlProvider->getUrls($context$this->batchSize$offset);
  60.                     $this->processSiteMapHandles($result);
  61.                     $needRun $result->getNextOffset() !== null;
  62.                     $offset $result->getNextOffset();
  63.                 } while ($needRun);
  64.             }
  65.             $this->finishSitemapHandles();
  66.         } finally {
  67.             $this->unlock($context);
  68.         }
  69.         $this->dispatcher->dispatch(new SitemapGeneratedEvent($context));
  70.         return new SitemapGenerationResult(
  71.             true,
  72.             $lastProvider,
  73.             null,
  74.             $context->getSalesChannel()->getId(),
  75.             $context->getLanguageId()
  76.         );
  77.     }
  78.     private function lock(SalesChannelContext $salesChannelContextbool $force): void
  79.     {
  80.         $key $this->generateCacheKeyForSalesChannel($salesChannelContext);
  81.         $item $this->cache->getItem($key);
  82.         if ($item->isHit() && !$force) {
  83.             throw new AlreadyLockedException($salesChannelContext);
  84.         }
  85.         $item->set(true);
  86.         $this->cache->save($item);
  87.     }
  88.     private function unlock(SalesChannelContext $salesChannelContext): void
  89.     {
  90.         $this->cache->deleteItem($this->generateCacheKeyForSalesChannel($salesChannelContext));
  91.     }
  92.     private function generateCacheKeyForSalesChannel(SalesChannelContext $salesChannelContext): string
  93.     {
  94.         return sprintf('sitemap-exporter-running-%s-%s'$salesChannelContext->getSalesChannel()->getId(), $salesChannelContext->getLanguageId());
  95.     }
  96.     private function initSitemapHandles(SalesChannelContext $context): void
  97.     {
  98.         $languageId $context->getLanguageId();
  99.         $domainsEntity $context->getSalesChannel()->getDomains();
  100.         $sitemapDomains = [];
  101.         if ($domainsEntity instanceof SalesChannelDomainCollection) {
  102.             foreach ($domainsEntity as $domain) {
  103.                 if ($domain->getLanguageId() === $languageId) {
  104.                     $urlParts \parse_url($domain->getUrl());
  105.                     if ($urlParts === false) {
  106.                         continue;
  107.                     }
  108.                     $arrayKey = ($urlParts['host'] ?? '') . ($urlParts['path'] ?? '');
  109.                     if (\array_key_exists($arrayKey$sitemapDomains) && $sitemapDomains[$arrayKey]['scheme'] === 'https') {
  110.                         // NEXT-21735 - does not execute on every test run
  111.                         continue;
  112.                     }
  113.                     $sitemapDomains[$arrayKey] = [
  114.                         'url' => $domain->getUrl(),
  115.                         'scheme' => $urlParts['scheme'] ?? '',
  116.                     ];
  117.                 }
  118.             }
  119.         }
  120.         $sitemapHandles = [];
  121.         foreach ($sitemapDomains as $sitemapDomain) {
  122.             $sitemapHandles[$sitemapDomain['url']] = $this->sitemapHandleFactory->create($this->filesystem$context$sitemapDomain['url']);
  123.         }
  124.         if (empty($sitemapHandles)) {
  125.             throw new InvalidDomainException('Empty domain');
  126.         }
  127.         $this->sitemapHandles $sitemapHandles;
  128.     }
  129.     private function processSiteMapHandles(UrlResult $result): void
  130.     {
  131.         /** @var SitemapHandle $sitemapHandle */
  132.         foreach ($this->sitemapHandles as $host => $sitemapHandle) {
  133.             /** @var Url[] $urls */
  134.             $urls = [];
  135.             foreach ($result->getUrls() as $url) {
  136.                 $newUrl = clone $url;
  137.                 $newUrl->setLoc(empty($newUrl->getLoc()) ? $host $host '/' $newUrl->getLoc());
  138.                 $urls[] = $newUrl;
  139.             }
  140.             $sitemapHandle->write($urls);
  141.         }
  142.     }
  143.     private function finishSitemapHandles(): void
  144.     {
  145.         /** @var SitemapHandle $sitemapHandle */
  146.         foreach ($this->sitemapHandles as $index => $sitemapHandle) {
  147.             if ($index === array_key_first($this->sitemapHandles)) {
  148.                 $sitemapHandle->finish();
  149.                 continue;
  150.             }
  151.             $sitemapHandle->finish(false);
  152.         }
  153.     }
  154. }