SitemapGeneratorBase.php 9.48 KB
Newer Older
1 2 3 4
<?php

namespace Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator;

5
use Drupal\Core\Url;
6 7 8 9 10 11
use Drupal\simple_sitemap\Plugin\simple_sitemap\SimplesitemapPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Component\Datetime\Time;
12
use Drupal\Core\Language\LanguageInterface;
13 14 15 16 17 18 19

/**
 * Class SitemapGeneratorBase
 * @package Drupal\simple_sitemap\Plugin\simple_sitemap\UrlGenerator
 */
abstract class SitemapGeneratorBase extends SimplesitemapPluginBase implements SitemapGeneratorInterface {

20 21
  const FIRST_CHUNK_DELTA = 1;
  const INDEX_DELTA = 0;
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  const XMLNS = 'http://www.sitemaps.org/schemas/sitemap/0.9';

  /**
   * @var \Drupal\Core\Database\Connection
   */
  protected $db;

  /**
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

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

  /**
   * @var \Drupal\Component\Datetime\Time
   */
  protected $time;

  /**
   * @var array
   */
  protected $settings;

  /**
   * @var \Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapWriter
   */
  protected $writer;

54 55 56 57 58
  /**
   * @var string
   */
  protected $sitemapVariant;

59 60 61 62 63
  /**
   * @var array
   */
  protected $sitemapUrlSettings;

64 65 66 67 68 69 70
  /**
   * @var array
   */
  protected static $indexAttributes = [
    'xmlns' => self::XMLNS,
  ];

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  /**
   * SitemapGeneratorBase constructor.
   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   * @param \Drupal\Core\Database\Connection $database
   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   * @param \Drupal\Component\Datetime\Time $time
   * @param \Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator\SitemapWriter $sitemap_writer
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    Connection $database,
    ModuleHandler $module_handler,
    LanguageManagerInterface $language_manager,
    Time $time,
    SitemapWriter $sitemap_writer
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->db = $database;
    $this->moduleHandler = $module_handler;
    $this->languageManager = $language_manager;
    $this->time = $time;
    $this->writer = $sitemap_writer;
98
    $this->sitemapVariant = $this->settings['default_variant'];
99

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('database'),
      $container->get('module_handler'),
      $container->get('language_manager'),
      $container->get('datetime.time'),
      $container->get('simple_sitemap.sitemap_writer')
    );
  }

115
  /**
gbyte.co's avatar
gbyte.co committed
116
   * @param string $sitemap_variant
117 118 119 120 121 122 123
   * @return $this
   */
  public function setSitemapVariant($sitemap_variant) {
    $this->sitemapVariant = $sitemap_variant;
    return $this;
  }

124 125 126 127
  /**
   * @return bool
   */
  protected function isDefaultVariant() {
128
    return $this->sitemapVariant === $this->settings['default_variant'];
129 130
  }

131 132 133 134 135 136
  /**
   * @param array $links
   * @return string
   */
  abstract protected function getXml(array $links);

137 138 139
  protected function getChunkInfo() {
    return $this->db->select('simple_sitemap', 's')
      ->fields('s', ['delta', 'sitemap_created', 'type'])
140
      ->condition('s.type', $this->sitemapVariant)
141
      ->condition('s.delta', self::INDEX_DELTA, '<>')
142
      ->condition('s.status', 0)
143 144 145 146 147
      ->execute()
      ->fetchAllAssoc('delta');
  }

  /**
gbyte.co's avatar
gbyte.co committed
148
   * @param array $chunk_info
149 150 151 152 153
   * @return string
   */
  protected function getIndexXml(array $chunk_info) {
    $this->writer->openMemory();
    $this->writer->setIndent(TRUE);
154 155 156
    $this->writer->startSitemapDocument();

    // Add the XML stylesheet to document if enabled.
157 158 159
    if ($this->settings['xsl']) {
      $this->writer->writeXsl();
    }
160 161

    $this->writer->writeGeneratedBy();
162 163 164
    $this->writer->startElement('sitemapindex');

    // Add attributes to document.
165 166 167 168
    $attributes = self::$indexAttributes;
    $sitemap_variant = $this->sitemapVariant;
    $this->moduleHandler->alter('simple_sitemap_index_attributes', $attributes, $sitemap_variant);
    foreach ($attributes as $name => $value) {
169 170 171 172 173 174
      $this->writer->writeAttribute($name, $value);
    }

    // Add sitemap chunk locations to document.
    foreach ($chunk_info as $chunk_data) {
      $this->writer->startElement('sitemap');
175
      $this->writer->writeElement('loc', $this->getSitemapUrl($chunk_data->delta));
176
      $this->writer->writeElement('lastmod', date('c', $chunk_data->sitemap_created));
177 178 179 180 181 182 183 184 185
      $this->writer->endElement();
    }

    $this->writer->endElement();
    $this->writer->endDocument();

    return $this->writer->outputMemory();
  }

186
  /**
187
   * @param string $mode
188 189
   * @return $this
   */
190
  public function remove($mode = 'all') {
191
    self::purgeSitemapVariants($this->sitemapVariant, $mode);
192 193 194 195

    return $this;
  }

196
  public static function purgeSitemapVariants($variants = NULL, $mode = 'all') {
197 198
    if (NULL === $variants || !empty((array) $variants)) {
      $delete_query = \Drupal::database()->delete('simple_sitemap');
199

200 201 202 203
      switch($mode) {
        case 'published':
          $delete_query->condition('status', 1);
          break;
204

205 206 207
        case 'unpublished':
          $delete_query->condition('status', 0);
          break;
208

209 210
        case 'all':
          break;
211

212 213 214
        default:
          //todo: throw error
      }
215

216 217 218
      if (NULL !== $variants) {
        $delete_query->condition('type', (array) $variants, 'IN');
      }
219

220 221
      $delete_query->execute();
    }
222 223 224 225
  }

  /**
   * @param array $links
gbyte.co's avatar
gbyte.co committed
226 227
   * @return $this
   * @throws \Exception
228 229 230
   */
  public function generate(array $links) {
    $highest_id = $this->db->query('SELECT MAX(id) FROM {simple_sitemap}')->fetchField();
231
    $highest_delta = $this->db->query('SELECT MAX(delta) FROM {simple_sitemap} WHERE type = :type AND status = :status', [':type' => $this->sitemapVariant, ':status' => 0])
232 233
      ->fetchField();

234
    $this->db->insert('simple_sitemap')->fields([
235
      'id' => NULL === $highest_id ? 0 : $highest_id + 1,
236
      'delta' => NULL === $highest_delta ? self::FIRST_CHUNK_DELTA : $highest_delta + 1,
237
      'type' =>  $this->sitemapVariant,
238 239
      'sitemap_string' => $this->getXml($links),
      'sitemap_created' => $this->time->getRequestTime(),
240 241
      'status' => 0,
    ])->execute();
242 243

    return $this;
244 245
  }

246
  /**
gbyte.co's avatar
gbyte.co committed
247
   * @return $this
248 249
   * @throws \Exception
   */
250 251 252 253 254
  public function generateIndex() {
    if (!empty($chunk_info = $this->getChunkInfo()) && count($chunk_info) > 1) {
      $index_xml = $this->getIndexXml($chunk_info);
      $highest_id = $this->db->query('SELECT MAX(id) FROM {simple_sitemap}')->fetchField();
      $this->db->merge('simple_sitemap')
255 256 257 258 259
        ->keys([
          'delta' => self::INDEX_DELTA,
          'type' => $this->sitemapVariant,
          'status' => 0
        ])
260 261 262
        ->insertFields([
          'id' => NULL === $highest_id ? 0 : $highest_id + 1,
          'delta' => self::INDEX_DELTA,
263
          'type' =>  $this->sitemapVariant,
264 265
          'sitemap_string' => $index_xml,
          'sitemap_created' => $this->time->getRequestTime(),
266
          'status' => 0,
267 268 269 270 271 272 273
        ])
        ->updateFields([
          'sitemap_string' => $index_xml,
          'sitemap_created' => $this->time->getRequestTime(),
        ])
        ->execute();
    }
274 275 276 277

    return $this;
  }

gbyte.co's avatar
gbyte.co committed
278 279 280
  /**
   * @return $this
   */
281
  public function publish() {
282 283 284
    $unpublished_chunk = $this->db->query('SELECT MAX(id) FROM {simple_sitemap} WHERE type = :type AND status = :status', [
      ':type' => $this->sitemapVariant, ':status' => 0
    ])->fetchField();
285 286 287 288 289 290 291 292 293 294 295 296

    // Only allow publishing a sitemap variant if there is an unpublished
    // sitemap variant, as publishing involves deleting the currently published
    // variant.
    if (FALSE !== $unpublished_chunk) {
      $this->remove('published');
      $this->db->query('UPDATE {simple_sitemap} SET status = :status WHERE type = :type', [':type' => $this->sitemapVariant, ':status' => 1]);
    }

    return $this;
  }

297 298 299 300 301 302
  /**
   * @param array $settings
   * @return $this
   */
  public function setSettings(array $settings) {
    $this->settings = $settings;
303

304 305 306 307 308 309
    return $this;
  }

  /**
   * @return string
   */
310
  protected function getCustomBaseUrl() {
311
    $customBaseUrl = $this->settings['base_url'];
312

313
    return !empty($customBaseUrl) ? $customBaseUrl : $GLOBALS['base_url'];
314
  }
315

316 317 318 319 320 321 322 323 324 325 326 327 328
  protected function getSitemapUrlSettings() {
    if (NULL === $this->sitemapUrlSettings) {
      $this->sitemapUrlSettings = [
        'absolute' => TRUE,
        'base_url' => $this->getCustomBaseUrl(),
        'language' => $this->languageManager->getLanguage(LanguageInterface::LANGCODE_NOT_APPLICABLE),
      ];
    }

    return $this->sitemapUrlSettings;
  }

  /**
329
   * @param null $delta
330 331
   * @return \Drupal\Core\GeneratedUrl|string
   */
332 333
  public function getSitemapUrl($delta = NULL) {
    $parameters = NULL !== $delta ? ['page' => $delta] : [];
334
    $url = $this->isDefaultVariant()
335 336 337 338 339 340 341 342 343
      ? Url::fromRoute(
        'simple_sitemap.sitemap_default',
        $parameters,
        $this->getSitemapUrlSettings())
      : Url::fromRoute(
        'simple_sitemap.sitemap_variant',
        $parameters + ['variant' => $this->sitemapVariant],
        $this->getSitemapUrlSettings()
      );
344 345 346 347

    return $url->toString();
  }

348
}