From 2b3762ecb4ab9916ce1af50974f9f6cae6abeb14 Mon Sep 17 00:00:00 2001 From: daniel Date: Thu, 4 May 2017 18:10:28 +0200 Subject: [PATCH] resourceloader: Allow modules to be registered via a factory callback This should work the same way as registering API modules via a factory callback. Point in case: Ifb8611473a971 could avoid global state using this mechanism. Change-Id: Ifbf29006141ce2a2dff42efa352f406502a06bc6 --- RELEASE-NOTES-1.30 | 3 +++ docs/extension.schema.v2.json | 12 +++++++++++- includes/resourceloader/ResourceLoader.php | 4 ++++ .../resourceloader/ResourceLoaderTest.php | 17 +++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/RELEASE-NOTES-1.30 b/RELEASE-NOTES-1.30 index fbe23ab7ac..03ae7c2062 100644 --- a/RELEASE-NOTES-1.30 +++ b/RELEASE-NOTES-1.30 @@ -17,6 +17,9 @@ production. This is intended for extensions that want control over the instantiation of their jobs, to allow for proper dependency injection. +* $wgResourceModules may now specify callback functions as an alternative + to plain class names, using the 'factory' key in the module description + array. This allows dependency injection to be used for ResourceLoader modules. === New features in 1.30 === * (T37247) Output from Parser::parse() will now be wrapped in a div with diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index d5a9b65215..6345632fcc 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -318,7 +318,7 @@ } }, { - "description": "An arbitrary ResourceLoaderModule definition", + "description": "An arbitrary ResourceLoaderModule definition by class", "properties": { "class": { "type": "string", @@ -326,6 +326,16 @@ } }, "required": ["class"] + }, + { + "description": "An arbitrary ResourceLoaderModule definition with instantiator", + "properties": { + "factory": { + "type": "string", + "description": "A static instantiator function for creating the ResourceLoaderModule object." + } + }, + "required": ["factory"] } ] } diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index 3cd7821ed8..0d1284062c 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -541,6 +541,10 @@ class ResourceLoader implements LoggerAwareInterface { if ( isset( $info['object'] ) ) { // Object given in info array $object = $info['object']; + } elseif ( isset( $info['factory'] ) ) { + $object = call_user_func( $info['factory'], $info ); + $object->setConfig( $this->getConfig() ); + $object->setLogger( $this->logger ); } else { if ( !isset( $info['class'] ) ) { $class = 'ResourceLoaderFileModule'; diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php index af3212a863..0833047a0c 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php @@ -143,6 +143,23 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { ); } + /** + * @covers ResourceLoader::getModule + */ + public function testGetModuleFactory() { + $factory = function( array $info ) { + $this->assertArrayHasKey( 'kitten', $info ); + return new ResourceLoaderTestModule( $info ); + }; + + $rl = new EmptyResourceLoader(); + $rl->register( 'test', [ 'factory' => $factory, 'kitten' => 'little ball of fur' ] ); + $this->assertInstanceOf( + ResourceLoaderTestModule::class, + $rl->getModule( 'test' ) + ); + } + /** * @covers ResourceLoader::getModule */ -- 2.20.1