47 private const VERSION = 1;
50 private $contentLanguage;
56 private $languageNameUtils;
59 private $linkBatchFactory;
62 private $linkRenderer;
65 private $loadBalancer;
68 private $magicWordFactory;
71 private $namespaceInfo;
80 private $revisionLookup;
83 private $wanObjectCache;
86 private $watchedItemStore;
89 private $redirectLookup;
92 private $restrictionStore;
95 private $linksMigration;
138 $this->contentLanguage = $contentLanguage;
139 $this->hookRunner =
new HookRunner( $hookContainer );
140 $this->languageNameUtils = $languageNameUtils;
141 $this->linkBatchFactory = $linkBatchFactory;
142 $this->linkRenderer = $linkRenderer;
143 $this->loadBalancer = $loadBalancer;
144 $this->magicWordFactory = $magicWordFactory;
145 $this->namespaceInfo = $namespaceInfo;
146 $this->pageProps = $pageProps;
147 $this->repoGroup = $repoGroup;
148 $this->revisionLookup = $revisionLookup;
149 $this->wanObjectCache = $wanObjectCache;
150 $this->watchedItemStore = $watchedItemStore;
151 $this->redirectLookup = $redirectLookup;
152 $this->restrictionStore = $restrictionStore;
153 $this->linksMigration = $linksMigration;
191 $services = MediaWikiServices::getInstance();
193 $revision = $services->getRevisionLookup()
194 ->getRevisionByTitle(
$page, 0, IDBAccessObject::READ_LATEST );
195 $revid = $revision ? $revision->getId() :
null;
197 if ( $revid !==
null ) {
198 $cache = $services->getMainWANObjectCache();
211 'mediawiki.interface.helpers.styles',
212 'mediawiki.action.styles',
221 $revRecord = $this->
getArticle()->fetchRevisionRecord();
224 if ( $revRecord ===
null ) {
225 return $this->
msg(
'missing-revision', $oldid )->parse();
229 if ( !$revRecord->isCurrent() ) {
230 return $this->
msg(
'pageinfo-not-current' )->plain();
237 if ( !$this->
msg(
'pageinfo-header' )->isDisabled() ) {
238 $content .= $this->
msg(
'pageinfo-header' )->parse();
245 $this->hookRunner->onInfoAction( $this->
getContext(), $pageInfo );
248 foreach ( $pageInfo as
$header => $infoTable ) {
253 $this->
msg(
"pageinfo-$header" )->text(),
254 "mw-pageinfo-$header"
258 foreach ( $infoTable as $infoRow ) {
259 if ( $infoRow[0] ==
"below" ) {
260 $below = $infoRow[1] .
"\n";
263 $name = ( $infoRow[0] instanceof
Message ) ? $infoRow[0]->escaped() : $infoRow[0];
265 $value = ( $infoRow[1] instanceof
Message ) ? $infoRow[1]->escaped() : $infoRow[1];
267 $id = ( $infoRow[0] instanceof
Message ) ? $infoRow[0]->getKey() :
null;
268 $table = $this->
addRow( $table, $name, $value, $id ) .
"\n";
270 if ( $table ===
"\n" ) {
279 if ( !$this->
msg(
'pageinfo-footer' )->isDisabled() ) {
280 $content .= $this->
msg(
'pageinfo-footer' )->parse();
300 'class' =>
'mw-headline',
317 protected function addRow( $table, $name, $value, $id ) {
321 $id ===
null ? [] : [
'id' =>
'mw-' . $id ],
338 [
'class' =>
'wikitable mw-page-info' ],
359 $id =
$title->getArticleID();
360 $config = $this->context->getConfig();
361 $linkRenderer = $this->linkRenderer;
363 $pageCounts = $this->pageCounts();
365 $props = $this->pageProps->getAllProperties(
$title );
366 $pageProperties = $props[$id] ?? [];
370 $pageInfo[
'header-basic'] = [];
373 $displayTitle = $pageProperties[
'displaytitle'] ??
374 htmlspecialchars(
$title->getPrefixedText(), ENT_NOQUOTES );
376 $pageInfo[
'header-basic'][] = [
377 $this->
msg(
'pageinfo-display-title' ),
382 $redirectTarget = $this->redirectLookup->getRedirectTarget( $this->
getWikiPage() );
383 if ( $redirectTarget !==
null ) {
384 $pageInfo[
'header-basic'][] = [
385 $this->
msg(
'pageinfo-redirectsto' ),
386 $linkRenderer->
makeLink( $redirectTarget ) .
387 $this->
msg(
'word-separator' )->escaped() .
388 $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
390 $this->msg(
'pageinfo-redirectsto-info' )->text(),
392 [
'action' =>
'info' ]
398 $sortKey = $pageProperties[
'defaultsort'] ??
$title->getCategorySortkey();
400 $sortKey = htmlspecialchars( $sortKey );
401 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-default-sort' ), $sortKey ];
404 $pageInfo[
'header-basic'][] = [
405 $this->
msg(
'pageinfo-length' ),
410 $pageNamespace =
$title->getNsText();
411 if ( $pageNamespace ) {
412 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-namespace' ), $pageNamespace ];
416 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-article-id' ), $id ];
419 $pageLang =
$title->getPageLanguage()->getCode();
421 $pageLangHtml = $pageLang .
' - ' .
422 $this->languageNameUtils->getLanguageName( $pageLang,
$lang->getCode() );
424 if ( $config->get( MainConfigNames::PageLanguageUseDB )
425 && $this->getAuthority()->probablyCan(
'pagelang',
$title )
427 $pageLangHtml .=
' ' . $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
429 $this->msg(
'pageinfo-language-change' )->text()
433 $pageInfo[
'header-basic'][] = [
434 $this->
msg(
'pageinfo-language' )->escaped(),
442 $modelHtml .=
' ' . $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
444 $this->msg(
'pageinfo-content-model-change' )->text()
448 $pageInfo[
'header-basic'][] = [
449 $this->
msg(
'pageinfo-content-model' ),
455 if ( $pageUser && $pageUser->getId() && !$pageUser->isHidden() ) {
456 $pageInfo[
'header-basic'][] = [
457 $this->
msg(
'pageinfo-user-id' ),
465 if ( isset( $pageProperties[
'noindex'] ) ) {
466 $parserOutput->setIndexPolicy(
'noindex' );
468 if ( isset( $pageProperties[
'index'] ) ) {
469 $parserOutput->setIndexPolicy(
'index' );
473 $policy = $this->
getArticle()->getRobotPolicy(
'view', $parserOutput );
474 $pageInfo[
'header-basic'][] = [
476 $this->
msg(
'pageinfo-robot-policy' ),
477 $this->
msg(
"pageinfo-robot-{$policy['index']}" )
480 $unwatchedPageThreshold = $config->get( MainConfigNames::UnwatchedPageThreshold );
481 if ( $this->
getAuthority()->isAllowed(
'unwatchedpages' ) ||
482 ( $unwatchedPageThreshold !==
false &&
483 $pageCounts[
'watchers'] >= $unwatchedPageThreshold )
486 $pageInfo[
'header-basic'][] = [
487 $this->
msg(
'pageinfo-watchers' ),
488 $lang->formatNum( $pageCounts[
'watchers'] )
491 $config->get( MainConfigNames::ShowUpdatedMarker ) &&
492 isset( $pageCounts[
'visitingWatchers'] )
494 $minToDisclose = $config->get( MainConfigNames::UnwatchedPageSecret );
495 if ( $pageCounts[
'visitingWatchers'] > $minToDisclose ||
496 $this->
getAuthority()->isAllowed(
'unwatchedpages' ) ) {
497 $pageInfo[
'header-basic'][] = [
498 $this->
msg(
'pageinfo-visiting-watchers' ),
499 $lang->formatNum( $pageCounts[
'visitingWatchers'] )
502 $pageInfo[
'header-basic'][] = [
503 $this->
msg(
'pageinfo-visiting-watchers' ),
504 $this->
msg(
'pageinfo-few-visiting-watchers' )
508 } elseif ( $unwatchedPageThreshold !==
false ) {
509 $pageInfo[
'header-basic'][] = [
510 $this->
msg(
'pageinfo-watchers' ),
511 $this->
msg(
'pageinfo-few-watchers' )->numParams( $unwatchedPageThreshold )
517 $pageInfo[
'header-basic'][] = [
520 $this->
msg(
'pageinfo-redirects-name' )->text(),
528 $this->
msg(
'pageinfo-redirects-value' )
529 ->numParams( count(
$title->getRedirectsHere() ) )
534 $pageInfo[
'header-basic'][] = [
535 $this->
msg(
'pageinfo-contentpage' ),
536 $this->
msg(
'pageinfo-contentpage-yes' )
541 if ( $this->namespaceInfo->hasSubpages(
$title->getNamespace() ) ) {
544 $title->getPrefixedText() .
'/'
546 $pageInfo[
'header-basic'][] = [
549 $this->
msg(
'pageinfo-subpages-name' )->text()
551 $this->
msg(
'pageinfo-subpages-value' )
553 $pageCounts[
'subpages'][
'total'],
554 $pageCounts[
'subpages'][
'redirects'],
555 $pageCounts[
'subpages'][
'nonredirects']
563 $allCount = $category->getMemberCount();
564 $subcatCount = $category->getSubcatCount();
565 $fileCount = $category->getFileCount();
568 $pageInfo[
'category-info'] = [
570 $this->
msg(
'pageinfo-category-total' ),
571 $lang->formatNum( $allCount )
574 $this->
msg(
'pageinfo-category-pages' ),
575 $lang->formatNum( $pageCount )
578 $this->
msg(
'pageinfo-category-subcats' ),
579 $lang->formatNum( $subcatCount )
582 $this->
msg(
'pageinfo-category-files' ),
583 $lang->formatNum( $fileCount )
590 $fileObj = $this->repoGroup->findFile(
$title );
591 if ( $fileObj !==
false ) {
593 $output = Wikimedia\base_convert( $fileObj->getSha1(), 36, 16, 40 );
594 $pageInfo[
'header-basic'][] = [
595 $this->
msg(
'pageinfo-file-hash' ),
602 $pageInfo[
'header-restrictions'] = [];
605 if ( $this->restrictionStore->isCascadeProtected(
$title ) ) {
607 $sources = $this->restrictionStore->getCascadeProtectionSources(
$title )[0];
609 foreach ( $sources as $sourcePageIdentity ) {
618 $pageInfo[
'header-restrictions'][] = [
619 $this->
msg(
'pageinfo-protect-cascading-from' ),
625 if ( $this->restrictionStore->areRestrictionsCascading(
$title ) ) {
626 $pageInfo[
'header-restrictions'][] = [
627 $this->
msg(
'pageinfo-protect-cascading' ),
628 $this->
msg(
'pageinfo-protect-cascading-yes' )
633 foreach ( $this->restrictionStore->listApplicableRestrictionTypes(
$title ) as $restrictionType ) {
634 $protections = $this->restrictionStore->getRestrictions(
$title, $restrictionType );
636 switch ( count( $protections ) ) {
639 if ( $message ===
null ) {
641 $message = $this->
msg(
'protect-default' )->escaped();
647 $message = $this->
msg(
'protect-level-' . $protections[0] );
648 if ( !$message->isDisabled() ) {
649 $message = $message->escaped();
656 $message = $this->
msg(
"protect-fallback",
$lang->commaList( $protections ) )->parse();
659 $expiry = $this->restrictionStore->getRestrictionExpiry(
$title, $restrictionType );
660 $formattedexpiry = $expiry ===
null ?
'' : $this->
msg(
662 $lang->formatExpiry( $expiry,
true,
'infinity', $user )
664 $message .= $this->
msg(
'word-separator' )->escaped() . $formattedexpiry;
668 $pageInfo[
'header-restrictions'][] = [
669 $this->
msg(
"restriction-$restrictionType" ), $message
673 $pageInfo[
'header-restrictions'][] = [
677 $this->
msg(
'pageinfo-view-protect-log' )->text(),
679 [
'type' =>
'protect',
'page' =>
$title->getPrefixedText() ]
688 $pageInfo[
'header-edits'] = [];
690 $firstRev = $this->revisionLookup->getFirstRevision( $this->
getTitle() );
691 $lastRev = $this->
getWikiPage()->getRevisionRecord();
692 $batch = $this->linkBatchFactory->newLinkBatch();
694 $firstRevUser = $firstRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
695 if ( $firstRevUser ) {
696 $batch->add(
NS_USER, $firstRevUser->getName() );
702 $lastRevUser = $lastRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
703 if ( $lastRevUser ) {
704 $batch->add(
NS_USER, $lastRevUser->getName() );
713 $pageInfo[
'header-edits'][] = [
714 $this->
msg(
'pageinfo-firstuser' ),
719 $pageInfo[
'header-edits'][] = [
720 $this->
msg(
'pageinfo-firsttime' ),
723 $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
725 [
'oldid' => $firstRev->getId() ]
732 $pageInfo[
'header-edits'][] = [
733 $this->
msg(
'pageinfo-lastuser' ),
738 $pageInfo[
'header-edits'][] = [
739 $this->
msg(
'pageinfo-lasttime' ),
742 $lang->userTimeAndDate( $this->getWikiPage()->getTimestamp(), $user ),
744 [
'oldid' => $this->getWikiPage()->getLatest() ]
750 $pageInfo[
'header-edits'][] = [
751 $this->
msg(
'pageinfo-edits' ),
752 $lang->formatNum( $pageCounts[
'edits'] )
756 if ( $pageCounts[
'authors'] > 0 ) {
757 $pageInfo[
'header-edits'][] = [
758 $this->
msg(
'pageinfo-authors' ),
759 $lang->formatNum( $pageCounts[
'authors'] )
764 $pageInfo[
'header-edits'][] = [
766 'pageinfo-recent-edits',
767 $lang->formatDuration( $config->get( MainConfigNames::RCMaxAge ) )
769 $lang->formatNum( $pageCounts[
'recent_edits'] )
773 $pageInfo[
'header-edits'][] = [
774 $this->
msg(
'pageinfo-recent-authors' ),
775 $lang->formatNum( $pageCounts[
'recent_authors'] )
779 $magicWords = $this->magicWordFactory->getDoubleUnderscoreArray();
785 $localizedWords = $this->contentLanguage->getMagicWords();
788 foreach ( $pageProperties as $property => $value ) {
789 if ( in_array( $property, $wordIDs ) ) {
790 $listItems[] =
Html::element(
'li', [], $localizedWords[$property][1] );
795 $hiddenCategories = $this->
getWikiPage()->getHiddenCategories();
798 count( $listItems ) > 0 ||
799 count( $hiddenCategories ) > 0 ||
800 $pageCounts[
'transclusion'][
'from'] > 0 ||
801 $pageCounts[
'transclusion'][
'to'] > 0
803 $options = [
'LIMIT' => $config->get( MainConfigNames::PageInfoTransclusionLimit ) ];
804 $transcludedTemplates =
$title->getTemplateLinksFrom( $options );
805 if ( $config->get( MainConfigNames::MiserMode ) ) {
806 $transcludedTargets = [];
808 $transcludedTargets =
$title->getTemplateLinksTo( $options );
812 $pageInfo[
'header-properties'] = [];
815 if ( count( $listItems ) > 0 ) {
816 $pageInfo[
'header-properties'][] = [
817 $this->
msg(
'pageinfo-magic-words' )->numParams( count( $listItems ) ),
823 if ( count( $hiddenCategories ) > 0 ) {
824 $pageInfo[
'header-properties'][] = [
825 $this->
msg(
'pageinfo-hidden-categories' )
826 ->numParams( count( $hiddenCategories ) ),
832 if ( $pageCounts[
'transclusion'][
'from'] > 0 ) {
833 if ( $pageCounts[
'transclusion'][
'from'] > count( $transcludedTemplates ) ) {
834 $more = $this->
msg(
'morenotlisted' )->escaped();
842 $this->linkBatchFactory,
843 $this->restrictionStore
846 $pageInfo[
'header-properties'][] = [
847 $this->
msg(
'pageinfo-templates' )
848 ->numParams( $pageCounts[
'transclusion'][
'from'] ),
849 $templateListFormatter->format( $transcludedTemplates,
false, $more )
853 if ( !$config->get( MainConfigNames::MiserMode ) && $pageCounts[
'transclusion'][
'to'] > 0 ) {
854 if ( $pageCounts[
'transclusion'][
'to'] > count( $transcludedTargets ) ) {
857 $this->
msg(
'moredotdotdot' )->text(),
859 [
'hidelinks' => 1,
'hideredirs' => 1 ]
868 $this->linkBatchFactory,
869 $this->restrictionStore
872 $pageInfo[
'header-properties'][] = [
873 $this->
msg(
'pageinfo-transclusions' )
874 ->numParams( $pageCounts[
'transclusion'][
'to'] ),
875 $templateListFormatter->format( $transcludedTargets,
false, $more )
892 if (
$title->isRawHtmlMessage() ) {
893 $rights[] =
'editsitecss';
894 $rights[] =
'editsitejs';
895 } elseif (
$title->isSiteCssConfigPage() ) {
896 $rights[] =
'editsitecss';
897 } elseif (
$title->isSiteJsConfigPage() ) {
898 $rights[] =
'editsitejs';
899 } elseif (
$title->isSiteJsonConfigPage() ) {
900 $rights[] =
'editsitejson';
901 } elseif (
$title->isUserCssConfigPage() ) {
902 $rights[] =
'editusercss';
903 } elseif (
$title->isUserJsConfigPage() ) {
904 $rights[] =
'edituserjs';
905 } elseif (
$title->isUserJsonConfigPage() ) {
906 $rights[] =
'edituserjson';
908 $namespaceProtection = $this->context->getConfig()->get( MainConfigNames::NamespaceProtection );
909 $right = $namespaceProtection[
$title->getNamespace()] ??
null;
912 $rights = (array)$right;
916 return $this->
msg(
'protect-fallback', $this->
getLanguage()->commaList( $rights ) )->parse();
927 private function pageCounts() {
928 $page = $this->getWikiPage();
930 $config = $this->context->getConfig();
931 $cache = $this->wanObjectCache;
933 return $cache->getWithSetCallback(
934 self::getCacheKey(
$cache, $page->getTitle(), $page->getLatest() ),
935 WANObjectCache::TTL_WEEK,
936 function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname ) {
937 $title = $page->getTitle();
938 $id =
$title->getArticleID();
941 $dbrWatchlist = $this->loadBalancer->getConnectionRef(
945 $setOpts += Database::getCacheSetOptions(
$dbr, $dbrWatchlist );
947 $tables = [
'revision' ];
948 $field =
'rev_actor';
949 $pageField =
'rev_page';
950 $tsField =
'rev_timestamp';
953 $watchedItemStore = $this->watchedItemStore;
958 if ( $config->get( MainConfigNames::ShowUpdatedMarker ) ) {
959 $updated = (int)
wfTimestamp( TS_UNIX, $page->getTimestamp() );
962 $updated - $config->get( MainConfigNames::WatchersMaxAge )
967 $edits = (int)
$dbr->selectField(
970 [
'rev_page' => $id ],
973 $result[
'edits'] = $edits;
976 if ( $config->get( MainConfigNames::MiserMode ) ) {
977 $result[
'authors'] = 0;
979 $result[
'authors'] = (int)
$dbr->selectField(
981 "COUNT(DISTINCT $field)",
982 [ $pageField => $id ],
990 $threshold =
$dbr->timestamp( time() - $config->get( MainConfigNames::RCMaxAge ) );
993 $edits = (int)
$dbr->selectField(
998 "rev_timestamp >= " .
$dbr->addQuotes( $threshold )
1002 $result[
'recent_edits'] = $edits;
1005 $result[
'recent_authors'] = (int)
$dbr->selectField(
1007 "COUNT(DISTINCT $field)",
1010 "$tsField >= " .
$dbr->addQuotes( $threshold )
1018 if ( $this->namespaceInfo->hasSubpages(
$title->getNamespace() ) ) {
1019 $conds = [
'page_namespace' =>
$title->getNamespace() ];
1020 $conds[] =
'page_title ' .
1024 $conds[
'page_is_redirect'] = 1;
1025 $result[
'subpages'][
'redirects'] = (int)
$dbr->selectField(
1033 $conds[
'page_is_redirect'] = 0;
1034 $result[
'subpages'][
'nonredirects'] = (int)
$dbr->selectField(
1042 $result[
'subpages'][
'total'] = $result[
'subpages'][
'redirects']
1043 + $result[
'subpages'][
'nonredirects'];
1047 if ( $config->get( MainConfigNames::MiserMode ) ) {
1048 $result[
'transclusion'][
'to'] = 0;
1050 $result[
'transclusion'][
'to'] = (int)
$dbr->selectField(
1053 $this->linksMigration->getLinksConditions(
'templatelinks',
$title ),
1058 $result[
'transclusion'][
'from'] = (int)
$dbr->selectField(
1061 [
'tl_from' =>
$title->getArticleID() ],
1076 return $this->msg(
'pageinfo-title', $this->
getTitle()->getPrefixedText() )->text();
1095 return $cache->makeKey(
'infoaction', md5( (
string)$page ), $revId, self::VERSION );
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$magicWords
@phpcs-require-sorted-array
getWikiPage()
Get a WikiPage object.
IContextSource null $context
IContextSource if specified; otherwise we'll use the Context from the Page.
WikiPage Article ImagePage CategoryPage Page $page
Page on which we're performing the action.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
getTitle()
Shortcut to get the Title object from the page.
getContext()
Get the IContextSource in use here.
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User being used for this instance.
static exists(string $name)
Check if a given action is recognised, even if it's disabled.
getArticle()
Get a Article object.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
getLanguage()
Shortcut to get the user Language being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
static newFromTitle(PageIdentity $page)
Factory function.
const COUNT_CONTENT_PAGES
static getLocalizedName( $name, Language $lang=null)
Returns the localized name for a given content model.
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Displays information about a page.
requiresWrite()
Whether this action requires the wiki not to be locked.
makeHeader( $header, $canonicalId)
Creates a header that can be added to the output.
__construct(Page $page, IContextSource $context, Language $contentLanguage, HookContainer $hookContainer, LanguageNameUtils $languageNameUtils, LinkBatchFactory $linkBatchFactory, LinkRenderer $linkRenderer, ILoadBalancer $loadBalancer, MagicWordFactory $magicWordFactory, NamespaceInfo $namespaceInfo, PageProps $pageProps, RepoGroup $repoGroup, RevisionLookup $revisionLookup, WANObjectCache $wanObjectCache, WatchedItemStoreInterface $watchedItemStore, RedirectLookup $redirectLookup, RestrictionStore $restrictionStore, LinksMigration $linksMigration)
getPageTitle()
Returns the name that goes in the "<h1>" page title.
pageInfo()
Returns an array of info groups (will be rendered as tables), keyed by group ID.
static getCacheKey(WANObjectCache $cache, PageIdentity $page, $revId)
onView()
Shows page information on GET request.
getNamespaceProtectionMessage(Title $title)
Get namespace protection message for title or null if no namespace protection has been applied.
getDescription()
Returns the description that goes below the "<h1>" tag.
requiresUnblock()
Whether this action can still be executed by a blocked user.
getName()
Returns the name of the action this object responds to.
addRow( $table, $name, $value, $id)
Adds a row to a table that will be added to the content.
addTable( $content, $table)
Adds a table to the content that will be added to the output.
static invalidateCache(PageIdentity $page, $revid=null)
Clear the info cache for a given Title.
Base class for language-specific code.
static formatHiddenCategories( $hiddencats)
Returns HTML for the "hidden categories on this page" list.
static revUserTools(RevisionRecord $revRecord, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
A factory that stores information about MagicWords, and creates them on demand with caching.
A class containing constants representing the names of configuration variables.
The Message class deals with fetching and processing of interface message into a variety of formats.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Gives access to properties of a page.
Prioritized list of file repositories.
static escapeIdForAttribute( $id, $mode=self::ID_PRIMARY)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid HTM...
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,...
static getTitleValueFor( $name, $subpage=false, $fragment='')
Get a localised TitleValue object for a specified special page name.
Handles formatting for the "templates used on this page" lists.
Represents a title within MediaWiki.
getLength( $flags=0)
What is the length of this page? Uses link cache, adding it if necessary.
static newFromName( $name, $validate='valid')
Multi-datacenter aware caching interface.
Interface for objects which can provide a MediaWiki context on request.
Interface for objects (potentially) representing an editable wiki page.
Service for resolving a wiki page redirect.
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
countVisitingWatchers( $target, $threshold)
Number of page watchers who also visited a "recent" edit.
if(!isset( $args[0])) $lang