Commit 169f2f9e authored by Pawel G's avatar Pawel G
Browse files

Refactor generators into own classes

parent 97c92cbd
......@@ -14,7 +14,7 @@ services:
simple_sitemap.sitemap_generator:
class: Drupal\simple_sitemap\SitemapGenerator
public: false
public: true
arguments:
- '@simple_sitemap.batch'
- '@simple_sitemap.entity_helper'
......@@ -40,8 +40,20 @@ services:
class: Drupal\simple_sitemap\Batch\Batch
public: false
simple_sitemap.batch_url_generator:
class: Drupal\simple_sitemap\Batch\BatchUrlGenerator
simple_sitemap.entity_url_generator:
class: Drupal\simple_sitemap\Batch\EntityUrlGenerator
public: true
arguments:
- '@simple_sitemap.generator'
- '@simple_sitemap.sitemap_generator'
- '@language_manager'
- '@entity_type.manager'
- '@path.validator'
- '@entity.query'
- '@simple_sitemap.logger'
simple_sitemap.custom_url_generator:
class: Drupal\simple_sitemap\Batch\CustomUrlGenerator
public: true
arguments:
- '@simple_sitemap.generator'
......@@ -54,7 +66,7 @@ services:
simple_sitemap.logger:
class: Drupal\simple_sitemap\Logger
public: false
public: true
arguments:
- '@logger.channel.simple_sitemap'
- '@current_user'
......
......@@ -3,9 +3,14 @@
namespace Drupal\simple_sitemap\Batch;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Cache\Cache;
/**
* Class Batch
* @package Drupal\simple_sitemap\Batch
*
* The services of this class are not injected, as this class looses its state
* on every method call because of how the batch APi works.
*/
class Batch {
......@@ -25,6 +30,8 @@ class Batch {
const BATCH_INIT_MESSAGE = 'Initializing batch...';
const BATCH_ERROR_MESSAGE = 'An error has occurred. This may result in an incomplete XML sitemap.';
const BATCH_PROGRESS_MESSAGE = 'Processing @current out of @total link types.';
const REGENERATION_FINISHED_MESSAGE = "The <a href='@url' target='_blank'>XML sitemap</a> has been regenerated for all languages.";
const REGENERATION_FINISHED_ERROR_MESSAGE = 'The sitemap generation finished with an error.';
/**
* Batch constructor.
......@@ -113,10 +120,10 @@ class Batch {
* @see https://api.drupal.org/api/drupal/core!includes!form.inc/group/batch/8
*/
public static function generateBundleUrls(array $entity_info, array $batch_info, &$context) {
\Drupal::service('simple_sitemap.batch_url_generator')
\Drupal::service('simple_sitemap.entity_url_generator')
->setContext($context)
->setBatchInfo($batch_info)
->generateBundleUrls($entity_info);
->generate($entity_info);
}
/**
......@@ -129,10 +136,10 @@ class Batch {
* @see https://api.drupal.org/api/drupal/core!includes!form.inc/group/batch/8
*/
public static function generateCustomUrls(array $custom_paths, array $batch_info, &$context) {
\Drupal::service('simple_sitemap.batch_url_generator')
\Drupal::service('simple_sitemap.custom_url_generator')
->setContext($context)
->setBatchInfo($batch_info)
->generateCustomUrls($custom_paths);
->generate($custom_paths);
}
/**
......@@ -145,8 +152,24 @@ class Batch {
* @see https://api.drupal.org/api/drupal/core!includes!form.inc/group/batch/8
*/
public static function finishGeneration($success, $results, $operations) {
\Drupal::service('simple_sitemap.batch_url_generator')
->finishGeneration($success, $results, $operations);
if ($success) {
$remove_sitemap = empty($results['chunk_count']);
if (!empty($results['generate']) || $remove_sitemap) {
\Drupal::service('simple_sitemap.sitemap_generator')
->generateSitemap($results['generate'], $remove_sitemap);
}
Cache::invalidateTags(['simple_sitemap']);
\Drupal::service('simple_sitemap.logger')->m(self::REGENERATION_FINISHED_MESSAGE,
['@url' => $GLOBALS['base_url'] . '/sitemap.xml'])
// ['@url' => $this->sitemapGenerator->getCustomBaseUrl() . '/sitemap.xml']) //todo: Use actual base URL for message.
->display('status')
->log('info');
}
else {
\Drupal::service('simple_sitemap.logger')->m(self::REGENERATION_FINISHED_ERROR_MESSAGE)
->display('error', 'administer sitemap settings')
->log('error');
}
}
}
<?php
namespace Drupal\simple_sitemap\Batch;
use Drupal\Core\Url;
/**
* Class BatchUrlGenerator
* @package Drupal\simple_sitemap\Batch
*/
class CustomUrlGenerator extends UrlGeneratorBase implements UrlGeneratorInterface {
const PATH_DOES_NOT_EXIST_OR_NO_ACCESS_MESSAGE = "The custom path @path has been omitted from the XML sitemap as it either does not exist, or it is not accessible to anonymous users. You can review custom paths <a href='@custom_paths_url'>here</a>.";
/**
* Batch function which generates urls to custom paths.
*
* @param mixed $custom_paths
*/
public function generate($custom_paths) {
foreach ($this->getBatchIterationCustomPaths($custom_paths) as $i => $custom_path) {
$this->setCurrentId($i);
// todo: Change to different function, as this also checks if current user has access. The user however varies depending if process was started from the web interface or via cron/drush. Use getUrlIfValidWithoutAccessCheck()?
if (!$this->pathValidator->isValid($custom_path['path'])) {
// if (!(bool) $this->pathValidator->getUrlIfValidWithoutAccessCheck($custom_path['path'])) {
$this->logger->m(self::PATH_DOES_NOT_EXIST_OR_NO_ACCESS_MESSAGE,
['@path' => $custom_path['path'], '@custom_paths_url' => $GLOBALS['base_url'] . '/admin/config/search/simplesitemap/custom'])
->display('warning', 'administer sitemap settings')
->log('warning');
continue;
}
$url_object = Url::fromUserInput($custom_path['path'], ['absolute' => TRUE]);
$path = $url_object->getInternalPath();
if ($this->batchInfo['remove_duplicates'] && $this->pathProcessed($path)) {
continue;
}
$entity = $this->getEntityFromUrlObject($url_object);
$path_data = [
'path' => $path,
'lastmod' => method_exists($entity, 'getChangedTime') ? date_iso8601($entity->getChangedTime()) : NULL,
'priority' => isset($custom_path['priority']) ? $custom_path['priority'] : NULL,
];
if (NULL !== $entity) {
$path_data['entity_info'] = ['entity_type' => $entity->getEntityTypeId(), 'id' => $entity->id()];
}
$this->addUrlVariants($url_object, $path_data, $entity);
}
$this->processSegment();
}
/**
* @param array $custom_paths
* @return array
*/
protected function getBatchIterationCustomPaths(array $custom_paths) {
if ($this->needsInitialization()) {
$this->initializeBatch(count($custom_paths));
}
if ($this->isBatch()) {
$custom_paths = array_slice($custom_paths, $this->context['sandbox']['progress'], $this->batchInfo['batch_process_limit']);
}
return $custom_paths;
}
/**
* @param $url_object
* @return object|null
*/
protected function getEntityFromUrlObject(Url $url_object) {
$route_parameters = $url_object->getRouteParameters();
return !empty($route_parameters) && $this->entityTypeManager
->getDefinition($entity_type_id = key($route_parameters), FALSE)
? $this->entityTypeManager->getStorage($entity_type_id)
->load($route_parameters[$entity_type_id])
: NULL;
}
}
<?php
namespace Drupal\simple_sitemap\Batch;
/**
* Class BatchUrlGenerator
* @package Drupal\simple_sitemap\Batch
*/
class EntityUrlGenerator extends UrlGeneratorBase implements UrlGeneratorInterface {
/**
* Batch callback function which generates urls to entity paths.
*
* @param mixed $entity_info
*/
public function generate($entity_info) {
foreach ($this->getBatchIterationEntities($entity_info) as $entity_id => $entity) {
$this->setCurrentId($entity_id);
$entity_settings = $this->generator->getEntityInstanceSettings($entity_info['entity_type_name'], $entity_id);
if (empty($entity_settings['index'])) {
continue;
}
switch ($entity_info['entity_type_name']) {
// Loading url object for menu links.
case 'menu_link_content':
if (!$entity->isEnabled()) {
continue 2;
}
$url_object = $entity->getUrlObject();
break;
// Loading url object for other entities.
default:
$url_object = $entity->toUrl();
}
// Do not include external paths.
if (!$url_object->isRouted()) {
continue;
}
$path = $url_object->getInternalPath();
// Do not include paths that have been already indexed.
if ($this->batchInfo['remove_duplicates'] && $this->pathProcessed($path)) {
continue;
}
$url_object->setOption('absolute', TRUE);
$path_data = [
'path' => $path,
'entity_info' => ['entity_type' => $entity_info['entity_type_name'], 'id' => $entity_id],
'lastmod' => method_exists($entity, 'getChangedTime') ? date_iso8601($entity->getChangedTime()) : NULL,
'priority' => $entity_settings['priority'],
];
$this->addUrlVariants($url_object, $path_data, $entity);
}
$this->processSegment();
}
/**
* @param array $entity_info
* @return \Drupal\Core\Entity\EntityInterface[]
*/
protected function getBatchIterationEntities(array $entity_info) {
$query = $this->entityQuery->get($entity_info['entity_type_name']);
if (!empty($entity_info['keys']['id'])) {
$query->sort($entity_info['keys']['id'], 'ASC');
}
if (!empty($entity_info['keys']['bundle'])) {
$query->condition($entity_info['keys']['bundle'], $entity_info['bundle_name']);
}
if (!empty($entity_info['keys']['status'])) {
$query->condition($entity_info['keys']['status'], 1);
}
if ($this->needsInitialization()) {
$count_query = clone $query;
$this->initializeBatch($count_query->count()->execute());
}
if ($this->isBatch()) {
$query->range($this->context['sandbox']['progress'], $this->batchInfo['batch_process_limit']);
}
return $this->entityTypeManager
->getStorage($entity_info['entity_type_name'])
->loadMultiple($query->execute());
}
}
......@@ -2,10 +2,10 @@
namespace Drupal\simple_sitemap\Batch;
use Drupal\Core\Url;
use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\simple_sitemap\Logger;
use Drupal\simple_sitemap\Simplesitemap;
use Drupal\simple_sitemap\SitemapGenerator;
......@@ -18,15 +18,12 @@ use Drupal\Core\Entity\Query\QueryFactory;
* Class BatchUrlGenerator
* @package Drupal\simple_sitemap\Batch
*/
class BatchUrlGenerator {
class UrlGeneratorBase {
use StringTranslationTrait;
const ANONYMOUS_USER_ID = 0;
const PATH_DOES_NOT_EXIST_OR_NO_ACCESS_MESSAGE = "The custom path @path has been omitted from the XML sitemap as it either does not exist, or it is not accessible to anonymous users. You can review custom paths <a href='@custom_paths_url'>here</a>.";
const PROCESSING_PATH_MESSAGE = 'Processing path #@current out of @max: @path';
const REGENERATION_FINISHED_MESSAGE = "The <a href='@url' target='_blank'>XML sitemap</a> has been regenerated for all languages.";
const REGENERATION_FINISHED_ERROR_MESSAGE = 'The sitemap generation finished with an error.';
/**
* @var \Drupal\simple_sitemap\Simplesitemap
......@@ -60,11 +57,15 @@ class BatchUrlGenerator {
/**
* @var \Drupal\Core\Path\PathValidator
*
* @todo Move to CustomUrlGenerator
*/
protected $pathValidator;
/**
* @var \Drupal\Core\Entity\Query\QueryFactory
*
* @todo Move to EntityUrlGenerator
*/
protected $entityQuery;
......@@ -108,8 +109,7 @@ class BatchUrlGenerator {
Logger $logger
) {
$this->generator = $generator;
// todo: using only one method, maybe make method static instead?
$this->sitemapGenerator = $sitemap_generator;
$this->sitemapGenerator = $sitemap_generator; // todo: using only one method, maybe make method static instead?
$this->languageManager = $language_manager;
$this->languages = $language_manager->getLanguages();
$this->defaultLanguageId = $language_manager->getDefaultLanguage()->getId();
......@@ -117,7 +117,8 @@ class BatchUrlGenerator {
$this->pathValidator = $path_validator;
$this->entityQuery = $entity_query;
$this->logger = $logger;
$this->anonUser = $this->entityTypeManager->getStorage('user')->load(self::ANONYMOUS_USER_ID);
$this->anonUser = $this->entityTypeManager->getStorage('user')
->load(self::ANONYMOUS_USER_ID);
}
/**
......@@ -138,109 +139,6 @@ class BatchUrlGenerator {
return $this;
}
/**
* Batch callback function which generates urls to entity paths.
*
* @param array $entity_info
*/
public function generateBundleUrls(array $entity_info) {
foreach ($this->getBatchIterationEntities($entity_info) as $entity_id => $entity) {
$this->setCurrentId($entity_id);
$entity_settings = $this->generator->getEntityInstanceSettings($entity_info['entity_type_name'], $entity_id);
if (empty($entity_settings['index'])) {
continue;
}
switch ($entity_info['entity_type_name']) {
// Loading url object for menu links.
case 'menu_link_content':
if (!$entity->isEnabled()) {
continue 2;
}
$url_object = $entity->getUrlObject();
break;
// Loading url object for other entities.
default:
$url_object = $entity->toUrl();
}
// Do not include external paths.
if (!$url_object->isRouted()) {
continue;
}
$path = $url_object->getInternalPath();
// Do not include paths that have been already indexed.
if ($this->batchInfo['remove_duplicates'] && $this->pathProcessed($path)) {
continue;
}
$url_object->setOption('absolute', TRUE);
$path_data = [
'path' => $path,
'entity_info' => ['entity_type' => $entity_info['entity_type_name'], 'id' => $entity_id],
'lastmod' => method_exists($entity, 'getChangedTime') ? date_iso8601($entity->getChangedTime()) : NULL,
'priority' => $entity_settings['priority'],
];
$this->addUrlVariants($url_object, $path_data, $entity);
}
$this->processSegment();
}
/**
* Batch function which generates urls to custom paths.
*
* @param array $custom_paths
*/
public function generateCustomUrls(array $custom_paths) {
$custom_paths = $this->getBatchIterationCustomPaths($custom_paths);
if ($this->needsInitialization()) {
$this->initializeBatch(count($custom_paths));
}
foreach ($custom_paths as $i => $custom_path) {
$this->setCurrentId($i);
// todo: Change to different function, as this also checks if current user has access. The user however varies depending if process was started from the web interface or via cron/drush. Use getUrlIfValidWithoutAccessCheck()?
if (!$this->pathValidator->isValid($custom_path['path'])) {
// if (!(bool) $this->pathValidator->getUrlIfValidWithoutAccessCheck($custom_path['path'])) {
$this->logger->m(self::PATH_DOES_NOT_EXIST_OR_NO_ACCESS_MESSAGE,
['@path' => $custom_path['path'], '@custom_paths_url' => $GLOBALS['base_url'] . '/admin/config/search/simplesitemap/custom'])
->display('warning', 'administer sitemap settings')
->log('warning');
continue;
}
$url_object = Url::fromUserInput($custom_path['path'], ['absolute' => TRUE]);
$path = $url_object->getInternalPath();
if ($this->batchInfo['remove_duplicates'] && $this->pathProcessed($path)) {
continue;
}
$entity = $this->getEntityFromUrlObject($url_object);
$path_data = [
'path' => $path,
'lastmod' => method_exists($entity, 'getChangedTime') ? date_iso8601($entity->getChangedTime()) : NULL,
'priority' => isset($custom_path['priority']) ? $custom_path['priority'] : NULL,
];
if (NULL !== $entity) {
$path_data['entity_info'] = ['entity_type' => $entity->getEntityTypeId(), 'id' => $entity->id()];
}
$this->addUrlVariants($url_object, $path_data, $entity);
}
$this->processSegment();
}
/**
* @return bool
*/
......@@ -262,63 +160,16 @@ class BatchUrlGenerator {
}
/**
* @param $entity_info
* @return mixed
*/
protected function getBatchIterationEntities($entity_info) {
$query = $this->entityQuery->get($entity_info['entity_type_name']);
if (!empty($entity_info['keys']['id'])) {
$query->sort($entity_info['keys']['id'], 'ASC');
}
if (!empty($entity_info['keys']['bundle'])) {
$query->condition($entity_info['keys']['bundle'], $entity_info['bundle_name']);
}
if (!empty($entity_info['keys']['status'])) {
$query->condition($entity_info['keys']['status'], 1);
}
if ($this->needsInitialization()) {
$count_query = clone $query;
$this->initializeBatch($count_query->count()->execute());
}
if ($this->isBatch()) {
$query->range($this->context['sandbox']['progress'], $this->batchInfo['batch_process_limit']);
}
return $this->entityTypeManager
->getStorage($entity_info['entity_type_name'])
->loadMultiple($query->execute());
}
/**
* @param array $custom_paths
* @return array
* @param \Drupal\Core\Url $url_object
* @param array $path_data
* @param \Drupal\Core\Entity\ContentEntityBase $entity
*/
protected function getBatchIterationCustomPaths(array $custom_paths) {
if ($this->needsInitialization()) {
$this->initializeBatch(count($custom_paths));
}
if ($this->isBatch()) {
$custom_paths = array_slice($custom_paths, $this->context['sandbox']['progress'], $this->batchInfo['batch_process_limit']);
}
return $custom_paths;
}
/**
* @param $url_object
* @param $path_data
* @param $entity
*/
protected function addUrlVariants($url_object, $path_data, $entity) {
protected function addUrlVariants(Url $url_object, array $path_data, ContentEntityBase $entity = null) {
$alternate_urls = [];
$translation_languages = NULL !== $entity && $this->batchInfo['skip_untranslated']
? $entity->getTranslationLanguages() : $this->languages;
? $entity->getTranslationLanguages()
: $this->languages;
// Entity is not translated.
if (NULL !== $entity && isset($translation_languages['und'])) {
......@@ -425,19 +276,6 @@ class BatchUrlGenerator {
}
}
/**
* @param $url_object
* @return object|null
*/
protected function getEntityFromUrlObject($url_object) {
$route_parameters = $url_object->getRouteParameters();
return !empty($route_parameters) && $this->entityTypeManager
->getDefinition($entity_type_id = key($route_parameters), FALSE)
? $this->entityTypeManager->getStorage($entity_type_id)
->load($route_parameters[$entity_type_id])
: NULL;
}
/**
* @param string $url
* @return string
......@@ -447,29 +285,4 @@ class BatchUrlGenerator {
? str_replace($GLOBALS['base_url'], $this->batchInfo['base_url'], $url)
: $url;
}
/**
* Callback function called by the batch API when all operations are finished.
*
* @see https://api.drupal.org/api/drupal/core!includes!form.inc/group/batch/8
*/
public function finishGeneration($success, $results, $operations) {
if ($success) {
$remove_sitemap = empty($results['chunk_count']);
if (!empty($results['generate']) || $remove_sitemap) {
$this->sitemapGenerator->generateSitemap($results['generate'], $remove_sitemap);
}
Cache::invalidateTags(['simple_sitemap']);
$this->logger->m(self::REGENERATION_FINISHED_MESSAGE,
['@url' => $GLOBALS['base_url'] . '/sitemap.xml'])
// ['@url' => $this->sitemapGenerator->getCustomBaseUrl() . '/sitemap.xml']) //todo: Use actual base URL for message.
->display('status')
->log('info');
}
else {
$this->logger->m(self::REGENERATION_FINISHED_ERROR_MESSAGE)
->display('error', 'administer sitemap settings')
->log('error');
}
}
}
<?php
namespace Drupal\simple_sitemap\Batch;
/**
* Interface UrlGeneratorInterface
* @package Drupal\simple_sitemap\Batch
*/
interface UrlGeneratorInterface {
/**
* @param mixed $data
*/
public function generate($data);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment