MediaWiki REL1_37
FullSearchResultWidget.php
Go to the documentation of this file.
1<?php
2
4
5use Category;
6use Html;
7use HtmlArmor;
12use SearchResult;
14use Title;
15
25 protected $specialPage;
27 protected $linkRenderer;
29 private $hookRunner;
30
32 HookContainer $hookContainer
33 ) {
34 $this->specialPage = $specialPage;
35 $this->linkRenderer = $linkRenderer;
36 $this->hookRunner = new HookRunner( $hookContainer );
37 }
38
44 public function render( SearchResult $result, $position ) {
45 // If the page doesn't *exist*... our search index is out of date.
46 // The least confusing at this point is to drop the result.
47 // You may get less results, but... on well. :P
48 if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
49 return '';
50 }
51
52 $link = $this->generateMainLinkHtml( $result, $position );
53 // If page content is not readable, just return ths title.
54 // This is not quite safe, but better than showing excerpts from
55 // non-readable pages. Note that hiding the entry entirely would
56 // screw up paging (really?).
57 if ( !$this->specialPage->getAuthority()->definitelyCan( 'read', $result->getTitle() ) ) {
58 return Html::rawElement( 'li', [], $link );
59 }
60
61 $redirect = $this->generateRedirectHtml( $result );
62 $section = $this->generateSectionHtml( $result );
63 $category = $this->generateCategoryHtml( $result );
64 $date = htmlspecialchars(
65 $this->specialPage->getLanguage()->userTimeAndDate(
66 $result->getTimestamp(),
67 $this->specialPage->getUser()
68 )
69 );
70 list( $file, $desc, $thumb ) = $this->generateFileHtml( $result );
71 $snippet = $result->getTextSnippet();
72 if ( $snippet ) {
73 $extract = Html::rawElement( 'div', [ 'class' => 'searchresult' ], $snippet );
74 } else {
75 $extract = '';
76 }
77
78 if ( $thumb === null ) {
79 // If no thumb, then the description is about size
80 $desc = $this->generateSizeHtml( $result );
81
82 // Let hooks do their own final construction if desired.
83 // FIXME: Not sure why this is only for results without thumbnails,
84 // but keeping it as-is for now to prevent breaking hook consumers.
85 $html = null;
86 $score = '';
87 $related = '';
88 // TODO: remove this instanceof and always pass [], let implementors do the cast if
89 // they want to be SearchDatabase specific
90 $terms = $result instanceof \SqlSearchResult ? $result->getTermMatches() : [];
91 if ( !$this->hookRunner->onShowSearchHit( $this->specialPage, $result,
92 $terms, $link, $redirect, $section, $extract, $score,
93 $desc, $date, $related, $html )
94 ) {
95 return $html;
96 }
97 }
98
99 // All the pieces have been collected. Now generate the final HTML
100 $joined = "{$link} {$redirect} {$category} {$section} {$file}";
101 $meta = $this->buildMeta( $desc, $date );
102
103 if ( $thumb === null ) {
104 $html = Html::rawElement(
105 'div',
106 [ 'class' => 'mw-search-result-heading' ],
107 $joined
108 );
109 $html .= $extract . ' ' . $meta;
110 } else {
111 $tableCells = Html::rawElement(
112 'td',
113 [ 'style' => 'width: 120px; text-align: center; vertical-align: top' ],
114 $thumb
115 ) . Html::rawElement(
116 'td',
117 [ 'style' => 'vertical-align: top' ],
118 "$joined $extract $meta"
119 );
120 $html = Html::rawElement(
121 'table',
122 [ 'class' => 'searchResultImage' ],
123 Html::rawElement(
124 'tr',
125 [],
126 $tableCells
127 )
128 );
129 }
130
131 return Html::rawElement( 'li', [ 'class' => 'mw-search-result' ], $html );
132 }
133
144 protected function generateMainLinkHtml( SearchResult $result, $position ) {
145 $snippet = $result->getTitleSnippet();
146 if ( $snippet === '' ) {
147 $snippet = null;
148 } else {
149 $snippet = new HtmlArmor( $snippet );
150 }
151
152 // clone to prevent hook from changing the title stored inside $result
153 $title = clone $result->getTitle();
154 $query = [];
155
156 $attributes = [ 'data-serp-pos' => $position ];
157 $this->hookRunner->onShowSearchHitTitle( $title, $snippet, $result,
158 $result instanceof \SqlSearchResult ? $result->getTermMatches() : [],
159 $this->specialPage, $query, $attributes );
160
161 $link = $this->linkRenderer->makeLink(
162 $title,
163 $snippet,
164 $attributes,
165 $query
166 );
167
168 return $link;
169 }
170
181 protected function generateAltTitleHtml( $msgKey, ?Title $title, $text ) {
182 $inner = $title === null
183 ? $text
184 : $this->linkRenderer->makeLink( $title, $text ? new HtmlArmor( $text ) : null );
185
186 return "<span class='searchalttitle'>" .
187 $this->specialPage->msg( $msgKey )->rawParams( $inner )->parse()
188 . "</span>";
189 }
190
195 protected function generateRedirectHtml( SearchResult $result ) {
196 $title = $result->getRedirectTitle();
197 return $title === null
198 ? ''
199 : $this->generateAltTitleHtml( 'search-redirect', $title, $result->getRedirectSnippet() );
200 }
201
206 protected function generateSectionHtml( SearchResult $result ) {
207 $title = $result->getSectionTitle();
208 return $title === null
209 ? ''
210 : $this->generateAltTitleHtml( 'search-section', $title, $result->getSectionSnippet() );
211 }
212
217 protected function generateCategoryHtml( SearchResult $result ) {
218 $snippet = $result->getCategorySnippet();
219 return $snippet
220 ? $this->generateAltTitleHtml( 'search-category', null, $snippet )
221 : '';
222 }
223
228 protected function generateSizeHtml( SearchResult $result ) {
229 $title = $result->getTitle();
230 if ( $title->getNamespace() === NS_CATEGORY ) {
231 $cat = Category::newFromTitle( $title );
232 return $this->specialPage->msg( 'search-result-category-size' )
233 ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() )
234 ->escaped();
235 // TODO: This is a bit odd...but requires changing the i18n message to fix
236 } elseif ( $result->getByteSize() !== null || $result->getWordCount() > 0 ) {
237 $lang = $this->specialPage->getLanguage();
238 $bytes = $lang->formatSize( $result->getByteSize() );
239 $words = $result->getWordCount();
240
241 return $this->specialPage->msg( 'search-result-size', $bytes )
242 ->numParams( $words )
243 ->escaped();
244 }
245
246 return '';
247 }
248
255 protected function generateFileHtml( SearchResult $result ) {
256 $title = $result->getTitle();
257 if ( $title->getNamespace() !== NS_FILE ) {
258 return [ '', null, null ];
259 }
260
261 if ( $result->isFileMatch() ) {
262 $html = Html::rawElement(
263 'span',
264 [ 'class' => 'searchalttitle' ],
265 $this->specialPage->msg( 'search-file-match' )->escaped()
266 );
267 } else {
268 $html = '';
269 }
270
271 $descHtml = null;
272 $thumbHtml = null;
273
274 $img = $result->getFile() ?: MediaWikiServices::getInstance()->getRepoGroup()
275 ->findFile( $title );
276 if ( $img ) {
277 $thumb = $img->transform( [ 'width' => 120, 'height' => 120 ] );
278 if ( $thumb ) {
279 $descHtml = $this->specialPage->msg( 'parentheses' )
280 ->rawParams( $img->getShortDesc() )
281 ->escaped();
282 $thumbHtml = $thumb->toHtml( [ 'desc-link' => true ] );
283 }
284 }
285
286 return [ $html, $descHtml, $thumbHtml ];
287 }
288
296 protected function buildMeta( $desc, $date ) {
297 if ( $desc && $date ) {
298 $meta = "{$desc} - {$date}";
299 } elseif ( $desc ) {
300 $meta = $desc;
301 } elseif ( $date ) {
302 $meta = $date;
303 } else {
304 return '';
305 }
306
307 return "<div class='mw-search-result-data'>{$meta}</div>";
308 }
309}
const NS_FILE
Definition Defines.php:70
const NS_CATEGORY
Definition Defines.php:78
Category objects are immutable, strictly speaking.
Definition Category.php:33
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:30
This class is a collection of static functions that serve two purposes:
Definition Html.php:49
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:48
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