diff --git a/docs/config-schema.yaml b/docs/config-schema.yaml index 6dea9e08d07..2373859275c 100644 --- a/docs/config-schema.yaml +++ b/docs/config-schema.yaml @@ -1994,7 +1994,7 @@ config-schema: - 1.40: Added ContentHandlers: default: - wikitext: WikitextContentHandler + wikitext: { class: WikitextContentHandler, services: [TitleFactory, ParserFactory, GlobalIdGenerator, LanguageNameUtils, MagicWordFactory] } javascript: JavaScriptContentHandler json: JsonContentHandler css: CssContentHandler @@ -2003,7 +2003,7 @@ config-schema: type: object description: |- Plugins for page content model handling. - Each entry in the array maps a model id to a class name or callback + Each entry in the array maps a model id to an ObjectFactory specification that creates an instance of the appropriate ContentHandler subclass. @since 1.21 NamespaceContentModels: diff --git a/includes/MainConfigSchema.php b/includes/MainConfigSchema.php index cb7d5f2760f..529d0b591dc 100644 --- a/includes/MainConfigSchema.php +++ b/includes/MainConfigSchema.php @@ -3260,7 +3260,7 @@ class MainConfigSchema { /** * Plugins for page content model handling. * - * Each entry in the array maps a model id to a class name or callback + * Each entry in the array maps a model id to an ObjectFactory specification * that creates an instance of the appropriate ContentHandler subclass. * * @since 1.21 @@ -3269,7 +3269,16 @@ class MainConfigSchema { 'default' => [ // the usual case - CONTENT_MODEL_WIKITEXT => WikitextContentHandler::class, + CONTENT_MODEL_WIKITEXT => [ + 'class' => WikitextContentHandler::class, + 'services' => [ + 'TitleFactory', + 'ParserFactory', + 'GlobalIdGenerator', + 'LanguageNameUtils', + 'MagicWordFactory', + ], + ], // dumb version, no syntax highlighting CONTENT_MODEL_JAVASCRIPT => JavaScriptContentHandler::class, // simple implementation, for use by extensions, etc. diff --git a/includes/config-schema.php b/includes/config-schema.php index 07df00af0fc..ee1a22f8d90 100644 --- a/includes/config-schema.php +++ b/includes/config-schema.php @@ -386,7 +386,16 @@ return [ 'TemplateLinksSchemaMigrationStage' => 768, 'ExternalLinksSchemaMigrationStage' => 3, 'ContentHandlers' => [ - 'wikitext' => 'WikitextContentHandler', + 'wikitext' => [ + 'class' => 'WikitextContentHandler', + 'services' => [ + 0 => 'TitleFactory', + 1 => 'ParserFactory', + 2 => 'GlobalIdGenerator', + 3 => 'LanguageNameUtils', + 4 => 'MagicWordFactory', + ], + ], 'javascript' => 'JavaScriptContentHandler', 'json' => 'JsonContentHandler', 'css' => 'CssContentHandler', diff --git a/includes/content/WikitextContentHandler.php b/includes/content/WikitextContentHandler.php index 1da1e349c36..43003e315e9 100644 --- a/includes/content/WikitextContentHandler.php +++ b/includes/content/WikitextContentHandler.php @@ -27,9 +27,10 @@ use MediaWiki\Content\Renderer\ContentParseParams; use MediaWiki\Content\Transform\PreloadTransformParams; use MediaWiki\Content\Transform\PreSaveTransformParams; use MediaWiki\Languages\LanguageNameUtils; -use MediaWiki\MediaWikiServices; use MediaWiki\Parser\ParserOutputFlags; use MediaWiki\Revision\RevisionRecord; +use MediaWiki\Title\TitleFactory; +use Wikimedia\UUID\GlobalIdGenerator; /** * Content handler for wiki text pages. @@ -38,8 +39,44 @@ use MediaWiki\Revision\RevisionRecord; */ class WikitextContentHandler extends TextContentHandler { - public function __construct( $modelId = CONTENT_MODEL_WIKITEXT ) { + /** @var TitleFactory */ + private $titleFactory; + + /** @var ParserFactory */ + private $parserFactory; + + /** @var GlobalIdGenerator */ + private $globalIdGenerator; + + /** @var LanguageNameUtils */ + private $languageNameUtils; + + /** @var MagicWordFactory */ + private $magicWordFactory; + + /** + * @param string $modelId + * @param TitleFactory $titleFactory + * @param ParserFactory $parserFactory + * @param GlobalIdGenerator $globalIdGenerator + * @param LanguageNameUtils $languageNameUtils + * @param MagicWordFactory $magicWordFactory + */ + public function __construct( + string $modelId, + TitleFactory $titleFactory, + ParserFactory $parserFactory, + GlobalIdGenerator $globalIdGenerator, + LanguageNameUtils $languageNameUtils, + MagicWordFactory $magicWordFactory + ) { + // $modelId should always be CONTENT_MODEL_WIKITEXT parent::__construct( $modelId, [ CONTENT_FORMAT_WIKITEXT ] ); + $this->titleFactory = $titleFactory; + $this->parserFactory = $parserFactory; + $this->globalIdGenerator = $globalIdGenerator; + $this->languageNameUtils = $languageNameUtils; + $this->magicWordFactory = $magicWordFactory; } protected function getContentClass() { @@ -59,14 +96,11 @@ class WikitextContentHandler extends TextContentHandler { public function makeRedirectContent( Title $destination, $text = '' ) { $optionalColon = ''; - $services = MediaWikiServices::getInstance(); if ( $destination->getNamespace() === NS_CATEGORY ) { $optionalColon = ':'; } else { $iw = $destination->getInterwiki(); - if ( $iw && $services - ->getLanguageNameUtils() - ->getLanguageName( $iw, + if ( $iw && $this->languageNameUtils->getLanguageName( $iw, LanguageNameUtils::AUTONYMS, LanguageNameUtils::DEFINED ) ) { @@ -74,7 +108,7 @@ class WikitextContentHandler extends TextContentHandler { } } - $mwRedir = $services->getMagicWordFactory()->get( 'redirect' ); + $mwRedir = $this->magicWordFactory->get( 'redirect' ); $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $optionalColon . $destination->getFullText() . ']]'; @@ -131,7 +165,14 @@ class WikitextContentHandler extends TextContentHandler { * @return FileContentHandler */ protected function getFileHandler() { - return new FileContentHandler(); + return new FileContentHandler( + $this->getModelID(), + $this->titleFactory, + $this->parserFactory, + $this->globalIdGenerator, + $this->languageNameUtils, + $this->magicWordFactory + ); } public function getFieldsForSearchIndex( SearchEngine $engine ) { @@ -216,10 +257,9 @@ class WikitextContentHandler extends TextContentHandler { } '@phan-var WikitextContent $content'; - $text = $content->getText(); - $parser = MediaWikiServices::getInstance()->getParserFactory()->getInstance(); + $parser = $this->parserFactory->getInstance(); $pst = $parser->preSaveTransform( $text, $pstParams->getPage(), @@ -263,9 +303,9 @@ class WikitextContentHandler extends TextContentHandler { } '@phan-var WikitextContent $content'; - $text = $content->getText(); - $plt = MediaWikiServices::getInstance()->getParserFactory()->getInstance() + + $plt = $this->parserFactory->getInstance() ->getPreloadText( $text, $pltParams->getPage(), @@ -292,15 +332,15 @@ class WikitextContentHandler extends TextContentHandler { ParserOutput &$parserOutput ) { '@phan-var WikitextContent $content'; - $services = MediaWikiServices::getInstance(); - $title = $services->getTitleFactory()->castFromPageReference( $cpoParams->getPage() ); + $title = $this->titleFactory->castFromPageReference( $cpoParams->getPage() ); $parserOptions = $cpoParams->getParserOptions(); $revId = $cpoParams->getRevId(); [ $redir, $text ] = $content->getRedirectTargetAndText(); - $parserOutput = $services->getParserFactory()->getInstance() - // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here - ->parse( $text, $title, $parserOptions, true, true, $revId ); + + $parser = $this->parserFactory->getInstance(); + // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here + $parserOutput = $parser->parse( $text, $title, $parserOptions, true, true, $revId ); // Add redirect indicator at the top if ( $redir ) { diff --git a/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php b/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php index abb9cc55d34..871506450f0 100644 --- a/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php +++ b/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php @@ -587,7 +587,16 @@ class DerivedPageDataUpdaterTest extends MediaWikiIntegrationTestCase { $this->overrideConfigValue( MainConfigNames::ContentHandlers, [ - CONTENT_MODEL_WIKITEXT => WikitextContentHandler::class, + CONTENT_MODEL_WIKITEXT => [ + 'class' => WikitextContentHandler::class, + 'services' => [ + 'TitleFactory', + 'ParserFactory', + 'GlobalIdGenerator', + 'LanguageNameUtils', + 'MagicWordFactory', + ], + ], 'testing' => DummyContentHandlerForTesting::class, ] ); diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php index cb3b8464407..f4655a1ca48 100644 --- a/tests/phpunit/includes/content/ContentHandlerTest.php +++ b/tests/phpunit/includes/content/ContentHandlerTest.php @@ -1,10 +1,13 @@ 'testing', ], MainConfigNames::ContentHandlers => [ - CONTENT_MODEL_WIKITEXT => WikitextContentHandler::class, + CONTENT_MODEL_WIKITEXT => [ + 'class' => WikitextContentHandler::class, + 'services' => [ + 'TitleFactory', + 'ParserFactory', + 'GlobalIdGenerator', + 'LanguageNameUtils', + 'MagicWordFactory', + ], + ], CONTENT_MODEL_JAVASCRIPT => JavaScriptContentHandler::class, CONTENT_MODEL_JSON => JsonContentHandler::class, CONTENT_MODEL_CSS => CssContentHandler::class, @@ -487,7 +499,14 @@ class ContentHandlerTest extends MediaWikiIntegrationTestCase { ] ); // test default renderer - $contentHandler = new WikitextContentHandler( CONTENT_MODEL_WIKITEXT ); + $contentHandler = new WikitextContentHandler( + CONTENT_MODEL_WIKITEXT, + $this->createMock( TitleFactory::class ), + $this->createMock( ParserFactory::class ), + $this->createMock( GlobalIdGenerator::class ), + $this->createMock( LanguageNameUtils::class ), + $this->createMock( MagicWordFactory::class ) + ); $slotDiffRenderer = $contentHandler->getSlotDiffRenderer( RequestContext::getMain() ); $this->assertInstanceOf( TextSlotDiffRenderer::class, $slotDiffRenderer ); } diff --git a/tests/phpunit/includes/content/RegistrationContentHandlerFactoryToMediaWikiServicesTest.php b/tests/phpunit/includes/content/RegistrationContentHandlerFactoryToMediaWikiServicesTest.php index 36be189e7ca..1bad22031bf 100644 --- a/tests/phpunit/includes/content/RegistrationContentHandlerFactoryToMediaWikiServicesTest.php +++ b/tests/phpunit/includes/content/RegistrationContentHandlerFactoryToMediaWikiServicesTest.php @@ -13,7 +13,16 @@ class RegistrationContentHandlerFactoryToMediaWikiServicesTest extends MediaWiki $this->overrideConfigValue( MainConfigNames::ContentHandlers, [ - CONTENT_MODEL_WIKITEXT => WikitextContentHandler::class, + CONTENT_MODEL_WIKITEXT => [ + 'class' => WikitextContentHandler::class, + 'services' => [ + 'TitleFactory', + 'ParserFactory', + 'GlobalIdGenerator', + 'LanguageNameUtils', + 'MagicWordFactory', + ], + ], CONTENT_MODEL_JAVASCRIPT => JavaScriptContentHandler::class, CONTENT_MODEL_JSON => JsonContentHandler::class, CONTENT_MODEL_CSS => CssContentHandler::class, diff --git a/tests/phpunit/integration/includes/Rest/Handler/UpdateHandlerTest.php b/tests/phpunit/integration/includes/Rest/Handler/UpdateHandlerTest.php index 0addb0b0198..75c6c36d28d 100644 --- a/tests/phpunit/integration/includes/Rest/Handler/UpdateHandlerTest.php +++ b/tests/phpunit/integration/includes/Rest/Handler/UpdateHandlerTest.php @@ -5,7 +5,9 @@ namespace MediaWiki\Tests\Rest\Handler; use ApiUsageException; use FormatJson; use HashConfig; +use MagicWordFactory; use MediaWiki\Content\IContentHandlerFactory; +use MediaWiki\Languages\LanguageNameUtils; use MediaWiki\Rest\Handler\UpdateHandler; use MediaWiki\Rest\LocalizedHttpException; use MediaWiki\Rest\RequestData; @@ -13,13 +15,16 @@ use MediaWiki\Revision\MutableRevisionRecord; use MediaWiki\Revision\RevisionLookup; use MediaWiki\Revision\SlotRecord; use MediaWiki\Tests\Unit\DummyServicesTrait; +use MediaWiki\Title\TitleFactory; use MockTitleTrait; +use ParserFactory; use PHPUnit\Framework\MockObject\MockObject; use Status; use Title; use Wikimedia\Message\MessageValue; use Wikimedia\Message\ParamType; use Wikimedia\Message\ScalarParam; +use Wikimedia\UUID\GlobalIdGenerator; use WikitextContent; use WikitextContentHandler; @@ -52,7 +57,14 @@ class UpdateHandlerTest extends \MediaWikiLangTestCase { $contentHandlerFactory ->method( 'getContentHandler' ) - ->willReturn( new WikitextContentHandler() ); + ->willReturn( new WikitextContentHandler( + CONTENT_MODEL_WIKITEXT, + $this->createMock( TitleFactory::class ), + $this->createMock( ParserFactory::class ), + $this->createMock( GlobalIdGenerator::class ), + $this->createMock( LanguageNameUtils::class ), + $this->createMock( MagicWordFactory::class ) + ) ); // DummyServicesTrait::getDummyMediaWikiTitleCodec $titleCodec = $this->getDummyMediaWikiTitleCodec(); diff --git a/tests/phpunit/unit/includes/content/FileContentHandlerTest.php b/tests/phpunit/unit/includes/content/FileContentHandlerTest.php index 3e3be27f1d7..85ddb1c4973 100644 --- a/tests/phpunit/unit/includes/content/FileContentHandlerTest.php +++ b/tests/phpunit/unit/includes/content/FileContentHandlerTest.php @@ -1,5 +1,18 @@ handler = new FileContentHandler(); + $this->handler = new FileContentHandler( + CONTENT_MODEL_WIKITEXT, + $this->createMock( TitleFactory::class ), + $this->createMock( ParserFactory::class ), + $this->createMock( GlobalIdGenerator::class ), + $this->createMock( LanguageNameUtils::class ), + $this->createMock( MagicWordFactory::class ) + ); } public function testIndexMapping() { diff --git a/tests/phpunit/unit/includes/content/WikitextContentHandlerTest.php b/tests/phpunit/unit/includes/content/WikitextContentHandlerTest.php index b4f80cf0e90..1f9be9847e3 100644 --- a/tests/phpunit/unit/includes/content/WikitextContentHandlerTest.php +++ b/tests/phpunit/unit/includes/content/WikitextContentHandlerTest.php @@ -2,11 +2,16 @@ namespace MediaWiki\Tests\Unit; +use MagicWordFactory; +use MediaWiki\Languages\LanguageNameUtils; use MediaWiki\Revision\SlotRecord; use MediaWiki\Revision\SlotRenderingProvider; +use MediaWiki\Title\TitleFactory; use MediaWikiUnitTestCase; use MWException; +use ParserFactory; use Title; +use Wikimedia\UUID\GlobalIdGenerator; use WikitextContent; use WikitextContentHandler; @@ -18,12 +23,23 @@ use WikitextContentHandler; */ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { + private function newWikitextContentHandler(): WikitextContentHandler { + return new WikitextContentHandler( + CONTENT_MODEL_WIKITEXT, + $this->createMock( TitleFactory::class ), + $this->createMock( ParserFactory::class ), + $this->createMock( GlobalIdGenerator::class ), + $this->createMock( LanguageNameUtils::class ), + $this->createMock( MagicWordFactory::class ) + ); + } + /** * @covers ::serializeContent */ public function testSerializeContent() { $content = new WikitextContent( 'hello world' ); - $handler = new WikitextContentHandler(); + $handler = $this->newWikitextContentHandler(); $this->assertEquals( 'hello world', $handler->serializeContent( $content ) ); $this->assertEquals( @@ -39,7 +55,7 @@ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { * @covers ::unserializeContent */ public function testUnserializeContent() { - $handler = new WikitextContentHandler(); + $handler = $this->newWikitextContentHandler(); $content = $handler->unserializeContent( 'hello world' ); $this->assertEquals( 'hello world', $content->getText() ); @@ -55,7 +71,7 @@ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { * @covers WikitextContentHandler::makeEmptyContent */ public function testMakeEmptyContent() { - $handler = new WikitextContentHandler(); + $handler = $this->newWikitextContentHandler(); $content = $handler->makeEmptyContent(); $this->assertTrue( $content->isEmpty() ); @@ -75,7 +91,7 @@ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { * @covers ::isSupportedFormat */ public function testIsSupportedFormat( $format, $supported ) { - $handler = new WikitextContentHandler(); + $handler = $this->newWikitextContentHandler(); $this->assertEquals( $supported, $handler->isSupportedFormat( $format ) ); } @@ -83,7 +99,7 @@ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { * @covers ::supportsDirectEditing */ public function testSupportsDirectEditing() { - $handler = new WikiTextContentHandler(); + $handler = $this->newWikiTextContentHandler(); $this->assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' ); } @@ -94,7 +110,7 @@ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { $title = $this->createMock( Title::class ); $content = new WikitextContent( '' ); $srp = $this->createMock( SlotRenderingProvider::class ); - $handler = new WikitextContentHandler(); + $handler = $this->newWikitextContentHandler(); $updates = $handler->getSecondaryDataUpdates( $title, $content, SlotRecord::MAIN, $srp ); @@ -106,7 +122,7 @@ class WikitextContentHandlerTest extends MediaWikiUnitTestCase { */ public function testGetDeletionUpdates() { $title = $this->createMock( Title::class ); - $handler = new WikitextContentHandler(); + $handler = $this->newWikitextContentHandler(); $updates = $handler->getDeletionUpdates( $title, SlotRecord::MAIN ); $this->assertEquals( [], $updates );