MediaWiki REL1_34
FullSearchResultWidget.php
Go to the documentation of this file.
1<?php
2
4
5use Category;
6use Hooks;
7use HtmlArmor;
10use SearchResult;
12use Title;
13
23 protected $specialPage;
25 protected $linkRenderer;
26
28 $this->specialPage = $specialPage;
29 $this->linkRenderer = $linkRenderer;
30 }
31
37 public function render( SearchResult $result, $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, $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 $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
51 if ( !$permissionManager->userCan(
52 'read', $this->specialPage->getUser(), $result->getTitle()
53 ) ) {
54 return "<li>{$link}</li>";
55 }
56
57 $redirect = $this->generateRedirectHtml( $result );
58 $section = $this->generateSectionHtml( $result );
59 $category = $this->generateCategoryHtml( $result );
60 $date = $this->specialPage->getLanguage()->userTimeAndDate(
61 $result->getTimestamp(),
62 $this->specialPage->getUser()
63 );
64 list( $file, $desc, $thumb ) = $this->generateFileHtml( $result );
65 $snippet = $result->getTextSnippet();
66 if ( $snippet ) {
67 $extract = "<div class='searchresult'>$snippet</div>";
68 } else {
69 $extract = '';
70 }
71
72 if ( $thumb === null ) {
73 // If no thumb, then the description is about size
74 $desc = $this->generateSizeHtml( $result );
75
76 // Let hooks do their own final construction if desired.
77 // FIXME: Not sure why this is only for results without thumbnails,
78 // but keeping it as-is for now to prevent breaking hook consumers.
79 $html = null;
80 $score = '';
81 $related = '';
82 // TODO: remove this instanceof and always pass [], let implementors do the cast if
83 // they want to be SearchDatabase specific
84 $terms = $result instanceof \SqlSearchResult ? $result->getTermMatches() : [];
85 if ( !Hooks::run( 'ShowSearchHit', [
86 $this->specialPage, $result, $terms,
87 &$link, &$redirect, &$section, &$extract,
88 &$score, &$desc, &$date, &$related, &$html
89 ] ) ) {
90 return $html;
91 }
92 }
93
94 // All the pieces have been collected. Now generate the final HTML
95 $joined = "{$link} {$redirect} {$category} {$section} {$file}";
96 $meta = $this->buildMeta( $desc, $date );
97
98 if ( $thumb === null ) {
99 $html =
100 "<div class='mw-search-result-heading'>{$joined}</div>" .
101 "{$extract} {$meta}";
102 } else {
103 $html =
104 "<table class='searchResultImage'>" .
105 "<tr>" .
106 "<td style='width: 120px; text-align: center; vertical-align: top'>" .
107 $thumb .
108 "</td>" .
109 "<td style='vertical-align: top'>" .
110 "{$joined} {$extract} {$meta}" .
111 "</td>" .
112 "</tr>" .
113 "</table>";
114 }
115
116 return "<li class='mw-search-result'>{$html}</li>";
117 }
118
129 protected function generateMainLinkHtml( SearchResult $result, $position ) {
130 $snippet = $result->getTitleSnippet();
131 if ( $snippet === '' ) {
132 $snippet = null;
133 } else {
134 $snippet = new HtmlArmor( $snippet );
135 }
136
137 // clone to prevent hook from changing the title stored inside $result
138 $title = clone $result->getTitle();
139 $query = [];
140
141 $attributes = [ 'data-serp-pos' => $position ];
142 Hooks::run( 'ShowSearchHitTitle',
143 [ &$title, &$snippet, $result,
144 $result instanceof \SqlSearchResult ? $result->getTermMatches() : [],
145 $this->specialPage, &$query, &$attributes ] );
146
147 $link = $this->linkRenderer->makeLink(
148 $title,
149 $snippet,
150 $attributes,
151 $query
152 );
153
154 return $link;
155 }
156
167 protected function generateAltTitleHtml( $msgKey, Title $title = null, $text ) {
168 $inner = $title === null
169 ? $text
170 : $this->linkRenderer->makeLink( $title, $text ? new HtmlArmor( $text ) : null );
171
172 return "<span class='searchalttitle'>" .
173 $this->specialPage->msg( $msgKey )->rawParams( $inner )->parse()
174 . "</span>";
175 }
176
181 protected function generateRedirectHtml( SearchResult $result ) {
182 $title = $result->getRedirectTitle();
183 return $title === null
184 ? ''
185 : $this->generateAltTitleHtml( 'search-redirect', $title, $result->getRedirectSnippet() );
186 }
187
192 protected function generateSectionHtml( SearchResult $result ) {
193 $title = $result->getSectionTitle();
194 return $title === null
195 ? ''
196 : $this->generateAltTitleHtml( 'search-section', $title, $result->getSectionSnippet() );
197 }
198
203 protected function generateCategoryHtml( SearchResult $result ) {
204 $snippet = $result->getCategorySnippet();
205 return $snippet
206 ? $this->generateAltTitleHtml( 'search-category', null, $snippet )
207 : '';
208 }
209
214 protected function generateSizeHtml( SearchResult $result ) {
215 $title = $result->getTitle();
216 if ( $title->getNamespace() === NS_CATEGORY ) {
217 $cat = Category::newFromTitle( $title );
218 return $this->specialPage->msg( 'search-result-category-size' )
219 ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() )
220 ->escaped();
221 // TODO: This is a bit odd...but requires changing the i18n message to fix
222 } elseif ( $result->getByteSize() !== null || $result->getWordCount() > 0 ) {
223 $lang = $this->specialPage->getLanguage();
224 $bytes = $lang->formatSize( $result->getByteSize() );
225 $words = $result->getWordCount();
226
227 return $this->specialPage->msg( 'search-result-size', $bytes )
228 ->numParams( $words )
229 ->escaped();
230 }
231
232 return '';
233 }
234
241 protected function generateFileHtml( SearchResult $result ) {
242 $title = $result->getTitle();
243 if ( $title->getNamespace() !== NS_FILE ) {
244 return [ '', null, null ];
245 }
246
247 if ( $result->isFileMatch() ) {
248 $html = "<span class='searchalttitle'>" .
249 $this->specialPage->msg( 'search-file-match' )->escaped() .
250 "</span>";
251 } else {
252 $html = '';
253 }
254
255 $descHtml = null;
256 $thumbHtml = null;
257
258 $img = $result->getFile() ?: MediaWikiServices::getInstance()->getRepoGroup()
259 ->findFile( $title );
260 if ( $img ) {
261 $thumb = $img->transform( [ 'width' => 120, 'height' => 120 ] );
262 if ( $thumb ) {
263 $descHtml = $this->specialPage->msg( 'parentheses' )
264 ->rawParams( $img->getShortDesc() )
265 ->escaped();
266 $thumbHtml = $thumb->toHtml( [ 'desc-link' => true ] );
267 }
268 }
269
270 return [ $html, $descHtml, $thumbHtml ];
271 }
272
280 protected function buildMeta( $desc, $date ) {
281 if ( $desc && $date ) {
282 $meta = "{$desc} - {$date}";
283 } elseif ( $desc ) {
284 $meta = $desc;
285 } elseif ( $date ) {
286 $meta = $date;
287 } else {
288 return '';
289 }
290
291 return "<div class='mw-search-result-data'>{$meta}</div>";
292 }
293}
Category objects are immutable, strictly speaking.
Definition Category.php:29
Hooks class.
Definition Hooks.php:34
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:28
Class that generates HTML links for pages.
MediaWikiServices is the service locator for the application scope of MediaWiki.
static getInstance()
Returns the global default instance of the top level service locator.
Renders a 'full' multi-line search result with metadata.
__construct(SpecialSearch $specialPage, LinkRenderer $linkRenderer)
generateMainLinkHtml(SearchResult $result, $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).
NOTE: this class is being refactored into an abstract base class.
implements Special:Search - Run text & title search and display the output
Represents a title within MediaWiki.
Definition Title.php:42
const NS_FILE
Definition Defines.php:75
const NS_CATEGORY
Definition Defines.php:83
Renders a single search result to HTML.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42
if(!isset( $args[0])) $lang