MediaWiki REL1_32
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 = $this->specialPage->getLanguage()->userTimeAndDate(
58 $result->getTimestamp(),
59 $this->specialPage->getUser()
60 );
61 list( $file, $desc, $thumb ) = $this->generateFileHtml( $result );
62 $snippet = $result->getTextSnippet( $terms );
63 if ( $snippet ) {
64 $extract = "<div class='searchresult'>$snippet</div>";
65 } else {
66 $extract = '';
67 }
68
69 if ( $thumb === null ) {
70 // If no thumb, then the description is about size
71 $desc = $this->generateSizeHtml( $result );
72
73 // Let hooks do their own final construction if desired.
74 // FIXME: Not sure why this is only for results without thumbnails,
75 // but keeping it as-is for now to prevent breaking hook consumers.
76 $html = null;
77 $score = '';
78 $related = '';
79 if ( !Hooks::run( 'ShowSearchHit', [
80 $this->specialPage, $result, $terms,
81 &$link, &$redirect, &$section, &$extract,
82 &$score, &$desc, &$date, &$related, &$html
83 ] ) ) {
84 return $html;
85 }
86 }
87
88 // All the pieces have been collected. Now generate the final HTML
89 $joined = "{$link} {$redirect} {$category} {$section} {$file}";
90 $meta = $this->buildMeta( $desc, $date );
91
92 if ( $thumb === null ) {
93 $html =
94 "<div class='mw-search-result-heading'>{$joined}</div>" .
95 "{$extract} {$meta}";
96 } else {
97 $html =
98 "<table class='searchResultImage'>" .
99 "<tr>" .
100 "<td style='width: 120px; text-align: center; vertical-align: top'>" .
101 $thumb .
102 "</td>" .
103 "<td style='vertical-align: top'>" .
104 "{$joined} {$extract} {$meta}" .
105 "</td>" .
106 "</tr>" .
107 "</table>";
108 }
109
110 return "<li class='mw-search-result'>{$html}</li>";
111 }
112
124 protected function generateMainLinkHtml( SearchResult $result, $terms, $position ) {
125 $snippet = $result->getTitleSnippet();
126 if ( $snippet === '' ) {
127 $snippet = null;
128 } else {
129 $snippet = new HtmlArmor( $snippet );
130 }
131
132 // clone to prevent hook from changing the title stored inside $result
133 $title = clone $result->getTitle();
134 $query = [];
135
136 $attributes = [ 'data-serp-pos' => $position ];
137 Hooks::run( 'ShowSearchHitTitle',
138 [ &$title, &$snippet, $result, $terms, $this->specialPage, &$query, &$attributes ] );
139
140 $link = $this->linkRenderer->makeLink(
141 $title,
142 $snippet,
143 $attributes,
144 $query
145 );
146
147 return $link;
148 }
149
160 protected function generateAltTitleHtml( $msgKey, Title $title = null, $text ) {
161 $inner = $title === null
162 ? $text
163 : $this->linkRenderer->makeLink( $title, $text ? new HtmlArmor( $text ) : null );
164
165 return "<span class='searchalttitle'>" .
166 $this->specialPage->msg( $msgKey )->rawParams( $inner )->parse()
167 . "</span>";
168 }
169
174 protected function generateRedirectHtml( SearchResult $result ) {
175 $title = $result->getRedirectTitle();
176 return $title === null
177 ? ''
178 : $this->generateAltTitleHtml( 'search-redirect', $title, $result->getRedirectSnippet() );
179 }
180
185 protected function generateSectionHtml( SearchResult $result ) {
186 $title = $result->getSectionTitle();
187 return $title === null
188 ? ''
189 : $this->generateAltTitleHtml( 'search-section', $title, $result->getSectionSnippet() );
190 }
191
196 protected function generateCategoryHtml( SearchResult $result ) {
197 $snippet = $result->getCategorySnippet();
198 return $snippet
199 ? $this->generateAltTitleHtml( 'search-category', null, $snippet )
200 : '';
201 }
202
207 protected function generateSizeHtml( SearchResult $result ) {
208 $title = $result->getTitle();
209 if ( $title->getNamespace() === NS_CATEGORY ) {
210 $cat = Category::newFromTitle( $title );
211 return $this->specialPage->msg( 'search-result-category-size' )
212 ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() )
213 ->escaped();
214 // TODO: This is a bit odd...but requires changing the i18n message to fix
215 } elseif ( $result->getByteSize() !== null || $result->getWordCount() > 0 ) {
216 $lang = $this->specialPage->getLanguage();
217 $bytes = $lang->formatSize( $result->getByteSize() );
218 $words = $result->getWordCount();
219
220 return $this->specialPage->msg( 'search-result-size', $bytes )
221 ->numParams( $words )
222 ->escaped();
223 }
224
225 return '';
226 }
227
234 protected function generateFileHtml( SearchResult $result ) {
235 $title = $result->getTitle();
236 if ( $title->getNamespace() !== NS_FILE ) {
237 return [ '', null, null ];
238 }
239
240 if ( $result->isFileMatch() ) {
241 $html = "<span class='searchalttitle'>" .
242 $this->specialPage->msg( 'search-file-match' )->escaped() .
243 "</span>";
244 } else {
245 $html = '';
246 }
247
248 $descHtml = null;
249 $thumbHtml = null;
250
251 $img = $result->getFile() ?: wfFindFile( $title );
252 if ( $img ) {
253 $thumb = $img->transform( [ 'width' => 120, 'height' => 120 ] );
254 if ( $thumb ) {
255 $descHtml = $this->specialPage->msg( 'parentheses' )
256 ->rawParams( $img->getShortDesc() )
257 ->escaped();
258 $thumbHtml = $thumb->toHtml( [ 'desc-link' => true ] );
259 }
260 }
261
262 return [ $html, $descHtml, $thumbHtml ];
263 }
264
272 protected function buildMeta( $desc, $date ) {
273 if ( $desc && $date ) {
274 $meta = "{$desc} - {$date}";
275 } elseif ( $desc ) {
276 $meta = $desc;
277 } elseif ( $date ) {
278 $meta = $date;
279 } else {
280 return '';
281 }
282
283 return "<div class='mw-search-result-data'>{$meta}</div>";
284 }
285}
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:2062
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:3106
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:1656
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:3107
const NS_FILE
Definition Defines.php:70
const NS_CATEGORY
Definition Defines.php:78
Renders a single search result to HTML.
if(!isset( $args[0])) $lang