Simplesitemap.php 18.8 KB
Newer Older
1 2
<?php

Pawel G's avatar
Pawel G committed
3
namespace Drupal\simple_sitemap;
4

5
use Drupal\Core\Entity\ContentEntityTypeInterface;
6
use Drupal\simple_sitemap\Form\FormHelper;
Pawel G's avatar
Pawel G committed
7 8 9
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Path\PathValidator;
Pawel G's avatar
Pawel G committed
10 11 12
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Datetime\DateFormatter;
13

14
/**
Pawel G's avatar
Pawel G committed
15 16
 * Class Simplesitemap.
 *
Pawel G's avatar
Pawel G committed
17
 * @package Drupal\simple_sitemap
18 19 20
 */
class Simplesitemap {

21
  private $sitemapGenerator;
22 23
  private $configFactory;
  private $db;
24
  private $entityQuery;
25
  private $entityTypeManager;
26
  private $pathValidator;
27 28
  private static $allowed_link_settings = [
    'entity' => ['index', 'priority'],
Pawel G's avatar
Pawel G committed
29
    'custom' => ['priority'],
30
  ];
31

32 33
  /**
   * Simplesitemap constructor.
Pawel G's avatar
Pawel G committed
34 35 36 37 38 39 40
   * @param \Drupal\simple_sitemap\SitemapGenerator $sitemapGenerator
   * @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
41
   */
42
  public function __construct(
Pawel G's avatar
Pawel G committed
43
    SitemapGenerator $sitemapGenerator,
Pawel G's avatar
Pawel G committed
44
    ConfigFactory $configFactory,
Pawel G's avatar
Pawel G committed
45
    Connection $database,
Pawel G's avatar
Pawel G committed
46
    QueryFactory $entityQuery,
Pawel G's avatar
Pawel G committed
47 48
    EntityTypeManagerInterface $entityTypeManager,
    PathValidator $pathValidator,
49
    DateFormatter $dateFormatter
50 51
  ) {
    $this->sitemapGenerator = $sitemapGenerator;
Pawel G's avatar
Pawel G committed
52
    $this->configFactory = $configFactory;
53
    $this->db = $database;
54
    $this->entityQuery = $entityQuery;
55
    $this->entityTypeManager = $entityTypeManager;
56
    $this->pathValidator = $pathValidator;
57
    $this->dateFormatter = $dateFormatter;
58 59
  }

60
  /**
61
   * Fetches all sitemap chunks indexed by chunk ID.
Pawel G's avatar
Pawel G committed
62
   *
63
   * @return string
Pawel G's avatar
Pawel G committed
64
   */
Pawel G's avatar
Pawel G committed
65
  private function fetchSitemapChunks() {
66
    return $this->db
67 68 69 70
      ->query("SELECT * FROM {simple_sitemap}")
      ->fetchAllAssoc('id');
  }

71 72
  /**
   * Enables sitemap support for an entity type. Enabled entity types show
73 74
   * sitemap settings on their bundle setting forms. If an enabled entity type
   * features bundles (e.g. 'node'), it needs to be set up with
75 76 77
   * setBundleSettings() as well.
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
78
   *   Entity type id like 'node'.
79
   *
Pawel G's avatar
Pawel G committed
80
   * @return $this
81 82
   */
  public function enableEntityType($entity_type_id) {
83 84 85 86
    $enabled_entity_types = $this->getSetting('enabled_entity_types');
    if (!in_array($entity_type_id, $enabled_entity_types)) {
      $enabled_entity_types[] = $entity_type_id;
      $this->saveSetting('enabled_entity_types', $enabled_entity_types);
87
    }
Pawel G's avatar
Pawel G committed
88
    return $this;
89 90 91 92 93 94 95 96
  }

  /**
   * Disables sitemap support for an entity type. Disabling support for an
   * entity type deletes its sitemap settings permanently and removes sitemap
   * settings from entity forms.
   *
   * @param string $entity_type_id
97
   *  Entity type id like 'node'.
98
   *
Pawel G's avatar
Pawel G committed
99
   * @return $this
100 101
   */
  public function disableEntityType($entity_type_id) {
102 103 104 105 106

    // Updating settings.
    $enabled_entity_types = $this->getSetting('enabled_entity_types');
    if (($key = array_search($entity_type_id, $enabled_entity_types)) !== FALSE) {
      unset ($enabled_entity_types[$key]);
107
      $this->saveSetting('enabled_entity_types', array_values($enabled_entity_types));
108 109 110 111 112 113
    }

    // Deleting inclusion settings.
    $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings.$entity_type_id");
    foreach($config_names as $config_name) {
      $this->configFactory->getEditable($config_name)->delete();
114
    }
115 116 117

    // Deleting entity overrides.
    $this->removeEntityInstanceSettings($entity_type_id);
Pawel G's avatar
Pawel G committed
118
    return $this;
119 120 121
  }

  /**
Pawel G's avatar
Pawel G committed
122
   * Sets sitemap settings for a non-bundle entity type (e.g. user) or a bundle
123 124 125
   * of an entity type (e.g. page).
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
126
   *   Entity type id like 'node' the bundle belongs to.
127
   * @param string $bundle_name
Pawel G's avatar
Pawel G committed
128
   *   Name of the bundle. NULL if entity type has no bundles.
129
   * @param array $settings
Pawel G's avatar
Pawel G committed
130 131
   *   An array of sitemap settings for this bundle/entity type.
   *   Example: ['index' => TRUE, 'priority' => 0.5].
Pawel G's avatar
Pawel G committed
132 133
   *
   * @return $this
134 135
   */
  public function setBundleSettings($entity_type_id, $bundle_name = NULL, $settings) {
136

137
    $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
138

139 140 141 142 143 144 145 146 147 148
    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();
    }
    //todo: Use addLinkSettings()?
149 150

    // Delete entity overrides which are identical to new bundle setting.
151 152 153 154 155 156 157 158 159
    $sitemap_entity_types = $this->getSitemapEntityTypes();
    if (isset($sitemap_entity_types[$entity_type_id])) {
      $entity_type = $sitemap_entity_types[$entity_type_id];
      $keys = $entity_type->getKeys();
      $keys['bundle'] = $entity_type_id == 'menu_link_content' ? 'menu_name' : $keys['bundle'];

      $query = $this->entityQuery->get($entity_type_id);
      if (!$this->entityTypeIsAtomic($entity_type_id)) {
        $query->condition($keys['bundle'], $bundle_name);
160
      }
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
      $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);
      if (!empty($entity_ids)) {
        $query->condition('o.entity_id', $entity_ids, 'IN');
      }
      $results = $query->execute()
        ->fetchAll();

      foreach($results 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)) {
            $delete = FALSE;
            break;
          }
        }
        if ($delete) {
          $this->db->delete('simple_sitemap_entity_overrides')
            ->condition('id', $result->id)
            ->execute();
        }
189 190
      }
    }
191 192 193
    else {
      //todo: log error
    }
Pawel G's avatar
Pawel G committed
194
    return $this;
195 196
  }

197
  /**
198 199
   * Gets sitemap settings for an entity bundle, a non-bundle entity type or for
   * all entity types and their bundles.
200
   *
201 202 203
   * @param string|null $entity_type_id
   *  If set to null, sitemap settings for all entity types and their bundles
   *  are fetched.
204 205 206
   * @param string|null $bundle_name
   *
   * @return array|false
207 208
   *  Array of sitemap settings or array of entity types with their settings.
   *  False if entity type does not exist.
209
   */
210 211 212 213 214 215 216
  public function getBundleSettings($entity_type_id = NULL, $bundle_name = NULL) {
    if (!is_null($entity_type_id)) {
      $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
      $settings = $this->configFactory
        ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
        ->get();
      $bundle_settings = !empty($settings) ? $settings : FALSE;
217
    }
218 219 220 221 222 223 224 225 226 227
    else {
      $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings");
      $bundle_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();
      }
    }
    return $bundle_settings;
228 229
  }

Pawel G's avatar
Pawel G committed
230 231 232
  /**
   * Overrides entity bundle/entity type sitemap settings for a single entity.
   *
Pawel G's avatar
Pawel G committed
233 234 235
   * @param string $entity_type_id
   * @param int $id
   * @param array $settings
Pawel G's avatar
Pawel G committed
236
   *
Pawel G's avatar
Pawel G committed
237 238
   * @return $this
   */
239
  public function setEntityInstanceSettings($entity_type_id, $id, $settings) {
240

241 242
    $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($id);
    $bundle_name = $this->getEntityInstanceBundleName($entity);
243 244 245 246 247
    $bundle_settings = $this->configFactory
      ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
      ->get();

    if (!empty($bundle_settings)) {
248 249 250 251

      // Check if overrides are different from bundle setting before saving.
      $override = FALSE;
      foreach ($settings as $key => $setting) {
252
        if ($setting != $bundle_settings[$key]) {
253 254 255 256
          $override = TRUE;
          break;
        }
      }
Pawel G's avatar
Pawel G committed
257 258
      // Save overrides for this entity if something is different.
      if ($override) {
259 260 261 262 263 264 265 266 267 268
        $this->db->merge('simple_sitemap_entity_overrides')
          ->key([
            'entity_type' => $entity_type_id,
            'entity_id' => $id])
          ->fields([
            'entity_type' => $entity_type_id,
            'entity_id' => $id,
            'inclusion_settings' => serialize($settings),
          ])
          ->execute();
269
      }
Pawel G's avatar
Pawel G committed
270 271
      // Else unset override.
      else {
272
        $this->removeEntityInstanceSettings($entity_type_id, $id);
273
      }
274 275 276
    }
    else {
      //todo: log error
277
    }
Pawel G's avatar
Pawel G committed
278
    return $this;
279 280
  }

Pawel G's avatar
Pawel G committed
281
  /**
282 283
   * Gets sitemap settings for an entity instance which overrides the sitemap
   * settings of its bundle.
Pawel G's avatar
Pawel G committed
284
   *
Pawel G's avatar
Pawel G committed
285
   * @param string $entity_type_id
286
   * @param int $id
Pawel G's avatar
Pawel G committed
287
   *
288
   * @return array
Pawel G's avatar
Pawel G committed
289
   */
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
  public function getEntityInstanceSettings($entity_type_id, $id) {
    $results = $this->db->select('simple_sitemap_entity_overrides', 'o')
      ->fields('o', ['inclusion_settings'])
      ->condition('o.entity_type', $entity_type_id)
      ->condition('o.entity_id', $id)
      ->execute()
      ->fetchField();

    if (!empty($results)) {
      return unserialize($results);
    }
    else {
      $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($id);
      $bundle_name = $this->getEntityInstanceBundleName($entity);
      return $this->getBundleSettings($entity_type_id, $bundle_name);
305 306 307
    }
  }

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
  /**
   * Removes sitemap settings for an entity that overrides the sitemap settings
   * of its bundle.
   *
   * @param string $entity_type_id
   * @param string|null $entity_ids
   *
   * @return $this
   */
  public function removeEntityInstanceSettings($entity_type_id, $entity_ids = NULL) {
    $query = $this->db->delete('simple_sitemap_entity_overrides')
      ->condition('entity_type', $entity_type_id);
    if (!is_null($entity_ids)) {
      $entity_ids = !is_array($entity_ids) ? [$entity_ids] : $entity_ids;
      $query->condition('entity_id', $entity_ids, 'IN');
    }
    $query->execute();
    return $this;
  }

Pawel G's avatar
Pawel G committed
328 329 330 331
  /**
   * Checks if an entity bundle (or a non-bundle entity type) is set to be
   * indexed in the sitemap settings.
   *
332 333
   * @param string $entity_type_id
   * @param string|null $bundle_name
Pawel G's avatar
Pawel G committed
334
   *
Pawel G's avatar
Pawel G committed
335 336
   * @return bool
   */
337
  public function bundleIsIndexed($entity_type_id, $bundle_name = NULL) {
338 339 340 341
    $settings = $this->getBundleSettings($entity_type_id, $bundle_name);
    return !empty($settings['index']);
  }

Pawel G's avatar
Pawel G committed
342 343 344
  /**
   * Checks if an entity type is enabled in the sitemap settings.
   *
345
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
346
   *
Pawel G's avatar
Pawel G committed
347 348
   * @return bool
   */
349
  public function entityTypeIsEnabled($entity_type_id) {
350
    return in_array($entity_type_id, $this->getSetting('enabled_entity_types', []));
351 352
  }

Pawel G's avatar
Pawel G committed
353
  /**
354
   * Stores a custom path along with its sitemap settings to configuration.
Pawel G's avatar
Pawel G committed
355
   *
Pawel G's avatar
Pawel G committed
356 357
   * @param string $path
   * @param array $settings
Pawel G's avatar
Pawel G committed
358
   *
Pawel G's avatar
Pawel G committed
359
   * @return $this
Pawel G's avatar
Pawel G committed
360
   */
361
  public function addCustomLink($path, $settings) {
Pawel G's avatar
Pawel G committed
362 363 364 365 366 367 368 369
    if (!$this->pathValidator->isValid($path)) {
      // todo: log error.
      return $this;
    }
    if ($path[0] != '/') {
      // todo: log error.
      return $this;
    }
Pawel G's avatar
Pawel G committed
370

371
    $custom_links = $this->getCustomLinks();
Pawel G's avatar
Pawel G committed
372
    foreach ($custom_links as $key => $link) {
373 374 375 376 377 378 379
      if ($link['path'] == $path) {
        $link_key = $key;
        break;
      }
    }
    $link_key = isset($link_key) ? $link_key : count($custom_links);
    $custom_links[$link_key]['path'] = $path;
380 381
    $this->addLinkSettings('custom', $settings, $custom_links[$link_key]); //todo: dirty
    $this->configFactory->getEditable("simple_sitemap.custom")
382
      ->set('links', $custom_links)->save();
Pawel G's avatar
Pawel G committed
383
    return $this;
384 385
  }

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
  /**
   *
   */
  private 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.
   *
   * @return array
   */
  public function getCustomLinks() {
    $custom_links = $this->configFactory
      ->get('simple_sitemap.custom')
415
      ->get('links');
416 417 418
    return $custom_links;
  }

Pawel G's avatar
Pawel G committed
419 420 421
  /**
   * Returns settings for a custom path added to the sitemap settings.
   *
Pawel G's avatar
Pawel G committed
422
   * @param string $path
Pawel G's avatar
Pawel G committed
423
   *
Pawel G's avatar
Pawel G committed
424
   * @return array|false
Pawel G's avatar
Pawel G committed
425
   */
426
  public function getCustomLink($path) {
427
    foreach ($this->getCustomLinks() as $key => $link) {
428
      if ($link['path'] == $path) {
429
        return $link;
430 431 432 433 434
      }
    }
    return FALSE;
  }

Pawel G's avatar
Pawel G committed
435 436 437
  /**
   * Removes a custom path from the sitemap settings.
   *
Pawel G's avatar
Pawel G committed
438
   * @param string $path
Pawel G's avatar
Pawel G committed
439
   *
Pawel G's avatar
Pawel G committed
440 441
   * @return $this
   */
442
  public function removeCustomLink($path) {
443
    $custom_links = $this->getCustomLinks();
Pawel G's avatar
Pawel G committed
444
    foreach ($custom_links as $key => $link) {
445 446 447
      if ($link['path'] == $path) {
        unset($custom_links[$key]);
        $custom_links = array_values($custom_links);
448
        $this->configFactory->getEditable("simple_sitemap.custom")
449
          ->set('links', $custom_links)->save();
450
        break;
451 452
      }
    }
Pawel G's avatar
Pawel G committed
453
    return $this;
454 455
  }

Pawel G's avatar
Pawel G committed
456 457
  /**
   * Removes all custom paths from the sitemap settings.
Pawel G's avatar
Pawel G committed
458 459
   *
   * @return $this
Pawel G's avatar
Pawel G committed
460
   */
461
  public function removeCustomLinks() {
462
    $this->configFactory->getEditable("simple_sitemap.custom")
463
      ->set('links', [])->save();
Pawel G's avatar
Pawel G committed
464
    return $this;
465 466
  }

Pawel G's avatar
Pawel G committed
467
  /**
468
   * Gets an entity's bundle name.
Pawel G's avatar
Pawel G committed
469
   *
470 471
   * @param string $entity
   * @return string
Pawel G's avatar
Pawel G committed
472
   */
Pawel G's avatar
Pawel G committed
473 474
  public function getEntityInstanceBundleName($entity) {
    return $entity->getEntityTypeId() == 'menu_link_content'
475
      // Menu fix.
Pawel G's avatar
Pawel G committed
476
      ? $entity->getMenuName() : $entity->bundle();
Pawel G's avatar
Pawel G committed
477 478
  }

Pawel G's avatar
Pawel G committed
479
  /**
480 481 482
   * Gets the entity type id for a bundle.
   *
   * @param string $entity
Pawel G's avatar
Pawel G committed
483 484
   * @return string
   */
Pawel G's avatar
Pawel G committed
485 486
  public function getBundleEntityTypeId($entity) {
    return $entity->getEntityTypeId() == 'menu'
487
      // Menu fix.
Pawel G's avatar
Pawel G committed
488
      ? 'menu_link_content' : $entity->getEntityType()->getBundleOf();
Pawel G's avatar
Pawel G committed
489 490
  }

491 492 493 494
  /**
   * Returns the whole sitemap, a requested sitemap chunk,
   * or the sitemap index file.
   *
Pawel G's avatar
Pawel G committed
495
   * @param int $chunk_id
496
   *
Pawel G's avatar
Pawel G committed
497
   * @return string|false
Pawel G's avatar
Pawel G committed
498 499 500 501
   *   If no sitemap id provided, either a sitemap index is returned, or the
   *   whole sitemap, if the amount of links does not exceed the max links
   *   setting. If a sitemap id is provided, a sitemap chunk is returned. False
   *   if sitemap is not retrievable from the database.
502
   */
Pawel G's avatar
Pawel G committed
503 504
  public function getSitemap($chunk_id = NULL) {
    $chunks = $this->fetchSitemapChunks();
505
    if (is_null($chunk_id) || !isset($chunks[$chunk_id])) {
506 507

      // Return sitemap index, if there are multiple sitemap chunks.
Pawel G's avatar
Pawel G committed
508 509
      if (count($chunks) > 1) {
        return $this->getSitemapIndex($chunks);
510
      }
Pawel G's avatar
Pawel G committed
511 512
      // Return sitemap if there is only one chunk.
      else {
Pawel G's avatar
Pawel G committed
513 514
        if (isset($chunks[1])) {
          return $chunks[1]->sitemap_string;
515 516
        }
        return FALSE;
517 518
      }
    }
Pawel G's avatar
Pawel G committed
519 520
    // Return specific sitemap chunk.
    else {
Pawel G's avatar
Pawel G committed
521
      return $chunks[$chunk_id]->sitemap_string;
522
    }
523 524
  }

525 526
  /**
   * Generates the sitemap for all languages and saves it to the db.
527 528
   *
   * @param string $from
Pawel G's avatar
Pawel G committed
529 530
   *   Can be 'form', 'cron', 'drush' or 'nobatch'.
   *   This decides how the batch process is to be run.
531
   */
532
  public function generateSitemap($from = 'form') {
533 534 535 536
    $this->sitemapGenerator
      ->setGenerator($this)
      ->setGenerateFrom($from)
      ->startGeneration();
537 538
  }

539
  /**
540 541
   * Generates and returns the sitemap index as string.
   *
Pawel G's avatar
Pawel G committed
542
   * @param array $chunks
Pawel G's avatar
Pawel G committed
543
   *   Sitemap chunks which to generate the index from.
544
   *
545
   * @return string
Pawel G's avatar
Pawel G committed
546
   *   The sitemap index.
547
   */
Pawel G's avatar
Pawel G committed
548
  private function getSitemapIndex($chunks) {
549 550
    return $this->sitemapGenerator
      ->setGenerator($this)
Pawel G's avatar
Pawel G committed
551
      ->generateSitemapIndex($chunks);
Pawel G's avatar
Pawel G committed
552 553
  }

554
  /**
555 556
   * Returns a specific sitemap setting or a default value if setting does not
   * exist.
557 558
   *
   * @param string $name
Pawel G's avatar
Pawel G committed
559
   *   Name of the setting, like 'max_links'.
560
   *
561
   * @param mixed $default
Pawel G's avatar
Pawel G committed
562
   *   Value to be returned if the setting does not exist in the configuration.
563
   *
564
   * @return mixed
565
   *   The current setting from configuration or a default value.
566
   */
567
  public function getSetting($name, $default = FALSE) {
568 569 570 571
    $setting = $this->configFactory
      ->get('simple_sitemap.settings')
      ->get($name);
    return !is_null($setting) ? $setting : $default;
572
  }
573

574
  /**
575
   * Stores a specific sitemap setting in configuration.
576
   *
Pawel G's avatar
Pawel G committed
577
   * @param string $name
Pawel G's avatar
Pawel G committed
578
   *   Setting name, like 'max_links'.
Pawel G's avatar
Pawel G committed
579
   * @param mixed $setting
Pawel G's avatar
Pawel G committed
580
   *   The setting to be saved.
Pawel G's avatar
Pawel G committed
581 582
   *
   * @return $this
583
   */
584
  public function saveSetting($name, $setting) {
585 586
    $this->configFactory->getEditable("simple_sitemap.settings")
      ->set($name, $setting)->save();
Pawel G's avatar
Pawel G committed
587
    return $this;
588
  }
589

Pawel G's avatar
Pawel G committed
590 591
  /**
   * Returns a 'time ago' string of last timestamp generation.
592
   *
Pawel G's avatar
Pawel G committed
593
   * @return string|false
Pawel G's avatar
Pawel G committed
594
   *   Formatted timestamp of last sitemap generation, otherwise FALSE.
Pawel G's avatar
Pawel G committed
595
   */
596
  public function getGeneratedAgo() {
597
    $chunks = $this->fetchSitemapChunks();
Pawel G's avatar
Pawel G committed
598
    if (isset($chunks[1]->sitemap_created)) {
599
      return $this->dateFormatter
600
        ->formatInterval(REQUEST_TIME - $chunks[1]->sitemap_created);
601 602 603
    }
    return FALSE;
  }
Pawel G's avatar
Pawel G committed
604

605
  /**
606
   * Returns objects of entity types that can be indexed.
607 608
   *
   * @return array
Pawel G's avatar
Pawel G committed
609
   *   Objects of entity types that can be indexed by the sitemap.
610
   */
611 612
  public function getSitemapEntityTypes() {
    $entity_types = $this->entityTypeManager->getDefinitions();
613 614

    foreach ($entity_types as $entity_type_id => $entity_type) {
615 616 617
      if (!$entity_type instanceof ContentEntityTypeInterface
        || !method_exists($entity_type, 'getBundleEntityType')
        || !$entity_type->hasLinkTemplate('canonical')) {
618 619 620 621 622
        unset($entity_types[$entity_type_id]);
      }
    }
    return $entity_types;
  }
623

Pawel G's avatar
Pawel G committed
624
  /**
625 626 627
   * Checks whether an entity type does not provide bundles.
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
628 629
   * @return bool
   */
630
  public function entityTypeIsAtomic($entity_type_id) {
Pawel G's avatar
Pawel G committed
631 632
    // Menu fix.
    if ($entity_type_id == 'menu_link_content') {
633
      return FALSE;
Pawel G's avatar
Pawel G committed
634
    }
635

636
    $sitemap_entity_types = $this->getSitemapEntityTypes();
637 638 639 640 641 642
    if (isset($sitemap_entity_types[$entity_type_id])) {
      $entity_type = $sitemap_entity_types[$entity_type_id];
      if (empty($entity_type->getBundleEntityType())) {
        return TRUE;
      }
    }
Pawel G's avatar
Pawel G committed
643 644
    // todo: throw exception.
    return FALSE;
645
  }
Pawel G's avatar
Pawel G committed
646

647
}