MediaWiki  master
CategoryViewer.php
Go to the documentation of this file.
1 <?php
23 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
25 
27  use ProtectedHookAccessorTrait;
28 
30  public $limit;
31 
33  public $from;
34 
36  public $until;
37 
39  public $articles;
40 
43 
45  public $children;
46 
49 
51  public $showGallery;
52 
55 
58 
60  public $nextPage;
61 
63  protected $prevPage;
64 
66  public $flip;
67 
69  public $title;
70 
72  public $collation;
73 
75  public $gallery;
76 
78  private $cat;
79 
81  private $query;
82 
85 
95  public function __construct( $title, IContextSource $context, $from = [],
96  $until = [], $query = []
97  ) {
98  $this->title = $title;
99  $this->setContext( $context );
100  $this->getOutput()->addModuleStyles( [
101  'mediawiki.action.view.categoryPage.styles'
102  ] );
103  $this->from = $from;
104  $this->until = $until;
105  $this->limit = $context->getConfig()->get( 'CategoryPagingLimit' );
106  $this->cat = Category::newFromTitle( $title );
107  $this->query = $query;
108  $this->collation = Collation::singleton();
109  $this->languageConverter = MediaWikiServices::getInstance()
110  ->getLanguageConverterFactory()->getLanguageConverter();
111  unset( $this->query['title'] );
112  }
113 
119  public function getHTML() {
120  $this->showGallery = $this->getConfig()->get( 'CategoryMagicGallery' )
121  && !$this->getOutput()->mNoGallery;
122 
123  $this->clearCategoryState();
124  $this->doCategoryQuery();
125  $this->finaliseCategoryState();
126 
127  $r = $this->getSubcategorySection() .
128  $this->getPagesSection() .
129  $this->getImageSection();
130 
131  if ( $r == '' ) {
132  // If there is no category content to display, only
133  // show the top part of the navigation links.
134  // @todo FIXME: Cannot be completely suppressed because it
135  // is unknown if 'until' or 'from' makes this
136  // give 0 results.
137  $r = $this->getCategoryTop();
138  } else {
139  $r = $this->getCategoryTop() .
140  $r .
141  $this->getCategoryBottom();
142  }
143 
144  // Give a proper message if category is empty
145  if ( $r == '' ) {
146  $r = $this->msg( 'category-empty' )->parseAsBlock();
147  }
148 
149  $lang = $this->getLanguage();
150  $attribs = [
151  'class' => 'mw-category-generated',
152  'lang' => $lang->getHtmlCode(),
153  'dir' => $lang->getDir()
154  ];
155  # put a div around the headings which are in the user language
156  $r = Html::openElement( 'div', $attribs ) . $r . '</div>';
157 
158  return $r;
159  }
160 
161  protected function clearCategoryState() {
162  $this->articles = [];
163  $this->articles_start_char = [];
164  $this->children = [];
165  $this->children_start_char = [];
166  if ( $this->showGallery ) {
167  // Note that null for mode is taken to mean use default.
168  $mode = $this->getRequest()->getVal( 'gallerymode', null );
169  try {
170  $this->gallery = ImageGalleryBase::factory( $mode, $this->getContext() );
171  } catch ( Exception $e ) {
172  // User specified something invalid, fallback to default.
173  $this->gallery = ImageGalleryBase::factory( false, $this->getContext() );
174  }
175 
176  $this->gallery->setHideBadImages();
177  } else {
178  $this->imgsNoGallery = [];
179  $this->imgsNoGallery_start_char = [];
180  }
181  }
182 
189  public function addSubcategoryObject( Category $cat, $sortkey, $pageLength ) {
190  // Subcategory; strip the 'Category' namespace from the link text.
191  $title = $cat->getTitle();
192 
193  $this->children[] = $this->generateLink(
194  'subcat',
195  $title,
196  $title->isRedirect(),
197  htmlspecialchars( $title->getText() )
198  );
199 
200  $this->children_start_char[] =
201  $this->getSubcategorySortChar( $cat->getTitle(), $sortkey );
202  }
203 
215  private function generateLink( $type, Title $title, $isRedirect, $html = null ) {
216  $link = null;
217  $this->getHookRunner()->onCategoryViewer__generateLink( $type, $title, $html, $link );
218  if ( $link === null ) {
219  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
220  if ( $html !== null ) {
221  $html = new HtmlArmor( $html );
222  }
223  $link = $linkRenderer->makeLink( $title, $html );
224  }
225  if ( $isRedirect ) {
226  $link = '<span class="redirect-in-category">' . $link . '</span>';
227  }
228 
229  return $link;
230  }
231 
243  public function getSubcategorySortChar( $title, $sortkey ) {
244  if ( $title->getPrefixedText() == $sortkey ) {
245  $word = $title->getDBkey();
246  } else {
247  $word = $sortkey;
248  }
249 
250  $firstChar = $this->collation->getFirstLetter( $word );
251 
252  return $this->languageConverter->convert( $firstChar );
253  }
254 
262  public function addImage( Title $title, $sortkey, $pageLength, $isRedirect = false ) {
263  if ( $this->showGallery ) {
264  $flip = $this->flip['file'];
265  if ( $flip ) {
266  $this->gallery->insert( $title );
267  } else {
268  $this->gallery->add( $title );
269  }
270  } else {
271  $this->imgsNoGallery[] = $this->generateLink( 'image', $title, $isRedirect );
272 
273  $this->imgsNoGallery_start_char[] =
274  $this->languageConverter->convert( $this->collation->getFirstLetter( $sortkey ) );
275  }
276  }
277 
285  public function addPage( $title, $sortkey, $pageLength, $isRedirect = false ) {
286  $this->articles[] = $this->generateLink( 'page', $title, $isRedirect );
287 
288  $this->articles_start_char[] =
289  $this->languageConverter->convert( $this->collation->getFirstLetter( $sortkey ) );
290  }
291 
292  protected function finaliseCategoryState() {
293  if ( $this->flip['subcat'] ) {
294  $this->children = array_reverse( $this->children );
295  $this->children_start_char = array_reverse( $this->children_start_char );
296  }
297  if ( $this->flip['page'] ) {
298  $this->articles = array_reverse( $this->articles );
299  $this->articles_start_char = array_reverse( $this->articles_start_char );
300  }
301  if ( !$this->showGallery && $this->flip['file'] ) {
302  $this->imgsNoGallery = array_reverse( $this->imgsNoGallery );
303  $this->imgsNoGallery_start_char = array_reverse( $this->imgsNoGallery_start_char );
304  }
305  }
306 
307  protected function doCategoryQuery() {
308  $dbr = wfGetDB( DB_REPLICA, 'category' );
309 
310  $this->nextPage = [
311  'page' => null,
312  'subcat' => null,
313  'file' => null,
314  ];
315  $this->prevPage = [
316  'page' => null,
317  'subcat' => null,
318  'file' => null,
319  ];
320 
321  $this->flip = [ 'page' => false, 'subcat' => false, 'file' => false ];
322 
323  foreach ( [ 'page', 'subcat', 'file' ] as $type ) {
324  # Get the sortkeys for start/end, if applicable. Note that if
325  # the collation in the database differs from the one
326  # set in $wgCategoryCollation, pagination might go totally haywire.
327  $extraConds = [ 'cl_type' => $type ];
328  if ( isset( $this->from[$type] ) ) {
329  $extraConds[] = 'cl_sortkey >= '
330  . $dbr->addQuotes( $this->collation->getSortKey( $this->from[$type] ) );
331  } elseif ( isset( $this->until[$type] ) ) {
332  $extraConds[] = 'cl_sortkey < '
333  . $dbr->addQuotes( $this->collation->getSortKey( $this->until[$type] ) );
334  $this->flip[$type] = true;
335  }
336 
337  $res = $dbr->select(
338  [ 'page', 'categorylinks', 'category' ],
339  array_merge(
341  [
342  'page_namespace',
343  'page_title',
344  'cl_sortkey',
345  'cat_id',
346  'cat_title',
347  'cat_subcats',
348  'cat_pages',
349  'cat_files',
350  'cl_sortkey_prefix',
351  'cl_collation'
352  ]
353  ),
354  array_merge( [ 'cl_to' => $this->title->getDBkey() ], $extraConds ),
355  __METHOD__,
356  [
357  'USE INDEX' => [ 'categorylinks' => 'cl_sortkey' ],
358  'LIMIT' => $this->limit + 1,
359  'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey',
360  ],
361  [
362  'categorylinks' => [ 'JOIN', 'cl_from = page_id' ],
363  'category' => [ 'LEFT JOIN', [
364  'cat_title = page_title',
365  'page_namespace' => NS_CATEGORY
366  ] ]
367  ]
368  );
369 
370  $this->getHookRunner()->onCategoryViewer__doCategoryQuery( $type, $res );
371  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
372 
373  $count = 0;
374  foreach ( $res as $row ) {
375  $title = Title::newFromRow( $row );
376  $linkCache->addGoodLinkObjFromRow( $title, $row );
377 
378  if ( $row->cl_collation === '' ) {
379  // Hack to make sure that while updating from 1.16 schema
380  // and db is inconsistent, that the sky doesn't fall.
381  // See r83544. Could perhaps be removed in a couple decades...
382  $humanSortkey = $row->cl_sortkey;
383  } else {
384  $humanSortkey = $title->getCategorySortkey( $row->cl_sortkey_prefix );
385  }
386 
387  if ( ++$count > $this->limit ) {
388  # We've reached the one extra which shows that there
389  # are additional pages to be had. Stop here...
390  $this->nextPage[$type] = $humanSortkey;
391  break;
392  }
393  if ( $count == $this->limit ) {
394  $this->prevPage[$type] = $humanSortkey;
395  }
396 
397  if ( $title->getNamespace() === NS_CATEGORY ) {
398  $cat = Category::newFromRow( $row, $title );
399  $this->addSubcategoryObject( $cat, $humanSortkey, $row->page_len );
400  } elseif ( $title->getNamespace() === NS_FILE ) {
401  $this->addImage( $title, $humanSortkey, $row->page_len, $row->page_is_redirect );
402  } else {
403  $this->addPage( $title, $humanSortkey, $row->page_len, $row->page_is_redirect );
404  }
405  }
406  }
407  }
408 
412  protected function getCategoryTop() {
413  $r = $this->getCategoryBottom();
414  return $r === ''
415  ? $r
416  : "<br style=\"clear:both;\"/>\n" . $r;
417  }
418 
422  protected function getSubcategorySection() {
423  # Don't show subcategories section if there are none.
424  $r = '';
425  $rescnt = count( $this->children );
426  $dbcnt = $this->cat->getSubcatCount();
427  // This function should be called even if the result isn't used, it has side-effects
428  $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'subcat' );
429 
430  if ( $rescnt > 0 ) {
431  # Showing subcategories
432  $r .= "<div id=\"mw-subcategories\">\n";
433  $r .= '<h2>' . $this->msg( 'subcategories' )->parse() . "</h2>\n";
434  $r .= $countmsg;
435  $r .= $this->getSectionPagingLinks( 'subcat' );
436  $r .= $this->formatList( $this->children, $this->children_start_char );
437  $r .= $this->getSectionPagingLinks( 'subcat' );
438  $r .= "\n</div>";
439  }
440  return $r;
441  }
442 
446  protected function getPagesSection() {
447  $name = $this->getOutput()->getUnprefixedDisplayTitle();
448  # Don't show articles section if there are none.
449  $r = '';
450 
451  # @todo FIXME: Here and in the other two sections: we don't need to bother
452  # with this rigmarole if the entire category contents fit on one page
453  # and have already been retrieved. We can just use $rescnt in that
454  # case and save a query and some logic.
455  $dbcnt = $this->cat->getPageCount() - $this->cat->getSubcatCount()
456  - $this->cat->getFileCount();
457  $rescnt = count( $this->articles );
458  // This function should be called even if the result isn't used, it has side-effects
459  $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'article' );
460 
461  if ( $rescnt > 0 ) {
462  $r = "<div id=\"mw-pages\">\n";
463  $r .= '<h2>' . $this->msg( 'category_header' )->rawParams( $name )->parse() . "</h2>\n";
464  $r .= $countmsg;
465  $r .= $this->getSectionPagingLinks( 'page' );
466  $r .= $this->formatList( $this->articles, $this->articles_start_char );
467  $r .= $this->getSectionPagingLinks( 'page' );
468  $r .= "\n</div>";
469  }
470  return $r;
471  }
472 
476  protected function getImageSection() {
477  $name = $this->getOutput()->getUnprefixedDisplayTitle();
478  $r = '';
479  $rescnt = $this->showGallery ? $this->gallery->count() : count( $this->imgsNoGallery );
480  $dbcnt = $this->cat->getFileCount();
481  // This function should be called even if the result isn't used, it has side-effects
482  $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'file' );
483 
484  if ( $rescnt > 0 ) {
485  $r .= "<div id=\"mw-category-media\">\n";
486  $r .= '<h2>' .
487  $this->msg( 'category-media-header' )->rawParams( $name )->parse() .
488  "</h2>\n";
489  $r .= $countmsg;
490  $r .= $this->getSectionPagingLinks( 'file' );
491  if ( $this->showGallery ) {
492  $r .= $this->gallery->toHTML();
493  } else {
494  $r .= $this->formatList( $this->imgsNoGallery, $this->imgsNoGallery_start_char );
495  }
496  $r .= $this->getSectionPagingLinks( 'file' );
497  $r .= "\n</div>";
498  }
499  return $r;
500  }
501 
509  private function getSectionPagingLinks( $type ) {
510  if ( isset( $this->until[$type] ) ) {
511  // The new value for the until parameter should be pointing to the first
512  // result displayed on the page which is the second last result retrieved
513  // from the database.The next link should have a from parameter pointing
514  // to the until parameter of the current page.
515  if ( $this->nextPage[$type] !== null ) {
516  return $this->pagingLinks( $this->prevPage[$type], $this->until[$type], $type );
517  } else {
518  // If the nextPage variable is null, it means that we have reached the first page
519  // and therefore the previous link should be disabled.
520  return $this->pagingLinks( null, $this->until[$type], $type );
521  }
522  } elseif ( $this->nextPage[$type] !== null || isset( $this->from[$type] ) ) {
523  return $this->pagingLinks( $this->from[$type], $this->nextPage[$type], $type );
524  } else {
525  return '';
526  }
527  }
528 
532  protected function getCategoryBottom() {
533  return '';
534  }
535 
546  private function formatList( $articles, $articles_start_char, $cutoff = 6 ) {
547  $list = '';
548  if ( count( $articles ) > $cutoff ) {
550  } elseif ( count( $articles ) > 0 ) {
551  // for short lists of articles in categories.
553  }
554 
555  $pageLang = $this->title->getPageLanguage();
556  $attribs = [ 'lang' => $pageLang->getHtmlCode(), 'dir' => $pageLang->getDir(),
557  'class' => 'mw-content-' . $pageLang->getDir() ];
558  $list = Html::rawElement( 'div', $attribs, $list );
559 
560  return $list;
561  }
562 
577  public static function columnList( $articles, $articles_start_char ) {
578  $columns = array_combine( $articles, $articles_start_char );
579 
580  $ret = Html::openElement( 'div', [ 'class' => 'mw-category' ] );
581 
582  $colContents = [];
583 
584  # Kind of like array_flip() here, but we keep duplicates in an
585  # array instead of dropping them.
586  foreach ( $columns as $article => $char ) {
587  if ( !isset( $colContents[$char] ) ) {
588  $colContents[$char] = [];
589  }
590  $colContents[$char][] = $article;
591  }
592 
593  foreach ( $colContents as $char => $articles ) {
594  # Change space to non-breaking space to keep headers aligned
595  $h3char = $char === ' ' ? "\u{00A0}" : htmlspecialchars( $char );
596 
597  $ret .= '<div class="mw-category-group"><h3>' . $h3char;
598  $ret .= "</h3>\n";
599 
600  $ret .= '<ul><li>';
601  $ret .= implode( "</li>\n<li>", $articles );
602  $ret .= '</li></ul></div>';
603 
604  }
605 
606  $ret .= Html::closeElement( 'div' );
607  return $ret;
608  }
609 
618  public static function shortList( $articles, $articles_start_char ) {
619  $r = '<h3>' . htmlspecialchars( $articles_start_char[0] ) . "</h3>\n";
620  $r .= '<ul><li>' . $articles[0] . '</li>';
621  $articleCount = count( $articles );
622  for ( $index = 1; $index < $articleCount; $index++ ) {
623  if ( $articles_start_char[$index] != $articles_start_char[$index - 1] ) {
624  $r .= "</ul><h3>" . htmlspecialchars( $articles_start_char[$index] ) . "</h3>\n<ul>";
625  }
626 
627  $r .= "<li>{$articles[$index]}</li>";
628  }
629  $r .= '</ul>';
630  return $r;
631  }
632 
642  private function pagingLinks( $first, $last, $type = '' ) {
643  $prevLink = $this->msg( 'prev-page' )->escaped();
644 
645  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
646  if ( $first != '' ) {
647  $prevQuery = $this->query;
648  $prevQuery["{$type}until"] = $first;
649  unset( $prevQuery["{$type}from"] );
650  $prevLink = $linkRenderer->makeKnownLink(
651  $this->addFragmentToTitle( $this->title, $type ),
652  new HtmlArmor( $prevLink ),
653  [],
654  $prevQuery
655  );
656  }
657 
658  $nextLink = $this->msg( 'next-page' )->escaped();
659 
660  if ( $last != '' ) {
661  $lastQuery = $this->query;
662  $lastQuery["{$type}from"] = $last;
663  unset( $lastQuery["{$type}until"] );
664  $nextLink = $linkRenderer->makeKnownLink(
665  $this->addFragmentToTitle( $this->title, $type ),
666  new HtmlArmor( $nextLink ),
667  [],
668  $lastQuery
669  );
670  }
671 
672  return $this->msg( 'categoryviewer-pagedlinks' )->rawParams( $prevLink, $nextLink )->escaped();
673  }
674 
684  private function addFragmentToTitle( $title, $section ) {
685  switch ( $section ) {
686  case 'page':
687  $fragment = 'mw-pages';
688  break;
689  case 'subcat':
690  $fragment = 'mw-subcategories';
691  break;
692  case 'file':
693  $fragment = 'mw-category-media';
694  break;
695  default:
696  throw new MWException( __METHOD__ .
697  " Invalid section $section." );
698  }
699 
701  $title->getDBkey(), $fragment );
702  }
703 
714  private function getCountMessage( $rescnt, $dbcnt, $type ) {
715  // There are three cases:
716  // 1) The category table figure seems sane. It might be wrong, but
717  // we can't do anything about it if we don't recalculate it on ev-
718  // ery category view.
719  // 2) The category table figure isn't sane, like it's smaller than the
720  // number of actual results, *but* the number of results is less
721  // than $this->limit and there's no offset. In this case we still
722  // know the right figure.
723  // 3) We have no idea.
724 
725  // Check if there's a "from" or "until" for anything
726 
727  // This is a little ugly, but we seem to use different names
728  // for the paging types then for the messages.
729  if ( $type === 'article' ) {
730  $pagingType = 'page';
731  } else {
732  $pagingType = $type;
733  }
734 
735  $fromOrUntil = false;
736  if ( isset( $this->from[$pagingType] ) || isset( $this->until[$pagingType] ) ) {
737  $fromOrUntil = true;
738  }
739 
740  if ( $dbcnt == $rescnt ||
741  ( ( $rescnt == $this->limit || $fromOrUntil ) && $dbcnt > $rescnt )
742  ) {
743  // Case 1: seems sane.
744  $totalcnt = $dbcnt;
745  } elseif ( $rescnt < $this->limit && !$fromOrUntil ) {
746  // Case 2: not sane, but salvageable. Use the number of results.
747  $totalcnt = $rescnt;
748  } else {
749  // Case 3: hopeless. Don't give a total count at all.
750  // Messages: category-subcat-count-limited, category-article-count-limited,
751  // category-file-count-limited
752  return $this->msg( "category-$type-count-limited" )->numParams( $rescnt )->parseAsBlock();
753  }
754  // Messages: category-subcat-count, category-article-count, category-file-count
755  return $this->msg( "category-$type-count" )->numParams( $rescnt, $totalcnt )->parseAsBlock();
756  }
757 }
CategoryViewer\$children
array $children
Definition: CategoryViewer.php:45
CategoryViewer\$query
array $query
The original query array, to be used in generating paging links.
Definition: CategoryViewer.php:81
Category\getTitle
getTitle()
Definition: Category.php:258
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:38
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:71
CategoryViewer\shortList
static shortList( $articles, $articles_start_char)
Format a list of articles chunked by letter in a bullet list.
Definition: CategoryViewer.php:618
CategoryViewer\$gallery
ImageGalleryBase $gallery
Definition: CategoryViewer.php:75
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:46
HtmlArmor
Marks HTML that shouldn't be escaped.
Definition: HtmlArmor.php:30
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:180
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
CategoryViewer\$languageConverter
ILanguageConverter $languageConverter
Definition: CategoryViewer.php:84
ImageGalleryBase
Image gallery.
Definition: ImageGalleryBase.php:32
CategoryViewer\addFragmentToTitle
addFragmentToTitle( $title, $section)
Takes a title, and adds the fragment identifier that corresponds to the correct segment of the catego...
Definition: CategoryViewer.php:684
Category
Category objects are immutable, strictly speaking.
Definition: Category.php:32
CategoryViewer\columnList
static columnList( $articles, $articles_start_char)
Format a list of articles chunked by letter in a three-column list, ordered vertically.
Definition: CategoryViewer.php:577
CategoryViewer\getCountMessage
getCountMessage( $rescnt, $dbcnt, $type)
What to do if the category table conflicts with the number of results returned? This function says wh...
Definition: CategoryViewer.php:714
Title\getPrefixedText
getPrefixedText()
Get the prefixed title with spaces.
Definition: Title.php:1895
CategoryViewer\getImageSection
getImageSection()
Definition: CategoryViewer.php:476
CategoryViewer\getPagesSection
getPagesSection()
Definition: CategoryViewer.php:446
CategoryViewer\getSubcategorySortChar
getSubcategorySortChar( $title, $sortkey)
Get the character to be used for sorting subcategories.
Definition: CategoryViewer.php:243
CategoryViewer\$articles
string[] $articles
Definition: CategoryViewer.php:39
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:80
CategoryViewer\$imgsNoGallery_start_char
array $imgsNoGallery_start_char
Definition: CategoryViewer.php:54
$res
$res
Definition: testCompression.php:57
CategoryViewer\clearCategoryState
clearCategoryState()
Definition: CategoryViewer.php:161
LinkCache\getSelectFields
static getSelectFields()
Fields that LinkCache needs to select.
Definition: LinkCache.php:233
Collation
Definition: Collation.php:30
CategoryViewer\__construct
__construct( $title, IContextSource $context, $from=[], $until=[], $query=[])
Definition: CategoryViewer.php:95
CategoryViewer\formatList
formatList( $articles, $articles_start_char, $cutoff=6)
Format a list of articles chunked by letter, either as a bullet list or a columnar format,...
Definition: CategoryViewer.php:546
CategoryViewer\finaliseCategoryState
finaliseCategoryState()
Definition: CategoryViewer.php:292
CategoryViewer\doCategoryQuery
doCategoryQuery()
Definition: CategoryViewer.php:307
$dbr
$dbr
Definition: testCompression.php:54
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:152
Collation\singleton
static singleton()
Definition: Collation.php:37
CategoryViewer\$cat
Category $cat
Category object for this page.
Definition: CategoryViewer.php:78
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:318
CategoryViewer\getSectionPagingLinks
getSectionPagingLinks( $type)
Get the paging links for a section (subcats/pages/files), to go at the top and bottom of the output.
Definition: CategoryViewer.php:509
Title\getDBkey
getDBkey()
Get the main part with underscores.
Definition: Title.php:1058
MWException
MediaWiki exception.
Definition: MWException.php:29
CategoryViewer\$articles_start_char
array $articles_start_char
Definition: CategoryViewer.php:42
CategoryViewer\$imgsNoGallery
array $imgsNoGallery
Definition: CategoryViewer.php:57
Title\getNamespace
getNamespace()
Get the namespace index, i.e.
Definition: Title.php:1067
CategoryViewer\$collation
Collation $collation
Definition: CategoryViewer.php:72
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:582
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2306
Title\getCategorySortkey
getCategorySortkey( $prefix='')
Returns the raw sort key to be used for categories, with the specified prefix.
Definition: Title.php:4243
ContextSource\getOutput
getOutput()
Definition: ContextSource.php:125
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:32
CategoryViewer\$flip
array $flip
Definition: CategoryViewer.php:66
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:650
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
CategoryViewer\addSubcategoryObject
addSubcategoryObject(Category $cat, $sortkey, $pageLength)
Add a subcategory to the internal lists, using a Category object.
Definition: CategoryViewer.php:189
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:62
CategoryViewer\getCategoryBottom
getCategoryBottom()
Definition: CategoryViewer.php:532
CategoryViewer\$from
array $from
Definition: CategoryViewer.php:33
Category\newFromRow
static newFromRow( $row, $title=null)
Factory function, for constructing a Category object from a result set.
Definition: Category.php:186
CategoryViewer\getHTML
getHTML()
Format the category data list.
Definition: CategoryViewer.php:119
CategoryViewer\$prevPage
array $prevPage
Definition: CategoryViewer.php:63
Category\newFromTitle
static newFromTitle( $title)
Factory function.
Definition: Category.php:153
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:196
ILanguageConverter
The shared interface for all language converters.
Definition: ILanguageConverter.php:29
CategoryViewer
Definition: CategoryViewer.php:26
CategoryViewer\$title
Title $title
Definition: CategoryViewer.php:69
CategoryViewer\generateLink
generateLink( $type, Title $title, $isRedirect, $html=null)
Definition: CategoryViewer.php:215
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:57
Title
Represents a title within MediaWiki.
Definition: Title.php:49
Title\isRedirect
isRedirect( $flags=0)
Is this an article that is a redirect page? Uses link cache, adding it if necessary.
Definition: Title.php:3209
CategoryViewer\pagingLinks
pagingLinks( $first, $last, $type='')
Create paging links, as a helper method to getSectionPagingLinks().
Definition: CategoryViewer.php:642
IContextSource\getConfig
getConfig()
Get the site configuration.
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:254
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:212
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:78
CategoryViewer\$limit
int $limit
Definition: CategoryViewer.php:30
CategoryViewer\$showGallery
bool $showGallery
Definition: CategoryViewer.php:51
CategoryViewer\getSubcategorySection
getSubcategorySection()
Definition: CategoryViewer.php:422
ImageGalleryBase\factory
static factory( $mode=false, IContextSource $context=null)
Get a new image gallery.
Definition: ImageGalleryBase.php:116
CategoryViewer\addPage
addPage( $title, $sortkey, $pageLength, $isRedirect=false)
Add a miscellaneous page.
Definition: CategoryViewer.php:285
NS_FILE
const NS_FILE
Definition: Defines.php:70
CategoryViewer\$nextPage
array $nextPage
Definition: CategoryViewer.php:60
CategoryViewer\$children_start_char
array $children_start_char
Definition: CategoryViewer.php:48
CategoryViewer\getCategoryTop
getCategoryTop()
Definition: CategoryViewer.php:412
CategoryViewer\addImage
addImage(Title $title, $sortkey, $pageLength, $isRedirect=false)
Add a page in the image namespace.
Definition: CategoryViewer.php:262
Title\getText
getText()
Get the text form (spaces not underscores) of the main part.
Definition: Title.php:1040
$type
$type
Definition: testCompression.php:52
CategoryViewer\$until
array $until
Definition: CategoryViewer.php:36