MediaWiki  master
FullSearchResultWidget.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use Category;
6 use Hooks;
7 use HtmlArmor;
10 use SearchResult;
11 use SpecialSearch;
12 use 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, $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 }
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
static newFromTitle( $title)
Factory function.
Definition: Category.php:146
if(!isset( $args[0])) $lang
__construct(SpecialSearch $specialPage, LinkRenderer $linkRenderer)
static getInstance()
Returns the global default instance of the top level service locator.
Renders a &#39;full&#39; multi-line search result with metadata.
Class that generates HTML links for pages.
generateMainLinkHtml(SearchResult $result, $position)
Generates HTML for the primary call to action.
generateAltTitleHtml( $msgKey, ?Title $title, $text)
Generates an alternate title link, such as (redirect from Foo).
const NS_CATEGORY
Definition: Defines.php:74
const NS_FILE
Definition: Defines.php:66
Renders a single search result to HTML.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200