dokuwiki-sphinxsearch-plugin – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 <?php
2 /**
3 * Script to search in dokuwiki documents
4 *
5 * @author Ivinco <opensource@ivinco.com>
6 */
7  
8 if (!defined('DOKU_INC')) die();
9 if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
10  
11 require_once(DOKU_INC . 'inc/parser/parser.php');
12  
13 require_once(DOKU_PLUGIN . 'action.php');
14 require_once(DOKU_PLUGIN . 'sphinxsearch/sphinxapi.php');
15 require_once(DOKU_PLUGIN . 'sphinxsearch/PageMapper.php');
16 require_once(DOKU_PLUGIN . 'sphinxsearch/SphinxSearch.php');
17 require_once(DOKU_PLUGIN . 'sphinxsearch/functions.php');
18  
19  
20 class action_plugin_sphinxsearch extends DokuWiki_Action_Plugin
21 {
22 var $_search = null;
23  
24 var $_helpMessage = '';
25 var $_versionNumber = '0.3.11-was1';
26  
27 /**
28 * return some info
29 */
30 function getInfo()
31 {
32 return confToHash(dirname(__FILE__) . '/plugin.info.txt');
33 }
34  
35 function getHelpInfo()
36 {
37 $this->_helpMessage = "
38 ====== DokuWiki Sphinx Search plugin features ======
39  
40 To use the search you need to just enter your search keywords into the searchbox at the top right corner of the DokuWiki. When basic simple search is not enough you can try using the methods listed below:
41  
42 ===== Phrase search (\"\") =====
43 Put double quotes around a set of words to enable phrase search mode. For example:
44 <code>\"James Bond\"</code>
45  
46 ===== Search within a namespace =====
47 You can add \"@ns\" parameter to limit the search to some namespace. For exapmle:
48 <code>hotel @ns personal:mike:travel</code>
49 Such query will return only results from \"personal:mike:travel\" namespace for keyword \"hotel\".
50  
51 ===== Excluding keywords or namespaces from search =====
52 You can add a minus sign to a keyword or a category name exclude it from search. For example:
53 <code>hotel @ns -personal:mike</code>
54 Such query will look for \"hotel\" everywhere except the \"personal:mike\" namespace.
55 <code>blog -post</code>
56 Such query will look for documents that have keyword \"blog\" but don't have keyword \"post\".
57  
58 ";
59 if ($this->getConf('showversion')) {
60 $this->_helpMessage .= "DokuWiki Sphinx Search plugin (version $this->_versionNumber) by [[http://www.ivinco.com/software/dokuwiki-sphinx-search-plugin/|Ivinco]].";
61 }
62 return $this->_helpMessage;
63 }
64  
65 /**
66 * Register to the content display event to place the results under it.
67 */
68 /**
69 * register the eventhandlers
70 */
71 function register(Doku_Event_Handler $controller)
72 {
73 $controller->register_hook('TPL_CONTENT_DISPLAY', 'BEFORE', $this, 'handle_act_unknown', array());
74 }
75  
76 /**
77 * If our own action was given we produce our content here
78 */
79 function handle_act_unknown(&$event, $param)
80 {
81 global $ACT;
82 global $QUERY;
83 if ($ACT != 'search') return; // nothing to do for us
84  
85 // we can handle it -> prevent others
86 $event->stopPropagation();
87 $event->preventDefault();
88  
89 /* if (!extension_loaded('sqlite')) {
90 echo "SQLite extension is not loaded!";
91 return;
92 }*/
93  
94 if (!empty($_REQUEST['ssplugininfo'])) {
95 $info = array();
96 echo p_render('xhtml', p_get_instructions($this->getHelpInfo()), $info);
97 return;
98 }
99  
100 $this->_search($QUERY, $_REQUEST['start'], $_REQUEST['prev']);
101 }
102  
103 /**
104 * do the search and displays the result
105 */
106 function _search($query, $start, $prev)
107 {
108 global $conf;
109  
110 $start = (int)$start;
111 if ($start < 0) {
112 $start = 0;
113 }
114 if (empty($prev)) {
115 $prev = 0;
116 }
117  
118 $categories = $this->_getCategories($query);
119 $keywords = $this->_getKeywords($query);
120  
121 $search = new SphinxSearch($this->getConf('host'), $this->getConf('port'), $this->getConf('index'));
122 $search->setSnippetSize($this->getConf('snippetsize'));
123 $search->setArroundWordsCount($this->getConf('aroundwords'));
124 $search->setTitlePriority($this->getConf('title_priority'));
125 $search->setBodyPriority($this->getConf('body_priority'));
126 $search->setNamespacePriority($this->getConf('namespace_priority'));
127 $search->setPagenamePriority($this->getConf('pagename_priority'));
128  
129 if (!empty($keywords) && empty($categories)) {
130 $search->setSearchAllQuery($keywords, $categories);
131 } elseif (!empty($keywords)) {
132 $search->setSearchAllQueryWithCategoryFilter($keywords, $categories);
133 } else {
134 echo 'Your search - <strong>' . $query . '</strong> - did not match any documents.<br>
135 <a href="?do=search&ssplugininfo=1&id=' . $query . '">Search help</a>';
136 return;
137 }
138 $result = $search->search($start, $this->getConf('maxresults'));
139 $this->_search = $search;
140  
141 if ($search->getError()) {
142 echo "Could not connect to Sphinx search engine.";
143 return;
144 }
145  
146 if (!$result) {
147 echo 'Your search - <strong>' . $query . '</strong> - did not match any documents.<br/>
148 <a href="?do=search&ssplugininfo=1&id=' . $query . '">Search help</a>';
149 return;
150 }
151  
152 $pagesList = $search->getPages($keywords);
153 $totalFound = $search->getTotalFound();
154  
155 if (empty($pagesList) || 0 == $totalFound) {
156 echo 'Your search - <strong>' . $query . '</strong> - did not match any documents.<br/>
157 <a href="?do=search&ssplugininfo=1&id=' . $query . '">Search help</a>';
158 return;
159 } else {
160 echo '<link rel="stylesheet" href="' . DOKU_URL . 'lib/plugins/sphinxsearch/css/style.css">';
161 echo '<script type="text/javascript" src="' . DOKU_URL . 'lib/plugins/sphinxsearch/js/search.js"></script>';
162 echo '<div class="search">';
163 echo '<div class="search_sidebar">';
164 echo '<h1>Pages Containing Search Terms</h1>';
165 printNamespacesNew($this->_getMatchingPagenames($keywords, $categories));
166 echo '</div>';
167 echo '<h1>Found ' . $totalFound . ($totalFound == 1 ? ' match ' : ' matches ') . ' for query "' . hsc($query) . '"</h1>';
168 echo '<div class="search_result">';
169 // printout the results
170 $pageListGroupByPage = array();
171 foreach ($pagesList as $row) {
172 $page = $row['page'];
173 if (!isset($pageListGroupByPage[$page])) {
174 $pageListGroupByPage[$page] = $row;
175 } else {
176 $pageListGroupByPage[$page]['subpages'][] = $row;
177 }
178 }
179 foreach ($pageListGroupByPage as $row) {
180 $this->_showResult($row, $keywords, false);
181 if (!empty($row['subpages'])) {
182 echo '<div id="more' . $row['page'] . '" class="hide">';
183 foreach ($row['subpages'] as $sub) {
184 $this->_showResult($sub, $keywords, true);
185 }
186 echo '</div>';
187 }
188 }
189 echo '</div>';
190 echo '<div class="sphinxsearch_nav">';
191 echo '<a class="searchhelp" href="?do=search&ssplugininfo=1&id=' . $query . '">Search help</a>';
192 if ($start > 1) {
193 if (false !== strpos($prev, ',')) {
194 $prevArry = explode(",", $prev);
195 $prevNum = $prevArry[count($prevArry) - 1];
196 unset($prevArry[count($prevArry) - 1]);
197 $prevString = implode(",", $prevArry);
198 } else {
199 $prevNum = 0;
200 }
201  
202 echo $this->external_link(
203 wl('', array('do' => 'search', 'id' => $query, 'start' => $prevNum, 'prev' => $prevString), 'false', '&'),
204 'prev',
205 'wikilink1 gs_prev',
206 $conf['target']['interwiki']
207 );
208 }
209  
210 echo ' ';
211  
212 //if($start + $this->getConf('maxresults') < $totalFound){
213 //$next = $start + $this->getConf('maxresults');
214 if ($start + $search->getOffset() < $totalFound) {
215 $next = $start + $search->getOffset();
216 if ($start > 1) {
217 $prevString = $prev . ',' . $start;
218 }
219 echo $this->external_link(
220 wl('', array('do' => 'search', 'id' => $query, 'start' => $next, 'prev' => $prevString), 'false', '&'),
221 'next',
222 'wikilink1 gs_next',
223 $conf['target']['interwiki']
224 );
225 }
226 echo '</div>';
227 if ($this->getConf('showversion')) {
228 echo 'DokuWiki Sphinx Search plugin (version ' . $this->_versionNumber . ') by <a href="http://www.ivinco.com/software/dokuwiki-sphinx-search-plugin/">Ivinco</a>.';
229 }
230 echo '</div>';
231 }
232 }
233  
234 function _showResult($row, $keywords, $subpages = false)
235 {
236 $page = $row['page'];
237 $bodyExcerpt = $row['bodyExcerpt'];
238 $titleTextExcerpt = $row['titleTextExcerpt'];
239 $hid = $row['hid'];
240  
241 $metaData = p_get_metadata($page);
242  
243 if (!empty($titleTextExcerpt)) {
244 $titleText = $titleTextExcerpt;
245 } elseif (!empty($row['title_text'])) {
246 $titleText = $row['title_text'];
247 } elseif (!empty($metaData['title'])) {
248 $titleText = hsc($metaData['title']);
249 } else {
250 $titleText = hsc($page);
251 }
252  
253 $namespaces = getNsLinks($page, $keywords, $this->_search);
254 $href = !empty($hid) ? (wl($page) . '#' . $hid) : wl($page);
255  
256 if ($subpages) {
257 echo '<div class="search_result_row_child">';
258 } else {
259 echo '<div class="search_result_row">';
260 }
261  
262 echo '<a class="wikilink1 title" href="' . $href . '" title="" >' . $titleText . '</a><br/>';
263 echo '<div class="search_snippet">';
264 echo strip_tags($bodyExcerpt, '<b>,<strong>');
265 echo '</div>';
266 $sep = ':';
267 $i = 0;
268 echo '<span class="search_nmsp">';
269 foreach ($namespaces as $name) {
270 $link = $name['link'];
271 $pageTitle = $name['title'];
272 tpl_link($link, $pageTitle);
273 if ($i++ < count($namespaces) - 1) {
274 echo $sep;
275 }
276 }
277 if (!empty($hid)) {
278 echo '#' . $hid;
279 }
280 echo '</span>';
281  
282 if (!empty($metaData['last_change']['date'])) {
283 echo '<span class="search_cnt"> - Last modified ' . date("Y-m-d H:i", $metaData['last_change']['date']) . '</span> ';
284 } else if (!empty($metaData['date']['created'])) {
285 echo '<span class="search_cnt"> - Last modified ' . date("Y-m-d H:i", $metaData['date']['created']) . '</span> ';
286 }
287  
288 if (!empty($metaData['last_change']['user'])) {
289 echo '<span class="search_cnt">by ' . $metaData['last_change']['user'] . '</span> ';
290 } else if (!empty($metaData['creator'])) {
291 echo '<span class="search_cnt">by ' . $metaData['creator'] . '</span> ';
292 }
293  
294 if (!empty($row['subpages'])) {
295 echo '<br />';
296 echo '<div class="morematches"><a href="javascript:void(0)" onClick="sh(' . "'more" . $page . "'" . ');" >Show more matches from this document</a></div>';
297 } else {
298 echo '<br />';
299 }
300 echo '<br />';
301 echo '</div>';
302 }
303  
304 function searchform()
305 {
306 global $lang;
307 global $ACT;
308 global $QUERY;
309  
310 // don't print the search form if search action has been disabled
311 if (!actionOk('search')) return false;
312  
313 print '<form action="' . wl() . '" accept-charset="utf-8" class="search" id="dw__search"><div class="no">';
314 print '<input type="hidden" name="do" value="search" />';
315 print '<input type="text" ';
316 if ($ACT == 'search') print 'value="' . htmlspecialchars($QUERY) . '" ';
317 print 'id="qsearch__in" accesskey="f" name="id" class="edit" title="[ALT+F]" />';
318 print '<input type="submit" value="' . $lang['btn_search'] . '" class="button" title="' . $lang['btn_search'] . '" />';
319 print '</div></form>';
320 return true;
321 }
322  
323 function _getCategories($query)
324 {
325 $categories = '';
326 $query = urldecode($query);
327 if (false !== ($pos = strpos($query, "@ns"))) {;
328 $categories = substr($query, $pos + strlen("@ns"));
329 }
330 return trim($categories);
331 }
332  
333 function _getKeywords($query)
334 {
335 $keywords = $query;
336 $query = urldecode($query);
337 if (false !== ($pos = strpos($query, "-@ns"))) {;
338 $keywords = substr($keywords, 0, $pos);
339 } else if (false !== ($pos = strpos($query, "@ns"))) {;
340 $keywords = substr($keywords, 0, $pos);
341 }
342 return trim($keywords);
343 }
344  
345 function _getMatchingPagenames($keywords, $categories)
346 {
347 //$this->_search->setSearchCategoryQuery($keywords, $categories);
348 $this->_search->setSearchOnlyPagename();
349 $this->_search->setNamespacePriority($this->getConf('mp_namespace_priority'));
350 $this->_search->setPagenamePriority($this->getConf('mp_pagename_priority'));
351  
352 $res = $this->_search->search(0, 10);
353 if (!$res) {
354 return false;
355 }
356  
357 return $this->_search->getPageNames();
358 }
359 }