Moved "action links" from LogEventsList to LogFormatter.
authorAlexandre Emsenhuber <ialex.wiki@gmail.com>
Sat, 30 Jun 2012 18:18:03 +0000 (20:18 +0200)
committerAlexandre Emsenhuber <ialex.wiki@gmail.com>
Wed, 15 Aug 2012 09:02:50 +0000 (11:02 +0200)
* This allow extensions to set both action text and links directly
  from a subclass LogFormatter instead of having to use the LogLine
  hooks for this purpose.
* Moved stuff for logs that already use a subclass of LogFormatter
  there and the remaining in LegacyLogFormatter. I had to an hack
  there so that the pass-by-ref of the comment parameter in the
  LogLine hook still works.
* Removed RevisionDeleter::getLogLinks(), included it directly in
  DeleteLogFormatter::getActionLinks(); it have a so ugly signature
  that is very hard to use it somewhere else (and maintain backward
  compatibility too).
* Removed the message caching system in LogEventsList since it's
  not used anymore.
* Some misc cleanup to LogEventsList::logLine()

Change-Id: I96d696eed2ae35f5f5640e422ceb0a5b0c33babf

includes/logging/LogEventsList.php
includes/logging/LogFormatter.php
includes/revisiondelete/RevisionDeleter.php

index 61cba57..6016641 100644 (file)
@@ -30,11 +30,6 @@ class LogEventsList extends ContextSource {
 
        public $flags;
 
-       /**
-        * @var Array
-        */
-       protected $message;
-
        /**
         * @var Array
         */
@@ -59,7 +54,6 @@ class LogEventsList extends ContextSource {
                }
 
                $this->flags = $flags;
-               $this->preCacheMessages();
        }
 
        /**
@@ -72,22 +66,6 @@ class LogEventsList extends ContextSource {
                return $this->getTitle();
        }
 
-       /**
-        * As we use the same small set of messages in various methods and that
-        * they are called often, we call them once and save them in $this->message
-        */
-       private function preCacheMessages() {
-               // Precache various messages
-               if( !isset( $this->message ) ) {
-                       $messages = array( 'revertmerge', 'protect_change', 'unblocklink', 'change-blocklink',
-                               'revertmove', 'undeletelink', 'undeleteviewlink', 'revdel-restore', 'hist', 'diff',
-                               'pipe-separator', 'revdel-restore-deleted', 'revdel-restore-visible' );
-                       foreach( $messages as $msg ) {
-                               $this->message[$msg] = $this->msg( $msg )->escaped();
-                       }
-               }
-       }
-
        /**
         * Set page title and show header for this log type
         * @param $type Array
@@ -329,157 +307,35 @@ class LogEventsList extends ContextSource {
                $formatter->setContext( $this->getContext() );
                $formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) );
 
+               $title = $entry->getTarget();
+               $time = htmlspecialchars( $this->getLanguage()->userTimeAndDate(
+                       $entry->getTimestamp(), $this->getUser() ) );
+
                $action = $formatter->getActionText();
-               $comment = $formatter->getComment();
 
-               $classes = array( 'mw-logline-' . $entry->getType() );
-               $title = $entry->getTarget();
-               $time = $this->logTimestamp( $entry );
+               if ( $this->flags & self::NO_ACTION_LINK ) {
+                       $revert = '';
+               } else {
+                       $revert = $formatter->getActionLinks();
+                       if ( $revert != '' ) {
+                               $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
+                       }
+               }
 
-               // Extract extra parameters
-               $paramArray = LogPage::extractParams( $row->log_params );
-               // Add review/revert links and such...
-               $revert = $this->logActionLinks( $row, $title, $paramArray, $comment );
+               $comment = $formatter->getComment();
 
                // Some user can hide log items and have review links
                $del = $this->getShowHideLinks( $row );
-               if( $del != '' ) $del .= ' ';
 
                // Any tags...
                list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'logevent' );
-               $classes = array_merge( $classes, $newClasses );
-
-               return Xml::tags( 'li', array( "class" => implode( ' ', $classes ) ),
-                       $del . "$time $action $comment $revert $tagDisplay" ) . "\n";
-       }
-
-       private function logTimestamp( LogEntry $entry ) {
-               return htmlspecialchars( $this->getLanguage()->userTimeAndDate(
-                       $entry->getTimestamp(), $this->getUser() ) );
-       }
+               $classes = array_merge(
+                       array( 'mw-logline-' . $entry->getType() ),
+                       $newClasses
+               );
 
-       /**
-        * @todo split up!
-        *
-        * @param  $row
-        * @param Title $title
-        * @param Array $paramArray
-        * @param String $comment Passed by reference
-        * @return String
-        */
-       private function logActionLinks( $row, $title, $paramArray, &$comment ) {
-               if( ( $this->flags & self::NO_ACTION_LINK ) // we don't want to see the action
-                       || self::isDeleted( $row, LogPage::DELETED_ACTION ) ) // action is hidden
-               {
-                       return '';
-               }
-               $revert = '';
-               if( self::typeAction( $row, 'move', 'move', 'move' ) && !empty( $paramArray[0] ) ) {
-                       $destTitle = Title::newFromText( $paramArray[0] );
-                       if( $destTitle ) {
-                               $revert = Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Movepage' ),
-                                       $this->message['revertmove'],
-                                       array(),
-                                       array(
-                                               'wpOldTitle' => $destTitle->getPrefixedDBkey(),
-                                               'wpNewTitle' => $title->getPrefixedDBkey(),
-                                               'wpReason'   => $this->msg( 'revertmove' )->inContentLanguage()->text(),
-                                               'wpMovetalk' => 0
-                                       )
-                               );
-                               $revert = $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
-                       }
-               // Show undelete link
-               } elseif( self::typeAction( $row, array( 'delete', 'suppress' ), 'delete', 'deletedhistory' ) ) {
-                       if( !$this->getUser()->isAllowed( 'undelete' ) ) {
-                               $viewdeleted = $this->message['undeleteviewlink'];
-                       } else {
-                               $viewdeleted = $this->message['undeletelink'];
-                       }
-                       $revert = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'Undelete' ),
-                               $viewdeleted,
-                               array(),
-                               array( 'target' => $title->getPrefixedDBkey() )
-                        );
-                       $revert = $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
-               // Show unblock/change block link
-               } elseif( self::typeAction( $row, array( 'block', 'suppress' ), array( 'block', 'reblock' ), 'block' ) ) {
-                       $revert = Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Unblock', $row->log_title ),
-                                       $this->message['unblocklink']
-                               ) .
-                               $this->message['pipe-separator'] .
-                               Linker::linkKnown(
-                                       SpecialPage::getTitleFor( 'Block', $row->log_title ),
-                                       $this->message['change-blocklink']
-                               );
-                               $revert = $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
-               // Show change protection link
-               } elseif( self::typeAction( $row, 'protect', array( 'modify', 'protect', 'unprotect' ) ) ) {
-                       $revert .= Linker::link( $title,
-                                       $this->message['hist'],
-                                       array(),
-                                       array(
-                                               'action' => 'history',
-                                               'offset' => $row->log_timestamp
-                                       )
-                               );
-                       if( $this->getUser()->isAllowed( 'protect' ) ) {
-                               $revert .= $this->message['pipe-separator'] .
-                                       Linker::link( $title,
-                                               $this->message['protect_change'],
-                                               array(),
-                                               array( 'action' => 'protect' ),
-                                               'known' );
-                       }
-                       $revert = ' ' . $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
-               // Show unmerge link
-               } elseif( self::typeAction( $row, 'merge', 'merge', 'mergehistory' ) ) {
-                       $revert = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'MergeHistory' ),
-                               $this->message['revertmerge'],
-                               array(),
-                               array(
-                                       'target' => $paramArray[0],
-                                       'dest' => $title->getPrefixedDBkey(),
-                                       'mergepoint' => $paramArray[1]
-                               )
-                       );
-                       $revert = $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
-               // If an edit was hidden from a page give a review link to the history
-               } elseif( self::typeAction( $row, array( 'delete', 'suppress' ), 'revision', 'deletedhistory' ) ) {
-                       $revert = RevisionDeleter::getLogLinks( $title, $paramArray,
-                                                               $this->message );
-               // Hidden log items, give review link
-               } elseif( self::typeAction( $row, array( 'delete', 'suppress' ), 'event', 'deletedhistory' ) ) {
-                       if( count($paramArray) >= 1 ) {
-                               $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
-                               // $paramArray[1] is a CSV of the IDs
-                               $query = $paramArray[0];
-                               // Link to each hidden object ID, $paramArray[1] is the url param
-                               $revert = Linker::linkKnown(
-                                       $revdel,
-                                       $this->message['revdel-restore'],
-                                       array(),
-                                       array(
-                                               'target' => $title->getPrefixedText(),
-                                               'type' => 'logging',
-                                               'ids' => $query
-                                       )
-                               );
-                               $revert = $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
-                       }
-               // Do nothing. The implementation is handled by the hook modifiying the passed-by-ref parameters.
-               } else {
-                       wfRunHooks( 'LogLine', array( $row->log_type, $row->log_action, $title, $paramArray,
-                               &$comment, &$revert, $row->log_timestamp ) );
-               }
-               if( $revert != '' ) {
-                       $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
-               }
-               return $revert;
+               return Html::rawElement( 'li', array( 'class' => $classes ),
+                       "$del $time $action $comment $revert $tagDisplay" ) . "\n";
        }
 
        /**
index 4f3292f..8d2219a 100644 (file)
@@ -109,24 +109,24 @@ class LogFormatter {
 
        /**
         * Set the visibility restrictions for displaying content.
-        * If set to public, and an item is deleted, then it will be replaced 
+        * If set to public, and an item is deleted, then it will be replaced
         * with a placeholder even if the context user is allowed to view it.
         * @param $audience integer self::FOR_THIS_USER or self::FOR_PUBLIC
         */
        public function setAudience( $audience ) {
                $this->audience = ( $audience == self::FOR_THIS_USER )
-                       ? self::FOR_THIS_USER 
+                       ? self::FOR_THIS_USER
                        : self::FOR_PUBLIC;
        }
 
        /**
         * Check if a log item can be displayed
         * @param $field integer LogPage::DELETED_* constant
-        * @return bool 
+        * @return bool
         */
        protected function canView( $field ) {
                if ( $this->audience == self::FOR_THIS_USER ) {
-                       return LogEventsList::userCanBitfield( 
+                       return LogEventsList::userCanBitfield(
                                $this->entry->getDeleted(), $field, $this->context->getUser() );
                } else {
                        return !$this->entry->isDeleted( $field );
@@ -279,7 +279,7 @@ class LogFormatter {
                                                break;
                                }
                                break;
-                       
+
 
                        // case 'suppress' --private log -- aaron  (sign your messages so we know who to blame in a few years :-D)
                        // default:
@@ -340,6 +340,15 @@ class LogFormatter {
                return "logentry-$type-$subtype";
        }
 
+       /**
+        * Returns extra links that comes after the action text, like "revert", etc.
+        *
+        * @return string
+        */
+       public function getActionLinks() {
+               return '';
+       }
+
        /**
         * Extracts the optional extra parameters for use in action messages.
         * The array indexes start from number 3.
@@ -537,6 +546,41 @@ class LogFormatter {
  * @since 1.19
  */
 class LegacyLogFormatter extends LogFormatter {
+
+       /**
+        * Backward compatibility for extension changing the comment from
+        * the LogLine hook. This will be set by the first call on getComment(),
+        * then it might be modified by the hook when calling getActionLinks(),
+        * so that the modified value will be returned when calling getComment()
+        * a second time.
+        *
+        * @var string|null
+        */
+       private $comment = null;
+
+       /**
+        * Cache for the result of getActionLinks() so that it does not need to
+        * run multiple times depending on the order that getComment() and
+        * getActionLinks() are called.
+        *
+        * @var string|null
+        */
+       private $revert = null;
+
+       public function getComment() {
+               if ( $this->comment === null ) {
+                       $this->comment = parent::getComment();
+               }
+
+               // Make sure we execute the LogLine hook so that we immediately return
+               // the correct value.
+               if ( $this->revert === null ) {
+                       $this->getActionLinks();
+               }
+
+               return $this->comment;
+       }
+
        protected function getActionMessage() {
                $entry = $this->entry;
                $action = LogPage::actionText(
@@ -556,6 +600,97 @@ class LegacyLogFormatter extends LogFormatter {
                return $action;
        }
 
+       public function getActionLinks() {
+               if ( $this->revert !== null ) {
+                       return $this->revert;
+               }
+
+               if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
+                       return $this->revert = '';
+               }
+
+               $title = $this->entry->getTarget();
+               $type = $this->entry->getType();
+               $subtype = $this->entry->getSubtype();
+
+               // Show unblock/change block link
+               if ( ( $type == 'block' || $type == 'suppress' ) && ( $subtype == 'block' || $subtype == 'reblock' ) ) {
+                       if ( !$this->context->getUser()->isAllowed( 'block' ) ) {
+                               return '';
+                       }
+
+                       $links = array(
+                               Linker::linkKnown(
+                                       SpecialPage::getTitleFor( 'Unblock', $title->getDBkey() ),
+                                       $this->msg( 'unblocklink' )->escaped()
+                               ),
+                               Linker::linkKnown(
+                                       SpecialPage::getTitleFor( 'Block', $title->getDBkey() ),
+                                       $this->msg( 'change-blocklink' )->escaped()
+                               )
+                       );
+                       return $this->msg( 'parentheses' )->rawParams(
+                               $this->context->getLanguage()->pipeList( $links ) )->escaped();
+               // Show change protection link
+               } elseif ( $type == 'protect' && ( $subtype == 'protect' || $subtype == 'modify' || $subtype == 'unprotect' ) ) {
+                       $links = array(
+                               Linker::link( $title,
+                                       $this->msg( 'hist' )->escaped(),
+                                       array(),
+                                       array(
+                                               'action' => 'history',
+                                               'offset' => $this->entry->getTimestamp()
+                                       )
+                               )
+                       );
+                       if ( $this->context->getUser()->isAllowed( 'protect' ) ) {
+                               $links[] = Linker::linkKnown(
+                                       $title,
+                                       $this->msg( 'protect_change' )->escaped(),
+                                       array(),
+                                       array( 'action' => 'protect' )
+                               );
+                       }
+                       return $this->msg( 'parentheses' )->rawParams(
+                               $this->context->getLanguage()->pipeList( $links ) )->escaped();
+               // Show unmerge link
+               } elseif( $type == 'merge' && $subtype == 'merge' ) {
+                       if ( !$this->context->getUser()->isAllowed( 'mergehistory' ) ) {
+                               return '';
+                       }
+
+                       $params = $this->extractParameters();
+                       $revert = Linker::linkKnown(
+                               SpecialPage::getTitleFor( 'MergeHistory' ),
+                               $this->msg( 'revertmerge' )->escaped(),
+                               array(),
+                               array(
+                                       'target' => $params[3],
+                                       'dest' => $title->getPrefixedDBkey(),
+                                       'mergepoint' => $params[4]
+                               )
+                       );
+                       return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+               }
+
+               // Do nothing. The implementation is handled by the hook modifiying the
+               // passed-by-ref parameters. This also changes the default value so that
+               // getComment() and getActionLinks() do not call them indefinitely.
+               $this->revert = '';
+
+               // This is to populate the $comment member of this instance so that it
+               // can be modified when calling the hook just below.
+               if ( $this->comment === null ) {
+                       $this->getComment();
+               }
+
+               $params = $this->entry->getParameters();
+
+               wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params,
+                       &$this->comment, &$this->revert, $this->entry->getTimestamp() ) );
+
+               return $this->revert;
+       }
 }
 
 /**
@@ -585,6 +720,34 @@ class MoveLogFormatter extends LogFormatter {
                $params[3] = Message::rawParam( $newname );
                return $params;
        }
+
+       public function getActionLinks() {
+               if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
+                       || $this->entry->getSubtype() !== 'move'
+                       || !$this->context->getUser()->isAllowed( 'move' ) )
+               {
+                       return '';
+               }
+
+               $params = $this->extractParameters();
+               $destTitle = Title::newFromText( $params[3] );
+               if ( !$destTitle ) {
+                       return '';
+               }
+
+               $revert = Linker::linkKnown(
+                       SpecialPage::getTitleFor( 'Movepage' ),
+                       $this->msg( 'revertmove' )->escaped(),
+                       array(),
+                       array(
+                               'wpOldTitle' => $destTitle->getPrefixedDBkey(),
+                               'wpNewTitle' => $this->entry->getTarget()->getPrefixedDBkey(),
+                               'wpReason'   => $this->msg( 'revertmove' )->inContentLanguage()->text(),
+                               'wpMovetalk' => 0
+                       )
+               );
+               return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+       }
 }
 
 /**
@@ -654,6 +817,107 @@ class DeleteLogFormatter extends LogFormatter {
                        return (int) $string;
                }
        }
+
+       public function getActionLinks() {
+               $user = $this->context->getUser();
+               if ( !$user->isAllowed( 'deletedhistory' ) || $this->entry->isDeleted( LogPage::DELETED_ACTION ) ) {
+                       return '';
+               }
+
+               switch ( $this->entry->getSubtype() ) {
+               case 'delete': // Show undelete link
+                       if( $user->isAllowed( 'undelete' ) ) {
+                               $message = 'undeletelink';
+                       } else {
+                               $message = 'undeleteviewlink';
+                       }
+                       $revert = Linker::linkKnown(
+                               SpecialPage::getTitleFor( 'Undelete' ),
+                               $this->msg( $message )->escaped(),
+                               array(),
+                               array( 'target' => $this->entry->getTarget()->getPrefixedDBkey() )
+                        );
+                       return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+
+               case 'revision': // If an edit was hidden from a page give a review link to the history
+                       $params = $this->extractParameters();
+                       if ( !isset( $params[3] ) || !isset( $params[4] ) ) {
+                               return '';
+                       }
+
+                       // Different revision types use different URL params...
+                       $key = $params[3];
+                       // This is a CSV of the IDs
+                       $ids = explode( ',', $params[4] );
+
+                       $links = array();
+
+                       // If there's only one item, we can show a diff link
+                       if ( count( $ids ) == 1 ) {
+                               // Live revision diffs...
+                               if ( $key == 'oldid' || $key == 'revision' ) {
+                                       $links[] = Linker::linkKnown(
+                                               $this->entry->getTarget(),
+                                               $this->msg( 'diff' )->escaped(),
+                                               array(),
+                                               array(
+                                                       'diff' => intval( $ids[0] ),
+                                                       'unhide' => 1
+                                               )
+                                       );
+                               // Deleted revision diffs...
+                               } elseif ( $key == 'artimestamp' || $key == 'archive' ) {
+                                       $links[] = Linker::linkKnown(
+                                               SpecialPage::getTitleFor( 'Undelete' ),
+                                               $this->msg( 'diff' )->escaped(),
+                                               array(),
+                                               array(
+                                                       'target'    => $this->entry->getTarget()->getPrefixedDBKey(),
+                                                       'diff'      => 'prev',
+                                                       'timestamp' => $ids[0]
+                                               )
+                                       );
+                               }
+                       }
+
+                       // View/modify link...
+                       $links[] = Linker::linkKnown(
+                               SpecialPage::getTitleFor( 'Revisiondelete' ),
+                               $this->msg( 'revdel-restore' )->escaped(),
+                               array(),
+                               array(
+                                       'target' => $this->entry->getTarget()->getPrefixedText(),
+                                       'type' => $key,
+                                       'ids' => implode( ',', $ids ),
+                               )
+                       );
+
+                       return $this->msg( 'parentheses' )->rawParams(
+                               $this->context->getLanguage()->pipeList( $links ) )->escaped();
+
+               case 'event': // Hidden log items, give review link
+                       $params = $this->extractParameters();
+                       if ( !isset( $params[3] ) ) {
+                               return '';
+                       }
+                       // This is a CSV of the IDs
+                       $query = $params[3];
+                       // Link to each hidden object ID, $params[1] is the url param
+                       $revert = Linker::linkKnown(
+                               SpecialPage::getTitleFor( 'Revisiondelete' ),
+                               $this->msg( 'revdel-restore' )->escaped(),
+                               array(),
+                               array(
+                                       'target' => $this->entry->getTarget()->getPrefixedText(),
+                                       'type' => 'logging',
+                                       'ids' => $query
+                               )
+                       );
+                       return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+               default:
+                       return '';
+               }
+       }
 }
 
 /**
index 95d372c..c59edc2 100644 (file)
@@ -124,69 +124,4 @@ class RevisionDeleter {
 
                return $timestamp;
        }
-
-       /**
-        * Creates utility links for log entries.
-        *
-        * @param $title Title
-        * @param $paramArray Array
-        * @param $messages
-        * @return String
-        */
-       public static function getLogLinks( $title, $paramArray, $messages ) {
-               global $wgLang;
-
-               if ( count( $paramArray ) >= 2 ) {
-                       // Different revision types use different URL params...
-                       $key = $paramArray[0];
-                       // $paramArray[1] is a CSV of the IDs
-                       $Ids = explode( ',', $paramArray[1] );
-
-                       $revert = array();
-
-                       // Diff link for single rev deletions
-                       if ( count( $Ids ) == 1 ) {
-                               // Live revision diffs...
-                               if ( in_array( $key, array( 'oldid', 'revision' ) ) ) {
-                                       $revert[] = Linker::linkKnown(
-                                               $title,
-                                               $messages['diff'],
-                                               array(),
-                                               array(
-                                                       'diff' => intval( $Ids[0] ),
-                                                       'unhide' => 1
-                                               )
-                                       );
-                               // Deleted revision diffs...
-                               } elseif ( in_array( $key, array( 'artimestamp','archive' ) ) ) {
-                                       $revert[] = Linker::linkKnown(
-                                               SpecialPage::getTitleFor( 'Undelete' ),
-                                               $messages['diff'],
-                                               array(),
-                                               array(
-                                                       'target'    => $title->getPrefixedDBKey(),
-                                                       'diff'      => 'prev',
-                                                       'timestamp' => $Ids[0]
-                                               )
-                                       );
-                               }
-                       }
-
-                       // View/modify link...
-                       $revert[] = Linker::linkKnown(
-                               SpecialPage::getTitleFor( 'Revisiondelete' ),
-                               $messages['revdel-restore'],
-                               array(),
-                               array(
-                                       'target' => $title->getPrefixedText(),
-                                       'type' => $key,
-                                       'ids' => implode(',', $Ids),
-                               )
-                       );
-
-                       // Pipe links
-                       return wfMsg( 'parentheses', $wgLang->pipeList( $revert ) );
-               }
-               return '';
-       }
 }