Introduce includes/Storage/PageUpdaterFactory
Change-Id: I2a060bfa8ac098edf24fc4d51212eeb7ddf3942d
This commit is contained in:
parent
7466a4c958
commit
1829057944
9 changed files with 522 additions and 98 deletions
|
|
@ -83,6 +83,7 @@ use MediaWiki\Storage\BlobStoreFactory;
|
|||
use MediaWiki\Storage\NameTableStore;
|
||||
use MediaWiki\Storage\NameTableStoreFactory;
|
||||
use MediaWiki\Storage\PageEditStash;
|
||||
use MediaWiki\Storage\PageUpdaterFactory;
|
||||
use MediaWiki\Storage\RevertedTagUpdateManager;
|
||||
use MediaWiki\Tidy\TidyDriverBase;
|
||||
use MediaWiki\User\ActorNormalization;
|
||||
|
|
@ -1224,6 +1225,14 @@ class MediaWikiServices extends ServiceContainer {
|
|||
return $this->getService( 'PageStoreFactory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.37
|
||||
* @return PageUpdaterFactory
|
||||
*/
|
||||
public function getPageUpdaterFactory() : PageUpdaterFactory {
|
||||
return $this->getService( 'PageUpdaterFactory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.29
|
||||
* @return Parser
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ use MediaWiki\Storage\EditResultCache;
|
|||
use MediaWiki\Storage\NameTableStore;
|
||||
use MediaWiki\Storage\NameTableStoreFactory;
|
||||
use MediaWiki\Storage\PageEditStash;
|
||||
use MediaWiki\Storage\PageUpdaterFactory;
|
||||
use MediaWiki\Storage\RevertedTagUpdateManager;
|
||||
use MediaWiki\Storage\SqlBlobStore;
|
||||
use MediaWiki\Tidy\RemexDriver;
|
||||
|
|
@ -1032,6 +1033,42 @@ return [
|
|||
);
|
||||
},
|
||||
|
||||
'PageUpdaterFactory' => static function (
|
||||
MediaWikiServices $services
|
||||
): PageUpdaterFactory {
|
||||
$editResultCache = new EditResultCache(
|
||||
$services->getMainObjectStash(),
|
||||
$services->getDBLoadBalancer(),
|
||||
new ServiceOptions(
|
||||
EditResultCache::CONSTRUCTOR_OPTIONS,
|
||||
$services->getMainConfig()
|
||||
)
|
||||
);
|
||||
|
||||
return new PageUpdaterFactory(
|
||||
$services->getRevisionStore(),
|
||||
$services->getRevisionRenderer(),
|
||||
$services->getSlotRoleRegistry(),
|
||||
$services->getParserCache(),
|
||||
$services->getJobQueueGroup(),
|
||||
$services->getMessageCache(),
|
||||
$services->getContentLanguage(),
|
||||
$services->getDBLoadBalancerFactory(),
|
||||
$services->getContentHandlerFactory(),
|
||||
$services->getHookContainer(),
|
||||
$editResultCache,
|
||||
$services->getUserNameUtils(),
|
||||
LoggerFactory::getInstance( 'SavePage' ),
|
||||
new ServiceOptions(
|
||||
PageUpdaterFactory::CONSTRUCTOR_OPTIONS,
|
||||
$services->getMainConfig()
|
||||
),
|
||||
$services->getUserEditTracker(),
|
||||
$services->getUserGroupManager(),
|
||||
ChangeTags::getSoftwareTags()
|
||||
);
|
||||
},
|
||||
|
||||
'Parser' => static function ( MediaWikiServices $services ) : Parser {
|
||||
return $services->getParserFactory()->create();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ use MediaWiki\Content\IContentHandlerFactory;
|
|||
use MediaWiki\HookContainer\HookContainer;
|
||||
use MediaWiki\HookContainer\HookRunner;
|
||||
use MediaWiki\Linker\LinkTarget;
|
||||
use MediaWiki\Permissions\Authority;
|
||||
use MediaWiki\Revision\MutableRevisionRecord;
|
||||
use MediaWiki\Revision\RevisionAccessException;
|
||||
use MediaWiki\Revision\RevisionRecord;
|
||||
|
|
@ -80,7 +79,7 @@ class PageUpdater {
|
|||
|
||||
/**
|
||||
* Options that have to be present in the ServiceOptions object passed to the constructor.
|
||||
*
|
||||
* @note When adding options here, also add them to PageUpdaterFactory::CONSTRUCTOR_OPTIONS.
|
||||
* @internal
|
||||
*/
|
||||
public const CONSTRUCTOR_OPTIONS = [
|
||||
|
|
@ -89,9 +88,9 @@ class PageUpdater {
|
|||
];
|
||||
|
||||
/**
|
||||
* @var Authority
|
||||
* @var UserIdentity
|
||||
*/
|
||||
private $performer;
|
||||
private $author;
|
||||
|
||||
/**
|
||||
* @var WikiPage
|
||||
|
|
@ -196,7 +195,7 @@ class PageUpdater {
|
|||
private $serviceOptions;
|
||||
|
||||
/**
|
||||
* @param Authority $performer
|
||||
* @param UserIdentity $author
|
||||
* @param WikiPage $wikiPage
|
||||
* @param DerivedPageDataUpdater $derivedDataUpdater
|
||||
* @param ILoadBalancer $loadBalancer
|
||||
|
|
@ -211,7 +210,7 @@ class PageUpdater {
|
|||
* obtained from ChangeTags::getSoftwareTags()
|
||||
*/
|
||||
public function __construct(
|
||||
Authority $performer,
|
||||
UserIdentity $author,
|
||||
WikiPage $wikiPage,
|
||||
DerivedPageDataUpdater $derivedDataUpdater,
|
||||
ILoadBalancer $loadBalancer,
|
||||
|
|
@ -227,7 +226,7 @@ class PageUpdater {
|
|||
$serviceOptions->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||
$this->serviceOptions = $serviceOptions;
|
||||
|
||||
$this->performer = $performer;
|
||||
$this->author = $author;
|
||||
$this->wikiPage = $wikiPage;
|
||||
$this->derivedDataUpdater = $derivedDataUpdater;
|
||||
|
||||
|
|
@ -775,11 +774,9 @@ class PageUpdater {
|
|||
$useStashed = $this->ajaxEditStash;
|
||||
}
|
||||
|
||||
$user = $this->performer->getUser();
|
||||
|
||||
// Prepare the update. This performs PST and generates the canonical ParserOutput.
|
||||
$this->derivedDataUpdater->prepareContent(
|
||||
$user,
|
||||
$this->author,
|
||||
$this->slotsUpdate,
|
||||
$useStashed
|
||||
);
|
||||
|
|
@ -788,7 +785,7 @@ class PageUpdater {
|
|||
$renderedRevision = $this->derivedDataUpdater->getRenderedRevision();
|
||||
$hookStatus = Status::newGood( [] );
|
||||
$allowedByHook = $this->hookRunner->onMultiContentSave(
|
||||
$renderedRevision, $user, $summary, $flags, $hookStatus
|
||||
$renderedRevision, $this->author, $summary, $flags, $hookStatus
|
||||
);
|
||||
if ( $allowedByHook && $this->hookContainer->isRegistered( 'PageContentSave' ) ) {
|
||||
// Also run the legacy hook.
|
||||
|
|
@ -796,7 +793,7 @@ class PageUpdater {
|
|||
// and only if something uses the legacy hook.
|
||||
$mainContent = $this->derivedDataUpdater->getSlots()->getContent( SlotRecord::MAIN );
|
||||
|
||||
$legacyUser = self::toLegacyUser( $user );
|
||||
$legacyUser = self::toLegacyUser( $this->author );
|
||||
|
||||
// Deprecated since 1.35.
|
||||
$allowedByHook = $this->hookRunner->onPageContentSave(
|
||||
|
|
@ -826,16 +823,16 @@ class PageUpdater {
|
|||
// Actually create the revision and create/update the page.
|
||||
// Do NOT yet set $this->status!
|
||||
if ( $flags & EDIT_UPDATE ) {
|
||||
$status = $this->doModify( $summary, $user, $flags );
|
||||
$status = $this->doModify( $summary, $this->author, $flags );
|
||||
} else {
|
||||
$status = $this->doCreate( $summary, $user, $flags );
|
||||
$status = $this->doCreate( $summary, $this->author, $flags );
|
||||
}
|
||||
|
||||
// Promote user to any groups they meet the criteria for
|
||||
DeferredUpdates::addCallableUpdate( function () use ( $user ) {
|
||||
$this->userGroupManager->addUserToAutopromoteOnceGroups( $user, 'onEdit' );
|
||||
DeferredUpdates::addCallableUpdate( function () {
|
||||
$this->userGroupManager->addUserToAutopromoteOnceGroups( $this->author, 'onEdit' );
|
||||
// Also run 'onView' for backwards compatibility
|
||||
$this->userGroupManager->addUserToAutopromoteOnceGroups( $user, 'onView' );
|
||||
$this->userGroupManager->addUserToAutopromoteOnceGroups( $this->author, 'onView' );
|
||||
} );
|
||||
|
||||
// NOTE: set $this->status only after all hooks have been called,
|
||||
|
|
@ -920,7 +917,7 @@ class PageUpdater {
|
|||
|
||||
// do we need PST?
|
||||
|
||||
$this->status = $this->doUpdate( $this->performer->getUser(), $revision );
|
||||
$this->status = $this->doUpdate( $this->author, $revision );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
314
includes/Storage/PageUpdaterFactory.php
Normal file
314
includes/Storage/PageUpdaterFactory.php
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
<?php
|
||||
/**
|
||||
* A factory for DerivedPageDataUpdater instances.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* @file
|
||||
*/
|
||||
|
||||
namespace MediaWiki\Storage;
|
||||
|
||||
use JobQueueGroup;
|
||||
use Language;
|
||||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\Content\IContentHandlerFactory;
|
||||
use MediaWiki\HookContainer\HookContainer;
|
||||
use MediaWiki\Revision\RevisionRenderer;
|
||||
use MediaWiki\Revision\RevisionStore;
|
||||
use MediaWiki\Revision\SlotRoleRegistry;
|
||||
use MediaWiki\User\UserEditTracker;
|
||||
use MediaWiki\User\UserGroupManager;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
use MediaWiki\User\UserNameUtils;
|
||||
use MessageCache;
|
||||
use ParserCache;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Wikimedia\Assert\Assert;
|
||||
use Wikimedia\Rdbms\ILBFactory;
|
||||
use WikiPage;
|
||||
|
||||
/**
|
||||
* A factory for PageUpdater instances.
|
||||
*
|
||||
* @since 1.37
|
||||
* @ingroup Page
|
||||
*/
|
||||
class PageUpdaterFactory {
|
||||
|
||||
/**
|
||||
* Options that have to be present in the ServiceOptions object passed to the constructor.
|
||||
* @note must include PageUpdater::CONSTRUCTOR_OPTIONS
|
||||
* @internal
|
||||
*/
|
||||
public const CONSTRUCTOR_OPTIONS = [
|
||||
'ArticleCountMethod',
|
||||
'RCWatchCategoryMembership',
|
||||
'PageCreationLog',
|
||||
'AjaxEditStash',
|
||||
'UseAutomaticEditSummaries',
|
||||
'ManualRevertSearchRadius',
|
||||
'UseRCPatrol',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var RevisionStore
|
||||
*/
|
||||
private $revisionStore;
|
||||
|
||||
/**
|
||||
* @var RevisionRenderer
|
||||
*/
|
||||
private $revisionRenderer;
|
||||
|
||||
/**
|
||||
* @var SlotRoleRegistry
|
||||
*/
|
||||
private $slotRoleRegistry;
|
||||
|
||||
/**
|
||||
* @var ParserCache
|
||||
*/
|
||||
private $parserCache;
|
||||
|
||||
/**
|
||||
* @var JobQueueGroup
|
||||
*/
|
||||
private $jobQueueGroup;
|
||||
|
||||
/**
|
||||
* @var MessageCache
|
||||
*/
|
||||
private $messageCache;
|
||||
|
||||
/**
|
||||
* @var Language
|
||||
*/
|
||||
private $contLang;
|
||||
|
||||
/**
|
||||
* @var ILBFactory
|
||||
*/
|
||||
private $loadbalancerFactory;
|
||||
|
||||
/**
|
||||
* @var IContentHandlerFactory
|
||||
*/
|
||||
private $contentHandlerFactory;
|
||||
|
||||
/**
|
||||
* @var HookContainer
|
||||
*/
|
||||
private $hookContainer;
|
||||
|
||||
/**
|
||||
* @var EditResultCache
|
||||
*/
|
||||
private $editResultCache;
|
||||
|
||||
/**
|
||||
* @var UserNameUtils
|
||||
*/
|
||||
private $userNameUtils;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @var ServiceOptions
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/** @var UserEditTracker */
|
||||
private $userEditTracker;
|
||||
|
||||
/** @var UserGroupManager */
|
||||
private $userGroupManager;
|
||||
|
||||
/** @var string[] */
|
||||
private $softwareTags;
|
||||
|
||||
/**
|
||||
* @param RevisionStore $revisionStore
|
||||
* @param RevisionRenderer $revisionRenderer
|
||||
* @param SlotRoleRegistry $slotRoleRegistry
|
||||
* @param ParserCache $parserCache
|
||||
* @param JobQueueGroup $jobQueueGroup
|
||||
* @param MessageCache $messageCache
|
||||
* @param Language $contLang
|
||||
* @param ILBFactory $loadbalancerFactory
|
||||
* @param IContentHandlerFactory $contentHandlerFactory
|
||||
* @param HookContainer $hookContainer
|
||||
* @param EditResultCache $editResultCache
|
||||
* @param UserNameUtils $userNameUtils
|
||||
* @param LoggerInterface $logger
|
||||
* @param ServiceOptions $options
|
||||
* @param UserEditTracker $userEditTracker
|
||||
* @param UserGroupManager $userGroupManager
|
||||
* @param string[] $softwareTags
|
||||
*/
|
||||
public function __construct(
|
||||
RevisionStore $revisionStore,
|
||||
RevisionRenderer $revisionRenderer,
|
||||
SlotRoleRegistry $slotRoleRegistry,
|
||||
ParserCache $parserCache,
|
||||
JobQueueGroup $jobQueueGroup,
|
||||
MessageCache $messageCache,
|
||||
Language $contLang,
|
||||
ILBFactory $loadbalancerFactory,
|
||||
IContentHandlerFactory $contentHandlerFactory,
|
||||
HookContainer $hookContainer,
|
||||
EditResultCache $editResultCache,
|
||||
UserNameUtils $userNameUtils,
|
||||
LoggerInterface $logger,
|
||||
ServiceOptions $options,
|
||||
UserEditTracker $userEditTracker,
|
||||
UserGroupManager $userGroupManager,
|
||||
array $softwareTags
|
||||
) {
|
||||
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||
|
||||
$this->revisionStore = $revisionStore;
|
||||
$this->revisionRenderer = $revisionRenderer;
|
||||
$this->slotRoleRegistry = $slotRoleRegistry;
|
||||
$this->parserCache = $parserCache;
|
||||
$this->jobQueueGroup = $jobQueueGroup;
|
||||
$this->messageCache = $messageCache;
|
||||
$this->contLang = $contLang;
|
||||
$this->loadbalancerFactory = $loadbalancerFactory;
|
||||
$this->contentHandlerFactory = $contentHandlerFactory;
|
||||
$this->hookContainer = $hookContainer;
|
||||
$this->editResultCache = $editResultCache;
|
||||
$this->userNameUtils = $userNameUtils;
|
||||
$this->logger = $logger;
|
||||
$this->options = $options;
|
||||
$this->userEditTracker = $userEditTracker;
|
||||
$this->userGroupManager = $userGroupManager;
|
||||
$this->softwareTags = $softwareTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PageUpdater for building an update to a page.
|
||||
*
|
||||
* @internal For now, most code should keep using WikiPage::newPageUpdater() instead.
|
||||
* @note We can only start using this method everywhere when WikiPage::prepareContentForEdit()
|
||||
* and WikiPage::getCurrentUpdate() have been removed. For now, the WikiPage instance is
|
||||
* used to make the state of an ongoing edit available to hook handlers.
|
||||
*
|
||||
* @param WikiPage $page
|
||||
* @param UserIdentity $user
|
||||
*
|
||||
* @return PageUpdater
|
||||
* @since 1.37
|
||||
*/
|
||||
public function newPageUpdater(
|
||||
WikiPage $page,
|
||||
UserIdentity $user
|
||||
): PageUpdater {
|
||||
return $this->newPageUpdaterForDerivedPageDataUpdater(
|
||||
$page,
|
||||
$user,
|
||||
$this->newDerivedPageDataUpdater( $page )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PageUpdater for building an update to a page, reusing the state of
|
||||
* an existing DerivedPageDataUpdater.
|
||||
*
|
||||
* @param WikiPage $page
|
||||
* @param UserIdentity $user
|
||||
* @param DerivedPageDataUpdater $derivedPageDataUpdater
|
||||
*
|
||||
* @return PageUpdater
|
||||
* @internal needed by WikiPage to back the WikiPage::newPageUpdater method.
|
||||
*
|
||||
* @since 1.37
|
||||
*/
|
||||
public function newPageUpdaterForDerivedPageDataUpdater(
|
||||
WikiPage $page,
|
||||
UserIdentity $user,
|
||||
DerivedPageDataUpdater $derivedPageDataUpdater
|
||||
): PageUpdater {
|
||||
Assert::precondition(
|
||||
$page->canExist(),
|
||||
'The WikiPage instance does not represent a proper page!'
|
||||
);
|
||||
|
||||
$pageUpdater = new PageUpdater(
|
||||
$user,
|
||||
$page, // NOTE: eventually, PageUpdater should not know about WikiPage
|
||||
$derivedPageDataUpdater,
|
||||
$this->loadbalancerFactory->getMainLB(),
|
||||
$this->revisionStore,
|
||||
$this->slotRoleRegistry,
|
||||
$this->contentHandlerFactory,
|
||||
$this->hookContainer,
|
||||
$this->userEditTracker,
|
||||
$this->userGroupManager,
|
||||
new ServiceOptions(
|
||||
PageUpdater::CONSTRUCTOR_OPTIONS,
|
||||
$this->options
|
||||
),
|
||||
$this->softwareTags
|
||||
);
|
||||
|
||||
$pageUpdater->setUsePageCreationLog( $this->options->get( 'PageCreationLog' ) );
|
||||
$pageUpdater->setAjaxEditStash( $this->options->get( 'AjaxEditStash' ) );
|
||||
$pageUpdater->setUseAutomaticEditSummaries(
|
||||
$this->options->get( 'UseAutomaticEditSummaries' )
|
||||
);
|
||||
|
||||
return $pageUpdater;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WikiPage $page
|
||||
*
|
||||
* @return DerivedPageDataUpdater
|
||||
* @internal Needed by WikiPage to back the deprecated prepareContentForEdit() method.
|
||||
* @note Avoid direct usage of DerivedPageDataUpdater.
|
||||
* @see docs/pageupdater.md for more information.
|
||||
*/
|
||||
public function newDerivedPageDataUpdater( WikiPage $page ): DerivedPageDataUpdater {
|
||||
$derivedDataUpdater = new DerivedPageDataUpdater(
|
||||
$page, // NOTE: eventually, PageUpdater should not know about WikiPage
|
||||
$this->revisionStore,
|
||||
$this->revisionRenderer,
|
||||
$this->slotRoleRegistry,
|
||||
$this->parserCache,
|
||||
$this->jobQueueGroup,
|
||||
$this->messageCache,
|
||||
$this->contLang,
|
||||
$this->loadbalancerFactory,
|
||||
$this->contentHandlerFactory,
|
||||
$this->hookContainer,
|
||||
$this->editResultCache,
|
||||
$this->userNameUtils
|
||||
);
|
||||
|
||||
$derivedDataUpdater->setLogger( $this->logger );
|
||||
$derivedDataUpdater->setArticleCountMethod( $this->options->get( 'ArticleCountMethod' ) );
|
||||
$derivedDataUpdater->setRcWatchCategoryMembership(
|
||||
$this->options->get( 'RCWatchCategoryMembership' )
|
||||
);
|
||||
|
||||
return $derivedDataUpdater;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ class ServiceOptions {
|
|||
* @stable to call since 1.36
|
||||
*
|
||||
* @param string[] $keys Which keys to extract from $sources
|
||||
* @param Config|array ...$sources Each source is either a Config object or an array. If the
|
||||
* @param Config|ServiceOptions|array ...$sources Each source is either a Config object or an array. If the
|
||||
* same key is present in two sources, the first one takes precedence. Keys that are not in
|
||||
* $keys are ignored.
|
||||
* @throws InvalidArgumentException if one of $keys is not found in any of $sources
|
||||
|
|
@ -46,6 +46,11 @@ class ServiceOptions {
|
|||
$this->options[$key] = $source->get( $key );
|
||||
continue 2;
|
||||
}
|
||||
} elseif ( $source instanceof ServiceOptions ) {
|
||||
if ( array_key_exists( $key, $source->options ) ) {
|
||||
$this->options[$key] = $source->get( $key );
|
||||
continue 2;
|
||||
}
|
||||
} else {
|
||||
if ( array_key_exists( $key, $source ) ) {
|
||||
$this->options[$key] = $source[$key];
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ use Wikimedia\ObjectFactory;
|
|||
* @ingroup Content
|
||||
* @since 1.35
|
||||
*/
|
||||
final class ContentHandlerFactory implements IContentHandlerFactory {
|
||||
class ContentHandlerFactory implements IContentHandlerFactory {
|
||||
|
||||
/**
|
||||
* @var string[]|callable[]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
* @file
|
||||
*/
|
||||
|
||||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\Content\ContentHandlerFactory;
|
||||
use MediaWiki\Content\IContentHandlerFactory;
|
||||
use MediaWiki\DAO\WikiAwareEntityTrait;
|
||||
|
|
@ -38,11 +37,10 @@ use MediaWiki\Permissions\Authority;
|
|||
use MediaWiki\Revision\RevisionRecord;
|
||||
use MediaWiki\Revision\RevisionStore;
|
||||
use MediaWiki\Revision\SlotRecord;
|
||||
use MediaWiki\Revision\SlotRoleRegistry;
|
||||
use MediaWiki\Storage\DerivedPageDataUpdater;
|
||||
use MediaWiki\Storage\EditResult;
|
||||
use MediaWiki\Storage\EditResultCache;
|
||||
use MediaWiki\Storage\PageUpdater;
|
||||
use MediaWiki\Storage\PageUpdaterFactory;
|
||||
use MediaWiki\Storage\RevisionSlotsUpdate;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
use Wikimedia\Assert\Assert;
|
||||
|
|
@ -260,6 +258,13 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PageUpdaterFactory
|
||||
*/
|
||||
private function getPageUpdaterFactory(): PageUpdaterFactory {
|
||||
return MediaWikiServices::getInstance()->getPageUpdaterFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RevisionStore
|
||||
*/
|
||||
|
|
@ -267,13 +272,6 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
|
|||
return MediaWikiServices::getInstance()->getRevisionStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SlotRoleRegistry
|
||||
*/
|
||||
private function getSlotRoleRegistry() {
|
||||
return MediaWikiServices::getInstance()->getSlotRoleRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContentHandlerFactory
|
||||
*/
|
||||
|
|
@ -1714,45 +1712,6 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
|
|||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DerivedPageDataUpdater
|
||||
*/
|
||||
private function newDerivedDataUpdater() {
|
||||
global $wgRCWatchCategoryMembership, $wgArticleCountMethod;
|
||||
|
||||
$services = MediaWikiServices::getInstance();
|
||||
$editResultCache = new EditResultCache(
|
||||
$services->getMainObjectStash(),
|
||||
$services->getDBLoadBalancer(),
|
||||
new ServiceOptions(
|
||||
EditResultCache::CONSTRUCTOR_OPTIONS,
|
||||
$services->getMainConfig()
|
||||
)
|
||||
);
|
||||
|
||||
$derivedDataUpdater = new DerivedPageDataUpdater(
|
||||
$this, // NOTE: eventually, PageUpdater should not know about WikiPage
|
||||
$this->getRevisionStore(),
|
||||
$services->getRevisionRenderer(),
|
||||
$this->getSlotRoleRegistry(),
|
||||
$services->getParserCache(),
|
||||
JobQueueGroup::singleton(),
|
||||
$services->getMessageCache(),
|
||||
$services->getContentLanguage(),
|
||||
$services->getDBLoadBalancerFactory(),
|
||||
$this->getContentHandlerFactory(),
|
||||
$this->getHookContainer(),
|
||||
$editResultCache,
|
||||
$services->getUserNameUtils()
|
||||
);
|
||||
|
||||
$derivedDataUpdater->setLogger( LoggerFactory::getInstance( 'SaveParse' ) );
|
||||
$derivedDataUpdater->setRcWatchCategoryMembership( $wgRCWatchCategoryMembership );
|
||||
$derivedDataUpdater->setArticleCountMethod( $wgArticleCountMethod );
|
||||
|
||||
return $derivedDataUpdater;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DerivedPageDataUpdater for use with the given target revision or new content.
|
||||
* This method attempts to re-use the same DerivedPageDataUpdater instance for subsequent calls.
|
||||
|
|
@ -1815,7 +1774,8 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
|
|||
}
|
||||
|
||||
if ( !$this->derivedDataUpdater ) {
|
||||
$this->derivedDataUpdater = $this->newDerivedDataUpdater();
|
||||
$this->derivedDataUpdater =
|
||||
$this->getPageUpdaterFactory()->newDerivedPageDataUpdater( $this );
|
||||
}
|
||||
|
||||
return $this->derivedDataUpdater;
|
||||
|
|
@ -1830,40 +1790,27 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
|
|||
*
|
||||
* @since 1.32
|
||||
*
|
||||
* @param Authority $performer
|
||||
* @note Once extensions no longer rely on WikiPage to get access to the state of an ongoing
|
||||
* edit via prepareContentForEdit() and WikiPage::getCurrentUpdate(),
|
||||
* this method should be deprecated and callers should be migrated to using
|
||||
* PageUpdaterFactory::newPageUpdater() instead.
|
||||
*
|
||||
* @param Authority|UserIdentity $performer
|
||||
* @param RevisionSlotsUpdate|null $forUpdate If given, allows any cached ParserOutput
|
||||
* that may already have been returned via getDerivedDataUpdater to be re-used.
|
||||
*
|
||||
* @return PageUpdater
|
||||
*/
|
||||
public function newPageUpdater( Authority $performer, RevisionSlotsUpdate $forUpdate = null ) {
|
||||
$this->assertProperPage();
|
||||
public function newPageUpdater( $performer, RevisionSlotsUpdate $forUpdate = null ) {
|
||||
if ( $performer instanceof Authority ) {
|
||||
// TODO: Deprecate this. But better get rid of this method entirely.
|
||||
$performer = $performer->getUser();
|
||||
}
|
||||
|
||||
$mwServices = MediaWikiServices::getInstance();
|
||||
$config = $mwServices->getMainConfig();
|
||||
|
||||
$pageUpdater = new PageUpdater(
|
||||
$pageUpdater = $this->getPageUpdaterFactory()->newPageUpdaterForDerivedPageDataUpdater(
|
||||
$this,
|
||||
$performer,
|
||||
$this, // NOTE: eventually, PageUpdater should not know about WikiPage
|
||||
$this->getDerivedDataUpdater( $performer->getUser(), null, $forUpdate, true ),
|
||||
$this->getDBLoadBalancer(),
|
||||
$this->getRevisionStore(),
|
||||
$this->getSlotRoleRegistry(),
|
||||
$this->getContentHandlerFactory(),
|
||||
$this->getHookContainer(),
|
||||
$mwServices->getUserEditTracker(),
|
||||
$mwServices->getUserGroupManager(),
|
||||
new ServiceOptions(
|
||||
PageUpdater::CONSTRUCTOR_OPTIONS,
|
||||
$config
|
||||
),
|
||||
ChangeTags::getSoftwareTags()
|
||||
);
|
||||
|
||||
$pageUpdater->setUsePageCreationLog( $config->get( 'PageCreationLog' ) );
|
||||
$pageUpdater->setAjaxEditStash( $config->get( 'AjaxEditStash' ) );
|
||||
$pageUpdater->setUseAutomaticEditSummaries(
|
||||
$config->get( 'UseAutomaticEditSummaries' )
|
||||
$this->getDerivedDataUpdater( $performer, null, $forUpdate, true )
|
||||
);
|
||||
|
||||
return $pageUpdater;
|
||||
|
|
|
|||
110
tests/phpunit/unit/includes/Storage/PageUpdaterFactoryTest.php
Normal file
110
tests/phpunit/unit/includes/Storage/PageUpdaterFactoryTest.php
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace MediaWiki\Tests\Storage;
|
||||
|
||||
use JobQueueGroup;
|
||||
use Language;
|
||||
use LoadBalancer;
|
||||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\Content\ContentHandlerFactory;
|
||||
use MediaWiki\HookContainer\HookContainer;
|
||||
use MediaWiki\Revision\RevisionRenderer;
|
||||
use MediaWiki\Revision\RevisionStore;
|
||||
use MediaWiki\Revision\SlotRoleRegistry;
|
||||
use MediaWiki\Storage\DerivedPageDataUpdater;
|
||||
use MediaWiki\Storage\EditResultCache;
|
||||
use MediaWiki\Storage\PageUpdater;
|
||||
use MediaWiki\Storage\PageUpdaterFactory;
|
||||
use MediaWiki\User\UserEditTracker;
|
||||
use MediaWiki\User\UserGroupManager;
|
||||
use MediaWiki\User\UserIdentityValue;
|
||||
use MediaWiki\User\UserNameUtils;
|
||||
use MediaWikiUnitTestCase;
|
||||
use MessageCache;
|
||||
use ParserCache;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Wikimedia\Rdbms\LBFactory;
|
||||
use WikiPage;
|
||||
|
||||
/**
|
||||
* @covers MediaWiki\Storage\PageUpdaterFactory
|
||||
* @group Database
|
||||
*/
|
||||
class PageUpdaterFactoryTest extends MediaWikiUnitTestCase {
|
||||
private function getPageUpdaterFactory() {
|
||||
$config = [
|
||||
'ArticleCountMethod' => null,
|
||||
'RCWatchCategoryMembership' => null,
|
||||
'PageCreationLog' => null,
|
||||
'AjaxEditStash' => null,
|
||||
'UseAutomaticEditSummaries' => null,
|
||||
'ManualRevertSearchRadius' => null,
|
||||
'UseRCPatrol' => null,
|
||||
];
|
||||
|
||||
$lb = $this->createNoOpMock( LoadBalancer::class );
|
||||
$lbFactory = $this->createNoOpMock( LBFactory::class, [ 'getMainLB' ] );
|
||||
$lbFactory->method( 'getMainLB' )->willReturn( $lb );
|
||||
|
||||
return new PageUpdaterFactory(
|
||||
$this->createNoOpMock( RevisionStore::class ),
|
||||
$this->createNoOpMock( RevisionRenderer::class ),
|
||||
$this->createNoOpMock( SlotRoleRegistry::class ),
|
||||
$this->createNoOpMock( ParserCache::class ),
|
||||
$this->createNoOpMock( JobQueueGroup::class ),
|
||||
$this->createNoOpMock( MessageCache::class ),
|
||||
$this->createNoOpMock( Language::class ),
|
||||
$lbFactory,
|
||||
$this->createNoOpMock( ContentHandlerFactory::class ),
|
||||
$this->createNoOpMock( HookContainer::class ),
|
||||
$this->createNoOpMock( EditResultCache::class ),
|
||||
$this->createNoOpMock( UserNameUtils::class ),
|
||||
$this->createNoOpMock( LoggerInterface::class ),
|
||||
new ServiceOptions(
|
||||
PageUpdaterFactory::CONSTRUCTOR_OPTIONS,
|
||||
$config
|
||||
),
|
||||
$this->createNoOpMock( UserEditTracker::class ),
|
||||
$this->createNoOpMock( UserGroupManager::class ),
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
public function testNewDerivedPageDataUpdater() {
|
||||
$page = $this->createNoOpMock( WikiPage::class );
|
||||
|
||||
$factory = $this->getPageUpdaterFactory();
|
||||
$derivedPageDataUpdater = $factory->newDerivedPageDataUpdater( $page );
|
||||
|
||||
$this->assertInstanceOf( DerivedPageDataUpdater::class, $derivedPageDataUpdater );
|
||||
}
|
||||
|
||||
public function testNewPageUpdater() {
|
||||
$page = $this->createNoOpMock( WikiPage::class, [ 'canExist' ] );
|
||||
$page->method( 'canExist' )->willReturn( true );
|
||||
|
||||
$user = new UserIdentityValue( 0, 'Dummy' );
|
||||
|
||||
$factory = $this->getPageUpdaterFactory();
|
||||
$pageUpdater = $factory->newPageUpdater( $page, $user );
|
||||
|
||||
$this->assertInstanceOf( PageUpdater::class, $pageUpdater );
|
||||
}
|
||||
|
||||
public function testNewPageUpdaterForDerivedPageDataUpdater() {
|
||||
$page = $this->createNoOpMock( WikiPage::class, [ 'canExist' ] );
|
||||
$page->method( 'canExist' )->willReturn( true );
|
||||
|
||||
$user = new UserIdentityValue( 0, 'Dummy' );
|
||||
|
||||
$factory = $this->getPageUpdaterFactory();
|
||||
$derivedPageDataUpdater = $factory->newDerivedPageDataUpdater( $page );
|
||||
$pageUpdater = $factory->newPageUpdaterForDerivedPageDataUpdater(
|
||||
$page,
|
||||
$user,
|
||||
$derivedPageDataUpdater
|
||||
);
|
||||
|
||||
$this->assertInstanceOf( PageUpdater::class, $pageUpdater );
|
||||
}
|
||||
}
|
||||
|
|
@ -42,12 +42,17 @@ class ServiceOptionsTest extends MediaWikiUnitTestCase {
|
|||
[ 'a', 'b' ],
|
||||
new HashConfig( [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ] ),
|
||||
],
|
||||
'Simple ServiceOptions source' => [
|
||||
[ 'a' => 'aval', 'b' => 'bval' ],
|
||||
[ 'a', 'b' ],
|
||||
new ServiceOptions( [ 'a', 'b', 'c' ], [ 'a' => 'aval', 'b' => 'bval', 'c' => 'cval' ] ),
|
||||
],
|
||||
'Three different sources' => [
|
||||
[ 'a' => 'aval', 'b' => 'bval' ],
|
||||
[ 'a', 'b' ],
|
||||
[ 'z' => 'zval' ],
|
||||
new HashConfig( [ 'a' => 'aval', 'c' => 'cval' ] ),
|
||||
[ 'b' => 'bval', 'd' => 'dval' ],
|
||||
new ServiceOptions( [ 'b', 'd' ], [ 'b' => 'bval', 'd' => 'dval' ] ),
|
||||
],
|
||||
'null key' => [
|
||||
[ 'a' => null ],
|
||||
|
|
|
|||
Loading…
Reference in a new issue