You are here

AdvancedHelpSearch.php in Advanced Help 8

File

src/Plugin/Search/AdvancedHelpSearch.php
View source
<?php

namespace Drupal\advanced_help\Plugin\Search;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Database\Connection;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessibleInterface;
use Drupal\search\Plugin\SearchPluginBase;
use Drupal\advanced_help\AdvancedHelpManager;
use Drupal\search\Plugin\SearchIndexingInterface;
use Drupal\Core\Config\Config;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\search\SearchIndexInterface;

/**
 * Executes a keyword search for Advanced Help against the {advanced_help} topic pages.
 *
 * @SearchPlugin(
 *   id = "advanced_help_search",
 *   title = @Translation("Advanced Help")
 * )
 */
class AdvancedHelpSearch extends SearchPluginBase implements AccessibleInterface, SearchIndexingInterface {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * Advanced Help Manager.
   *
   * @var \Drupal\advanced_help\AdvancedHelpManager
   */
  protected $advancedHelp;

  /**
   * A config object for 'search.settings'.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $searchSettings;

  /**
   * The search index.
   *
   * @var \Drupal\search\SearchIndexInterface
   */
  protected $searchIndex;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = new static($container
      ->get('database'), $container
      ->get('plugin.manager.advanced_help'), $container
      ->get('current_user'), $container
      ->get('config.factory')
      ->get('search.settings'), $configuration, $plugin_id, $plugin_definition);

    // The search Index service does not exist on Drupal 8.7 and below.
    if (floatval(\Drupal::VERSION) >= 8.800000000000001) {
      $instance->searchIndex = $container
        ->get('search.index');
    }
    return $instance;
  }

  /**
   * Creates a UserSearch object.
   *
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   * @param \Drupal\advanced_help\AdvancedHelpManager $advanced_help
   *   The advanced Help manager.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current user.
   * @param array $configuration
   * @param \Drupal\Core\Config\Config $search_settings
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   */
  public function __construct(Connection $database, AdvancedHelpManager $advanced_help, AccountInterface $current_user, Config $search_settings, array $configuration, $plugin_id, $plugin_definition) {
    $this->database = $database;
    $this->advancedHelp = $advanced_help;
    $this->currentUser = $current_user;
    $this->searchSettings = $search_settings;
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this
      ->addCacheTags([
      'user_list',
    ]);
  }

  /**
   *
   */
  public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
    $result = AccessResult::allowedIf(!empty($account) && $account
      ->hasPermission('access user profiles'))
      ->cachePerPermissions();
    return $return_as_object ? $result : $result
      ->isAllowed();
  }

  /**
   * Gets search id for each topic.
   *
   * Get or create an sid (search id) that correlates to each topic for
   * the search system.
   *
   * @param array $topics
   *
   * @return array
   */
  private function getSids($topics) {
    $language = \Drupal::languageManager()
      ->getCurrentLanguage()
      ->getId();
    $result = $this->database
      ->select('advanced_help_index', 'ahi')
      ->fields('ahi', [
      'sid',
      'module',
      'topic',
      'langcode',
    ])
      ->condition('langcode', $language)
      ->execute();
    foreach ($result as $sid) {
      if (empty($topics[$sid->module][$sid->topic])) {
        $this->database
          ->query("DELETE FROM {advanced_help_index} WHERE sid = :sid", [
          ':sid' => $sid->sid,
        ]);
      }
      else {
        $topics[$sid->module][$sid->topic]['sid'] = $sid->sid;
      }
    }
    return $topics;
  }

  /**
   * {@inheritdoc}
   */
  public function execute() {
    if ($this
      ->isSearchExecutable()) {
      $keys = $this->keywords;

      // Build matching conditions.
      $query = $this->database
        ->select('search_index', 'i', [
        'target' => 'replica',
      ])
        ->extend('Drupal\\search\\SearchQuery')
        ->extend('Drupal\\Core\\Database\\Query\\PagerSelectExtender');
      $query
        ->join('advanced_help_index', 'ahi', 'ahi.sid = i.sid');
      $query
        ->join('search_dataset', 'sd', "ahi.sid = sd.sid AND sd.type = '{$this->pluginId}'");
      $query
        ->searchExpression($keys, $this
        ->getPluginId());
      $find = $query
        ->fields('i', [
        'langcode',
      ])
        ->fields('ahi', [
        'module',
        'topic',
      ])
        ->fields('sd', [
        'data',
      ])
        ->groupBy('i.langcode, ahi.module, ahi.topic, sd.data')
        ->limit(10)
        ->execute();
      $results = [];
      foreach ($find as $key => $item) {
        $result = [
          'link' => '/help/ah/' . $item->module . '/' . $item->topic,
          'title' => $item->topic,
          'score' => $item->calculated_score,
          'snippet' => search_excerpt($keys, $item->data, $item->langcode),
          'langcode' => $item->langcode,
        ];
        $results[] = $result;
      }
      return $results;
    }
    return [];
  }

  /**
   * {@inheritdoc}
   */
  public function updateIndex() {

    // Interpret the cron limit setting as the maximum number of nodes to index
    // per cron run.
    $limit = (int) $this->searchSettings
      ->get('index.cron_limit');
    $language = \Drupal::languageManager()
      ->getCurrentLanguage()
      ->getId();
    $topics = $this
      ->getSids($this->advancedHelp
      ->getTopics());

    // If we got interrupted by limit, this will contain the last module
    // and topic we looked at.
    $last = \Drupal::state()
      ->get($this
      ->getPluginId() . '.last_cron', [
      'time' => 0,
    ]);
    $count = 0;
    foreach ($topics as $module => $module_topics) {

      // Fast forward if necessary.
      if (!empty($last['module']) && $last['module'] != $module) {
        continue;
      }
      foreach ($module_topics as $topic => $info) {

        // Fast forward if necessary.
        if (!empty($last['topic']) && $last['topic'] != $topic) {
          continue;
        }

        // If we've been looking to catch up, and we have, reset so we
        // stop fast forwarding.
        if (!empty($last['module'])) {
          unset($last['topic']);
          unset($last['module']);
        }
        $file = $this->advancedHelp
          ->getTopicFileName($module, $topic);
        if ($file && (empty($info['sid']) || filemtime($file) > $last['time'])) {
          if (empty($info['sid'])) {
            $info['sid'] = $this->database
              ->insert('advanced_help_index')
              ->fields([
              'module' => $module,
              'topic' => $topic,
              'langcode' => $language,
            ])
              ->execute();
          }
        }

        // Update index, using search index "type" equal to the plugin ID.
        if (floatval(\Drupal::VERSION) >= 8.800000000000001) {
          $this->searchIndex
            ->index($this
            ->getPluginId(), $info['sid'], $language, file_get_contents($file));
        }
        else {
          search_index($this
            ->getPluginId(), $info['sid'], $language, file_get_contents($file));
        }
        $count++;
        if ($count >= $limit) {
          $last['module'] = $module;
          $last['topic'] = $topic;
          \Drupal::state()
            ->set($this
            ->getPluginId() . '.last_cron', $last);
          return;
        }
      }
    }
    \Drupal::state()
      ->set($this
      ->getPluginId() . '.last_cron', [
      'time' => time(),
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function indexClear() {
    if (floatval(\Drupal::VERSION) >= 8.800000000000001) {
      $this->searchIndex
        ->clear($this
        ->getPluginId());
    }
    else {
      search_index_clear($this
        ->getPluginId());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function markForReindex() {
    if (floatval(\Drupal::VERSION) >= 8.800000000000001) {
      $this->searchIndex
        ->markForReindex($this
        ->getPluginId());
    }
    else {
      search_mark_for_reindex($this
        ->getPluginId());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function indexStatus() {
    $topics = $this->advancedHelp
      ->getTopics();
    $total = 0;
    foreach ($topics as $module => $module_topics) {
      foreach ($module_topics as $topic => $info) {
        $file = $this->advancedHelp
          ->getTopicFileName($module, $topic);
        if ($file) {
          $total++;
        }
      }
    }
    $last_cron = \Drupal::state()
      ->get($this
      ->getPluginId() . '.last_cron', [
      'time' => 0,
    ]);
    $indexed = 0;
    if ($last_cron['time'] != 0) {
      $indexed = $this->database
        ->select('search_dataset', 'sd')
        ->fields('sd', [
        'sid',
      ])
        ->condition('type', $this
        ->getPluginId())
        ->condition('reindex', 0)
        ->countQuery()
        ->execute()
        ->fetchField();
    }
    return [
      'remaining' => $total - $indexed,
      'total' => $total,
    ];
  }

}

Classes

Namesort descending Description
AdvancedHelpSearch Executes a keyword search for Advanced Help against the {advanced_help} topic pages.