Go to the documentation of this file.
32 use InvalidArgumentException;
54 use Wikimedia\Assert\Assert;
85 'ManualRevertSearchRadius',
238 'ManualRevertSearchRadius' =>
266 $this->rcPatrolStatus =
$status;
277 $this->usePageCreationLog = $use;
298 return $this->loadBalancer->getConnectionRef( $mode, [], $this->
getWikiId() );
306 return $this->wikiPage->getTitle();
314 return $this->wikiPage->getTitle();
360 $parentId = $parent ? $parent->getId() : 0;
362 return $parentId !== $expectedParentRevision;
393 return $this->derivedDataUpdater->grabCurrentRevision();
419 $this->slotsUpdate->modifyContent( $role,
$content );
430 $this->slotsUpdate->modifySlot( $slot );
453 $this->slotsUpdate->modifySlot( $inheritedSlot );
468 $this->slotsUpdate->removeSlot( $role );
483 $this->editResultBuilder->setOriginalRevisionId( $originalRevId );
501 int $oldestRevertedRevId,
502 int $newestRevertedRevId = 0
504 $this->editResultBuilder->markAsRevert(
505 $revertMethod, $oldestRevertedRevId, $newestRevertedRevId
527 Assert::parameterType(
'string', $tag,
'$tag' );
528 $this->tags[] = trim( $tag );
538 Assert::parameterElementType(
'string',
$tags,
'$tags' );
539 foreach (
$tags as $tag ) {
561 foreach ( $this->slotsUpdate->getModifiedRoles() as $role ) {
565 $content = $this->slotsUpdate->getModifiedSlot( $role )->getContent();
568 $tag = $handler->getChangeTag( $old_content,
$content, $flags );
577 return array_unique(
$tags );
590 if ( $parent && $parent->hasSlot( $role ) ) {
602 if ( $this->slotsUpdate->isModifiedSlot( $role ) ) {
603 $slot = $this->slotsUpdate->getModifiedSlot( $role );
614 return $this->contentHandlerFactory->getContentHandler( $slot->getModel() );
623 if ( !$this->useAutomaticEditSummaries || ( $flags &
EDIT_AUTOSUMMARY ) === 0 ) {
630 $roles = $this->slotsUpdate->getModifiedRoles();
631 $role = reset( $roles );
633 if ( $role ===
false ) {
638 $content = $this->slotsUpdate->getModifiedSlot( $role )->getContent();
640 $summary = $handler->getAutosummary( $old_content,
$content, $flags );
693 Assert::parameterType(
'integer', $flags,
'$flags' );
696 throw new RuntimeException(
'saveRevision() has already been called on this PageUpdater!' );
701 throw new RuntimeException(
'Something is trying to edit an article with an empty title' );
707 $this->slotsUpdate->getModifiedRoles(),
711 $this->slotsUpdate->getRemovedRoles(),
720 foreach ( $this->slotsUpdate->getModifiedRoles() as $role ) {
721 $slot = $this->slotsUpdate->getModifiedSlot( $role );
722 $roleHandler = $this->slotRoleRegistry->getRoleHandler( $role );
724 if ( !$roleHandler->isAllowedModel( $slot->getModel(), $this->getTitle() ) ) {
725 $contentHandler = $this->contentHandlerFactory
726 ->getContentHandler( $slot->getModel() );
729 $this->getTitle()->getPrefixedText(),
730 wfMessage( $roleHandler->getNameMessageKey() )
755 $this->derivedDataUpdater->prepareContent(
762 $renderedRevision = $this->derivedDataUpdater->getRenderedRevision();
764 $allowedByHook = $this->hookRunner->onMultiContentSave(
765 $renderedRevision,
$user, $summary, $flags, $hookStatus
767 if ( $allowedByHook && $this->hookContainer->isRegistered(
'PageContentSave' ) ) {
771 $mainContent = $this->derivedDataUpdater->getSlots()->getContent(
SlotRecord::MAIN );
774 $allowedByHook = $this->hookRunner->onPageContentSave(
776 $flags &
EDIT_MINOR,
null,
null, $flags, $hookStatus
780 if ( !$allowedByHook ) {
782 if ( $hookStatus->isOK() ) {
784 $hookStatus->fatal(
'edit-hook-aborted' );
787 $this->status = $hookStatus;
794 if ( $summary->text ===
'' && $summary->data ===
null ) {
817 return ( $this->status && $this->status->isOK() )
818 ? $this->status->value[
'revision-record']
828 return $this->status !==
null;
864 return $this->status && $this->status->isOK();
873 return $this->status && $this->status->isOK() && $this->status->value[
'new'];
885 && $this->status->isOK()
886 && $this->status->value[
'revision-record'] ===
null;
896 return ( $this->status && $this->status->isOK() )
897 ? $this->status->value[
'revision-record']
929 $rev = $this->derivedDataUpdater->getRevision();
930 '@phan-var MutableRevisionRecord $rev';
934 $rev->getPageId() !==
null &&
$title->exists()
935 && $rev->getPageId() !==
$title->getArticleID()
937 $titlePageId =
$title->getArticleID();
938 $revPageId = $rev->getPageId();
939 $masterPageId =
$title->getArticleID( Title::READ_LATEST );
941 if ( $revPageId === $masterPageId ) {
942 wfWarn( __METHOD__ .
": Encountered stale Title object: old ID was $titlePageId, "
943 .
"continuing with new ID from master, $masterPageId" );
945 throw new InvalidArgumentException(
946 "Revision inherited page ID $revPageId from its parent, "
947 .
"but the provided Title object belongs to page ID $masterPageId"
952 $rev->setPageId(
$title->getArticleID() );
955 $oldid = $parent->getId();
956 $rev->setParentId( $oldid );
961 $rev->setComment( $comment );
962 $rev->setUser(
$user );
963 $rev->setMinorEdit( ( $flags &
EDIT_MINOR ) > 0 );
965 foreach ( $rev->getSlots()->getSlots() as $slot ) {
978 $rev->getSlotRoles(),
993 $this->editResultBuilder->setRevisionRecord( $revision );
994 $this->editResultBuilder->setIsNew( $isNew );
995 $this->editResult = $this->editResultBuilder->buildEditResult();
1012 [
'new' =>
false,
'revision' =>
null,
'revision-record' =>
null ],
1013 [
'revision' =>
'1.35' ],
1014 __METHOD__ .
' status'
1019 $oldid = $oldRev ? $oldRev->getId() : 0;
1039 $now = $newRevisionRecord->getTimestamp();
1042 $changed = $this->derivedDataUpdater->isChange();
1050 $this->editResultBuilder->setOriginalRevisionId( $oldid );
1057 $dbw->startAtomic( __METHOD__ );
1063 if ( $latestNow != $oldid ) {
1067 $dbw->endAtomic( __METHOD__ );
1080 $newRevisionRecord = $this->revisionStore->insertRevisionOn( $newRevisionRecord, $dbw );
1084 $wasRedirect = $this->derivedDataUpdater->wasRedirect();
1091 $this->hookRunner->onRevisionFromEditComplete(
1096 if ( $this->hookContainer->isRegistered(
'NewRevisionFromEditComplete' ) ) {
1098 $newLegacyRevision =
new Revision( $newRevisionRecord );
1099 $this->hookRunner->onNewRevisionFromEditComplete(
1114 $newRevisionRecord->isMinor(),
1118 $newRevisionRecord->getTimestamp(),
1122 $newRevisionRecord->getSize(),
1123 $newRevisionRecord->getId(),
1124 $this->rcPatrolStatus,
1132 $dbw->endAtomic( __METHOD__ );
1135 $status->value[
'revision-record'] = $newRevisionRecord;
1138 $status->value[
'revision'] =
function () use ( $newRevisionRecord ) {
1139 return new Revision( $newRevisionRecord );
1146 $newRevisionRecord = $oldRev;
1152 $this->
getTitle()->invalidateCache( $now );
1170 [
'changed' => $changed, ]
1172 DeferredUpdates::PRESEND
1190 if ( !$this->derivedDataUpdater->getSlots()->hasSlot(
SlotRecord::MAIN ) ) {
1196 [
'new' =>
true,
'revision' =>
null,
'revision-record' =>
null ],
1197 [
'revision' =>
'1.35' ],
1198 __METHOD__ .
' status'
1214 $now = $newRevisionRecord->getTimestamp();
1217 $dbw->startAtomic( __METHOD__ );
1222 if ( $newid ===
false ) {
1223 $dbw->endAtomic( __METHOD__ );
1233 $newRevisionRecord->setPageId( $newid );
1236 $newRevisionRecord = $this->revisionStore->insertRevisionOn( $newRevisionRecord, $dbw );
1245 $this->hookRunner->onRevisionFromEditComplete(
1250 if ( $this->hookContainer->isRegistered(
'NewRevisionFromEditComplete' ) ) {
1252 $newLegacyRevision =
new Revision( $newRevisionRecord );
1253 $this->hookRunner->onNewRevisionFromEditComplete(
1268 $newRevisionRecord->isMinor(),
1273 $newRevisionRecord->getSize(),
1274 $newRevisionRecord->getId(),
1275 $this->rcPatrolStatus,
1282 if ( $this->usePageCreationLog ) {
1286 $logEntry->setPerformer(
$user );
1287 $logEntry->setTarget( $this->
getTitle() );
1288 $logEntry->setComment( $summary->text );
1289 $logEntry->setTimestamp( $now );
1290 $logEntry->setAssociatedRevId( $newRevisionRecord->getId() );
1291 $logEntry->insert();
1297 $dbw->endAtomic( __METHOD__ );
1300 $status->value[
'revision-record'] = $newRevisionRecord;
1303 $status->value[
'revision'] =
function () use ( $newRevisionRecord ) {
1304 return new Revision( $newRevisionRecord );
1317 [
'created' =>
true ]
1319 DeferredUpdates::PRESEND
1340 $summary, $flags,
$status, $hints
1343 $hints[
'causeAction'] =
'edit-page';
1353 $approved = !$this->serviceOptions->get(
'UseRCPatrol' ) ||
1358 $this->hookRunner->onBeforeRevertedTagUpdate(
1367 $hints[
'approved'] = $approved;
1371 $this->derivedDataUpdater->prepareUpdate( $newRevisionRecord, $hints );
1372 $this->derivedDataUpdater->doUpdates();
1374 $created = $hints[
'created'] ??
false;
1378 $this->hookRunner->onPageSaveComplete(
1388 if ( !$this->hookContainer->isRegistered(
'PageContentInsertComplete' )
1389 && !$this->hookContainer->isRegistered(
'PageContentSaveComplete' )
1396 $newLegacyRevision =
new Revision( $newRevisionRecord );
1399 $this->hookRunner->onPageContentInsertComplete(
$wikiPage,
$user,
1400 $mainContent, $summary->text, $flags &
EDIT_MINOR,
1401 null,
null, $flags, $newLegacyRevision );
1405 $this->hookRunner->onPageContentSaveComplete(
$wikiPage,
$user, $mainContent,
1407 null, $flags, $newLegacyRevision,
$status,
1417 return $this->slotRoleRegistry->getRequiredRoles( $this->
getTitle() );
1424 return $this->slotRoleRegistry->getAllowedRoles( $this->
getTitle() );
1429 if ( !in_array( $role, $allowedRoles ) ) {
1436 if ( in_array( $role, $requiredRoles ) ) {
1444 $forbidden = array_diff( $roles, $allowedRoles );
1445 if ( !empty( $forbidden ) ) {
1447 'edit-slots-cannot-add',
1448 count( $forbidden ),
1449 implode(
', ', $forbidden )
1457 $needed = array_diff( $roles, $requiredRoles );
1458 if ( !empty( $needed ) ) {
1460 'edit-slots-cannot-remove',
1462 implode(
', ', $needed )
1470 $missing = array_diff( $requiredRoles, $roles );
1471 if ( !empty( $missing ) ) {
1473 'edit-slots-missing',
1475 implode(
', ', $missing )
addTags(array $tags)
Sets tags to apply to this update.
makeNewRevision(CommentStoreComment $comment, User $user, $flags, Status $status)
Constructs a MutableRevisionRecord based on the Content prepared by the DerivedPageDataUpdater.
A content handler knows how do deal with a specific type of content on a wiki page.
saveRevision(CommentStoreComment $summary, $flags=0)
Change an existing article or create a new article.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
setAjaxEditStash( $ajaxEditStash)
doModify(CommentStoreComment $summary, User $user, $flags)
bool $usePageCreationLog
whether to create a log entry for new page creations.
updateRevisionOn( $dbw, $revision, $lastRevision=null, $lastRevIsRedirect=null)
Update the page record to point to a newly saved revision.
const CONSTRUCTOR_OPTIONS
Options that have to be present in the ServiceOptions object passed to the constructor.
checkNoRolesRequired(array $roles, Status $status)
error( $message,... $parameters)
Add an error, do not set fatal flag This can be used for non-fatal errors.
inheritSlot(SlotRecord $originalSlot)
Explicitly inherit a slot from some earlier revision.
incEditCount()
Schedule a deferred update to update the user's edit count.
setOriginalRevisionId( $originalRevId)
Sets the ID of an earlier revision that is being repeated or restored by this update.
Utility class for creating new RC entries.
getExplicitTags()
Returns the list of tags set using the addTag() method.
warning( $message,... $parameters)
Add a new warning.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the pending update queue for execution at the appropriate time.
getEditResult()
Returns the EditResult associated with this PageUpdater.
Class representing a MediaWiki article and history.
fatal( $message,... $parameters)
Add an error and set OK to false, indicating that the operation as a whole was fatal.
setUsePageCreationLog( $use)
Whether to create a log entry for new page creations.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
bool $ajaxEditStash
see $wgAjaxEditStash
getParentContent( $role)
Returns the content of the given slot of the parent revision, with no audience checks applied.
ILoadBalancer $loadBalancer
static notifyEdit( $timestamp, $title, $minor, $user, $comment, $oldId, $lastTimestamp, $bot, $ip='', $oldSize=0, $newSize=0, $newId=0, $patrol=0, $tags=[], EditResult $editResult=null)
Makes an entry in the database corresponding to an edit.
wasCommitted()
Whether saveRevision() has been called on this instance.
EditResultBuilder $editResultBuilder
ensureRoleAllowed( $role)
Generic operation result class Has warning/error list, boolean status and arbitrary value.
doCreate(CommentStoreComment $summary, User $user, $flags)
RevisionStore $revisionStore
checkFlags( $flags)
Check flags and add EDIT_NEW or EDIT_UPDATE to them as needed.
wasSuccessful()
Whether saveRevision() completed successfully.
setContent( $role, Content $content)
Set the new content for the given slot role.
markAsRevert(int $revertMethod, int $oldestRevertedRevId, int $newestRevertedRevId=0)
Marks this edit as a revert and applies relevant information.
__construct(User $user, WikiPage $wikiPage, DerivedPageDataUpdater $derivedDataUpdater, ILoadBalancer $loadBalancer, RevisionStore $revisionStore, SlotRoleRegistry $slotRoleRegistry, IContentHandlerFactory $contentHandlerFactory, HookContainer $hookContainer, ServiceOptions $serviceOptions, array $softwareTags)
isOK()
Returns whether the operation completed.
insertOn( $dbw, $pageId=null)
Insert a new empty page record for this article.
Class for managing the deferral of updates within the scope of a PHP script invocation.
getNewRevision()
The new revision created by saveRevision(), or null if saveRevision() has not yet been called,...
computeEffectiveTags( $flags)
getAtomicSectionUpdate(IDatabase $dbw, WikiPage $wikiPage, RevisionRecord $newRevisionRecord, User $user, CommentStoreComment $summary, $flags, Status $status, $hints=[])
merge( $other, $overwriteValue=false)
Merge another status object into this one.
removeSlot( $role)
Removes the slot with the given role.
ServiceOptions $serviceOptions
lockAndGetLatest()
Lock the page row for this title+id and return page_latest (or 0)
HookContainer $hookContainer
checkAllRolesAllowed(array $roles, Status $status)
addTag( $tag)
Sets a tag to apply to this update.
Deferrable Update for closure/callback updates via IDatabase::doAtomicSection()
string[] $softwareTags
currently enabled software change tags
static getLocalizedName( $name, Language $lang=null)
Returns the localized name for a given content model.
static newGood( $value=null)
Factory function for good results.
IContentHandlerFactory $contentHandlerFactory
Controller-like object for creating and updating pages by creating new revisions.
getDBConnectionRef( $mode)
bool $useAutomaticEditSummaries
see $wgUseAutomaticEditSummaries
hasEditConflict( $expectedParentRevision)
Checks whether this update conflicts with another update performed between the client loading data to...
Base interface for content objects.
RevisionSlotsUpdate $slotsUpdate
Represents a title within MediaWiki.
grabParentRevision()
Returns the revision that was the page's current revision when grabParentRevision() was first called.
static notifyNew( $timestamp, $title, $minor, $user, $comment, $bot, $ip='', $size=0, $newId=0, $patrol=0, $tags=[])
Makes an entry in the database corresponding to page creation Note: the title object must be loaded w...
getStatus()
The Status object indicating whether saveRevision() was successful, or null if saveRevision() was not...
setRcPatrolStatus( $status)
Sets the "patrolled" status of the edit.
int $rcPatrolStatus
the RC patrol status the new revision should be marked with.
ensureRoleNotRequired( $role)
getContentHandler( $role)
addAutopromoteOnceGroups( $event)
Add the user to the group if he/she meets given criteria.
Class for creating new log entries and inserting them into the database.
buildEditResult(RevisionRecord $revision, bool $isNew)
Builds the EditResult for this update.
DerivedPageDataUpdater $derivedDataUpdater
checkAllRequiredRoles(array $roles, Status $status)
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
Exception representing a failure to update a page entry.
A handle for managing updates for derived page data on edit, import, purge, etc.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add an update to the pending update queue that invokes the specified callback when run.
SlotRoleRegistry $slotRoleRegistry
getName()
Get the user name, or the IP of an anonymous user.
setUseAutomaticEditSummaries( $useAutomaticEditSummaries)
Can be used to enable or disable automatic summaries that are applied to certain kinds of changes,...
EditResult null $editResult
isNew()
Whether saveRevision() was called and created a new page.
isUnchanged()
Whether saveRevision() did not create a revision because the content didn't change (null-edit).
setSlot(SlotRecord $slot)
Set the new slot for the given slot role.