Merge "Fix tabs inside/between statements/text"
[lhc/web/wiklou.git] / includes / Revision.php
index 0008b4e..984da69 100644 (file)
  */
 class Revision implements IDBAccessObject {
        protected $mId;
+
+       /**
+        * @var int|null
+        */
        protected $mPage;
        protected $mUserText;
        protected $mOrigUserText;
@@ -38,11 +42,23 @@ class Revision implements IDBAccessObject {
        protected $mComment;
        protected $mText;
        protected $mTextRow;
+
+       /**
+        * @var null|Title
+        */
        protected $mTitle;
        protected $mCurrent;
        protected $mContentModel;
        protected $mContentFormat;
+
+       /**
+        * @var Content
+        */
        protected $mContent;
+
+       /**
+        * @var null|ContentHandler
+        */
        protected $mContentHandler;
 
        // Revision deletion constants
@@ -87,7 +103,7 @@ class Revision implements IDBAccessObject {
         * @param $flags Integer Bitfield (optional)
         * @return Revision or null
         */
-       public static function newFromTitle( $title, $id = 0, $flags = null ) {
+       public static function newFromTitle( $title, $id = 0, $flags = 0 ) {
                $conds = array(
                        'page_namespace' => $title->getNamespace(),
                        'page_title'     => $title->getDBkey()
@@ -98,8 +114,6 @@ class Revision implements IDBAccessObject {
                } else {
                        // Use a join to get the latest revision
                        $conds[] = 'rev_id=page_latest';
-                       // Callers assume this will be up-to-date
-                       $flags = is_int( $flags ) ? $flags : self::READ_LATEST; // b/c
                }
                return self::newFromConds( $conds, (int)$flags );
        }
@@ -118,15 +132,13 @@ class Revision implements IDBAccessObject {
         * @param $flags Integer Bitfield (optional)
         * @return Revision or null
         */
-       public static function newFromPageId( $pageId, $revId = 0, $flags = null ) {
+       public static function newFromPageId( $pageId, $revId = 0, $flags = 0 ) {
                $conds = array( 'page_id' => $pageId );
                if ( $revId ) {
                        $conds['rev_id'] = $revId;
                } else {
                        // Use a join to get the latest revision
                        $conds[] = 'rev_id = page_latest';
-                       // Callers assume this will be up-to-date
-                       $flags = is_int( $flags ) ? $flags : self::READ_LATEST; // b/c
                }
                return self::newFromConds( $conds, (int)$flags );
        }
@@ -139,6 +151,7 @@ class Revision implements IDBAccessObject {
         * @param $row
         * @param $overrides array
         *
+        * @throws MWException
         * @return Revision
         */
        public static function newFromArchiveRow( $row, $overrides = array() ) {
@@ -156,7 +169,7 @@ class Revision implements IDBAccessObject {
                        'deleted'    => $row->ar_deleted,
                        'len'        => $row->ar_len,
                        'sha1'       => isset( $row->ar_sha1 ) ? $row->ar_sha1 : null,
-                       'content_model' => isset( $row->ar_content_model ) ? $row->ar_content_model : null,
+                       'content_model'   => isset( $row->ar_content_model ) ? $row->ar_content_model : null,
                        'content_format'  => isset( $row->ar_content_format ) ? $row->ar_content_format : null,
                );
 
@@ -333,7 +346,7 @@ class Revision implements IDBAccessObject {
                        self::selectUserFields()
                );
                $options = array( 'LIMIT' => 1 );
-               if ( $flags & self::READ_LOCKING ) {
+               if ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING ) {
                        $options[] = 'FOR UPDATE';
                }
                return $db->select(
@@ -459,6 +472,7 @@ class Revision implements IDBAccessObject {
         * Constructor
         *
         * @param $row Mixed: either a database row or an array
+        * @throws MWException
         * @access private
         */
        function __construct( $row ) {
@@ -558,8 +572,8 @@ class Revision implements IDBAccessObject {
                        $this->mParentId  = isset( $row['parent_id']  ) ? intval( $row['parent_id']  ) : null;
                        $this->mSha1      = isset( $row['sha1']  )      ? strval( $row['sha1']  )      : null;
 
-                       $this->mContentModel = isset( $row['content_model']  )  ? strval( $row['content_model'] )  : null;
-                       $this->mContentFormat    = isset( $row['content_format']  ) ? strval( $row['content_format'] ) : null;
+                       $this->mContentModel   = isset( $row['content_model']  )  ? strval( $row['content_model'] )  : null;
+                       $this->mContentFormat  = isset( $row['content_format']  ) ? strval( $row['content_format'] ) : null;
 
                        // Enforce spacing trimming on supplied text
                        $this->mComment   = isset( $row['comment']    ) ?  trim( strval( $row['comment'] ) ) : null;
@@ -570,6 +584,10 @@ class Revision implements IDBAccessObject {
 
                        // if we have a Content object, override mText and mContentModel
                        if ( !empty( $row['content'] ) ) {
+                               if ( !( $row['content'] instanceof Content ) ) {
+                                       throw new MWException( '`content` field must contain a Content object.' );
+                               }
+
                                $handler = $this->getContentHandler();
                                $this->mContent = $row['content'];
 
@@ -883,12 +901,12 @@ class Revision implements IDBAccessObject {
         * @param $user User object to check for, only if FOR_THIS_USER is passed
         *              to the $audience parameter
         *
-        * @deprecated in 1.WD, use getContent() instead
+        * @deprecated in 1.21, use getContent() instead
         * @todo: replace usage in core
         * @return String
         */
        public function getText( $audience = self::FOR_PUBLIC, User $user = null ) {
-               wfDeprecated( __METHOD__, '1.WD' );
+               ContentHandler::deprecated( __METHOD__, '1.21' );
 
                $content = $this->getContent( $audience, $user );
                return ContentHandler::getContentText( $content ); # returns the raw content text, if applicable
@@ -905,8 +923,8 @@ class Revision implements IDBAccessObject {
         *      Revision::RAW              get the text regardless of permissions
         * @param $user User object to check for, only if FOR_THIS_USER is passed
         *              to the $audience parameter
-        * @since 1.WD
-        * @return Content
+        * @since 1.21
+        * @return Content|null
         */
        public function getContent( $audience = self::FOR_PUBLIC, User $user = null ) {
                if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) {
@@ -934,19 +952,18 @@ class Revision implements IDBAccessObject {
         *
         * @return String
         *
-        * @deprecated since 1.WD. Instead, use Revision::getContent( Revision::RAW )
+        * @deprecated since 1.21. Instead, use Revision::getContent( Revision::RAW )
         *                         or Revision::getSerializedData() as appropriate.
         */
        public function getRawText() {
-               wfDeprecated( __METHOD__, "1.WD" );
-
+               ContentHandler::deprecated( __METHOD__, "1.21" );
                return $this->getText( self::RAW );
        }
 
        /**
         * Fetch original serialized data without regard for view restrictions
         *
-        * @since 1.WD
+        * @since 1.21
         * @return String
         */
        public function getSerializedData() {
@@ -956,7 +973,7 @@ class Revision implements IDBAccessObject {
        /**
         * Gets the content object for the revision
         *
-        * @since 1.WD
+        * @since 1.21
         * @return Content
         */
        protected function getContentInternal() {
@@ -965,7 +982,6 @@ class Revision implements IDBAccessObject {
 
                        $handler = $this->getContentHandler();
                        $format = $this->getContentFormat();
-                       $title = $this->getTitle();
 
                        if( is_null( $this->mText ) ) {
                                // Load text on demand:
@@ -1020,6 +1036,7 @@ class Revision implements IDBAccessObject {
        /**
         * Returns the content handler appropriate for this revision's content model.
         *
+        * @throws MWException
         * @return ContentHandler
         */
        public function getContentHandler() {
@@ -1216,6 +1233,7 @@ class Revision implements IDBAccessObject {
         * number on success and dies horribly on failure.
         *
         * @param $dbw DatabaseBase: (master connection)
+        * @throws MWException
         * @return Integer
         */
        public function insertOn( $dbw ) {
@@ -1286,7 +1304,13 @@ class Revision implements IDBAccessObject {
                        $model = $this->getContentModel();
                        $format = $this->getContentFormat();
 
-                       $defaultModel = ContentHandler::getDefaultModelFor( $this->getTitle() );
+                       $title = $this->getTitle();
+
+                       if ( $title === null ) {
+                               throw new MWException( "Insufficient information to determine the title of the revision's page!" );
+                       }
+
+                       $defaultModel = ContentHandler::getDefaultModelFor( $title );
                        $defaultFormat = ContentHandler::getForModelID( $defaultModel )->getDefaultFormat();
 
                        $row[ 'rev_content_model' ] = ( $model === $defaultModel ) ? null : $model;
@@ -1580,4 +1604,42 @@ class Revision implements IDBAccessObject {
                }
                return 0;
        }
+
+       /**
+        * Check if no edits were made by other users since
+        * the time a user started editing the page. Limit to
+        * 50 revisions for the sake of performance.
+        *
+        * @since 1.20
+        *
+        * @param DatabaseBase|int $db the Database to perform the check on. May be given as a Database object or
+        *        a database identifier usable with wfGetDB.
+        * @param int $pageId the ID of the page in question
+        * @param int $userId the ID of the user in question
+        * @param string $since look at edits since this time
+        *
+        * @return bool True if the given user was the only one to edit since the given timestamp
+        */
+       public static function userWasLastToEdit( $db, $pageId, $userId, $since ) {
+               if ( !$userId ) return false;
+
+               if ( is_int( $db ) ) {
+                       $db = wfGetDB( $db );
+               }
+
+               $res = $db->select( 'revision',
+                       'rev_user',
+                       array(
+                               'rev_page' => $pageId,
+                               'rev_timestamp > ' . $db->addQuotes( $db->timestamp( $since ) )
+                       ),
+                       __METHOD__,
+                       array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ) );
+               foreach ( $res as $row ) {
+                       if ( $row->rev_user != $userId ) {
+                               return false;
+                       }
+               }
+               return true;
+       }
 }