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

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

Pawel G's avatar
Pawel G committed
5 6 7
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Path\PathValidator;
Pawel G's avatar
Pawel G committed
8 9
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Datetime\DateFormatter;
10
use Drupal\Component\Datetime\Time;
11 12 13
use Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\DefaultSitemapGenerator;
use Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapGeneratorBase;
use Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapGeneratorManager;
14
use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager;
15

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

Pawel G's avatar
Pawel G committed
22 23 24
  /**
   * @var \Drupal\simple_sitemap\EntityHelper
   */
25
  protected $entityHelper;
Pawel G's avatar
Pawel G committed
26 27 28 29

  /**
   * @var \Drupal\Core\Config\ConfigFactory
   */
30
  protected $configFactory;
Pawel G's avatar
Pawel G committed
31 32 33 34

  /**
   * @var \Drupal\Core\Database\Connection
   */
35
  protected $db;
Pawel G's avatar
Pawel G committed
36 37 38 39

  /**
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
40
  protected $entityTypeManager;
Pawel G's avatar
Pawel G committed
41 42 43 44

  /**
   * @var \Drupal\Core\Path\PathValidator
   */
45
  protected $pathValidator;
Pawel G's avatar
Pawel G committed
46

47 48 49 50 51
  /**
   * @var \Drupal\Core\Datetime\DateFormatter
   */
  protected $dateFormatter;

52 53 54 55 56
  /**
   * @var \Drupal\Component\Datetime\Time
   */
  protected $time;

57
  /**
58
   * @var \Drupal\simple_sitemap\Batch
59 60 61 62 63 64 65 66
   */
  protected $batch;

  /**
   * @var \Drupal\Core\Extension\ModuleHandler
   */
  protected $moduleHandler;

67 68 69 70 71
  /**
   * @var \Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager
   */
  protected $urlGeneratorManager;

72 73 74 75 76
  /**
   * @var \Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapGeneratorManager
   */
  protected $sitemapGeneratorManager;

Pawel G's avatar
Pawel G committed
77 78 79
  /**
   * @var array
   */
Pawel G's avatar
Pawel G committed
80
  protected static $allowedLinkSettings = [
81
    'entity' => ['index', 'priority', 'changefreq', 'include_images'],
82 83 84
    'custom' => ['priority', 'changefreq'],
  ];

Pawel G's avatar
Pawel G committed
85 86 87 88
  /**
   * @var array
   */
  protected static $linkSettingDefaults = [
89
    'index' => 1,
90
    'priority' => 0.5,
91
    'changefreq' => '',
92
    'include_images' => 0,
93
  ];
94

95 96
  /**
   * Simplesitemap constructor.
97 98
   * @param \Drupal\simple_sitemap\EntityHelper $entity_helper
   * @param \Drupal\Core\Config\ConfigFactory $config_factory
Pawel G's avatar
Pawel G committed
99
   * @param \Drupal\Core\Database\Connection $database
100 101 102
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   * @param \Drupal\Core\Path\PathValidator $path_validator
   * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
103
   * @param \Drupal\Component\Datetime\Time $time
104
   * @param \Drupal\simple_sitemap\Batch $batch
105 106
   * @param \Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager $url_generator_manager
   * @param \Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapGeneratorManager $sitemap_generator_manager
107
   */
108
  public function __construct(
109 110
    EntityHelper $entity_helper,
    ConfigFactory $config_factory,
Pawel G's avatar
Pawel G committed
111
    Connection $database,
112 113 114
    EntityTypeManagerInterface $entity_type_manager,
    PathValidator $path_validator,
    DateFormatter $date_formatter,
115 116
    Time $time,
    Batch $batch,
117 118
    UrlGeneratorManager $url_generator_manager,
    SitemapGeneratorManager $sitemap_generator_manager
119
  ) {
120 121
    $this->entityHelper = $entity_helper;
    $this->configFactory = $config_factory;
122
    $this->db = $database;
123 124 125
    $this->entityTypeManager = $entity_type_manager;
    $this->pathValidator = $path_validator;
    $this->dateFormatter = $date_formatter;
126
    $this->time = $time;
127
    $this->batch = $batch;
128 129
    $this->urlGeneratorManager = $url_generator_manager;
    $this->sitemapGeneratorManager = $sitemap_generator_manager;
130 131
  }

132
  /**
133 134
   * Returns a specific sitemap setting or a default value if setting does not
   * exist.
Pawel G's avatar
Pawel G committed
135
   *
136 137 138 139 140 141 142 143
   * @param string $name
   *   Name of the setting, like 'max_links'.
   *
   * @param mixed $default
   *   Value to be returned if the setting does not exist in the configuration.
   *
   * @return mixed
   *   The current setting from configuration or a default value.
Pawel G's avatar
Pawel G committed
144
   */
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
  public function getSetting($name, $default = FALSE) {
    $setting = $this->configFactory
      ->get('simple_sitemap.settings')
      ->get($name);
    return NULL !== $setting ? $setting : $default;
  }

  /**
   * Stores a specific sitemap setting in configuration.
   *
   * @param string $name
   *   Setting name, like 'max_links'.
   * @param mixed $setting
   *   The setting to be saved.
   *
   * @return $this
   */
  public function saveSetting($name, $setting) {
Pawel G's avatar
Pawel G committed
163
    $this->configFactory->getEditable('simple_sitemap.settings')
164 165 166 167 168 169 170 171
      ->set($name, $setting)->save();
    return $this;
  }

  /**
   * Returns the whole sitemap, a requested sitemap chunk,
   * or the sitemap index file.
   *
172 173 174
   * @param string $type
   *
   * @param int $delta
175 176 177 178 179 180 181
   *
   * @return string|false
   *   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.
   */
182 183
  public function getSitemap($type = SitemapGeneratorBase::DEFAULT_SITEMAP_TYPE, $delta = NULL) {
    $chunk_info = $this->fetchSitemapChunkInfo($type);
184

185
    if (NULL === $delta || !isset($chunk_info[$delta])) {
186 187 188 189 190 191 192 193

      if (count($chunk_info) > 1) {
        // Return sitemap index, if there are multiple sitemap chunks.
        return $this->getSitemapIndex($chunk_info);
      }
      else {
        // Return sitemap if there is only one chunk.
        return count($chunk_info) === 1
194 195
        && isset($chunk_info[SitemapGeneratorBase::FIRST_DELTA_INDEX])
          ? $this->fetchSitemapChunk($chunk_info[SitemapGeneratorBase::FIRST_DELTA_INDEX]->id)
196 197 198 199 200 201
            ->sitemap_string
          : FALSE;
      }
    }
    else {
      // Return specific sitemap chunk.
202
      return $this->fetchSitemapChunk($chunk_info[$delta]->id)->sitemap_string;
203 204 205
    }
  }

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
  /**
   * Generates and returns the sitemap index as string.
   *
   * @param array $chunk_info
   *   Array containing chunk creation timestamps keyed by chunk ID.
   *
   * @return string
   *   The sitemap index.
   */
  protected function getSitemapIndex($chunk_info) {
    return $this->sitemapGeneratorManager->createInstance('index')
      ->setSettings(['base_url' => $this->getSetting('base_url', '')])
      ->getSitemapIndex($chunk_info);
  }

221 222 223
  /**
   * Fetches all sitemap chunk timestamps keyed by chunk ID.
   *
224 225
   * @param string|null $type
   *
226 227 228
   * @return array
   *   An array containing chunk creation timestamps keyed by chunk ID.
   */
229 230 231 232 233 234 235 236 237 238 239
  protected function fetchSitemapChunkInfo($type = NULL) {
    $query = $this->db->select('simple_sitemap', 's')
      ->fields('s', ['id', 'delta', 'sitemap_created', 'type']);

    if (NULL !== $type) {
      $query->condition('s.type', $type);
    }

    $result = $query->execute();

    return NULL === $type ? $result->fetchAllAssoc('type') : $result->fetchAllAssoc('delta');
240 241
  }

242 243 244 245 246 247 248 249 250
  /**
   * Fetches a single sitemap chunk by ID.
   *
   * @param int $id
   *   The chunk ID.
   *
   * @return object
   *   A sitemap chunk object.
   */
251
  protected function fetchSitemapChunk($id) {
252 253 254 255 256
    return $this->db->query('SELECT * FROM {simple_sitemap} WHERE id = :id',
      [':id' => $id])->fetchObject();
  }

  /**
Pawel G's avatar
Pawel G committed
257
   * Generates the XML sitemap and saves it to the db.
258 259
   *
   * @param string $from
Pawel G's avatar
Pawel G committed
260
   *   Can be 'form', 'backend', 'drush' or 'nobatch'.
261
   *   This decides how the batch process is to be run.
Pawel G's avatar
Pawel G committed
262 263
   *
   * @return bool|\Drupal\simple_sitemap\Simplesitemap
264 265
   */
  public function generateSitemap($from = 'form') {
266

Pawel G's avatar
Pawel G committed
267
    $this->batch->setBatchSettings([
268
      'base_url' => $this->getSetting('base_url', ''),
269
      'batch_process_limit' => $this->getSetting('batch_process_limit', 1500),
270 271 272 273 274 275
      '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', []),
    ]);

276 277 278 279
    $this->batch->setBatchMeta(['from' => $from]);

    $sitemap_generators = $this->sitemapGeneratorManager->getDefinitions();
    $url_generators = $this->urlGeneratorManager->getDefinitions();
Pawel G's avatar
Pawel G committed
280

281 282 283 284 285
    foreach ([&$sitemap_generators, &$url_generators] as &$plugin_group) {
      usort($plugin_group, function($a, $b) {
        return $a['weight'] - $b['weight'];
      });
    }
Pawel G's avatar
Pawel G committed
286

287 288 289 290 291 292 293 294 295 296 297 298 299
    foreach ($sitemap_generators as $sitemap_generator) {
      if ($sitemap_generator['enabled'] && $sitemap_generator['settings']['list']) {
        foreach ($url_generators as $url_generator) {
          if ($url_generator['enabled']
            && $url_generator['settings']['default_sitemap_generator'] === $sitemap_generator['id']) {
            if (!empty($url_generator['settings']['instantiate_for_each_data_set'])) {
              foreach ($this->urlGeneratorManager->createInstance($url_generator['id'])->getDataSets() as $data_sets) {
                $this->batch->addOperation($url_generator['id'], $data_sets);
              }
            }
            else {
              $this->batch->addOperation($url_generator['id']);
            }
300 301
          }
        }
302
      }
303 304
    }

Pawel G's avatar
Pawel G committed
305 306
    $success = $this->batch->start();
    return $from === 'nobatch' ? $this : $success;
307 308 309 310 311
  }

  /**
   * Returns a 'time ago' string of last timestamp generation.
   *
312 313 314
   * @param string|null $type
   *
   * @return string|array|false
315 316
   *   Formatted timestamp of last sitemap generation, otherwise FALSE.
   */
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
  public function getGeneratedAgo($type = NULL) {
    $chunks = $this->fetchSitemapChunkInfo($type);
    if ($type !== NULL) {
      return isset($chunks[DefaultSitemapGenerator::FIRST_DELTA_INDEX]->sitemap_created)
        ? $this->dateFormatter
          ->formatInterval($this->time->getRequestTime() - $chunks[DefaultSitemapGenerator::FIRST_DELTA_INDEX]
              ->sitemap_created)
        : FALSE;
    }
    else {
      $time_strings = [];
//      foreach ($chunks as $sitemap_type => $type_chunks) {
//        $time_strings[$sitemap_type] = isset($type_chunks[DefaultSitemapGenerator::FIRST_DELTA_INDEX]->sitemap_created)
//          ? $type_chunks[DefaultSitemapGenerator::FIRST_DELTA_INDEX]->sitemap_created
//          : FALSE;
//    }
      // todo: Implement.
      return $time_strings;
335 336 337
    }
  }

338 339
  /**
   * Enables sitemap support for an entity type. Enabled entity types show
340 341
   * sitemap settings on their bundle setting forms. If an enabled entity type
   * features bundles (e.g. 'node'), it needs to be set up with
342 343 344
   * setBundleSettings() as well.
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
345
   *  Entity type id like 'node'.
346
   *
Pawel G's avatar
Pawel G committed
347
   * @return $this
348 349
   */
  public function enableEntityType($entity_type_id) {
350 351 352 353
    $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);
354
    }
Pawel G's avatar
Pawel G committed
355
    return $this;
356 357 358 359 360 361 362 363
  }

  /**
   * 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
364
   *  Entity type id like 'node'.
365
   *
Pawel G's avatar
Pawel G committed
366
   * @return $this
367 368
   */
  public function disableEntityType($entity_type_id) {
369 370 371

    // Updating settings.
    $enabled_entity_types = $this->getSetting('enabled_entity_types');
372
    if (FALSE !== ($key = array_search($entity_type_id, $enabled_entity_types))) {
373
      unset ($enabled_entity_types[$key]);
374
      $this->saveSetting('enabled_entity_types', array_values($enabled_entity_types));
375 376 377
    }

    // Deleting inclusion settings.
378
    $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings.$entity_type_id.");
Pawel G's avatar
Pawel G committed
379
    foreach ($config_names as $config_name) {
380
      $this->configFactory->getEditable($config_name)->delete();
381
    }
382 383 384

    // Deleting entity overrides.
    $this->removeEntityInstanceSettings($entity_type_id);
Pawel G's avatar
Pawel G committed
385
    return $this;
386 387 388
  }

  /**
Pawel G's avatar
Pawel G committed
389
   * Sets sitemap settings for a non-bundle entity type (e.g. user) or a bundle
390 391 392
   * of an entity type (e.g. page).
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
393
   *  Entity type id like 'node' the bundle belongs to.
394
   * @param string $bundle_name
Pawel G's avatar
Pawel G committed
395
   *  Name of the bundle. NULL if entity type has no bundles.
396
   * @param array $settings
Pawel G's avatar
Pawel G committed
397 398
   *  An array of sitemap settings for this bundle/entity type.
   *  Example: ['index' => TRUE, 'priority' => 0.5, 'changefreq' => 'never', 'include_images' => FALSE].
Pawel G's avatar
Pawel G committed
399 400
   *
   * @return $this
401 402
   *
   * @todo: enableEntityType automatically
403
   */
404
  public function setBundleSettings($entity_type_id, $bundle_name = NULL, $settings = []) {
405
    $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
406

Pawel G's avatar
Pawel G committed
407 408 409 410 411 412
    if (!empty($old_settings = $this->getBundleSettings($entity_type_id, $bundle_name))) {
      $settings = array_merge($old_settings, $settings);
    }
    else {
      self::supplementDefaultSettings('entity', $settings);
    }
413 414 415

    $bundle_settings = $this->configFactory
      ->getEditable("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name");
Pawel G's avatar
Pawel G committed
416
    foreach ($settings as $setting_key => $setting) {
417
      if ($setting_key === 'index') {
418 419
        $setting = intval($setting);
      }
420
      $bundle_settings->set($setting_key, $setting);
421
    }
422
    $bundle_settings->save();
423 424

    // Delete entity overrides which are identical to new bundle setting.
Pawel G's avatar
Pawel G committed
425
    $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes();
426 427 428
    if (isset($sitemap_entity_types[$entity_type_id])) {
      $entity_type = $sitemap_entity_types[$entity_type_id];
      $keys = $entity_type->getKeys();
429 430

      // Menu fix.
Pawel G's avatar
Pawel G committed
431
      $keys['bundle'] = $entity_type_id === 'menu_link_content' ? 'menu_name' : $keys['bundle'];
432

433
      $query = $this->entityTypeManager->getStorage($entity_type_id)->getQuery();
434
      if (!$this->entityHelper->entityTypeIsAtomic($entity_type_id)) {
435
        $query->condition($keys['bundle'], $bundle_name);
436
      }
437 438 439 440 441 442 443 444 445
      $entity_ids = $query->execute();

      $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');
      }

446
      $delete_instances = [];
Pawel G's avatar
Pawel G committed
447
      foreach ($query->execute()->fetchAll() as $result) {
448 449 450
        $delete = TRUE;
        $instance_settings = unserialize($result->inclusion_settings);
        foreach ($instance_settings as $setting_key => $instance_setting) {
451
          if ($instance_setting != $settings[$setting_key]) {
452 453 454 455 456
            $delete = FALSE;
            break;
          }
        }
        if ($delete) {
457
          $delete_instances[] = $result->id;
458
        }
459
      }
460 461 462 463 464
      if (!empty($delete_instances)) {
        $this->db->delete('simple_sitemap_entity_overrides')
          ->condition('id', $delete_instances, 'IN')
          ->execute();
      }
465
    }
466 467 468
    else {
      //todo: log error
    }
Pawel G's avatar
Pawel G committed
469
    return $this;
470 471
  }

472
  /**
473 474
   * Gets sitemap settings for an entity bundle, a non-bundle entity type or for
   * all entity types and their bundles.
475
   *
476 477 478
   * @param string|null $entity_type_id
   *  If set to null, sitemap settings for all entity types and their bundles
   *  are fetched.
479 480 481
   * @param string|null $bundle_name
   *
   * @return array|false
Pawel G's avatar
Pawel G committed
482 483
   *  Array of sitemap settings for an entity bundle, a non-bundle entity type
   *  or for all entity types and their bundles.
484
   *  False if entity type does not exist.
485
   */
486
  public function getBundleSettings($entity_type_id = NULL, $bundle_name = NULL) {
487
    if (NULL !== $entity_type_id) {
488
      $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
489
      $bundle_settings = $this->configFactory
490 491
        ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
        ->get();
492
      return !empty($bundle_settings) ? $bundle_settings : FALSE;
493
    }
494
    else {
Pawel G's avatar
Pawel G committed
495
      $config_names = $this->configFactory->listAll('simple_sitemap.bundle_settings.');
496
      $all_settings = [];
Pawel G's avatar
Pawel G committed
497
      foreach ($config_names as $config_name) {
498
        $config_name_parts = explode('.', $config_name);
499
        $all_settings[$config_name_parts[2]][$config_name_parts[3]] = $this->configFactory->get($config_name)->get();
500 501 502 503 504 505
      }
      return $all_settings;
    }
  }

  /**
506 507
   * Supplements all missing link setting with default values.
   *
508
   * @param string $type
Pawel G's avatar
Pawel G committed
509 510 511
   *  'entity'|'custom'
   * @param array &$settings
   * @param array $overrides
512
   */
Pawel G's avatar
Pawel G committed
513
  public static function supplementDefaultSettings($type, &$settings, $overrides = []) {
514
    foreach (self::$allowedLinkSettings[$type] as $allowed_link_setting) {
515
      if (!isset($settings[$allowed_link_setting])
Pawel G's avatar
Pawel G committed
516
        && isset(self::$linkSettingDefaults[$allowed_link_setting])) {
517 518 519
        $settings[$allowed_link_setting] = isset($overrides[$allowed_link_setting])
          ? $overrides[$allowed_link_setting]
          : self::$linkSettingDefaults[$allowed_link_setting];
520 521
      }
    }
522 523
  }

Pawel G's avatar
Pawel G committed
524 525 526
  /**
   * Overrides entity bundle/entity type sitemap settings for a single entity.
   *
Pawel G's avatar
Pawel G committed
527 528 529
   * @param string $entity_type_id
   * @param int $id
   * @param array $settings
Pawel G's avatar
Pawel G committed
530
   *
Pawel G's avatar
Pawel G committed
531 532
   * @return $this
   */
533
  public function setEntityInstanceSettings($entity_type_id, $id, $settings) {
534
    $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($id);
535 536 537
    $bundle_settings = $this->getBundleSettings(
      $entity_type_id, $this->entityHelper->getEntityInstanceBundleName($entity)
    );
538
    if (!empty($bundle_settings)) {
539 540 541 542

      // Check if overrides are different from bundle setting before saving.
      $override = FALSE;
      foreach ($settings as $key => $setting) {
543
        if (!isset($bundle_settings[$key]) || $setting != $bundle_settings[$key]) {
544 545 546 547
          $override = TRUE;
          break;
        }
      }
Pawel G's avatar
Pawel G committed
548 549
      // Save overrides for this entity if something is different.
      if ($override) {
550 551 552 553 554 555 556
        $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,
557
            'inclusion_settings' => serialize(array_merge($bundle_settings, $settings)),])
558
          ->execute();
559
      }
Pawel G's avatar
Pawel G committed
560 561
      // Else unset override.
      else {
562
        $this->removeEntityInstanceSettings($entity_type_id, $id);
563
      }
564 565 566
    }
    else {
      //todo: log error
567
    }
Pawel G's avatar
Pawel G committed
568
    return $this;
569 570
  }

Pawel G's avatar
Pawel G committed
571
  /**
572
   * Gets sitemap settings for an entity instance which overrides the sitemap
573
   * settings of its bundle, or bundle settings, if they are not overridden.
Pawel G's avatar
Pawel G committed
574
   *
Pawel G's avatar
Pawel G committed
575
   * @param string $entity_type_id
576
   * @param int $id
Pawel G's avatar
Pawel G committed
577
   *
578
   * @return array|false
Pawel G's avatar
Pawel G committed
579
   */
580 581 582 583 584 585 586 587 588
  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)) {
589
      return unserialize($results);
590 591
    }
    else {
592 593 594 595 596 597
      $entity = $this->entityTypeManager->getStorage($entity_type_id)
        ->load($id);
      return $this->getBundleSettings(
        $entity_type_id,
        $this->entityHelper->getEntityInstanceBundleName($entity)
      );
598 599 600
    }
  }

601 602 603 604 605 606 607 608 609 610 611 612
  /**
   * 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);
613
    if (NULL !== $entity_ids) {
614 615 616 617 618 619 620
      $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
621 622 623 624
  /**
   * Checks if an entity bundle (or a non-bundle entity type) is set to be
   * indexed in the sitemap settings.
   *
625 626
   * @param string $entity_type_id
   * @param string|null $bundle_name
Pawel G's avatar
Pawel G committed
627
   *
Pawel G's avatar
Pawel G committed
628 629
   * @return bool
   */
630
  public function bundleIsIndexed($entity_type_id, $bundle_name = NULL) {
631 632 633 634
    $settings = $this->getBundleSettings($entity_type_id, $bundle_name);
    return !empty($settings['index']);
  }

Pawel G's avatar
Pawel G committed
635 636 637
  /**
   * Checks if an entity type is enabled in the sitemap settings.
   *
638
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
639
   *
Pawel G's avatar
Pawel G committed
640 641
   * @return bool
   */
642
  public function entityTypeIsEnabled($entity_type_id) {
643
    return in_array($entity_type_id, $this->getSetting('enabled_entity_types', []));
644 645
  }

Pawel G's avatar
Pawel G committed
646
  /**
647
   * Stores a custom path along with its sitemap settings to configuration.
Pawel G's avatar
Pawel G committed
648
   *
Pawel G's avatar
Pawel G committed
649 650
   * @param string $path
   * @param array $settings
Pawel G's avatar
Pawel G committed
651
   *
Pawel G's avatar
Pawel G committed
652
   * @return $this
653 654
   *
   * @todo Validate $settings and throw exceptions
Pawel G's avatar
Pawel G committed
655
   */
656
  public function addCustomLink($path, $settings = []) {
Pawel G's avatar
Pawel G committed
657 658 659 660
    if (!$this->pathValidator->isValid($path)) {
      // todo: log error.
      return $this;
    }
Pawel G's avatar
Pawel G committed
661
    if ($path[0] !== '/') {
Pawel G's avatar
Pawel G committed
662 663 664
      // todo: log error.
      return $this;
    }
Pawel G's avatar
Pawel G committed
665

666
    $custom_links = $this->getCustomLinks(FALSE);
Pawel G's avatar
Pawel G committed
667
    foreach ($custom_links as $key => $link) {
668
      if ($link['path'] === $path) {
669 670 671 672 673
        $link_key = $key;
        break;
      }
    }
    $link_key = isset($link_key) ? $link_key : count($custom_links);
674
    $custom_links[$link_key] = ['path' => $path] + $settings;
Pawel G's avatar
Pawel G committed
675
    $this->configFactory->getEditable('simple_sitemap.custom')
676
      ->set('links', $custom_links)->save();
Pawel G's avatar
Pawel G committed
677
    return $this;
678 679
  }

680 681 682
  /**
   * Returns an array of custom paths and their sitemap settings.
   *
683
   * @param bool $supplement_default_settings
684 685
   * @return array
   */
686
  public function getCustomLinks($supplement_default_settings = TRUE) {
687 688
    $custom_links = $this->configFactory
      ->get('simple_sitemap.custom')
689
      ->get('links');
690 691 692

    if ($supplement_default_settings) {
      foreach ($custom_links as $i => $link_settings) {
Pawel G's avatar
Pawel G committed
693 694
        self::supplementDefaultSettings('custom', $link_settings);
        $custom_links[$i] = $link_settings;
695 696 697
      }
    }

698
    return $custom_links !== NULL ? $custom_links : [];
699 700
  }

Pawel G's avatar
Pawel G committed
701 702 703
  /**
   * Returns settings for a custom path added to the sitemap settings.
   *
Pawel G's avatar
Pawel G committed
704
   * @param string $path
Pawel G's avatar
Pawel G committed
705
   *
Pawel G's avatar
Pawel G committed
706
   * @return array|false
Pawel G's avatar
Pawel G committed
707
   */
708
  public function getCustomLink($path) {
709
    foreach ($this->getCustomLinks() as $key => $link) {
710
      if ($link['path'] === $path) {
711
        return $link;
712 713 714 715 716
      }
    }
    return FALSE;
  }

Pawel G's avatar
Pawel G committed
717 718 719
  /**
   * Removes a custom path from the sitemap settings.
   *
Pawel G's avatar
Pawel G committed
720
   * @param string $path
Pawel G's avatar
Pawel G committed
721
   *
Pawel G's avatar
Pawel G committed
722 723
   * @return $this
   */
724
  public function removeCustomLink($path) {
725
    $custom_links = $this->getCustomLinks(FALSE);
Pawel G's avatar
Pawel G committed
726
    foreach ($custom_links as $key => $link) {
727
      if ($link['path'] === $path) {
728 729
        unset($custom_links[$key]);
        $custom_links = array_values($custom_links);
Pawel G's avatar
Pawel G committed
730
        $this->configFactory->getEditable('simple_sitemap.custom')
731
          ->set('links', $custom_links)->save();
732
        break;
733 734
      }
    }
Pawel G's avatar
Pawel G committed
735
    return $this;
736 737
  }

Pawel G's avatar
Pawel G committed
738 739
  /**
   * Removes all custom paths from the sitemap settings.
Pawel G's avatar
Pawel G committed
740 741
   *
   * @return $this
Pawel G's avatar
Pawel G committed
742
   */
743
  public function removeCustomLinks() {
Pawel G's avatar
Pawel G committed
744
    $this->configFactory->getEditable('simple_sitemap.custom')
745
      ->set('links', [])->save();
Pawel G's avatar
Pawel G committed
746
    return $this;
747
  }
748
}