MediaWiki  1.34.0
CategoryTree.php
Go to the documentation of this file.
1 <?php
26 
31 class CategoryTree {
32  public $mOptions = [];
33 
37  private $linkRenderer;
38 
43  public function __construct( array $options ) {
44  global $wgCategoryTreeDefaultOptions;
45  $this->linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
46 
47  // ensure default values and order of options.
48  // Order may become important, it may influence the cache key!
49  foreach ( $wgCategoryTreeDefaultOptions as $option => $default ) {
50  if ( isset( $options[$option] ) ) {
51  $this->mOptions[$option] = $options[$option];
52  } else {
53  $this->mOptions[$option] = $default;
54  }
55  }
56 
57  $this->mOptions['mode'] = self::decodeMode( $this->mOptions['mode'] );
58 
59  if ( $this->mOptions['mode'] == CategoryTreeMode::PARENTS ) {
60  // namespace filter makes no sense with CategoryTreeMode::PARENTS
61  $this->mOptions['namespaces'] = false;
62  }
63 
64  $this->mOptions['hideprefix'] = self::decodeHidePrefix( $this->mOptions['hideprefix'] );
65  $this->mOptions['showcount'] = self::decodeBoolean( $this->mOptions['showcount'] );
66  $this->mOptions['namespaces'] = self::decodeNamespaces( $this->mOptions['namespaces'] );
67 
68  if ( $this->mOptions['namespaces'] ) {
69  # automatically adjust mode to match namespace filter
70  if ( count( $this->mOptions['namespaces'] ) === 1
71  && $this->mOptions['namespaces'][0] == NS_CATEGORY ) {
72  $this->mOptions['mode'] = CategoryTreeMode::CATEGORIES;
73  } elseif ( !in_array( NS_FILE, $this->mOptions['namespaces'] ) ) {
74  $this->mOptions['mode'] = CategoryTreeMode::PAGES;
75  } else {
76  $this->mOptions['mode'] = CategoryTreeMode::ALL;
77  }
78  }
79  }
80 
85  public function getOption( $name ) {
86  return $this->mOptions[$name];
87  }
88 
92  private function isInverse() {
93  return $this->getOption( 'mode' ) == CategoryTreeMode::PARENTS;
94  }
95 
100  private static function decodeNamespaces( $nn ) {
101  if ( $nn === false || is_null( $nn ) ) {
102  return false;
103  }
104 
105  if ( !is_array( $nn ) ) {
106  $nn = preg_split( '![\s#:|]+!', $nn );
107  }
108 
109  $namespaces = [];
110  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
111  foreach ( $nn as $n ) {
112  if ( is_int( $n ) ) {
113  $ns = $n;
114  } else {
115  $n = trim( $n );
116  if ( $n === '' ) {
117  continue;
118  }
119 
120  $lower = strtolower( $n );
121 
122  if ( is_numeric( $n ) ) {
123  $ns = (int)$n;
124  } elseif ( $n == '-' || $n == '_' || $n == '*' || $lower == 'main' ) {
125  $ns = NS_MAIN;
126  } else {
127  $ns = $contLang->getNsIndex( $n );
128  }
129  }
130 
131  if ( is_int( $ns ) ) {
132  $namespaces[] = $ns;
133  }
134  }
135 
136  # get elements into canonical order
137  sort( $namespaces );
138  return $namespaces;
139  }
140 
145  public static function decodeMode( $mode ) {
146  global $wgCategoryTreeDefaultOptions;
147 
148  if ( is_null( $mode ) ) {
149  return $wgCategoryTreeDefaultOptions['mode'];
150  }
151  if ( is_int( $mode ) ) {
152  return $mode;
153  }
154 
155  $mode = trim( strtolower( $mode ) );
156 
157  if ( is_numeric( $mode ) ) {
158  return (int)$mode;
159  }
160 
161  if ( $mode == 'all' ) {
162  $mode = CategoryTreeMode::ALL;
163  } elseif ( $mode == 'pages' ) {
164  $mode = CategoryTreeMode::PAGES;
165  } elseif ( $mode == 'categories' || $mode == 'sub' ) {
167  } elseif ( $mode == 'parents' || $mode == 'super' || $mode == 'inverse' ) {
169  } elseif ( $mode == 'default' ) {
170  $mode = $wgCategoryTreeDefaultOptions['mode'];
171  }
172 
173  return (int)$mode;
174  }
175 
182  public static function decodeBoolean( $value ) {
183  if ( is_null( $value ) ) {
184  return null;
185  }
186  if ( is_bool( $value ) ) {
187  return $value;
188  }
189  if ( is_int( $value ) ) {
190  return ( $value > 0 );
191  }
192 
193  $value = trim( strtolower( $value ) );
194  if ( is_numeric( $value ) ) {
195  return ( (int)$value > 0 );
196  }
197 
198  if ( $value == 'yes' || $value == 'y'
199  || $value == 'true' || $value == 't' || $value == 'on'
200  ) {
201  return true;
202  } elseif ( $value == 'no' || $value == 'n'
203  || $value == 'false' || $value == 'f' || $value == 'off'
204  ) {
205  return false;
206  } elseif ( $value == 'null' || $value == 'default' || $value == 'none' || $value == 'x' ) {
207  return null;
208  } else {
209  return false;
210  }
211  }
212 
217  public static function decodeHidePrefix( $value ) {
218  global $wgCategoryTreeDefaultOptions;
219 
220  if ( is_null( $value ) ) {
221  return $wgCategoryTreeDefaultOptions['hideprefix'];
222  }
223  if ( is_int( $value ) ) {
224  return $value;
225  }
226  if ( $value === true ) {
228  }
229  if ( $value === false ) {
231  }
232 
233  $value = trim( strtolower( $value ) );
234 
235  if ( $value == 'yes' || $value == 'y'
236  || $value == 'true' || $value == 't' || $value == 'on'
237  ) {
239  } elseif ( $value == 'no' || $value == 'n'
240  || $value == 'false' || $value == 'f' || $value == 'off'
241  ) {
243  } elseif ( $value == 'always' ) {
245  } elseif ( $value == 'never' ) {
247  } elseif ( $value == 'auto' ) {
249  } elseif ( $value == 'categories' || $value == 'category' || $value == 'smart' ) {
251  } else {
252  return $wgCategoryTreeDefaultOptions['hideprefix'];
253  }
254  }
255 
260  public static function setHeaders( OutputPage $outputPage ) {
261  # Add the modules
262  $outputPage->addModuleStyles( 'ext.categoryTree.styles' );
263  $outputPage->addModules( 'ext.categoryTree' );
264  }
265 
272  protected static function encodeOptions( array $options, $enc ) {
273  if ( $enc == 'mode' || $enc == '' ) {
274  $opt = $options['mode'];
275  } elseif ( $enc == 'json' ) {
276  $opt = FormatJson::encode( $options );
277  } else {
278  throw new Exception( 'Unknown encoding for CategoryTree options: ' . $enc );
279  }
280 
281  return $opt;
282  }
283 
288  public function getOptionsAsCacheKey( $depth = null ) {
289  $key = "";
290 
291  foreach ( $this->mOptions as $k => $v ) {
292  if ( is_array( $v ) ) {
293  $v = implode( '|', $v );
294  }
295  $key .= $k . ':' . $v . ';';
296  }
297 
298  if ( !is_null( $depth ) ) {
299  $key .= ";depth=" . $depth;
300  }
301  return $key;
302  }
303 
308  public function getOptionsAsJsStructure( $depth = null ) {
309  if ( $depth !== null ) {
310  $opt = $this->mOptions;
311  $opt['depth'] = $depth;
312  $s = self::encodeOptions( $opt, 'json' );
313  } else {
314  $s = self::encodeOptions( $this->mOptions, 'json' );
315  }
316 
317  return $s;
318  }
319 
332  public function getTag( Parser $parser = null, $category, $hideroot = false, array $attr = [],
333  $depth = 1, $allowMissing = false
334  ) {
335  global $wgCategoryTreeDisableCache;
336 
337  $category = trim( $category );
338  if ( $category === '' ) {
339  return false;
340  }
341 
342  if ( $parser ) {
343  if ( $wgCategoryTreeDisableCache === true ) {
344  $parser->getOutput()->updateCacheExpiry( 0 );
345  } elseif ( is_int( $wgCategoryTreeDisableCache ) ) {
346  $parser->getOutput()->updateCacheExpiry( $wgCategoryTreeDisableCache );
347  }
348  }
349 
350  $title = self::makeTitle( $category );
351 
352  if ( $title === false || $title === null ) {
353  return false;
354  }
355 
356  if ( isset( $attr['class'] ) ) {
357  $attr['class'] .= ' CategoryTreeTag';
358  } else {
359  $attr['class'] = ' CategoryTreeTag';
360  }
361 
362  $attr['data-ct-mode'] = $this->mOptions['mode'];
363  $attr['data-ct-options'] = $this->getOptionsAsJsStructure();
364 
365  $html = '';
366  $html .= Html::openElement( 'div', $attr );
367 
368  if ( !$allowMissing && !$title->getArticleID() ) {
369  $html .= Html::openElement( 'span', [ 'class' => 'CategoryTreeNotice' ] );
370  if ( $parser ) {
371  $html .= $parser->recursiveTagParse(
372  wfMessage( 'categorytree-not-found', $category )->plain() );
373  } else {
374  $html .= wfMessage( 'categorytree-not-found', $category )->parse();
375  }
376  $html .= Html::closeElement( 'span' );
377  } else {
378  if ( !$hideroot ) {
379  $html .= $this->renderNode( $title, $depth );
380  } else {
381  $html .= $this->renderChildren( $title, $depth );
382  }
383  }
384 
385  $html .= Xml::closeElement( 'div' );
386 
387  return $html;
388  }
389 
396  public function renderChildren( Title $title, $depth = 1 ) {
397  global $wgCategoryTreeMaxChildren, $wgCategoryTreeUseCategoryTable;
398 
399  if ( $title->getNamespace() != NS_CATEGORY ) {
400  // Non-categories can't have children. :)
401  return '';
402  }
403 
404  $dbr = wfGetDB( DB_REPLICA );
405 
406  $inverse = $this->isInverse();
407  $mode = $this->getOption( 'mode' );
408  $namespaces = $this->getOption( 'namespaces' );
409 
410  $tables = [ 'page', 'categorylinks' ];
411  $fields = [ 'page_id', 'page_namespace', 'page_title',
412  'page_is_redirect', 'page_len', 'page_latest', 'cl_to',
413  'cl_from' ];
414  $where = [];
415  $joins = [];
416  $options = [ 'ORDER BY' => 'cl_type, cl_sortkey', 'LIMIT' => $wgCategoryTreeMaxChildren ];
417 
418  if ( $inverse ) {
419  $joins['categorylinks'] = [ 'RIGHT JOIN', [
420  'cl_to = page_title', 'page_namespace' => NS_CATEGORY
421  ] ];
422  $where['cl_from'] = $title->getArticleID();
423  } else {
424  $joins['categorylinks'] = [ 'JOIN', 'cl_from = page_id' ];
425  $where['cl_to'] = $title->getDBkey();
426  $options['USE INDEX']['categorylinks'] = 'cl_sortkey';
427 
428  # namespace filter.
429  if ( $namespaces ) {
430  // NOTE: we assume that the $namespaces array contains only integers!
431  // decodeNamepsaces makes it so.
432  $where['page_namespace'] = $namespaces;
433  } elseif ( $mode != CategoryTreeMode::ALL ) {
434  if ( $mode == CategoryTreeMode::PAGES ) {
435  $where['cl_type'] = [ 'page', 'subcat' ];
436  } else {
437  $where['cl_type'] = 'subcat';
438  }
439  }
440  }
441 
442  # fetch member count if possible
443  $doCount = !$inverse && $wgCategoryTreeUseCategoryTable;
444 
445  if ( $doCount ) {
446  $tables = array_merge( $tables, [ 'category' ] );
447  $fields = array_merge( $fields, [
448  'cat_id', 'cat_title', 'cat_subcats', 'cat_pages', 'cat_files'
449  ] );
450  $joins['category'] = [ 'LEFT JOIN', [
451  'cat_title = page_title', 'page_namespace' => NS_CATEGORY ]
452  ];
453  }
454 
455  $res = $dbr->select( $tables, $fields, $where, __METHOD__, $options, $joins );
456 
457  # collect categories separately from other pages
458  $categories = '';
459  $other = '';
460 
461  foreach ( $res as $row ) {
462  # NOTE: in inverse mode, the page record may be null, because we use a right join.
463  # happens for categories with no category page (red cat links)
464  if ( $inverse && $row->page_title === null ) {
465  $t = Title::makeTitle( NS_CATEGORY, $row->cl_to );
466  } else {
467  # TODO: translation support; ideally added to Title object
468  $t = Title::newFromRow( $row );
469  }
470 
471  $cat = null;
472 
473  if ( $doCount && $row->page_namespace == NS_CATEGORY ) {
474  $cat = Category::newFromRow( $row, $t );
475  }
476 
477  $s = $this->renderNodeInfo( $t, $cat, $depth - 1 );
478 
479  if ( $row->page_namespace == NS_CATEGORY ) {
480  $categories .= $s;
481  } else {
482  $other .= $s;
483  }
484  }
485 
486  return $categories . $other;
487  }
488 
494  public function renderParents( Title $title ) {
495  global $wgCategoryTreeMaxChildren;
496 
497  $dbr = wfGetDB( DB_REPLICA );
498 
499  $res = $dbr->select(
500  'categorylinks',
501  [ 'cl_to' ],
502  [ 'cl_from' => $title->getArticleID() ],
503  __METHOD__,
504  [
505  'LIMIT' => $wgCategoryTreeMaxChildren,
506  'ORDER BY' => 'cl_to'
507  ]
508  );
509 
510  $special = SpecialPage::getTitleFor( 'CategoryTree' );
511 
512  $s = '';
513 
514  foreach ( $res as $row ) {
515  $t = Title::makeTitle( NS_CATEGORY, $row->cl_to );
516 
517  if ( $s !== '' ) {
518  $s .= wfMessage( 'pipe-separator' )->escaped();
519  }
520 
521  $s .= Xml::openElement( 'span', [ 'class' => 'CategoryTreeItem' ] );
522  $s .= $this->linkRenderer->makeLink(
523  $special,
524  $t->getText(),
525  [ 'class' => 'CategoryTreeLabel' ],
526  [ 'target' => $t->getPartialURL() ] + $this->mOptions
527  );
528  $s .= Xml::closeElement( 'span' );
529  }
530 
531  return $s;
532  }
533 
540  public function renderNode( Title $title, $children = 0 ) {
541  global $wgCategoryTreeUseCategoryTable;
542 
543  if ( $wgCategoryTreeUseCategoryTable && $title->getNamespace() == NS_CATEGORY
544  && !$this->isInverse()
545  ) {
546  $cat = Category::newFromTitle( $title );
547  } else {
548  $cat = null;
549  }
550 
551  return $this->renderNodeInfo( $title, $cat, $children );
552  }
553 
562  public function renderNodeInfo( Title $title, Category $cat = null, $children = 0 ) {
563  $mode = $this->getOption( 'mode' );
564 
565  $ns = $title->getNamespace();
566  $key = $title->getDBkey();
567 
568  $hideprefix = $this->getOption( 'hideprefix' );
569 
570  if ( $hideprefix == CategoryTreeHidePrefix::ALWAYS ) {
571  $hideprefix = true;
572  } elseif ( $hideprefix == CategoryTreeHidePrefix::AUTO ) {
573  $hideprefix = ( $mode == CategoryTreeMode::CATEGORIES );
574  } elseif ( $hideprefix == CategoryTreeHidePrefix::CATEGORIES ) {
575  $hideprefix = ( $ns == NS_CATEGORY );
576  } else {
577  $hideprefix = true;
578  }
579 
580  // when showing only categories, omit namespace in label unless we explicitely defined the
581  // configuration setting
582  // patch contributed by Manuel Schneider <manuel.schneider@wikimedia.ch>, Bug 8011
583  if ( $hideprefix ) {
584  $label = $title->getText();
585  } else {
586  $label = $title->getPrefixedText();
587  }
588 
589  $link = $this->linkRenderer->makeLink( $title, $label );
590 
591  $count = false;
592  $s = '';
593 
594  # NOTE: things in CategoryTree.js rely on the exact order of tags!
595  # Specifically, the CategoryTreeChildren div must be the first
596  # sibling with nodeName = DIV of the grandparent of the expland link.
597 
598  $s .= Xml::openElement( 'div', [ 'class' => 'CategoryTreeSection' ] );
599  $s .= Xml::openElement( 'div', [ 'class' => 'CategoryTreeItem' ] );
600 
601  $attr = [ 'class' => 'CategoryTreeBullet' ];
602 
603  if ( $ns == NS_CATEGORY ) {
604  if ( $cat ) {
605  if ( $mode == CategoryTreeMode::CATEGORIES ) {
606  $count = intval( $cat->getSubcatCount() );
607  } elseif ( $mode == CategoryTreeMode::PAGES ) {
608  $count = intval( $cat->getPageCount() ) - intval( $cat->getFileCount() );
609  } else {
610  $count = intval( $cat->getPageCount() );
611  }
612  }
613  if ( $count === 0 ) {
614  $bullet = wfMessage( 'categorytree-empty-bullet' )->escaped() . ' ';
615  $attr['class'] = 'CategoryTreeEmptyBullet';
616  } else {
617  $linkattr = [];
618 
619  $linkattr[ 'class' ] = "CategoryTreeToggle";
620  $linkattr['data-ct-title'] = $key;
621 
622  if ( $children == 0 ) {
623  // Use ->plain() to ensure identical result as JS,
624  // which does:
625  // $link.text( mw.msg( 'categorytree-expand-bullet' ) );
626  $txt = wfMessage( 'categorytree-expand-bullet' )->plain();
627  $linkattr[ 'data-ct-state' ] = 'collapsed';
628  } else {
629  $txt = wfMessage( 'categorytree-collapse-bullet' )->plain();
630  $linkattr[ 'data-ct-loaded' ] = true;
631  $linkattr[ 'data-ct-state' ] = 'expanded';
632  }
633 
634  $bullet = Html::element( 'span', $linkattr, $txt ) . ' ';
635  }
636  } else {
637  $bullet = wfMessage( 'categorytree-page-bullet' )->escaped();
638  }
639  $s .= Xml::tags( 'span', $attr, $bullet ) . ' ';
640 
641  $s .= $link;
642 
643  if ( $count !== false && $this->getOption( 'showcount' ) ) {
644  $s .= self::createCountString( RequestContext::getMain(), $cat, $count );
645  }
646 
647  $s .= Xml::closeElement( 'div' );
648  $s .= Xml::openElement(
649  'div',
650  [
651  'class' => 'CategoryTreeChildren',
652  'style' => $children > 0 ? "display:block" : "display:none"
653  ]
654  );
655 
656  if ( $ns == NS_CATEGORY && $children > 0 ) {
657  $children = $this->renderChildren( $title, $children );
658  if ( $children == '' ) {
659  $s .= Xml::openElement( 'i', [ 'class' => 'CategoryTreeNotice' ] );
660  if ( $mode == CategoryTreeMode::CATEGORIES ) {
661  $s .= wfMessage( 'categorytree-no-subcategories' )->escaped();
662  } elseif ( $mode == CategoryTreeMode::PAGES ) {
663  $s .= wfMessage( 'categorytree-no-pages' )->escaped();
664  } elseif ( $mode == CategoryTreeMode::PARENTS ) {
665  $s .= wfMessage( 'categorytree-no-parent-categories' )->escaped();
666  } else {
667  $s .= wfMessage( 'categorytree-nothing-found' )->escaped();
668  }
669  $s .= Xml::closeElement( 'i' );
670  } else {
671  $s .= $children;
672  }
673  }
674 
675  $s .= Xml::closeElement( 'div' );
676  $s .= Xml::closeElement( 'div' );
677 
678  return $s;
679  }
680 
689  public static function createCountString( IContextSource $context, Category $cat = null,
690  $countMode
691  ) {
692  # Get counts, with conversion to integer so === works
693  # Note: $allCount is the total number of cat members,
694  # not the count of how many members are normal pages.
695  $allCount = $cat ? intval( $cat->getPageCount() ) : 0;
696  $subcatCount = $cat ? intval( $cat->getSubcatCount() ) : 0;
697  $fileCount = $cat ? intval( $cat->getFileCount() ) : 0;
698  $pages = $allCount - $subcatCount - $fileCount;
699 
700  $attr = [
701  'title' => $context->msg( 'categorytree-member-counts' )
702  ->numParams( $subcatCount, $pages, $fileCount, $allCount, $countMode )->text(),
703  # numbers and commas get messed up in a mixed dir env
704  'dir' => $context->getLanguage()->getDir()
705  ];
706  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
707  $s = $contLang->getDirMark() . ' ';
708 
709  # Create a list of category members with only non-zero member counts
710  $memberNums = [];
711  if ( $subcatCount ) {
712  $memberNums[] = $context->msg( 'categorytree-num-categories' )
713  ->numParams( $subcatCount )->text();
714  }
715  if ( $pages ) {
716  $memberNums[] = $context->msg( 'categorytree-num-pages' )->numParams( $pages )->text();
717  }
718  if ( $fileCount ) {
719  $memberNums[] = $context->msg( 'categorytree-num-files' )
720  ->numParams( $fileCount )->text();
721  }
722  $memberNumsShort = $memberNums
723  ? $context->getLanguage()->commaList( $memberNums )
724  : $context->msg( 'categorytree-num-empty' )->text();
725 
726  # Only $5 is actually used in the default message.
727  # Other arguments can be used in a customized message.
728  $s .= Xml::tags(
729  'span',
730  $attr,
731  $context->msg( 'categorytree-member-num' )
732  // Do not use numParams on params 1-4, as they are only used for customisation.
733  ->params( $subcatCount, $pages, $fileCount, $allCount, $memberNumsShort )
734  ->escaped()
735  );
736 
737  return $s;
738  }
739 
745  public static function makeTitle( $title ) {
746  $title = trim( $title );
747 
748  if ( strval( $title ) === '' ) {
749  return null;
750  }
751 
752  # The title must be in the category namespace
753  # Ignore a leading Category: if there is one
755  if ( !$t || $t->getNamespace() != NS_CATEGORY || $t->getInterwiki() != '' ) {
756  // If we were given something like "Wikipedia:Foo" or "Template:",
757  // try it again but forced.
758  $title = "Category:$title";
760  }
761  return $t;
762  }
763 
771  public static function capDepth( $mode, $depth ) {
772  global $wgCategoryTreeMaxDepth;
773 
774  if ( is_numeric( $depth ) ) {
775  $depth = intval( $depth );
776  } else {
777  return 1;
778  }
779 
780  if ( is_array( $wgCategoryTreeMaxDepth ) ) {
781  $max = isset( $wgCategoryTreeMaxDepth[$mode] ) ? $wgCategoryTreeMaxDepth[$mode] : 1;
782  } elseif ( is_numeric( $wgCategoryTreeMaxDepth ) ) {
783  $max = $wgCategoryTreeMaxDepth;
784  } else {
785  wfDebug( 'CategoryTree::capDepth: $wgCategoryTreeMaxDepth is invalid.' );
786  $max = 1;
787  }
788 
789  return min( $depth, $max );
790  }
791 }
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:316
CategoryTree\getOption
getOption( $name)
Definition: CategoryTree.php:85
CategoryTree\isInverse
isInverse()
Definition: CategoryTree.php:92
CategoryTree\capDepth
static capDepth( $mode, $depth)
Internal function to cap depth PhanPluginDuplicateConditionalNullCoalescing until PHP7 is required.
Definition: CategoryTree.php:771
CategoryTree\renderParents
renderParents(Title $title)
Returns a string with an HTML representation of the parents of the given category.
Definition: CategoryTree.php:494
CategoryTree\decodeMode
static decodeMode( $mode)
Definition: CategoryTree.php:145
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:41
Category
Category objects are immutable, strictly speaking.
Definition: Category.php:29
NS_FILE
const NS_FILE
Definition: Defines.php:66
CategoryTree
Core functions for the CategoryTree extension, an AJAX based gadget to display the category structure...
Definition: CategoryTree.php:31
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1264
$s
$s
Definition: mergeMessageFileList.php:185
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:83
CategoryTree\decodeHidePrefix
static decodeHidePrefix( $value)
Definition: CategoryTree.php:217
$res
$res
Definition: testCompression.php:52
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:108
CategoryTree\renderNodeInfo
renderNodeInfo(Title $title, Category $cat=null, $children=0)
Returns a string with a HTML represenation of the given page.
Definition: CategoryTree.php:562
CategoryTreeHidePrefix\NEVER
const NEVER
Definition: CategoryTreeHidePrefix.php:31
CategoryTree\createCountString
static createCountString(IContextSource $context, Category $cat=null, $countMode)
Create a string which format the page, subcat and file counts of a category PhanParamReqAfterOpt $cat...
Definition: CategoryTree.php:689
CategoryTreeMode\PAGES
const PAGES
Definition: CategoryTreeMode.php:32
$dbr
$dbr
Definition: testCompression.php:50
NS_MAIN
const NS_MAIN
Definition: Defines.php:60
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:115
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:518
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2575
CategoryTreeHidePrefix\ALWAYS
const ALWAYS
Definition: CategoryTreeHidePrefix.php:33
$t
$t
Definition: make-normalization-table.php:143
$title
$title
Definition: testCompression.php:34
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:586
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:74
CategoryTree\getTag
getTag(Parser $parser=null, $category, $hideroot=false, array $attr=[], $depth=1, $allowMissing=false)
Custom tag implementation.
Definition: CategoryTree.php:332
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:913
Category\newFromRow
static newFromRow( $row, $title=null)
Factory function, for constructing a Category object from a result set.
Definition: Category.php:179
Category\newFromTitle
static newFromTitle( $title)
Factory function.
Definition: Category.php:146
Xml\tags
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:130
CategoryTree\renderChildren
renderChildren(Title $title, $depth=1)
Returns a string with an HTML representation of the children of the given category.
Definition: CategoryTree.php:396
CategoryTreeMode\PARENTS
const PARENTS
Definition: CategoryTreeMode.php:36
CategoryTree\$mOptions
$mOptions
Definition: CategoryTree.php:32
CategoryTreeMode\ALL
const ALL
Definition: CategoryTreeMode.php:34
CategoryTree\decodeBoolean
static decodeBoolean( $value)
Helper function to convert a string to a boolean value.
Definition: CategoryTree.php:182
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:431
CategoryTree\__construct
__construct(array $options)
PhanTypeInvalidDimOffset.
Definition: CategoryTree.php:43
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:53
$context
$context
Definition: load.php:45
CategoryTree\encodeOptions
static encodeOptions(array $options, $enc)
Definition: CategoryTree.php:272
Title
Represents a title within MediaWiki.
Definition: Title.php:42
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:117
CategoryTree\getOptionsAsCacheKey
getOptionsAsCacheKey( $depth=null)
Definition: CategoryTree.php:288
CategoryTree\$linkRenderer
LinkRenderer $linkRenderer
Definition: CategoryTree.php:37
CategoryTreeHidePrefix\AUTO
const AUTO
Definition: CategoryTreeHidePrefix.php:37
CategoryTree\renderNode
renderNode(Title $title, $children=0)
Returns a string with a HTML represenation of the given page.
Definition: CategoryTree.php:540
CategoryTree\makeTitle
static makeTitle( $title)
Creates a Title object from a user provided (and thus unsafe) string.
Definition: CategoryTree.php:745
CategoryTree\getOptionsAsJsStructure
getOptionsAsJsStructure( $depth=null)
Definition: CategoryTree.php:308
CategoryTreeMode\CATEGORIES
const CATEGORIES
Definition: CategoryTreeMode.php:30
CategoryTreeHidePrefix\CATEGORIES
const CATEGORIES
Definition: CategoryTreeHidePrefix.php:35
CategoryTree\decodeNamespaces
static decodeNamespaces( $nn)
Definition: CategoryTree.php:100
CategoryTree\setHeaders
static setHeaders(OutputPage $outputPage)
Add ResourceLoader modules to the OutputPage object.
Definition: CategoryTree.php:260