Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / modules / contrib / simple_sitemap / src / Simplesitemap.php
index 34dcda2534c5c6e9e1940d5d62822c6407358773..307508f7b689ff8dd9b0da1481b01d4c98af6c62 100644 (file)
@@ -2,13 +2,13 @@
 
 namespace Drupal\simple_sitemap;
 
-use Drupal\simple_sitemap\Form\FormHelper;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Path\PathValidator;
-use Drupal\Core\Entity\Query\QueryFactory;
 use Drupal\Core\Config\ConfigFactory;
 use Drupal\Core\Datetime\DateFormatter;
+use Drupal\Component\Datetime\Time;
+use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager;
 
 /**
  * Class Simplesitemap
@@ -36,11 +36,6 @@ class Simplesitemap {
    */
   protected $db;
 
-  /**
-   * @var \Drupal\Core\Entity\Query\QueryFactory
-   */
-  protected $entityQuery;
-
   /**
    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
@@ -51,12 +46,47 @@ class Simplesitemap {
    */
   protected $pathValidator;
 
+  /**
+   * @var \Drupal\Core\Datetime\DateFormatter
+   */
+  protected $dateFormatter;
+
+  /**
+   * @var \Drupal\Component\Datetime\Time
+   */
+  protected $time;
+
+  /**
+   * @var \Drupal\simple_sitemap\Batch
+   */
+  protected $batch;
+
+  /**
+   * @var \Drupal\Core\Extension\ModuleHandler
+   */
+  protected $moduleHandler;
+
+  /**
+   * @var \Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager
+   */
+  protected $urlGeneratorManager;
+
   /**
    * @var array
    */
-  protected static $allowed_link_settings = [
-    'entity' => ['index', 'priority'],
-    'custom' => ['priority'],
+  protected static $allowedLinkSettings = [
+    'entity' => ['index', 'priority', 'changefreq', 'include_images'],
+    'custom' => ['priority', 'changefreq'],
+  ];
+
+  /**
+   * @var array
+   */
+  protected static $linkSettingDefaults = [
+    'index' => 1,
+    'priority' => 0.5,
+    'changefreq' => '',
+    'include_images' => 0,
   ];
 
   /**
@@ -65,29 +95,35 @@ class Simplesitemap {
    * @param \Drupal\simple_sitemap\EntityHelper $entityHelper
    * @param \Drupal\Core\Config\ConfigFactory $configFactory
    * @param \Drupal\Core\Database\Connection $database
-   * @param \Drupal\Core\Entity\Query\QueryFactory $entityQuery
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
    * @param \Drupal\Core\Path\PathValidator $pathValidator
    * @param \Drupal\Core\Datetime\DateFormatter $dateFormatter
+   * @param \Drupal\Component\Datetime\Time $time
+   * @param \Drupal\simple_sitemap\Batch $batch
+   * @param \Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager $urlGeneratorManager
    */
   public function __construct(
     SitemapGenerator $sitemapGenerator,
     EntityHelper $entityHelper,
     ConfigFactory $configFactory,
     Connection $database,
-    QueryFactory $entityQuery,
     EntityTypeManagerInterface $entityTypeManager,
     PathValidator $pathValidator,
-    DateFormatter $dateFormatter
+    DateFormatter $dateFormatter,
+    Time $time,
+    Batch $batch,
+    UrlGeneratorManager $urlGeneratorManager
   ) {
     $this->sitemapGenerator = $sitemapGenerator;
     $this->entityHelper = $entityHelper;
     $this->configFactory = $configFactory;
     $this->db = $database;
-    $this->entityQuery = $entityQuery;
     $this->entityTypeManager = $entityTypeManager;
     $this->pathValidator = $pathValidator;
     $this->dateFormatter = $dateFormatter;
+    $this->time = $time;
+    $this->batch = $batch;
+    $this->urlGeneratorManager = $urlGeneratorManager;
   }
 
   /**
@@ -121,7 +157,7 @@ class Simplesitemap {
    * @return $this
    */
   public function saveSetting($name, $setting) {
-    $this->configFactory->getEditable("simple_sitemap.settings")
+    $this->configFactory->getEditable('simple_sitemap.settings')
       ->set($name, $setting)->save();
     return $this;
   }
@@ -170,7 +206,7 @@ class Simplesitemap {
    */
   protected function fetchSitemapChunkInfo() {
     return $this->db
-      ->query("SELECT id, sitemap_created FROM {simple_sitemap}")
+      ->query('SELECT id, sitemap_created FROM {simple_sitemap}')
       ->fetchAllAssoc('id');
   }
 
@@ -183,23 +219,53 @@ class Simplesitemap {
    * @return object
    *   A sitemap chunk object.
    */
-  private function fetchSitemapChunk($id) {
+  protected function fetchSitemapChunk($id) {
     return $this->db->query('SELECT * FROM {simple_sitemap} WHERE id = :id',
       [':id' => $id])->fetchObject();
   }
 
   /**
-   * Generates the sitemap for all languages and saves it to the db.
+   * Generates the XML sitemap and saves it to the db.
    *
    * @param string $from
-   *   Can be 'form', 'cron', 'drush' or 'nobatch'.
+   *   Can be 'form', 'backend', 'drush' or 'nobatch'.
    *   This decides how the batch process is to be run.
+   *
+   * @return bool|\Drupal\simple_sitemap\Simplesitemap
    */
   public function generateSitemap($from = 'form') {
-    $this->sitemapGenerator
-      ->setGenerator($this)
-      ->setGenerateFrom($from)
-      ->startGeneration();
+
+    $this->batch->setBatchSettings([
+      'base_url' => $this->getSetting('base_url', ''),
+      'batch_process_limit' => $this->getSetting('batch_process_limit', NULL),
+      'max_links' => $this->getSetting('max_links', 2000),
+      'skip_untranslated' => $this->getSetting('skip_untranslated', FALSE),
+      'remove_duplicates' => $this->getSetting('remove_duplicates', TRUE),
+      'excluded_languages' => $this->getSetting('excluded_languages', []),
+      'from' => $from,
+    ]);
+
+    $plugins = $this->urlGeneratorManager->getDefinitions();
+
+    usort($plugins, function($a, $b) {
+      return $a['weight'] - $b['weight'];
+    });
+
+    foreach ($plugins as $plugin) {
+      if ($plugin['enabled']) {
+        if (!empty($plugin['settings']['instantiate_for_each_data_set'])) {
+          foreach ($this->urlGeneratorManager->createInstance($plugin['id'])->getDataSets() as $data_sets) {
+            $this->batch->addOperation($plugin['id'], $data_sets);
+          }
+        }
+        else {
+          $this->batch->addOperation($plugin['id']);
+        }
+      }
+    }
+
+    $success = $this->batch->start();
+    return $from === 'nobatch' ? $this : $success;
   }
 
   /**
@@ -210,10 +276,12 @@ class Simplesitemap {
    *
    * @return string
    *   The sitemap index.
+   *
+   * @todo Need to make sure response is cached.
    */
   protected function getSitemapIndex($chunk_info) {
     return $this->sitemapGenerator
-      ->setGenerator($this)
+      ->setSettings(['base_url' => $this->getSetting('base_url', '')])
       ->generateSitemapIndex($chunk_info);
   }
 
@@ -227,7 +295,7 @@ class Simplesitemap {
     $chunks = $this->fetchSitemapChunkInfo();
     if (isset($chunks[SitemapGenerator::FIRST_CHUNK_INDEX]->sitemap_created)) {
       return $this->dateFormatter
-        ->formatInterval(REQUEST_TIME - $chunks[SitemapGenerator::FIRST_CHUNK_INDEX]
+        ->formatInterval($this->time->getRequestTime() - $chunks[SitemapGenerator::FIRST_CHUNK_INDEX]
             ->sitemap_created);
     }
     return FALSE;
@@ -240,7 +308,7 @@ class Simplesitemap {
    * setBundleSettings() as well.
    *
    * @param string $entity_type_id
-   *   Entity type id like 'node'.
+   *  Entity type id like 'node'.
    *
    * @return $this
    */
@@ -273,8 +341,8 @@ class Simplesitemap {
     }
 
     // Deleting inclusion settings.
-    $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings.$entity_type_id");
-    foreach($config_names as $config_name) {
+    $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings.$entity_type_id.");
+    foreach ($config_names as $config_name) {
       $this->configFactory->getEditable($config_name)->delete();
     }
 
@@ -288,48 +356,52 @@ class Simplesitemap {
    * of an entity type (e.g. page).
    *
    * @param string $entity_type_id
-   *   Entity type id like 'node' the bundle belongs to.
+   *  Entity type id like 'node' the bundle belongs to.
    * @param string $bundle_name
-   *   Name of the bundle. NULL if entity type has no bundles.
+   *  Name of the bundle. NULL if entity type has no bundles.
    * @param array $settings
-   *   An array of sitemap settings for this bundle/entity type.
-   *   Example: ['index' => TRUE, 'priority' => 0.5].
+   *  An array of sitemap settings for this bundle/entity type.
+   *  Example: ['index' => TRUE, 'priority' => 0.5, 'changefreq' => 'never', 'include_images' => FALSE].
    *
    * @return $this
+   *
+   * @todo: enableEntityType automatically
    */
-  public function setBundleSettings($entity_type_id, $bundle_name = NULL, $settings) {
-
+  public function setBundleSettings($entity_type_id, $bundle_name = NULL, $settings = []) {
     $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
 
-    foreach($settings as $setting_key => $setting) {
-      if ($setting_key == 'index') {
+    if (!empty($old_settings = $this->getBundleSettings($entity_type_id, $bundle_name))) {
+      $settings = array_merge($old_settings, $settings);
+    }
+    else {
+      self::supplementDefaultSettings('entity', $settings);
+    }
+
+    $bundle_settings = $this->configFactory
+      ->getEditable("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name");
+    foreach ($settings as $setting_key => $setting) {
+      if ($setting_key === 'index') {
         $setting = intval($setting);
       }
-      $this->configFactory
-        ->getEditable("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
-        ->set($setting_key, $setting)
-        ->save();
+      $bundle_settings->set($setting_key, $setting);
     }
-    //todo: Use addLinkSettings()?
+    $bundle_settings->save();
 
     // Delete entity overrides which are identical to new bundle setting.
-    $sitemap_entity_types = $this->entityHelper->getSitemapEntityTypes();
+    $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes();
     if (isset($sitemap_entity_types[$entity_type_id])) {
       $entity_type = $sitemap_entity_types[$entity_type_id];
       $keys = $entity_type->getKeys();
 
       // Menu fix.
-      $keys['bundle'] = $entity_type_id == 'menu_link_content' ? 'menu_name' : $keys['bundle'];
+      $keys['bundle'] = $entity_type_id === 'menu_link_content' ? 'menu_name' : $keys['bundle'];
 
-      $query = $this->entityQuery->get($entity_type_id);
+      $query = $this->entityTypeManager->getStorage($entity_type_id)->getQuery();
       if (!$this->entityHelper->entityTypeIsAtomic($entity_type_id)) {
         $query->condition($keys['bundle'], $bundle_name);
       }
       $entity_ids = $query->execute();
 
-      $bundle_settings = $this->configFactory
-        ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name");
-
       $query = $this->db->select('simple_sitemap_entity_overrides', 'o')
         ->fields('o', ['id', 'inclusion_settings'])
         ->condition('o.entity_type', $entity_type_id);
@@ -337,21 +409,25 @@ class Simplesitemap {
         $query->condition('o.entity_id', $entity_ids, 'IN');
       }
 
-      foreach($query->execute()->fetchAll() as $result) {
+      $delete_instances = [];
+      foreach ($query->execute()->fetchAll() as $result) {
         $delete = TRUE;
         $instance_settings = unserialize($result->inclusion_settings);
         foreach ($instance_settings as $setting_key => $instance_setting) {
-          if ($instance_setting != $bundle_settings->get($setting_key)) {
+          if ($instance_setting != $settings[$setting_key]) {
             $delete = FALSE;
             break;
           }
         }
         if ($delete) {
-          $this->db->delete('simple_sitemap_entity_overrides')
-            ->condition('id', $result->id)
-            ->execute();
+          $delete_instances[] = $result->id;
         }
       }
+      if (!empty($delete_instances)) {
+        $this->db->delete('simple_sitemap_entity_overrides')
+          ->condition('id', $delete_instances, 'IN')
+          ->execute();
+      }
     }
     else {
       //todo: log error
@@ -376,21 +452,39 @@ class Simplesitemap {
   public function getBundleSettings($entity_type_id = NULL, $bundle_name = NULL) {
     if (NULL !== $entity_type_id) {
       $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
-      $settings = $this->configFactory
+      $bundle_settings = $this->configFactory
         ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
         ->get();
-      $bundle_settings = !empty($settings) ? $settings : FALSE;
+      return !empty($bundle_settings) ? $bundle_settings : FALSE;
     }
     else {
-      $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings");
-      $bundle_settings = [];
-      foreach($config_names as $config_name) {
+      $config_names = $this->configFactory->listAll('simple_sitemap.bundle_settings.');
+      $all_settings = [];
+      foreach ($config_names as $config_name) {
         $config_name_parts = explode('.', $config_name);
-        $bundle_settings[$config_name_parts[2]][$config_name_parts[3]]
-          = $this->configFactory->get($config_name)->get();
+        $all_settings[$config_name_parts[2]][$config_name_parts[3]] = $this->configFactory->get($config_name)->get();
+      }
+      return $all_settings;
+    }
+  }
+
+  /**
+   * Supplements all missing link setting with default values.
+   *
+   * @param string $type
+   *  'entity'|'custom'
+   * @param array &$settings
+   * @param array $overrides
+   */
+  public static function supplementDefaultSettings($type, &$settings, $overrides = []) {
+    foreach (self::$allowedLinkSettings[$type] as $allowed_link_setting) {
+      if (!isset($settings[$allowed_link_setting])
+        && isset(self::$linkSettingDefaults[$allowed_link_setting])) {
+        $settings[$allowed_link_setting] = isset($overrides[$allowed_link_setting])
+          ? $overrides[$allowed_link_setting]
+          : self::$linkSettingDefaults[$allowed_link_setting];
       }
     }
-    return $bundle_settings;
   }
 
   /**
@@ -403,19 +497,16 @@ class Simplesitemap {
    * @return $this
    */
   public function setEntityInstanceSettings($entity_type_id, $id, $settings) {
-
     $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($id);
-    $bundle_name = $this->entityHelper->getEntityInstanceBundleName($entity);
-    $bundle_settings = $this->configFactory
-      ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
-      ->get();
-
+    $bundle_settings = $this->getBundleSettings(
+      $entity_type_id, $this->entityHelper->getEntityInstanceBundleName($entity)
+    );
     if (!empty($bundle_settings)) {
 
       // Check if overrides are different from bundle setting before saving.
       $override = FALSE;
       foreach ($settings as $key => $setting) {
-        if ($setting != $bundle_settings[$key]) {
+        if (!isset($bundle_settings[$key]) || $setting != $bundle_settings[$key]) {
           $override = TRUE;
           break;
         }
@@ -429,8 +520,7 @@ class Simplesitemap {
           ->fields([
             'entity_type' => $entity_type_id,
             'entity_id' => $id,
-            'inclusion_settings' => serialize($settings),
-          ])
+            'inclusion_settings' => serialize(array_merge($bundle_settings, $settings)),])
           ->execute();
       }
       // Else unset override.
@@ -526,62 +616,51 @@ class Simplesitemap {
    * @param array $settings
    *
    * @return $this
+   *
+   * @todo Validate $settings and throw exceptions
    */
-  public function addCustomLink($path, $settings) {
+  public function addCustomLink($path, $settings = []) {
     if (!$this->pathValidator->isValid($path)) {
       // todo: log error.
       return $this;
     }
-    if ($path[0] != '/') {
+    if ($path[0] !== '/') {
       // todo: log error.
       return $this;
     }
 
-    $custom_links = $this->getCustomLinks();
+    $custom_links = $this->getCustomLinks(FALSE);
     foreach ($custom_links as $key => $link) {
-      if ($link['path'] == $path) {
+      if ($link['path'] === $path) {
         $link_key = $key;
         break;
       }
     }
     $link_key = isset($link_key) ? $link_key : count($custom_links);
-    $custom_links[$link_key]['path'] = $path;
-    $this->addLinkSettings('custom', $settings, $custom_links[$link_key]); //todo: dirty
-    $this->configFactory->getEditable("simple_sitemap.custom")
+    $custom_links[$link_key] = ['path' => $path] + $settings;
+    $this->configFactory->getEditable('simple_sitemap.custom')
       ->set('links', $custom_links)->save();
     return $this;
   }
 
-  /**
-   *
-   */
-  protected function addLinkSettings($type, $settings, &$target) {
-    foreach ($settings as $setting_key => $setting) {
-      if (in_array($setting_key, self::$allowed_link_settings[$type])) {
-        switch ($setting_key) {
-          case 'priority':
-            if (!FormHelper::isValidPriority($setting)) {
-              // todo: log error.
-              continue;
-            }
-            break;
-
-          // todo: add index check.
-        }
-        $target[$setting_key] = $setting;
-      }
-    }
-  }
-
   /**
    * Returns an array of custom paths and their sitemap settings.
    *
+   * @param bool $supplement_default_settings
    * @return array
    */
-  public function getCustomLinks() {
+  public function getCustomLinks($supplement_default_settings = TRUE) {
     $custom_links = $this->configFactory
       ->get('simple_sitemap.custom')
       ->get('links');
+
+    if ($supplement_default_settings) {
+      foreach ($custom_links as $i => $link_settings) {
+        self::supplementDefaultSettings('custom', $link_settings);
+        $custom_links[$i] = $link_settings;
+      }
+    }
+
     return $custom_links !== NULL ? $custom_links : [];
   }
 
@@ -594,7 +673,7 @@ class Simplesitemap {
    */
   public function getCustomLink($path) {
     foreach ($this->getCustomLinks() as $key => $link) {
-      if ($link['path'] == $path) {
+      if ($link['path'] === $path) {
         return $link;
       }
     }
@@ -609,12 +688,12 @@ class Simplesitemap {
    * @return $this
    */
   public function removeCustomLink($path) {
-    $custom_links = $this->getCustomLinks();
+    $custom_links = $this->getCustomLinks(FALSE);
     foreach ($custom_links as $key => $link) {
-      if ($link['path'] == $path) {
+      if ($link['path'] === $path) {
         unset($custom_links[$key]);
         $custom_links = array_values($custom_links);
-        $this->configFactory->getEditable("simple_sitemap.custom")
+        $this->configFactory->getEditable('simple_sitemap.custom')
           ->set('links', $custom_links)->save();
         break;
       }
@@ -628,7 +707,7 @@ class Simplesitemap {
    * @return $this
    */
   public function removeCustomLinks() {
-    $this->configFactory->getEditable("simple_sitemap.custom")
+    $this->configFactory->getEditable('simple_sitemap.custom')
       ->set('links', [])->save();
     return $this;
   }