MediaWiki  REL1_20
LogFormatter.php
Go to the documentation of this file.
00001 <?php
00033 class LogFormatter {
00034         // Audience options for viewing usernames, comments, and actions
00035         const FOR_PUBLIC = 1;
00036         const FOR_THIS_USER = 2;
00037 
00038         // Static->
00039 
00045         public static function newFromEntry( LogEntry $entry ) {
00046                 global $wgLogActionsHandlers;
00047                 $fulltype = $entry->getFullType();
00048                 $wildcard = $entry->getType() . '/*';
00049                 $handler = '';
00050 
00051                 if ( isset( $wgLogActionsHandlers[$fulltype] ) ) {
00052                         $handler = $wgLogActionsHandlers[$fulltype];
00053                 } elseif ( isset( $wgLogActionsHandlers[$wildcard] ) ) {
00054                         $handler = $wgLogActionsHandlers[$wildcard];
00055                 }
00056 
00057                 if ( $handler !== '' && is_string( $handler ) && class_exists( $handler ) ) {
00058                         return new $handler( $entry );
00059                 }
00060 
00061                 return new LegacyLogFormatter( $entry );
00062         }
00063 
00071         public static function newFromRow( $row ) {
00072                 return self::newFromEntry( DatabaseLogEntry::newFromRow( $row ) );
00073         }
00074 
00075         // Nonstatic->
00076 
00078         protected $entry;
00079 
00081         protected $audience = self::FOR_PUBLIC;
00082 
00084         protected $linkFlood = false;
00085 
00093         protected $plaintext = false;
00094 
00095         protected $irctext = false;
00096 
00097         protected function __construct( LogEntry $entry ) {
00098                 $this->entry = $entry;
00099                 $this->context = RequestContext::getMain();
00100         }
00101 
00106         public function setContext( IContextSource $context ) {
00107                 $this->context = $context;
00108         }
00109 
00116         public function setAudience( $audience ) {
00117                 $this->audience = ( $audience == self::FOR_THIS_USER )
00118                         ? self::FOR_THIS_USER
00119                         : self::FOR_PUBLIC;
00120         }
00121 
00127         protected function canView( $field ) {
00128                 if ( $this->audience == self::FOR_THIS_USER ) {
00129                         return LogEventsList::userCanBitfield(
00130                                 $this->entry->getDeleted(), $field, $this->context->getUser() );
00131                 } else {
00132                         return !$this->entry->isDeleted( $field );
00133                 }
00134         }
00135 
00142         public function setShowUserToolLinks( $value ) {
00143                 $this->linkFlood = $value;
00144         }
00145 
00153         public function getPlainActionText() {
00154                 $this->plaintext = true;
00155                 $text = $this->getActionText();
00156                 $this->plaintext = false;
00157                 return $text;
00158         }
00159 
00166         public function getIRCActionComment() {
00167                 $actionComment = $this->getIRCActionText();
00168                 $comment = $this->entry->getComment();
00169 
00170                 if ( $comment != '' ) {
00171                         if ( $actionComment == '' ) {
00172                                 $actionComment = $comment;
00173                         } else {
00174                                 $actionComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $comment;
00175                         }
00176                 }
00177 
00178                 return $actionComment;
00179         }
00180 
00187         public function getIRCActionText() {
00188                 $this->plaintext = true;
00189                 $this->irctext = true;
00190 
00191                 $entry = $this->entry;
00192                 $parameters = $entry->getParameters();
00193                 // @see LogPage::actionText()
00194                 // Text of title the action is aimed at.
00195                 $target = $entry->getTarget()->getPrefixedText() ;
00196                 $text = null;
00197                 switch( $entry->getType() ) {
00198                         case 'move':
00199                                 switch( $entry->getSubtype() ) {
00200                                         case 'move':
00201                                                 $movesource =  $parameters['4::target'];
00202                                                 $text = wfMessage( '1movedto2' )
00203                                                         ->rawParams( $target, $movesource )->inContentLanguage()->escaped();
00204                                                 break;
00205                                         case 'move_redir':
00206                                                 $movesource =  $parameters['4::target'];
00207                                                 $text = wfMessage( '1movedto2_redir' )
00208                                                         ->rawParams( $target, $movesource )->inContentLanguage()->escaped();
00209                                                 break;
00210                                         case 'move-noredirect':
00211                                                 break;
00212                                         case 'move_redir-noredirect':
00213                                                 break;
00214                                 }
00215                                 break;
00216 
00217                         case 'delete':
00218                                 switch( $entry->getSubtype() ) {
00219                                         case 'delete':
00220                                                 $text = wfMessage( 'deletedarticle' )
00221                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00222                                                 break;
00223                                         case 'restore':
00224                                                 $text = wfMessage( 'undeletedarticle' )
00225                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00226                                                 break;
00227                                         //case 'revision': // Revision deletion
00228                                         //case 'event': // Log deletion
00229                                                 // see https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/LogPage.php?&pathrev=97044&r1=97043&r2=97044
00230                                         //default:
00231                                 }
00232                                 break;
00233 
00234                         case 'patrol':
00235                                 // https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/PatrolLog.php?&pathrev=97495&r1=97494&r2=97495
00236                                 // Create a diff link to the patrolled revision
00237                                 if ( $entry->getSubtype() === 'patrol' ) {
00238                                         $diffLink = htmlspecialchars(
00239                                                 wfMessage( 'patrol-log-diff', $parameters['4::curid'] )
00240                                                         ->inContentLanguage()->text() );
00241                                         $text = wfMessage( 'patrol-log-line', $diffLink, "[[$target]]", "" )
00242                                                 ->inContentLanguage()->text();
00243                                 } else {
00244                                         // broken??
00245                                 }
00246                                 break;
00247 
00248                         case 'protect':
00249                                 switch( $entry->getSubtype() ) {
00250                                 case 'protect':
00251                                         $text = wfMessage( 'protectedarticle' )
00252                                                 ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
00253                                         break;
00254                                 case 'unprotect':
00255                                         $text = wfMessage( 'unprotectedarticle' )
00256                                                 ->rawParams( $target )->inContentLanguage()->escaped();
00257                                         break;
00258                                 case 'modify':
00259                                         $text = wfMessage( 'modifiedarticleprotection' )
00260                                                 ->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
00261                                         break;
00262                                 }
00263                                 break;
00264 
00265                         case 'newusers':
00266                                 switch( $entry->getSubtype() ) {
00267                                         case 'newusers':
00268                                         case 'create':
00269                                                 $text = wfMessage( 'newuserlog-create-entry' )
00270                                                         ->inContentLanguage()->escaped();
00271                                                 break;
00272                                         case 'create2':
00273                                                 $text = wfMessage( 'newuserlog-create2-entry' )
00274                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00275                                                 break;
00276                                         case 'autocreate':
00277                                                 $text = wfMessage( 'newuserlog-autocreate-entry' )
00278                                                         ->inContentLanguage()->escaped();
00279                                                 break;
00280                                 }
00281                                 break;
00282 
00283                         case 'upload':
00284                                 switch( $entry->getSubtype() ) {
00285                                         case 'upload':
00286                                                 $text = wfMessage( 'uploadedimage' )
00287                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00288                                                 break;
00289                                         case 'overwrite':
00290                                                 $text = wfMessage( 'overwroteimage' )
00291                                                         ->rawParams( $target )->inContentLanguage()->escaped();
00292                                                 break;
00293                                 }
00294                                 break;
00295 
00296 
00297                         // case 'suppress' --private log -- aaron  (sign your messages so we know who to blame in a few years :-D)
00298                         // default:
00299                 }
00300                 if( is_null( $text ) ) {
00301                         $text = $this->getPlainActionText();
00302                 }
00303 
00304                 $this->plaintext = false;
00305                 $this->irctext = false;
00306                 return $text;
00307         }
00308 
00313         public function getActionText() {
00314                 if ( $this->canView( LogPage::DELETED_ACTION ) ) {
00315                         $element = $this->getActionMessage();
00316                         if ( $element instanceof Message ) {
00317                                 $element = $this->plaintext ? $element->text() : $element->escaped();
00318                         }
00319                         if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
00320                                 $element = $this->styleRestricedElement( $element );
00321                         }
00322                 } else {
00323                         $performer = $this->getPerformerElement() . $this->msg( 'word-separator' )->text();
00324                         $element = $performer . $this->getRestrictedElement( 'rev-deleted-event' );
00325                 }
00326 
00327                 return $element;
00328         }
00329 
00336         protected function getActionMessage() {
00337                 $message = $this->msg( $this->getMessageKey() );
00338                 $message->params( $this->getMessageParameters() );
00339                 return $message;
00340         }
00341 
00349         protected function getMessageKey() {
00350                 $type = $this->entry->getType();
00351                 $subtype = $this->entry->getSubtype();
00352 
00353                 return "logentry-$type-$subtype";
00354         }
00355 
00361         public function getActionLinks() {
00362                 return '';
00363         }
00364 
00370         protected function extractParameters() {
00371                 $entry = $this->entry;
00372                 $params = array();
00373 
00374                 if ( $entry->isLegacy() ) {
00375                         foreach ( $entry->getParameters() as $index => $value ) {
00376                                 $params[$index + 3] = $value;
00377                         }
00378                 }
00379 
00380                 // Filter out parameters which are not in format #:foo
00381                 foreach ( $entry->getParameters() as $key => $value ) {
00382                         if ( strpos( $key, ':' ) === false ) continue;
00383                         list( $index, $type, $name ) = explode( ':', $key, 3 );
00384                         $params[$index - 1] = $value;
00385                 }
00386 
00387                 /* Message class doesn't like non consecutive numbering.
00388                  * Fill in missing indexes with empty strings to avoid
00389                  * incorrect renumbering.
00390                  */
00391                 if ( count( $params ) ) {
00392                         $max = max( array_keys( $params ) );
00393                         for ( $i = 4; $i < $max; $i++ ) {
00394                                 if ( !isset( $params[$i] ) ) {
00395                                         $params[$i] = '';
00396                                 }
00397                         }
00398                 }
00399                 return $params;
00400         }
00401 
00411         protected function getMessageParameters() {
00412                 if ( isset( $this->parsedParameters ) ) {
00413                         return $this->parsedParameters;
00414                 }
00415 
00416                 $entry = $this->entry;
00417                 $params = $this->extractParameters();
00418                 $params[0] = Message::rawParam( $this->getPerformerElement() );
00419                 $params[1] = $entry->getPerformer()->getName();
00420                 $params[2] = Message::rawParam( $this->makePageLink( $entry->getTarget() ) );
00421 
00422                 // Bad things happens if the numbers are not in correct order
00423                 ksort( $params );
00424                 return $this->parsedParameters = $params;
00425         }
00426 
00434         protected function makePageLink( Title $title = null, $parameters = array() ) {
00435                 if ( !$this->plaintext ) {
00436                         $link = Linker::link( $title, null, array(), $parameters );
00437                 } else {
00438                         if ( !$title instanceof Title ) {
00439                                 throw new MWException( "Expected title, got null" );
00440                         }
00441                         $link = '[[' . $title->getPrefixedText() . ']]';
00442                 }
00443                 return $link;
00444         }
00445 
00452         public function getPerformerElement() {
00453                 if ( $this->canView( LogPage::DELETED_USER ) ) {
00454                         $performer = $this->entry->getPerformer();
00455                         $element = $this->makeUserLink( $performer );
00456                         if ( $this->entry->isDeleted( LogPage::DELETED_USER ) ) {
00457                                 $element = $this->styleRestricedElement( $element );
00458                         }
00459                 } else {
00460                         $element = $this->getRestrictedElement( 'rev-deleted-user' );
00461                 }
00462 
00463                 return $element;
00464         }
00465 
00470         public function getComment() {
00471                 if ( $this->canView( LogPage::DELETED_COMMENT ) ) {
00472                         $comment = Linker::commentBlock( $this->entry->getComment() );
00473                         // No hard coded spaces thanx
00474                         $element = ltrim( $comment );
00475                         if ( $this->entry->isDeleted( LogPage::DELETED_COMMENT ) ) {
00476                                 $element = $this->styleRestricedElement( $element );
00477                         }
00478                 } else {
00479                         $element = $this->getRestrictedElement( 'rev-deleted-comment' );
00480                 }
00481 
00482                 return $element;
00483         }
00484 
00490         protected function getRestrictedElement( $message ) {
00491                 if ( $this->plaintext ) {
00492                         return $this->msg( $message )->text();
00493                 }
00494 
00495                 $content =  $this->msg( $message )->escaped();
00496                 $attribs = array( 'class' => 'history-deleted' );
00497                 return Html::rawElement( 'span', $attribs, $content );
00498         }
00499 
00505         protected function styleRestricedElement( $content ) {
00506                 if ( $this->plaintext ) {
00507                         return $content;
00508                 }
00509                 $attribs = array( 'class' => 'history-deleted' );
00510                 return Html::rawElement( 'span', $attribs, $content );
00511         }
00512 
00519         protected function msg( $key ) {
00520                 return $this->context->msg( $key );
00521         }
00522 
00523         protected function makeUserLink( User $user ) {
00524                 if ( $this->plaintext ) {
00525                         $element = $user->getName();
00526                 } else {
00527                         $element = Linker::userLink(
00528                                 $user->getId(),
00529                                 $user->getName()
00530                         );
00531 
00532                         if ( $this->linkFlood ) {
00533                                 $element .= Linker::userToolLinksRedContribs(
00534                                         $user->getId(),
00535                                         $user->getName(),
00536                                         $user->getEditCount()
00537                                 );
00538                         }
00539                 }
00540                 return $element;
00541         }
00542 
00546         public function getPreloadTitles() {
00547                 return array();
00548         }
00549 
00550 }
00551 
00561 class LegacyLogFormatter extends LogFormatter {
00562 
00572         private $comment = null;
00573 
00581         private $revert = null;
00582 
00583         public function getComment() {
00584                 if ( $this->comment === null ) {
00585                         $this->comment = parent::getComment();
00586                 }
00587 
00588                 // Make sure we execute the LogLine hook so that we immediately return
00589                 // the correct value.
00590                 if ( $this->revert === null ) {
00591                         $this->getActionLinks();
00592                 }
00593 
00594                 return $this->comment;
00595         }
00596 
00597         protected function getActionMessage() {
00598                 $entry = $this->entry;
00599                 $action = LogPage::actionText(
00600                         $entry->getType(),
00601                         $entry->getSubtype(),
00602                         $entry->getTarget(),
00603                         $this->plaintext ? null : $this->context->getSkin(),
00604                         (array)$entry->getParameters(),
00605                         !$this->plaintext // whether to filter [[]] links
00606                 );
00607 
00608                 $performer = $this->getPerformerElement();
00609                 if ( !$this->irctext ) {
00610                         $action = $performer .  $this->msg( 'word-separator' )->text() . $action;
00611                 }
00612 
00613                 return $action;
00614         }
00615 
00616         public function getActionLinks() {
00617                 if ( $this->revert !== null ) {
00618                         return $this->revert;
00619                 }
00620 
00621                 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
00622                         return $this->revert = '';
00623                 }
00624 
00625                 $title = $this->entry->getTarget();
00626                 $type = $this->entry->getType();
00627                 $subtype = $this->entry->getSubtype();
00628 
00629                 // Show unblock/change block link
00630                 if ( ( $type == 'block' || $type == 'suppress' ) && ( $subtype == 'block' || $subtype == 'reblock' ) ) {
00631                         if ( !$this->context->getUser()->isAllowed( 'block' ) ) {
00632                                 return '';
00633                         }
00634 
00635                         $links = array(
00636                                 Linker::linkKnown(
00637                                         SpecialPage::getTitleFor( 'Unblock', $title->getDBkey() ),
00638                                         $this->msg( 'unblocklink' )->escaped()
00639                                 ),
00640                                 Linker::linkKnown(
00641                                         SpecialPage::getTitleFor( 'Block', $title->getDBkey() ),
00642                                         $this->msg( 'change-blocklink' )->escaped()
00643                                 )
00644                         );
00645                         return $this->msg( 'parentheses' )->rawParams(
00646                                 $this->context->getLanguage()->pipeList( $links ) )->escaped();
00647                 // Show change protection link
00648                 } elseif ( $type == 'protect' && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' ) ) {
00649                         $links = array(
00650                                 Linker::link( $title,
00651                                         $this->msg( 'hist' )->escaped(),
00652                                         array(),
00653                                         array(
00654                                                 'action' => 'history',
00655                                                 'offset' => $this->entry->getTimestamp()
00656                                         )
00657                                 )
00658                         );
00659                         if ( $this->context->getUser()->isAllowed( 'protect' ) ) {
00660                                 $links[] = Linker::linkKnown(
00661                                         $title,
00662                                         $this->msg( 'protect_change' )->escaped(),
00663                                         array(),
00664                                         array( 'action' => 'protect' )
00665                                 );
00666                         }
00667                         return $this->msg( 'parentheses' )->rawParams(
00668                                 $this->context->getLanguage()->pipeList( $links ) )->escaped();
00669                 // Show unmerge link
00670                 } elseif( $type == 'merge' && $subtype == 'merge' ) {
00671                         if ( !$this->context->getUser()->isAllowed( 'mergehistory' ) ) {
00672                                 return '';
00673                         }
00674 
00675                         $params = $this->extractParameters();
00676                         $revert = Linker::linkKnown(
00677                                 SpecialPage::getTitleFor( 'MergeHistory' ),
00678                                 $this->msg( 'revertmerge' )->escaped(),
00679                                 array(),
00680                                 array(
00681                                         'target' => $params[3],
00682                                         'dest' => $title->getPrefixedDBkey(),
00683                                         'mergepoint' => $params[4]
00684                                 )
00685                         );
00686                         return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00687                 }
00688 
00689                 // Do nothing. The implementation is handled by the hook modifiying the
00690                 // passed-by-ref parameters. This also changes the default value so that
00691                 // getComment() and getActionLinks() do not call them indefinitely.
00692                 $this->revert = '';
00693 
00694                 // This is to populate the $comment member of this instance so that it
00695                 // can be modified when calling the hook just below.
00696                 if ( $this->comment === null ) {
00697                         $this->getComment();
00698                 }
00699 
00700                 $params = $this->entry->getParameters();
00701 
00702                 wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params,
00703                         &$this->comment, &$this->revert, $this->entry->getTimestamp() ) );
00704 
00705                 return $this->revert;
00706         }
00707 }
00708 
00713 class MoveLogFormatter extends LogFormatter {
00714         public function getPreloadTitles() {
00715                 $params = $this->extractParameters();
00716                 return array( Title::newFromText( $params[3] ) );
00717         }
00718 
00719         protected function getMessageKey() {
00720                 $key = parent::getMessageKey();
00721                 $params = $this->getMessageParameters();
00722                 if ( isset( $params[4] ) && $params[4] === '1' ) {
00723                         $key .= '-noredirect';
00724                 }
00725                 return $key;
00726         }
00727 
00728         protected function getMessageParameters() {
00729                 $params = parent::getMessageParameters();
00730                 $oldname = $this->makePageLink( $this->entry->getTarget(), array( 'redirect' => 'no' ) );
00731                 $newname = $this->makePageLink( Title::newFromText( $params[3] ) );
00732                 $params[2] = Message::rawParam( $oldname );
00733                 $params[3] = Message::rawParam( $newname );
00734                 return $params;
00735         }
00736 
00737         public function getActionLinks() {
00738                 if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
00739                         || $this->entry->getSubtype() !== 'move'
00740                         || !$this->context->getUser()->isAllowed( 'move' ) )
00741                 {
00742                         return '';
00743                 }
00744 
00745                 $params = $this->extractParameters();
00746                 $destTitle = Title::newFromText( $params[3] );
00747                 if ( !$destTitle ) {
00748                         return '';
00749                 }
00750 
00751                 $revert = Linker::linkKnown(
00752                         SpecialPage::getTitleFor( 'Movepage' ),
00753                         $this->msg( 'revertmove' )->escaped(),
00754                         array(),
00755                         array(
00756                                 'wpOldTitle' => $destTitle->getPrefixedDBkey(),
00757                                 'wpNewTitle' => $this->entry->getTarget()->getPrefixedDBkey(),
00758                                 'wpReason'   => $this->msg( 'revertmove' )->inContentLanguage()->text(),
00759                                 'wpMovetalk' => 0
00760                         )
00761                 );
00762                 return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00763         }
00764 }
00765 
00770 class DeleteLogFormatter extends LogFormatter {
00771         protected function getMessageKey() {
00772                 $key = parent::getMessageKey();
00773                 if ( in_array( $this->entry->getSubtype(), array( 'event', 'revision' ) ) ) {
00774                         if ( count( $this->getMessageParameters() ) < 5 ) {
00775                                 return "$key-legacy";
00776                         }
00777                 }
00778                 return $key;
00779         }
00780 
00781         protected function getMessageParameters() {
00782                 if ( isset( $this->parsedParametersDeleteLog ) ) {
00783                         return $this->parsedParametersDeleteLog;
00784                 }
00785 
00786                 $params = parent::getMessageParameters();
00787                 $subtype = $this->entry->getSubtype();
00788                 if ( in_array( $subtype, array( 'event', 'revision' ) ) ) {
00789                         if (
00790                                 ($subtype === 'event' && count( $params ) === 6 ) ||
00791                                 ($subtype === 'revision' && isset( $params[3] ) && $params[3] === 'revision' )
00792                         ) {
00793                                 $paramStart = $subtype === 'revision' ? 4 : 3;
00794 
00795                                 $old = $this->parseBitField( $params[$paramStart+1] );
00796                                 $new = $this->parseBitField( $params[$paramStart+2] );
00797                                 list( $hid, $unhid, $extra ) = RevisionDeleter::getChanges( $new, $old );
00798                                 $changes = array();
00799                                 foreach ( $hid as $v ) {
00800                                         $changes[] = $this->msg( "$v-hid" )->plain();
00801                                 }
00802                                 foreach ( $unhid as $v ) {
00803                                         $changes[] = $this->msg( "$v-unhid" )->plain();
00804                                 }
00805                                 foreach ( $extra as $v ) {
00806                                         $changes[] = $this->msg( $v )->plain();
00807                                 }
00808                                 $changeText =  $this->context->getLanguage()->listToText( $changes );
00809 
00810 
00811                                 $newParams = array_slice( $params, 0, 3 );
00812                                 $newParams[3] = $changeText;
00813                                 $count = count( explode( ',', $params[$paramStart] ) );
00814                                 $newParams[4] = $this->context->getLanguage()->formatNum( $count );
00815                                 return $this->parsedParametersDeleteLog = $newParams;
00816                         } else {
00817                                 return $this->parsedParametersDeleteLog = array_slice( $params, 0, 3 );
00818                         }
00819                 }
00820 
00821                 return $this->parsedParametersDeleteLog = $params;
00822         }
00823 
00824         protected function parseBitField( $string ) {
00825                 // Input is like ofield=2134 or just the number
00826                 if ( strpos( $string, 'field=' ) === 1 ) {
00827                         list( , $field ) = explode( '=', $string );
00828                         return (int) $field;
00829                 } else {
00830                         return (int) $string;
00831                 }
00832         }
00833 
00834         public function getActionLinks() {
00835                 $user = $this->context->getUser();
00836                 if ( !$user->isAllowed( 'deletedhistory' ) || $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
00837                         return '';
00838                 }
00839 
00840                 switch ( $this->entry->getSubtype() ) {
00841                 case 'delete': // Show undelete link
00842                         if( $user->isAllowed( 'undelete' ) ) {
00843                                 $message = 'undeletelink';
00844                         } else {
00845                                 $message = 'undeleteviewlink';
00846                         }
00847                         $revert = Linker::linkKnown(
00848                                 SpecialPage::getTitleFor( 'Undelete' ),
00849                                 $this->msg( $message )->escaped(),
00850                                 array(),
00851                                 array( 'target' => $this->entry->getTarget()->getPrefixedDBkey() )
00852                          );
00853                         return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00854 
00855                 case 'revision': // If an edit was hidden from a page give a review link to the history
00856                         $params = $this->extractParameters();
00857                         if ( !isset( $params[3] ) || !isset( $params[4] ) ) {
00858                                 return '';
00859                         }
00860 
00861                         // Different revision types use different URL params...
00862                         $key = $params[3];
00863                         // This is a CSV of the IDs
00864                         $ids = explode( ',', $params[4] );
00865 
00866                         $links = array();
00867 
00868                         // If there's only one item, we can show a diff link
00869                         if ( count( $ids ) == 1 ) {
00870                                 // Live revision diffs...
00871                                 if ( $key == 'oldid' || $key == 'revision' ) {
00872                                         $links[] = Linker::linkKnown(
00873                                                 $this->entry->getTarget(),
00874                                                 $this->msg( 'diff' )->escaped(),
00875                                                 array(),
00876                                                 array(
00877                                                         'diff' => intval( $ids[0] ),
00878                                                         'unhide' => 1
00879                                                 )
00880                                         );
00881                                 // Deleted revision diffs...
00882                                 } elseif ( $key == 'artimestamp' || $key == 'archive' ) {
00883                                         $links[] = Linker::linkKnown(
00884                                                 SpecialPage::getTitleFor( 'Undelete' ),
00885                                                 $this->msg( 'diff' )->escaped(),
00886                                                 array(),
00887                                                 array(
00888                                                         'target'    => $this->entry->getTarget()->getPrefixedDBKey(),
00889                                                         'diff'      => 'prev',
00890                                                         'timestamp' => $ids[0]
00891                                                 )
00892                                         );
00893                                 }
00894                         }
00895 
00896                         // View/modify link...
00897                         $links[] = Linker::linkKnown(
00898                                 SpecialPage::getTitleFor( 'Revisiondelete' ),
00899                                 $this->msg( 'revdel-restore' )->escaped(),
00900                                 array(),
00901                                 array(
00902                                         'target' => $this->entry->getTarget()->getPrefixedText(),
00903                                         'type' => $key,
00904                                         'ids' => implode( ',', $ids ),
00905                                 )
00906                         );
00907 
00908                         return $this->msg( 'parentheses' )->rawParams(
00909                                 $this->context->getLanguage()->pipeList( $links ) )->escaped();
00910 
00911                 case 'event': // Hidden log items, give review link
00912                         $params = $this->extractParameters();
00913                         if ( !isset( $params[3] ) ) {
00914                                 return '';
00915                         }
00916                         // This is a CSV of the IDs
00917                         $query = $params[3];
00918                         // Link to each hidden object ID, $params[1] is the url param
00919                         $revert = Linker::linkKnown(
00920                                 SpecialPage::getTitleFor( 'Revisiondelete' ),
00921                                 $this->msg( 'revdel-restore' )->escaped(),
00922                                 array(),
00923                                 array(
00924                                         'target' => $this->entry->getTarget()->getPrefixedText(),
00925                                         'type' => 'logging',
00926                                         'ids' => $query
00927                                 )
00928                         );
00929                         return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
00930                 default:
00931                         return '';
00932                 }
00933         }
00934 }
00935 
00940 class PatrolLogFormatter extends LogFormatter {
00941         protected function getMessageKey() {
00942                 $key = parent::getMessageKey();
00943                 $params = $this->getMessageParameters();
00944                 if ( isset( $params[5] ) && $params[5] ) {
00945                         $key .= '-auto';
00946                 }
00947                 return $key;
00948         }
00949 
00950         protected function getMessageParameters() {
00951                 $params = parent::getMessageParameters();
00952 
00953                 $target = $this->entry->getTarget();
00954                 $oldid = $params[3];
00955                 $revision = $this->context->getLanguage()->formatNum( $oldid, true );
00956 
00957                 if ( $this->plaintext ) {
00958                         $revlink = $revision;
00959                 } elseif ( $target->exists() ) {
00960                         $query = array(
00961                                 'oldid' => $oldid,
00962                                 'diff' => 'prev'
00963                         );
00964                         $revlink = Linker::link( $target, htmlspecialchars( $revision ), array(), $query );
00965                 } else {
00966                         $revlink = htmlspecialchars( $revision );
00967                 }
00968 
00969                 $params[3] = Message::rawParam( $revlink );
00970                 return $params;
00971         }
00972 }
00973 
00978 class NewUsersLogFormatter extends LogFormatter {
00979         protected function getMessageParameters() {
00980                 $params = parent::getMessageParameters();
00981                 if ( $this->entry->getSubtype() === 'create2' ) {
00982                         if ( isset( $params[3] ) ) {
00983                                 $target = User::newFromId( $params[3] );
00984                         } else {
00985                                 $target = User::newFromName( $this->entry->getTarget()->getText(), false );
00986                         }
00987                         $params[2] = Message::rawParam( $this->makeUserLink( $target ) );
00988                         $params[3] = $target->getName();
00989                 }
00990                 return $params;
00991         }
00992 
00993         public function getComment() {
00994                 $timestamp = wfTimestamp( TS_MW, $this->entry->getTimestamp() );
00995                 if ( $timestamp < '20080129000000' ) {
00996                         # Suppress $comment from old entries (before 2008-01-29),
00997                         # not needed and can contain incorrect links
00998                         return '';
00999                 }
01000                 return parent::getComment();
01001         }
01002 
01003         public function getPreloadTitles() {
01004                 if ( $this->entry->getSubtype() === 'create2' ) {
01005                         //add the user talk to LinkBatch for the userLink
01006                         return array( Title::makeTitle( NS_USER_TALK, $this->entry->getTarget()->getText() ) );
01007                 }
01008                 return array();
01009         }
01010 }