vendor/presta/sitemap-bundle/src/Service/AbstractGenerator.php line 172

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the PrestaSitemapBundle package.
  4. *
  5. * (c) PrestaConcept <https://prestaconcept.net>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Presta\SitemapBundle\Service;
  11. use Presta\SitemapBundle\Event\SitemapPopulateEvent;
  12. use Presta\SitemapBundle\Sitemap\Sitemapindex;
  13. use Presta\SitemapBundle\Sitemap\Url\Url;
  14. use Presta\SitemapBundle\Sitemap\Url\UrlConcrete;
  15. use Presta\SitemapBundle\Sitemap\Url\UrlDecorator;
  16. use Presta\SitemapBundle\Sitemap\Urlset;
  17. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  18. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  19. /**
  20. * Base class for all sitemap generators.
  21. *
  22. * @phpstan-type Defaults array{
  23. * lastmod: string|null,
  24. * changefreq: string|null,
  25. * priority: float|string|int|null
  26. * }
  27. */
  28. abstract class AbstractGenerator implements UrlContainerInterface
  29. {
  30. /**
  31. * @var EventDispatcherInterface
  32. */
  33. protected $dispatcher;
  34. /**
  35. * @var Sitemapindex|null
  36. */
  37. protected $root;
  38. /**
  39. * @var Urlset[]
  40. */
  41. protected $urlsets = [];
  42. /**
  43. * The maximum number of item generated in a sitemap
  44. * @var int
  45. */
  46. protected $itemsBySet;
  47. /**
  48. * @var UrlGeneratorInterface|null
  49. */
  50. protected $urlGenerator;
  51. /**
  52. * @var Defaults
  53. */
  54. private $defaults;
  55. /**
  56. * @param EventDispatcherInterface $dispatcher
  57. * @param int|null $itemsBySet
  58. * @param UrlGeneratorInterface|null $urlGenerator
  59. */
  60. public function __construct(
  61. EventDispatcherInterface $dispatcher,
  62. int $itemsBySet = null,
  63. UrlGeneratorInterface $urlGenerator = null
  64. ) {
  65. if (!$urlGenerator) {
  66. @trigger_error(
  67. 'Not injecting the $urlGenerator is deprecated and will be required in 4.0.',
  68. \E_USER_DEPRECATED
  69. );
  70. }
  71. $this->dispatcher = $dispatcher;
  72. // We add one to LIMIT_ITEMS because it was used as an index, not a quantity
  73. $this->itemsBySet = ($itemsBySet === null) ? Sitemapindex::LIMIT_ITEMS + 1 : $itemsBySet;
  74. $this->urlGenerator = $urlGenerator;
  75. $this->defaults = [
  76. 'priority' => 1,
  77. 'changefreq' => UrlConcrete::CHANGEFREQ_DAILY,
  78. 'lastmod' => 'now',
  79. ];
  80. }
  81. /**
  82. * @param Defaults $defaults
  83. */
  84. public function setDefaults(array $defaults): void
  85. {
  86. $this->defaults = $defaults;
  87. }
  88. /**
  89. * @inheritdoc
  90. */
  91. public function addUrl(Url $url, string $section): void
  92. {
  93. $urlset = $this->getUrlset($section);
  94. // Compare the number of items in the urlset against the maximum
  95. // allowed and check the maximum of 50k sitemap in sitemapindex
  96. $i = 0;
  97. while ((count($urlset) >= $this->itemsBySet || $urlset->isFull()) && $i <= Sitemapindex::LIMIT_ITEMS) {
  98. $urlset = $this->getUrlset($section . '_' . $i);
  99. $i++;
  100. }
  101. if (count($urlset) >= $this->itemsBySet || $urlset->isFull()) {
  102. throw new \RuntimeException('The limit of sitemapindex has been exceeded');
  103. }
  104. $concreteUrl = $this->getUrlConcrete($url);
  105. if ($concreteUrl instanceof UrlConcrete) {
  106. if (null === $concreteUrl->getLastmod() && null !== $this->defaults['lastmod']) {
  107. $concreteUrl->setLastmod(new \DateTimeImmutable($this->defaults['lastmod']));
  108. }
  109. if (null === $concreteUrl->getChangefreq()) {
  110. $concreteUrl->setChangefreq($this->defaults['changefreq']);
  111. }
  112. if (null === $concreteUrl->getPriority()) {
  113. $concreteUrl->setPriority($this->defaults['priority']);
  114. }
  115. }
  116. $urlset->addUrl($url);
  117. }
  118. /**
  119. * get or create urlset
  120. *
  121. * @param string $name
  122. *
  123. * @return Urlset
  124. */
  125. public function getUrlset(string $name): Urlset
  126. {
  127. if (!isset($this->urlsets[$name])) {
  128. $this->urlsets[$name] = $this->newUrlset($name);
  129. }
  130. return $this->urlsets[$name];
  131. }
  132. /**
  133. * Factory method for create Urlsets
  134. *
  135. * @param string $name
  136. * @param \DateTimeInterface|null $lastmod
  137. *
  138. * @return Urlset
  139. */
  140. abstract protected function newUrlset(string $name, \DateTimeInterface $lastmod = null): Urlset;
  141. /**
  142. * Dispatches SitemapPopulate Event - the listeners should use it to add their URLs to the sitemap
  143. *
  144. * @param string|null $section
  145. */
  146. protected function populate(string $section = null): void
  147. {
  148. $event = new SitemapPopulateEvent($this, $section, $this->urlGenerator);
  149. $this->dispatcher->dispatch($event, SitemapPopulateEvent::ON_SITEMAP_POPULATE);
  150. }
  151. /**
  152. * @return Sitemapindex
  153. */
  154. protected function getRoot(): Sitemapindex
  155. {
  156. if (null === $this->root) {
  157. $this->root = new Sitemapindex();
  158. foreach ($this->urlsets as $urlset) {
  159. $this->root->addSitemap($urlset);
  160. }
  161. }
  162. return $this->root;
  163. }
  164. /**
  165. * @param Url $url
  166. *
  167. * @return Url|null
  168. */
  169. private function getUrlConcrete(Url $url): ?Url
  170. {
  171. if ($url instanceof UrlConcrete) {
  172. return $url;
  173. }
  174. if ($url instanceof UrlDecorator) {
  175. return $this->getUrlConcrete($url->getUrlDecorated());
  176. }
  177. return null;
  178. }
  179. }