Move Content::preSaveTransform to ContentHandler

Create ContentTransformer to access ContentHandler::preSaveTransform through the service.
Prepare object to hold a data that required for ContentHandler::preSaveTranform params.

This will require making a semi-backwards-incompatible
change no matter what, we don't really have a great way
of hard-deprecating overriding methods.

However, with the ContentHandler calling Content and
Content calling ContentHandler, and with the ProxyContent
trick to stop infinite recursion, it doesn't matter whether
callers use Content or ContentHandler. This will allow us
to naturally convert all callers. But won't really allow
hard-deprecation.

Bug: T287156
Change-Id: If6a2025868ceca3a3b6f11baec39695e47292e40
This commit is contained in:
Petr Pchelko 2021-07-20 18:03:59 -07:00 committed by Roman Stolar
parent b03f5b5e4a
commit b782a7e66d
24 changed files with 397 additions and 145 deletions

View file

@ -1323,9 +1323,11 @@ class EditPage implements IEditObject {
if ( $undoMsg === null ) {
$oldContent = $this->page->getContent( RevisionRecord::RAW );
$popts = ParserOptions::newFromUserAndLang(
$user, MediaWikiServices::getInstance()->getContentLanguage() );
$newContent = $content->preSaveTransform( $this->mTitle, $user, $popts );
$services = MediaWikiServices::getInstance();
$popts = ParserOptions::newFromUserAndLang( $user, $services->getContentLanguage() );
$contentTransformer = $services->getContentTransformer();
$newContent = $contentTransformer->preSaveTransform( $content, $this->mTitle, $user, $popts );
if ( $newContent->getModel() !== $oldContent->getModel() ) {
// The undo may change content
// model if its reverting the top
@ -2455,10 +2457,12 @@ class EditPage implements IEditObject {
}
// Do a pre-save transform on the retrieved undo content
$contentLanguage = MediaWikiServices::getInstance()->getContentLanguage();
$services = MediaWikiServices::getInstance();
$contentLanguage = $services->getContentLanguage();
$user = $this->context->getUser();
$parserOptions = ParserOptions::newFromUserAndLang( $user, $contentLanguage );
$undoContent = $undoContent->preSaveTransform( $this->mTitle, $user, $parserOptions );
$contentTransformer = $services->getContentTransformer();
$undoContent = $contentTransformer->preSaveTransform( $undoContent, $this->mTitle, $user, $parserOptions );
if ( $undoContent->equals( $content ) ) {
return true;
@ -3664,7 +3668,9 @@ class EditPage implements IEditObject {
$user = $this->context->getUser();
$popts = ParserOptions::newFromUserAndLang( $user,
MediaWikiServices::getInstance()->getContentLanguage() );
$newContent = $newContent->preSaveTransform( $this->mTitle, $user, $popts );
$services = MediaWikiServices::getInstance();
$contentTransformer = $services->getContentTransformer();
$newContent = $contentTransformer->preSaveTransform( $newContent, $this->mTitle, $user, $popts );
}
if ( ( $oldContent && !$oldContent->isEmpty() ) || ( $newContent && !$newContent->isEmpty() ) ) {
@ -4191,7 +4197,9 @@ class EditPage implements IEditObject {
// causing the context user to be used for {{subst:REVISIONUSER}}.
// XXX: Alternatively, we could also call setupFakeRevision() a second time:
// once before PST with $content, and then after PST with $pstContent.
$pstContent = $content->preSaveTransform( $this->mTitle, $user, $parserOptions );
$services = MediaWikiServices::getInstance();
$contentTransformer = $services->getContentTransformer();
$pstContent = $contentTransformer->preSaveTransform( $content, $this->mTitle, $user, $parserOptions );
$scopedCallback = $parserOptions->setupFakeRevision( $this->mTitle, $pstContent, $user );
$parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
ScopedCallback::consume( $scopedCallback );

View file

@ -40,6 +40,7 @@ use MediaWiki\Block\UnblockUserFactory;
use MediaWiki\Cache\LinkBatchFactory;
use MediaWiki\Config\ConfigRepository;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Content\Transform\ContentTransformer;
use MediaWiki\EditPage\SpamChecker;
use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
@ -787,6 +788,14 @@ class MediaWikiServices extends ServiceContainer {
return $this->getService( 'ContentModelStore' );
}
/**
* @since 1.37
* @return ContentTransformer
*/
public function getContentTransformer(): ContentTransformer {
return $this->getService( 'ContentTransformer' );
}
/**
* @since 1.35
* @return ContributionsLookup

View file

@ -62,6 +62,7 @@ use MediaWiki\Config\ConfigRepository;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Content\ContentHandlerFactory;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Content\Transform\ContentTransformer;
use MediaWiki\EditPage\Constraint\EditConstraintFactory;
use MediaWiki\EditPage\SpamChecker;
use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
@ -353,6 +354,10 @@ return [
return $services->getNameTableStoreFactory()->getContentModels();
},
'ContentTransformer' => static function ( MediaWikiServices $services ): ContentTransformer {
return new ContentTransformer( $services->getContentHandlerFactory() );
},
'ContributionsLookup' => static function ( MediaWikiServices $services ): ContributionsLookup {
return new ContributionsLookup(
$services->getRevisionStore(),
@ -1067,6 +1072,7 @@ return [
$services->getUserEditTracker(),
$services->getUserGroupManager(),
$services->getTitleFormatter(),
$services->getContentTransformer(),
ChangeTags::getSoftwareTags()
);
},

View file

@ -34,6 +34,7 @@ use Language;
use LinksUpdate;
use LogicException;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Content\Transform\ContentTransformer;
use MediaWiki\Edit\PreparedEdit;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
@ -288,6 +289,9 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
/** @var UserNameUtils */
private $userNameUtils;
/** @var ContentTransformer */
private $contentTransformer;
/**
* @param WikiPage $wikiPage ,
* @param RevisionStore $revisionStore
@ -302,6 +306,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
* @param HookContainer $hookContainer
* @param EditResultCache $editResultCache
* @param UserNameUtils $userNameUtils
* @param ContentTransformer $contentTransformer
*/
public function __construct(
WikiPage $wikiPage,
@ -316,7 +321,8 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
IContentHandlerFactory $contentHandlerFactory,
HookContainer $hookContainer,
EditResultCache $editResultCache,
UserNameUtils $userNameUtils
UserNameUtils $userNameUtils,
ContentTransformer $contentTransformer
) {
$this->wikiPage = $wikiPage;
@ -334,6 +340,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
$this->hookRunner = new HookRunner( $hookContainer );
$this->editResultCache = $editResultCache;
$this->userNameUtils = $userNameUtils;
$this->contentTransformer = $contentTransformer;
$this->logger = new NullLogger();
}
@ -855,8 +862,13 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
// TODO: MCR: allow PST content for all slots to be stashed.
$pstSlot = SlotRecord::newUnsaved( $role, $stashedEdit->pstContent );
} else {
$content = $slot->getContent();
$pstContent = $content->preSaveTransform( $title, $legacyUser, $userPopts );
$pstContent = $this->contentTransformer->preSaveTransform(
$slot->getContent(),
$title,
$user,
$userPopts
);
$pstSlot = SlotRecord::newUnsaved( $role, $pstContent );
}

View file

@ -26,6 +26,7 @@ use JobQueueGroup;
use Language;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Content\Transform\ContentTransformer;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\Revision\RevisionRenderer;
use MediaWiki\Revision\RevisionStore;
@ -116,6 +117,9 @@ class PageUpdaterFactory {
/** @var TitleFormatter */
private $titleFormatter;
/** @var ContentTransformer */
private $contentTransformer;
/** @var string[] */
private $softwareTags;
@ -137,6 +141,7 @@ class PageUpdaterFactory {
* @param UserEditTracker $userEditTracker
* @param UserGroupManager $userGroupManager
* @param TitleFormatter $titleFormatter
* @param ContentTransformer $contentTransformer
* @param string[] $softwareTags
*/
public function __construct(
@ -157,6 +162,7 @@ class PageUpdaterFactory {
UserEditTracker $userEditTracker,
UserGroupManager $userGroupManager,
TitleFormatter $titleFormatter,
ContentTransformer $contentTransformer,
array $softwareTags
) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
@ -178,6 +184,7 @@ class PageUpdaterFactory {
$this->userEditTracker = $userEditTracker;
$this->userGroupManager = $userGroupManager;
$this->titleFormatter = $titleFormatter;
$this->contentTransformer = $contentTransformer;
$this->softwareTags = $softwareTags;
}
@ -279,7 +286,8 @@ class PageUpdaterFactory {
$this->contentHandlerFactory,
$this->hookContainer,
$this->editResultCache,
$this->userNameUtils
$this->userNameUtils,
$this->contentTransformer
);
$derivedDataUpdater->setLogger( $this->logger );

View file

@ -27,6 +27,7 @@
*/
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Content\Transform\PreSaveTransformParamsValue;
use MediaWiki\MediaWikiServices;
/**
@ -386,8 +387,9 @@ abstract class AbstractContent implements Content {
}
/**
* @stable to override
* @since 1.21
* @deprecated since 1.37. Use ContentTransformer::preSaveTransform instead.
* Extensions defining a content model should override ContentHandler::preSaveTransform.
*
* @param Title $title
* @param User $user
@ -397,7 +399,11 @@ abstract class AbstractContent implements Content {
* @see Content::preSaveTransform
*/
public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
return $this;
$pstParams = new PreSaveTransformParamsValue( $title, $user, $popts );
return $this->getContentHandler()->preSaveTransform(
$this,
$pstParams
);
}
/**

View file

@ -387,6 +387,7 @@ interface Content {
* object if no transformations apply).
*
* @since 1.21
* @deprecated since 1.37 Use ContentTransformer::preSaveTransform and override ContentHandler::preSaveTransform.
*
* @param Title $title
* @param User $user

View file

@ -26,6 +26,7 @@
* @author Daniel Kinzler
*/
use MediaWiki\Content\Transform\PreSaveTransformParams;
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
@ -1527,4 +1528,35 @@ abstract class ContentHandler {
return [];
}
/**
* Returns a $content object with pre-save transformations applied (or the same
* object if no transformations apply).
*
* @note Not stable to call other then from ContentHandler hierarchy.
* Callers need to use ContentTransformer::preSaveTransform.
* @stable to override
* @since 1.37
*
* @param Content $content
* @param PreSaveTransformParams $pstParams
*
* @return Content
*/
public function preSaveTransform(
Content $content,
PreSaveTransformParams $pstParams
): Content {
$contentOverridesTransform = MWDebug::detectDeprecatedOverride(
$content,
AbstractContent::class,
'preSaveTransform'
);
if ( $contentOverridesTransform ) {
$services = MediaWikiServices::getInstance();
$legacyUser = $services->getUserFactory()->newFromUserIdentity( $pstParams->getUser() );
$legacyTitle = $services->getTitleFactory()->castFromPageReference( $pstParams->getPage() );
return $content->preSaveTransform( $legacyTitle, $legacyUser, $pstParams->getParserOptions() );
}
return $content;
}
}

View file

@ -25,8 +25,6 @@
* @author Daniel Kinzler
*/
use MediaWiki\MediaWikiServices;
/**
* Content object for CSS pages.
*
@ -49,34 +47,6 @@ class CssContent extends TextContent {
parent::__construct( $text, $modelId );
}
/**
* Returns a Content object with pre-save transformations applied using
* Parser::preSaveTransform().
*
* @param Title $title
* @param User $user
* @param ParserOptions $popts
*
* @return CssContent
*
* @see TextContent::preSaveTransform
*/
public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
// @todo Make pre-save transformation optional for script pages (T34858)
if ( !MediaWikiServices::getInstance()->getUserOptionsLookup()->getBoolOption( $user, 'pst-cssjs' ) ) {
// Allow bot users to disable the pre-save transform for CSS/JS (T236828).
$popts = clone $popts;
$popts->setPreSaveTransform( false );
}
$text = $this->getText();
$pst = MediaWikiServices::getInstance()->getParser()
->preSaveTransform( $text, $title, $user, $popts );
return new static( $pst );
}
/**
* @return string CSS wrapped in a <pre> tag.
*/

View file

@ -20,6 +20,9 @@
* @file
* @ingroup Content
*/
use MediaWiki\Content\Transform\PreSaveTransformParams;
use MediaWiki\MediaWikiServices;
use Wikimedia\Minify\CSSMin;
/**
@ -59,4 +62,29 @@ class CssContentHandler extends CodeContentHandler {
return new $class( '/* #REDIRECT */@import ' . CSSMin::buildUrlValue( $url ) . ';' );
}
public function preSaveTransform(
Content $content,
PreSaveTransformParams $pstParams
): Content {
'@phan-var CssContent $content';
// @todo Make pre-save transformation optional for script pages (T34858)
$services = MediaWikiServices::getInstance();
if ( !$services->getUserOptionsLookup()->getBoolOption( $pstParams->getUser(), 'pst-cssjs' ) ) {
// Allow bot users to disable the pre-save transform for CSS/JS (T236828).
$popts = clone $pstParams->getParserOptions();
$popts->setPreSaveTransform( false );
}
$text = $content->getText();
$pst = $services->getParser()->preSaveTransform(
$text,
$pstParams->getPage(),
$pstParams->getUser(),
$pstParams->getParserOptions()
);
$class = $this->getContentClass();
return new $class( $pst );
}
}

View file

@ -25,8 +25,6 @@
* @author Daniel Kinzler
*/
use MediaWiki\MediaWikiServices;
/**
* Content for JavaScript pages.
*
@ -49,32 +47,6 @@ class JavaScriptContent extends TextContent {
parent::__construct( $text, $modelId );
}
/**
* Returns a Content object with pre-save transformations applied using
* Parser::preSaveTransform().
*
* @param Title $title
* @param User $user
* @param ParserOptions $popts
*
* @return JavaScriptContent
*/
public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
// @todo Make pre-save transformation optional for script pages (T34858)
if ( !MediaWikiServices::getInstance()->getUserOptionsLookup()->getBoolOption( $user, 'pst-cssjs' ) ) {
// Allow bot users to disable the pre-save transform for CSS/JS (T236828).
$popts = clone $popts;
$popts->setPreSaveTransform( false );
}
$text = $this->getText();
$pst = MediaWikiServices::getInstance()->getParser()
->preSaveTransform( $text, $title, $user, $popts );
return new static( $pst );
}
/**
* @return string JavaScript wrapped in a <pre> tag.
*/

View file

@ -18,6 +18,9 @@
* @file
*/
use MediaWiki\Content\Transform\PreSaveTransformParams;
use MediaWiki\MediaWikiServices;
/**
* Content handler for JavaScript pages.
*
@ -59,4 +62,31 @@ class JavaScriptContentHandler extends CodeContentHandler {
$class = $this->getContentClass();
return new $class( '/* #REDIRECT */' . Xml::encodeJsCall( 'mw.loader.load', [ $url ] ) );
}
public function preSaveTransform(
Content $content,
PreSaveTransformParams $pstParams
): Content {
'@phan-var JavascriptContent $content';
$parserOptions = $pstParams->getParserOptions();
// @todo Make pre-save transformation optional for script pages (T34858)
$services = MediaWikiServices::getInstance();
if ( !$services->getUserOptionsLookup()->getBoolOption( $pstParams->getUser(), 'pst-cssjs' ) ) {
// Allow bot users to disable the pre-save transform for CSS/JS (T236828).
$parserOptions = clone $parserOptions;
$parserOptions->setPreSaveTransform( false );
}
$text = $content->getText();
$pst = $services->getParser()->preSaveTransform(
$text,
$pstParams->getPage(),
$pstParams->getUser(),
$parserOptions
);
$contentClass = $this->getContentClass();
return new $contentClass( $pst );
}
}

View file

@ -61,24 +61,6 @@ class JsonContent extends TextContent {
return FormatJson::encode( $this->getData()->getValue(), true, FormatJson::UTF8_OK );
}
/**
* Beautifies JSON prior to save.
*
* @param Title $title
* @param User $user
* @param ParserOptions $popts
* @return JsonContent
*/
public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
// FIXME: WikiPage::doEditContent invokes PST before validation. As such, native data
// may be invalid (though PST result is discarded later in that case).
if ( !$this->isValid() ) {
return $this;
}
return new static( self::normalizeLineEndings( $this->beautifyJSON() ) );
}
/**
* Set the HTML and add the appropriate styles.
*

View file

@ -18,6 +18,8 @@
* @file
*/
use MediaWiki\Content\Transform\PreSaveTransformParams;
/**
* Content handler for JSON.
*
@ -44,4 +46,20 @@ class JsonContentHandler extends CodeContentHandler {
$class = $this->getContentClass();
return new $class( '{}' );
}
public function preSaveTransform(
Content $content,
PreSaveTransformParams $pstParams
): Content {
'@phan-var JsonContent $content';
// FIXME: WikiPage::doEditContent invokes PST before validation. As such, native data
// may be invalid (though PST result is discarded later in that case).
if ( !$content->isValid() ) {
return $content;
}
$contentClass = $this->getContentClass();
return new $contentClass( JsonContent::normalizeLineEndings( $content->beautifyJSON() ) );
}
}

View file

@ -204,27 +204,6 @@ class TextContent extends AbstractContent {
return str_replace( [ "\r\n", "\r" ], "\n", rtrim( $text ) );
}
/**
* Returns a Content object with pre-save transformations applied.
*
* At a minimum, subclasses should make sure to call TextContent::normalizeLineEndings()
* either directly or part of Parser::preSaveTransform().
*
* @stable to override
*
* @param Title $title
* @param User $user
* @param ParserOptions $popts
*
* @return Content
*/
public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
$text = $this->getText();
$pst = self::normalizeLineEndings( $text );
return ( $text === $pst ) ? $this : new static( $pst, $this->getModel() );
}
/**
* Diff this content object with another content object.
*

View file

@ -23,6 +23,8 @@
* @ingroup Content
*/
use MediaWiki\Content\Transform\PreSaveTransformParams;
/**
* Base content handler implementation for flat text contents.
*
@ -160,4 +162,17 @@ class TextContentHandler extends ContentHandler {
return $fields;
}
public function preSaveTransform(
Content $content,
PreSaveTransformParams $pstParams
): Content {
'@phan-var TextContent $content';
$text = $content->getText();
$pst = TextContent::normalizeLineEndings( $text );
$contentClass = $this->getContentClass();
return ( $text === $pst ) ? $content : new $contentClass( $pst, $content->getModel() );
}
}

View file

@ -0,0 +1,48 @@
<?php
namespace MediaWiki\Content\Transform;
use Content;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Page\PageReference;
use MediaWiki\User\UserIdentity;
use ParserOptions;
/**
* A service to transform content.
*
* @since 1.37
*/
class ContentTransformer {
/** @var IContentHandlerFactory */
private $contentHandlerFactory;
/**
* @param IContentHandlerFactory $contentHandlerFactory
*/
public function __construct( IContentHandlerFactory $contentHandlerFactory ) {
$this->contentHandlerFactory = $contentHandlerFactory;
}
/**
* Returns a Content object with pre-save transformations applied (or $content
* if no transformations apply).
*
* @param Content $content
* @param PageReference $page
* @param UserIdentity $user
* @param ParserOptions $parser
*
* @return Content
*/
public function preSaveTransform(
Content $content,
PageReference $page,
UserIdentity $user,
ParserOptions $parser
): Content {
$contentHandler = $this->contentHandlerFactory->getContentHandler( $content->getModel() );
$pstParams = new PreSaveTransformParamsValue( $page, $user, $parser );
return $contentHandler->preSaveTransform( $content, $pstParams );
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace MediaWiki\Content\Transform;
use MediaWiki\Page\PageReference;
use MediaWiki\User\UserIdentity;
use ParserOptions;
/**
* @since 1.37
* An interface to hold pre-save transform params.
*/
interface PreSaveTransformParams {
/**
* @return PageReference
*/
public function getPage(): PageReference;
/**
* @return UserIdentity
*/
public function getUser(): UserIdentity;
/**
* @return ParserOptions
*/
public function getParserOptions(): ParserOptions;
}

View file

@ -0,0 +1,51 @@
<?php
namespace MediaWiki\Content\Transform;
use MediaWiki\Page\PageReference;
use MediaWiki\User\UserIdentity;
use ParserOptions;
/**
* @internal
* An object to hold pre-save transform params.
*/
class PreSaveTransformParamsValue implements PreSaveTransformParams {
/** @var PageReference */
private $page;
/** @var UserIdentity */
private $user;
/** @var ParserOptions */
private $parserOptions;
public function __construct( PageReference $page, UserIdentity $user, ParserOptions $parserOptions ) {
$this->page = $page;
$this->user = $user;
$this->parserOptions = $parserOptions;
}
/**
*
* @return PageReference
*/
public function getPage(): PageReference {
return $this->page;
}
/**
*
* @return UserIdentity
*/
public function getUser(): UserIdentity {
return $this->user;
}
/**
*
* @return ParserOptions
*/
public function getParserOptions(): ParserOptions {
return $this->parserOptions;
}
}

View file

@ -38,10 +38,9 @@ class WikitextContent extends TextContent {
private $redirectTargetAndText = null;
/**
* @var bool Tracks if the parser set the user-signature flag when creating this content, which
* would make it expire faster in ApiStashEdit.
* @var string[] flags set by PST
*/
private $hadSignature = false;
private $preSaveTransformFlags = [];
/**
* @var string|null Stack trace of the previous parse
@ -142,35 +141,6 @@ class WikitextContent extends TextContent {
return new static( $text );
}
/**
* Returns a Content object with pre-save transformations applied using
* Parser::preSaveTransform().
*
* @param Title $title
* @param User $user
* @param ParserOptions $popts
*
* @return Content
*/
public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
$text = $this->getText();
$parser = MediaWikiServices::getInstance()->getParser();
$pst = $parser->preSaveTransform( $text, $title, $user, $popts );
if ( $text === $pst ) {
return $this;
}
$ret = new static( $pst );
if ( $parser->getOutput()->getFlag( 'user-signature' ) ) {
$ret->hadSignature = true;
}
return $ret;
}
/**
* Returns a Content object with preload transformations applied (or this
* object if no transformations apply).
@ -389,7 +359,7 @@ class WikitextContent extends TextContent {
}
// Pass along user-signature flag
if ( $this->hadSignature ) {
if ( in_array( 'user-signature', $this->preSaveTransformFlags ) ) {
$output->setFlag( 'user-signature' );
}
}
@ -417,4 +387,12 @@ class WikitextContent extends TextContent {
return $word->match( $this->getText() );
}
/**
* Records flags set by preSaveTransform
* @internal for use by WikitextContentHandler
* @param string[] $flags
*/
public function setPreSaveTransformFlags( array $flags ) {
$this->preSaveTransformFlags = $flags;
}
}

View file

@ -23,6 +23,7 @@
* @ingroup Content
*/
use MediaWiki\Content\Transform\PreSaveTransformParams;
use MediaWiki\Languages\LanguageNameUtils;
use MediaWiki\MediaWikiServices;
@ -188,4 +189,29 @@ class WikitextContentHandler extends TextContentHandler {
return parent::serializeContent( $content, $format );
}
public function preSaveTransform(
Content $content,
PreSaveTransformParams $pstParams
): Content {
'@phan-var WikitextContent $content';
$text = $content->getText();
$parser = MediaWikiServices::getInstance()->getParser();
$pst = $parser->preSaveTransform(
$text,
$pstParams->getPage(),
$pstParams->getUser(),
$pstParams->getParserOptions()
);
if ( $text === $pst ) {
return $content;
}
$contentClass = $this->getContentClass();
$ret = new $contentClass( $pst );
$ret->setPreSaveTransformFlags( $parser->getOutput()->getAllFlags() );
return $ret;
}
}

View file

@ -5,13 +5,23 @@
*/
class FallbackContentTest extends MediaWikiLangTestCase {
private const CONTENT_MODEL = 'xyzzy';
protected function setUp(): void {
parent::setUp();
$this->mergeMwGlobalArrayValue(
'wgContentHandlers',
[ self::CONTENT_MODEL => FallbackContentHandler::class ]
);
}
/**
* @param string $data
* @param string $type
*
* @return FallbackContent
*/
public function newContent( $data, $type = 'xyzzy' ) {
public function newContent( $data, $type = self::CONTENT_MODEL ) {
return new FallbackContent( $data, $type );
}
@ -159,7 +169,7 @@ class FallbackContentTest extends MediaWikiLangTestCase {
public function testGetContentHandler() {
$this->mergeMwGlobalArrayValue(
'wgContentHandlers',
[ 'horkyporky' => 'UnknownContentHandler' ]
[ 'horkyporky' => FallbackContentHandler::class ]
);
$content = $this->newContent( "hello world.", 'horkyporky' );

View file

@ -0,0 +1,31 @@
<?php
use MediaWiki\MediaWikiServices;
class ContentTransformerTest extends MediaWikiIntegrationTestCase {
public function preSaveTransformProvider() {
return [
[
new WikitextContent( 'Test ~~~' ),
'Test [[Special:Contributions/127.0.0.1|127.0.0.1]]'
],
];
}
/**
* @covers MediaWiki\Content\Transform\ContentTransformer::preSaveTransform
*
* @dataProvider preSaveTransformProvider
*/
public function testPreSaveTransform( $content, $expectedContainText ) {
$services = MediaWikiServices::getInstance();
$title = Title::newFromText( 'Test' );
$user = new User();
$user->setName( "127.0.0.1" );
$options = ParserOptions::newFromUser( $user );
$newContent = $services->getContentTransformer()->preSaveTransform( $content, $title, $user, $options );
$this->assertSame( $expectedContainText, $newContent->serialize() );
}
}

View file

@ -6,6 +6,10 @@ class DummyContentHandlerForTesting extends ContentHandler {
parent::__construct( $dataModel, $formats );
}
protected function getContentClass() {
return DummyContentForTesting::class;
}
/**
* @see ContentHandler::serializeContent
*