Simplesitemap.php 20.8 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
use Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator\UrlGeneratorManager;
12

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

Pawel G's avatar
Pawel G committed
19 20 21
  /**
   * @var \Drupal\simple_sitemap\SitemapGenerator
   */
22
  protected $sitemapGenerator;
Pawel G's avatar
Pawel G committed
23 24 25 26

  /**
   * @var \Drupal\simple_sitemap\EntityHelper
   */
27
  protected $entityHelper;
Pawel G's avatar
Pawel G committed
28 29 30 31

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

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

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

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

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

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

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

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

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

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

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

92 93 94 95 96 97
  protected static $generatorServices = [
    'simple_sitemap.custom_url_generator',
    'simple_sitemap.entity_url_generator',
    'simple_sitemap.arbitrary_url_generator',
  ];

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

135
  /**
136 137
   * Returns a specific sitemap setting or a default value if setting does not
   * exist.
Pawel G's avatar
Pawel G committed
138
   *
139 140 141 142 143 144 145 146
   * @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
147
   */
148 149 150 151 152 153 154 155 156 157 158 159 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 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  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) {
    $this->configFactory->getEditable("simple_sitemap.settings")
      ->set($name, $setting)->save();
    return $this;
  }

  /**
   * Returns the whole sitemap, a requested sitemap chunk,
   * or the sitemap index file.
   *
   * @param int $chunk_id
   *
   * @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.
   */
  public function getSitemap($chunk_id = NULL) {
    $chunk_info = $this->fetchSitemapChunkInfo();

    if (NULL === $chunk_id || !isset($chunk_info[$chunk_id])) {

      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
        && isset($chunk_info[SitemapGenerator::FIRST_CHUNK_INDEX])
          ? $this->fetchSitemapChunk(SitemapGenerator::FIRST_CHUNK_INDEX)
            ->sitemap_string
          : FALSE;
      }
    }
    else {
      // Return specific sitemap chunk.
      return $this->fetchSitemapChunk($chunk_id)->sitemap_string;
    }
  }

  /**
   * Fetches all sitemap chunk timestamps keyed by chunk ID.
   *
   * @return array
   *   An array containing chunk creation timestamps keyed by chunk ID.
   */
  protected function fetchSitemapChunkInfo() {
214
    return $this->db
215
      ->query("SELECT id, sitemap_created FROM {simple_sitemap}")
216 217 218
      ->fetchAllAssoc('id');
  }

219 220 221 222 223 224 225 226 227
  /**
   * Fetches a single sitemap chunk by ID.
   *
   * @param int $id
   *   The chunk ID.
   *
   * @return object
   *   A sitemap chunk object.
   */
228
  protected function fetchSitemapChunk($id) {
229 230 231 232 233
    return $this->db->query('SELECT * FROM {simple_sitemap} WHERE id = :id',
      [':id' => $id])->fetchObject();
  }

  /**
Pawel G's avatar
Pawel G committed
234
   * Generates the XML sitemap and saves it to the db.
235 236
   *
   * @param string $from
Pawel G's avatar
Pawel G committed
237
   *   Can be 'form', 'backend', 'drush' or 'nobatch'.
238 239 240
   *   This decides how the batch process is to be run.
   */
  public function generateSitemap($from = 'form') {
241

Pawel G's avatar
Pawel G committed
242
    $this->batch->setBatchSettings([
243 244 245 246 247 248 249 250 251
      '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,
    ]);

Pawel G's avatar
Pawel G committed
252 253 254 255 256 257 258
    $plugins = $this->urlGeneratorManager->getDefinitions();

    usort($plugins, function($a, $b) {
      return $a['weight'] - $b['weight'];
    });

    foreach ($plugins as $plugin) {
259
      $this->batch->addOperation($plugin['id']);
260 261 262
    }

    $this->batch->start();
263 264 265 266 267
  }

  /**
   * Generates and returns the sitemap index as string.
   *
Pawel G's avatar
Pawel G committed
268 269
   * @param array $chunk_info
   *   Array containing chunk creation timestamps keyed by chunk ID.
270 271 272
   *
   * @return string
   *   The sitemap index.
273 274
   *
   * @todo Need to make sure response is cached.
275
   */
Pawel G's avatar
Pawel G committed
276
  protected function getSitemapIndex($chunk_info) {
277
    return $this->sitemapGenerator
Pawel G's avatar
Pawel G committed
278
      ->setSettings(['base_url' => $this->getSetting('base_url', '')])
Pawel G's avatar
Pawel G committed
279
      ->generateSitemapIndex($chunk_info);
280 281 282 283 284 285 286 287 288 289 290 291
  }

  /**
   * Returns a 'time ago' string of last timestamp generation.
   *
   * @return string|false
   *   Formatted timestamp of last sitemap generation, otherwise FALSE.
   */
  public function getGeneratedAgo() {
    $chunks = $this->fetchSitemapChunkInfo();
    if (isset($chunks[SitemapGenerator::FIRST_CHUNK_INDEX]->sitemap_created)) {
      return $this->dateFormatter
292
        ->formatInterval($this->time->getRequestTime() - $chunks[SitemapGenerator::FIRST_CHUNK_INDEX]
293 294 295 296 297
            ->sitemap_created);
    }
    return FALSE;
  }

298 299
  /**
   * Enables sitemap support for an entity type. Enabled entity types show
300 301
   * sitemap settings on their bundle setting forms. If an enabled entity type
   * features bundles (e.g. 'node'), it needs to be set up with
302 303 304
   * setBundleSettings() as well.
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
305
   *   Entity type id like 'node'.
306
   *
Pawel G's avatar
Pawel G committed
307
   * @return $this
308 309
   */
  public function enableEntityType($entity_type_id) {
310 311 312 313
    $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);
314
    }
Pawel G's avatar
Pawel G committed
315
    return $this;
316 317 318 319 320 321 322 323
  }

  /**
   * 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
324
   *  Entity type id like 'node'.
325
   *
Pawel G's avatar
Pawel G committed
326
   * @return $this
327 328
   */
  public function disableEntityType($entity_type_id) {
329 330 331

    // Updating settings.
    $enabled_entity_types = $this->getSetting('enabled_entity_types');
332
    if (FALSE !== ($key = array_search($entity_type_id, $enabled_entity_types))) {
333
      unset ($enabled_entity_types[$key]);
334
      $this->saveSetting('enabled_entity_types', array_values($enabled_entity_types));
335 336 337
    }

    // Deleting inclusion settings.
338
    $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings.$entity_type_id.");
339 340
    foreach($config_names as $config_name) {
      $this->configFactory->getEditable($config_name)->delete();
341
    }
342 343 344

    // Deleting entity overrides.
    $this->removeEntityInstanceSettings($entity_type_id);
Pawel G's avatar
Pawel G committed
345
    return $this;
346 347 348
  }

  /**
Pawel G's avatar
Pawel G committed
349
   * Sets sitemap settings for a non-bundle entity type (e.g. user) or a bundle
350 351 352
   * of an entity type (e.g. page).
   *
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
353
   *   Entity type id like 'node' the bundle belongs to.
354
   * @param string $bundle_name
Pawel G's avatar
Pawel G committed
355
   *   Name of the bundle. NULL if entity type has no bundles.
356
   * @param array $settings
Pawel G's avatar
Pawel G committed
357
   *   An array of sitemap settings for this bundle/entity type.
358
   *   Example: ['index' => TRUE, 'priority' => 0.5, 'changefreq' => 'never', 'include_images' => FALSE].
Pawel G's avatar
Pawel G committed
359 360
   *
   * @return $this
361 362
   *
   * @todo: enableEntityType automatically
363
   */
364
  public function setBundleSettings($entity_type_id, $bundle_name = NULL, $settings = []) {
365
    $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
366

367 368 369 370 371
    $old_settings = $this->getBundleSettings($entity_type_id, $bundle_name);
    $settings = !empty($old_settings) ? array_merge($old_settings, $settings) : $this->supplementDefaultSettings('entity', $settings);

    $bundle_settings = $this->configFactory
      ->getEditable("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name");
372
    foreach($settings as $setting_key => $setting) {
373
      if ($setting_key === 'index') {
374 375
        $setting = intval($setting);
      }
376
      $bundle_settings->set($setting_key, $setting);
377
    }
378
    $bundle_settings->save();
379 380

    // Delete entity overrides which are identical to new bundle setting.
Pawel G's avatar
Pawel G committed
381
    $sitemap_entity_types = $this->entityHelper->getSupportedEntityTypes();
382 383 384
    if (isset($sitemap_entity_types[$entity_type_id])) {
      $entity_type = $sitemap_entity_types[$entity_type_id];
      $keys = $entity_type->getKeys();
385 386

      // Menu fix.
387 388
      $keys['bundle'] = $entity_type_id == 'menu_link_content' ? 'menu_name' : $keys['bundle'];

389
      $query = $this->entityTypeManager->getStorage($entity_type_id)->getQuery();
390
      if (!$this->entityHelper->entityTypeIsAtomic($entity_type_id)) {
391
        $query->condition($keys['bundle'], $bundle_name);
392
      }
393 394 395 396 397 398 399 400 401
      $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');
      }

402
      $delete_instances = [];
403
      foreach($query->execute()->fetchAll() as $result) {
404 405 406
        $delete = TRUE;
        $instance_settings = unserialize($result->inclusion_settings);
        foreach ($instance_settings as $setting_key => $instance_setting) {
407
          if ($instance_setting != $settings[$setting_key]) {
408 409 410 411 412
            $delete = FALSE;
            break;
          }
        }
        if ($delete) {
413
          $delete_instances[] = $result->id;
414
        }
415
      }
416 417 418 419 420
      if (!empty($delete_instances)) {
        $this->db->delete('simple_sitemap_entity_overrides')
          ->condition('id', $delete_instances, 'IN')
          ->execute();
      }
421
    }
422 423 424
    else {
      //todo: log error
    }
Pawel G's avatar
Pawel G committed
425
    return $this;
426 427
  }

428
  /**
429 430
   * Gets sitemap settings for an entity bundle, a non-bundle entity type or for
   * all entity types and their bundles.
431
   *
432 433 434
   * @param string|null $entity_type_id
   *  If set to null, sitemap settings for all entity types and their bundles
   *  are fetched.
435 436 437
   * @param string|null $bundle_name
   *
   * @return array|false
Pawel G's avatar
Pawel G committed
438 439
   *  Array of sitemap settings for an entity bundle, a non-bundle entity type
   *  or for all entity types and their bundles.
440
   *  False if entity type does not exist.
441
   */
442
  public function getBundleSettings($entity_type_id = NULL, $bundle_name = NULL) {
443
    if (NULL !== $entity_type_id) {
444
      $bundle_name = empty($bundle_name) ? $entity_type_id : $bundle_name;
445
      $bundle_settings = $this->configFactory
446 447
        ->get("simple_sitemap.bundle_settings.$entity_type_id.$bundle_name")
        ->get();
448
      return !empty($bundle_settings) ? $bundle_settings : FALSE;
449
    }
450
    else {
451
      $config_names = $this->configFactory->listAll("simple_sitemap.bundle_settings.");
452
      $all_settings = [];
453 454
      foreach($config_names as $config_name) {
        $config_name_parts = explode('.', $config_name);
455
        $all_settings[$config_name_parts[2]][$config_name_parts[3]] = $this->configFactory->get($config_name)->get();
456 457 458 459 460 461
      }
      return $all_settings;
    }
  }

  /**
462 463
   * Supplements all missing link setting with default values.
   *
464 465 466 467 468
   * @param string $type
   * @param array $settings
   * @return array
   */
  protected function supplementDefaultSettings($type, $settings) {
Pawel G's avatar
Pawel G committed
469
    foreach(self::$allowedLinkSettings[$type] as $allowed_link_setting) {
470
      if (!isset($settings[$allowed_link_setting])
Pawel G's avatar
Pawel G committed
471 472
        && isset(self::$linkSettingDefaults[$allowed_link_setting])) {
        $settings[$allowed_link_setting] = self::$linkSettingDefaults[$allowed_link_setting];
473 474
      }
    }
475
    return $settings;
476 477
  }

Pawel G's avatar
Pawel G committed
478 479 480
  /**
   * Overrides entity bundle/entity type sitemap settings for a single entity.
   *
Pawel G's avatar
Pawel G committed
481 482 483
   * @param string $entity_type_id
   * @param int $id
   * @param array $settings
Pawel G's avatar
Pawel G committed
484
   *
Pawel G's avatar
Pawel G committed
485 486
   * @return $this
   */
487
  public function setEntityInstanceSettings($entity_type_id, $id, $settings) {
488
    $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($id);
489 490 491
    $bundle_settings = $this->getBundleSettings(
      $entity_type_id, $this->entityHelper->getEntityInstanceBundleName($entity)
    );
492
    if (!empty($bundle_settings)) {
493 494 495 496

      // Check if overrides are different from bundle setting before saving.
      $override = FALSE;
      foreach ($settings as $key => $setting) {
497
        if (!isset($bundle_settings[$key]) || $setting != $bundle_settings[$key]) {
498 499 500 501
          $override = TRUE;
          break;
        }
      }
Pawel G's avatar
Pawel G committed
502 503
      // Save overrides for this entity if something is different.
      if ($override) {
504 505 506 507 508 509 510
        $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,
511
            'inclusion_settings' => serialize(array_merge($bundle_settings, $settings)),])
512
          ->execute();
513
      }
Pawel G's avatar
Pawel G committed
514 515
      // Else unset override.
      else {
516
        $this->removeEntityInstanceSettings($entity_type_id, $id);
517
      }
518 519 520
    }
    else {
      //todo: log error
521
    }
Pawel G's avatar
Pawel G committed
522
    return $this;
523 524
  }

Pawel G's avatar
Pawel G committed
525
  /**
526
   * Gets sitemap settings for an entity instance which overrides the sitemap
527
   * settings of its bundle, or bundle settings, if they are not overridden.
Pawel G's avatar
Pawel G committed
528
   *
Pawel G's avatar
Pawel G committed
529
   * @param string $entity_type_id
530
   * @param int $id
Pawel G's avatar
Pawel G committed
531
   *
532
   * @return array|false
Pawel G's avatar
Pawel G committed
533
   */
534 535 536 537 538 539 540 541 542
  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)) {
543
      return unserialize($results);
544 545
    }
    else {
546 547 548 549 550 551
      $entity = $this->entityTypeManager->getStorage($entity_type_id)
        ->load($id);
      return $this->getBundleSettings(
        $entity_type_id,
        $this->entityHelper->getEntityInstanceBundleName($entity)
      );
552 553 554
    }
  }

555 556 557 558 559 560 561 562 563 564 565 566
  /**
   * 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);
567
    if (NULL !== $entity_ids) {
568 569 570 571 572 573 574
      $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
575 576 577 578
  /**
   * Checks if an entity bundle (or a non-bundle entity type) is set to be
   * indexed in the sitemap settings.
   *
579 580
   * @param string $entity_type_id
   * @param string|null $bundle_name
Pawel G's avatar
Pawel G committed
581
   *
Pawel G's avatar
Pawel G committed
582 583
   * @return bool
   */
584
  public function bundleIsIndexed($entity_type_id, $bundle_name = NULL) {
585 586 587 588
    $settings = $this->getBundleSettings($entity_type_id, $bundle_name);
    return !empty($settings['index']);
  }

Pawel G's avatar
Pawel G committed
589 590 591
  /**
   * Checks if an entity type is enabled in the sitemap settings.
   *
592
   * @param string $entity_type_id
Pawel G's avatar
Pawel G committed
593
   *
Pawel G's avatar
Pawel G committed
594 595
   * @return bool
   */
596
  public function entityTypeIsEnabled($entity_type_id) {
597
    return in_array($entity_type_id, $this->getSetting('enabled_entity_types', []));
598 599
  }

Pawel G's avatar
Pawel G committed
600
  /**
601
   * Stores a custom path along with its sitemap settings to configuration.
Pawel G's avatar
Pawel G committed
602
   *
Pawel G's avatar
Pawel G committed
603 604
   * @param string $path
   * @param array $settings
Pawel G's avatar
Pawel G committed
605
   *
Pawel G's avatar
Pawel G committed
606
   * @return $this
607 608
   *
   * @todo Validate $settings and throw exceptions
Pawel G's avatar
Pawel G committed
609
   */
610
  public function addCustomLink($path, $settings = []) {
Pawel G's avatar
Pawel G committed
611 612 613 614 615 616 617 618
    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
619

620
    $custom_links = $this->getCustomLinks(FALSE);
Pawel G's avatar
Pawel G committed
621
    foreach ($custom_links as $key => $link) {
622
      if ($link['path'] === $path) {
623 624 625 626 627
        $link_key = $key;
        break;
      }
    }
    $link_key = isset($link_key) ? $link_key : count($custom_links);
628
    $custom_links[$link_key] = ['path' => $path] + $settings;
629
    $this->configFactory->getEditable("simple_sitemap.custom")
630
      ->set('links', $custom_links)->save();
Pawel G's avatar
Pawel G committed
631
    return $this;
632 633
  }

634 635 636
  /**
   * Returns an array of custom paths and their sitemap settings.
   *
637
   * @param bool $supplement_default_settings
638 639
   * @return array
   */
640
  public function getCustomLinks($supplement_default_settings = TRUE) {
641 642
    $custom_links = $this->configFactory
      ->get('simple_sitemap.custom')
643
      ->get('links');
644 645 646 647 648 649 650

    if ($supplement_default_settings) {
      foreach ($custom_links as $i => $link_settings) {
        $custom_links[$i] = $this->supplementDefaultSettings('custom', $link_settings);
      }
    }

651
    return $custom_links !== NULL ? $custom_links : [];
652 653
  }

Pawel G's avatar
Pawel G committed
654 655 656
  /**
   * Returns settings for a custom path added to the sitemap settings.
   *
Pawel G's avatar
Pawel G committed
657
   * @param string $path
Pawel G's avatar
Pawel G committed
658
   *
Pawel G's avatar
Pawel G committed
659
   * @return array|false
Pawel G's avatar
Pawel G committed
660
   */
661
  public function getCustomLink($path) {
662
    foreach ($this->getCustomLinks() as $key => $link) {
663
      if ($link['path'] === $path) {
664
        return $link;
665 666 667 668 669
      }
    }
    return FALSE;
  }

Pawel G's avatar
Pawel G committed
670 671 672
  /**
   * Removes a custom path from the sitemap settings.
   *
Pawel G's avatar
Pawel G committed
673
   * @param string $path
Pawel G's avatar
Pawel G committed
674
   *
Pawel G's avatar
Pawel G committed
675 676
   * @return $this
   */
677
  public function removeCustomLink($path) {
678
    $custom_links = $this->getCustomLinks(FALSE);
Pawel G's avatar
Pawel G committed
679
    foreach ($custom_links as $key => $link) {
680
      if ($link['path'] === $path) {
681 682
        unset($custom_links[$key]);
        $custom_links = array_values($custom_links);
683
        $this->configFactory->getEditable("simple_sitemap.custom")
684
          ->set('links', $custom_links)->save();
685
        break;
686 687
      }
    }
Pawel G's avatar
Pawel G committed
688
    return $this;
689 690
  }

Pawel G's avatar
Pawel G committed
691 692
  /**
   * Removes all custom paths from the sitemap settings.
Pawel G's avatar
Pawel G committed
693 694
   *
   * @return $this
Pawel G's avatar
Pawel G committed
695
   */
696
  public function removeCustomLinks() {
697
    $this->configFactory->getEditable("simple_sitemap.custom")
698
      ->set('links', [])->save();
Pawel G's avatar
Pawel G committed
699
    return $this;
700
  }
701
}