MediaWiki  REL1_23
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, $wgRCMaxAge, $wgMemc, $wgMiserMode,
00197             $wgUnwatchedPageThreshold, $wgPageInfoTransclusionLimit;
00198 
00199         $user = $this->getUser();
00200         $lang = $this->getLanguage();
00201         $title = $this->getTitle();
00202         $id = $title->getArticleID();
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 = self::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         $pageInfo['header-basic'][] = array( $this->msg( 'pageinfo-language' ),
00279             Language::fetchLanguageName( $pageLang, $lang->getCode() )
00280             . ' ' . $this->msg( 'parentheses', $pageLang ) );
00281 
00282         // Content model of the page
00283         $pageInfo['header-basic'][] = array(
00284             $this->msg( 'pageinfo-content-model' ),
00285             ContentHandler::getLocalizedName( $title->getContentModel() )
00286         );
00287 
00288         // Search engine status
00289         $pOutput = new ParserOutput();
00290         if ( isset( $pageProperties['noindex'] ) ) {
00291             $pOutput->setIndexPolicy( 'noindex' );
00292         }
00293         if ( isset( $pageProperties['index'] ) ) {
00294             $pOutput->setIndexPolicy( 'index' );
00295         }
00296 
00297         // Use robot policy logic
00298         $policy = $this->page->getRobotPolicy( 'view', $pOutput );
00299         $pageInfo['header-basic'][] = array(
00300             // Messages: pageinfo-robot-index, pageinfo-robot-noindex
00301             $this->msg( 'pageinfo-robot-policy' ), $this->msg( "pageinfo-robot-${policy['index']}" )
00302         );
00303 
00304         if ( isset( $pageCounts['views'] ) ) {
00305             // Number of views
00306             $pageInfo['header-basic'][] = array(
00307                 $this->msg( 'pageinfo-views' ), $lang->formatNum( $pageCounts['views'] )
00308             );
00309         }
00310 
00311         if (
00312             $user->isAllowed( 'unwatchedpages' ) ||
00313             ( $wgUnwatchedPageThreshold !== false &&
00314                 $pageCounts['watchers'] >= $wgUnwatchedPageThreshold )
00315         ) {
00316             // Number of page watchers
00317             $pageInfo['header-basic'][] = array(
00318                 $this->msg( 'pageinfo-watchers' ), $lang->formatNum( $pageCounts['watchers'] )
00319             );
00320         } elseif ( $wgUnwatchedPageThreshold !== false ) {
00321             $pageInfo['header-basic'][] = array(
00322                 $this->msg( 'pageinfo-watchers' ),
00323                 $this->msg( 'pageinfo-few-watchers' )->numParams( $wgUnwatchedPageThreshold )
00324             );
00325         }
00326 
00327         // Redirects to this page
00328         $whatLinksHere = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
00329         $pageInfo['header-basic'][] = array(
00330             Linker::link(
00331                 $whatLinksHere,
00332                 $this->msg( 'pageinfo-redirects-name' )->escaped(),
00333                 array(),
00334                 array( 'hidelinks' => 1, 'hidetrans' => 1 )
00335             ),
00336             $this->msg( 'pageinfo-redirects-value' )
00337                 ->numParams( count( $title->getRedirectsHere() ) )
00338         );
00339 
00340         // Is it counted as a content page?
00341         if ( $this->page->isCountable() ) {
00342             $pageInfo['header-basic'][] = array(
00343                 $this->msg( 'pageinfo-contentpage' ),
00344                 $this->msg( 'pageinfo-contentpage-yes' )
00345             );
00346         }
00347 
00348         // Subpages of this page, if subpages are enabled for the current NS
00349         if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
00350             $prefixIndex = SpecialPage::getTitleFor( 'Prefixindex', $title->getPrefixedText() . '/' );
00351             $pageInfo['header-basic'][] = array(
00352                 Linker::link( $prefixIndex, $this->msg( 'pageinfo-subpages-name' )->escaped() ),
00353                 $this->msg( 'pageinfo-subpages-value' )
00354                     ->numParams(
00355                         $pageCounts['subpages']['total'],
00356                         $pageCounts['subpages']['redirects'],
00357                         $pageCounts['subpages']['nonredirects'] )
00358             );
00359         }
00360 
00361         if ( $title->inNamespace( NS_CATEGORY ) ) {
00362             $category = Category::newFromTitle( $title );
00363             $pageInfo['category-info'] = array(
00364                 array(
00365                     $this->msg( 'pageinfo-category-pages' ),
00366                     $lang->formatNum( $category->getPageCount() )
00367                 ),
00368                 array(
00369                     $this->msg( 'pageinfo-category-subcats' ),
00370                     $lang->formatNum( $category->getSubcatCount() )
00371                 ),
00372                 array(
00373                     $this->msg( 'pageinfo-category-files' ),
00374                     $lang->formatNum( $category->getFileCount() )
00375                 )
00376             );
00377         }
00378 
00379         // Page protection
00380         $pageInfo['header-restrictions'] = array();
00381 
00382         // Is this page effected by the cascading protection of something which includes it?
00383         if ( $title->isCascadeProtected() ) {
00384             $cascadingFrom = '';
00385             $sources = $title->getCascadeProtectionSources(); // Array deferencing is in PHP 5.4 :(
00386 
00387             foreach ( $sources[0] as $sourceTitle ) {
00388                 $cascadingFrom .= Html::rawElement( 'li', array(), Linker::linkKnown( $sourceTitle ) );
00389             }
00390 
00391             $cascadingFrom = Html::rawElement( 'ul', array(), $cascadingFrom );
00392             $pageInfo['header-restrictions'][] = array(
00393                 $this->msg( 'pageinfo-protect-cascading-from' ),
00394                 $cascadingFrom
00395             );
00396         }
00397 
00398         // Is out protection set to cascade to other pages?
00399         if ( $title->areRestrictionsCascading() ) {
00400             $pageInfo['header-restrictions'][] = array(
00401                 $this->msg( 'pageinfo-protect-cascading' ),
00402                 $this->msg( 'pageinfo-protect-cascading-yes' )
00403             );
00404         }
00405 
00406         // Page protection
00407         foreach ( $title->getRestrictionTypes() as $restrictionType ) {
00408             $protectionLevel = implode( ', ', $title->getRestrictions( $restrictionType ) );
00409 
00410             if ( $protectionLevel == '' ) {
00411                 // Allow all users
00412                 $message = $this->msg( 'protect-default' )->escaped();
00413             } else {
00414                 // Administrators only
00415                 // Messages: protect-level-autoconfirmed, protect-level-sysop
00416                 $message = $this->msg( "protect-level-$protectionLevel" );
00417                 if ( $message->isDisabled() ) {
00418                     // Require "$1" permission
00419                     $message = $this->msg( "protect-fallback", $protectionLevel )->parse();
00420                 } else {
00421                     $message = $message->escaped();
00422                 }
00423             }
00424 
00425             // Messages: restriction-edit, restriction-move, restriction-create,
00426             // restriction-upload
00427             $pageInfo['header-restrictions'][] = array(
00428                 $this->msg( "restriction-$restrictionType" ), $message
00429             );
00430         }
00431 
00432         if ( !$this->page->exists() ) {
00433             return $pageInfo;
00434         }
00435 
00436         // Edit history
00437         $pageInfo['header-edits'] = array();
00438 
00439         $firstRev = $this->page->getOldestRevision();
00440         $lastRev = $this->page->getRevision();
00441         $batch = new LinkBatch;
00442 
00443         if ( $firstRev ) {
00444             $firstRevUser = $firstRev->getUserText( Revision::FOR_THIS_USER );
00445             if ( $firstRevUser !== '' ) {
00446                 $batch->add( NS_USER, $firstRevUser );
00447                 $batch->add( NS_USER_TALK, $firstRevUser );
00448             }
00449         }
00450 
00451         if ( $lastRev ) {
00452             $lastRevUser = $lastRev->getUserText( Revision::FOR_THIS_USER );
00453             if ( $lastRevUser !== '' ) {
00454                 $batch->add( NS_USER, $lastRevUser );
00455                 $batch->add( NS_USER_TALK, $lastRevUser );
00456             }
00457         }
00458 
00459         $batch->execute();
00460 
00461         if ( $firstRev ) {
00462             // Page creator
00463             $pageInfo['header-edits'][] = array(
00464                 $this->msg( 'pageinfo-firstuser' ),
00465                 Linker::revUserTools( $firstRev )
00466             );
00467 
00468             // Date of page creation
00469             $pageInfo['header-edits'][] = array(
00470                 $this->msg( 'pageinfo-firsttime' ),
00471                 Linker::linkKnown(
00472                     $title,
00473                     $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
00474                     array(),
00475                     array( 'oldid' => $firstRev->getId() )
00476                 )
00477             );
00478         }
00479 
00480         if ( $lastRev ) {
00481             // Latest editor
00482             $pageInfo['header-edits'][] = array(
00483                 $this->msg( 'pageinfo-lastuser' ),
00484                 Linker::revUserTools( $lastRev )
00485             );
00486 
00487             // Date of latest edit
00488             $pageInfo['header-edits'][] = array(
00489                 $this->msg( 'pageinfo-lasttime' ),
00490                 Linker::linkKnown(
00491                     $title,
00492                     $lang->userTimeAndDate( $this->page->getTimestamp(), $user ),
00493                     array(),
00494                     array( 'oldid' => $this->page->getLatest() )
00495                 )
00496             );
00497         }
00498 
00499         // Total number of edits
00500         $pageInfo['header-edits'][] = array(
00501             $this->msg( 'pageinfo-edits' ), $lang->formatNum( $pageCounts['edits'] )
00502         );
00503 
00504         // Total number of distinct authors
00505         $pageInfo['header-edits'][] = array(
00506             $this->msg( 'pageinfo-authors' ), $lang->formatNum( $pageCounts['authors'] )
00507         );
00508 
00509         // Recent number of edits (within past 30 days)
00510         $pageInfo['header-edits'][] = array(
00511             $this->msg( 'pageinfo-recent-edits', $lang->formatDuration( $wgRCMaxAge ) ),
00512             $lang->formatNum( $pageCounts['recent_edits'] )
00513         );
00514 
00515         // Recent number of distinct authors
00516         $pageInfo['header-edits'][] = array(
00517             $this->msg( 'pageinfo-recent-authors' ), $lang->formatNum( $pageCounts['recent_authors'] )
00518         );
00519 
00520         // Array of MagicWord objects
00521         $magicWords = MagicWord::getDoubleUnderscoreArray();
00522 
00523         // Array of magic word IDs
00524         $wordIDs = $magicWords->names;
00525 
00526         // Array of IDs => localized magic words
00527         $localizedWords = $wgContLang->getMagicWords();
00528 
00529         $listItems = array();
00530         foreach ( $pageProperties as $property => $value ) {
00531             if ( in_array( $property, $wordIDs ) ) {
00532                 $listItems[] = Html::element( 'li', array(), $localizedWords[$property][1] );
00533             }
00534         }
00535 
00536         $localizedList = Html::rawElement( 'ul', array(), implode( '', $listItems ) );
00537         $hiddenCategories = $this->page->getHiddenCategories();
00538 
00539         if (
00540             count( $listItems ) > 0 ||
00541             count( $hiddenCategories ) > 0 ||
00542             $pageCounts['transclusion']['from'] > 0 ||
00543             $pageCounts['transclusion']['to'] > 0
00544         ) {
00545             $options = array( 'LIMIT' => $wgPageInfoTransclusionLimit );
00546             $transcludedTemplates = $title->getTemplateLinksFrom( $options );
00547             if ( $wgMiserMode ) {
00548                 $transcludedTargets = array();
00549             } else {
00550                 $transcludedTargets = $title->getTemplateLinksTo( $options );
00551             }
00552 
00553             // Page properties
00554             $pageInfo['header-properties'] = array();
00555 
00556             // Magic words
00557             if ( count( $listItems ) > 0 ) {
00558                 $pageInfo['header-properties'][] = array(
00559                     $this->msg( 'pageinfo-magic-words' )->numParams( count( $listItems ) ),
00560                     $localizedList
00561                 );
00562             }
00563 
00564             // Hidden categories
00565             if ( count( $hiddenCategories ) > 0 ) {
00566                 $pageInfo['header-properties'][] = array(
00567                     $this->msg( 'pageinfo-hidden-categories' )
00568                         ->numParams( count( $hiddenCategories ) ),
00569                     Linker::formatHiddenCategories( $hiddenCategories )
00570                 );
00571             }
00572 
00573             // Transcluded templates
00574             if ( $pageCounts['transclusion']['from'] > 0 ) {
00575                 if ( $pageCounts['transclusion']['from'] > count( $transcludedTemplates ) ) {
00576                     $more = $this->msg( 'morenotlisted' )->escaped();
00577                 } else {
00578                     $more = null;
00579                 }
00580 
00581                 $pageInfo['header-properties'][] = array(
00582                     $this->msg( 'pageinfo-templates' )
00583                         ->numParams( $pageCounts['transclusion']['from'] ),
00584                     Linker::formatTemplates(
00585                         $transcludedTemplates,
00586                         false,
00587                         false,
00588                         $more )
00589                 );
00590             }
00591 
00592             if ( !$wgMiserMode && $pageCounts['transclusion']['to'] > 0 ) {
00593                 if ( $pageCounts['transclusion']['to'] > count( $transcludedTargets ) ) {
00594                     $more = Linker::link(
00595                         $whatLinksHere,
00596                         $this->msg( 'moredotdotdot' )->escaped(),
00597                         array(),
00598                         array( 'hidelinks' => 1, 'hideredirs' => 1 )
00599                     );
00600                 } else {
00601                     $more = null;
00602                 }
00603 
00604                 $pageInfo['header-properties'][] = array(
00605                     $this->msg( 'pageinfo-transclusions' )
00606                         ->numParams( $pageCounts['transclusion']['to'] ),
00607                     Linker::formatTemplates(
00608                         $transcludedTargets,
00609                         false,
00610                         false,
00611                         $more )
00612                 );
00613             }
00614         }
00615 
00616         return $pageInfo;
00617     }
00618 
00625     protected static function pageCounts( Title $title ) {
00626         global $wgRCMaxAge, $wgDisableCounters, $wgMiserMode;
00627 
00628         wfProfileIn( __METHOD__ );
00629         $id = $title->getArticleID();
00630 
00631         $dbr = wfGetDB( DB_SLAVE );
00632         $result = array();
00633 
00634         if ( !$wgDisableCounters ) {
00635             // Number of views
00636             $views = (int)$dbr->selectField(
00637                 'page',
00638                 'page_counter',
00639                 array( 'page_id' => $id ),
00640                 __METHOD__
00641             );
00642             $result['views'] = $views;
00643         }
00644 
00645         // Number of page watchers
00646         $watchers = (int)$dbr->selectField(
00647             'watchlist',
00648             'COUNT(*)',
00649             array(
00650                 'wl_namespace' => $title->getNamespace(),
00651                 'wl_title' => $title->getDBkey(),
00652             ),
00653             __METHOD__
00654         );
00655         $result['watchers'] = $watchers;
00656 
00657         // Total number of edits
00658         $edits = (int)$dbr->selectField(
00659             'revision',
00660             'COUNT(rev_page)',
00661             array( 'rev_page' => $id ),
00662             __METHOD__
00663         );
00664         $result['edits'] = $edits;
00665 
00666         // Total number of distinct authors
00667         $authors = (int)$dbr->selectField(
00668             'revision',
00669             'COUNT(DISTINCT rev_user_text)',
00670             array( 'rev_page' => $id ),
00671             __METHOD__
00672         );
00673         $result['authors'] = $authors;
00674 
00675         // "Recent" threshold defined by $wgRCMaxAge
00676         $threshold = $dbr->timestamp( time() - $wgRCMaxAge );
00677 
00678         // Recent number of edits
00679         $edits = (int)$dbr->selectField(
00680             'revision',
00681             'COUNT(rev_page)',
00682             array(
00683                 'rev_page' => $id,
00684                 "rev_timestamp >= " . $dbr->addQuotes( $threshold )
00685             ),
00686             __METHOD__
00687         );
00688         $result['recent_edits'] = $edits;
00689 
00690         // Recent number of distinct authors
00691         $authors = (int)$dbr->selectField(
00692             'revision',
00693             'COUNT(DISTINCT rev_user_text)',
00694             array(
00695                 'rev_page' => $id,
00696                 "rev_timestamp >= " . $dbr->addQuotes( $threshold )
00697             ),
00698             __METHOD__
00699         );
00700         $result['recent_authors'] = $authors;
00701 
00702         // Subpages (if enabled)
00703         if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
00704             $conds = array( 'page_namespace' => $title->getNamespace() );
00705             $conds[] = 'page_title ' . $dbr->buildLike( $title->getDBkey() . '/', $dbr->anyString() );
00706 
00707             // Subpages of this page (redirects)
00708             $conds['page_is_redirect'] = 1;
00709             $result['subpages']['redirects'] = (int)$dbr->selectField(
00710                 'page',
00711                 'COUNT(page_id)',
00712                 $conds,
00713                 __METHOD__ );
00714 
00715             // Subpages of this page (non-redirects)
00716             $conds['page_is_redirect'] = 0;
00717             $result['subpages']['nonredirects'] = (int)$dbr->selectField(
00718                 'page',
00719                 'COUNT(page_id)',
00720                 $conds,
00721                 __METHOD__
00722             );
00723 
00724             // Subpages of this page (total)
00725             $result['subpages']['total'] = $result['subpages']['redirects']
00726                 + $result['subpages']['nonredirects'];
00727         }
00728 
00729         // Counts for the number of transclusion links (to/from)
00730         if ( $wgMiserMode ) {
00731             $result['transclusion']['to'] = 0;
00732         } else {
00733             $result['transclusion']['to'] = (int)$dbr->selectField(
00734                 'templatelinks',
00735                 'COUNT(tl_from)',
00736                 array(
00737                     'tl_namespace' => $title->getNamespace(),
00738                     'tl_title' => $title->getDBkey()
00739                 ),
00740                 __METHOD__
00741             );
00742         }
00743 
00744         $result['transclusion']['from'] = (int)$dbr->selectField(
00745             'templatelinks',
00746             'COUNT(*)',
00747             array( 'tl_from' => $title->getArticleID() ),
00748             __METHOD__
00749         );
00750 
00751         wfProfileOut( __METHOD__ );
00752 
00753         return $result;
00754     }
00755 
00761     protected function getPageTitle() {
00762         return $this->msg( 'pageinfo-title', $this->getTitle()->getPrefixedText() )->text();
00763     }
00764 
00769     protected function getContributors() {
00770         global $wgHiddenPrefs;
00771 
00772         $contributors = $this->page->getContributors();
00773         $real_names = array();
00774         $user_names = array();
00775         $anon_ips = array();
00776 
00777         # Sift for real versus user names
00778 
00779         foreach ( $contributors as $user ) {
00780             $page = $user->isAnon()
00781                 ? SpecialPage::getTitleFor( 'Contributions', $user->getName() )
00782                 : $user->getUserPage();
00783 
00784             if ( $user->getID() == 0 ) {
00785                 $anon_ips[] = Linker::link( $page, htmlspecialchars( $user->getName() ) );
00786             } elseif ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
00787                 $real_names[] = Linker::link( $page, htmlspecialchars( $user->getRealName() ) );
00788             } else {
00789                 $user_names[] = Linker::link( $page, htmlspecialchars( $user->getName() ) );
00790             }
00791         }
00792 
00793         $lang = $this->getLanguage();
00794 
00795         $real = $lang->listToText( $real_names );
00796 
00797         # "ThisSite user(s) A, B and C"
00798         if ( count( $user_names ) ) {
00799             $user = $this->msg( 'siteusers' )->rawParams( $lang->listToText( $user_names ) )->params(
00800                 count( $user_names ) )->escaped();
00801         } else {
00802             $user = false;
00803         }
00804 
00805         if ( count( $anon_ips ) ) {
00806             $anon = $this->msg( 'anonusers' )->rawParams( $lang->listToText( $anon_ips ) )->params(
00807                 count( $anon_ips ) )->escaped();
00808         } else {
00809             $anon = false;
00810         }
00811 
00812         # This is the big list, all mooshed together. We sift for blank strings
00813         $fulllist = array();
00814         foreach ( array( $real, $user, $anon ) as $s ) {
00815             if ( $s !== '' ) {
00816                 array_push( $fulllist, $s );
00817             }
00818         }
00819 
00820         $count = count( $fulllist );
00821 
00822         # "Based on work by ..."
00823         return $count
00824             ? $this->msg( 'othercontribs' )->rawParams(
00825                 $lang->listToText( $fulllist ) )->params( $count )->escaped()
00826             : '';
00827     }
00828 
00834     protected function getDescription() {
00835         return '';
00836     }
00837 }