use Message;
use MWException;
use MWUnknownContentModelException;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
use RecentChange;
use stdClass;
use Title;
* @note This was written to act as a drop-in replacement for the corresponding
* static methods in Revision.
*/
-class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup {
+class RevisionStore
+ implements IDBAccessObject, RevisionFactory, RevisionLookup, LoggerAwareInterface {
/**
* @var SqlBlobStore
*/
private $cache;
+ /**
+ * @var LoggerInterface
+ */
+ private $logger;
+
/**
* @todo $blobStore should be allowed to be any BlobStore!
*
$this->blobStore = $blobStore;
$this->cache = $cache;
$this->wikiId = $wikiId;
+ $this->logger = new NullLogger();
+ }
+
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
}
/**
* @return Title
* @throws RevisionAccessException
*/
- public function getTitle( $pageId, $revId, $queryFlags = 0 ) {
+ public function getTitle( $pageId, $revId, $queryFlags = self::READ_NORMAL ) {
if ( !$pageId && !$revId ) {
throw new InvalidArgumentException( '$pageId and $revId cannot both be 0 or null' );
}
- list( $dbMode, $dbOptions, , ) = DBAccessObjectUtils::getDBOptions( $queryFlags );
- $titleFlags = $dbMode == DB_MASTER ? Title::GAID_FOR_UPDATE : 0;
- $title = null;
+ // This method recalls itself with READ_LATEST if READ_NORMAL doesn't get us a Title
+ // So ignore READ_LATEST_IMMUTABLE flags and handle the fallback logic in this method
+ if ( DBAccessObjectUtils::hasFlags( $queryFlags, self::READ_LATEST_IMMUTABLE ) ) {
+ $queryFlags = self::READ_NORMAL;
+ }
+
+ $canUseTitleNewFromId = ( $pageId !== null && $pageId > 0 && $this->wikiId === false );
+ list( $dbMode, $dbOptions ) = DBAccessObjectUtils::getDBOptions( $queryFlags );
+ $titleFlags = ( $dbMode == DB_MASTER ? Title::GAID_FOR_UPDATE : 0 );
// Loading by ID is best, but Title::newFromID does not support that for foreign IDs.
- if ( $pageId !== null && $pageId > 0 && $this->wikiId === false ) {
+ if ( $canUseTitleNewFromId ) {
// TODO: better foreign title handling (introduce TitleFactory)
$title = Title::newFromID( $pageId, $titleFlags );
+ if ( $title ) {
+ return $title;
+ }
}
// rev_id is defined as NOT NULL, but this revision may not yet have been inserted.
- if ( !$title && $revId !== null && $revId > 0 ) {
+ $canUseRevId = ( $revId !== null && $revId > 0 );
+
+ if ( $canUseRevId ) {
$dbr = $this->getDBConnectionRef( $dbMode );
// @todo: Title::getSelectFields(), or Title::getQueryInfo(), or something like that
$row = $dbr->selectRow(
);
if ( $row ) {
// TODO: better foreign title handling (introduce TitleFactory)
- $title = Title::newFromRow( $row );
+ return Title::newFromRow( $row );
}
}
- if ( !$title ) {
- throw new RevisionAccessException(
- "Could not determine title for page ID $pageId and revision ID $revId"
- );
+ // If we still don't have a title, fallback to master if that wasn't already happening.
+ if ( $dbMode !== DB_MASTER ) {
+ $title = $this->getTitle( $pageId, $revId, self::READ_LATEST );
+ if ( $title ) {
+ $this->logger->info(
+ __METHOD__ . ' fell back to READ_LATEST and got a Title.',
+ [ 'trace' => wfDebugBacktrace() ]
+ );
+ return $title;
+ }
}
- return $title;
+ throw new RevisionAccessException(
+ "Could not determine title for page ID $pageId and revision ID $revId"
+ );
}
/**
}
list( $commentFields, $commentCallback ) =
- CommentStore::newKey( 'rev_comment' )->insertWithTempTable( $dbw, $comment );
+ CommentStore::getStore()->insertWithTempTable( $dbw, 'rev_comment', $comment );
$row += $commentFields;
if ( $this->contentHandlerUseDB ) {
$user = $this->getUserIdentityFromRowObject( $row, 'ar_' );
- $comment = CommentStore::newKey( 'ar_comment' )
+ $comment = CommentStore::getStore()
// Legacy because $row may have come from self::selectFields()
- ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), $row, true );
+ ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), 'ar_comment', $row, true );
$mainSlot = $this->emulateMainSlot_1_29( $row, $queryFlags, $title );
$slots = new RevisionSlots( [ 'main' => $mainSlot ] );
$user = $this->getUserIdentityFromRowObject( $row );
- $comment = CommentStore::newKey( 'rev_comment' )
+ $comment = CommentStore::getStore()
// Legacy because $row may have come from self::selectFields()
- ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), $row, true );
+ ->getCommentLegacy( $this->getDBConnection( DB_REPLICA ), 'rev_comment', $row, true );
$mainSlot = $this->emulateMainSlot_1_29( $row, $queryFlags, $title );
$slots = new RevisionSlots( [ 'main' => $mainSlot ] );
* @throws MWException
*/
private function checkDatabaseWikiId( IDatabase $db ) {
- $storeWiki = $this->loadBalancer->getLocalDomainID();
+ $storeWiki = $this->wikiId;
$dbWiki = $db->getDomainID();
if ( $dbWiki === $storeWiki ) {
return;
}
+ // XXX: we really want the default database ID...
+ $storeWiki = $storeWiki ?: wfWikiID();
+ $dbWiki = $dbWiki ?: wfWikiID();
+
+ if ( $dbWiki === $storeWiki ) {
+ return;
+ }
+
+ // HACK: counteract encoding imposed by DatabaseDomain
+ $storeWiki = str_replace( '?h', '-', $storeWiki );
+ $dbWiki = str_replace( '?h', '-', $dbWiki );
+
+ if ( $dbWiki === $storeWiki ) {
+ return;
+ }
+
throw new MWException( "RevisionStore for $storeWiki "
. "cannot be used with a DB connection for $dbWiki" );
}
'rev_sha1',
] );
- $commentQuery = CommentStore::newKey( 'rev_comment' )->getJoin();
+ $commentQuery = CommentStore::getStore()->getJoin( 'rev_comment' );
$ret['tables'] = array_merge( $ret['tables'], $commentQuery['tables'] );
$ret['fields'] = array_merge( $ret['fields'], $commentQuery['fields'] );
$ret['joins'] = array_merge( $ret['joins'], $commentQuery['joins'] );
* - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
*/
public function getArchiveQueryInfo() {
- $commentQuery = CommentStore::newKey( 'ar_comment' )->getJoin();
+ $commentQuery = CommentStore::getStore()->getJoin( 'ar_comment' );
$ret = [
'tables' => [ 'archive' ] + $commentQuery['tables'],
'fields' => [