52 private const VERSION = 1;
55 private $contentLanguage;
58 private $languageNameUtils;
61 private $linkBatchFactory;
64 private $linkRenderer;
67 private $loadBalancer;
70 private $magicWordFactory;
73 private $namespaceInfo;
82 private $revisionLookup;
85 private $wanObjectCache;
88 private $watchedItemStore;
91 private $redirectLookup;
94 private $restrictionStore;
97 private $linksMigration;
137 parent::__construct( $article,
$context );
138 $this->contentLanguage = $contentLanguage;
139 $this->languageNameUtils = $languageNameUtils;
140 $this->linkBatchFactory = $linkBatchFactory;
141 $this->linkRenderer = $linkRenderer;
142 $this->loadBalancer = $loadBalancer;
143 $this->magicWordFactory = $magicWordFactory;
144 $this->namespaceInfo = $namespaceInfo;
145 $this->pageProps = $pageProps;
146 $this->repoGroup = $repoGroup;
147 $this->revisionLookup = $revisionLookup;
148 $this->wanObjectCache = $wanObjectCache;
149 $this->watchedItemStore = $watchedItemStore;
150 $this->redirectLookup = $redirectLookup;
151 $this->restrictionStore = $restrictionStore;
152 $this->linksMigration = $linksMigration;
190 $services = MediaWikiServices::getInstance();
192 $revision = $services->getRevisionLookup()
193 ->getRevisionByTitle( $page, 0, IDBAccessObject::READ_LATEST );
194 $revid = $revision ? $revision->getId() :
null;
196 if ( $revid !==
null ) {
197 $cache = $services->getMainWANObjectCache();
199 $cache->delete( $key );
210 'mediawiki.interface.helpers.styles',
211 'mediawiki.action.styles',
220 $revRecord = $this->
getArticle()->fetchRevisionRecord();
223 if ( $revRecord ===
null ) {
224 return $this->
msg(
'missing-revision', $oldid )->parse();
228 if ( !$revRecord->isCurrent() ) {
229 return $this->
msg(
'pageinfo-not-current' )->plain();
236 if ( !$this->
msg(
'pageinfo-header' )->isDisabled() ) {
237 $content .= $this->
msg(
'pageinfo-header' )->parse();
247 foreach ( $pageInfo as
$header => $infoTable ) {
252 $this->
msg(
"pageinfo-$header" )->text(),
253 "mw-pageinfo-$header"
257 foreach ( $infoTable as $infoRow ) {
258 if ( $infoRow[0] ==
"below" ) {
259 $below = $infoRow[1] .
"\n";
262 $name = ( $infoRow[0] instanceof
Message ) ? $infoRow[0]->escaped() : $infoRow[0];
264 $value = ( $infoRow[1] instanceof
Message ) ? $infoRow[1]->escaped() : $infoRow[1];
266 $id = ( $infoRow[0] instanceof
Message ) ? $infoRow[0]->getKey() :
null;
267 $table = $this->
addRow( $table, $name, $value, $id ) .
"\n";
269 if ( $table ===
"\n" ) {
278 if ( !$this->
msg(
'pageinfo-footer' )->isDisabled() ) {
279 $content .= $this->
msg(
'pageinfo-footer' )->parse();
293 return Html::rawElement(
314 protected function addRow( $table, $name, $value, $id ) {
318 $id ===
null ? [] : [
'id' =>
'mw-' . $id ],
319 Html::rawElement(
'td', [
'style' =>
'vertical-align: top;' ], $name ) .
320 Html::rawElement(
'td', [], $value )
335 [
'class' =>
'wikitable mw-page-info' ],
356 $id =
$title->getArticleID();
357 $config = $this->context->getConfig();
358 $linkRenderer = $this->linkRenderer;
360 $pageCounts = $this->pageCounts();
362 $props = $this->pageProps->getAllProperties(
$title );
363 $pageProperties = $props[$id] ?? [];
367 $pageInfo[
'header-basic'] = [];
370 $displayTitle = $pageProperties[
'displaytitle'] ??
371 htmlspecialchars(
$title->getPrefixedText(), ENT_NOQUOTES );
373 $pageInfo[
'header-basic'][] = [
374 $this->
msg(
'pageinfo-display-title' ),
379 $redirectTarget = $this->redirectLookup->getRedirectTarget( $this->
getWikiPage() );
380 if ( $redirectTarget !==
null ) {
381 $pageInfo[
'header-basic'][] = [
382 $this->
msg(
'pageinfo-redirectsto' ),
383 $linkRenderer->
makeLink( $redirectTarget ) .
384 $this->
msg(
'word-separator' )->escaped() .
385 $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
387 $this->msg(
'pageinfo-redirectsto-info' )->text(),
389 [
'action' =>
'info' ]
395 $sortKey = $pageProperties[
'defaultsort'] ??
$title->getCategorySortkey();
397 $sortKey = htmlspecialchars( $sortKey );
398 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-default-sort' ), $sortKey ];
401 $pageInfo[
'header-basic'][] = [
402 $this->
msg(
'pageinfo-length' ),
407 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-namespace-id' ), $title->
getNamespace() ];
408 $pageNamespace =
$title->getNsText();
409 if ( $pageNamespace ) {
410 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-namespace' ), $pageNamespace ];
414 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-article-id' ), $id ];
417 $pageLang =
$title->getPageLanguage()->getCode();
419 $pageLangHtml = $pageLang .
' - ' .
420 $this->languageNameUtils->getLanguageName( $pageLang,
$lang->getCode() );
422 if ( $config->get( MainConfigNames::PageLanguageUseDB )
423 && $this->getAuthority()->probablyCan(
'pagelang',
$title )
425 $pageLangHtml .=
' ' . $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
427 $this->msg(
'pageinfo-language-change' )->text()
431 $pageInfo[
'header-basic'][] = [
432 $this->
msg(
'pageinfo-language' )->escaped(),
440 $modelHtml .=
' ' . $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
442 $this->msg(
'pageinfo-content-model-change' )->text()
446 $pageInfo[
'header-basic'][] = [
447 $this->
msg(
'pageinfo-content-model' ),
453 if ( $pageUser && $pageUser->getId() && !$pageUser->isHidden() ) {
454 $pageInfo[
'header-basic'][] = [
455 $this->
msg(
'pageinfo-user-id' ),
463 if ( isset( $pageProperties[
'noindex'] ) ) {
464 $parserOutput->setIndexPolicy(
'noindex' );
466 if ( isset( $pageProperties[
'index'] ) ) {
467 $parserOutput->setIndexPolicy(
'index' );
471 $policy = $this->
getArticle()->getRobotPolicy(
'view', $parserOutput );
472 $pageInfo[
'header-basic'][] = [
474 $this->
msg(
'pageinfo-robot-policy' ),
475 $this->
msg(
"pageinfo-robot-{$policy['index']}" )
478 $unwatchedPageThreshold = $config->get( MainConfigNames::UnwatchedPageThreshold );
479 if ( $this->
getAuthority()->isAllowed(
'unwatchedpages' ) ||
480 ( $unwatchedPageThreshold !==
false &&
481 $pageCounts[
'watchers'] >= $unwatchedPageThreshold )
484 $pageInfo[
'header-basic'][] = [
485 $this->
msg(
'pageinfo-watchers' ),
486 $lang->formatNum( $pageCounts[
'watchers'] )
489 $config->get( MainConfigNames::ShowUpdatedMarker ) &&
490 isset( $pageCounts[
'visitingWatchers'] )
492 $minToDisclose = $config->get( MainConfigNames::UnwatchedPageSecret );
493 if ( $pageCounts[
'visitingWatchers'] > $minToDisclose ||
494 $this->
getAuthority()->isAllowed(
'unwatchedpages' ) ) {
495 $pageInfo[
'header-basic'][] = [
496 $this->
msg(
'pageinfo-visiting-watchers' ),
497 $lang->formatNum( $pageCounts[
'visitingWatchers'] )
500 $pageInfo[
'header-basic'][] = [
501 $this->
msg(
'pageinfo-visiting-watchers' ),
502 $this->
msg(
'pageinfo-few-visiting-watchers' )
506 } elseif ( $unwatchedPageThreshold !==
false ) {
507 $pageInfo[
'header-basic'][] = [
508 $this->
msg(
'pageinfo-watchers' ),
509 $this->
msg(
'pageinfo-few-watchers' )->numParams( $unwatchedPageThreshold )
515 $pageInfo[
'header-basic'][] = [
518 $this->
msg(
'pageinfo-redirects-name' )->text(),
526 $this->
msg(
'pageinfo-redirects-value' )
527 ->numParams( count(
$title->getRedirectsHere() ) )
532 $pageInfo[
'header-basic'][] = [
533 $this->
msg(
'pageinfo-contentpage' ),
534 $this->
msg(
'pageinfo-contentpage-yes' )
539 if ( $this->namespaceInfo->hasSubpages(
$title->getNamespace() ) ) {
542 $title->getPrefixedText() .
'/'
544 $pageInfo[
'header-basic'][] = [
547 $this->
msg(
'pageinfo-subpages-name' )->text()
549 $this->
msg(
'pageinfo-subpages-value' )
551 $pageCounts[
'subpages'][
'total'],
552 $pageCounts[
'subpages'][
'redirects'],
553 $pageCounts[
'subpages'][
'nonredirects']
559 $category = Category::newFromTitle(
$title );
561 $allCount = $category->getMemberCount();
562 $subcatCount = $category->getSubcatCount();
563 $fileCount = $category->getFileCount();
564 $pageCount = $category->getPageCount( Category::COUNT_CONTENT_PAGES );
566 $pageInfo[
'category-info'] = [
568 $this->
msg(
'pageinfo-category-total' ),
569 $lang->formatNum( $allCount )
572 $this->
msg(
'pageinfo-category-pages' ),
573 $lang->formatNum( $pageCount )
576 $this->
msg(
'pageinfo-category-subcats' ),
577 $lang->formatNum( $subcatCount )
580 $this->
msg(
'pageinfo-category-files' ),
581 $lang->formatNum( $fileCount )
588 $fileObj = $this->repoGroup->findFile(
$title );
589 if ( $fileObj !==
false ) {
591 $output = Wikimedia\base_convert( $fileObj->getSha1(), 36, 16, 40 );
592 $pageInfo[
'header-basic'][] = [
593 $this->
msg(
'pageinfo-file-hash' ),
600 $pageInfo[
'header-restrictions'] = [];
603 if ( $this->restrictionStore->isCascadeProtected(
$title ) ) {
605 $sources = $this->restrictionStore->getCascadeProtectionSources(
$title )[0];
607 foreach ( $sources as $sourcePageIdentity ) {
608 $cascadingFrom .= Html::rawElement(
615 $cascadingFrom = Html::rawElement(
'ul', [], $cascadingFrom );
616 $pageInfo[
'header-restrictions'][] = [
617 $this->
msg(
'pageinfo-protect-cascading-from' ),
623 if ( $this->restrictionStore->areRestrictionsCascading(
$title ) ) {
624 $pageInfo[
'header-restrictions'][] = [
625 $this->
msg(
'pageinfo-protect-cascading' ),
626 $this->
msg(
'pageinfo-protect-cascading-yes' )
631 foreach ( $this->restrictionStore->listApplicableRestrictionTypes(
$title ) as $restrictionType ) {
632 $protections = $this->restrictionStore->getRestrictions(
$title, $restrictionType );
634 switch ( count( $protections ) ) {
638 $this->
msg(
'protect-default' )->escaped();
643 $message = $this->
msg(
'protect-level-' . $protections[0] );
644 if ( !$message->isDisabled() ) {
645 $message = $message->escaped();
652 $message = $this->
msg(
"protect-fallback",
$lang->commaList( $protections ) )->parse();
655 $expiry = $this->restrictionStore->getRestrictionExpiry(
$title, $restrictionType );
656 $formattedexpiry = $expiry ===
null ?
'' : $this->
msg(
658 $lang->formatExpiry( $expiry,
true,
'infinity', $user )
660 $message .= $this->
msg(
'word-separator' )->escaped() . $formattedexpiry;
664 $pageInfo[
'header-restrictions'][] = [
665 $this->
msg(
"restriction-$restrictionType" ), $message
669 $pageInfo[
'header-restrictions'][] = [
673 $this->
msg(
'pageinfo-view-protect-log' )->text(),
675 [
'type' =>
'protect',
'page' =>
$title->getPrefixedText() ]
684 $pageInfo[
'header-edits'] = [];
686 $firstRev = $this->revisionLookup->getFirstRevision( $this->
getTitle() );
687 $lastRev = $this->
getWikiPage()->getRevisionRecord();
688 $batch = $this->linkBatchFactory->newLinkBatch();
690 $firstRevUser = $firstRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
691 if ( $firstRevUser ) {
692 $batch->add(
NS_USER, $firstRevUser->getName() );
698 $lastRevUser = $lastRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
699 if ( $lastRevUser ) {
700 $batch->add(
NS_USER, $lastRevUser->getName() );
709 $pageInfo[
'header-edits'][] = [
710 $this->
msg(
'pageinfo-firstuser' ),
711 Linker::revUserTools( $firstRev )
715 $pageInfo[
'header-edits'][] = [
716 $this->
msg(
'pageinfo-firsttime' ),
719 $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
721 [
'oldid' => $firstRev->getId() ]
728 $pageInfo[
'header-edits'][] = [
729 $this->
msg(
'pageinfo-lastuser' ),
730 Linker::revUserTools( $lastRev )
734 $pageInfo[
'header-edits'][] = [
735 $this->
msg(
'pageinfo-lasttime' ),
738 $lang->userTimeAndDate( $this->getWikiPage()->getTimestamp(), $user ),
740 [
'oldid' => $this->getWikiPage()->getLatest() ]
746 $pageInfo[
'header-edits'][] = [
747 $this->
msg(
'pageinfo-edits' ),
748 $lang->formatNum( $pageCounts[
'edits'] )
752 if ( $pageCounts[
'authors'] > 0 ) {
753 $pageInfo[
'header-edits'][] = [
754 $this->
msg(
'pageinfo-authors' ),
755 $lang->formatNum( $pageCounts[
'authors'] )
760 $pageInfo[
'header-edits'][] = [
762 'pageinfo-recent-edits',
763 $lang->formatDuration( $config->get( MainConfigNames::RCMaxAge ) )
765 $lang->formatNum( $pageCounts[
'recent_edits'] )
769 $pageInfo[
'header-edits'][] = [
770 $this->
msg(
'pageinfo-recent-authors' ),
771 $lang->formatNum( $pageCounts[
'recent_authors'] )
775 $magicWords = $this->magicWordFactory->getDoubleUnderscoreArray();
781 $localizedWords = $this->contentLanguage->getMagicWords();
784 foreach ( $pageProperties as $property => $value ) {
785 if ( in_array( $property, $wordIDs ) ) {
786 $listItems[] = Html::element(
'li', [], $localizedWords[$property][1] );
790 $localizedList = Html::rawElement(
'ul', [], implode(
'', $listItems ) );
791 $hiddenCategories = $this->
getWikiPage()->getHiddenCategories();
794 count( $listItems ) > 0 ||
795 count( $hiddenCategories ) > 0 ||
796 $pageCounts[
'transclusion'][
'from'] > 0 ||
797 $pageCounts[
'transclusion'][
'to'] > 0
799 $options = [
'LIMIT' => $config->get( MainConfigNames::PageInfoTransclusionLimit ) ];
800 $transcludedTemplates =
$title->getTemplateLinksFrom( $options );
801 if ( $config->get( MainConfigNames::MiserMode ) ) {
802 $transcludedTargets = [];
804 $transcludedTargets =
$title->getTemplateLinksTo( $options );
808 $pageInfo[
'header-properties'] = [];
811 if ( count( $listItems ) > 0 ) {
812 $pageInfo[
'header-properties'][] = [
813 $this->
msg(
'pageinfo-magic-words' )->numParams( count( $listItems ) ),
819 if ( count( $hiddenCategories ) > 0 ) {
820 $pageInfo[
'header-properties'][] = [
821 $this->
msg(
'pageinfo-hidden-categories' )
822 ->numParams( count( $hiddenCategories ) ),
823 Linker::formatHiddenCategories( $hiddenCategories )
828 if ( $pageCounts[
'transclusion'][
'from'] > 0 ) {
829 if ( $pageCounts[
'transclusion'][
'from'] > count( $transcludedTemplates ) ) {
830 $more = $this->
msg(
'morenotlisted' )->escaped();
838 $this->linkBatchFactory,
839 $this->restrictionStore
842 $pageInfo[
'header-properties'][] = [
843 $this->
msg(
'pageinfo-templates' )
844 ->numParams( $pageCounts[
'transclusion'][
'from'] ),
845 $templateListFormatter->format( $transcludedTemplates,
false, $more )
849 if ( !$config->get( MainConfigNames::MiserMode ) && $pageCounts[
'transclusion'][
'to'] > 0 ) {
850 if ( $pageCounts[
'transclusion'][
'to'] > count( $transcludedTargets ) ) {
853 $this->
msg(
'moredotdotdot' )->text(),
855 [
'hidelinks' => 1,
'hideredirs' => 1 ]
864 $this->linkBatchFactory,
865 $this->restrictionStore
868 $pageInfo[
'header-properties'][] = [
869 $this->
msg(
'pageinfo-transclusions' )
870 ->numParams( $pageCounts[
'transclusion'][
'to'] ),
871 $templateListFormatter->format( $transcludedTargets,
false, $more )
888 if (
$title->isRawHtmlMessage() ) {
889 $rights[] =
'editsitecss';
890 $rights[] =
'editsitejs';
891 } elseif (
$title->isSiteCssConfigPage() ) {
892 $rights[] =
'editsitecss';
893 } elseif (
$title->isSiteJsConfigPage() ) {
894 $rights[] =
'editsitejs';
895 } elseif (
$title->isSiteJsonConfigPage() ) {
896 $rights[] =
'editsitejson';
897 } elseif (
$title->isUserCssConfigPage() ) {
898 $rights[] =
'editusercss';
899 } elseif (
$title->isUserJsConfigPage() ) {
900 $rights[] =
'edituserjs';
901 } elseif (
$title->isUserJsonConfigPage() ) {
902 $rights[] =
'edituserjson';
904 $namespaceProtection = $this->context->getConfig()->get( MainConfigNames::NamespaceProtection );
905 $right = $namespaceProtection[
$title->getNamespace()] ??
null;
908 $rights = (array)$right;
912 return $this->
msg(
'protect-fallback', $this->
getLanguage()->commaList( $rights ) )->parse();
923 private function pageCounts() {
924 $page = $this->getWikiPage();
926 $config = $this->context->getConfig();
927 $cache = $this->wanObjectCache;
929 return $cache->getWithSetCallback(
930 self::getCacheKey( $cache, $page->getTitle(), $page->getLatest() ),
931 WANObjectCache::TTL_WEEK,
932 function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname ) {
933 $title = $page->getTitle();
934 $id =
$title->getArticleID();
937 $setOpts += Database::getCacheSetOptions(
$dbr );
939 $field =
'rev_actor';
940 $pageField =
'rev_page';
942 $watchedItemStore = $this->watchedItemStore;
947 if ( $config->get( MainConfigNames::ShowUpdatedMarker ) ) {
948 $updated = (int)
wfTimestamp( TS_UNIX, $page->getTimestamp() );
951 $updated - $config->get( MainConfigNames::WatchersMaxAge )
956 $edits = (int)
$dbr->newSelectQueryBuilder()
957 ->select(
'COUNT(*)' )
959 ->where( [
'rev_page' => $id ] )
962 $result[
'edits'] = $edits;
965 if ( $config->get( MainConfigNames::MiserMode ) ) {
966 $result[
'authors'] = 0;
968 $result[
'authors'] = (int)
$dbr->newSelectQueryBuilder()
969 ->select(
"COUNT(DISTINCT $field)" )
971 ->where( [ $pageField => $id ] )
977 $threshold =
$dbr->timestamp( time() - $config->get( MainConfigNames::RCMaxAge ) );
980 $edits = (int)
$dbr->newSelectQueryBuilder()
981 ->select(
'COUNT(rev_page)' )
983 ->where( [
'rev_page' => $id ] )
984 ->andWhere( [
"rev_timestamp >= " .
$dbr->addQuotes( $threshold ) ] )
987 $result[
'recent_edits'] = $edits;
990 $result[
'recent_authors'] = (int)
$dbr->newSelectQueryBuilder()
991 ->select(
"COUNT(DISTINCT $field)" )
993 ->where( [ $pageField => $id ] )
994 ->andWhere( [
'rev_timestamp >= ' .
$dbr->addQuotes( $threshold ) ] )
999 if ( $this->namespaceInfo->hasSubpages(
$title->getNamespace() ) ) {
1000 $conds = [
'page_namespace' =>
$title->getNamespace() ];
1001 $conds[] =
'page_title ' .
1005 $conds[
'page_is_redirect'] = 1;
1006 $result[
'subpages'][
'redirects'] = (int)
$dbr->newSelectQueryBuilder()
1007 ->select(
'COUNT(page_id)' )
1013 $conds[
'page_is_redirect'] = 0;
1014 $result[
'subpages'][
'nonredirects'] = (int)
$dbr->newSelectQueryBuilder()
1015 ->select(
'COUNT(page_id)' )
1022 $result[
'subpages'][
'total'] = $result[
'subpages'][
'redirects']
1023 + $result[
'subpages'][
'nonredirects'];
1027 if ( $config->get( MainConfigNames::MiserMode ) ) {
1028 $result[
'transclusion'][
'to'] = 0;
1030 $result[
'transclusion'][
'to'] = (int)
$dbr->newSelectQueryBuilder()
1031 ->select(
'COUNT(tl_from)' )
1032 ->from(
'templatelinks' )
1033 ->where( $this->linksMigration->getLinksConditions(
'templatelinks',
$title ) )
1038 $result[
'transclusion'][
'from'] = (int)
$dbr->newSelectQueryBuilder()
1039 ->select(
'COUNT(*)' )
1040 ->from(
'templatelinks' )
1041 ->where( [
'tl_from' =>
$title->getArticleID() ] )
1056 return $this->msg(
'pageinfo-title', $this->
getTitle()->getPrefixedText() )->text();
1075 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.
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.
Legacy class representing an editable page and handling UI for some page actions.
static getLocalizedName( $name, Language $lang=null)
Returns the localized name for a given content model.
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.
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.
__construct(Article $article, IContextSource $context, Language $contentLanguage, 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)
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.
Handles formatting for the "templates used on this page" lists.
A class containing constants representing the names of configuration variables.
Gives access to properties of a page.
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...
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.
static newFromName( $name, $validate='valid')
Multi-datacenter aware caching interface.
makeKey( $collection,... $components)
Make a cache key using the "global" keyspace for the given components.
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.
countVisitingWatchers( $target, $threshold)
Number of page watchers who also visited a "recent" edit.
if(!isset( $args[0])) $lang