namespace MediaWiki\Storage;
-use ApiStashEdit;
use CategoryMembershipChangeJob;
use Content;
use ContentHandler;
use LinksUpdate;
use LogicException;
use MediaWiki\Edit\PreparedEdit;
+use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RenderedRevision;
use MediaWiki\Revision\RevisionRecord;
// TODO: MCR: allow output for all slots to be stashed.
if ( $useStash && $slotsUpdate->isModifiedSlot( SlotRecord::MAIN ) ) {
- $mainContent = $slotsUpdate->getModifiedSlot( SlotRecord::MAIN )->getContent();
- $legacyUser = User::newFromIdentity( $user );
- $stashedEdit = ApiStashEdit::checkCache( $title, $mainContent, $legacyUser );
+ $editStash = MediaWikiServices::getInstance()->getPageEditStash();
+ $stashedEdit = $editStash->checkCache(
+ $title,
+ $slotsUpdate->getModifiedSlot( SlotRecord::MAIN )->getContent(),
+ User::newFromIdentity( $user )
+ );
}
$userPopts = ParserOptions::newFromUserAndLang( $user, $this->contLang );
$preparedEdit = new PreparedEdit();
$preparedEdit->popts = $this->getCanonicalParserOptions();
- $preparedEdit->output = $this->getCanonicalParserOutput();
+ $preparedEdit->parserOutputCallback = [ $this, 'getCanonicalParserOutput' ];
$preparedEdit->pstContent = $this->revision->getContent( SlotRecord::MAIN );
$preparedEdit->newContent =
$slotsUpdate->isModifiedSlot( SlotRecord::MAIN )
$legacyUser = User::newFromIdentity( $this->user );
$legacyRevision = new Revision( $this->revision );
- $this->doParserCacheUpdate();
+ $userParserOptions = ParserOptions::newFromUser( $legacyUser );
+ // Decide whether to save the final canonical parser ouput based on the fact that
+ // users are typically redirected to viewing pages right after they edit those pages.
+ // Due to vary-revision-id, getting/saving that output here might require a reparse.
+ if ( $userParserOptions->matchesForCacheKey( $this->getCanonicalParserOptions() ) ) {
+ // Whether getting the final output requires a reparse or not, the user will
+ // need canonical output anyway, since that is what their parser options use.
+ // A reparse now at least has the benefit of various warm process caches.
+ $this->doParserCacheUpdate();
+ } else {
+ // If the user does not have canonical parse options, then don't risk another parse
+ // to make output they cannot use on the page refresh that typically occurs after
+ // editing. Doing the parser output save post-send will still benefit *other* users.
+ DeferredUpdates::addCallableUpdate( function () {
+ $this->doParserCacheUpdate();
+ } );
+ }
- $this->doSecondaryDataUpdates( [
- // T52785 do not update any other pages on a null edit
- 'recursive' => $this->options['changed'],
- 'defer' => DeferredUpdates::POSTSEND,
- ] );
+ // Defer the getCannonicalParserOutput() call triggered by getSecondaryDataUpdates()
+ DeferredUpdates::addCallableUpdate( function () {
+ $this->doSecondaryDataUpdates( [
+ // T52785 do not update any other pages on a null edit
+ 'recursive' => $this->options['changed']
+ ] );
+ } );
// TODO: MCR: check if *any* changed slot supports categories!
if ( $this->rcWatchCategoryMembership
}
// TODO: replace legacy hook! Use a listener on PageEventEmitter instead!
+ // @note: Extensions should *avoid* calling getCannonicalParserOutput() when using
+ // this hook whenever possible in order to avoid unnecessary additional parses.
$editInfo = $this->getPreparedEdit();
- Hooks::run( 'ArticleEditUpdates', [ &$wikiPage, &$editInfo, $this->options['changed'] ] );
+ Hooks::run( 'ArticleEditUpdates',
+ [ &$wikiPage, &$editInfo, $this->options['changed'] ] );
// TODO: replace legacy hook! Use a listener on PageEventEmitter instead!
if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', [ &$wikiPage ] ) ) {
return;
}
- if ( $this->options['oldcountable'] === 'no-change' ||
- ( !$this->options['changed'] && !$this->options['moved'] )
- ) {
- $good = 0;
- } elseif ( $this->options['created'] ) {
- $good = (int)$this->isCountable();
- } elseif ( $this->options['oldcountable'] !== null ) {
- $good = (int)$this->isCountable()
- - (int)$this->options['oldcountable'];
- } elseif ( isset( $this->pageState['oldCountable'] ) ) {
- $good = (int)$this->isCountable()
- - (int)$this->pageState['oldCountable'];
- } else {
- $good = 0;
- }
- $edits = $this->options['changed'] ? 1 : 0;
- $pages = $this->options['created'] ? 1 : 0;
+ DeferredUpdates::addCallableUpdate( function () {
+ if (
+ $this->options['oldcountable'] === 'no-change' ||
+ ( !$this->options['changed'] && !$this->options['moved'] )
+ ) {
+ $good = 0;
+ } elseif ( $this->options['created'] ) {
+ $good = (int)$this->isCountable();
+ } elseif ( $this->options['oldcountable'] !== null ) {
+ $good = (int)$this->isCountable()
+ - (int)$this->options['oldcountable'];
+ } elseif ( isset( $this->pageState['oldCountable'] ) ) {
+ $good = (int)$this->isCountable()
+ - (int)$this->pageState['oldCountable'];
+ } else {
+ $good = 0;
+ }
+ $edits = $this->options['changed'] ? 1 : 0;
+ $pages = $this->options['created'] ? 1 : 0;
- DeferredUpdates::addUpdate( SiteStatsUpdate::factory(
- [ 'edits' => $edits, 'articles' => $good, 'pages' => $pages ]
- ) );
+ DeferredUpdates::addUpdate( SiteStatsUpdate::factory(
+ [ 'edits' => $edits, 'articles' => $good, 'pages' => $pages ]
+ ) );
+ } );
// TODO: make search infrastructure aware of slots!
$mainSlot = $this->revision->getSlot( SlotRecord::MAIN );