You are here

class SimpleSitemapViews in Simple XML sitemap (Views integration) 8

Class to manage sitemap data for views.

Hierarchy

Expanded class hierarchy of SimpleSitemapViews

3 files declare their use of SimpleSitemapViews
ArgumentCollector.php in src/EventSubscriber/ArgumentCollector.php
Contains argument collector.
GarbageCollector.php in src/Plugin/QueueWorker/GarbageCollector.php
Contains queue worker for garbage collection.
ViewsUrlGenerator.php in src/Plugin/simple_sitemap/UrlGenerator/ViewsUrlGenerator.php
Contains Views URL generator.
1 string reference to 'SimpleSitemapViews'
simple_sitemap_views.services.yml in ./simple_sitemap_views.services.yml
simple_sitemap_views.services.yml
1 service uses SimpleSitemapViews
simple_sitemap_views in ./simple_sitemap_views.services.yml
Drupal\simple_sitemap_views\SimpleSitemapViews

File

src/SimpleSitemapViews.php, line 21
Contains simple_sitemap_views service.

Namespace

Drupal\simple_sitemap_views
View source
class SimpleSitemapViews {

  /**
   * Separator between arguments.
   */
  const ARGUMENT_SEPARATOR = '/';

  /**
   * The current active database's master connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * SimpleSitemapViews constructor.
   *
   * @param \Drupal\Core\Database\Connection $database
   *   The current active database's master connection.
   */
  public function __construct(Connection $database) {
    $this->database = $database;
  }

  /**
   * Get sitemap settings for view display.
   *
   * @param \Drupal\views\ViewExecutable $view
   *   A view executable instance.
   * @param string|null $display_id
   *   The display id. If empty uses the preselected display.
   *
   * @return array|null
   *   The sitemap settings if the display is indexed, NULL otherwise.
   */
  public function getSitemapSettings(ViewExecutable $view, $display_id = NULL) {

    // Ensure the display was correctly set.
    if (!$view
      ->setDisplay($display_id)) {
      return NULL;
    }

    // Get the list of extenders.
    $extenders = $view->display_handler
      ->getExtenders();
    $extender = isset($extenders['simple_sitemap_display_extender']) ? $extenders['simple_sitemap_display_extender'] : NULL;

    // Retrieve the sitemap settings from the extender.
    if ($extender instanceof SimpleSitemapDisplayExtender && $extender
      ->hasSitemapSettings() && $extender
      ->isIndexingEnabled()) {
      return $extender
        ->getSitemapSettings();
    }
    return NULL;
  }

  /**
   * Get indexable arguments for view display.
   *
   * @param \Drupal\views\ViewExecutable $view
   *   A view executable instance.
   * @param string|null $display_id
   *   The display id. If empty uses the preselected display.
   *
   * @return array
   *   Indexable arguments identifiers.
   */
  public function getIndexableArguments(ViewExecutable $view, $display_id = NULL) {
    $indexable_arguments = [];
    $settings = $this
      ->getSitemapSettings($view, $display_id);
    if ($settings && !empty($settings['arguments']) && is_array($settings['arguments'])) {

      // Find indexable arguments.
      $arguments = array_keys($view->display_handler
        ->getHandlers('argument'));
      foreach ($arguments as $argument_id) {
        if (empty($settings['arguments'][$argument_id])) {
          break;
        }
        $indexable_arguments[] = $argument_id;
      }
    }
    return $indexable_arguments;
  }

  /**
   * Adds view arguments to the index.
   *
   * @param \Drupal\views\ViewExecutable $view
   *   A view executable instance.
   * @param array $args
   *   Array of arguments to add to the index.
   * @param string|null $display_id
   *   The display id. If empty uses the preselected display.
   *
   * @return bool
   *   TRUE if the arguments are added to the index, FALSE otherwise.
   */
  public function addArgumentsToIndex(ViewExecutable $view, array $args, $display_id = NULL) {

    // An array of arguments to be added to the index can not be empty.
    // Also ensure the display was correctly set.
    if (empty($args) || !$view
      ->setDisplay($display_id)) {
      return FALSE;
    }

    // Check that indexing of at least one argument is enabled.
    $indexable_arguments = $this
      ->getIndexableArguments($view);
    if (empty($indexable_arguments)) {
      return FALSE;
    }

    // Check that the number of identifiers is equal to the number of values.
    $args_ids = array_slice($indexable_arguments, 0, count($args));
    if (count($args_ids) != count($args)) {
      return FALSE;
    }

    // Check that the current number of rows in the index does not
    // exceed the specified number.
    $condition = new Condition('AND');
    $condition
      ->condition('view_id', $view
      ->id());
    $condition
      ->condition('display_id', $view->current_display);
    $settings = $this
      ->getSitemapSettings($view);
    $max_links = is_numeric($settings['max_links']) ? $settings['max_links'] : 0;
    if ($max_links > 0 && $this
      ->getArgumentsFromIndexCount($condition) >= $max_links) {
      return FALSE;
    }

    // Convert the set of identifiers and a set of values to string.
    $args_ids = $this
      ->convertArgumentsArrayToString($args_ids);
    $args_values = $this
      ->convertArgumentsArrayToString($args);
    $condition
      ->condition('arguments_ids', $args_ids);
    $condition
      ->condition('arguments_values', $args_values);

    // Check that this set of arguments has not yet been indexed.
    if ($this
      ->getArgumentsFromIndexCount($condition)) {
      return FALSE;
    }

    // Check that the view result is not empty for this set of arguments.
    $params = array_merge([
      $view
        ->id(),
      $view->current_display,
    ], $args);
    $view_result = call_user_func_array('views_get_view_result', $params);
    if (empty($view_result)) {
      return FALSE;
    }

    // Add a set of arguments to the index.
    $options = [
      'return' => Database::RETURN_AFFECTED,
    ];
    $query = $this->database
      ->insert('simple_sitemap_views', $options);
    $query
      ->fields([
      'view_id' => $view
        ->id(),
      'display_id' => $view->current_display,
      'arguments_ids' => $args_ids,
      'arguments_values' => $args_values,
    ]);
    return (bool) $query
      ->execute();
  }

  /**
   * Get arguments from index.
   *
   * @param \Drupal\Core\Database\Query\ConditionInterface|null $condition
   *   The query conditions.
   * @param int|null $limit
   *   The number of records to return from the result set. If NULL, returns
   *   all records.
   * @param bool $convert
   *   Defaults to FALSE. If TRUE, the argument string will be converted
   *   to an array.
   *
   * @return array
   *   An array with information about the indexed arguments.
   */
  public function getArgumentsFromIndex(ConditionInterface $condition = NULL, $limit = NULL, $convert = FALSE) {

    // Select the rows from the index table.
    $query = $this->database
      ->select('simple_sitemap_views', 'ssv');
    $query
      ->addField('ssv', 'id');
    $query
      ->addField('ssv', 'view_id');
    $query
      ->addField('ssv', 'display_id');
    $query
      ->addField('ssv', 'arguments_values', 'arguments');

    // Add conditions if necessary.
    if (!empty($condition)) {
      $query
        ->condition($condition);
    }

    // Limit results if necessary.
    if (!empty($limit)) {
      $query
        ->range(0, $limit);
    }
    $rows = $query
      ->execute()
      ->fetchAll();

    // Form the result.
    $arguments = [];
    foreach ($rows as $row) {
      $arguments[$row->id] = [
        'view_id' => $row->view_id,
        'display_id' => $row->display_id,
        'arguments' => $convert ? $this
          ->convertArgumentsStringToArray($row->arguments) : $row->arguments,
      ];
    }
    return $arguments;
  }

  /**
   * Get the number of rows in the index.
   *
   * @param \Drupal\Core\Database\Query\ConditionInterface|null $condition
   *   The query conditions.
   *
   * @return int
   *   The number of rows.
   */
  public function getArgumentsFromIndexCount(ConditionInterface $condition = NULL) {
    $query = $this->database
      ->select('simple_sitemap_views', 'ssv');

    // Add conditions if necessary.
    if (!empty($condition)) {
      $query
        ->condition($condition);
    }

    // Get the number of rows from the index table.
    return $query
      ->countQuery()
      ->execute()
      ->fetchField();
  }

  /**
   * Returns the ID of the record in the index for the specified position.
   *
   * @param int $position
   *   Position of the record.
   * @param \Drupal\Core\Database\Query\ConditionInterface|null $condition
   *   The query conditions.
   *
   * @return int|bool
   *   The ID of the record, or FALSE if there is no specified position.
   */
  public function getIndexIdByPosition($position, ConditionInterface $condition = NULL) {
    $query = $this->database
      ->select('simple_sitemap_views', 'ssv');
    $query
      ->addField('ssv', 'id');

    // Add conditions if necessary.
    if (!empty($condition)) {
      $query
        ->condition($condition);
    }
    $query
      ->orderBy('id', 'ASC');
    $query
      ->range($position - 1, 1);
    return $query
      ->execute()
      ->fetchField();
  }

  /**
   * Remove arguments from index.
   *
   * @param \Drupal\Core\Database\Query\ConditionInterface|null $condition
   *   The query conditions.
   */
  public function removeArgumentsFromIndex(ConditionInterface $condition = NULL) {
    if (empty($condition)) {

      // If there are no conditions, use the TRUNCATE query.
      $query = $this->database
        ->truncate('simple_sitemap_views');
    }
    else {

      // Otherwise, use the DELETE query.
      $query = $this->database
        ->delete('simple_sitemap_views');
      $query
        ->condition($condition);
    }
    $query
      ->execute();
  }

  /**
   * Get all display plugins that use the route.
   *
   * @return array
   *   An array with plugin identifiers.
   */
  public function getDisplayPathPluginIds() {
    static $plugin_ids = [];
    if (empty($plugin_ids)) {

      // Get all display plugins that use the route.
      $display_plugins = Views::pluginManager('display')
        ->getDefinitions();
      foreach ($display_plugins as $plugin_id => $definition) {
        if (!empty($definition['uses_route'])) {
          $plugin_ids[$plugin_id] = $plugin_id;
        }
      }
    }
    return $plugin_ids;
  }

  /**
   * Callback for filtering view displays.
   *
   * @param array $display
   *   The display options.
   *
   * @return bool
   *   The display is valid (TRUE) or not (FALSE).
   */
  public function isValidDisplay(array $display) {
    $display_plugins = $this
      ->getDisplayPathPluginIds();
    return !empty($display['display_plugin']) && in_array($display['display_plugin'], $display_plugins);
  }

  /**
   * Get variations for string representation of arguments.
   *
   * @param array $args
   *   Array of arguments.
   *
   * @return array
   *   Array of variations of the string representation of arguments.
   */
  public function getArgumentsStringVariations(array $args) {
    $variations = [];
    for ($length = 1; $length <= count($args); $length++) {
      $args_slice = array_slice($args, 0, $length);
      $variations[] = $this
        ->convertArgumentsArrayToString($args_slice);
    }
    return $variations;
  }

  /**
   * Converts an array of arguments to a string.
   *
   * @param array $args
   *   Array of arguments to convert.
   *
   * @return string
   *   A string representation of the arguments.
   */
  protected function convertArgumentsArrayToString(array $args) {
    return implode(self::ARGUMENT_SEPARATOR, $args);
  }

  /**
   * Converts a string with arguments to an array.
   *
   * @param string $args
   *   A string representation of the arguments to convert.
   *
   * @return array
   *   Array of arguments.
   */
  protected function convertArgumentsStringToArray($args) {
    return explode(self::ARGUMENT_SEPARATOR, $args);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SimpleSitemapViews::$database protected property The current active database's master connection.
SimpleSitemapViews::addArgumentsToIndex public function Adds view arguments to the index.
SimpleSitemapViews::ARGUMENT_SEPARATOR constant Separator between arguments.
SimpleSitemapViews::convertArgumentsArrayToString protected function Converts an array of arguments to a string.
SimpleSitemapViews::convertArgumentsStringToArray protected function Converts a string with arguments to an array.
SimpleSitemapViews::getArgumentsFromIndex public function Get arguments from index.
SimpleSitemapViews::getArgumentsFromIndexCount public function Get the number of rows in the index.
SimpleSitemapViews::getArgumentsStringVariations public function Get variations for string representation of arguments.
SimpleSitemapViews::getDisplayPathPluginIds public function Get all display plugins that use the route.
SimpleSitemapViews::getIndexableArguments public function Get indexable arguments for view display.
SimpleSitemapViews::getIndexIdByPosition public function Returns the ID of the record in the index for the specified position.
SimpleSitemapViews::getSitemapSettings public function Get sitemap settings for view display.
SimpleSitemapViews::isValidDisplay public function Callback for filtering view displays.
SimpleSitemapViews::removeArgumentsFromIndex public function Remove arguments from index.
SimpleSitemapViews::__construct public function SimpleSitemapViews constructor.