MediaWiki  REL1_24
InfoAction.php
Go to the documentation of this file.
00001 <?php
00030 class InfoAction extends FormlessAction {
00031     const CACHE_VERSION = '2013-03-17';
00032 
00038     public function getName() {
00039         return 'info';
00040     }
00041 
00047     public function requiresUnblock() {
00048         return false;
00049     }
00050 
00056     public function requiresWrite() {
00057         return false;
00058     }
00059 
00066     public static function invalidateCache( Title $title ) {
00067         global $wgMemc;
00068         // Clear page info.
00069         $revision = WikiPage::factory( $title )->getRevision();
00070         if ( $revision !== null ) {
00071             $key = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $revision->getId() );
00072             $wgMemc->delete( $key );
00073         }
00074     }
00075 
00081     public function onView() {
00082         $content = '';
00083 
00084         // Validate revision
00085         $oldid = $this->page->getOldID();
00086         if ( $oldid ) {
00087             $revision = $this->page->getRevisionFetched();
00088 
00089             // Revision is missing
00090             if ( $revision === null ) {
00091                 return $this->msg( 'missing-revision', $oldid )->parse();
00092             }
00093 
00094             // Revision is not current
00095             if ( !$revision->isCurrent() ) {
00096                 return $this->msg( 'pageinfo-not-current' )->plain();
00097             }
00098         }
00099 
00100         // Page header
00101         if ( !$this->msg( 'pageinfo-header' )->isDisabled() ) {
00102             $content .= $this->msg( 'pageinfo-header' )->parse();
00103         }
00104 
00105         // Hide "This page is a member of # hidden categories" explanation
00106         $content .= Html::element( 'style', array(),
00107             '.mw-hiddenCategoriesExplanation { display: none; }' ) . "\n";
00108 
00109         // Hide "Templates used on this page" explanation
00110         $content .= Html::element( 'style', array(),
00111             '.mw-templatesUsedExplanation { display: none; }' ) . "\n";
00112 
00113         // Get page information
00114         $pageInfo = $this->pageInfo();
00115 
00116         // Allow extensions to add additional information
00117         wfRunHooks( 'InfoAction', array( $this->getContext(), &$pageInfo ) );
00118 
00119         // Render page information
00120         foreach ( $pageInfo as $header => $infoTable ) {
00121             // Messages:
00122             // pageinfo-header-basic, pageinfo-header-edits, pageinfo-header-restrictions,
00123             // pageinfo-header-properties, pageinfo-category-info
00124             $content .= $this->makeHeader( $this->msg( "pageinfo-${header}" )->escaped() ) . "\n";
00125             $table = "\n";
00126             foreach ( $infoTable as $infoRow ) {
00127                 $name = ( $infoRow[0] instanceof Message ) ? $infoRow[0]->escaped() : $infoRow[0];
00128                 $value = ( $infoRow[1] instanceof Message ) ? $infoRow[1]->escaped() : $infoRow[1];
00129                 $id = ( $infoRow[0] instanceof Message ) ? $infoRow[0]->getKey() : null;
00130                 $table = $this->addRow( $table, $name, $value, $id ) . "\n";
00131             }
00132             $content = $this->addTable( $content, $table ) . "\n";
00133         }
00134 
00135         // Page footer
00136         if ( !$this->msg( 'pageinfo-footer' )->isDisabled() ) {
00137             $content .= $this->msg( 'pageinfo-footer' )->parse();
00138         }
00139 
00140         // Page credits
00141         /*if ( $this->page->exists() ) {
00142             $content .= Html::rawElement( 'div', array( 'id' => 'mw-credits' ), $this->getContributors() );
00143         }*/
00144 
00145         return $content;
00146     }
00147 
00154     protected function makeHeader( $header ) {
00155         $spanAttribs = array( 'class' => 'mw-headline', 'id' => Sanitizer::escapeId( $header ) );
00156 
00157         return Html::rawElement( 'h2', array(), Html::element( 'span', $spanAttribs, $header ) );
00158     }
00159 
00169     protected function addRow( $table, $name, $value, $id ) {
00170         return $table . Html::rawElement( 'tr', $id === null ? array() : array( 'id' => 'mw-' . $id ),
00171             Html::rawElement( 'td', array( 'style' => 'vertical-align: top;' ), $name ) .
00172             Html::rawElement( 'td', array(), $value )
00173         );
00174     }
00175 
00183     protected function addTable( $content, $table ) {
00184         return $content . Html::rawElement( 'table', array( 'class' => 'wikitable mw-page-info' ),
00185             $table );
00186     }
00187 
00195     protected function pageInfo() {
00196         global $wgContLang, $wgMemc;
00197 
00198         $user = $this->getUser();
00199         $lang = $this->getLanguage();
00200         $title = $this->getTitle();
00201         $id = $title->getArticleID();
00202         $config = $this->context->getConfig();
00203 
00204         $memcKey = wfMemcKey( 'infoaction',
00205             sha1( $title->getPrefixedText() ), $this->page->getLatest() );
00206         $pageCounts = $wgMemc->get( $memcKey );
00207         $version = isset( $pageCounts['cacheversion'] ) ? $pageCounts['cacheversion'] : false;
00208         if ( $pageCounts === false || $version !== self::CACHE_VERSION ) {
00209             // Get page information that would be too "expensive" to retrieve by normal means
00210             $pageCounts = $this->pageCounts( $title );
00211             $pageCounts['cacheversion'] = self::CACHE_VERSION;
00212 
00213             $wgMemc->set( $memcKey, $pageCounts );
00214         }
00215 
00216         // Get page properties
00217         $dbr = wfGetDB( DB_SLAVE );
00218         $result = $dbr->select(
00219             'page_props',
00220             array( 'pp_propname', 'pp_value' ),
00221             array( 'pp_page' => $id ),
00222             __METHOD__
00223         );
00224 
00225         $pageProperties = array();
00226         foreach ( $result as $row ) {
00227             $pageProperties[$row->pp_propname] = $row->pp_value;
00228         }
00229 
00230         // Basic information
00231         $pageInfo = array();
00232         $pageInfo['header-basic'] = array();
00233 
00234         // Display title
00235         $displayTitle = $title->getPrefixedText();
00236         if ( !empty( $pageProperties['displaytitle'] ) ) {
00237             $displayTitle = $pageProperties['displaytitle'];
00238         }
00239 
00240         $pageInfo['header-basic'][] = array(
00241             $this->msg( 'pageinfo-display-title' ), $displayTitle
00242         );
00243 
00244         // Is it a redirect? If so, where to?
00245         if ( $title->isRedirect() ) {
00246             $pageInfo['header-basic'][] = array(
00247                 $this->msg( 'pageinfo-redirectsto' ),
00248                 Linker::link( $this->page->getRedirectTarget() ) .
00249                 $this->msg( 'word-separator' )->text() .
00250                 $this->msg( 'parentheses', Linker::link(
00251                     $this->page->getRedirectTarget(),
00252                     $this->msg( 'pageinfo-redirectsto-info' )->escaped(),
00253                     array(),
00254                     array( 'action' => 'info' )
00255                 ) )->text()
00256             );
00257         }
00258 
00259         // Default sort key
00260         $sortKey = $title->getCategorySortkey();
00261         if ( !empty( $pageProperties['defaultsort'] ) ) {
00262             $sortKey = $pageProperties['defaultsort'];
00263         }
00264 
00265         $sortKey = htmlspecialchars( $sortKey );
00266         $pageInfo['header-basic'][] = array( $this->msg( 'pageinfo-default-sort' ), $sortKey );
00267 
00268         // Page length (in bytes)
00269         $pageInfo['header-basic'][] = array(
00270             $this->msg( 'pageinfo-length' ), $lang->formatNum( $title->getLength() )
00271         );
00272 
00273         // Page ID (number not localised, as it's a database ID)
00274         $pageInfo['header-basic'][] = array( $this->msg( 'pageinfo-article-id' ), $id );
00275 
00276         // Language in which the page content is (supposed to be) written
00277         $pageLang = $title->getPageLanguage()->getCode();
00278 
00279         if ( $config->get( 'PageLanguageUseDB' ) && $this->getTitle()->userCan( 'pagelang' ) ) {
00280             // Link to Special:PageLanguage with pre-filled page title if user has permissions
00281             $titleObj = SpecialPage::getTitleFor( 'PageLanguage', $title->getPrefixedText() );
00282             $langDisp = Linker::link(
00283                 $titleObj,
00284                 $this->msg( 'pageinfo-language' )->escaped()
00285             );
00286         } else {
00287             // Display just the message
00288             $langDisp = $this->msg( 'pageinfo-language' )->escaped();
00289         }
00290 
00291         $pageInfo['header-basic'][] = array( $langDisp,
00292             Language::fetchLanguageName( $pageLang, $lang->getCode() )
00293             . ' ' . $this->msg( 'parentheses', $pageLang ) );
00294 
00295         // Content model of the page
00296         $pageInfo['header-basic'][] = array(
00297             $this->msg( 'pageinfo-content-model' ),
00298             ContentHandler::getLocalizedName( $title->getContentModel() )
00299         );
00300 
00301         // Search engine status
00302         $pOutput = new ParserOutput();
00303         if ( isset( $pageProperties['noindex'] ) ) {
00304             $pOutput->setIndexPolicy( 'noindex' );
00305         }
00306         if ( isset( $pageProperties['index'] ) ) {
00307             $pOutput->setIndexPolicy( 'index' );
00308         }
00309 
00310         // Use robot policy logic
00311         $policy = $this->page->getRobotPolicy( 'view', $pOutput );
00312         $pageInfo['header-basic'][] = array(
00313             // Messages: pageinfo-robot-index, pageinfo-robot-noindex
00314             $this->msg( 'pageinfo-robot-policy' ), $this->msg( "pageinfo-robot-${policy['index']}" )
00315         );
00316 
00317         if ( isset( $pageCounts['views'] ) ) {
00318             // Number of views
00319             $pageInfo['header-basic'][] = array(
00320                 $this->msg( 'pageinfo-views' ), $lang->formatNum( $pageCounts['views'] )
00321             );
00322         }
00323 
00324         $unwatchedPageThreshold = $config->get( 'UnwatchedPageThreshold' );
00325         if (
00326             $user->isAllowed( 'unwatchedpages' ) ||
00327             ( $unwatchedPageThreshold !== false &&
00328                 $pageCounts['watchers'] >= $unwatchedPageThreshold )
00329         ) {
00330             // Number of page watchers
00331             $pageInfo['header-basic'][] = array(
00332                 $this->msg( 'pageinfo-watchers' ), $lang->formatNum( $pageCounts['watchers'] )
00333             );
00334         } elseif ( $unwatchedPageThreshold !== false ) {
00335             $pageInfo['header-basic'][] = array(
00336                 $this->msg( 'pageinfo-watchers' ),
00337                 $this->msg( 'pageinfo-few-watchers' )->numParams( $unwatchedPageThreshold )
00338             );
00339         }
00340 
00341         // Redirects to this page
00342         $whatLinksHere = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
00343         $pageInfo['header-basic'][] = array(
00344             Linker::link(
00345                 $whatLinksHere,
00346                 $this->msg( 'pageinfo-redirects-name' )->escaped(),
00347                 array(),
00348                 array( 'hidelinks' => 1, 'hidetrans' => 1 )
00349             ),
00350             $this->msg( 'pageinfo-redirects-value' )
00351                 ->numParams( count( $title->getRedirectsHere() ) )
00352         );
00353 
00354         // Is it counted as a content page?
00355         if ( $this->page->isCountable() ) {
00356             $pageInfo['header-basic'][] = array(
00357                 $this->msg( 'pageinfo-contentpage' ),
00358                 $this->msg( 'pageinfo-contentpage-yes' )
00359             );
00360         }
00361 
00362         // Subpages of this page, if subpages are enabled for the current NS
00363         if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
00364             $prefixIndex = SpecialPage::getTitleFor( 'Prefixindex', $title->getPrefixedText() . '/' );
00365             $pageInfo['header-basic'][] = array(
00366                 Linker::link( $prefixIndex, $this->msg( 'pageinfo-subpages-name' )->escaped() ),
00367                 $this->msg( 'pageinfo-subpages-value' )
00368                     ->numParams(
00369                         $pageCounts['subpages']['total'],
00370                         $pageCounts['subpages']['redirects'],
00371                         $pageCounts['subpages']['nonredirects'] )
00372             );
00373         }
00374 
00375         if ( $title->inNamespace( NS_CATEGORY ) ) {
00376             $category = Category::newFromTitle( $title );
00377             $pageInfo['category-info'] = array(
00378                 array(
00379                     $this->msg( 'pageinfo-category-pages' ),
00380                     $lang->formatNum( $category->getPageCount() )
00381                 ),
00382                 array(
00383                     $this->msg( 'pageinfo-category-subcats' ),
00384                     $lang->formatNum( $category->getSubcatCount() )
00385                 ),
00386                 array(
00387                     $this->msg( 'pageinfo-category-files' ),
00388                     $lang->formatNum( $category->getFileCount() )
00389                 )
00390             );
00391         }
00392 
00393         // Page protection
00394         $pageInfo['header-restrictions'] = array();
00395 
00396         // Is this page effected by the cascading protection of something which includes it?
00397         if ( $title->isCascadeProtected() ) {
00398             $cascadingFrom = '';
00399             $sources = $title->getCascadeProtectionSources(); // Array deferencing is in PHP 5.4 :(
00400 
00401             foreach ( $sources[0] as $sourceTitle ) {
00402                 $cascadingFrom .= Html::rawElement( 'li', array(), Linker::linkKnown( $sourceTitle ) );
00403             }
00404 
00405             $cascadingFrom = Html::rawElement( 'ul', array(), $cascadingFrom );
00406             $pageInfo['header-restrictions'][] = array(
00407                 $this->msg( 'pageinfo-protect-cascading-from' ),
00408                 $cascadingFrom
00409             );
00410         }
00411 
00412         // Is out protection set to cascade to other pages?
00413         if ( $title->areRestrictionsCascading() ) {
00414             $pageInfo['header-restrictions'][] = array(
00415                 $this->msg( 'pageinfo-protect-cascading' ),
00416                 $this->msg( 'pageinfo-protect-cascading-yes' )
00417             );
00418         }
00419 
00420         // Page protection
00421         foreach ( $title->getRestrictionTypes() as $restrictionType ) {
00422             $protectionLevel = implode( ', ', $title->getRestrictions( $restrictionType ) );
00423 
00424             if ( $protectionLevel == '' ) {
00425                 // Allow all users
00426                 $message = $this->msg( 'protect-default' )->escaped();
00427             } else {
00428                 // Administrators only
00429                 // Messages: protect-level-autoconfirmed, protect-level-sysop
00430                 $message = $this->msg( "protect-level-$protectionLevel" );
00431                 if ( $message->isDisabled() ) {
00432                     // Require "$1" permission
00433                     $message = $this->msg( "protect-fallback", $protectionLevel )->parse();
00434                 } else {
00435                     $message = $message->escaped();
00436                 }
00437             }
00438 
00439             // Messages: restriction-edit, restriction-move, restriction-create,
00440             // restriction-upload
00441             $pageInfo['header-restrictions'][] = array(
00442                 $this->msg( "restriction-$restrictionType" ), $message
00443             );
00444         }
00445 
00446         if ( !$this->page->exists() ) {
00447             return $pageInfo;
00448         }
00449 
00450         // Edit history
00451         $pageInfo['header-edits'] = array();
00452 
00453         $firstRev = $this->page->getOldestRevision();
00454         $lastRev = $this->page->getRevision();
00455         $batch = new LinkBatch;
00456 
00457         if ( $firstRev ) {
00458             $firstRevUser = $firstRev->getUserText( Revision::FOR_THIS_USER );
00459             if ( $firstRevUser !== '' ) {
00460                 $batch->add( NS_USER, $firstRevUser );
00461                 $batch->add( NS_USER_TALK, $firstRevUser );
00462             }
00463         }
00464 
00465         if ( $lastRev ) {
00466             $lastRevUser = $lastRev->getUserText( Revision::FOR_THIS_USER );
00467             if ( $lastRevUser !== '' ) {
00468                 $batch->add( NS_USER, $lastRevUser );
00469                 $batch->add( NS_USER_TALK, $lastRevUser );
00470             }
00471         }
00472 
00473         $batch->execute();
00474 
00475         if ( $firstRev ) {
00476             // Page creator
00477             $pageInfo['header-edits'][] = array(
00478                 $this->msg( 'pageinfo-firstuser' ),
00479                 Linker::revUserTools( $firstRev )
00480             );
00481 
00482             // Date of page creation
00483             $pageInfo['header-edits'][] = array(
00484                 $this->msg( 'pageinfo-firsttime' ),
00485                 Linker::linkKnown(
00486                     $title,
00487                     $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
00488                     array(),
00489                     array( 'oldid' => $firstRev->getId() )
00490                 )
00491             );
00492         }
00493 
00494         if ( $lastRev ) {
00495             // Latest editor
00496             $pageInfo['header-edits'][] = array(
00497                 $this->msg( 'pageinfo-lastuser' ),
00498                 Linker::revUserTools( $lastRev )
00499             );
00500 
00501             // Date of latest edit
00502             $pageInfo['header-edits'][] = array(
00503                 $this->msg( 'pageinfo-lasttime' ),
00504                 Linker::linkKnown(
00505                     $title,
00506                     $lang->userTimeAndDate( $this->page->getTimestamp(), $user ),
00507                     array(),
00508                     array( 'oldid' => $this->page->getLatest() )
00509                 )
00510             );
00511         }
00512 
00513         // Total number of edits
00514         $pageInfo['header-edits'][] = array(
00515             $this->msg( 'pageinfo-edits' ), $lang->formatNum( $pageCounts['edits'] )
00516         );
00517 
00518         // Total number of distinct authors
00519         $pageInfo['header-edits'][] = array(
00520             $this->msg( 'pageinfo-authors' ), $lang->formatNum( $pageCounts['authors'] )
00521         );
00522 
00523         // Recent number of edits (within past 30 days)
00524         $pageInfo['header-edits'][] = array(
00525             $this->msg( 'pageinfo-recent-edits', $lang->formatDuration( $config->get( 'RCMaxAge' ) ) ),
00526             $lang->formatNum( $pageCounts['recent_edits'] )
00527         );
00528 
00529         // Recent number of distinct authors
00530         $pageInfo['header-edits'][] = array(
00531             $this->msg( 'pageinfo-recent-authors' ), $lang->formatNum( $pageCounts['recent_authors'] )
00532         );
00533 
00534         // Array of MagicWord objects
00535         $magicWords = MagicWord::getDoubleUnderscoreArray();
00536 
00537         // Array of magic word IDs
00538         $wordIDs = $magicWords->names;
00539 
00540         // Array of IDs => localized magic words
00541         $localizedWords = $wgContLang->getMagicWords();
00542 
00543         $listItems = array();
00544         foreach ( $pageProperties as $property => $value ) {
00545             if ( in_array( $property, $wordIDs ) ) {
00546                 $listItems[] = Html::element( 'li', array(), $localizedWords[$property][1] );
00547             }
00548         }
00549 
00550         $localizedList = Html::rawElement( 'ul', array(), implode( '', $listItems ) );
00551         $hiddenCategories = $this->page->getHiddenCategories();
00552 
00553         if (
00554             count( $listItems ) > 0 ||
00555             count( $hiddenCategories ) > 0 ||
00556             $pageCounts['transclusion']['from'] > 0 ||
00557             $pageCounts['transclusion']['to'] > 0
00558         ) {
00559             $options = array( 'LIMIT' => $config->get( 'PageInfoTransclusionLimit' ) );
00560             $transcludedTemplates = $title->getTemplateLinksFrom( $options );
00561             if ( $config->get( 'MiserMode' ) ) {
00562                 $transcludedTargets = array();
00563             } else {
00564                 $transcludedTargets = $title->getTemplateLinksTo( $options );
00565             }
00566 
00567             // Page properties
00568             $pageInfo['header-properties'] = array();
00569 
00570             // Magic words
00571             if ( count( $listItems ) > 0 ) {
00572                 $pageInfo['header-properties'][] = array(
00573                     $this->msg( 'pageinfo-magic-words' )->numParams( count( $listItems ) ),
00574                     $localizedList
00575                 );
00576             }
00577 
00578             // Hidden categories
00579             if ( count( $hiddenCategories ) > 0 ) {
00580                 $pageInfo['header-properties'][] = array(
00581                     $this->msg( 'pageinfo-hidden-categories' )
00582                         ->numParams( count( $hiddenCategories ) ),
00583                     Linker::formatHiddenCategories( $hiddenCategories )
00584                 );
00585             }
00586 
00587             // Transcluded templates
00588             if ( $pageCounts['transclusion']['from'] > 0 ) {
00589                 if ( $pageCounts['transclusion']['from'] > count( $transcludedTemplates ) ) {
00590                     $more = $this->msg( 'morenotlisted' )->escaped();
00591                 } else {
00592                     $more = null;
00593                 }
00594 
00595                 $pageInfo['header-properties'][] = array(
00596                     $this->msg( 'pageinfo-templates' )
00597                         ->numParams( $pageCounts['transclusion']['from'] ),
00598                     Linker::formatTemplates(
00599                         $transcludedTemplates,
00600                         false,
00601                         false,
00602                         $more )
00603                 );
00604             }
00605 
00606             if ( !$config->get( 'MiserMode' ) && $pageCounts['transclusion']['to'] > 0 ) {
00607                 if ( $pageCounts['transclusion']['to'] > count( $transcludedTargets ) ) {
00608                     $more = Linker::link(
00609                         $whatLinksHere,
00610                         $this->msg( 'moredotdotdot' )->escaped(),
00611                         array(),
00612                         array( 'hidelinks' => 1, 'hideredirs' => 1 )
00613                     );
00614                 } else {
00615                     $more = null;
00616                 }
00617 
00618                 $pageInfo['header-properties'][] = array(
00619                     $this->msg( 'pageinfo-transclusions' )
00620                         ->numParams( $pageCounts['transclusion']['to'] ),
00621                     Linker::formatTemplates(
00622                         $transcludedTargets,
00623                         false,
00624                         false,
00625                         $more )
00626                 );
00627             }
00628         }
00629 
00630         return $pageInfo;
00631     }
00632 
00639     protected function pageCounts( Title $title ) {
00640         wfProfileIn( __METHOD__ );
00641         $id = $title->getArticleID();
00642         $config = $this->context->getConfig();
00643 
00644         $dbr = wfGetDB( DB_SLAVE );
00645         $result = array();
00646 
00647         if ( !$config->get( 'DisableCounters' ) ) {
00648             // Number of views
00649             $views = (int)$dbr->selectField(
00650                 'page',
00651                 'page_counter',
00652                 array( 'page_id' => $id ),
00653                 __METHOD__
00654             );
00655             $result['views'] = $views;
00656         }
00657 
00658         // Number of page watchers
00659         $watchers = (int)$dbr->selectField(
00660             'watchlist',
00661             'COUNT(*)',
00662             array(
00663                 'wl_namespace' => $title->getNamespace(),
00664                 'wl_title' => $title->getDBkey(),
00665             ),
00666             __METHOD__
00667         );
00668         $result['watchers'] = $watchers;
00669 
00670         // Total number of edits
00671         $edits = (int)$dbr->selectField(
00672             'revision',
00673             'COUNT(rev_page)',
00674             array( 'rev_page' => $id ),
00675             __METHOD__
00676         );
00677         $result['edits'] = $edits;
00678 
00679         // Total number of distinct authors
00680         $authors = (int)$dbr->selectField(
00681             'revision',
00682             'COUNT(DISTINCT rev_user_text)',
00683             array( 'rev_page' => $id ),
00684             __METHOD__
00685         );
00686         $result['authors'] = $authors;
00687 
00688         // "Recent" threshold defined by RCMaxAge setting
00689         $threshold = $dbr->timestamp( time() - $config->get( 'RCMaxAge' ) );
00690 
00691         // Recent number of edits
00692         $edits = (int)$dbr->selectField(
00693             'revision',
00694             'COUNT(rev_page)',
00695             array(
00696                 'rev_page' => $id,
00697                 "rev_timestamp >= " . $dbr->addQuotes( $threshold )
00698             ),
00699             __METHOD__
00700         );
00701         $result['recent_edits'] = $edits;
00702 
00703         // Recent number of distinct authors
00704         $authors = (int)$dbr->selectField(
00705             'revision',
00706             'COUNT(DISTINCT rev_user_text)',
00707             array(
00708                 'rev_page' => $id,
00709                 "rev_timestamp >= " . $dbr->addQuotes( $threshold )
00710             ),
00711             __METHOD__
00712         );
00713         $result['recent_authors'] = $authors;
00714 
00715         // Subpages (if enabled)
00716         if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
00717             $conds = array( 'page_namespace' => $title->getNamespace() );
00718             $conds[] = 'page_title ' . $dbr->buildLike( $title->getDBkey() . '/', $dbr->anyString() );
00719 
00720             // Subpages of this page (redirects)
00721             $conds['page_is_redirect'] = 1;
00722             $result['subpages']['redirects'] = (int)$dbr->selectField(
00723                 'page',
00724                 'COUNT(page_id)',
00725                 $conds,
00726                 __METHOD__ );
00727 
00728             // Subpages of this page (non-redirects)
00729             $conds['page_is_redirect'] = 0;
00730             $result['subpages']['nonredirects'] = (int)$dbr->selectField(
00731                 'page',
00732                 'COUNT(page_id)',
00733                 $conds,
00734                 __METHOD__
00735             );
00736 
00737             // Subpages of this page (total)
00738             $result['subpages']['total'] = $result['subpages']['redirects']
00739                 + $result['subpages']['nonredirects'];
00740         }
00741 
00742         // Counts for the number of transclusion links (to/from)
00743         if ( $config->get( 'MiserMode' ) ) {
00744             $result['transclusion']['to'] = 0;
00745         } else {
00746             $result['transclusion']['to'] = (int)$dbr->selectField(
00747                 'templatelinks',
00748                 'COUNT(tl_from)',
00749                 array(
00750                     'tl_namespace' => $title->getNamespace(),
00751                     'tl_title' => $title->getDBkey()
00752                 ),
00753                 __METHOD__
00754             );
00755         }
00756 
00757         $result['transclusion']['from'] = (int)$dbr->selectField(
00758             'templatelinks',
00759             'COUNT(*)',
00760             array( 'tl_from' => $title->getArticleID() ),
00761             __METHOD__
00762         );
00763 
00764         wfProfileOut( __METHOD__ );
00765 
00766         return $result;
00767     }
00768 
00774     protected function getPageTitle() {
00775         return $this->msg( 'pageinfo-title', $this->getTitle()->getPrefixedText() )->text();
00776     }
00777 
00782     protected function getContributors() {
00783         $contributors = $this->page->getContributors();
00784         $real_names = array();
00785         $user_names = array();
00786         $anon_ips = array();
00787 
00788         # Sift for real versus user names
00789 
00790         foreach ( $contributors as $user ) {
00791             $page = $user->isAnon()
00792                 ? SpecialPage::getTitleFor( 'Contributions', $user->getName() )
00793                 : $user->getUserPage();
00794 
00795             $hiddenPrefs = $this->context->getConfig()->get( 'HiddenPrefs' );
00796             if ( $user->getID() == 0 ) {
00797                 $anon_ips[] = Linker::link( $page, htmlspecialchars( $user->getName() ) );
00798             } elseif ( !in_array( 'realname', $hiddenPrefs ) && $user->getRealName() ) {
00799                 $real_names[] = Linker::link( $page, htmlspecialchars( $user->getRealName() ) );
00800             } else {
00801                 $user_names[] = Linker::link( $page, htmlspecialchars( $user->getName() ) );
00802             }
00803         }
00804 
00805         $lang = $this->getLanguage();
00806 
00807         $real = $lang->listToText( $real_names );
00808 
00809         # "ThisSite user(s) A, B and C"
00810         if ( count( $user_names ) ) {
00811             $user = $this->msg( 'siteusers' )->rawParams( $lang->listToText( $user_names ) )->params(
00812                 count( $user_names ) )->escaped();
00813         } else {
00814             $user = false;
00815         }
00816 
00817         if ( count( $anon_ips ) ) {
00818             $anon = $this->msg( 'anonusers' )->rawParams( $lang->listToText( $anon_ips ) )->params(
00819                 count( $anon_ips ) )->escaped();
00820         } else {
00821             $anon = false;
00822         }
00823 
00824         # This is the big list, all mooshed together. We sift for blank strings
00825         $fulllist = array();
00826         foreach ( array( $real, $user, $anon ) as $s ) {
00827             if ( $s !== '' ) {
00828                 array_push( $fulllist, $s );
00829             }
00830         }
00831 
00832         $count = count( $fulllist );
00833 
00834         # "Based on work by ..."
00835         return $count
00836             ? $this->msg( 'othercontribs' )->rawParams(
00837                 $lang->listToText( $fulllist ) )->params( $count )->escaped()
00838             : '';
00839     }
00840 
00846     protected function getDescription() {
00847         return '';
00848     }
00849 }