ffb376326f670ab7474fafcaf06e1708151d2582
[yaffs-website] / web / modules / contrib / simple_sitemap / src / Plugin / simple_sitemap / UrlGenerator / UrlGeneratorBase.php
1 <?php
2
3 namespace Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator;
4
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;
9 use Drupal\Core\Url;
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;
17
18 /**
19  * Class UrlGeneratorBase
20  * @package Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator
21  */
22 abstract class UrlGeneratorBase extends UrlGeneratorPluginBase implements UrlGeneratorInterface {
23
24   const ANONYMOUS_USER_ID = 0;
25   const PROCESSING_PATH_MESSAGE = 'Processing path #@current out of @max: @path';
26
27   /**
28    * @var \Drupal\simple_sitemap\Simplesitemap
29    */
30   protected $generator;
31
32   /**
33    * @var \Drupal\simple_sitemap\SitemapGenerator
34    */
35   protected $sitemapGenerator;
36
37   /**
38    * @var \Drupal\Core\Language\LanguageManagerInterface
39    */
40   protected $languageManager;
41
42   /**
43    * @var \Drupal\Core\Language\LanguageInterface[]
44    */
45   protected $languages;
46
47   /**
48    * @var string
49    */
50   protected $defaultLanguageId;
51
52   /**
53    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
54    */
55   protected $entityTypeManager;
56
57   /**
58    * @var \Drupal\simple_sitemap\Logger
59    */
60   protected $logger;
61
62   /**
63    * @var \Drupal\Core\Entity\EntityInterface|null
64    */
65   protected $anonUser;
66
67   /**
68    * @var array
69    */
70   protected $context;
71
72   /**
73    * @var array
74    */
75   protected $batchSettings;
76
77   /**
78    * @var \Drupal\simple_sitemap\EntityHelper
79    */
80   protected $entityHelper;
81
82   /**
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
93    */
94   public function __construct(
95     array $configuration,
96     $plugin_id,
97     $plugin_definition,
98     Simplesitemap $generator,
99     SitemapGenerator $sitemap_generator,
100     LanguageManagerInterface $language_manager,
101     EntityTypeManagerInterface $entity_type_manager,
102     Logger $logger,
103     EntityHelper $entityHelper
104   ) {
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);
116   }
117
118   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
119     return new static(
120       $configuration,
121       $plugin_id,
122       $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')
129     );
130   }
131
132   /**
133    * @param $context
134    * @return $this
135    */
136   public function setContext(&$context) {
137     $this->context = &$context;
138     return $this;
139   }
140
141   /**
142    * @param array $batch_settings
143    * @return $this
144    */
145   public function setBatchSettings(array $batch_settings) {
146     $this->batchSettings = $batch_settings;
147     return $this;
148   }
149
150   /**
151    * @return bool
152    */
153   protected function isBatch() {
154     return $this->batchSettings['from'] !== 'nobatch';
155   }
156
157   protected function getProcessedElements() {
158     return !empty($this->context['results']['processed_paths'])
159       ? $this->context['results']['processed_paths']
160       : [];
161   }
162
163   protected function addProcessedElement($path) {
164     $this->context['results']['processed_paths'][] = $path;
165   }
166
167   protected function setProcessedElements($elements) {
168     $this->context['results']['processed_elements'] = $elements;
169   }
170
171   protected function getBatchResults() {
172     return !empty($this->context['results']['generate'])
173       ? $this->context['results']['generate']
174       : [];
175   }
176
177   protected function addBatchResult($result) {
178     $this->context['results']['generate'][] = $result;
179   }
180
181   protected function setBatchResults($results) {
182     $this->context['results']['generate'] = $results;
183   }
184
185   protected function getChunkCount() {
186     return !empty($this->context['results']['chunk_count'])
187       ? $this->context['results']['chunk_count']
188       : 0;
189   }
190
191   protected function setChunkCount($chunk_count) {
192     $this->context['results']['chunk_count'] = $chunk_count;
193   }
194
195   /**
196    * @param string $path
197    * @return bool
198    */
199   protected function pathProcessed($path) {
200     if (in_array($path, $this->getProcessedElements())) {
201       return TRUE;
202     }
203     $this->addProcessedElement($path);
204     return FALSE;
205   }
206
207   /**
208    * @param array $path_data
209    */
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);
215     }
216     else {
217       $this->addBatchResult($path_data);
218     }
219   }
220
221   /**
222    * @param Url $url_object
223    * @param array $path_data
224    */
225   protected function addUrlVariants(array $path_data, Url $url_object) {
226
227     if (!$url_object->isRouted()) {
228       // Not a routed URL, including only default variant.
229       $alternate_urls = $this->getAlternateUrlsForDefaultLanguage($url_object);
230     }
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);
238       }
239       else {
240         // Including only translated variants of content entity.
241         $alternate_urls = $this->getAlternateUrlsForTranslatedLanguages($entity, $url_object);
242       }
243     }
244     else {
245       // Not a content entity or including all untranslated variants.
246       $alternate_urls = $this->getAlternateUrlsForAllLanguages($url_object);
247     }
248
249     foreach ($alternate_urls as $langcode => $url) {
250       $this->addBatchResult(
251         $path_data + [
252           'langcode' => $langcode, 'url' => $url, 'alternate_urls' => $alternate_urls
253         ]
254       );
255     }
256   }
257
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());
263     }
264     return $alternate_urls;
265   }
266
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());
275         }
276       }
277     }
278     return $alternate_urls;
279   }
280
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());
288         }
289       }
290     }
291     return $alternate_urls;
292   }
293
294   /**
295    * @return bool
296    */
297   protected function needsInitialization() {
298     return empty($this->context['sandbox']);
299   }
300
301   /**
302    * @param $max
303    */
304   protected function initializeBatch($max) {
305     $this->setBatchResults($this->getBatchResults());
306     $this->setChunkCount($this->getChunkCount());
307     $this->setProcessedElements($this->getProcessedElements());
308
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;
315     }
316   }
317
318   /**
319    * @param $id
320    */
321   protected function setCurrentId($id) {
322     if ($this->isBatch()) {
323       $this->context['sandbox']['progress']++;
324       $this->context['sandbox']['current_id'] = $id;
325     }
326   }
327
328   /**
329    *
330    */
331   protected function processSegment() {
332     if ($this->isBatch()) {
333       $this->setProgressInfo();
334     }
335
336     if (!empty($max_links = $this->batchSettings['max_links'])
337       && count($this->getBatchResults()) >= $max_links) {
338
339       foreach (array_chunk($this->getBatchResults(), $max_links) as $chunk_links) {
340
341         if (count($chunk_links) == $max_links) {
342
343           // Generate sitemap.
344           $this->sitemapGenerator
345             ->setSettings(['excluded_languages' => $this->batchSettings['excluded_languages']])
346             ->generateSitemap($chunk_links, empty($this->getChunkCount()));
347
348           // Update chunk count info.
349           $this->setChunkCount(empty($this->getChunkCount()) ? 1 : ($this->getChunkCount() + 1));
350
351           // Remove links from result array that have been generated.
352           $this->setBatchResults(array_slice($this->getBatchResults(), count($chunk_links)));
353         }
354       }
355     }
356   }
357
358   protected function setProgressInfo() {
359     if ($this->context['sandbox']['progress'] != $this->context['sandbox']['max']) {
360
361       // Provide progress info to the batch API.
362       $this->context['finished'] = $this->context['sandbox']['progress'] / $this->context['sandbox']['max'];
363
364       // Add processing message after finishing every batch segment.
365       $this->setProcessingBatchMessage();
366     }
367   }
368
369   protected function setProcessingBatchMessage() {
370     $results = $this->getBatchResults();
371     end($results);
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),
377       ]);
378     }
379   }
380
381   /**
382    * @param string $url
383    * @return string
384    */
385   protected function replaceBaseUrlWithCustom($url) {
386     return !empty($this->batchSettings['base_url'])
387       ? str_replace($GLOBALS['base_url'], $this->batchSettings['base_url'], $url)
388       : $url;
389   }
390
391   /**
392    * @param mixed $elements
393    * @return array
394    */
395   protected function getBatchIterationElements($elements) {
396     if ($this->needsInitialization()) {
397       $this->initializeBatch(count($elements));
398     }
399
400     return $this->isBatch()
401       ? array_slice($elements, $this->context['sandbox']['progress'], $this->batchSettings['batch_process_limit'])
402       : $elements;
403   }
404
405   /**
406    * @return array
407    */
408   abstract public function getDataSets();
409
410   /**
411    * @param $data_set
412    * @return array
413    */
414   abstract protected function processDataSet($data_set);
415
416   /**
417    * Called by batch.
418    *
419    * @param array|null $data_sets
420    */
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);
426       if (!$path_data) {
427         continue;
428       }
429       $this->addUrl($path_data);
430     }
431     $this->processSegment();
432   }
433
434   /**
435    * @param $entity_type_name
436    * @param $entity_id
437    * @return array
438    */
439   protected function getImages($entity_type_name, $entity_id) {
440     $images = [];
441     foreach ($this->entityHelper->getEntityImageUrls($entity_type_name, $entity_id) as $url) {
442       $images[]['path'] = $this->replaceBaseUrlWithCustom($url);
443     }
444     return $images;
445   }
446 }