diff --git a/3251227-make-compatible-with-simple-sitemap-34-combined-with-D10-fixes.patch b/3251227-make-compatible-with-simple-sitemap-34-combined-with-D10-fixes.patch index e69de29..898ec39 100644 --- a/3251227-make-compatible-with-simple-sitemap-34-combined-with-D10-fixes.patch +++ b/3251227-make-compatible-with-simple-sitemap-34-combined-with-D10-fixes.patch @@ -0,0 +1,778 @@ +diff --git a/domain_simple_sitemap.info.yml b/domain_simple_sitemap.info.yml +index 6972f23..5fbf8aa 100644 +--- a/domain_simple_sitemap.info.yml ++++ b/domain_simple_sitemap.info.yml +@@ -1,8 +1,7 @@ + name: Domain Access Simple Sitemap + type: module + description: Module for generating sitemaps on domains with Domain Access module. +-core: 8.x +-core_version_requirement: ^8 || ^9 ++core_version_requirement: ^9 || ^10 + package: SEO + configure: domain_simple_sitemap.settings + dependencies: +diff --git a/domain_simple_sitemap.module b/domain_simple_sitemap.module +index b51b504..fd88f52 100644 +--- a/domain_simple_sitemap.module ++++ b/domain_simple_sitemap.module +@@ -6,6 +6,9 @@ + */ + + use Drupal\Core\Entity\EntityInterface; ++use Drupal\Core\Entity\EntityTypeInterface; ++use Drupal\Core\Form\FormStateInterface; ++use Drupal\simple_sitemap\Entity\SimpleSitemapType; + + /** + * Implements hook_ENTITY_TYPE_insert(). +@@ -13,9 +16,7 @@ use Drupal\Core\Entity\EntityInterface; + function domain_simple_sitemap_domain_insert(EntityInterface $domain) { + /** @var \Drupal\domain_simple_sitemap\DomainSitemapManager $domainSitemapManager */ + $domainSitemapManager = Drupal::service('domain_simple_sitemap.manager'); +- if ($domain->isNew()) { +- $domainSitemapManager->addSitemapVariant($domain); +- } ++ $domainSitemapManager->addSitemapVariant($domain); + } + + /** +@@ -57,7 +58,7 @@ function domain_simple_sitemap_simple_sitemap_links_alter(array &$links, $sitema + // Resolve this variant to a domain. + $storage = \Drupal::entityTypeManager()->getStorage('domain'); + +- if ($domain = $storage->load($sitemap_variant)) { ++ if (isset($sitemap_variant->type) && $domain = $storage->load($sitemap_variant->type)) { + // The base URL of the domain is also its path. + $front = $domain->getPath(); + // Load the domain's configuration to find the front page. +@@ -81,3 +82,62 @@ function domain_simple_sitemap_simple_sitemap_links_alter(array &$links, $sitema + } + } + } ++ ++/** ++ * Implements hook_form_FORM_ID_alter(). ++ * ++ * Alter the sitemap variant edit form to select domain. ++ */ ++function domain_simple_sitemap_form_simple_sitemap_type_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) { ++ // Get the Simple Sitemap Type entity we are editing. ++ $simple_sitemap = $form_state->getformObject()->getEntity(); ++ // Create an options array of all domains. ++ $storage = \Drupal::entityTypeManager()->getStorage('domain'); ++ $domains = $storage->loadMultiple(); ++ $options = []; ++ foreach ($domains as $key => $domain) { ++ $options[$key] = $domain->label(); ++ } ++ ++ // Dont't allow multiple options on url_generator field becaus then the #states based on that field value wont work. ++ // $form['url_generators']['#multiple'] = FALSE; ++ // Create our domain select form element. ++ $form['sitemap_domain'] = [ ++ '#type' => 'select', ++ '#title' => t('Select domain for this sitemap'), ++ '#options' => $options, ++ '#default_value' => $simple_sitemap->getThirdPartySetting('domain_simple_sitemap', 'sitemap_domain'), ++ '#weight' => 1, ++ // '#states' => [ ++ // 'visible' => [ ++ // ':input[name="url_generators"]' => ['value' => 'domain_entity'], ++ // ], ++ // 'required' => [ ++ // ':input[name="url_generators"]' => ['value' => 'domain_entity'], ++ // ], ++ // ], ++ ]; ++ $form['#entity_builders'][] = '_domain_simple_sitemap_sitemap_type_form_builder'; ++} ++ ++/** ++ * Entity builder for the migration config entity. ++ */ ++function _domain_simple_sitemap_sitemap_type_form_builder($entity_type, SimpleSitemapType $simple_sitemap, &$form, FormStateInterface $form_state) { ++ // If a domain was selected, save it as third party setting. ++ if ($form_state->getValue('sitemap_domain')) { ++ $simple_sitemap->setThirdPartySetting('domain_simple_sitemap', 'sitemap_domain', $form_state->getValue('sitemap_domain')); ++ return; ++ } ++ // If not, remove third party setting. ++ $simple_sitemap->unsetThirdPartySetting('domain_simple_sitemap', 'sitemap_domain'); ++} ++ ++/** ++ * @param EntityTypeInterface[] $entity_types ++ */ ++function domain_simple_sitemap_entity_type_build(&$entity_types) { ++ if (isset($entity_types['simple_sitemap'])) { ++ $entity_types['simple_sitemap']->setClass('Drupal\domain_simple_sitemap\Entity\DomainSimpleSitemap'); ++ } ++} +diff --git a/domain_simple_sitemap.services.yml b/domain_simple_sitemap.services.yml +index c5d2017..b0dc297 100644 +--- a/domain_simple_sitemap.services.yml ++++ b/domain_simple_sitemap.services.yml +@@ -5,4 +5,4 @@ services: + - { name: event_subscriber } + domain_simple_sitemap.manager: + class: Drupal\domain_simple_sitemap\DomainSitemapManager +- arguments: ['@entity_type.manager', '@simple_sitemap.generator', '@domain.validator'] ++ arguments: ['@entity_type.manager', '@domain.validator'] +diff --git a/src/Controller/DomainSimpleSitemapController.php b/src/Controller/DomainSimpleSitemapController.php +index 32d5881..e4869ac 100644 +--- a/src/Controller/DomainSimpleSitemapController.php ++++ b/src/Controller/DomainSimpleSitemapController.php +@@ -2,24 +2,25 @@ + + namespace Drupal\domain_simple_sitemap\Controller; + ++use Drupal\Core\Cache\CacheableResponse; + use Drupal\domain\DomainNegotiatorInterface; +-use Drupal\simple_sitemap\Controller\SimplesitemapController; +-use Drupal\simple_sitemap\Simplesitemap; +-use Drupal\simple_sitemap\SimplesitemapManager; ++use Drupal\simple_sitemap\Controller\SimpleSitemapController; + use Symfony\Component\DependencyInjection\ContainerInterface; + use Symfony\Component\HttpFoundation\Request; ++use Drupal\simple_sitemap\Manager\Generator; ++use Symfony\Component\HttpFoundation\Response; + + /** + * Class DomainSimpleSitemapController. + * + * @package Drupal\simple_sitemap\Controller + */ +-class DomainSimpleSitemapController extends SimplesitemapController { ++class DomainSimpleSitemapController extends SimpleSitemapController { + + /** + * Drupal `simple_sitemap.generator` service. + * +- * @var \Drupal\simple_sitemap\Simplesitemap ++ * @var \Drupal\simple_sitemap\Manager\Generator + */ + protected $generator; + +@@ -30,37 +31,26 @@ class DomainSimpleSitemapController extends SimplesitemapController { + */ + protected $domainNegotiator; + +- /** +- * Drupal `simple_sitemap.manager` service. +- * +- * @var \Drupal\simple_sitemap\SimplesitemapManager +- */ +- protected $sitemapManager; +- + /** + * DomainSitemapController constructor. + * +- * @param \Drupal\simple_sitemap\Simplesitemap $generator +- * Drupal `simple_sitemap.generator` service. ++ * @param \Drupal\simple_sitemap\Manager\Generator $generator ++ * The simple_sitemap.generator service. + * @param \Drupal\domain\DomainNegotiatorInterface $domain_negoriator + * Drupal `domain.negotiator` service. +- * @param \Drupal\simple_sitemap\SimplesitemapManager $sitemap_manager +- * Drupal `simple_sitemap.manager` service. + */ +- public function __construct(Simplesitemap $generator, DomainNegotiatorInterface $domain_negoriator, SimplesitemapManager $sitemap_manager) { ++ public function __construct(Generator $generator, DomainNegotiatorInterface $domain_negoriator) { + $this->generator = $generator; + $this->domainNegotiator = $domain_negoriator; +- $this->sitemapManager = $sitemap_manager; + } + + /** + * {@inheritdoc} + */ +- public static function create(ContainerInterface $container) { ++ public static function create(ContainerInterface $container): SimpleSitemapController { + return new static( + $container->get('simple_sitemap.generator'), +- $container->get('domain.negotiator'), +- $container->get('simple_sitemap.manager') ++ $container->get('domain.negotiator') + ); + } + +@@ -69,21 +59,20 @@ class DomainSimpleSitemapController extends SimplesitemapController { + * + * {@inheritdoc} + */ +- public function getSitemap(Request $request, $variant = NULL) { ++ public function getSitemap(Request $request, ?string $variant = NULL): Response { + if (empty($variant)) { +- $active_domain = $this->domainNegotiator->getActiveId(); ++ $active_domain = $this->domainNegotiator->getActiveDomain(); ++ $active_domain_id = $active_domain->id(); ++ $variant = $active_domain_id; ++ } + +- if (!empty($active_domain)) { +- $all_sitemap_variants = $this->sitemapManager +- ->getSitemapVariants('domain'); + +- if (array_key_exists($active_domain, $all_sitemap_variants)) { +- $variant = $active_domain; +- } +- } ++ $response = parent::getSitemap($request, $variant); ++ if ($response instanceof CacheableResponse) { ++ $response->getCacheableMetadata() ++ ->addCacheContexts(['url']); + } +- +- return parent::getSitemap($request, $variant); ++ return $response; + } + + } +diff --git a/src/DomainSitemapManager.php b/src/DomainSitemapManager.php +index b06f99a..a4358f7 100644 +--- a/src/DomainSitemapManager.php ++++ b/src/DomainSitemapManager.php +@@ -5,7 +5,7 @@ namespace Drupal\domain_simple_sitemap; + use Drupal\Core\Entity\EntityTypeManagerInterface; + use Drupal\domain\DomainInterface; + use Drupal\domain\DomainValidatorInterface; +-use Drupal\simple_sitemap\Simplesitemap; ++use Drupal\simple_sitemap\Entity\SimpleSitemapType; + + /** + * The service for domain_simple_sitemap module. +@@ -21,13 +21,6 @@ class DomainSitemapManager { + */ + protected $entityTypeManager; + +- /** +- * The simple sitemap generator. +- * +- * @var \Drupal\simple_sitemap\Simplesitemap +- */ +- protected $simpleSitemapManager; +- + /** + * The domain validator. + * +@@ -40,18 +33,14 @@ class DomainSitemapManager { + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager + * The entity type manager. +- * @param \Drupal\simple_sitemap\Simplesitemap $simpleSitemapManager +- * The simple sitemap manager. + * @param \Drupal\domain\DomainValidatorInterface $domainValidator + * The domain validator service. + */ + public function __construct( + EntityTypeManagerInterface $entityTypeManager, +- Simplesitemap $simpleSitemapManager, + DomainValidatorInterface $domainValidator + ) { + $this->entityTypeManager = $entityTypeManager; +- $this->simpleSitemapManager = $simpleSitemapManager; + $this->domainValidator = $domainValidator; + } + +@@ -62,56 +51,53 @@ class DomainSitemapManager { + * The domain to validate for syntax and uniqueness. + */ + public function addSitemapVariant(DomainInterface $domain) { +- // Create an sitemap variant. +- $manager = $this->simpleSitemapManager->getSitemapManager(); +- $manager->addSitemapVariant($domain->id(), [ +- 'type' => 'domain', +- 'label' => $domain->label(), +- ]); +- // Generate the site map. +- $generator = $manager->getSitemapGenerator('default'); +- $generator->setSitemapVariant($domain->id()); +- $generator->setSettings(['excluded_languages' => [], 'xsl' => TRUE]); +- if ($domain->status()) { +- $generator->generate([]); +- $generator->publish(); ++ // Test if it does not already exist. ++ $sitemap_type = SimpleSitemapType::load($domain->id()); ++ if (!is_null($sitemap_type)) { ++ \Drupal::logger('domain_simple_sitemap')->notice('Failed creating new sitemap type because it already exists: ' . $domain->id()); ++ return; + } ++ // Create a new sitemap type for the domain. ++ $type_storage = \Drupal::entityTypeManager()->getStorage('simple_sitemap_type'); ++ if ($type_storage->load($domain->id()) === NULL) { ++ $domain_sitemap = $type_storage->create([ ++ 'id' => $domain->id(), ++ 'label' => $domain->label() . ' sitemap', ++ 'description' => 'Sitemap type for domain: ' . $domain->label(), ++ 'sitemap_generator' => 'default', ++ 'url_generators' => [ ++ 'domain_entity', ++ 'custom', ++ 'entity', ++ 'entity_menu_link_content', ++ 'arbitrary', ++ ], ++ ]); ++ // Set the domain to the sitemap type via third party settings. ++ $domain_sitemap->setThirdPartySetting('domain_simple_sitemap', 'sitemap_domain', $domain->id()); ++ // Save our new sitemap type. ++ $domain_sitemap->save(); ++ } ++ ++ // Generate the site map. ++ /** @var \Drupal\simple_sitemap\Manager\Generator $generator */ ++ $generator = \Drupal::service('simple_sitemap.generator'); ++ $generator ++ ->rebuildQueue() ++ ->generate(); + } + + /** + * Delete sitemap variant for domain. + * + * @param \Drupal\domain\DomainInterface $domain +- * The domain to validate for syntax and uniqueness. ++ * The domain of which to delete the sitemap type from. + */ + public function deleteSitemapVariant(DomainInterface $domain) { +- // Remove the sitemap variant. +- $manager = $this->simpleSitemapManager->getSitemapManager(); +- $manager->removeSitemapVariants([$domain->id()]); +- // Remove the sitemap. +- $generator = $manager->getSitemapGenerator('default'); +- $generator->setSitemapVariant($domain->id()); +- $generator->setSettings(['excluded_languages' => []]); +- $generator->remove(); +- } +- +- /** +- * Checks a domain exists by trying to do an http request to it. +- * +- * @param \Drupal\domain\DomainInterface $domain +- * The domain to validate for syntax and uniqueness. +- * +- * @return int +- * The server response code for the request. +- * +- * @see domain_validate() +- */ +- private function checkDomain(DomainInterface $domain) { +- $response = $this->domainValidator->checkResponse($domain); +- if ($response >= 200 && $response <= 299) { +- return TRUE; ++ $sitemap_type = SimpleSitemapType::load($domain->id()); ++ if ($sitemap_type) { ++ $sitemap_type->delete(); + } +- return FALSE; + } + + } +diff --git a/src/Entity/DomainSimpleSitemap.php b/src/Entity/DomainSimpleSitemap.php +new file mode 100644 +index 0000000..61c9163 +--- /dev/null ++++ b/src/Entity/DomainSimpleSitemap.php +@@ -0,0 +1,47 @@ ++ $options['delta']] : []; ++ unset($options['delta']); ++ ++ if (empty($options['base_url'])) { ++ /** @var \Drupal\simple_sitemap\Settings $settings */ ++ $settings = \Drupal::service('simple_sitemap.settings'); ++ $options['base_url'] = $settings->get('base_url') ?: $GLOBALS['base_url']; ++ ++ $storage = \Drupal::entityTypeManager()->getStorage('domain'); ++ $domains = $storage->loadMultiple(); ++ $sitemap_type = $this->get('type'); ++ ++ // Try to get domain's path. ++ foreach ($domains as $key => $domain) { ++ if ($key == $sitemap_type) { ++ $options['base_url'] = rtrim($domain->getPath(), '/'); ++ } ++ } ++ } ++ $options['language'] = $this->languageManager()->getLanguage(LanguageInterface::LANGCODE_NOT_APPLICABLE); ++ ++ return Url::fromRoute( ++ 'simple_sitemap.sitemap_default', ++ $parameters, ++ $options); ++ } ++ ++} +diff --git a/src/Form/DomainSimpleSitemapConfigForm.php b/src/Form/DomainSimpleSitemapConfigForm.php +index 2e0cffc..140fe93 100644 +--- a/src/Form/DomainSimpleSitemapConfigForm.php ++++ b/src/Form/DomainSimpleSitemapConfigForm.php +@@ -116,7 +116,7 @@ class DomainSimpleSitemapConfigForm extends ConfigFormBase { + ]; + + $form['domain_sitemap_variants'] = [ +- '#markup' => Link::createFromRoute('You can check existing sitemap variants of domains', 'simple_sitemap.sitemaps') ++ '#markup' => Link::createFromRoute('You can check existing sitemap variants of domains', 'entity.simple_sitemap.collection') + ->toString(), + ]; + +diff --git a/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php b/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php +index 19eaa24..0ebab51 100644 +--- a/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php ++++ b/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php +@@ -3,7 +3,6 @@ + namespace Drupal\domain_simple_sitemap\Plugin\simple_sitemap\UrlGenerator; + + use Drupal\Core\Url; +-use Drupal\domain\Entity\Domain; + use Drupal\domain_access\DomainAccessManagerInterface; + use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\EntityUrlGenerator; + +@@ -22,207 +21,134 @@ class DomainEntityUrlGenerator extends EntityUrlGenerator { + /** + * {@inheritdoc} + */ +- public function getDataSets() { ++ public function getDataSets(): array { + $data_sets = []; + $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes(); ++ $all_bundle_settings = $this->entitiesManager->setVariants($this->sitemap->id())->getAllBundleSettings(); ++ $domainStorage = \Drupal::entityTypeManager()->getStorage('domain'); ++ $original_domain = \Drupal::service('domain.negotiator')->getActiveDomain(); ++ ++ if (isset($all_bundle_settings[$this->sitemap->id()])) { ++ foreach ($all_bundle_settings[$this->sitemap->id()] as $entity_type_name => $bundles) { ++ if (!isset($sitemap_entity_types[$entity_type_name])) { ++ continue; ++ } + +- foreach ($this->generator +- ->setVariants($this->sitemapVariant) +- ->getBundleSettings() as $entity_type_name => $bundles) { +- if (isset($sitemap_entity_types[$entity_type_name])) { +- // Skip this entity type +- // if another plugin is written to override its generation. +- foreach ($this->urlGeneratorManager->getDefinitions() as $plugin) { +- if (isset($plugin['settings']['overrides_entity_type']) +- && $plugin['settings']['overrides_entity_type'] === $entity_type_name) { +- continue 2; +- } ++ if ($this->isOverwrittenForEntityType($entity_type_name)) { ++ continue; + } + + $entityTypeStorage = $this->entityTypeManager->getStorage($entity_type_name); + $keys = $sitemap_entity_types[$entity_type_name]->getKeys(); + + foreach ($bundles as $bundle_name => $bundle_settings) { +- // Skip if "Content type" is excluded for selected Variant +- // (Index entities of this type in /admin/structure/types/manage/page) +- if (!empty($bundle_settings['index'])) { +- $query = $entityTypeStorage->getQuery(); ++ if ($bundle_settings['index']) { ++ $query = $entityTypeStorage->getQuery()->accessCheck(FALSE); + +- if (empty($keys['id'])) { +- $query->sort($keys['id'], 'ASC'); ++ if (!empty($keys['id'])) { ++ $query->sort($keys['id']); + } + if (!empty($keys['bundle'])) { + $query->condition($keys['bundle'], $bundle_name); + } +- if (!empty($keys['status'])) { ++ if (!empty($keys['published'])) { ++ $query->condition($keys['published'], 1); ++ } ++ elseif (!empty($keys['status'])) { + $query->condition($keys['status'], 1); + } + +- $activeId = \Drupal::service('domain.negotiator')->getActiveId(); +- $domainSource = "field_domain_source"; +- +- if (!empty($keys['bundle'])) { +- if ($keys['bundle'] == 'type' && $entity_type_name == 'node') { +- $source_only = \Drupal::config('domain_simple_sitemap.settings') +- ->get('domain_simple_sitemap_filter'); +- if ($source_only) { +- // Filter by Node Domain source. +- $query->condition($domainSource . '.target_id', $activeId); +- } +- else { +- // Filtered by Node Domain access. +- $orGroupDomain = $query->orConditionGroup() +- ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '.target_id', $activeId) +- ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD, 1); +- $query->condition($orGroupDomain); +- } +- foreach ($query->execute() as $entity_id) { +- $data_sets[] = [ +- 'entity_type' => $entity_type_name, +- 'id' => $entity_id, +- 'domain_source' => $activeId, +- ]; +- } +- } +- elseif ($keys['bundle'] == 'vid' && $entity_type_name == 'taxonomy_term') { +- // For taxonomy. +- foreach ($query->execute() as $entity_id) { +- $data_sets[] = [ +- 'entity_type' => $entity_type_name, +- 'id' => $entity_id, +- 'domain_source' => $activeId, +- ]; +- } ++ // Get the selected domain for the sitemap type. ++ $sitemap_domain_id = $this->sitemap->getType()->getThirdPartySetting('domain_simple_sitemap', 'sitemap_domain'); ++ if (!$sitemap_domain_id) { ++ continue; ++ } ++ // Activate the domain. ++ $domain = $domainStorage->load($sitemap_domain_id); ++ \Drupal::service('domain.negotiator')->setActiveDomain($domain); ++ // Filter nodes based on their Domain Access settings. ++ $domain_entity = FALSE; ++ $all_bundle_fields = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_name, $bundle_name); ++ if (\Drupal::service('module_handler')->moduleExists('domain_entity')) { ++ if (array_key_exists(\Drupal\domain_entity\DomainEntityMapper::FIELD_NAME, $all_bundle_fields)) { ++ // Setting this query tag will cause the domain_entity module ++ // to alter the query to add domain access conditions. ++ $query->addTag($entity_type_name . '_access'); ++ $domain_entity = TRUE; + } +- else { +- // For all other bundles. +- foreach ($query->execute() as $entity_id) { +- $data_sets[] = [ +- 'entity_type' => $entity_type_name, +- 'id' => $entity_id, +- 'domain_source' => $activeId, +- ]; +- } ++ } ++ if (!$domain_entity && array_key_exists(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD, $all_bundle_fields)) { ++ $orGroupDomain = $query->orConditionGroup() ++ ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD, $sitemap_domain_id) ++ ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD, 1); ++ $query->condition($orGroupDomain); ++ } ++ ++ // Shift access check to EntityUrlGeneratorBase for language ++ // specific access. ++ // See https://www.drupal.org/project/simple_sitemap/issues/3102450. ++ $query->accessCheck(FALSE); ++ ++ $data_set = [ ++ 'entity_type' => $entity_type_name, ++ 'id' => [], ++ 'domain' => $sitemap_domain_id, ++ ]; ++ $entities = []; ++ foreach ($query->execute() as $entity_id) { ++ $entities[] = $entity_id; ++ $data_set['id'][] = $entity_id; ++ if (count($data_set['id']) >= $this->entitiesPerDataset) { ++ $data_sets[] = $data_set; ++ $data_set['id'] = []; + } + } ++ ++ // Add the last data set if there are some IDs gathered. ++ if (!empty($data_set['id'])) { ++ $data_sets[] = $data_set; ++ } + } + } + } + } ++ \Drupal::service('domain.negotiator')->setActiveDomain($original_domain); + return $data_sets; + } + ++ + /** + * {@inheritdoc} + */ +- protected function processDataSet($data_set) { +- // Equal $entity->id(). +- $entity_id = $data_set['id']; +- // Equal $entity->getEntityTypeId(). +- $entity_type_name = $data_set['entity_type']; +- $entity_source = $data_set['domain_source']; +- +- if (empty($entity = $this->entityTypeManager->getStorage($entity_type_name) +- ->load($entity_id))) { +- return FALSE; +- } +- +- // Remove Entity of other sources. +- if ($this->sitemapVariant != $entity_source) { +- return FALSE; ++ public function generate($data_set): array { ++ $original_domain = \Drupal::service('domain.negotiator')->getActiveDomain(); ++ // Set active domain to the one matching the dataset. ++ if (isset($data_set['domain'])) { ++ $domainStorage = \Drupal::entityTypeManager()->getStorage('domain'); ++ $domain = $domainStorage->load($data_set['domain']); ++ \Drupal::service('domain.negotiator')->setActiveDomain($domain); + } + +- $entity_settings = $this->generator +- ->setVariants($this->sitemapVariant) +- ->getEntityInstanceSettings($entity_type_name, $entity_id); +- +- if (empty($entity_settings['index'])) { +- return FALSE; +- } +- +- // Domain & URL variables. +- $url_object = $entity->toUrl(); +- $url_object->setOption('absolute', TRUE); +- +- // Do not include external paths. +- if (!$url_object->isRouted()) { +- return FALSE; +- } +- +- $path = $url_object->getInternalPath(); +- $url_object->setOption('absolute', TRUE); +- // Photos. +- $url_photo_formatted = ""; +- if (!empty($entity_settings['include_images'])) { +- $url_photo = $this->getImages($this->sitemapVariant, $entity_type_name, $entity_id); +- if (!empty($url_photo)) { +- $url_photo_formatted = Url::fromUri($url_photo); ++ $path_data_sets = $this->processDataSet($data_set); ++ $url_variant_sets = []; ++ foreach ($path_data_sets as $path_data) { ++ if (isset($path_data['url']) && $path_data['url'] instanceof Url) { ++ $url_object = $path_data['url']; ++ unset($path_data['url']); ++ $url_variant_sets[] = $this->getUrlVariants($path_data, $url_object); + } + } + +- $paths = []; +- $paths[] = [ +- 'url' => $url_object, +- 'lastmod' => method_exists($entity, 'getChangedTime') ? date('c', $entity->getChangedTime()) : NULL, +- 'priority' => isset($entity_settings['priority']) ? $entity_settings['priority'] : NULL, +- 'changefreq' => !empty($entity_settings['changefreq']) ? $entity_settings['changefreq'] : NULL, +- 'images' => !empty($url_photo_formatted) ? $url_photo_formatted : [], +- // Additional info useful in hooks. +- 'meta' => [ +- 'path' => $path, +- 'entity_info' => [ +- 'entity_type' => $entity_type_name, +- 'id' => $entity_id, +- ], +- ], +- ]; +- return $paths; +- } +- +- /** +- * Set Sitemap Variant for specific domain. +- * +- * @param string $sitemap_variant +- * The sitemap variant. +- * +- * @return $this +- */ +- public function setSitemapVariant($sitemap_variant) { +- parent::setSitemapVariant($sitemap_variant); +- $domain = Domain::load($sitemap_variant); +- \Drupal::service('domain.negotiator')->setActiveDomain($domain); +- return $this; +- } +- +- /** +- * Get images field from entity's fields. +- * +- * @param string $current_variant +- * The current sitemap variant. +- * @param string $entity_type_name +- * The entity name of type. +- * @param mixed $entity_id +- * The Entity ID. +- * +- * @return string +- * A string containing a URL that may be used to access the image file. +- */ +- protected function getImages($current_variant, $entity_type_name, $entity_id) { +- $term_obj = $this->entityTypeManager->getStorage($entity_type_name) +- ->load($entity_id); +- // TODO : change "field_photo" by something not specific. +- if (empty($term_obj)) { +- return ""; +- } +- if ($term_obj->hasField('field_image') && isset($term_obj->get('field_image')->entity)) { +- return file_create_url($term_obj->get('field_image')->entity->getFileUri()); +- } +- elseif ($term_obj->hasField('field_photo') && isset($term_obj->get('field_photo')->entity)) { +- return file_create_url($term_obj->get('field_photo')->entity->getFileUri()); +- } +- elseif ($term_obj->hasField('field_img') && isset($term_obj->get('field_img')->entity)) { +- return file_create_url($term_obj->get('field_img')->entity->getFileUri()); ++ // Make sure to clear entity memory cache so it does not build up resulting ++ // in a constant increase of memory. ++ // See https://www.drupal.org/project/simple_sitemap/issues/3170261 and ++ // https://www.drupal.org/project/simple_sitemap/issues/3202233 ++ if ($this->entityTypeManager->getDefinition($data_set['entity_type'])->isStaticallyCacheable()) { ++ $this->entityMemoryCache->deleteAll(); + } ++ ++ \Drupal::service('domain.negotiator')->setActiveDomain($original_domain); ++ return array_merge([], ...$url_variant_sets); + } + + /** +@@ -234,7 +160,8 @@ class DomainEntityUrlGenerator extends EntityUrlGenerator { + * @return string + * A replaced URL. + */ +- protected function replaceBaseUrlWithCustom($url) { ++ protected function replaceBaseUrlWithCustom(string $url): string { ++ /** @var \Drupal\domain\DomainInterface $domain */ + $domain = \Drupal::service('domain.negotiator')->getActiveDomain(); + $url_parts = explode("/", $url); + /* +diff --git a/src/Routing/RouteSubscriber.php b/src/Routing/RouteSubscriber.php +index 0892f69..1e1181f 100644 +--- a/src/Routing/RouteSubscriber.php ++++ b/src/Routing/RouteSubscriber.php +@@ -18,11 +18,9 @@ class RouteSubscriber extends RouteSubscriberBase { + * {@inheritdoc} + */ + public function alterRoutes(RouteCollection $collection) { +- if ($route = $collection->get('simple_sitemap.sitemap_default')) { +- $route->setDefaults([ +- '_controller' => '\Drupal\domain_simple_sitemap\Controller\DomainSimpleSitemapController::getSitemap', +- ]); +- } ++ if ($route = $collection->get('simple_sitemap.sitemap_default')) { ++ $route->setDefault('_controller', '\Drupal\domain_simple_sitemap\Controller\DomainSimpleSitemapController::getSitemap'); ++ } + } + + } diff --git a/domain_simple_sitemap.info.yml b/domain_simple_sitemap.info.yml index 6972f23..5fbf8aa 100644 --- a/domain_simple_sitemap.info.yml +++ b/domain_simple_sitemap.info.yml @@ -1,8 +1,7 @@ name: Domain Access Simple Sitemap type: module description: Module for generating sitemaps on domains with Domain Access module. -core: 8.x -core_version_requirement: ^8 || ^9 +core_version_requirement: ^9 || ^10 package: SEO configure: domain_simple_sitemap.settings dependencies: diff --git a/domain_simple_sitemap.module b/domain_simple_sitemap.module index b51b504..fd88f52 100644 --- a/domain_simple_sitemap.module +++ b/domain_simple_sitemap.module @@ -6,6 +6,9 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Form\FormStateInterface; +use Drupal\simple_sitemap\Entity\SimpleSitemapType; /** * Implements hook_ENTITY_TYPE_insert(). @@ -13,9 +16,7 @@ use Drupal\Core\Entity\EntityInterface; function domain_simple_sitemap_domain_insert(EntityInterface $domain) { /** @var \Drupal\domain_simple_sitemap\DomainSitemapManager $domainSitemapManager */ $domainSitemapManager = Drupal::service('domain_simple_sitemap.manager'); - if ($domain->isNew()) { - $domainSitemapManager->addSitemapVariant($domain); - } + $domainSitemapManager->addSitemapVariant($domain); } /** @@ -57,7 +58,7 @@ function domain_simple_sitemap_simple_sitemap_links_alter(array &$links, $sitema // Resolve this variant to a domain. $storage = \Drupal::entityTypeManager()->getStorage('domain'); - if ($domain = $storage->load($sitemap_variant)) { + if (isset($sitemap_variant->type) && $domain = $storage->load($sitemap_variant->type)) { // The base URL of the domain is also its path. $front = $domain->getPath(); // Load the domain's configuration to find the front page. @@ -81,3 +82,62 @@ function domain_simple_sitemap_simple_sitemap_links_alter(array &$links, $sitema } } } + +/** + * Implements hook_form_FORM_ID_alter(). + * + * Alter the sitemap variant edit form to select domain. + */ +function domain_simple_sitemap_form_simple_sitemap_type_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) { + // Get the Simple Sitemap Type entity we are editing. + $simple_sitemap = $form_state->getformObject()->getEntity(); + // Create an options array of all domains. + $storage = \Drupal::entityTypeManager()->getStorage('domain'); + $domains = $storage->loadMultiple(); + $options = []; + foreach ($domains as $key => $domain) { + $options[$key] = $domain->label(); + } + + // Dont't allow multiple options on url_generator field becaus then the #states based on that field value wont work. + // $form['url_generators']['#multiple'] = FALSE; + // Create our domain select form element. + $form['sitemap_domain'] = [ + '#type' => 'select', + '#title' => t('Select domain for this sitemap'), + '#options' => $options, + '#default_value' => $simple_sitemap->getThirdPartySetting('domain_simple_sitemap', 'sitemap_domain'), + '#weight' => 1, + // '#states' => [ + // 'visible' => [ + // ':input[name="url_generators"]' => ['value' => 'domain_entity'], + // ], + // 'required' => [ + // ':input[name="url_generators"]' => ['value' => 'domain_entity'], + // ], + // ], + ]; + $form['#entity_builders'][] = '_domain_simple_sitemap_sitemap_type_form_builder'; +} + +/** + * Entity builder for the migration config entity. + */ +function _domain_simple_sitemap_sitemap_type_form_builder($entity_type, SimpleSitemapType $simple_sitemap, &$form, FormStateInterface $form_state) { + // If a domain was selected, save it as third party setting. + if ($form_state->getValue('sitemap_domain')) { + $simple_sitemap->setThirdPartySetting('domain_simple_sitemap', 'sitemap_domain', $form_state->getValue('sitemap_domain')); + return; + } + // If not, remove third party setting. + $simple_sitemap->unsetThirdPartySetting('domain_simple_sitemap', 'sitemap_domain'); +} + +/** + * @param EntityTypeInterface[] $entity_types + */ +function domain_simple_sitemap_entity_type_build(&$entity_types) { + if (isset($entity_types['simple_sitemap'])) { + $entity_types['simple_sitemap']->setClass('Drupal\domain_simple_sitemap\Entity\DomainSimpleSitemap'); + } +} diff --git a/domain_simple_sitemap.services.yml b/domain_simple_sitemap.services.yml index c5d2017..b0dc297 100644 --- a/domain_simple_sitemap.services.yml +++ b/domain_simple_sitemap.services.yml @@ -5,4 +5,4 @@ services: - { name: event_subscriber } domain_simple_sitemap.manager: class: Drupal\domain_simple_sitemap\DomainSitemapManager - arguments: ['@entity_type.manager', '@simple_sitemap.generator', '@domain.validator'] + arguments: ['@entity_type.manager', '@domain.validator'] diff --git a/src/Controller/DomainSimpleSitemapController.php b/src/Controller/DomainSimpleSitemapController.php index 32d5881..e4869ac 100644 --- a/src/Controller/DomainSimpleSitemapController.php +++ b/src/Controller/DomainSimpleSitemapController.php @@ -2,24 +2,25 @@ namespace Drupal\domain_simple_sitemap\Controller; +use Drupal\Core\Cache\CacheableResponse; use Drupal\domain\DomainNegotiatorInterface; -use Drupal\simple_sitemap\Controller\SimplesitemapController; -use Drupal\simple_sitemap\Simplesitemap; -use Drupal\simple_sitemap\SimplesitemapManager; +use Drupal\simple_sitemap\Controller\SimpleSitemapController; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; +use Drupal\simple_sitemap\Manager\Generator; +use Symfony\Component\HttpFoundation\Response; /** * Class DomainSimpleSitemapController. * * @package Drupal\simple_sitemap\Controller */ -class DomainSimpleSitemapController extends SimplesitemapController { +class DomainSimpleSitemapController extends SimpleSitemapController { /** * Drupal `simple_sitemap.generator` service. * - * @var \Drupal\simple_sitemap\Simplesitemap + * @var \Drupal\simple_sitemap\Manager\Generator */ protected $generator; @@ -30,37 +31,26 @@ class DomainSimpleSitemapController extends SimplesitemapController { */ protected $domainNegotiator; - /** - * Drupal `simple_sitemap.manager` service. - * - * @var \Drupal\simple_sitemap\SimplesitemapManager - */ - protected $sitemapManager; - /** * DomainSitemapController constructor. * - * @param \Drupal\simple_sitemap\Simplesitemap $generator - * Drupal `simple_sitemap.generator` service. + * @param \Drupal\simple_sitemap\Manager\Generator $generator + * The simple_sitemap.generator service. * @param \Drupal\domain\DomainNegotiatorInterface $domain_negoriator * Drupal `domain.negotiator` service. - * @param \Drupal\simple_sitemap\SimplesitemapManager $sitemap_manager - * Drupal `simple_sitemap.manager` service. */ - public function __construct(Simplesitemap $generator, DomainNegotiatorInterface $domain_negoriator, SimplesitemapManager $sitemap_manager) { + public function __construct(Generator $generator, DomainNegotiatorInterface $domain_negoriator) { $this->generator = $generator; $this->domainNegotiator = $domain_negoriator; - $this->sitemapManager = $sitemap_manager; } /** * {@inheritdoc} */ - public static function create(ContainerInterface $container) { + public static function create(ContainerInterface $container): SimpleSitemapController { return new static( $container->get('simple_sitemap.generator'), - $container->get('domain.negotiator'), - $container->get('simple_sitemap.manager') + $container->get('domain.negotiator') ); } @@ -69,21 +59,20 @@ class DomainSimpleSitemapController extends SimplesitemapController { * * {@inheritdoc} */ - public function getSitemap(Request $request, $variant = NULL) { + public function getSitemap(Request $request, ?string $variant = NULL): Response { if (empty($variant)) { - $active_domain = $this->domainNegotiator->getActiveId(); + $active_domain = $this->domainNegotiator->getActiveDomain(); + $active_domain_id = $active_domain->id(); + $variant = $active_domain_id; + } - if (!empty($active_domain)) { - $all_sitemap_variants = $this->sitemapManager - ->getSitemapVariants('domain'); - if (array_key_exists($active_domain, $all_sitemap_variants)) { - $variant = $active_domain; - } - } + $response = parent::getSitemap($request, $variant); + if ($response instanceof CacheableResponse) { + $response->getCacheableMetadata() + ->addCacheContexts(['url']); } - - return parent::getSitemap($request, $variant); + return $response; } } diff --git a/src/DomainSitemapManager.php b/src/DomainSitemapManager.php index b06f99a..a4358f7 100644 --- a/src/DomainSitemapManager.php +++ b/src/DomainSitemapManager.php @@ -5,7 +5,7 @@ namespace Drupal\domain_simple_sitemap; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\domain\DomainInterface; use Drupal\domain\DomainValidatorInterface; -use Drupal\simple_sitemap\Simplesitemap; +use Drupal\simple_sitemap\Entity\SimpleSitemapType; /** * The service for domain_simple_sitemap module. @@ -21,13 +21,6 @@ class DomainSitemapManager { */ protected $entityTypeManager; - /** - * The simple sitemap generator. - * - * @var \Drupal\simple_sitemap\Simplesitemap - */ - protected $simpleSitemapManager; - /** * The domain validator. * @@ -40,18 +33,14 @@ class DomainSitemapManager { * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * The entity type manager. - * @param \Drupal\simple_sitemap\Simplesitemap $simpleSitemapManager - * The simple sitemap manager. * @param \Drupal\domain\DomainValidatorInterface $domainValidator * The domain validator service. */ public function __construct( EntityTypeManagerInterface $entityTypeManager, - Simplesitemap $simpleSitemapManager, DomainValidatorInterface $domainValidator ) { $this->entityTypeManager = $entityTypeManager; - $this->simpleSitemapManager = $simpleSitemapManager; $this->domainValidator = $domainValidator; } @@ -62,56 +51,53 @@ class DomainSitemapManager { * The domain to validate for syntax and uniqueness. */ public function addSitemapVariant(DomainInterface $domain) { - // Create an sitemap variant. - $manager = $this->simpleSitemapManager->getSitemapManager(); - $manager->addSitemapVariant($domain->id(), [ - 'type' => 'domain', - 'label' => $domain->label(), - ]); - // Generate the site map. - $generator = $manager->getSitemapGenerator('default'); - $generator->setSitemapVariant($domain->id()); - $generator->setSettings(['excluded_languages' => [], 'xsl' => TRUE]); - if ($domain->status()) { - $generator->generate([]); - $generator->publish(); + // Test if it does not already exist. + $sitemap_type = SimpleSitemapType::load($domain->id()); + if (!is_null($sitemap_type)) { + \Drupal::logger('domain_simple_sitemap')->notice('Failed creating new sitemap type because it already exists: ' . $domain->id()); + return; } + // Create a new sitemap type for the domain. + $type_storage = \Drupal::entityTypeManager()->getStorage('simple_sitemap_type'); + if ($type_storage->load($domain->id()) === NULL) { + $domain_sitemap = $type_storage->create([ + 'id' => $domain->id(), + 'label' => $domain->label() . ' sitemap', + 'description' => 'Sitemap type for domain: ' . $domain->label(), + 'sitemap_generator' => 'default', + 'url_generators' => [ + 'domain_entity', + 'custom', + 'entity', + 'entity_menu_link_content', + 'arbitrary', + ], + ]); + // Set the domain to the sitemap type via third party settings. + $domain_sitemap->setThirdPartySetting('domain_simple_sitemap', 'sitemap_domain', $domain->id()); + // Save our new sitemap type. + $domain_sitemap->save(); + } + + // Generate the site map. + /** @var \Drupal\simple_sitemap\Manager\Generator $generator */ + $generator = \Drupal::service('simple_sitemap.generator'); + $generator + ->rebuildQueue() + ->generate(); } /** * Delete sitemap variant for domain. * * @param \Drupal\domain\DomainInterface $domain - * The domain to validate for syntax and uniqueness. + * The domain of which to delete the sitemap type from. */ public function deleteSitemapVariant(DomainInterface $domain) { - // Remove the sitemap variant. - $manager = $this->simpleSitemapManager->getSitemapManager(); - $manager->removeSitemapVariants([$domain->id()]); - // Remove the sitemap. - $generator = $manager->getSitemapGenerator('default'); - $generator->setSitemapVariant($domain->id()); - $generator->setSettings(['excluded_languages' => []]); - $generator->remove(); - } - - /** - * Checks a domain exists by trying to do an http request to it. - * - * @param \Drupal\domain\DomainInterface $domain - * The domain to validate for syntax and uniqueness. - * - * @return int - * The server response code for the request. - * - * @see domain_validate() - */ - private function checkDomain(DomainInterface $domain) { - $response = $this->domainValidator->checkResponse($domain); - if ($response >= 200 && $response <= 299) { - return TRUE; + $sitemap_type = SimpleSitemapType::load($domain->id()); + if ($sitemap_type) { + $sitemap_type->delete(); } - return FALSE; } } diff --git a/src/Form/DomainSimpleSitemapConfigForm.php b/src/Form/DomainSimpleSitemapConfigForm.php index 2e0cffc..6a0f53d 100644 --- a/src/Form/DomainSimpleSitemapConfigForm.php +++ b/src/Form/DomainSimpleSitemapConfigForm.php @@ -116,7 +116,7 @@ class DomainSimpleSitemapConfigForm extends ConfigFormBase { ]; $form['domain_sitemap_variants'] = [ - '#markup' => Link::createFromRoute('You can check existing sitemap variants of domains', 'simple_sitemap.sitemaps') + '#markup' => Link::createFromRoute('You can check existing sitemap variants of domains', 'entity.simple_sitemap.collection') ->toString(), ]; @@ -206,7 +206,7 @@ class DomainSimpleSitemapConfigForm extends ConfigFormBase { ->setProgressMessage($this->t('Completed @current of @total.')) ->setErrorMessage($this->t('An error has occurred.')); - $this->batchBuilder->setFile(drupal_get_path('module', 'domain_simple_sitemap') . '/src/Form/DomainSimpleSitemapConfigForm.php'); + $this->batchBuilder->setFile(\Drupal::service('extension.list.module')->getPath('domain_simple_sitemap') . '/src/Form/DomainSimpleSitemapConfigForm.php'); $this->batchBuilder->addOperation([ $this, 'batchProcess', diff --git a/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php b/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php index 19eaa24..0ebab51 100644 --- a/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php +++ b/src/Plugin/simple_sitemap/UrlGenerator/DomainEntityUrlGenerator.php @@ -3,7 +3,6 @@ namespace Drupal\domain_simple_sitemap\Plugin\simple_sitemap\UrlGenerator; use Drupal\Core\Url; -use Drupal\domain\Entity\Domain; use Drupal\domain_access\DomainAccessManagerInterface; use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\EntityUrlGenerator; @@ -22,207 +21,134 @@ class DomainEntityUrlGenerator extends EntityUrlGenerator { /** * {@inheritdoc} */ - public function getDataSets() { + public function getDataSets(): array { $data_sets = []; $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes(); + $all_bundle_settings = $this->entitiesManager->setVariants($this->sitemap->id())->getAllBundleSettings(); + $domainStorage = \Drupal::entityTypeManager()->getStorage('domain'); + $original_domain = \Drupal::service('domain.negotiator')->getActiveDomain(); + + if (isset($all_bundle_settings[$this->sitemap->id()])) { + foreach ($all_bundle_settings[$this->sitemap->id()] as $entity_type_name => $bundles) { + if (!isset($sitemap_entity_types[$entity_type_name])) { + continue; + } - foreach ($this->generator - ->setVariants($this->sitemapVariant) - ->getBundleSettings() as $entity_type_name => $bundles) { - if (isset($sitemap_entity_types[$entity_type_name])) { - // Skip this entity type - // if another plugin is written to override its generation. - foreach ($this->urlGeneratorManager->getDefinitions() as $plugin) { - if (isset($plugin['settings']['overrides_entity_type']) - && $plugin['settings']['overrides_entity_type'] === $entity_type_name) { - continue 2; - } + if ($this->isOverwrittenForEntityType($entity_type_name)) { + continue; } $entityTypeStorage = $this->entityTypeManager->getStorage($entity_type_name); $keys = $sitemap_entity_types[$entity_type_name]->getKeys(); foreach ($bundles as $bundle_name => $bundle_settings) { - // Skip if "Content type" is excluded for selected Variant - // (Index entities of this type in /admin/structure/types/manage/page) - if (!empty($bundle_settings['index'])) { - $query = $entityTypeStorage->getQuery(); + if ($bundle_settings['index']) { + $query = $entityTypeStorage->getQuery()->accessCheck(FALSE); - if (empty($keys['id'])) { - $query->sort($keys['id'], 'ASC'); + if (!empty($keys['id'])) { + $query->sort($keys['id']); } if (!empty($keys['bundle'])) { $query->condition($keys['bundle'], $bundle_name); } - if (!empty($keys['status'])) { + if (!empty($keys['published'])) { + $query->condition($keys['published'], 1); + } + elseif (!empty($keys['status'])) { $query->condition($keys['status'], 1); } - $activeId = \Drupal::service('domain.negotiator')->getActiveId(); - $domainSource = "field_domain_source"; - - if (!empty($keys['bundle'])) { - if ($keys['bundle'] == 'type' && $entity_type_name == 'node') { - $source_only = \Drupal::config('domain_simple_sitemap.settings') - ->get('domain_simple_sitemap_filter'); - if ($source_only) { - // Filter by Node Domain source. - $query->condition($domainSource . '.target_id', $activeId); - } - else { - // Filtered by Node Domain access. - $orGroupDomain = $query->orConditionGroup() - ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD . '.target_id', $activeId) - ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD, 1); - $query->condition($orGroupDomain); - } - foreach ($query->execute() as $entity_id) { - $data_sets[] = [ - 'entity_type' => $entity_type_name, - 'id' => $entity_id, - 'domain_source' => $activeId, - ]; - } - } - elseif ($keys['bundle'] == 'vid' && $entity_type_name == 'taxonomy_term') { - // For taxonomy. - foreach ($query->execute() as $entity_id) { - $data_sets[] = [ - 'entity_type' => $entity_type_name, - 'id' => $entity_id, - 'domain_source' => $activeId, - ]; - } + // Get the selected domain for the sitemap type. + $sitemap_domain_id = $this->sitemap->getType()->getThirdPartySetting('domain_simple_sitemap', 'sitemap_domain'); + if (!$sitemap_domain_id) { + continue; + } + // Activate the domain. + $domain = $domainStorage->load($sitemap_domain_id); + \Drupal::service('domain.negotiator')->setActiveDomain($domain); + // Filter nodes based on their Domain Access settings. + $domain_entity = FALSE; + $all_bundle_fields = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_name, $bundle_name); + if (\Drupal::service('module_handler')->moduleExists('domain_entity')) { + if (array_key_exists(\Drupal\domain_entity\DomainEntityMapper::FIELD_NAME, $all_bundle_fields)) { + // Setting this query tag will cause the domain_entity module + // to alter the query to add domain access conditions. + $query->addTag($entity_type_name . '_access'); + $domain_entity = TRUE; } - else { - // For all other bundles. - foreach ($query->execute() as $entity_id) { - $data_sets[] = [ - 'entity_type' => $entity_type_name, - 'id' => $entity_id, - 'domain_source' => $activeId, - ]; - } + } + if (!$domain_entity && array_key_exists(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD, $all_bundle_fields)) { + $orGroupDomain = $query->orConditionGroup() + ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_FIELD, $sitemap_domain_id) + ->condition(DomainAccessManagerInterface::DOMAIN_ACCESS_ALL_FIELD, 1); + $query->condition($orGroupDomain); + } + + // Shift access check to EntityUrlGeneratorBase for language + // specific access. + // See https://www.drupal.org/project/simple_sitemap/issues/3102450. + $query->accessCheck(FALSE); + + $data_set = [ + 'entity_type' => $entity_type_name, + 'id' => [], + 'domain' => $sitemap_domain_id, + ]; + $entities = []; + foreach ($query->execute() as $entity_id) { + $entities[] = $entity_id; + $data_set['id'][] = $entity_id; + if (count($data_set['id']) >= $this->entitiesPerDataset) { + $data_sets[] = $data_set; + $data_set['id'] = []; } } + + // Add the last data set if there are some IDs gathered. + if (!empty($data_set['id'])) { + $data_sets[] = $data_set; + } } } } } + \Drupal::service('domain.negotiator')->setActiveDomain($original_domain); return $data_sets; } + /** * {@inheritdoc} */ - protected function processDataSet($data_set) { - // Equal $entity->id(). - $entity_id = $data_set['id']; - // Equal $entity->getEntityTypeId(). - $entity_type_name = $data_set['entity_type']; - $entity_source = $data_set['domain_source']; - - if (empty($entity = $this->entityTypeManager->getStorage($entity_type_name) - ->load($entity_id))) { - return FALSE; - } - - // Remove Entity of other sources. - if ($this->sitemapVariant != $entity_source) { - return FALSE; + public function generate($data_set): array { + $original_domain = \Drupal::service('domain.negotiator')->getActiveDomain(); + // Set active domain to the one matching the dataset. + if (isset($data_set['domain'])) { + $domainStorage = \Drupal::entityTypeManager()->getStorage('domain'); + $domain = $domainStorage->load($data_set['domain']); + \Drupal::service('domain.negotiator')->setActiveDomain($domain); } - $entity_settings = $this->generator - ->setVariants($this->sitemapVariant) - ->getEntityInstanceSettings($entity_type_name, $entity_id); - - if (empty($entity_settings['index'])) { - return FALSE; - } - - // Domain & URL variables. - $url_object = $entity->toUrl(); - $url_object->setOption('absolute', TRUE); - - // Do not include external paths. - if (!$url_object->isRouted()) { - return FALSE; - } - - $path = $url_object->getInternalPath(); - $url_object->setOption('absolute', TRUE); - // Photos. - $url_photo_formatted = ""; - if (!empty($entity_settings['include_images'])) { - $url_photo = $this->getImages($this->sitemapVariant, $entity_type_name, $entity_id); - if (!empty($url_photo)) { - $url_photo_formatted = Url::fromUri($url_photo); + $path_data_sets = $this->processDataSet($data_set); + $url_variant_sets = []; + foreach ($path_data_sets as $path_data) { + if (isset($path_data['url']) && $path_data['url'] instanceof Url) { + $url_object = $path_data['url']; + unset($path_data['url']); + $url_variant_sets[] = $this->getUrlVariants($path_data, $url_object); } } - $paths = []; - $paths[] = [ - 'url' => $url_object, - 'lastmod' => method_exists($entity, 'getChangedTime') ? date('c', $entity->getChangedTime()) : NULL, - 'priority' => isset($entity_settings['priority']) ? $entity_settings['priority'] : NULL, - 'changefreq' => !empty($entity_settings['changefreq']) ? $entity_settings['changefreq'] : NULL, - 'images' => !empty($url_photo_formatted) ? $url_photo_formatted : [], - // Additional info useful in hooks. - 'meta' => [ - 'path' => $path, - 'entity_info' => [ - 'entity_type' => $entity_type_name, - 'id' => $entity_id, - ], - ], - ]; - return $paths; - } - - /** - * Set Sitemap Variant for specific domain. - * - * @param string $sitemap_variant - * The sitemap variant. - * - * @return $this - */ - public function setSitemapVariant($sitemap_variant) { - parent::setSitemapVariant($sitemap_variant); - $domain = Domain::load($sitemap_variant); - \Drupal::service('domain.negotiator')->setActiveDomain($domain); - return $this; - } - - /** - * Get images field from entity's fields. - * - * @param string $current_variant - * The current sitemap variant. - * @param string $entity_type_name - * The entity name of type. - * @param mixed $entity_id - * The Entity ID. - * - * @return string - * A string containing a URL that may be used to access the image file. - */ - protected function getImages($current_variant, $entity_type_name, $entity_id) { - $term_obj = $this->entityTypeManager->getStorage($entity_type_name) - ->load($entity_id); - // TODO : change "field_photo" by something not specific. - if (empty($term_obj)) { - return ""; - } - if ($term_obj->hasField('field_image') && isset($term_obj->get('field_image')->entity)) { - return file_create_url($term_obj->get('field_image')->entity->getFileUri()); - } - elseif ($term_obj->hasField('field_photo') && isset($term_obj->get('field_photo')->entity)) { - return file_create_url($term_obj->get('field_photo')->entity->getFileUri()); - } - elseif ($term_obj->hasField('field_img') && isset($term_obj->get('field_img')->entity)) { - return file_create_url($term_obj->get('field_img')->entity->getFileUri()); + // Make sure to clear entity memory cache so it does not build up resulting + // in a constant increase of memory. + // See https://www.drupal.org/project/simple_sitemap/issues/3170261 and + // https://www.drupal.org/project/simple_sitemap/issues/3202233 + if ($this->entityTypeManager->getDefinition($data_set['entity_type'])->isStaticallyCacheable()) { + $this->entityMemoryCache->deleteAll(); } + + \Drupal::service('domain.negotiator')->setActiveDomain($original_domain); + return array_merge([], ...$url_variant_sets); } /** @@ -234,7 +160,8 @@ class DomainEntityUrlGenerator extends EntityUrlGenerator { * @return string * A replaced URL. */ - protected function replaceBaseUrlWithCustom($url) { + protected function replaceBaseUrlWithCustom(string $url): string { + /** @var \Drupal\domain\DomainInterface $domain */ $domain = \Drupal::service('domain.negotiator')->getActiveDomain(); $url_parts = explode("/", $url); /* diff --git a/src/Routing/RouteSubscriber.php b/src/Routing/RouteSubscriber.php index 0892f69..1e1181f 100644 --- a/src/Routing/RouteSubscriber.php +++ b/src/Routing/RouteSubscriber.php @@ -18,11 +18,9 @@ class RouteSubscriber extends RouteSubscriberBase { * {@inheritdoc} */ public function alterRoutes(RouteCollection $collection) { - if ($route = $collection->get('simple_sitemap.sitemap_default')) { - $route->setDefaults([ - '_controller' => '\Drupal\domain_simple_sitemap\Controller\DomainSimpleSitemapController::getSitemap', - ]); - } + if ($route = $collection->get('simple_sitemap.sitemap_default')) { + $route->setDefault('_controller', '\Drupal\domain_simple_sitemap\Controller\DomainSimpleSitemapController::getSitemap'); + } } }