56 private const VERSION = 1;
112 parent::__construct( $article,
$context );
113 $this->contentLanguage = $contentLanguage;
114 $this->languageNameUtils = $languageNameUtils;
115 $this->linkBatchFactory = $linkBatchFactory;
116 $this->linkRenderer = $linkRenderer;
117 $this->dbProvider = $dbProvider;
118 $this->magicWordFactory = $magicWordFactory;
119 $this->namespaceInfo = $namespaceInfo;
120 $this->pageProps = $pageProps;
121 $this->repoGroup = $repoGroup;
122 $this->revisionLookup = $revisionLookup;
123 $this->wanObjectCache = $wanObjectCache;
124 $this->watchedItemStore = $watchedItemStore;
125 $this->redirectLookup = $redirectLookup;
126 $this->restrictionStore = $restrictionStore;
127 $this->linksMigration = $linksMigration;
165 $services = MediaWikiServices::getInstance();
166 if ( $revid ===
null ) {
167 $revision = $services->getRevisionLookup()
168 ->getRevisionByTitle( $page, 0, IDBAccessObject::READ_LATEST );
169 $revid = $revision ? $revision->getId() : 0;
171 $cache = $services->getMainWANObjectCache();
173 $cache->delete( $key );
183 'mediawiki.interface.helpers.styles',
184 'mediawiki.action.styles',
193 $revRecord = $this->
getArticle()->fetchRevisionRecord();
196 if ( $revRecord ===
null ) {
197 return $this->
msg(
'missing-revision', $oldid )->parse();
201 if ( !$revRecord->isCurrent() ) {
202 return $this->
msg(
'pageinfo-not-current' )->plain();
209 if ( !$this->
msg(
'pageinfo-header' )->isDisabled() ) {
210 $content .= $this->
msg(
'pageinfo-header' )->parse();
220 foreach ( $pageInfo as
$header => $infoTable ) {
225 $this->
msg(
"pageinfo-$header" )->text(),
226 "mw-pageinfo-$header"
230 foreach ( $infoTable as $infoRow ) {
231 if ( $infoRow[0] ==
"below" ) {
232 $below = $infoRow[1] .
"\n";
235 $name = ( $infoRow[0] instanceof
Message ) ? $infoRow[0]->escaped() : $infoRow[0];
237 $value = ( $infoRow[1] instanceof
Message ) ? $infoRow[1]->escaped() : $infoRow[1];
239 $id = ( $infoRow[0] instanceof
Message ) ? $infoRow[0]->getKey() :
null;
240 $table = $this->
addRow( $table, $name, $value, $id ) .
"\n";
242 if ( $table ===
"\n" ) {
251 if ( !$this->
msg(
'pageinfo-footer' )->isDisabled() ) {
252 $content .= $this->
msg(
'pageinfo-footer' )->parse();
266 return Html::rawElement(
268 [
'id' => Sanitizer::escapeIdForAttribute(
$header ) ],
271 [
'id' => Sanitizer::escapeIdForAttribute( $canonicalId ) ],
287 protected function addRow( $table, $name, $value, $id ) {
291 $id ===
null ? [] : [
'id' =>
'mw-' . $id ],
292 Html::rawElement(
'td', [
'style' =>
'vertical-align: top;' ], $name ) .
293 Html::rawElement(
'td', [], $value )
308 [
'class' =>
'wikitable mw-page-info' ],
330 $config = $this->context->getConfig();
331 $linkRenderer = $this->linkRenderer;
333 $pageCounts = $this->pageCounts();
335 $props = $this->pageProps->getAllProperties( $title );
336 $pageProperties = $props[$id] ?? [];
340 $pageInfo[
'header-basic'] = [];
343 $displayTitle = $pageProperties[
'displaytitle'] ??
346 $pageInfo[
'header-basic'][] = [
347 $this->
msg(
'pageinfo-display-title' ),
352 $redirectTarget = $this->redirectLookup->getRedirectTarget( $this->
getWikiPage() );
353 if ( $redirectTarget !==
null ) {
354 $pageInfo[
'header-basic'][] = [
355 $this->
msg(
'pageinfo-redirectsto' ),
356 $linkRenderer->
makeLink( $redirectTarget ) .
357 $this->
msg(
'word-separator' )->escaped() .
358 $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
360 $this->msg(
'pageinfo-redirectsto-info' )->text(),
362 [
'action' =>
'info' ]
370 $sortKey = htmlspecialchars( $sortKey );
371 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-default-sort' ), $sortKey ];
374 $pageInfo[
'header-basic'][] = [
375 $this->
msg(
'pageinfo-length' ),
380 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-namespace-id' ), $title->
getNamespace() ];
382 if ( $pageNamespace ) {
383 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-namespace' ), $pageNamespace ];
387 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-article-id' ), $id ];
392 $pageLangHtml = $pageLang .
' - ' .
393 $this->languageNameUtils->getLanguageName( $pageLang, $lang->getCode() );
395 if ( $config->get( MainConfigNames::PageLanguageUseDB )
396 && $this->getAuthority()->probablyCan(
'pagelang', $title )
398 $pageLangHtml .= $this->
msg(
'word-separator' )->escaped();
399 $pageLangHtml .= $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
400 SpecialPage::getTitleValueFor(
'PageLanguage', $title->
getPrefixedText() ),
401 $this->msg(
'pageinfo-language-change' )->text()
405 $pageInfo[
'header-basic'][] = [
406 $this->
msg(
'pageinfo-language' )->escaped(),
413 if ( $this->
getAuthority()->probablyCan(
'editcontentmodel', $title ) ) {
414 $modelHtml .= $this->
msg(
'word-separator' )->escaped();
415 $modelHtml .= $this->
msg(
'parentheses' )->rawParams( $linkRenderer->
makeLink(
416 SpecialPage::getTitleValueFor(
'ChangeContentModel', $title->
getPrefixedText() ),
417 $this->msg(
'pageinfo-content-model-change' )->text()
421 $pageInfo[
'header-basic'][] = [
422 $this->
msg(
'pageinfo-content-model' ),
427 $pageUser = User::newFromName( $title->
getRootText() );
428 if ( $pageUser && $pageUser->getId() && !$pageUser->isHidden() ) {
429 $pageInfo[
'header-basic'][] = [
430 $this->
msg(
'pageinfo-user-id' ),
438 if ( isset( $pageProperties[
'noindex'] ) ) {
439 $parserOutput->setIndexPolicy(
'noindex' );
441 if ( isset( $pageProperties[
'index'] ) ) {
442 $parserOutput->setIndexPolicy(
'index' );
446 $policy = $this->
getArticle()->getRobotPolicy(
'view', $parserOutput );
447 $pageInfo[
'header-basic'][] = [
449 $this->
msg(
'pageinfo-robot-policy' ),
450 $this->
msg(
"pageinfo-robot-{$policy['index']}" )
453 $unwatchedPageThreshold = $config->get( MainConfigNames::UnwatchedPageThreshold );
454 if ( $this->
getAuthority()->isAllowed(
'unwatchedpages' ) ||
455 ( $unwatchedPageThreshold !==
false &&
456 $pageCounts[
'watchers'] >= $unwatchedPageThreshold )
459 $pageInfo[
'header-basic'][] = [
460 $this->
msg(
'pageinfo-watchers' ),
461 $lang->formatNum( $pageCounts[
'watchers'] )
464 $config->get( MainConfigNames::ShowUpdatedMarker ) &&
465 isset( $pageCounts[
'visitingWatchers'] )
467 $minToDisclose = $config->get( MainConfigNames::UnwatchedPageSecret );
468 if ( $pageCounts[
'visitingWatchers'] > $minToDisclose ||
469 $this->
getAuthority()->isAllowed(
'unwatchedpages' ) ) {
470 $pageInfo[
'header-basic'][] = [
471 $this->
msg(
'pageinfo-visiting-watchers' ),
472 $lang->formatNum( $pageCounts[
'visitingWatchers'] )
475 $pageInfo[
'header-basic'][] = [
476 $this->
msg(
'pageinfo-visiting-watchers' ),
477 $this->
msg(
'pageinfo-few-visiting-watchers' )
481 } elseif ( $unwatchedPageThreshold !==
false ) {
482 $pageInfo[
'header-basic'][] = [
483 $this->
msg(
'pageinfo-watchers' ),
484 $this->
msg(
'pageinfo-few-watchers' )->numParams( $unwatchedPageThreshold )
489 $whatLinksHere = SpecialPage::getTitleFor(
'Whatlinkshere', $title->
getPrefixedText() );
490 $pageInfo[
'header-basic'][] = [
493 $this->
msg(
'pageinfo-redirects-name' )->text(),
501 $this->
msg(
'pageinfo-redirects-value' )
507 $pageInfo[
'header-basic'][] = [
508 $this->
msg(
'pageinfo-contentpage' ),
509 $this->
msg(
'pageinfo-contentpage-yes' )
514 if ( $this->namespaceInfo->hasSubpages( $title->
getNamespace() ) ) {
515 $prefixIndex = SpecialPage::getTitleFor(
519 $pageInfo[
'header-basic'][] = [
522 $this->
msg(
'pageinfo-subpages-name' )->text()
525 isset( $pageCounts[
'subpages'] )
526 ? $this->
msg(
'pageinfo-subpages-value' )->numParams(
527 $pageCounts[
'subpages'][
'total'],
528 $pageCounts[
'subpages'][
'redirects'],
529 $pageCounts[
'subpages'][
'nonredirects']
530 ) : $this->
msg(
'pageinfo-subpages-value-unknown' )->rawParams(
532 $title, $this->msg(
'purge' )->text(), [], [
'action' =>
'purge' ] )
538 $category = Category::newFromTitle( $title );
540 $allCount = $category->getMemberCount();
541 $subcatCount = $category->getSubcatCount();
542 $fileCount = $category->getFileCount();
543 $pageCount = $category->getPageCount( Category::COUNT_CONTENT_PAGES );
545 $pageInfo[
'category-info'] = [
547 $this->
msg(
'pageinfo-category-total' ),
548 $lang->formatNum( $allCount )
551 $this->
msg(
'pageinfo-category-pages' ),
552 $lang->formatNum( $pageCount )
555 $this->
msg(
'pageinfo-category-subcats' ),
556 $lang->formatNum( $subcatCount )
559 $this->
msg(
'pageinfo-category-files' ),
560 $lang->formatNum( $fileCount )
567 $fileObj = $this->repoGroup->findFile( $title );
568 if ( $fileObj !==
false ) {
570 $output = Wikimedia\base_convert( $fileObj->getSha1(), 36, 16, 40 );
571 $pageInfo[
'header-basic'][] = [
572 $this->
msg(
'pageinfo-file-hash' ),
579 $pageInfo[
'header-restrictions'] = [];
582 if ( $this->restrictionStore->isCascadeProtected( $title ) ) {
584 $sources = $this->restrictionStore->getCascadeProtectionSources( $title )[0];
586 foreach ( $sources as $sourcePageIdentity ) {
587 $cascadingFrom .= Html::rawElement(
594 $cascadingFrom = Html::rawElement(
'ul', [], $cascadingFrom );
595 $pageInfo[
'header-restrictions'][] = [
596 $this->
msg(
'pageinfo-protect-cascading-from' ),
602 if ( $this->restrictionStore->areRestrictionsCascading( $title ) ) {
603 $pageInfo[
'header-restrictions'][] = [
604 $this->
msg(
'pageinfo-protect-cascading' ),
605 $this->
msg(
'pageinfo-protect-cascading-yes' )
610 foreach ( $this->restrictionStore->listApplicableRestrictionTypes( $title ) as $restrictionType ) {
611 $protections = $this->restrictionStore->getRestrictions( $title, $restrictionType );
613 switch ( count( $protections ) ) {
617 $this->
msg(
'protect-default' )->escaped();
622 $message = $this->
msg(
'protect-level-' . $protections[0] );
623 if ( !$message->isDisabled() ) {
624 $message = $message->escaped();
631 $message = $this->
msg(
"protect-fallback", $lang->commaList( $protections ) )->parse();
634 $expiry = $this->restrictionStore->getRestrictionExpiry( $title, $restrictionType );
635 $formattedexpiry = $expiry ===
null ?
'' : $this->
msg(
637 $lang->formatExpiry( $expiry,
true,
'infinity', $user )
639 $message .= $this->
msg(
'word-separator' )->escaped() . $formattedexpiry;
643 $pageInfo[
'header-restrictions'][] = [
644 $this->
msg(
"restriction-$restrictionType" ), $message
647 $protectLog = SpecialPage::getTitleFor(
'Log' );
648 $pageInfo[
'header-restrictions'][] = [
652 $this->
msg(
'pageinfo-view-protect-log' )->text(),
663 $pageInfo[
'header-edits'] = [];
665 $firstRev = $this->revisionLookup->getFirstRevision( $this->
getTitle() );
666 $lastRev = $this->
getWikiPage()->getRevisionRecord();
667 $batch = $this->linkBatchFactory->newLinkBatch();
669 $firstRevUser = $firstRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
670 if ( $firstRevUser ) {
671 $batch->add(
NS_USER, $firstRevUser->getName() );
677 $lastRevUser = $lastRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
678 if ( $lastRevUser ) {
679 $batch->add(
NS_USER, $lastRevUser->getName() );
688 $firstRevUser = $firstRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
692 $firstRevUserName = $firstRevUser ? $firstRevUser->getName() :
'[HIDDEN]';
693 $pageInfo[
'header-edits'][] = [
694 $this->
msg(
'pageinfo-firstuser', $firstRevUserName ),
695 Linker::revUserTools( $firstRev )
699 $pageInfo[
'header-edits'][] = [
700 $this->
msg(
'pageinfo-firsttime' ),
703 $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
705 [
'oldid' => $firstRev->getId() ]
712 $lastRevUser = $lastRev->getUser( RevisionRecord::FOR_THIS_USER, $user );
716 $lastRevUserName = $lastRevUser ? $lastRevUser->getName() :
'[HIDDEN]';
717 $pageInfo[
'header-edits'][] = [
718 $this->
msg(
'pageinfo-lastuser', $lastRevUserName ),
719 Linker::revUserTools( $lastRev )
723 $pageInfo[
'header-edits'][] = [
724 $this->
msg(
'pageinfo-lasttime' ),
727 $lang->userTimeAndDate( $this->getWikiPage()->getTimestamp(), $user ),
729 [
'oldid' => $this->getWikiPage()->getLatest() ]
735 $pageInfo[
'header-edits'][] = [
736 $this->
msg(
'pageinfo-edits' ),
737 $lang->formatNum( $pageCounts[
'edits'] )
741 if ( $pageCounts[
'authors'] > 0 ) {
742 $pageInfo[
'header-edits'][] = [
743 $this->
msg(
'pageinfo-authors' ),
744 $lang->formatNum( $pageCounts[
'authors'] )
749 $pageInfo[
'header-edits'][] = [
751 'pageinfo-recent-edits',
752 $lang->formatDuration( $config->get( MainConfigNames::RCMaxAge ) )
754 $lang->formatNum( $pageCounts[
'recent_edits'] )
758 $pageInfo[
'header-edits'][] = [
759 $this->
msg(
'pageinfo-recent-authors' ),
760 $lang->formatNum( $pageCounts[
'recent_authors'] )
764 $magicWords = $this->magicWordFactory->getDoubleUnderscoreArray();
770 $localizedWords = $this->contentLanguage->getMagicWords();
773 foreach ( $pageProperties as $property => $value ) {
774 if ( in_array( $property, $wordIDs ) ) {
775 $listItems[] = Html::element(
'li', [], $localizedWords[$property][1] );
779 $localizedList = Html::rawElement(
'ul', [], implode(
'', $listItems ) );
780 $hiddenCategories = $this->
getWikiPage()->getHiddenCategories();
783 count( $listItems ) > 0 ||
784 count( $hiddenCategories ) > 0 ||
785 $pageCounts[
'transclusion'][
'from'] > 0 ||
786 $pageCounts[
'transclusion'][
'to'] > 0
788 $options = [
'LIMIT' => $config->get( MainConfigNames::PageInfoTransclusionLimit ) ];
790 if ( $config->get( MainConfigNames::MiserMode ) ) {
791 $transcludedTargets = [];
797 $pageInfo[
'header-properties'] = [];
800 if ( count( $listItems ) > 0 ) {
801 $pageInfo[
'header-properties'][] = [
802 $this->
msg(
'pageinfo-magic-words' )->numParams( count( $listItems ) ),
808 if ( count( $hiddenCategories ) > 0 ) {
809 $pageInfo[
'header-properties'][] = [
810 $this->
msg(
'pageinfo-hidden-categories' )
811 ->numParams( count( $hiddenCategories ) ),
812 Linker::formatHiddenCategories( $hiddenCategories )
817 if ( $pageCounts[
'transclusion'][
'from'] > 0 ) {
818 if ( $pageCounts[
'transclusion'][
'from'] > count( $transcludedTemplates ) ) {
819 $more = $this->
msg(
'morenotlisted' )->escaped();
827 $this->linkBatchFactory,
828 $this->restrictionStore
831 $pageInfo[
'header-properties'][] = [
832 $this->
msg(
'pageinfo-templates' )
833 ->numParams( $pageCounts[
'transclusion'][
'from'] ),
834 $templateListFormatter->format( $transcludedTemplates,
false, $more )
838 if ( !$config->get( MainConfigNames::MiserMode ) && $pageCounts[
'transclusion'][
'to'] > 0 ) {
839 if ( $pageCounts[
'transclusion'][
'to'] > count( $transcludedTargets ) ) {
842 $this->
msg(
'moredotdotdot' )->text(),
844 [
'hidelinks' => 1,
'hideredirs' => 1 ]
853 $this->linkBatchFactory,
854 $this->restrictionStore
857 $pageInfo[
'header-properties'][] = [
858 $this->
msg(
'pageinfo-transclusions' )
859 ->numParams( $pageCounts[
'transclusion'][
'to'] ),
860 $templateListFormatter->format( $transcludedTargets,
false, $more )
878 $rights[] =
'editsitecss';
879 $rights[] =
'editsitejs';
881 $rights[] =
'editsitecss';
883 $rights[] =
'editsitejs';
885 $rights[] =
'editsitejson';
887 $rights[] =
'editusercss';
889 $rights[] =
'edituserjs';
891 $rights[] =
'edituserjson';
893 $namespaceProtection = $this->context->getConfig()->get( MainConfigNames::NamespaceProtection );
894 $right = $namespaceProtection[$title->
getNamespace()] ??
null;
897 $rights = (array)$right;
901 return $this->
msg(
'protect-fallback', $this->
getLanguage()->commaList( $rights ) )->parse();
912 private function pageCounts() {
913 $page = $this->getWikiPage();
915 $config = $this->context->getConfig();
916 $cache = $this->wanObjectCache;
918 return $cache->getWithSetCallback(
919 self::getCacheKey( $cache, $page->getTitle(), $page->getLatest() ),
920 WANObjectCache::TTL_WEEK,
921 function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname ) {
922 $title = $page->getTitle();
925 $dbr = $this->dbProvider->getReplicaDatabase();
926 $setOpts += Database::getCacheSetOptions( $dbr );
928 $field =
'rev_actor';
929 $pageField =
'rev_page';
931 $watchedItemStore = $this->watchedItemStore;
934 $result[
'watchers'] = $watchedItemStore->
countWatchers( $title );
936 if ( $config->get( MainConfigNames::ShowUpdatedMarker ) ) {
937 $updated = (int)
wfTimestamp( TS_UNIX, $page->getTimestamp() );
940 $updated - $config->get( MainConfigNames::WatchersMaxAge )
945 $edits = (int)$dbr->newSelectQueryBuilder()
946 ->select(
'COUNT(*)' )
948 ->where( [
'rev_page' => $id ] )
951 $result[
'edits'] = $edits;
954 if ( $config->get( MainConfigNames::MiserMode ) ) {
955 $result[
'authors'] = 0;
957 $result[
'authors'] = (int)$dbr->newSelectQueryBuilder()
958 ->select(
"COUNT(DISTINCT $field)" )
960 ->where( [ $pageField => $id ] )
966 $threshold = $dbr->timestamp( time() - $config->get( MainConfigNames::RCMaxAge ) );
969 $edits = (int)$dbr->newSelectQueryBuilder()
970 ->select(
'COUNT(rev_page)' )
972 ->where( [
'rev_page' => $id ] )
973 ->andWhere( [
"rev_timestamp >= " . $dbr->addQuotes( $threshold ) ] )
976 $result[
'recent_edits'] = $edits;
979 $result[
'recent_authors'] = (int)$dbr->newSelectQueryBuilder()
980 ->select(
"COUNT(DISTINCT $field)" )
982 ->where( [ $pageField => $id ] )
983 ->andWhere( [
'rev_timestamp >= ' . $dbr->addQuotes( $threshold ) ] )
988 if ( $this->namespaceInfo->hasSubpages( $title->
getNamespace() ) ) {
989 $conds = [
'page_namespace' => $title->
getNamespace() ];
990 $conds[] =
'page_title ' .
991 $dbr->buildLike( $title->
getDBkey() .
'/', $dbr->anyString() );
994 $conds[
'page_is_redirect'] = 1;
995 $result[
'subpages'][
'redirects'] = (int)$dbr->newSelectQueryBuilder()
996 ->select(
'COUNT(page_id)' )
1002 $conds[
'page_is_redirect'] = 0;
1003 $result[
'subpages'][
'nonredirects'] = (int)$dbr->newSelectQueryBuilder()
1004 ->select(
'COUNT(page_id)' )
1011 $result[
'subpages'][
'total'] = $result[
'subpages'][
'redirects']
1012 + $result[
'subpages'][
'nonredirects'];
1016 if ( $config->get( MainConfigNames::MiserMode ) ) {
1017 $result[
'transclusion'][
'to'] = 0;
1019 $result[
'transclusion'][
'to'] = (int)$dbr->newSelectQueryBuilder()
1020 ->select(
'COUNT(tl_from)' )
1021 ->from(
'templatelinks' )
1022 ->where( $this->linksMigration->getLinksConditions(
'templatelinks', $title ) )
1027 $result[
'transclusion'][
'from'] = (int)$dbr->newSelectQueryBuilder()
1028 ->select(
'COUNT(*)' )
1029 ->from(
'templatelinks' )
1045 return $this->msg(
'pageinfo-title' )->plaintextParams( $this->
getTitle()->getPrefixedText() );
1064 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.
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.
__construct(Article $article, IContextSource $context, Language $contentLanguage, LanguageNameUtils $languageNameUtils, LinkBatchFactory $linkBatchFactory, LinkRenderer $linkRenderer, IConnectionProvider $dbProvider, MagicWordFactory $magicWordFactory, NamespaceInfo $namespaceInfo, PageProps $pageProps, RepoGroup $repoGroup, RevisionLookup $revisionLookup, WANObjectCache $wanObjectCache, WatchedItemStoreInterface $watchedItemStore, RedirectLookup $redirectLookup, RestrictionStore $restrictionStore, LinksMigration $linksMigration)
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.
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.
Parent class for all special pages.
The Message class deals with fetching and processing of interface message into a variety of formats.
Prioritized list of file repositories.
Multi-datacenter aware caching interface.
makeKey( $keygroup,... $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.