Go to the documentation of this file.
34 use InvalidArgumentException;
61 use Wikimedia\Assert\Assert;
160 'oldrevision' =>
null,
161 'oldcountable' =>
null,
162 'oldredirect' =>
null,
163 'triggeringUser' =>
null,
166 'causeAction' =>
null,
167 'causeAgent' =>
null,
242 'knows-current' =>
true,
243 'has-content' =>
true,
244 'has-revision' =>
true,
247 'knows-current' =>
true,
248 'has-content' =>
true,
249 'has-revision' =>
true,
252 'has-content' =>
true,
253 'has-revision' =>
true,
256 'has-revision' =>
true,
312 $this->stage = $newStage;
327 if ( empty( self::$transitions[$this->stage][$newStage] ) ) {
328 throw new LogicException(
"Cannot transition from {$this->stage} to $newStage" );
361 throw new InvalidArgumentException(
'$parentId should match the parent of $revision' );
377 if ( $this->pageState
385 if ( $this->pageState
386 && $parentId !==
null
387 && $this->pageState[
'oldId'] !== $parentId
393 if ( $this->slotsUpdate
431 return $this->wikiPage->getTitle();
452 return $this->pageState[
'oldId'] > 0;
467 if ( $this->parentRevision ) {
471 if ( !$this->pageState[
'oldId'] ) {
477 $oldId = $this->
revision->getParentId();
478 $flags = $this->
useMaster() ? RevisionStore::READ_LATEST : 0;
479 $this->parentRevision = $oldId
480 ? $this->revisionStore->getRevisionById( $oldId, $flags )
507 if ( $this->pageState ) {
508 return $this->pageState[
'oldRevision'];
520 $current =
$rev ?
$rev->getRevisionRecord() :
null;
523 'oldRevision' => $current,
524 'oldId' =>
$rev ?
$rev->getId() : 0,
531 return $this->pageState[
'oldRevision'];
559 return $this->wikiPage->getId();
587 return $this->
getSlots()->getSlot( $role );
599 return $this->
getRawSlot( $role )->getContent();
609 return $this->
getRawSlot( $role )->getModel();
623 return $this->wikiPage->wasLoadedFrom( self::READ_LATEST );
632 if ( !$this->
getTitle()->isContentPage() ) {
648 if ( $this->articleCountMethod ===
'link' ) {
658 $roleHandler = $this->slotRoleRegistry->getRoleHandler( $role );
659 if ( $roleHandler->supportsArticleCount() ) {
662 if (
$content->isCountable( $hasLinks ) ) {
679 return $mainContent->isRedirect();
691 return $mainContent->isRedirect();
723 if ( $this->slotsUpdate ) {
724 if ( !$this->
user ) {
725 throw new LogicException(
726 'Unexpected state: $this->slotsUpdate was initialized, '
727 .
'but $this->user was not.'
731 if ( $this->
user->getName() !== $user->
getName() ) {
732 throw new LogicException(
'Can\'t call prepareContent() again for different user! '
733 .
'Expected ' . $this->
user->getName() .
', got ' . $user->
getName()
737 if ( !$this->slotsUpdate->hasSameUpdates(
$slotsUpdate ) ) {
738 throw new LogicException(
739 'Can\'t call prepareContent() again with different slot content!'
753 $this->slotsOutput = [];
754 $this->canonicalParserOutput =
null;
757 $stashedEdit =
false;
784 $oldCallback = $userPopts->getCurrentRevisionCallback();
785 $userPopts->setCurrentRevisionCallback(
789 return $legacyRevision;
791 return call_user_func( $oldCallback, $parserTitle,
$parser );
796 $pstContentSlots = $this->
revision->getSlots();
801 if ( $slot->isInherited() ) {
814 $pstContentSlots->setSlot( $pstSlot );
818 $pstContentSlots->removeSlot( $role );
827 if ( !$this->
options[
'changed'] ) {
849 if ( $stashedEdit ) {
851 $output = $stashedEdit->output;
854 $output->setCacheTime( $stashedEdit->timestamp );
856 $renderHints[
'known-revision-output'] =
$output;
861 $this->renderedRevision = $this->revisionRenderer->getRenderedRevision(
899 if ( !$this->pageState ) {
900 throw new LogicException(
901 'Must call grabCurrentRevision() or prepareContent() '
902 .
'or prepareUpdate() before calling ' . $method
909 throw new LogicException(
910 'Must call prepareContent() or prepareUpdate() before calling ' . $method
917 throw new LogicException(
918 'Must call prepareUpdate() before calling ' . $method
930 return $this->
options[
'created'];
944 return $this->
options[
'changed'];
955 if ( $this->pageState[
'oldIsRedirect'] ===
null ) {
957 $rev = $this->pageState[
'oldRevision'];
961 $this->pageState[
'oldIsRedirect'] =
false;
965 return $this->pageState[
'oldIsRedirect'];
989 if ( !$this->slotsUpdate ) {
993 $old ? $old->getSlots() :
null
1076 '$options["oldrevision"]',
1077 'must be a RevisionRecord (or Revision)'
1080 !isset(
$options[
'triggeringUser'] )
1082 '$options["triggeringUser"]',
1083 'must be a UserIdentity'
1087 throw new InvalidArgumentException(
1088 'Revision must have an ID set for it to be used with prepareUpdate()!'
1096 throw new LogicException(
1097 'Trying to re-use DerivedPageDataUpdater with revision '
1099 .
', but it\'s already bound to revision '
1108 throw new LogicException(
1109 'The Revision provided has mismatching content!'
1117 $oldId = $this->pageState[
'oldId'] ?? 0;
1118 $this->
options[
'newrev'] = ( $revision->
getId() !== $oldId );
1119 } elseif ( isset( $this->
options[
'oldrevision'] ) ) {
1121 $oldRev = $this->
options[
'oldrevision'];
1122 $oldId = $oldRev->getId();
1123 $this->
options[
'newrev'] = ( $revision->
getId() !== $oldId );
1128 if ( $oldId !==
null ) {
1137 $this->
options[
'changed'] =
true;
1140 $this->
options[
'changed'] =
false;
1143 throw new LogicException(
1144 'The Revision mismatches old revision ID: '
1145 .
'Old ID is ' . $oldId
1156 if ( $this->
user !==
null && $this->
options[
'changed'] && $this->slotsUpdate ) {
1159 throw new LogicException(
1160 'The Revision provided has a mismatching actor: expected '
1161 . $this->
user->getName()
1170 if ( !$this->pageState ) {
1171 $this->pageState = [
1172 'oldIsRedirect' => isset( $this->
options[
'oldredirect'] )
1173 && is_bool( $this->
options[
'oldredirect'] )
1174 ? $this->
options[
'oldredirect']
1176 'oldCountable' => isset( $this->
options[
'oldcountable'] )
1177 && is_bool( $this->
options[
'oldcountable'] )
1178 ? $this->
options[
'oldcountable']
1182 if ( $this->
options[
'changed'] ) {
1186 if ( isset( $this->
options[
'oldrevision'] ) ) {
1188 $this->pageState[
'oldRevision'] =
$rev instanceof
Revision
1189 ?
$rev->getRevisionRecord()
1195 $this->pageState[
'oldRevision'] =
$revision;
1200 $this->
options[
'created'] = ( $this->pageState[
'oldId'] === 0 );
1208 if ( !$this->
user ) {
1213 if ( $this->renderedRevision ) {
1214 $this->renderedRevision->updateRevision(
$revision );
1219 $this->renderedRevision = $this->revisionRenderer->getRenderedRevision(
1247 $preparedEdit->newContent =
1251 $preparedEdit->oldContent =
null;
1253 $preparedEdit->timestamp = $preparedEdit->output->getCacheTime();
1254 $preparedEdit->format = $preparedEdit->pstContent->getDefaultFormat();
1256 return $preparedEdit;
1267 [
'generate-html' => $generateHtml ]
1312 foreach ( $this->
getSlots()->getSlotRoles()
as $role ) {
1317 $updates =
$handler->getSecondaryDataUpdates(
1323 $allUpdates = array_merge( $allUpdates, $updates );
1328 $legacyUpdates =
$content->getSecondaryDataUpdates(
1336 $legacyUpdates = array_filter( $legacyUpdates,
function ( $update ) {
1340 $allUpdates = array_merge( $allUpdates, $legacyUpdates );
1358 $content = $parentSlot->getContent();
1361 $updates =
$handler->getDeletionUpdates(
1365 $allUpdates = array_merge( $allUpdates, $updates );
1371 $legacyUpdates = array_filter( $legacyUpdates,
function ( $update ) {
1375 $allUpdates = array_merge( $allUpdates, $legacyUpdates );
1380 'RevisionDataUpdates',
1411 'recursive' => $this->
options[
'changed'],
1416 if ( $this->rcWatchCategoryMembership
1419 && !$this->
options[
'restored']
1424 $this->jobQueueGroup->lazyPush(
1439 if ( mt_rand( 0, 9 ) == 0 ) {
1446 $dbKey =
$title->getPrefixedDBkey();
1447 $shortTitle =
$title->getDBkey();
1449 if ( !
$title->exists() ) {
1450 wfDebug( __METHOD__ .
": Page doesn't exist any more, bailing out\n" );
1456 if ( $this->
options[
'oldcountable'] ===
'no-change' ||
1460 } elseif ( $this->
options[
'created'] ) {
1462 } elseif ( $this->
options[
'oldcountable'] !==
null ) {
1464 - (int)$this->
options[
'oldcountable'];
1465 } elseif ( isset( $this->pageState[
'oldCountable'] ) ) {
1467 - (int)$this->pageState[
'oldCountable'];
1471 $edits = $this->
options[
'changed'] ? 1 : 0;
1472 $pages = $this->
options[
'created'] ? 1 : 0;
1475 [
'edits' => $edits,
'articles' => $good,
'pages' => $pages ]
1487 if ( $this->
options[
'changed']
1489 && $shortTitle != $legacyUser->getTitleKey()
1490 && !( $this->
revision->isMinor() && $legacyUser->isAllowed(
'nominornewtalk' ) )
1493 if ( !$recipient ) {
1494 wfDebug( __METHOD__ .
": invalid username\n" );
1502 $recipient->setNewtalk(
true, $legacyRevision );
1503 } elseif ( $recipient->isLoggedIn() ) {
1504 $recipient->setNewtalk(
true, $legacyRevision );
1506 wfDebug( __METHOD__ .
": don't need to notify a nonexistent user\n" );
1517 $this->messageCache->updateMessageOverride(
$title, $mainContent );
1521 if ( $this->
options[
'created'] ) {
1523 } elseif ( $this->
options[
'changed'] ) {
1528 $oldLegacyRevision = $oldRevision ?
new Revision( $oldRevision ) :
null;
1555 'recursive' =>
false,
1557 'transactionTicket' =>
null,
1560 if ( !in_array(
$options[
'defer'], $deferValues,
true ) ) {
1561 throw new InvalidArgumentException(
'invalid value for defer: ' .
$options[
'defer'] );
1563 Assert::parameterType(
'integer|null',
$options[
'transactionTicket'],
1564 '$options[\'transactionTicket\']' );
1569 if ( !$triggeringUser instanceof
User ) {
1572 $causeAction = $this->
options[
'causeAction'] ??
'unknown';
1573 $causeAgent = $this->
options[
'causeAgent'] ??
'unknown';
1576 if (
$options[
'defer'] ===
false &&
$options[
'transactionTicket'] !==
null ) {
1580 $this->loadbalancerFactory->commitAndWaitForReplication(
1581 __METHOD__,
$options[
'transactionTicket']
1585 foreach ( $updates
as $update ) {
1587 $update->setCause( $causeAction, $causeAgent );
1590 $update->setRevision( $legacyRevision );
1591 $update->setTriggeringUser( $triggeringUser );
1594 if (
$options[
'defer'] ===
false ) {
1596 $update->setTransactionTicket(
$options[
'transactionTicket'] );
1598 $update->doUpdate();
1620 $timestamp = $this->
options[
'newrev'] ? $this->
revision->getTimestamp()
1622 $this->parserCache->save(
1624 $timestamp, $this->
revision->getId()
getCanonicalParserOutput()
Set options of the Parser.
A content handler knows how do deal with a specific type of content on a wiki page.
static getForModelID( $modelId)
Returns the ContentHandler singleton for the given model ID.
static onArticleCreate(Title $title)
The onArticle*() functions are supposed to be a kind of hooks which should be called whenever any of ...
loadPageData( $from='fromdb')
Load the object from a given source by title.
pageExisted()
Determines whether the page being edited already existed.
getParentRevision()
Returns the parent revision of the new revision wrapped by this update.
getRevision()
Returns the update's target revision - that is, the revision that will be the current revision after ...
string $articleCountMethod
see $wgArticleCountMethod
prepareContent(User $user, RevisionSlotsUpdate $slotsUpdate, $useStash=true)
Prepare updates based on an update which has not yet been saved.
getSlotParserOutput( $role, $generateHtml=true)
Job for pruning recent changes.
prepareUpdate(RevisionRecord $revision, array $options=[])
Prepare derived data updates targeting the given Revision.
setArticleCountMethod( $articleCountMethod)
getSlots()
Returns the slots of the target revision, after PST.
LBFactory $loadbalancerFactory
RevisionRecord null $parentRevision
setRcWatchCategoryMembership( $rcWatchCategoryMembership)
Abstraction for ResourceLoader modules which pull from wiki pages.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the deferred list to be run later by execute()
Class representing a MediaWiki article and history.
RevisionRenderer $revisionRenderer
Class the manages updates of *_link tables as well as similar extension-managed tables.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
getRevision()
Get the latest revision.
$options
Stores (most of) the $options parameter of prepareUpdate().
RenderedRevision $renderedRevision
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
RevisionSlotsUpdate null $slotsUpdate
Interface for database access objects.
static onArticleEdit(Title $title, Revision $revision=null, $slotsChanged=null)
Purge caches on page update etc.
getCanonicalParserOptions()
doUpdates()
Do standard updates after page edit, purge, or import.
Abstract base class for update jobs that do something with some secondary data extracted from article...
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
RevisionStore $revisionStore
assertHasRevision( $method)
SlotRoleRegistry $slotRoleRegistry
namespace and then decline to actually register it file or subcat img or subcat $title
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such and we might be restricted by PHP settings such as safe mode or open_basedir We cannot assume that the software even has read access anywhere useful Many shared hosts run all users web applications under the same user
isReusableFor(UserIdentity $user=null, RevisionRecord $revision=null, RevisionSlotsUpdate $slotsUpdate=null, $parentId=null)
Checks whether this DerivedPageDataUpdater can be re-used for running updates targeting the given rev...
static newFromUserAndLang(User $user, Language $lang)
Get a ParserOptions object from a given user and language.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check set to true or false to override the $wgMaxImageArea check result gives extension the possibility to transform it themselves $handler
getRevisionSlotsUpdate()
Returns the RevisionSlotsUpdate for this updater.
Class for managing the deferred updates.
getContentHandler( $role)
__construct(WikiPage $wikiPage, RevisionStore $revisionStore, RevisionRenderer $revisionRenderer, SlotRoleRegistry $slotRoleRegistry, ParserCache $parserCache, JobQueueGroup $jobQueueGroup, MessageCache $messageCache, Language $contLang, LBFactory $loadbalancerFactory)
static isIP( $name)
Does the string match an anonymous IP address?
getContentModel( $role)
Returns the content model of the given slot.
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
wasRedirect()
Whether the page was a redirect before the edit.
static factory(array $deltas)
equals(Title $title)
Compare with another title.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Class for handling updates to the site_stats table.
isCreation()
Whether the edit creates the page.
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
assertTransition( $newStage)
Asserts that a transition to the given stage is possible, without performing it.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
isCountable( $editInfo=false)
Determine whether a page would be suitable for being counted as an article in the site_stats table ba...
Job to add recent change entries mentioning category membership changes.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
static array[] $transitions
Transition table for managing the life cycle of DerivedPageDateUpdater instances.
isContentDeleted()
Whether the content is deleted and thus not visible to the public.
static invalidateModuleCache(Title $title, Revision $old=null, Revision $new=null, $domain)
Clear the preloadTitleInfo() cache for all wiki modules on this wiki on page change if it was a JS or...
isContentPrepared()
Whether prepareUpdate() or prepareContent() have been called on this instance.
Update object handling the cleanup of links tables after a page was deleted.
either a unescaped string or a HtmlArmor object after in associative array form externallinks $linksUpdate
getRemovedSlotRoles()
Returns the role names of the slots removed by the new revision.
array $pageState
The state of the relevant row in page table before the edit.
MessageCache $messageCache
doTransition( $newStage)
Transition function for managing the life cycle of this instances.
getModifiedSlotRoles()
Returns the role names of the slots modified by the new revision, not including removed roles.
Base interface for content objects.
JobQueueGroup $jobQueueGroup
Represents a title within MediaWiki.
getRawContent( $role)
Returns the content of the given slot, with no audience checks.
getSecondaryDataUpdates( $recursive=false)
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
boolean $rcWatchCategoryMembership
see $wgRCWatchCategoryMembership
RevisionRecord null $revision
In both all secondary updates will be triggered handle like object that caches derived data representing a revision
getRawSlot( $role)
Returns the slot, modified or inherited, after PST, with no audience checks applied.
doSecondaryDataUpdates(array $options=[])
Do secondary data updates (such as updating link tables).
static newSpec(Title $title, $revisionTimestamp)
isChange()
Whether the edit created, or should create, a new revision (that is, it's not a null-edit).
assertHasPageState( $method)
Interface that deferrable updates should implement.
getTouchedSlotRoles()
Returns the role names of the slots touched by the new revision, including removed roles.
string $stage
A stage identifier for managing the life cycle of this instance.
isRedirect()
Tests if the article content represents a redirect.
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going and make changes or fix bugs In we can take all the code that deals with the little used title reversing options(say) and put it in one place. Instead of having little title-reversing if-blocks spread all over the codebase in showAnArticle
A handle for managing updates for derived page data on edit, import, purge, etc.
Cache of messages that are defined by MediaWiki namespace pages or by hooks.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
revisionIsRedirect(RevisionRecord $rev)
getName()
Get the user name, or the IP of an anonymous user.
Prepare an edit in shared cache so that it can be reused on edit.
static checkCache(Title $title, Content $content, User $user)
Check that a prepared edit is in cache and still up-to-date.
Internationalisation code.
grabCurrentRevision()
Returns the revision that was the page's current revision when grabCurrentRevision() was first called...
isUpdatePrepared()
Whether prepareUpdate() has been called on this instance.
Class to handle enqueueing of background jobs.
In both all secondary updates will be triggered handle like object that caches derived data representing a and can trigger updates of cached copies of that e g in the links the ParserCache