Further modules included.
[yaffs-website] / web / modules / contrib / advanced_help / src / Plugin / Search / AdvancedHelpSearch.php
1 <?php
2
3 namespace Drupal\advanced_help\Plugin\Search;
4
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;
14
15 /**
16  * Executes a keyword search for Advanced Help against the {advanced_help} topic pages.
17  *
18  * @SearchPlugin(
19  *   id = "advanced_help_search",
20  *   title = @Translation("Advanced Help")
21  * )
22  */
23 class AdvancedHelpSearch extends SearchPluginBase implements AccessibleInterface, SearchIndexingInterface {
24
25   /**
26    * The database connection.
27    *
28    * @var \Drupal\Core\Database\Connection
29    */
30   protected $database;
31
32   /**
33    * The current user.
34    *
35    * @var \Drupal\Core\Session\AccountInterface
36    */
37   protected $currentUser;
38
39   /**
40    * Advanced Help Manager.
41    * @var \Drupal\advanced_help\AdvancedHelpManager
42    */
43   protected $advancedHelp;
44
45   /**
46    * A config object for 'search.settings'.
47    *
48    * @var \Drupal\Core\Config\Config
49    */
50   protected $searchSettings;
51
52
53   /**
54    * {@inheritdoc}
55    */
56   static public function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
57     return new static(
58       $container->get('database'),
59       $container->get('plugin.manager.advanced_help'),
60       $container->get('current_user'),
61       $container->get('config.factory')->get('search.settings'),
62       $configuration,
63       $plugin_id,
64       $plugin_definition
65     );
66   }
67
68   /**
69    * Creates a UserSearch object.
70    *
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
76    *   The 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.
83    */
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;
89
90     parent::__construct($configuration, $plugin_id, $plugin_definition);
91
92     $this->addCacheTags(['user_list']);
93   }
94
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();
98   }
99
100   /**
101    * Gets search id for each topic.
102    *
103    * Get or create an sid (search id) that correlates to each topic for
104    * the search system.
105    * @param array $topics
106    * @return array
107    */
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)
113       ->execute();
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]);
117       }
118       else {
119         $topics[$sid->module][$sid->topic]['sid'] = $sid->sid;
120       }
121     }
122     return $topics;
123   }
124
125   /**
126    * {@inheritdoc}
127    */
128   public function execute() {
129     if ($this->isSearchExecutable()) {
130       $keys = $this->keywords;
131
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());
140
141       $find = $query
142         ->fields('i', ['langcode'])
143         ->fields('ahi', ['module', 'topic'])
144         ->fields('sd', ['data'])
145         ->groupBy('i.langcode, ahi.module, ahi.topic, sd.data')
146         ->limit(10)
147         ->execute();
148
149       $results = [];
150       foreach ($find as $key => $item) {
151         $result = [
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,
157         ];
158         $results[] = $result;
159       }
160
161       return $results;
162     }
163     return [];
164   }
165
166   /**
167    * {@inheritdoc}
168    */
169   public function updateIndex() {
170     // Interpret the cron limit setting as the maximum number of nodes to index
171     // per cron run.
172     $limit = (int)$this->searchSettings->get('index.cron_limit');
173     $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
174     $topics = $this->getSids($this->advancedHelp->getTopics());
175
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]);
179     $count = 0;
180     foreach ($topics as $module => $module_topics) {
181       // Fast forward if necessary.
182       if (!empty($last['module']) && $last['module'] != $module) {
183         continue;
184       }
185
186       foreach ($module_topics as $topic => $info) {
187         // Fast forward if necessary.
188         if (!empty($last['topic']) && $last['topic'] != $topic) {
189           continue;
190         }
191
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']);
197         }
198
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')
203               ->fields([
204                 'module' => $module,
205                 'topic' => $topic,
206                 'langcode' => $language
207               ])
208               ->execute();
209           }
210         }
211
212         // Update index, using search index "type" equal to the plugin ID.
213         search_index($this->getPluginId(), $info['sid'], $language, file_get_contents($file));
214         $count++;
215         if ($count >= $limit) {
216           $last['module'] = $module;
217           $last['topic'] = $topic;
218           \Drupal::state()->set($this->getPluginId() . '.last_cron', $last);
219           return;
220         }
221       }
222     }
223     \Drupal::state()->set($this->getPluginId() . '.last_cron', ['time' => time()]);
224   }
225
226   /**
227    * {@inheritdoc}
228    */
229   public function indexClear() {
230     search_index_clear($this->getPluginId());
231   }
232
233   /**
234    * {@inheritdoc}
235    */
236   public function markForReindex() {
237     search_mark_for_reindex($this->getPluginId());
238   }
239
240   /**
241    * {@inheritdoc}
242    */
243   public function indexStatus() {
244     $topics = $this->advancedHelp->getTopics();
245     $total = 0;
246     foreach ($topics as $module => $module_topics) {
247       foreach ($module_topics as $topic => $info) {
248         $file = $this->advancedHelp->getTopicFileName($module, $topic);
249         if ($file) {
250           $total++;
251         }
252       }
253     }
254     $last_cron = \Drupal::state()->get($this->getPluginId() . '.last_cron', ['time' => 0]);
255     $indexed = 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)
261         ->countQuery()
262         ->execute()
263         ->fetchField();
264     }
265     return ['remaining' => $total - $indexed, 'total' => $total];
266   }
267 }