You are here

class AdvancedHelpSearch in Advanced Help 8

Executes a keyword search for Advanced Help against the {advanced_help} topic pages.

Plugin annotation


@SearchPlugin(
  id = "advanced_help_search",
  title = @Translation("Advanced Help")
)

Hierarchy

Expanded class hierarchy of AdvancedHelpSearch

File

src/Plugin/Search/AdvancedHelpSearch.php, line 24

Namespace

Drupal\advanced_help\Plugin\Search
View source
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,
    ];
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AdvancedHelpSearch::$advancedHelp protected property Advanced Help Manager.
AdvancedHelpSearch::$currentUser protected property The current user.
AdvancedHelpSearch::$database protected property The database connection.
AdvancedHelpSearch::$searchIndex protected property The search index.
AdvancedHelpSearch::$searchSettings protected property A config object for 'search.settings'.
AdvancedHelpSearch::access public function Checks data value access. Overrides AccessibleInterface::access
AdvancedHelpSearch::create public static function Creates an instance of the plugin. Overrides SearchPluginBase::create
AdvancedHelpSearch::execute public function Executes the search. Overrides SearchInterface::execute
AdvancedHelpSearch::getSids private function Gets search id for each topic.
AdvancedHelpSearch::indexClear public function Clears the search index for this plugin. Overrides SearchIndexingInterface::indexClear
AdvancedHelpSearch::indexStatus public function Reports the status of indexing. Overrides SearchIndexingInterface::indexStatus
AdvancedHelpSearch::markForReindex public function Marks the search index for reindexing for this plugin. Overrides SearchIndexingInterface::markForReindex
AdvancedHelpSearch::updateIndex public function Updates the search index for this plugin. Overrides SearchIndexingInterface::updateIndex
AdvancedHelpSearch::__construct public function Creates a UserSearch object. Overrides PluginBase::__construct
CacheableDependencyTrait::$cacheContexts protected property Cache contexts.
CacheableDependencyTrait::$cacheMaxAge protected property Cache max-age.
CacheableDependencyTrait::$cacheTags protected property Cache tags.
CacheableDependencyTrait::getCacheContexts public function 3
CacheableDependencyTrait::getCacheMaxAge public function 3
CacheableDependencyTrait::getCacheTags public function 3
CacheableDependencyTrait::setCacheability protected function Sets cacheability; useful for value object constructors.
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
RefinableCacheableDependencyTrait::addCacheableDependency public function 1
RefinableCacheableDependencyTrait::addCacheContexts public function
RefinableCacheableDependencyTrait::addCacheTags public function
RefinableCacheableDependencyTrait::mergeCacheMaxAge public function
SearchPluginBase::$keywords protected property The keywords to use in a search.
SearchPluginBase::$searchAttributes protected property Array of attributes - usually from the request object.
SearchPluginBase::$searchParameters protected property Array of parameters from the query string from the request.
SearchPluginBase::buildResults public function Executes the search and builds render arrays for the result items. Overrides SearchInterface::buildResults 1
SearchPluginBase::buildSearchUrlQuery public function Builds the URL GET query parameters array for search. Overrides SearchInterface::buildSearchUrlQuery 1
SearchPluginBase::getAttributes public function Returns the currently set attributes (from the request). Overrides SearchInterface::getAttributes
SearchPluginBase::getHelp public function Returns the searching help. Overrides SearchInterface::getHelp 1
SearchPluginBase::getKeywords public function Returns the currently set keywords of the plugin instance. Overrides SearchInterface::getKeywords
SearchPluginBase::getParameters public function Returns the current parameters set using setSearch(). Overrides SearchInterface::getParameters
SearchPluginBase::getType public function Returns the search index type this plugin uses. Overrides SearchInterface::getType 2
SearchPluginBase::isSearchExecutable public function Verifies if the values set via setSearch() are valid and sufficient. Overrides SearchInterface::isSearchExecutable 2
SearchPluginBase::searchFormAlter public function Alters the search form when being built for a given plugin. Overrides SearchInterface::searchFormAlter 1
SearchPluginBase::setSearch public function Sets the keywords, parameters, and attributes to be used by execute(). Overrides SearchInterface::setSearch 1
SearchPluginBase::suggestedTitle public function Provides a suggested title for a page of search results. Overrides SearchInterface::suggestedTitle
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.