MediaWiki REL1_35
FullSearchResultWidget.php
Go to the documentation of this file.
1<?php
2
4
5use Category;
6use HtmlArmor;
11use SearchResult;
13use Title;
14
24 protected $specialPage;
26 protected $linkRenderer;
28 private $hookRunner;
29
31 HookContainer $hookContainer
32 ) {
33 $this->specialPage = $specialPage;
34 $this->linkRenderer = $linkRenderer;
35 $this->hookRunner = new HookRunner( $hookContainer );
36 }
37
43 public function render( SearchResult $result, $position ) {
44 // If the page doesn't *exist*... our search index is out of date.
45 // The least confusing at this point is to drop the result.
46 // You may get less results, but... on well. :P
47 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
48 return '';
49 }
50
51 $link = $this->generateMainLinkHtml( $result, $position );
52 // If page content is not readable, just return ths title.
53 // This is not quite safe, but better than showing excerpts from
54 // non-readable pages. Note that hiding the entry entirely would
55 // screw up paging (really?).
56 $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
57 if ( !$permissionManager->userCan(
58 'read', $this->specialPage->getUser(), $result->getTitle()
59 ) ) {
60 return "<li>{$link}</li>";
61 }
62
63 $redirect = $this->generateRedirectHtml( $result );
64 $section = $this->generateSectionHtml( $result );
65 $category = $this->generateCategoryHtml( $result );
66 $date = htmlspecialchars(
67 $this->specialPage->getLanguage()->userTimeAndDate(
68 $result->getTimestamp(),
69 $this->specialPage->getUser()
70 )
71 );
72 list( $file, $desc, $thumb ) = $this->generateFileHtml( $result );
73 $snippet = $result->getTextSnippet();
74 if ( $snippet ) {
75 $extract = "<div class='searchresult'>$snippet</div>";
76 } else {
77 $extract = '';
78 }
79
80 if ( $thumb === null ) {
81 // If no thumb, then the description is about size
82 $desc = $this->generateSizeHtml( $result );
83
84 // Let hooks do their own final construction if desired.
85 // FIXME: Not sure why this is only for results without thumbnails,
86 // but keeping it as-is for now to prevent breaking hook consumers.
87 $html = null;
88 $score = '';
89 $related = '';
90 // TODO: remove this instanceof and always pass [], let implementors do the cast if
91 // they want to be SearchDatabase specific
92 $terms = $result instanceof \SqlSearchResult ? $result->getTermMatches() : [];
93 if ( !$this->hookRunner->onShowSearchHit( $this->specialPage, $result,
94 $terms, $link, $redirect, $section, $extract, $score,
95 $desc, $date, $related, $html )
96 ) {
97 return $html;
98 }
99 }
100
101 // All the pieces have been collected. Now generate the final HTML
102 $joined = "{$link} {$redirect} {$category} {$section} {$file}";
103 $meta = $this->buildMeta( $desc, $date );
104
105 if ( $thumb === null ) {
106 $html =
107 "<div class='mw-search-result-heading'>{$joined}</div>" .
108 "{$extract} {$meta}";
109 } else {
110 $html =
111 "<table class='searchResultImage'>" .
112 "<tr>" .
113 "<td style='width: 120px; text-align: center; vertical-align: top'>" .
114 $thumb .
115 "</td>" .
116 "<td style='vertical-align: top'>" .
117 "{$joined} {$extract} {$meta}" .
118 "</td>" .
119 "</tr>" .
120 "</table>";
121 }
122
123 return "<li class='mw-search-result'>{$html}</li>";
124 }
125
136 protected function generateMainLinkHtml( SearchResult $result, $position ) {
137 $snippet = $result->getTitleSnippet();
138 if ( $snippet === '' ) {
139 $snippet = null;
140 } else {
141 $snippet = new HtmlArmor( $snippet );
142 }
143
144 // clone to prevent hook from changing the title stored inside $result
145 $title = clone $result->getTitle();
146 $query = [];
147
148 $attributes = [ 'data-serp-pos' => $position ];
149 $this->hookRunner->onShowSearchHitTitle( $title, $snippet, $result,
150 $result instanceof \SqlSearchResult ? $result->getTermMatches() : [],
151 $this->specialPage, $query, $attributes );
152
153 $link = $this->linkRenderer->makeLink(
154 $title,
155 $snippet,
156 $attributes,
157 $query
158 );
159
160 return $link;
161 }
162
173 protected function generateAltTitleHtml( $msgKey, ?Title $title, $text ) {
174 $inner = $title === null
175 ? $text
176 : $this->linkRenderer->makeLink( $title, $text ? new HtmlArmor( $text ) : null );
177
178 return "<span class='searchalttitle'>" .
179 $this->specialPage->msg( $msgKey )->rawParams( $inner )->parse()
180 . "</span>";
181 }
182
187 protected function generateRedirectHtml( SearchResult $result ) {
188 $title = $result->getRedirectTitle();
189 return $title === null
190 ? ''
191 : $this->generateAltTitleHtml( 'search-redirect', $title, $result->getRedirectSnippet() );
192 }
193
198 protected function generateSectionHtml( SearchResult $result ) {
199 $title = $result->getSectionTitle();
200 return $title === null
201 ? ''
202 : $this->generateAltTitleHtml( 'search-section', $title, $result->getSectionSnippet() );
203 }
204
209 protected function generateCategoryHtml( SearchResult $result ) {
210 $snippet = $result->getCategorySnippet();
211 return $snippet
212 ? $this->generateAltTitleHtml( 'search-category', null, $snippet )
213 : '';
214 }
215
220 protected function generateSizeHtml( SearchResult $result ) {
221 $title = $result->getTitle();
222 if ( $title->getNamespace() === NS_CATEGORY ) {
223 $cat = Category::newFromTitle( $title );
224 return $this->specialPage->msg( 'search-result-category-size' )
225 ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() )
226 ->escaped();
227 // TODO: This is a bit odd...but requires changing the i18n message to fix
228 } elseif ( $result->getByteSize() !== null || $result->getWordCount() > 0 ) {
229 $lang = $this->specialPage->getLanguage();
230 $bytes = $lang->formatSize( $result->getByteSize() );
231 $words = $result->getWordCount();
232
233 return $this->specialPage->msg( 'search-result-size', $bytes )
234 ->numParams( $words )
235 ->escaped();
236 }
237
238 return '';
239 }
240
247 protected function generateFileHtml( SearchResult $result ) {
248 $title = $result->getTitle();
249 if ( $title->getNamespace() !== NS_FILE ) {
250 return [ '', null, null ];
251 }
252
253 if ( $result->isFileMatch() ) {
254 $html = "<span class='searchalttitle'>" .
255 $this->specialPage->msg( 'search-file-match' )->escaped() .
256 "</span>";
257 } else {
258 $html = '';
259 }
260
261 $descHtml = null;
262 $thumbHtml = null;
263
264 $img = $result->getFile() ?: MediaWikiServices::getInstance()->getRepoGroup()
265 ->findFile( $title );
266 if ( $img ) {
267 $thumb = $img->transform( [ 'width' => 120, 'height' => 120 ] );
268 if ( $thumb ) {
269 $descHtml = $this->specialPage->msg( 'parentheses' )
270 ->rawParams( $img->getShortDesc() )
271 ->escaped();
272 $thumbHtml = $thumb->toHtml( [ 'desc-link' => true ] );
273 }
274 }
275
276 return [ $html, $descHtml, $thumbHtml ];
277 }
278
286 protected function buildMeta( $desc, $date ) {
287 if ( $desc && $date ) {
288 $meta = "{$desc} - {$date}";
289 } elseif ( $desc ) {
290 $meta = $desc;
291 } elseif ( $date ) {
292 $meta = $date;
293 } else {
294 return '';
295 }
296
297 return "<div class='mw-search-result-data'>{$meta}</div>";
298 }
299}
Category objects are immutable, strictly speaking.
Definition Category.php:32
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:30
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
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.
generateAltTitleHtml( $msgKey, ?Title $title, $text)
Generates an alternate title link, such as (redirect from Foo).
generateMainLinkHtml(SearchResult $result, $position)
Generates HTML for the primary call to action.
__construct(SpecialSearch $specialPage, LinkRenderer $linkRenderer, HookContainer $hookContainer)
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:76
const NS_CATEGORY
Definition Defines.php:84
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