3 namespace Drupal\advanced_help\Plugin\Search;
5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\Database\Connection;
7 use Drupal\Core\Session\AccountInterface;
8 use Drupal\Core\Access\AccessibleInterface;
9 use Drupal\search\Plugin\SearchPluginBase;
10 use Drupal\advanced_help\AdvancedHelpManager;
11 use Drupal\search\Plugin\SearchIndexingInterface;
12 use Drupal\Core\Config\Config;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
16 * Executes a keyword search for Advanced Help against the {advanced_help} topic pages.
19 * id = "advanced_help_search",
20 * title = @Translation("Advanced Help")
23 class AdvancedHelpSearch extends SearchPluginBase implements AccessibleInterface, SearchIndexingInterface {
26 * The database connection.
28 * @var \Drupal\Core\Database\Connection
35 * @var \Drupal\Core\Session\AccountInterface
37 protected $currentUser;
40 * Advanced Help Manager.
41 * @var \Drupal\advanced_help\AdvancedHelpManager
43 protected $advancedHelp;
46 * A config object for 'search.settings'.
48 * @var \Drupal\Core\Config\Config
50 protected $searchSettings;
56 static public function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
58 $container->get('database'),
59 $container->get('plugin.manager.advanced_help'),
60 $container->get('current_user'),
61 $container->get('config.factory')->get('search.settings'),
69 * Creates a UserSearch object.
71 * @param Connection $database
72 * The database connection.
73 * @param \Drupal\advanced_help\AdvancedHelpManager $advanced_help
74 * The advanced Help manager.
75 * @param \Drupal\Core\Session\AccountInterface $current_user
77 * @param array $configuration
78 * @param \Drupal\Core\Config\Config $search_settings
79 * @param string $plugin_id
80 * The plugin_id for the plugin instance.
81 * @param mixed $plugin_definition
82 * The plugin implementation definition.
84 public function __construct(Connection $database, AdvancedHelpManager $advanced_help, AccountInterface $current_user, Config $search_settings, array $configuration, $plugin_id, $plugin_definition) {
85 $this->database = $database;
86 $this->advancedHelp = $advanced_help;
87 $this->currentUser = $current_user;
88 $this->searchSettings = $search_settings;
90 parent::__construct($configuration, $plugin_id, $plugin_definition);
92 $this->addCacheTags(['user_list']);
95 public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
96 $result = AccessResult::allowedIf(!empty($account) && $account->hasPermission('access user profiles'))->cachePerPermissions();
97 return $return_as_object ? $result : $result->isAllowed();
101 * Gets search id for each topic.
103 * Get or create an sid (search id) that correlates to each topic for
105 * @param array $topics
108 private function getSids($topics) {
109 $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
110 $result = $this->database->select('advanced_help_index', 'ahi')
111 ->fields('ahi', ['sid', 'module', 'topic', 'langcode'])
112 ->condition('langcode', $language)
114 foreach ($result as $sid) {
115 if (empty($topics[$sid->module][$sid->topic])) {
116 $this->database->query("DELETE FROM {advanced_help_index} WHERE sid = :sid", [':sid' => $sid->sid]);
119 $topics[$sid->module][$sid->topic]['sid'] = $sid->sid;
128 public function execute() {
129 if ($this->isSearchExecutable()) {
130 $keys = $this->keywords;
132 // Build matching conditions.
133 $query = $this->database
134 ->select('search_index', 'i', ['target' => 'replica'])
135 ->extend('Drupal\search\SearchQuery')
136 ->extend('Drupal\Core\Database\Query\PagerSelectExtender');
137 $query->join('advanced_help_index', 'ahi', 'ahi.sid = i.sid');
138 $query->join('search_dataset', 'sd', "ahi.sid = sd.sid AND sd.type = '{$this->pluginId}'");
139 $query->searchExpression($keys, $this->getPluginId());
142 ->fields('i', ['langcode'])
143 ->fields('ahi', ['module', 'topic'])
144 ->fields('sd', ['data'])
145 ->groupBy('i.langcode, ahi.module, ahi.topic, sd.data')
150 foreach ($find as $key => $item) {
152 'link' => '/help/ah/' . $item->module . '/' . $item->topic,
153 'title' => $item->topic,
154 'score' => $item->calculated_score,
155 'snippet' => search_excerpt($keys, $item->data, $item->langcode),
156 'langcode' => $item->langcode,
158 $results[] = $result;
169 public function updateIndex() {
170 // Interpret the cron limit setting as the maximum number of nodes to index
172 $limit = (int)$this->searchSettings->get('index.cron_limit');
173 $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
174 $topics = $this->getSids($this->advancedHelp->getTopics());
176 // If we got interrupted by limit, this will contain the last module
177 // and topic we looked at.
178 $last = \Drupal::state()->get($this->getPluginId() . '.last_cron', ['time' => 0]);
180 foreach ($topics as $module => $module_topics) {
181 // Fast forward if necessary.
182 if (!empty($last['module']) && $last['module'] != $module) {
186 foreach ($module_topics as $topic => $info) {
187 // Fast forward if necessary.
188 if (!empty($last['topic']) && $last['topic'] != $topic) {
192 //If we've been looking to catch up, and we have, reset so we
193 // stop fast forwarding.
194 if (!empty($last['module'])) {
195 unset($last['topic']);
196 unset($last['module']);
199 $file = $this->advancedHelp->getTopicFileName($module, $topic);
200 if ($file && (empty($info['sid']) || filemtime($file) > $last['time'])) {
201 if (empty($info['sid'])) {
202 $info['sid'] = $this->database->insert('advanced_help_index')
206 'langcode' => $language
212 // Update index, using search index "type" equal to the plugin ID.
213 search_index($this->getPluginId(), $info['sid'], $language, file_get_contents($file));
215 if ($count >= $limit) {
216 $last['module'] = $module;
217 $last['topic'] = $topic;
218 \Drupal::state()->set($this->getPluginId() . '.last_cron', $last);
223 \Drupal::state()->set($this->getPluginId() . '.last_cron', ['time' => time()]);
229 public function indexClear() {
230 search_index_clear($this->getPluginId());
236 public function markForReindex() {
237 search_mark_for_reindex($this->getPluginId());
243 public function indexStatus() {
244 $topics = $this->advancedHelp->getTopics();
246 foreach ($topics as $module => $module_topics) {
247 foreach ($module_topics as $topic => $info) {
248 $file = $this->advancedHelp->getTopicFileName($module, $topic);
254 $last_cron = \Drupal::state()->get($this->getPluginId() . '.last_cron', ['time' => 0]);
256 if ($last_cron['time'] != 0) {
257 $indexed = $this->database->select('search_dataset', 'sd')
258 ->fields('sd', ['sid'])
259 ->condition('type', $this->getPluginId())
260 ->condition('reindex', 0)
265 return ['remaining' => $total - $indexed, 'total' => $total];