diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index ec2d37589f1..bca5d49240c 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -81,6 +81,7 @@ use MediaWiki\Permissions\GroupPermissionsLookup; use MediaWiki\Permissions\PermissionManager; use MediaWiki\Permissions\RestrictionStore; use MediaWiki\Preferences\PreferencesFactory; +use MediaWiki\Revision\ArchivedRevisionLookup; use MediaWiki\Revision\ContributionsLookup; use MediaWiki\Revision\RevisionFactory; use MediaWiki\Revision\RevisionLookup; @@ -609,6 +610,14 @@ class MediaWikiServices extends ServiceContainer { return $this->getService( 'ActorStoreFactory' ); } + /** + * @since 1.38 + * @return ArchivedRevisionLookup + */ + public function getArchivedRevisionLookup(): ArchivedRevisionLookup { + return $this->getService( 'ArchivedRevisionLookup' ); + } + /** * @since 1.35 * @return AuthManager diff --git a/includes/Revision/ArchivedRevisionLookup.php b/includes/Revision/ArchivedRevisionLookup.php index 9712564a090..d36176a215f 100644 --- a/includes/Revision/ArchivedRevisionLookup.php +++ b/includes/Revision/ArchivedRevisionLookup.php @@ -21,19 +21,15 @@ namespace MediaWiki\Revision; use ChangeTags; -use MediaWiki\MediaWikiServices; -use Title; +use MediaWiki\Page\PageIdentity; use Wikimedia\Rdbms\ILoadBalancer; use Wikimedia\Rdbms\IResultWrapper; /** - * @unstable Don't use this, it WILL change + * @since 1.38 */ class ArchivedRevisionLookup { - /** @var Title */ - protected $title; - /** @var ILoadBalancer */ private $loadBalancer; @@ -41,28 +37,30 @@ class ArchivedRevisionLookup { private $revisionStore; /** - * @param Title $title + * @param ILoadBalancer $loadBalancer + * @param RevisionStore $revisionStore */ - public function __construct( Title $title ) { - $this->title = $title; - - $services = MediaWikiServices::getInstance(); - $this->loadBalancer = $services->getDBLoadBalancer(); - $this->revisionStore = $services->getRevisionStore(); + public function __construct( + ILoadBalancer $loadBalancer, + RevisionStore $revisionStore + ) { + $this->loadBalancer = $loadBalancer; + $this->revisionStore = $revisionStore; } /** * List the revisions of the given page. Returns result wrapper with * various archive table fields. * + * @param PageIdentity $page * @return IResultWrapper|bool */ - public function listRevisions() { + public function listRevisions( PageIdentity $page ) { $queryInfo = $this->revisionStore->getArchiveQueryInfo(); $conds = [ - 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey(), + 'ar_namespace' => $page->getNamespace(), + 'ar_title' => $page->getDBkey(), ]; // NOTE: ordering by ar_timestamp and ar_id, to remove ambiguity. @@ -95,40 +93,47 @@ class ArchivedRevisionLookup { * * @internal only for use in SpecialUndelete * + * @param PageIdentity $page * @param string $timestamp * @return RevisionRecord|null */ - public function getRevisionRecordByTimestamp( $timestamp ) { + public function getRevisionRecordByTimestamp( PageIdentity $page, $timestamp ): ?RevisionRecord { $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA ); - $rec = $this->getRevisionByConditions( + return $this->getRevisionByConditions( + $page, [ 'ar_timestamp' => $dbr->timestamp( $timestamp ) ] ); - return $rec; } /** * Return the archived revision with the given ID. * + * @param PageIdentity $page * @param int $revId * @return RevisionRecord|null */ - public function getArchivedRevisionRecord( int $revId ) { - return $this->getRevisionByConditions( [ 'ar_rev_id' => $revId ] ); + public function getArchivedRevisionRecord( PageIdentity $page, int $revId ): ?RevisionRecord { + return $this->getRevisionByConditions( $page, [ 'ar_rev_id' => $revId ] ); } /** + * @param PageIdentity $page * @param array $conditions * @param array $options * * @return RevisionRecord|null */ - private function getRevisionByConditions( array $conditions, array $options = [] ) { + private function getRevisionByConditions( + PageIdentity $page, + array $conditions, + array $options = [] + ): ?RevisionRecord { $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA ); $arQuery = $this->revisionStore->getArchiveQueryInfo(); $conditions += [ - 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey(), + 'ar_namespace' => $page->getNamespace(), + 'ar_title' => $page->getDBkey(), ]; $row = $dbr->selectRow( @@ -141,7 +146,7 @@ class ArchivedRevisionLookup { ); if ( $row ) { - return $this->revisionStore->newRevisionFromArchiveRow( $row, 0, $this->title ); + return $this->revisionStore->newRevisionFromArchiveRow( $row, 0, $page ); } return null; @@ -154,17 +159,18 @@ class ArchivedRevisionLookup { * May produce unexpected results in case of history merges or other * unusual time issues. * + * @param PageIdentity $page * @param string $timestamp * @return RevisionRecord|null Null when there is no previous revision */ - public function getPreviousRevisionRecord( string $timestamp ) { + public function getPreviousRevisionRecord( PageIdentity $page, string $timestamp ): ?RevisionRecord { $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA ); // Check the previous deleted revision... $row = $dbr->selectRow( 'archive', [ 'ar_rev_id', 'ar_timestamp' ], - [ 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey(), + [ 'ar_namespace' => $page->getNamespace(), + 'ar_title' => $page->getDBkey(), 'ar_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ], __METHOD__, @@ -177,8 +183,8 @@ class ArchivedRevisionLookup { $row = $dbr->selectRow( [ 'page', 'revision' ], [ 'rev_id', 'rev_timestamp' ], [ - 'page_namespace' => $this->title->getNamespace(), - 'page_title' => $this->title->getDBkey(), + 'page_namespace' => $page->getNamespace(), + 'page_title' => $page->getDBkey(), 'page_id = rev_page', 'rev_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ], @@ -194,7 +200,7 @@ class ArchivedRevisionLookup { $rec = $this->revisionStore->getRevisionById( $prevLiveId ); } elseif ( $prevDeleted ) { // Most prior revision was deleted - $rec = $this->getArchivedRevisionRecord( $prevDeletedId ); + $rec = $this->getArchivedRevisionRecord( $page, $prevDeletedId ); } else { $rec = null; } @@ -205,15 +211,17 @@ class ArchivedRevisionLookup { /** * Returns the ID of the latest deleted revision. * + * @param PageIdentity $page + * * @return int|false The revision's ID, or false if there is no deleted revision. */ - public function getLastRevisionId() { + public function getLastRevisionId( PageIdentity $page ) { $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA ); $revId = $dbr->selectField( 'archive', 'ar_rev_id', - [ 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey() ], + [ 'ar_namespace' => $page->getNamespace(), + 'ar_title' => $page->getDBkey() ], __METHOD__, [ 'ORDER BY' => [ 'ar_timestamp DESC', 'ar_id DESC' ] ] ); @@ -225,15 +233,17 @@ class ArchivedRevisionLookup { * Quick check if any archived revisions are present for the page. * This says nothing about whether the page currently exists in the page table or not. * + * @param PageIdentity $page + * * @return bool */ - public function isDeleted() { + public function hasArchivedRevisions( PageIdentity $page ): bool { $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA ); $row = $dbr->selectRow( - [ 'archive' ], + 'archive', '1', // We don't care about the value. Allow the database to optimize. - [ 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey() ], + [ 'ar_namespace' => $page->getNamespace(), + 'ar_title' => $page->getDBkey() ], __METHOD__ ); diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index e8d72243155..023d708e642 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -115,6 +115,7 @@ use MediaWiki\Permissions\PermissionManager; use MediaWiki\Permissions\RestrictionStore; use MediaWiki\Preferences\DefaultPreferencesFactory; use MediaWiki\Preferences\PreferencesFactory; +use MediaWiki\Revision\ArchivedRevisionLookup; use MediaWiki\Revision\ContributionsLookup; use MediaWiki\Revision\MainSlotRoleHandler; use MediaWiki\Revision\RevisionFactory; @@ -200,6 +201,13 @@ return [ ); }, + 'ArchivedRevisionLookup' => static function ( MediaWikiServices $services ): ArchivedRevisionLookup { + return new ArchivedRevisionLookup( + $services->getDBLoadBalancer(), + $services->getRevisionStore() + ); + }, + 'AuthManager' => static function ( MediaWikiServices $services ): AuthManager { $authManager = new AuthManager( RequestContext::getMain()->getRequest(), diff --git a/includes/page/PageArchive.php b/includes/page/PageArchive.php index d96907a9baa..3ea4b99f592 100644 --- a/includes/page/PageArchive.php +++ b/includes/page/PageArchive.php @@ -20,7 +20,6 @@ use MediaWiki\MediaWikiServices; use MediaWiki\Page\UndeletePage; -use MediaWiki\Revision\ArchivedRevisionLookup; use MediaWiki\Revision\RevisionRecord; use MediaWiki\User\UserIdentity; use Wikimedia\Rdbms\IDatabase; @@ -164,8 +163,8 @@ class PageArchive { * @return IResultWrapper|bool */ public function listRevisions() { - $lookup = new ArchivedRevisionLookup( $this->title ); - return $lookup->listRevisions(); + $lookup = MediaWikiServices::getInstance()->getArchivedRevisionLookup(); + return $lookup->listRevisions( $this->title ); } /** @@ -202,8 +201,8 @@ class PageArchive { * @return RevisionRecord|null */ public function getRevisionRecordByTimestamp( $timestamp ) { - $lookup = new ArchivedRevisionLookup( $this->title ); - return $lookup->getRevisionRecordByTimestamp( $timestamp ); + $lookup = MediaWikiServices::getInstance()->getArchivedRevisionLookup(); + return $lookup->getRevisionRecordByTimestamp( $this->title, $timestamp ); } /** @@ -215,8 +214,8 @@ class PageArchive { * @return RevisionRecord|null */ public function getArchivedRevisionRecord( int $revId ) { - $lookup = new ArchivedRevisionLookup( $this->title ); - return $lookup->getArchivedRevisionRecord( $revId ); + $lookup = MediaWikiServices::getInstance()->getArchivedRevisionLookup(); + return $lookup->getArchivedRevisionRecord( $this->title, $revId ); } /** @@ -232,8 +231,8 @@ class PageArchive { * @return RevisionRecord|null Null when there is no previous revision */ public function getPreviousRevisionRecord( string $timestamp ) { - $lookup = new ArchivedRevisionLookup( $this->title ); - return $lookup->getPreviousRevisionRecord( $timestamp ); + $lookup = MediaWikiServices::getInstance()->getArchivedRevisionLookup(); + return $lookup->getPreviousRevisionRecord( $this->title, $timestamp ); } /** @@ -242,8 +241,8 @@ class PageArchive { * @return int|false The revision's ID, or false if there is no deleted revision. */ public function getLastRevisionId() { - $lookup = new ArchivedRevisionLookup( $this->title ); - return $lookup->getLastRevisionId(); + $lookup = MediaWikiServices::getInstance()->getArchivedRevisionLookup(); + return $lookup->getLastRevisionId( $this->title ); } /** @@ -253,8 +252,8 @@ class PageArchive { * @return bool */ public function isDeleted() { - $lookup = new ArchivedRevisionLookup( $this->title ); - return $lookup->isDeleted(); + $lookup = MediaWikiServices::getInstance()->getArchivedRevisionLookup(); + return $lookup->hasArchivedRevisions( $this->title ); } /**