SitemapGeneratorBase.php 8.81 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<?php

namespace Drupal\simple_sitemap\Plugin\simple_sitemap\SitemapGenerator;

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 {

18 19
  const FIRST_CHUNK_DELTA = 1;
  const INDEX_DELTA = 0;
20

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 53 54 55
  const GENERATED_BY = 'Generated by the Simple XML sitemap Drupal module: https://drupal.org/project/simple_sitemap.';
  const XML_VERSION = '1.0';
  const ENCODING = 'UTF-8';
  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;

56 57 58 59 60
  /**
   * @var string
   */
  protected $sitemapVariant;

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

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

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

111 112 113 114 115 116 117 118 119
  /**
   * @param $sitemap_variant
   * @return $this
   */
  public function setSitemapVariant($sitemap_variant) {
    $this->sitemapVariant = $sitemap_variant;
    return $this;
  }

120 121
  /**
   * @return bool
122
   * @todo: Variant cannot be null
123 124
   */
  protected function isDefaultVariant() {
125
    return $this->sitemapVariant === $this->settings['default_variant'];
126 127
  }

128 129 130
  /**
   * @param array $links
   * @return string
131
   * @todo: Variant cannot be null
132 133 134
   */
  abstract protected function getXml(array $links);

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

  /**
   * Returns the sitemap index for all sitemap chunks of this type.
   *
   * @return string
149
   * @todo: Variant cannot be null
150 151 152 153 154 155 156 157 158
   */
  protected function getIndexXml(array $chunk_info) {
    $this->writer->openMemory();
    $this->writer->setIndent(TRUE);
    $this->writer->startDocument(self::XML_VERSION, self::ENCODING);
    $this->writer->writeComment(self::GENERATED_BY);
    $this->writer->startElement('sitemapindex');

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

    // Add sitemap chunk locations to document.
    foreach ($chunk_info as $chunk_data) {
      $this->writer->startElement('sitemap');
      $this->writer->writeElement('loc', $this->getCustomBaseUrl()
170
        . '/' . (!$this->isDefaultVariant() ? ($chunk_data->type . '/') : '') . 'sitemap.xml?page=' . $chunk_data->delta);
171 172 173 174 175 176 177 178 179 180
      $this->writer->writeElement('lastmod', date_iso8601($chunk_data->sitemap_created));
      $this->writer->endElement();
    }

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

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

181
  /**
182
   * @param string $mode
183 184
   * @return $this
   */
185
  public function remove($mode = 'all') {
186 187 188 189 190 191
    self::removeSitemapVariant($this->sitemapVariant, $mode);

    return $this;
  }

  public static function removeSitemapVariant($variant = NULL, $mode = 'all') {
192
    $delete_query = \Drupal::database()->delete('simple_sitemap');
193 194 195

    switch($mode) {
      case 'published':
196
        $delete_query->condition('status', 1);
197
        break;
198

199
      case 'unpublished':
200
        $delete_query->condition('status', 0);
201
        break;
202

203 204
      case 'all':
        break;
205

206 207 208
      default:
        //todo: throw error
    }
209 210 211 212 213 214

    if (NULL !== $variant) {
      $delete_query->condition('type', $variant);
    }

    $delete_query->execute();
215 216 217
  }

  /**
218 219
   * Takes links along with their options and then generates and saves the
   * sitemap.
220 221 222
   *
   * @param array $links
   *   All links with their multilingual versions and settings.
223 224
   *
   * @todo Variant cannot be null
225 226 227
   */
  public function generate(array $links) {
    $highest_id = $this->db->query('SELECT MAX(id) FROM {simple_sitemap}')->fetchField();
228
    $highest_delta = $this->db->query('SELECT MAX(delta) FROM {simple_sitemap} WHERE type = :type AND status = :status', [':type' => $this->sitemapVariant, ':status' => 0])
229 230
      ->fetchField();

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

    return $this;
241 242
  }

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

    return $this;
  }

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  public function publish() {
    $unpublished_chunk = $this->db->query('SELECT MAX(id) FROM {simple_sitemap} WHERE type = :type AND status = :status', [':type' => $this->sitemapVariant, ':status' => 0])
      ->fetchField();

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

290 291 292 293 294 295 296 297 298 299 300 301
  /**
   * @param array $settings
   * @return $this
   */
  public function setSettings(array $settings) {
    $this->settings = $settings;
    return $this;
  }

  /**
   * @return string
   */
302
  protected function getCustomBaseUrl() {
303
    $customBaseUrl = $this->settings['base_url'];
304
    return !empty($customBaseUrl) ? $customBaseUrl : $GLOBALS['base_url']; //todo use service
305 306
  }
}