Add WikiPageFactory

Replace WikiPage::factory with a proper factory object with dependency
injection (only for dependencies needed by the factory methods,
not WikiPage itself).

Change-Id: Ie7d6e40d8387d8bc4f8592a31fdd70d0aad510ae
This commit is contained in:
Gergő Tisza 2020-07-27 15:24:05 +02:00
parent 9c6473dc1d
commit f871f7b93e
No known key found for this signature in database
GPG key ID: C34FEC97E6257F96
4 changed files with 167 additions and 45 deletions

View file

@ -50,6 +50,7 @@ use MediaWiki\Mail\IEmailer;
use MediaWiki\Page\ContentModelChangeFactory;
use MediaWiki\Page\MergeHistoryFactory;
use MediaWiki\Page\MovePageFactory;
use MediaWiki\Page\WikiPageFactory;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Preferences\PreferencesFactory;
use MediaWiki\Revision\ContributionsLookup;
@ -1361,6 +1362,14 @@ class MediaWikiServices extends ServiceContainer {
return $this->getService( 'WatchlistNotificationManager' );
}
/**
* @since 1.36
* @return WikiPageFactory
*/
public function getWikiPageFactory() : WikiPageFactory {
return $this->getService( 'WikiPageFactory' );
}
/**
* @since 1.31
* @return OldRevisionImporter

View file

@ -81,6 +81,7 @@ use MediaWiki\Page\ContentModelChangeFactory;
use MediaWiki\Page\MergeHistoryFactory;
use MediaWiki\Page\MovePageFactory;
use MediaWiki\Page\PageCommandFactory;
use MediaWiki\Page\WikiPageFactory;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Preferences\DefaultPreferencesFactory;
use MediaWiki\Preferences\PreferencesFactory;
@ -1363,6 +1364,14 @@ return [
);
},
'WikiPageFactory' => function ( MediaWikiServices $services ) : WikiPageFactory {
return new WikiPageFactory(
$services->getTitleFactory(),
new HookRunner( $services->getHookContainer() ),
$services->getDBLoadBalancer()
);
},
'WikiRevisionOldRevisionImporterNoUpdates' =>
function ( MediaWikiServices $services ) : ImportableOldRevisionImporter {
return new ImportableOldRevisionImporter(

View file

@ -151,33 +151,10 @@ class WikiPage implements Page, IDBAccessObject {
*
* @throws MWException
* @return WikiPage|WikiCategoryPage|WikiFilePage
* @deprecated since 1.36, use WikiPageFactory::newFromTitle instead
*/
public static function factory( Title $title ) {
$ns = $title->getNamespace();
if ( $ns == NS_MEDIA ) {
throw new MWException( "NS_MEDIA is a virtual namespace; use NS_FILE." );
} elseif ( $ns < 0 ) {
throw new MWException( "Invalid or virtual namespace $ns given." );
}
$page = null;
if ( !Hooks::runner()->onWikiPageFactory( $title, $page ) ) {
return $page;
}
switch ( $ns ) {
case NS_FILE:
$page = new WikiFilePage( $title );
break;
case NS_CATEGORY:
$page = new WikiCategoryPage( $title );
break;
default:
$page = new WikiPage( $title );
}
return $page;
return MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
}
/**
@ -189,24 +166,10 @@ class WikiPage implements Page, IDBAccessObject {
* - "fromdbmaster" or WikiPage::READ_LATEST to select from the master database
*
* @return WikiPage|null
* @deprecated since 1.36, use WikiPageFactory::newFromID instead
*/
public static function newFromID( $id, $from = 'fromdb' ) {
// page ids are never 0 or negative, see T63166
if ( $id < 1 ) {
return null;
}
$from = self::convertSelectType( $from );
$db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_REPLICA );
$pageQuery = self::getQueryInfo();
$row = $db->selectRow(
$pageQuery['tables'], $pageQuery['fields'], [ 'page_id' => $id ], __METHOD__,
[], $pageQuery['joins']
);
if ( !$row ) {
return null;
}
return self::newFromRow( $row, $from );
return MediaWikiServices::getInstance()->getWikiPageFactory()->newFromID( $id, $from );
}
/**
@ -219,11 +182,10 @@ class WikiPage implements Page, IDBAccessObject {
* - "fromdbmaster" or WikiPage::READ_LATEST: from the master DB
* - "forupdate" or WikiPage::READ_LOCKING: from the master DB using SELECT FOR UPDATE
* @return WikiPage
* @deprecated since 1.36, use WikiPageFactory::newFromRow instead
*/
public static function newFromRow( $row, $from = 'fromdb' ) {
$page = self::factory( Title::newFromRow( $row ) );
$page->loadFromRow( $row, $from );
return $page;
return MediaWikiServices::getInstance()->getWikiPageFactory()->newFromRow( $row, $from );
}
/**
@ -232,7 +194,7 @@ class WikiPage implements Page, IDBAccessObject {
* @param object|string|int $type
* @return mixed
*/
protected static function convertSelectType( $type ) {
public static function convertSelectType( $type ) {
switch ( $type ) {
case 'fromdb':
return self::READ_NORMAL;

View file

@ -0,0 +1,142 @@
<?php
namespace MediaWiki\Page;
use DBAccessObjectUtils;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Page\Hook\WikiPageFactoryHook;
use MWException;
use Title;
use TitleFactory;
use WikiCategoryPage;
use WikiFilePage;
use Wikimedia\Rdbms\ILoadBalancer;
use WikiPage;
/**
* @since 1.36
*/
class WikiPageFactory {
/** @var TitleFactory */
private $titleFactory;
/** @var WikiPageFactoryHook */
private $wikiPageFactoryHookRunner;
/** @var ILoadBalancer */
private $loadBalancer;
/**
* @param TitleFactory $titleFactory
* @param WikiPageFactoryHook $wikiPageFactoryHookRunner
* @param ILoadBalancer $loadBalancer
*/
public function __construct(
TitleFactory $titleFactory,
WikiPageFactoryHook $wikiPageFactoryHookRunner,
ILoadBalancer $loadBalancer
) {
$this->titleFactory = $titleFactory;
$this->wikiPageFactoryHookRunner = $wikiPageFactoryHookRunner;
$this->loadBalancer = $loadBalancer;
}
/**
* Create a WikiPage object from a title.
*
* @param Title $title
*
* @return WikiPage
* @throws MWException
*/
public function newFromTitle( Title $title ) {
$ns = $title->getNamespace();
if ( $ns == NS_MEDIA ) {
throw new MWException( "NS_MEDIA is a virtual namespace; use NS_FILE." );
} elseif ( $ns < 0 ) {
throw new MWException( "Invalid or virtual namespace $ns given." );
}
$page = null;
if ( !$this->wikiPageFactoryHookRunner->onWikiPageFactory( $title, $page ) ) {
return $page;
}
switch ( $ns ) {
case NS_FILE:
$page = new WikiFilePage( $title );
break;
case NS_CATEGORY:
$page = new WikiCategoryPage( $title );
break;
default:
$page = new WikiPage( $title );
}
return $page;
}
/**
* Create a WikiPage object from a link target.
*
* @param LinkTarget $title
*
* @throws MWException
* @return WikiPage
*/
public function newFromLinkTarget( LinkTarget $title ) {
return $this->newFromTitle( $this->titleFactory->newFromLinkTarget( $title ) );
}
/**
* Create a WikiPage object from a database row
*
* @param object $row Database row containing at least fields returned by getQueryInfo().
* @param string|int $from Source of $data:
* - "fromdb" or WikiPage::READ_NORMAL: from a replica DB
* - "fromdbmaster" or WikiPage::READ_LATEST: from the master DB
* - "forupdate" or WikiPage::READ_LOCKING: from the master DB using SELECT FOR UPDATE
*
* @return WikiPage
* @throws MWException
*/
public function newFromRow( $row, $from = 'fromdb' ) {
$page = $this->newFromTitle( $this->titleFactory->newFromRow( $row ) );
$page->loadFromRow( $row, $from );
return $page;
}
/**
* Create a WikiPage object from a page ID
*
* @param int $id Article ID to load
* @param string|int $from One of the following values:
* - "fromdb" or WikiPage::READ_NORMAL to select from a replica DB
* - "fromdbmaster" or WikiPage::READ_LATEST to select from the master database
*
* @return WikiPage|null Null when no page exists with that ID
* @throws MWException
*/
public function newFromID( $id, $from = 'fromdb' ) {
// page ids are never 0 or negative, see T63166
if ( $id < 1 ) {
return null;
}
$from = WikiPage::convertSelectType( $from );
[ $index ] = DBAccessObjectUtils::getDBOptions( $from );
$db = $this->loadBalancer->getMaintenanceConnectionRef( $index );
$pageQuery = WikiPage::getQueryInfo();
$row = $db->selectRow(
$pageQuery['tables'], $pageQuery['fields'], [ 'page_id' => $id ], __METHOD__,
[], $pageQuery['joins']
);
if ( !$row ) {
return null;
}
return $this->newFromRow( $row, $from );
}
}