MediaWiki  master
CategoryViewer.php
Go to the documentation of this file.
1 <?php
23 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
28 
30  use ProtectedHookAccessorTrait;
32 
34  public $limit;
35 
37  public $from;
38 
40  public $until;
41 
43  public $articles;
44 
47 
49  public $children;
50 
53 
55  public $showGallery;
56 
59 
62 
64  public $nextPage;
65 
67  protected $prevPage;
68 
70  public $flip;
71 
73  protected $page;
74 
76  public $collation;
77 
79  public $gallery;
80 
82  private $cat;
83 
85  private $query;
86 
89 
99  public function __construct( PageIdentity $page, IContextSource $context, array $from = [],
100  array $until = [], array $query = []
101  ) {
102  $this->page = $page;
103 
105  'title',
106  '1.37',
107  function (): Title {
108  return Title::castFromPageIdentity( $this->page );
109  },
110  function ( PageIdentity $page ) {
111  $this->page = $page;
112  }
113  );
114 
115  $this->setContext( $context );
116  $this->getOutput()->addModuleStyles( [
117  'mediawiki.action.view.categoryPage.styles'
118  ] );
119  $this->from = $from;
120  $this->until = $until;
121  $this->limit = $context->getConfig()->get( 'CategoryPagingLimit' );
122  $this->cat = Category::newFromTitle( $page );
123  $this->query = $query;
124  $this->collation = MediaWikiServices::getInstance()->getCollationFactory()->getCategoryCollation();
125  $this->languageConverter = MediaWikiServices::getInstance()
126  ->getLanguageConverterFactory()->getLanguageConverter();
127  unset( $this->query['title'] );
128  }
129 
135  public function getHTML() {
136  $this->showGallery = $this->getConfig()->get( 'CategoryMagicGallery' )
137  && !$this->getOutput()->mNoGallery;
138 
139  $this->clearCategoryState();
140  $this->doCategoryQuery();
141  $this->finaliseCategoryState();
142 
143  $r = $this->getSubcategorySection() .
144  $this->getPagesSection() .
145  $this->getImageSection();
146 
147  if ( $r == '' ) {
148  // If there is no category content to display, only
149  // show the top part of the navigation links.
150  // @todo FIXME: Cannot be completely suppressed because it
151  // is unknown if 'until' or 'from' makes this
152  // give 0 results.
153  $r = $this->getCategoryTop();
154  } else {
155  $r = $this->getCategoryTop() .
156  $r .
157  $this->getCategoryBottom();
158  }
159 
160  // Give a proper message if category is empty
161  if ( $r == '' ) {
162  $r = $this->msg( 'category-empty' )->parseAsBlock();
163  }
164 
165  $lang = $this->getLanguage();
166  $attribs = [
167  'class' => 'mw-category-generated',
168  'lang' => $lang->getHtmlCode(),
169  'dir' => $lang->getDir()
170  ];
171  # put a div around the headings which are in the user language
172  $r = Html::rawElement( 'div', $attribs, $r );
173 
174  return $r;
175  }
176 
177  protected function clearCategoryState() {
178  $this->articles = [];
179  $this->articles_start_char = [];
180  $this->children = [];
181  $this->children_start_char = [];
182  if ( $this->showGallery ) {
183  // Note that null for mode is taken to mean use default.
184  $mode = $this->getRequest()->getVal( 'gallerymode', null );
185  try {
186  $this->gallery = ImageGalleryBase::factory( $mode, $this->getContext() );
187  } catch ( Exception $e ) {
188  // User specified something invalid, fallback to default.
189  $this->gallery = ImageGalleryBase::factory( false, $this->getContext() );
190  }
191 
192  $this->gallery->setHideBadImages();
193  } else {
194  $this->imgsNoGallery = [];
195  $this->imgsNoGallery_start_char = [];
196  }
197  }
198 
205  public function addSubcategoryObject( Category $cat, $sortkey, $pageLength ) {
206  // Subcategory; strip the 'Category' namespace from the link text.
207  $pageRecord = MediaWikiServices::getInstance()->getPageStore()
208  ->getPageByReference( $cat->getPage() );
209 
210  $this->children[] = $this->generateLink(
211  'subcat',
212  $pageRecord,
213  $pageRecord->isRedirect(),
214  htmlspecialchars( str_replace( '_', ' ', $pageRecord->getDBkey() ) )
215  );
216 
217  $this->children_start_char[] =
218  $this->getSubcategorySortChar( $cat->getPage(), $sortkey );
219  }
220 
232  private function generateLink(
233  string $type, PageReference $page, bool $isRedirect, ?string $html = null
234  ): string {
235  $link = null;
236  $legacyTitle = MediaWikiServices::getInstance()->getTitleFactory()
237  ->castFromPageReference( $page );
238  $this->getHookRunner()->onCategoryViewer__generateLink( $type, $legacyTitle, $html, $link );
239  if ( $link === null ) {
240  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
241  if ( $html !== null ) {
242  $html = new HtmlArmor( $html );
243  }
244  $link = $linkRenderer->makeLink( $page, $html );
245  }
246  if ( $isRedirect ) {
247  $link = Html::rawElement(
248  'span',
249  [ 'class' => 'redirect-in-category' ],
250  $link
251  );
252  }
253 
254  return $link;
255  }
256 
268  public function getSubcategorySortChar( PageIdentity $page, string $sortkey ): string {
269  $titleText = MediaWikiServices::getInstance()->getTitleFormatter()
270  ->getPrefixedText( $page );
271  if ( $titleText === $sortkey ) {
272  $word = $page->getDBkey();
273  } else {
274  $word = $sortkey;
275  }
276 
277  $firstChar = $this->collation->getFirstLetter( $word );
278 
279  return $this->languageConverter->convert( $firstChar );
280  }
281 
289  public function addImage(
290  PageReference $page, string $sortkey, int $pageLength, bool $isRedirect = false
291  ): void {
292  $title = MediaWikiServices::getInstance()->getTitleFactory()
293  ->castFromPageReference( $page );
294  if ( $this->showGallery ) {
295  $flip = $this->flip['file'];
296  if ( $flip ) {
297  $this->gallery->insert( $title );
298  } else {
299  $this->gallery->add( $title );
300  }
301  } else {
302  $this->imgsNoGallery[] = $this->generateLink( 'image', $page, $isRedirect );
303 
304  $this->imgsNoGallery_start_char[] =
305  $this->languageConverter->convert( $this->collation->getFirstLetter( $sortkey ) );
306  }
307  }
308 
316  public function addPage(
317  PageReference $page, string $sortkey, int $pageLength, bool $isRedirect = false
318  ): void {
319  $this->articles[] = $this->generateLink( 'page', $page, $isRedirect );
320 
321  $this->articles_start_char[] =
322  $this->languageConverter->convert( $this->collation->getFirstLetter( $sortkey ) );
323  }
324 
325  protected function finaliseCategoryState() {
326  if ( $this->flip['subcat'] ) {
327  $this->children = array_reverse( $this->children );
328  $this->children_start_char = array_reverse( $this->children_start_char );
329  }
330  if ( $this->flip['page'] ) {
331  $this->articles = array_reverse( $this->articles );
332  $this->articles_start_char = array_reverse( $this->articles_start_char );
333  }
334  if ( !$this->showGallery && $this->flip['file'] ) {
335  $this->imgsNoGallery = array_reverse( $this->imgsNoGallery );
336  $this->imgsNoGallery_start_char = array_reverse( $this->imgsNoGallery_start_char );
337  }
338  }
339 
340  protected function doCategoryQuery() {
341  $dbr = wfGetDB( DB_REPLICA, 'category' );
342 
343  $this->nextPage = [
344  'page' => null,
345  'subcat' => null,
346  'file' => null,
347  ];
348  $this->prevPage = [
349  'page' => null,
350  'subcat' => null,
351  'file' => null,
352  ];
353 
354  $this->flip = [ 'page' => false, 'subcat' => false, 'file' => false ];
355 
356  foreach ( [ 'page', 'subcat', 'file' ] as $type ) {
357  # Get the sortkeys for start/end, if applicable. Note that if
358  # the collation in the database differs from the one
359  # set in $wgCategoryCollation, pagination might go totally haywire.
360  $extraConds = [ 'cl_type' => $type ];
361  if ( isset( $this->from[$type] ) ) {
362  $extraConds[] = 'cl_sortkey >= '
363  . $dbr->addQuotes( $this->collation->getSortKey( $this->from[$type] ) );
364  } elseif ( isset( $this->until[$type] ) ) {
365  $extraConds[] = 'cl_sortkey < '
366  . $dbr->addQuotes( $this->collation->getSortKey( $this->until[$type] ) );
367  $this->flip[$type] = true;
368  }
369 
370  $res = $dbr->select(
371  [ 'page', 'categorylinks', 'category' ],
372  array_merge(
374  [
375  'page_namespace',
376  'page_title',
377  'cl_sortkey',
378  'cat_id',
379  'cat_title',
380  'cat_subcats',
381  'cat_pages',
382  'cat_files',
383  'cl_sortkey_prefix',
384  'cl_collation'
385  ]
386  ),
387  array_merge( [ 'cl_to' => $this->page->getDBkey() ], $extraConds ),
388  __METHOD__,
389  [
390  'USE INDEX' => [ 'categorylinks' => 'cl_sortkey' ],
391  'LIMIT' => $this->limit + 1,
392  'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey',
393  ],
394  [
395  'categorylinks' => [ 'JOIN', 'cl_from = page_id' ],
396  'category' => [ 'LEFT JOIN', [
397  'cat_title = page_title',
398  'page_namespace' => NS_CATEGORY
399  ] ]
400  ]
401  );
402 
403  $this->getHookRunner()->onCategoryViewer__doCategoryQuery( $type, $res );
404  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
405 
406  $count = 0;
407  foreach ( $res as $row ) {
408  $title = Title::newFromRow( $row );
409  $linkCache->addGoodLinkObjFromRow( $title, $row );
410 
411  if ( $row->cl_collation === '' ) {
412  // Hack to make sure that while updating from 1.16 schema
413  // and db is inconsistent, that the sky doesn't fall.
414  // See r83544. Could perhaps be removed in a couple decades...
415  $humanSortkey = $row->cl_sortkey;
416  } else {
417  $humanSortkey = $title->getCategorySortkey( $row->cl_sortkey_prefix );
418  }
419 
420  if ( ++$count > $this->limit ) {
421  # We've reached the one extra which shows that there
422  # are additional pages to be had. Stop here...
423  $this->nextPage[$type] = $humanSortkey;
424  break;
425  }
426  if ( $count == $this->limit ) {
427  $this->prevPage[$type] = $humanSortkey;
428  }
429 
430  if ( $title->getNamespace() === NS_CATEGORY ) {
431  $cat = Category::newFromRow( $row, $title );
432  $this->addSubcategoryObject( $cat, $humanSortkey, $row->page_len );
433  } elseif ( $title->getNamespace() === NS_FILE ) {
434  $this->addImage( $title, $humanSortkey, $row->page_len, $row->page_is_redirect );
435  } else {
436  $this->addPage( $title, $humanSortkey, $row->page_len, $row->page_is_redirect );
437  }
438  }
439  }
440  }
441 
445  protected function getCategoryTop() {
446  $r = $this->getCategoryBottom();
447  return $r === ''
448  ? $r
449  : "<br style=\"clear:both;\"/>\n" . $r;
450  }
451 
455  protected function getSubcategorySection() {
456  # Don't show subcategories section if there are none.
457  $r = '';
458  $rescnt = count( $this->children );
459  $dbcnt = $this->cat->getSubcatCount();
460  // This function should be called even if the result isn't used, it has side-effects
461  $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'subcat' );
462 
463  if ( $rescnt > 0 ) {
464  # Showing subcategories
465  $r .= Html::openElement( 'div', [ 'id' => 'mw-subcategories' ] ) . "\n";
466  $r .= Html::rawElement( 'h2', [], $this->msg( 'subcategories' )->parse() ) . "\n";
467  $r .= $countmsg;
468  $r .= $this->getSectionPagingLinks( 'subcat' );
469  $r .= $this->formatList( $this->children, $this->children_start_char );
470  $r .= $this->getSectionPagingLinks( 'subcat' );
471  $r .= "\n" . Html::closeElement( 'div' );
472  }
473  return $r;
474  }
475 
479  protected function getPagesSection() {
480  $name = $this->getOutput()->getUnprefixedDisplayTitle();
481  # Don't show articles section if there are none.
482  $r = '';
483 
484  # @todo FIXME: Here and in the other two sections: we don't need to bother
485  # with this rigmarole if the entire category contents fit on one page
486  # and have already been retrieved. We can just use $rescnt in that
487  # case and save a query and some logic.
488  $dbcnt = $this->cat->getPageCount() - $this->cat->getSubcatCount()
489  - $this->cat->getFileCount();
490  $rescnt = count( $this->articles );
491  // This function should be called even if the result isn't used, it has side-effects
492  $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'article' );
493 
494  if ( $rescnt > 0 ) {
495  $r .= Html::openElement( 'div', [ 'id' => 'mw-pages' ] ) . "\n";
496  $r .= Html::rawElement(
497  'h2',
498  [],
499  $this->msg( 'category_header' )->rawParams( $name )->parse()
500  ) . "\n";
501  $r .= $countmsg;
502  $r .= $this->getSectionPagingLinks( 'page' );
503  $r .= $this->formatList( $this->articles, $this->articles_start_char );
504  $r .= $this->getSectionPagingLinks( 'page' );
505  $r .= "\n" . Html::closeElement( 'div' );
506  }
507  return $r;
508  }
509 
513  protected function getImageSection() {
514  $name = $this->getOutput()->getUnprefixedDisplayTitle();
515  $r = '';
516  $rescnt = $this->showGallery ? $this->gallery->count() : count( $this->imgsNoGallery );
517  $dbcnt = $this->cat->getFileCount();
518  // This function should be called even if the result isn't used, it has side-effects
519  $countmsg = $this->getCountMessage( $rescnt, $dbcnt, 'file' );
520 
521  if ( $rescnt > 0 ) {
522  $r .= Html::openElement( 'div', [ 'id' => 'mw-category-media' ] ) . "\n";
523  $r .= Html::rawElement(
524  'h2',
525  [],
526  $this->msg( 'category-media-header' )->rawParams( $name )->parse()
527  ) . "\n";
528  $r .= $countmsg;
529  $r .= $this->getSectionPagingLinks( 'file' );
530  if ( $this->showGallery ) {
531  $r .= $this->gallery->toHTML();
532  } else {
533  $r .= $this->formatList( $this->imgsNoGallery, $this->imgsNoGallery_start_char );
534  }
535  $r .= $this->getSectionPagingLinks( 'file' );
536  $r .= "\n" . Html::closeElement( 'div' );
537  }
538  return $r;
539  }
540 
548  private function getSectionPagingLinks( $type ) {
549  if ( isset( $this->until[$type] ) ) {
550  // The new value for the until parameter should be pointing to the first
551  // result displayed on the page which is the second last result retrieved
552  // from the database.The next link should have a from parameter pointing
553  // to the until parameter of the current page.
554  if ( $this->nextPage[$type] !== null ) {
555  return $this->pagingLinks( $this->prevPage[$type], $this->until[$type], $type );
556  } else {
557  // If the nextPage variable is null, it means that we have reached the first page
558  // and therefore the previous link should be disabled.
559  return $this->pagingLinks( null, $this->until[$type], $type );
560  }
561  } elseif ( $this->nextPage[$type] !== null || isset( $this->from[$type] ) ) {
562  return $this->pagingLinks( $this->from[$type], $this->nextPage[$type], $type );
563  } else {
564  return '';
565  }
566  }
567 
571  protected function getCategoryBottom() {
572  return '';
573  }
574 
585  private function formatList( $articles, $articles_start_char, $cutoff = 6 ) {
586  $list = '';
587  if ( count( $articles ) > $cutoff ) {
589  } elseif ( count( $articles ) > 0 ) {
590  // for short lists of articles in categories.
592  }
593 
594  $pageLang = MediaWikiServices::getInstance()->getTitleFactory()
595  ->castFromPageIdentity( $this->page )
596  ->getPageLanguage();
597  $attribs = [ 'lang' => $pageLang->getHtmlCode(), 'dir' => $pageLang->getDir(),
598  'class' => 'mw-content-' . $pageLang->getDir() ];
599  $list = Html::rawElement( 'div', $attribs, $list );
600 
601  return $list;
602  }
603 
618  public static function columnList( $articles, $articles_start_char ) {
619  $columns = array_combine( $articles, $articles_start_char );
620 
621  $ret = Html::openElement( 'div', [ 'class' => 'mw-category' ] );
622 
623  $colContents = [];
624 
625  # Kind of like array_flip() here, but we keep duplicates in an
626  # array instead of dropping them.
627  foreach ( $columns as $article => $char ) {
628  if ( !isset( $colContents[$char] ) ) {
629  $colContents[$char] = [];
630  }
631  $colContents[$char][] = $article;
632  }
633 
634  foreach ( $colContents as $char => $articles ) {
635  # Change space to non-breaking space to keep headers aligned
636  $h3char = $char === ' ' ? "\u{00A0}" : htmlspecialchars( $char );
637 
638  $ret .= Html::openELement( 'div', [ 'class' => 'mw-category-group' ] );
639  $ret .= Html::rawElement( 'h3', [], $h3char ) . "\n";
640  $ret .= Html::openElement( 'ul' );
641  $ret .= implode(
642  "\n",
643  array_map(
644  static function ( $article ) {
645  return Html::rawElement( 'li', [], $article );
646  },
647  $articles
648  )
649  );
650  $ret .= Html::closeElement( 'ul' ) . Html::closeElement( 'div' );
651 
652  }
653 
654  $ret .= Html::closeElement( 'div' );
655  return $ret;
656  }
657 
666  public static function shortList( $articles, $articles_start_char ) {
667  $r = '<h3>' . htmlspecialchars( $articles_start_char[0] ) . "</h3>\n";
668  $r .= '<ul><li>' . $articles[0] . '</li>';
669  $articleCount = count( $articles );
670  for ( $index = 1; $index < $articleCount; $index++ ) {
671  if ( $articles_start_char[$index] != $articles_start_char[$index - 1] ) {
672  $r .= "</ul><h3>" . htmlspecialchars( $articles_start_char[$index] ) . "</h3>\n<ul>";
673  }
674 
675  $r .= "<li>{$articles[$index]}</li>";
676  }
677  $r .= '</ul>';
678  return $r;
679  }
680 
690  private function pagingLinks( $first, $last, $type = '' ) {
691  $prevLink = $this->msg( 'prev-page' )->escaped();
692 
693  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
694  if ( $first != '' ) {
695  $prevQuery = $this->query;
696  $prevQuery["{$type}until"] = $first;
697  unset( $prevQuery["{$type}from"] );
698  $prevLink = $linkRenderer->makeKnownLink(
699  $this->addFragmentToTitle( $this->page, $type ),
700  new HtmlArmor( $prevLink ),
701  [],
702  $prevQuery
703  );
704  }
705 
706  $nextLink = $this->msg( 'next-page' )->escaped();
707 
708  if ( $last != '' ) {
709  $lastQuery = $this->query;
710  $lastQuery["{$type}from"] = $last;
711  unset( $lastQuery["{$type}until"] );
712  $nextLink = $linkRenderer->makeKnownLink(
713  $this->addFragmentToTitle( $this->page, $type ),
714  new HtmlArmor( $nextLink ),
715  [],
716  $lastQuery
717  );
718  }
719 
720  return $this->msg( 'categoryviewer-pagedlinks' )->rawParams( $prevLink, $nextLink )->escaped();
721  }
722 
732  private function addFragmentToTitle( PageReference $page, string $section ): LinkTarget {
733  switch ( $section ) {
734  case 'page':
735  $fragment = 'mw-pages';
736  break;
737  case 'subcat':
738  $fragment = 'mw-subcategories';
739  break;
740  case 'file':
741  $fragment = 'mw-category-media';
742  break;
743  default:
744  throw new MWException( __METHOD__ .
745  " Invalid section $section." );
746  }
747 
748  return new TitleValue( $page->getNamespace(),
749  $page->getDBkey(), $fragment );
750  }
751 
762  private function getCountMessage( $rescnt, $dbcnt, $type ) {
763  // There are three cases:
764  // 1) The category table figure seems sane. It might be wrong, but
765  // we can't do anything about it if we don't recalculate it on ev-
766  // ery category view.
767  // 2) The category table figure isn't sane, like it's smaller than the
768  // number of actual results, *but* the number of results is less
769  // than $this->limit and there's no offset. In this case we still
770  // know the right figure.
771  // 3) We have no idea.
772 
773  // Check if there's a "from" or "until" for anything
774 
775  // This is a little ugly, but we seem to use different names
776  // for the paging types then for the messages.
777  if ( $type === 'article' ) {
778  $pagingType = 'page';
779  } else {
780  $pagingType = $type;
781  }
782 
783  $fromOrUntil = false;
784  if ( isset( $this->from[$pagingType] ) || isset( $this->until[$pagingType] ) ) {
785  $fromOrUntil = true;
786  }
787 
788  if ( $dbcnt == $rescnt ||
789  ( ( $rescnt == $this->limit || $fromOrUntil ) && $dbcnt > $rescnt )
790  ) {
791  // Case 1: seems sane.
792  $totalcnt = $dbcnt;
793  } elseif ( $rescnt < $this->limit && !$fromOrUntil ) {
794  // Case 2: not sane, but salvageable. Use the number of results.
795  $totalcnt = $rescnt;
796  } else {
797  // Case 3: hopeless. Don't give a total count at all.
798  // Messages: category-subcat-count-limited, category-article-count-limited,
799  // category-file-count-limited
800  return $this->msg( "category-$type-count-limited" )->numParams( $rescnt )->parseAsBlock();
801  }
802  // Messages: category-subcat-count, category-article-count, category-file-count
803  return $this->msg( "category-$type-count" )->numParams( $rescnt, $totalcnt )->parseAsBlock();
804  }
805 }
CategoryViewer\$children
array $children
Definition: CategoryViewer.php:49
CategoryViewer\$query
array $query
The original query array, to be used in generating paging links.
Definition: CategoryViewer.php:85
Page\PageIdentity
Interface for objects (potentially) representing an editable wiki page.
Definition: PageIdentity.php:64
CategoryViewer\$page
PageIdentity $page
Definition: CategoryViewer.php:73
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:39
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:72
CategoryViewer\shortList
static shortList( $articles, $articles_start_char)
Format a list of articles chunked by letter in a bullet list.
Definition: CategoryViewer.php:666
CategoryViewer\$gallery
ImageGalleryBase $gallery
Definition: CategoryViewer.php:79
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
HtmlArmor
Marks HTML that shouldn't be escaped.
Definition: HtmlArmor.php:30
Category\newFromTitle
static newFromTitle(PageIdentity $page)
Factory function.
Definition: Category.php:159
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:193
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
CategoryViewer\$languageConverter
ILanguageConverter $languageConverter
Definition: CategoryViewer.php:88
ImageGalleryBase
Image gallery.
Definition: ImageGalleryBase.php:32
Category
Category objects are immutable, strictly speaking.
Definition: Category.php:33
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:618
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:762
CategoryViewer\getImageSection
getImageSection()
Definition: CategoryViewer.php:513
CategoryViewer\getPagesSection
getPagesSection()
Definition: CategoryViewer.php:479
CategoryViewer\$articles
string[] $articles
Definition: CategoryViewer.php:43
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:81
CategoryViewer\$imgsNoGallery_start_char
array $imgsNoGallery_start_char
Definition: CategoryViewer.php:58
$res
$res
Definition: testCompression.php:57
CategoryViewer\clearCategoryState
clearCategoryState()
Definition: CategoryViewer.php:177
Page\PageReference
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
Definition: PageReference.php:49
CategoryViewer\getSubcategorySortChar
getSubcategorySortChar(PageIdentity $page, string $sortkey)
Get the character to be used for sorting subcategories.
Definition: CategoryViewer.php:268
LinkCache\getSelectFields
static getSelectFields()
Fields that LinkCache needs to select.
Definition: LinkCache.php:382
Collation
Definition: Collation.php:30
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:585
CategoryViewer\finaliseCategoryState
finaliseCategoryState()
Definition: CategoryViewer.php:325
Category\newFromRow
static newFromRow(stdClass $row, ?PageIdentity $page=null)
Factory function, for constructing a Category object from a result set.
Definition: Category.php:190
CategoryViewer\doCategoryQuery
doCategoryQuery()
Definition: CategoryViewer.php:340
Title\castFromPageIdentity
static castFromPageIdentity(?PageIdentity $pageIdentity)
Return a Title for a given PageIdentity.
Definition: Title.php:332
$dbr
$dbr
Definition: testCompression.php:54
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:153
CategoryViewer\$cat
Category $cat
Category object for this page.
Definition: CategoryViewer.php:82
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:316
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:548
Category\getPage
getPage()
Definition: Category.php:264
MWException
MediaWiki exception.
Definition: MWException.php:29
deprecatePublicPropertyFallback
deprecatePublicPropertyFallback(string $property, string $version, callable $getter, ?callable $setter=null, $class=null, $component=null)
Mark a removed public property as deprecated and provide fallback getter and setter callables.
Definition: DeprecationHelper.php:123
CategoryViewer\$articles_start_char
array $articles_start_char
Definition: CategoryViewer.php:46
CategoryViewer\$imgsNoGallery
array $imgsNoGallery
Definition: CategoryViewer.php:61
CategoryViewer\$collation
Collation $collation
Definition: CategoryViewer.php:76
Page\PageReference\getNamespace
getNamespace()
Returns the page's namespace number.
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:580
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2225
ContextSource\getOutput
getOutput()
Definition: ContextSource.php:126
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:33
CategoryViewer\$flip
array $flip
Definition: CategoryViewer.php:70
$title
$title
Definition: testCompression.php:38
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:205
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:63
CategoryViewer\getCategoryBottom
getCategoryBottom()
Definition: CategoryViewer.php:571
CategoryViewer\$from
array $from
Definition: CategoryViewer.php:37
CategoryViewer\getHTML
getHTML()
Format the category data list.
Definition: CategoryViewer.php:135
CategoryViewer\$prevPage
array $prevPage
Definition: CategoryViewer.php:67
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:197
CategoryViewer\addPage
addPage(PageReference $page, string $sortkey, int $pageLength, bool $isRedirect=false)
Add a miscellaneous page.
Definition: CategoryViewer.php:316
ILanguageConverter
The shared interface for all language converters.
Definition: ILanguageConverter.php:29
CategoryViewer
Definition: CategoryViewer.php:29
Page\PageReference\getDBkey
getDBkey()
Get the page title in DB key form.
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
Title
Represents a title within MediaWiki.
Definition: Title.php:48
CategoryViewer\generateLink
generateLink(string $type, PageReference $page, bool $isRedirect, ?string $html=null)
Definition: CategoryViewer.php:232
CategoryViewer\pagingLinks
pagingLinks( $first, $last, $type='')
Create paging links, as a helper method to getSectionPagingLinks().
Definition: CategoryViewer.php:690
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:252
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:78
CategoryViewer\__construct
__construct(PageIdentity $page, IContextSource $context, array $from=[], array $until=[], array $query=[])
Definition: CategoryViewer.php:99
CategoryViewer\$limit
int $limit
Definition: CategoryViewer.php:34
CategoryViewer\addImage
addImage(PageReference $page, string $sortkey, int $pageLength, bool $isRedirect=false)
Add a page in the image namespace.
Definition: CategoryViewer.php:289
CategoryViewer\$showGallery
bool $showGallery
Definition: CategoryViewer.php:55
CategoryViewer\getSubcategorySection
getSubcategorySection()
Definition: CategoryViewer.php:455
ImageGalleryBase\factory
static factory( $mode=false, IContextSource $context=null)
Get a new image gallery.
Definition: ImageGalleryBase.php:116
NS_FILE
const NS_FILE
Definition: Defines.php:70
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
CategoryViewer\$nextPage
array $nextPage
Definition: CategoryViewer.php:64
DeprecationHelper
trait DeprecationHelper
Use this trait in classes which have properties for which public access is deprecated or implementati...
Definition: DeprecationHelper.php:60
CategoryViewer\addFragmentToTitle
addFragmentToTitle(PageReference $page, string $section)
Takes a title, and adds the fragment identifier that corresponds to the correct segment of the catego...
Definition: CategoryViewer.php:732
CategoryViewer\$children_start_char
array $children_start_char
Definition: CategoryViewer.php:52
CategoryViewer\getCategoryTop
getCategoryTop()
Definition: CategoryViewer.php:445
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:40
$type
$type
Definition: testCompression.php:52
CategoryViewer\$until
array $until
Definition: CategoryViewer.php:40