TL;DR:
when myExtension::onExtensionLoad( $info )executes $myConfig = \MediaWiki\MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'myExtension' ); we get a ConfigException. Ideas to fix this can be found further down below. Look for Ideas to solve this.
Problem
in my extension.json I have
"ConfigRegistry": {
"myExtension": "GlobalVarConfig::newInstance"
},as well as
"callback": "myExtension\\Setup::onExtensionLoad",
When I am trying to do
public static function onExtensionLoad( $info ) {
$myConfig = \MediaWiki\MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'myExtension' );
//...
}I am getting
PHP Fatal error: Uncaught exception 'ConfigException' with message 'No registered builder available for myExtension.' in /var/www/mediawiki-1.30.0/includes/config/ConfigFactory.php:131
Stack trace:
#0 /var/www/mediawiki-1.30.0/extensions/MyExtension/src/Setup.php(51): ConfigFactory->makeConfig('myExtension')
#1 [internal function]: MyExtension\Setup::onExtensionLoad(Array)
#2 /var/www/mediawiki-1.30.0/includes/registration/ExtensionRegistry.php(343): call_user_func('BootstrapCompon...', Array)
#3 /var/www/mediawiki-1.30.0/includes/registration/ExtensionRegistry.php(149): ExtensionRegistry->exportExtractedData(Array)
#4 /var/www/mediawiki-1.30.0/includes/Setup.php(40): ExtensionRegistry->loadFromQueue()
#5 /var/www/mediawiki-1.30.0/maintenance/doMaintenance.php(79): require_once('/var/www/medi...')
#6 /var/www/mediawiki-1.30.0/tests/phpunit/phpunit.php(172): require('/var/www/medi...')
#7 {main}
thrown in /var/www/mediawiki-1.30.0/includes/config/ConfigFactory.php on line 131I did some digging and found out that
- /includes/Setup.php calls ExtensionRegistry->loadFromQueue() in line 40
- loadFromQueue generates a LocalServerObjectCache (in line 135), which through some intermediary calls accesses the MainConfig
- MainConfig has a Closure in line 102 in ServiceWiring that produces a ConfigFactory with return $services->getConfigFactory()->makeConfig( 'main' );
- that call finally generates a MediaWiki\Services\ServiceContainer->createService('ConfigFactory') for 'main' in line 361
This Closure is executed:
function ( MediaWikiServices $services ) {
// Use the bootstrap config to initialize the ConfigFactory.
$registry = $services->getBootstrapConfig()->get( 'ConfigRegistry' );
$factory = new ConfigFactory();
foreach ( $registry as $name => $callback ) {
$factory->register( $name, $callback );
}
return $factory;
}When the closure is executed, the ConfigFactory object is created with the contents of wgConfigRegistry at the time:
Array
(
[main] => GlobalVarConfig::newInstance
)That, as you can see, does not yet include the extension config registry (remember we are at an early stage of ExtensionRegistry->loadFromQueue()). But unfortunately on ConfigFactory creation, the contents of wgConfigRegistry are stored and no updates will be taken.
Looking further into the excecution of the ExtensionRegistry: On line 146 or 149 ExtensionRegistry->exportExtractedData( $data ); is called which (after merging a bunch of arrays) executes the callbacks in line 342. You can find a complete call stack at [0].
Q: Why does the ConfigRegistry work at all for Extensions?
A: /includes/Setup.php (after registering Extensions and doing a bunch of other stuff) 'clears' all Services in line 533 with
MediaWikiServices::resetGlobalInstance( new GlobalVarConfig(), 'quick' );
Ideas to solve this
- call MediaWikiServices::resetGlobalInstance( new GlobalVarConfig(), 'quick' ); before the execution of the callback hooks in ExtensionRegistry
- have ExtensionRegistry call ConfigFactory::register for every extension before the callbacks are executed
- do just that, but in ExtensionProcessor while auto-registering the ConfigRegistry
- extensions have to register their own config in the onload callback.
Maybe this could be taken care of when addressing T155154? rMWc7cc4ecd81bf is awaiting merge and could be augmented.
[0]:
This dump is taken with a 1.30.0. Current master, however, also throws the described exception.
#0 [internal function]: MediaWiki\Services\ServiceContainer->{closure}(Object(MediaWiki\MediaWikiServices))
#1 /var/www/mediawiki-1.30.0/includes/services/ServiceContainer.php(361): call_user_func_array(Object(Closure), Array)
#2 /var/www/mediawiki-1.30.0/includes/services/ServiceContainer.php(344): MediaWiki\Services\ServiceContainer->createService('ConfigFactory')
#3 /var/www/mediawiki-1.30.0/includes/MediaWikiServices.php(411): MediaWiki\Services\ServiceContainer->getService('ConfigFactory')
#4 /var/www/mediawiki-1.30.0/includes/ServiceWiring.php(104): MediaWiki\MediaWikiServices->getConfigFactory()
#5 [internal function]: MediaWiki\Services\ServiceContainer->{closure}(Object(MediaWiki\MediaWikiServices))
#6 /var/www/mediawiki-1.30.0/includes/services/ServiceContainer.php(361): call_user_func_array(Object(Closure), Array)
#7 /var/www/mediawiki-1.30.0/includes/services/ServiceContainer.php(344): MediaWiki\Services\ServiceContainer->createService('MainConfig')
#8 /var/www/mediawiki-1.30.0/includes/MediaWikiServices.php(422): MediaWiki\Services\ServiceContainer->getService('MainConfig')
#9 /var/www/mediawiki-1.30.0/includes/ServiceWiring.php(386): MediaWiki\MediaWikiServices->getMainConfig()
#10 [internal function]: MediaWiki\Services\ServiceContainer->{closure}(Object(MediaWiki\MediaWikiServices))
#11 /var/www/mediawiki-1.30.0/includes/services/ServiceContainer.php(361): call_user_func_array(Object(Closure), Array)
#12 /var/www/mediawiki-1.30.0/includes/services/ServiceContainer.php(344): MediaWiki\Services\ServiceContainer->createService('LocalServerObje...')
#13 /var/www/mediawiki-1.30.0/includes/MediaWikiServices.php(658): MediaWiki\Services\ServiceContainer->getService('LocalServerObje...')
#14 /var/www/mediawiki-1.30.0/includes/registration/ExtensionRegistry.php(135): MediaWiki\MediaWikiServices->getLocalServerObjectCache()
#15 /var/www/mediawiki-1.30.0/includes/Setup.php(40): ExtensionRegistry->loadFromQueue()
#16 /var/www/mediawiki-1.30.0/includes/WebStart.php(114): require_once('/var/www/medi...')
#17 /var/www/mediawiki-1.30.0/index.php(40): require('/var/www/medi...')
#18 {main}