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:
parent
b03f5b5e4a
commit
b782a7e66d
24 changed files with 397 additions and 145 deletions
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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() ) );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
48
includes/content/Transform/ContentTransformer.php
Normal file
48
includes/content/Transform/ContentTransformer.php
Normal 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 );
|
||||
}
|
||||
}
|
||||
28
includes/content/Transform/PreSaveTransformParams.php
Normal file
28
includes/content/Transform/PreSaveTransformParams.php
Normal 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;
|
||||
}
|
||||
51
includes/content/Transform/PreSaveTransformParamsValue.php
Normal file
51
includes/content/Transform/PreSaveTransformParamsValue.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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' );
|
||||
|
|
|
|||
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,10 @@ class DummyContentHandlerForTesting extends ContentHandler {
|
|||
parent::__construct( $dataModel, $formats );
|
||||
}
|
||||
|
||||
protected function getContentClass() {
|
||||
return DummyContentForTesting::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ContentHandler::serializeContent
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue