3 namespace Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator;
5 use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGeneratorPluginBase;
6 use Symfony\Component\DependencyInjection\ContainerInterface;
7 use Drupal\Component\Utility\Html;
8 use Drupal\Core\Entity\ContentEntityBase;
10 use Drupal\simple_sitemap\EntityHelper;
11 use Drupal\simple_sitemap\Logger;
12 use Drupal\simple_sitemap\Simplesitemap;
13 use Drupal\simple_sitemap\SitemapGenerator;
14 use Drupal\Core\Language\LanguageManagerInterface;
15 use Drupal\Core\Entity\EntityTypeManagerInterface;
16 use Drupal\Core\Language\Language;
19 * Class UrlGeneratorBase
20 * @package Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator
22 abstract class UrlGeneratorBase extends UrlGeneratorPluginBase implements UrlGeneratorInterface {
24 const ANONYMOUS_USER_ID = 0;
25 const PROCESSING_PATH_MESSAGE = 'Processing path #@current out of @max: @path';
28 * @var \Drupal\simple_sitemap\Simplesitemap
33 * @var \Drupal\simple_sitemap\SitemapGenerator
35 protected $sitemapGenerator;
38 * @var \Drupal\Core\Language\LanguageManagerInterface
40 protected $languageManager;
43 * @var \Drupal\Core\Language\LanguageInterface[]
50 protected $defaultLanguageId;
53 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
55 protected $entityTypeManager;
58 * @var \Drupal\simple_sitemap\Logger
63 * @var \Drupal\Core\Entity\EntityInterface|null
75 protected $batchSettings;
78 * @var \Drupal\simple_sitemap\EntityHelper
80 protected $entityHelper;
83 * UrlGeneratorBase constructor.
84 * @param array $configuration
85 * @param string $plugin_id
86 * @param mixed $plugin_definition
87 * @param \Drupal\simple_sitemap\Simplesitemap $generator
88 * @param \Drupal\simple_sitemap\SitemapGenerator $sitemap_generator
89 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
90 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
91 * @param \Drupal\simple_sitemap\Logger $logger
92 * @param \Drupal\simple_sitemap\EntityHelper $entityHelper
94 public function __construct(
98 Simplesitemap $generator,
99 SitemapGenerator $sitemap_generator,
100 LanguageManagerInterface $language_manager,
101 EntityTypeManagerInterface $entity_type_manager,
103 EntityHelper $entityHelper
105 parent::__construct($configuration, $plugin_id, $plugin_definition);
106 $this->generator = $generator;
107 $this->sitemapGenerator = $sitemap_generator;
108 $this->languageManager = $language_manager;
109 $this->languages = $language_manager->getLanguages();
110 $this->defaultLanguageId = $language_manager->getDefaultLanguage()->getId();
111 $this->entityTypeManager = $entity_type_manager;
112 $this->logger = $logger;
113 $this->entityHelper = $entityHelper;
114 $this->anonUser = $this->entityTypeManager->getStorage('user')
115 ->load(self::ANONYMOUS_USER_ID);
118 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
123 $container->get('simple_sitemap.generator'),
124 $container->get('simple_sitemap.sitemap_generator'),
125 $container->get('language_manager'),
126 $container->get('entity_type.manager'),
127 $container->get('simple_sitemap.logger'),
128 $container->get('simple_sitemap.entity_helper')
136 public function setContext(&$context) {
137 $this->context = &$context;
142 * @param array $batch_settings
145 public function setBatchSettings(array $batch_settings) {
146 $this->batchSettings = $batch_settings;
153 protected function isBatch() {
154 return $this->batchSettings['from'] !== 'nobatch';
157 protected function getProcessedElements() {
158 return !empty($this->context['results']['processed_paths'])
159 ? $this->context['results']['processed_paths']
163 protected function addProcessedElement($path) {
164 $this->context['results']['processed_paths'][] = $path;
167 protected function setProcessedElements($elements) {
168 $this->context['results']['processed_elements'] = $elements;
171 protected function getBatchResults() {
172 return !empty($this->context['results']['generate'])
173 ? $this->context['results']['generate']
177 protected function addBatchResult($result) {
178 $this->context['results']['generate'][] = $result;
181 protected function setBatchResults($results) {
182 $this->context['results']['generate'] = $results;
185 protected function getChunkCount() {
186 return !empty($this->context['results']['chunk_count'])
187 ? $this->context['results']['chunk_count']
191 protected function setChunkCount($chunk_count) {
192 $this->context['results']['chunk_count'] = $chunk_count;
196 * @param string $path
199 protected function pathProcessed($path) {
200 if (in_array($path, $this->getProcessedElements())) {
203 $this->addProcessedElement($path);
208 * @param array $path_data
210 protected function addUrl(array $path_data) {
211 if ($path_data['url'] instanceof Url) {
212 $url_object = $path_data['url'];
213 unset($path_data['url']);
214 $this->addUrlVariants($path_data, $url_object);
217 $this->addBatchResult($path_data);
222 * @param Url $url_object
223 * @param array $path_data
225 protected function addUrlVariants(array $path_data, Url $url_object) {
227 if (!$url_object->isRouted()) {
228 // Not a routed URL, including only default variant.
229 $alternate_urls = $this->getAlternateUrlsForDefaultLanguage($url_object);
231 elseif ($this->batchSettings['skip_untranslated']
232 && ($entity = $this->entityHelper->getEntityFromUrlObject($url_object)) instanceof ContentEntityBase) {
233 $translation_languages = $entity->getTranslationLanguages();
234 if (isset($translation_languages[Language::LANGCODE_NOT_SPECIFIED])
235 || isset($translation_languages[Language::LANGCODE_NOT_APPLICABLE])) {
236 // Content entity's language is unknown, including only default variant.
237 $alternate_urls = $this->getAlternateUrlsForDefaultLanguage($url_object);
240 // Including only translated variants of content entity.
241 $alternate_urls = $this->getAlternateUrlsForTranslatedLanguages($entity, $url_object);
245 // Not a content entity or including all untranslated variants.
246 $alternate_urls = $this->getAlternateUrlsForAllLanguages($url_object);
249 foreach ($alternate_urls as $langcode => $url) {
250 $this->addBatchResult(
252 'langcode' => $langcode, 'url' => $url, 'alternate_urls' => $alternate_urls
258 protected function getAlternateUrlsForDefaultLanguage($url_object) {
259 $alternate_urls = [];
260 if ($url_object->access($this->anonUser)) {
261 $url_object->setOption('language', $this->languages[$this->defaultLanguageId]);
262 $alternate_urls[$this->defaultLanguageId] = $this->replaceBaseUrlWithCustom($url_object->toString());
264 return $alternate_urls;
267 protected function getAlternateUrlsForTranslatedLanguages($entity, $url_object) {
268 $alternate_urls = [];
269 foreach ($entity->getTranslationLanguages() as $language) {
270 if (!isset($this->batchSettings['excluded_languages'][$language->getId()]) || $language->isDefault()) {
271 $translation = $entity->getTranslation($language->getId());
272 if ($translation->access('view', $this->anonUser)) {
273 $url_object->setOption('language', $language);
274 $alternate_urls[$language->getId()] = $this->replaceBaseUrlWithCustom($url_object->toString());
278 return $alternate_urls;
281 protected function getAlternateUrlsForAllLanguages($url_object) {
282 $alternate_urls = [];
283 if ($url_object->access($this->anonUser)) {
284 foreach ($this->languages as $language) {
285 if (!isset($this->batchSettings['excluded_languages'][$language->getId()]) || $language->isDefault()) {
286 $url_object->setOption('language', $language);
287 $alternate_urls[$language->getId()] = $this->replaceBaseUrlWithCustom($url_object->toString());
291 return $alternate_urls;
297 protected function needsInitialization() {
298 return empty($this->context['sandbox']);
304 protected function initializeBatch($max) {
305 $this->setBatchResults($this->getBatchResults());
306 $this->setChunkCount($this->getChunkCount());
307 $this->setProcessedElements($this->getProcessedElements());
309 // Initialize sandbox for the batch process.
310 if ($this->isBatch()) {
311 $this->context['sandbox']['progress'] = 0;
312 $this->context['sandbox']['current_id'] = 0;
313 $this->context['sandbox']['max'] = $max;
314 $this->context['sandbox']['finished'] = 0;
321 protected function setCurrentId($id) {
322 if ($this->isBatch()) {
323 $this->context['sandbox']['progress']++;
324 $this->context['sandbox']['current_id'] = $id;
331 protected function processSegment() {
332 if ($this->isBatch()) {
333 $this->setProgressInfo();
336 if (!empty($max_links = $this->batchSettings['max_links'])
337 && count($this->getBatchResults()) >= $max_links) {
339 foreach (array_chunk($this->getBatchResults(), $max_links) as $chunk_links) {
341 if (count($chunk_links) == $max_links) {
344 $this->sitemapGenerator
345 ->setSettings(['excluded_languages' => $this->batchSettings['excluded_languages']])
346 ->generateSitemap($chunk_links, empty($this->getChunkCount()));
348 // Update chunk count info.
349 $this->setChunkCount(empty($this->getChunkCount()) ? 1 : ($this->getChunkCount() + 1));
351 // Remove links from result array that have been generated.
352 $this->setBatchResults(array_slice($this->getBatchResults(), count($chunk_links)));
358 protected function setProgressInfo() {
359 if ($this->context['sandbox']['progress'] != $this->context['sandbox']['max']) {
361 // Provide progress info to the batch API.
362 $this->context['finished'] = $this->context['sandbox']['progress'] / $this->context['sandbox']['max'];
364 // Add processing message after finishing every batch segment.
365 $this->setProcessingBatchMessage();
369 protected function setProcessingBatchMessage() {
370 $results = $this->getBatchResults();
372 if (!empty($path = $results[key($results)]['meta']['path'])) {
373 $this->context['message'] = $this->t(self::PROCESSING_PATH_MESSAGE, [
374 '@current' => $this->context['sandbox']['progress'],
375 '@max' => $this->context['sandbox']['max'],
376 '@path' => HTML::escape($path),
385 protected function replaceBaseUrlWithCustom($url) {
386 return !empty($this->batchSettings['base_url'])
387 ? str_replace($GLOBALS['base_url'], $this->batchSettings['base_url'], $url)
392 * @param mixed $elements
395 protected function getBatchIterationElements($elements) {
396 if ($this->needsInitialization()) {
397 $this->initializeBatch(count($elements));
400 return $this->isBatch()
401 ? array_slice($elements, $this->context['sandbox']['progress'], $this->batchSettings['batch_process_limit'])
408 abstract public function getDataSets();
414 abstract protected function processDataSet($data_set);
419 * @param array|null $data_sets
421 public function generate($data_sets = NULL) {
422 $data_sets = NULL !== $data_sets ? $data_sets : $this->getDataSets();
423 foreach ($this->getBatchIterationElements($data_sets) as $id => $data_set) {
424 $this->setCurrentId($id);
425 $path_data = $this->processDataSet($data_set);
429 $this->addUrl($path_data);
431 $this->processSegment();
435 * @param $entity_type_name
439 protected function getImages($entity_type_name, $entity_id) {
441 foreach ($this->entityHelper->getEntityImageUrls($entity_type_name, $entity_id) as $url) {
442 $images[]['path'] = $this->replaceBaseUrlWithCustom($url);