MediaWiki REL1_31
FullSearchResultWidget.php
Go to the documentation of this file.
1<?php
2
4
5use Category;
6use Hooks;
7use HtmlArmor;
11use Title;
12
22 protected $specialPage;
24 protected $linkRenderer;
25
27 $this->specialPage = $specialPage;
28 $this->linkRenderer = $linkRenderer;
29 }
30
37 public function render( SearchResult $result, $terms, $position ) {
38 // If the page doesn't *exist*... our search index is out of date.
39 // The least confusing at this point is to drop the result.
40 // You may get less results, but... on well. :P
41 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
42 return '';
43 }
44
45 $link = $this->generateMainLinkHtml( $result, $terms, $position );
46 // If page content is not readable, just return ths title.
47 // This is not quite safe, but better than showing excerpts from
48 // non-readable pages. Note that hiding the entry entirely would
49 // screw up paging (really?).
50 if ( !$result->getTitle()->userCan( 'read', $this->specialPage->getUser() ) ) {
51 return "<li>{$link}</li>";
52 }
53
54 $redirect = $this->generateRedirectHtml( $result );
55 $section = $this->generateSectionHtml( $result );
56 $category = $this->generateCategoryHtml( $result );
57 $date = htmlspecialchars(
58 $this->specialPage->getLanguage()->userTimeAndDate(
59 $result->getTimestamp(),
60 $this->specialPage->getUser()
61 )
62 );
63 list( $file, $desc, $thumb ) = $this->generateFileHtml( $result );
64 $snippet = $result->getTextSnippet( $terms );
65 if ( $snippet ) {
66 $extract = "<div class='searchresult'>$snippet</div>";
67 } else {
68 $extract = '';
69 }
70
71 if ( $thumb === null ) {
72 // If no thumb, then the description is about size
73 $desc = $this->generateSizeHtml( $result );
74
75 // Let hooks do their own final construction if desired.
76 // FIXME: Not sure why this is only for results without thumbnails,
77 // but keeping it as-is for now to prevent breaking hook consumers.
78 $html = null;
79 $score = '';
80 $related = '';
81 if ( !Hooks::run( 'ShowSearchHit', [
82 $this->specialPage, $result, $terms,
83 &$link, &$redirect, &$section, &$extract,
84 &$score, &$desc, &$date, &$related, &$html
85 ] ) ) {
86 return $html;
87 }
88 }
89
90 // All the pieces have been collected. Now generate the final HTML
91 $joined = "{$link} {$redirect} {$category} {$section} {$file}";
92 $meta = $this->buildMeta( $desc, $date );
93
94 if ( $thumb === null ) {
95 $html =
96 "<div class='mw-search-result-heading'>{$joined}</div>" .
97 "{$extract} {$meta}";
98 } else {
99 $html =
100 "<table class='searchResultImage'>" .
101 "<tr>" .
102 "<td style='width: 120px; text-align: center; vertical-align: top'>" .
103 $thumb .
104 "</td>" .
105 "<td style='vertical-align: top'>" .
106 "{$joined} {$extract} {$meta}" .
107 "</td>" .
108 "</tr>" .
109 "</table>";
110 }
111
112 return "<li>{$html}</li>";
113 }
114
126 protected function generateMainLinkHtml( SearchResult $result, $terms, $position ) {
127 $snippet = $result->getTitleSnippet();
128 if ( $snippet === '' ) {
129 $snippet = null;
130 } else {
131 $snippet = new HtmlArmor( $snippet );
132 }
133
134 // clone to prevent hook from changing the title stored inside $result
135 $title = clone $result->getTitle();
136 $query = [];
137
138 $attributes = [ 'data-serp-pos' => $position ];
139 Hooks::run( 'ShowSearchHitTitle',
140 [ &$title, &$snippet, $result, $terms, $this->specialPage, &$query, &$attributes ] );
141
142 $link = $this->linkRenderer->makeLink(
143 $title,
144 $snippet,
145 $attributes,
146 $query
147 );
148
149 return $link;
150 }
151
162 protected function generateAltTitleHtml( $msgKey, Title $title = null, $text ) {
163 $inner = $title === null
164 ? $text
165 : $this->linkRenderer->makeLink( $title, $text ? new HtmlArmor( $text ) : null );
166
167 return "<span class='searchalttitle'>" .
168 $this->specialPage->msg( $msgKey )->rawParams( $inner )->parse()
169 . "</span>";
170 }
171
176 protected function generateRedirectHtml( SearchResult $result ) {
177 $title = $result->getRedirectTitle();
178 return $title === null
179 ? ''
180 : $this->generateAltTitleHtml( 'search-redirect', $title, $result->getRedirectSnippet() );
181 }
182
187 protected function generateSectionHtml( SearchResult $result ) {
188 $title = $result->getSectionTitle();
189 return $title === null
190 ? ''
191 : $this->generateAltTitleHtml( 'search-section', $title, $result->getSectionSnippet() );
192 }
193
198 protected function generateCategoryHtml( SearchResult $result ) {
199 $snippet = $result->getCategorySnippet();
200 return $snippet
201 ? $this->generateAltTitleHtml( 'search-category', null, $snippet )
202 : '';
203 }
204
209 protected function generateSizeHtml( SearchResult $result ) {
210 $title = $result->getTitle();
211 if ( $title->getNamespace() === NS_CATEGORY ) {
212 $cat = Category::newFromTitle( $title );
213 return $this->specialPage->msg( 'search-result-category-size' )
214 ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() )
215 ->escaped();
216 // TODO: This is a bit odd...but requires changing the i18n message to fix
217 } elseif ( $result->getByteSize() !== null || $result->getWordCount() > 0 ) {
218 $lang = $this->specialPage->getLanguage();
219 $bytes = $lang->formatSize( $result->getByteSize() );
220 $words = $result->getWordCount();
221
222 return $this->specialPage->msg( 'search-result-size', $bytes )
223 ->numParams( $words )
224 ->escaped();
225 }
226
227 return '';
228 }
229
236 protected function generateFileHtml( SearchResult $result ) {
237 $title = $result->getTitle();
238 if ( $title->getNamespace() !== NS_FILE ) {
239 return [ '', null, null ];
240 }
241
242 if ( $result->isFileMatch() ) {
243 $html = "<span class='searchalttitle'>" .
244 $this->specialPage->msg( 'search-file-match' )->escaped() .
245 "</span>";
246 } else {
247 $html = '';
248 }
249
250 $descHtml = null;
251 $thumbHtml = null;
252
253 $img = $result->getFile() ?: wfFindFile( $title );
254 if ( $img ) {
255 $thumb = $img->transform( [ 'width' => 120, 'height' => 120 ] );
256 if ( $thumb ) {
257 $descHtml = $this->specialPage->msg( 'parentheses' )
258 ->rawParams( $img->getShortDesc() )
259 ->escaped();
260 $thumbHtml = $thumb->toHtml( [ 'desc-link' => true ] );
261 }
262 }
263
264 return [ $html, $descHtml, $thumbHtml ];
265 }
266
274 protected function buildMeta( $desc, $date ) {
275 if ( $desc && $date ) {
276 $meta = "{$desc} - {$date}";
277 } elseif ( $desc ) {
278 $meta = $desc;
279 } elseif ( $date ) {
280 $meta = $date;
281 } else {
282 return '';
283 }
284
285 return "<div class='mw-search-result-data'>{$meta}</div>";
286 }
287}
wfFindFile( $title, $options=[])
Find a file.
Category objects are immutable, strictly speaking.
Definition Category.php:31
Hooks class.
Definition Hooks.php:34
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:28
Class that generates HTML links for pages.
Renders a 'full' multi-line search result with metadata.
__construct(SpecialSearch $specialPage, LinkRenderer $linkRenderer)
render(SearchResult $result, $terms, $position)
generateMainLinkHtml(SearchResult $result, $terms, $position)
Generates HTML for the primary call to action.
generateAltTitleHtml( $msgKey, Title $title=null, $text)
Generates an alternate title link, such as (redirect from Foo).
implements Special:Search - Run text & title search and display the output
Represents a title within MediaWiki.
Definition Title.php:39
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition deferred.txt:11
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition hooks.txt:2013
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:3021
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition hooks.txt:1620
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template $section
Definition hooks.txt:3022
const NS_FILE
Definition Defines.php:80
const NS_CATEGORY
Definition Defines.php:88
Renders a single search result to HTML.
if(!isset( $args[0])) $lang