SitemapGeneratorBase.php 8.82 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 12 13 14 15 16 17 18
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;

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

19 20
  const FIRST_CHUNK_DELTA = 1;
  const INDEX_DELTA = 0;
21 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
  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;

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

58 59 60 61 62 63 64
  /**
   * @var array
   */
  protected static $indexAttributes = [
    'xmlns' => self::XMLNS,
  ];

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  /**
   * 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;
92
    $this->sitemapVariant = $this->settings['default_variant'];
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
  }

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

108
  /**
Pawel G's avatar
Pawel G committed
109
   * @param string $sitemap_variant
110 111 112 113 114 115 116
   * @return $this
   */
  public function setSitemapVariant($sitemap_variant) {
    $this->sitemapVariant = $sitemap_variant;
    return $this;
  }

117 118 119 120
  /**
   * @return bool
   */
  protected function isDefaultVariant() {
121
    return $this->sitemapVariant === $this->settings['default_variant'];
122 123
  }

124 125 126 127 128 129
  /**
   * @param array $links
   * @return string
   */
  abstract protected function getXml(array $links);

130 131 132
  protected function getChunkInfo() {
    return $this->db->select('simple_sitemap', 's')
      ->fields('s', ['delta', 'sitemap_created', 'type'])
133
      ->condition('s.type', $this->sitemapVariant)
134
      ->condition('s.delta', self::INDEX_DELTA, '<>')
135
      ->condition('s.status', 0)
136 137 138 139 140
      ->execute()
      ->fetchAllAssoc('delta');
  }

  /**
Pawel G's avatar
Pawel G committed
141
   * @param array $chunk_info
142 143 144 145 146
   * @return string
   */
  protected function getIndexXml(array $chunk_info) {
    $this->writer->openMemory();
    $this->writer->setIndent(TRUE);
147 148 149
    $this->writer->startSitemapDocument();

    // Add the XML stylesheet to document if enabled.
150 151 152
    if ($this->settings['xsl']) {
      $this->writer->writeXsl();
    }
153 154

    $this->writer->writeGeneratedBy();
155 156 157
    $this->writer->startElement('sitemapindex');

    // Add attributes to document.
158 159 160 161
    $attributes = self::$indexAttributes;
    $sitemap_variant = $this->sitemapVariant;
    $this->moduleHandler->alter('simple_sitemap_index_attributes', $attributes, $sitemap_variant);
    foreach ($attributes as $name => $value) {
162 163 164 165 166 167
      $this->writer->writeAttribute($name, $value);
    }

    // Add sitemap chunk locations to document.
    foreach ($chunk_info as $chunk_data) {
      $this->writer->startElement('sitemap');
168 169 170 171 172 173 174

      // Build the URL from route to be able to show potentially aliased paths.
      $url = $this->isDefaultVariant()
        ? Url::fromRoute('simple_sitemap.sitemap_default', ['page' => $chunk_data->delta])
        : Url::fromRoute('simple_sitemap.sitemap_variant', ['variant' => $chunk_data->type, 'page' => $chunk_data->delta]);

      $this->writer->writeElement('loc', $this->getCustomBaseUrl() . $url->toString(TRUE)->getGeneratedUrl());
175
      $this->writer->writeElement('lastmod', date('c', $chunk_data->sitemap_created));
176 177 178 179 180 181 182 183 184
      $this->writer->endElement();
    }

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

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

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

    return $this;
  }

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

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

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

208 209
        case 'all':
          break;
210

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

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

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

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

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

    return $this;
243 244
  }

245
  /**
Pawel G's avatar
Pawel G committed
246
   * @return $this
247 248
   * @throws \Exception
   */
249 250 251 252 253
  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')
254 255 256 257 258
        ->keys([
          'delta' => self::INDEX_DELTA,
          'type' => $this->sitemapVariant,
          'status' => 0
        ])
259 260 261
        ->insertFields([
          'id' => NULL === $highest_id ? 0 : $highest_id + 1,
          'delta' => self::INDEX_DELTA,
262
          'type' =>  $this->sitemapVariant,
263 264
          'sitemap_string' => $index_xml,
          'sitemap_created' => $this->time->getRequestTime(),
265
          'status' => 0,
266 267 268 269 270 271 272
        ])
        ->updateFields([
          'sitemap_string' => $index_xml,
          'sitemap_created' => $this->time->getRequestTime(),
        ])
        ->execute();
    }
273 274 275 276

    return $this;
  }

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

    // 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;
  }

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

  /**
   * @return string
   */
308
  protected function getCustomBaseUrl() {
309
    $customBaseUrl = $this->settings['base_url'];
Pawel G's avatar
Pawel G committed
310
    return !empty($customBaseUrl) ? $customBaseUrl : $GLOBALS['base_url'];
311
  }
312

313
}