* @file
*/
-use MediaWiki\Storage\MutableRevisionRecord;
-use MediaWiki\Storage\RevisionAccessException;
-use MediaWiki\Storage\RevisionFactory;
-use MediaWiki\Storage\RevisionLookup;
-use MediaWiki\Storage\RevisionRecord;
-use MediaWiki\Storage\RevisionStore;
-use MediaWiki\Storage\RevisionStoreRecord;
-use MediaWiki\Storage\SlotRecord;
+use MediaWiki\Revision\MutableRevisionRecord;
+use MediaWiki\Revision\RevisionAccessException;
+use MediaWiki\Revision\RevisionFactory;
+use MediaWiki\Revision\RevisionLookup;
+use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\Revision\RevisionStore;
+use MediaWiki\Revision\RevisionStoreRecord;
+use MediaWiki\Revision\SlotRecord;
use MediaWiki\Storage\SqlBlobStore;
+use Wikimedia\Assert\Assert;
use Wikimedia\Rdbms\IDatabase;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\ResultWrapper;
-use Wikimedia\Rdbms\FakeResultWrapper;
/**
* @deprecated since 1.31, use RevisionRecord, RevisionStore, and BlobStore instead.
/**
* @return RevisionStore
*/
- protected static function getRevisionStore() {
- return MediaWikiServices::getInstance()->getRevisionStore();
+ protected static function getRevisionStore( $wiki = false ) {
+ if ( $wiki ) {
+ return MediaWikiServices::getInstance()->getRevisionStoreFactory()
+ ->getRevisionStore( $wiki );
+ } else {
+ return MediaWikiServices::getInstance()->getRevisionStore();
+ }
}
/**
*/
public static function newFromId( $id, $flags = 0 ) {
$rec = self::getRevisionLookup()->getRevisionById( $id, $flags );
- return $rec === null ? null : new Revision( $rec, $flags );
+ return $rec ? new Revision( $rec, $flags ) : null;
}
/**
*/
public static function newFromTitle( LinkTarget $linkTarget, $id = 0, $flags = 0 ) {
$rec = self::getRevisionLookup()->getRevisionByTitle( $linkTarget, $id, $flags );
- return $rec === null ? null : new Revision( $rec, $flags );
+ return $rec ? new Revision( $rec, $flags ) : null;
}
/**
*/
public static function newFromPageId( $pageId, $revId = 0, $flags = 0 ) {
$rec = self::getRevisionLookup()->getRevisionByPageId( $pageId, $revId, $flags );
- return $rec === null ? null : new Revision( $rec, $flags );
+ return $rec ? new Revision( $rec, $flags ) : null;
}
/**
public static function loadFromId( $db, $id ) {
wfDeprecated( __METHOD__, '1.31' ); // no known callers
$rec = self::getRevisionStore()->loadRevisionFromId( $db, $id );
- return $rec === null ? null : new Revision( $rec );
+ return $rec ? new Revision( $rec ) : null;
}
/**
*/
public static function loadFromPageId( $db, $pageid, $id = 0 ) {
$rec = self::getRevisionStore()->loadRevisionFromPageId( $db, $pageid, $id );
- return $rec === null ? null : new Revision( $rec );
+ return $rec ? new Revision( $rec ) : null;
}
/**
*/
public static function loadFromTitle( $db, $title, $id = 0 ) {
$rec = self::getRevisionStore()->loadRevisionFromTitle( $db, $title, $id );
- return $rec === null ? null : new Revision( $rec );
+ return $rec ? new Revision( $rec ) : null;
}
/**
*/
public static function loadFromTimestamp( $db, $title, $timestamp ) {
$rec = self::getRevisionStore()->loadRevisionFromTimestamp( $db, $title, $timestamp );
- return $rec === null ? null : new Revision( $rec );
- }
-
- /**
- * Return a wrapper for a series of database rows to
- * fetch all of a given page's revisions in turn.
- * Each row can be fed to the constructor to get objects.
- *
- * @param LinkTarget $title
- * @return ResultWrapper
- * @deprecated Since 1.28, no callers in core nor in known extensions. No-op since 1.31.
- */
- public static function fetchRevision( LinkTarget $title ) {
- wfDeprecated( __METHOD__, '1.31' );
- return new FakeResultWrapper( [] );
+ return $rec ? new Revision( $rec ) : null;
}
/**
global $wgActorTableSchemaMigrationStage;
wfDeprecated( __METHOD__, '1.31' );
- if ( $wgActorTableSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+ if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
// If code is using this instead of self::getQueryInfo(), there's
// no way the join it's trying to do can work once the old fields
- // aren't being written anymore.
+ // aren't being used anymore.
throw new BadMethodCallException(
- 'Cannot use ' . __METHOD__ . ' when $wgActorTableSchemaMigrationStage > MIGRATION_WRITE_BOTH'
+ 'Cannot use ' . __METHOD__
+ . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
);
}
global $wgContentHandlerUseDB, $wgActorTableSchemaMigrationStage;
global $wgMultiContentRevisionSchemaMigrationStage;
- if ( $wgActorTableSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+ if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
// If code is using this instead of self::getQueryInfo(), there's a
// decent chance it's going to try to directly access
// $row->rev_user or $row->rev_user_text and we can't give it
- // useful values here once those aren't being written anymore.
+ // useful values here once those aren't being used anymore.
throw new BadMethodCallException(
- 'Cannot use ' . __METHOD__ . ' when $wgActorTableSchemaMigrationStage > MIGRATION_WRITE_BOTH'
+ 'Cannot use ' . __METHOD__
+ . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
);
}
global $wgContentHandlerUseDB, $wgActorTableSchemaMigrationStage;
global $wgMultiContentRevisionSchemaMigrationStage;
- if ( $wgActorTableSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+ if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
// If code is using this instead of self::getQueryInfo(), there's a
// decent chance it's going to try to directly access
// $row->ar_user or $row->ar_user_text and we can't give it
- // useful values here once those aren't being written anymore.
+ // useful values here once those aren't being used anymore.
throw new BadMethodCallException(
- 'Cannot use ' . __METHOD__ . ' when $wgActorTableSchemaMigrationStage > MIGRATION_WRITE_BOTH'
+ 'Cannot use ' . __METHOD__
+ . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
);
}
* @param int $queryFlags
* @param Title|null $title
*
- * @access private
+ * @private
*/
function __construct( $row, $queryFlags = 0, Title $title = null ) {
global $wgUser;
'$row must be a row object, an associative array, or a RevisionRecord'
);
}
+
+ Assert::postcondition( $this->mRecord !== null, 'Failed to construct a RevisionRecord' );
}
/**
* @return SlotRecord
*/
private function getMainSlotRaw() {
- return $this->mRecord->getSlot( 'main', RevisionRecord::RAW );
+ return $this->mRecord->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
}
/**
$user = $this->mRecord->getUser( $audience, $user );
return $user ? $user->getName() : '';
}
+
/**
- * Fetch revision comment if it's available to the specified audience.
- * If the specified audience does not have access to the comment, an
- * empty string will be returned.
- *
* @param int $audience One of:
* Revision::FOR_PUBLIC to be displayed to all users
* Revision::FOR_THIS_USER to be displayed to the given user
* Revision::RAW get the text regardless of permissions
* @param User|null $user User object to check for, only if FOR_THIS_USER is passed
* to the $audience parameter
- * @return string
+ *
+ * @return string|null Returns null if the specified audience does not have access to the
+ * comment.
*/
function getComment( $audience = self::FOR_PUBLIC, User $user = null ) {
global $wgUser;
}
try {
- return $this->mRecord->getContent( 'main', $audience, $user );
+ return $this->mRecord->getContent( SlotRecord::MAIN, $audience, $user );
}
catch ( RevisionAccessException $e ) {
return null;
public function getPrevious() {
$title = $this->getTitle();
$rec = self::getRevisionLookup()->getPreviousRevision( $this->mRecord, $title );
- return $rec === null ? null : new Revision( $rec, self::READ_NORMAL, $title );
+ return $rec ? new Revision( $rec, self::READ_NORMAL, $title ) : null;
}
/**
public function getNext() {
$title = $this->getTitle();
$rec = self::getRevisionLookup()->getNextRevision( $this->mRecord, $title );
- return $rec === null ? null : new Revision( $rec, self::READ_NORMAL, $title );
+ return $rec ? new Revision( $rec, self::READ_NORMAL, $title ) : null;
}
/**
* Get revision text associated with an old or archive row
*
- * Both the flags and the text field must be included. Including the old_id
+ * If the text field is not included, this uses RevisionStore to load the appropriate slot
+ * and return its serialized content. This is the default backwards-compatibility behavior
+ * when reading from the MCR aware database schema is enabled. For this to work, either
+ * the revision ID or the page ID must be included in the row.
+ *
+ * When using the old text field, the flags field must also be set. Including the old_id
* field will activate cache usage as long as the $wiki parameter is not set.
*
- * @param stdClass $row The text data
+ * @deprecated since 1.32, use RevisionStore::newRevisionFromRow instead.
+ *
+ * @param stdClass $row The text data. If a falsy value is passed instead, false is returned.
* @param string $prefix Table prefix (default 'old_')
* @param string|bool $wiki The name of the wiki to load the revision text from
* (same as the wiki $row was loaded from) or false to indicate the local
* @return string|false Text the text requested or false on failure
*/
public static function getRevisionText( $row, $prefix = 'old_', $wiki = false ) {
+ global $wgMultiContentRevisionSchemaMigrationStage;
+
+ if ( !$row ) {
+ return false;
+ }
+
$textField = $prefix . 'text';
$flagsField = $prefix . 'flags';
- if ( isset( $row->$flagsField ) ) {
- $flags = explode( ',', $row->$flagsField );
+ if ( isset( $row->$textField ) ) {
+ if ( !( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
+ // The text field was read, but it's no longer being populated!
+ // We could gloss over this by using the text when it's there and loading
+ // if when it's not, but it seems preferable to complain loudly about a
+ // query that is no longer guaranteed to work reliably.
+ throw new LogicException(
+ 'Cannot use ' . __METHOD__ . ' with the ' . $textField . ' field when'
+ . ' $wgMultiContentRevisionSchemaMigrationStage does not include'
+ . ' SCHEMA_COMPAT_WRITE_OLD. The field may not be populated for all revisions!'
+ );
+ }
+
+ $text = $row->$textField;
} else {
- $flags = [];
+ // Missing text field, we are probably looking at the MCR-enabled DB schema.
+
+ if ( !( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
+ // This method should no longer be used with the new schema. Ideally, we
+ // would already trigger a deprecation warning when SCHEMA_COMPAT_READ_NEW is set.
+ wfDeprecated( __METHOD__ . ' (MCR without SCHEMA_COMPAT_WRITE_OLD)', '1.32' );
+ }
+
+ $store = self::getRevisionStore( $wiki );
+ $rev = $prefix === 'ar_'
+ ? $store->newRevisionFromArchiveRow( $row )
+ : $store->newRevisionFromRow( $row );
+
+ $content = $rev->getContent( SlotRecord::MAIN );
+ return $content ? $content->serialize() : false;
}
- if ( isset( $row->$textField ) ) {
- $text = $row->$textField;
+ if ( isset( $row->$flagsField ) ) {
+ $flags = explode( ',', $row->$flagsField );
} else {
- return false;
+ $flags = [];
}
$cacheKey = isset( $row->old_id )
$rec = self::getRevisionStore()->insertRevisionOn( $this->mRecord, $dbw );
$this->mRecord = $rec;
-
- // Avoid PHP 7.1 warning of passing $this by reference
- $revision = $this;
+ Assert::postcondition( $this->mRecord !== null, 'Failed to acquire a RevisionRecord' );
return $rec->getId();
}
$rec = self::getRevisionStore()->newNullRevision( $dbw, $title, $comment, $minor, $user );
- return new Revision( $rec );
+ return $rec ? new Revision( $rec ) : null;
}
/**