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

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

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

  /**
   * 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
98
   *  Entity type id like 'node'.
99
   *
Pawel G's avatar
Pawel G committed
100
   * @return $this
101 102
   */
  public function disableEntityType($entity_type_id) {
103 104 105 106 107

    // 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]);
108
      $this->saveSetting('enabled_entity_types', array_values($enabled_entity_types));
109 110 111 112 113 114
    }

    // 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();
115
    }
116 117 118

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

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

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

140 141 142 143 144 145 146 147 148 149
    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()?
150 151

    // Delete entity overrides which are identical to new bundle setting.
152 153 154 155 156 157 158 159 160
    $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);
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 189
      $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();
        }
190 191
      }
    }
192 193 194
    else {
      //todo: log error
    }
Pawel G's avatar
Pawel G committed
195
    return $this;
196 197
  }

198
  /**
199 200
   * Gets sitemap settings for an entity bundle, a non-bundle entity type or for
   * all entity types and their bundles.
201
   *
202 203 204
   * @param string|null $entity_type_id
   *  If set to null, sitemap settings for all entity types and their bundles
   *  are fetched.
205 206 207
   * @param string|null $bundle_name
   *
   * @return array|false
208 209
   *  Array of sitemap settings or array of entity types with their settings.
   *  False if entity type does not exist.
210
   */
211 212 213 214 215 216 217
  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;
218
    }
219 220 221 222 223 224 225 226 227 228
    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;
229 230
  }

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

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

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

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

Pawel G's avatar
Pawel G committed
282
  /**
283 284
   * Gets sitemap settings for an entity instance which overrides the sitemap
   * settings of its bundle.
Pawel G's avatar
Pawel G committed
285
   *
Pawel G's avatar
Pawel G committed
286
   * @param string $entity_type_id
287
   * @param int $id
Pawel G's avatar
Pawel G committed
288
   *
289
   * @return array
Pawel G's avatar
Pawel G committed
290
   */
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
  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);
306 307 308
    }
  }

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
  /**
   * 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
329 330 331 332
  /**
   * Checks if an entity bundle (or a non-bundle entity type) is set to be
   * indexed in the sitemap settings.
   *
333 334
   * @param string $entity_type_id
   * @param string|null $bundle_name
Pawel G's avatar
Pawel G committed
335
   *
Pawel G's avatar
Pawel G committed
336 337
   * @return bool
   */
338
  public function bundleIsIndexed($entity_type_id, $bundle_name = NULL) {
339 340 341 342
    $settings = $this->getBundleSettings($entity_type_id, $bundle_name);
    return !empty($settings['index']);
  }

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

Pawel G's avatar
Pawel G committed
354
  /**
355
   * Stores a custom path along with its sitemap settings to configuration.
Pawel G's avatar
Pawel G committed
356
   *
Pawel G's avatar
Pawel G committed
357 358
   * @param string $path
   * @param array $settings
Pawel G's avatar
Pawel G committed
359
   *
Pawel G's avatar
Pawel G committed
360
   * @return $this
Pawel G's avatar
Pawel G committed
361
   */
362
  public function addCustomLink($path, $settings) {
Pawel G's avatar
Pawel G committed
363 364 365 366 367 368 369 370
    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
371

372
    $custom_links = $this->getCustomLinks();
Pawel G's avatar
Pawel G committed
373
    foreach ($custom_links as $key => $link) {
374 375 376 377 378 379 380
      if ($link['path'] == $path) {
        $link_key = $key;
        break;
      }
    }
    $link_key = isset($link_key) ? $link_key : count($custom_links);
    $custom_links[$link_key]['path'] = $path;
381 382 383
    $this->addLinkSettings('custom', $settings, $custom_links[$link_key]); //todo: dirty
    $this->configFactory->getEditable("simple_sitemap.custom")
      ->setData($custom_links)->save();
Pawel G's avatar
Pawel G committed
384
    return $this;
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 415 416 417 418 419 420
  /**
   *
   */
  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')
      ->get();
    unset($custom_links['_core']);
    return $custom_links;
  }

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

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

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

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

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

493 494 495 496
  /**
   * Returns the whole sitemap, a requested sitemap chunk,
   * or the sitemap index file.
   *
Pawel G's avatar
Pawel G committed
497
   * @param int $chunk_id
498
   *
Pawel G's avatar
Pawel G committed
499
   * @return string|false
Pawel G's avatar
Pawel G committed
500 501 502 503
   *   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.
504
   */
Pawel G's avatar
Pawel G committed
505 506 507
  public function getSitemap($chunk_id = NULL) {
    $chunks = $this->fetchSitemapChunks();
    if (is_null($chunk_id) || !isset($chunks[$chunk_id])) {
508 509

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

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

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

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

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

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

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

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

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

638
    $sitemap_entity_types = $this->getSitemapEntityTypes();
639 640 641 642 643 644
    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
645 646
    // todo: throw exception.
    return FALSE;
647
  }
Pawel G's avatar
Pawel G committed
648

649
}