X-Git-Url: https://git.cyclocoop.org/%242?a=blobdiff_plain;f=includes%2Fresourceloader%2FResourceLoader.php;h=9892b157059b034eed6cb1782b948e1345f0f4bc;hb=089c2aa550a06fe91a3b6873f1a7d452573eb2e9;hp=6eb9908a64a91cbedfa40c172c1b7fa7081a5559;hpb=672808c859d570fc66f8cf927237ea3f1e78eb9e;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index 6eb9908a64..9892b15705 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -36,66 +36,41 @@ use Wikimedia\WrappedString; * https://www.mediawiki.org/wiki/ResourceLoader */ class ResourceLoader implements LoggerAwareInterface { - /** @var int */ - const CACHE_VERSION = 8; + /** @var Config $config */ + protected $config; + /** @var MessageBlobStore */ + protected $blobStore; - /** @var bool */ - protected static $debugMode = null; + /** @var LoggerInterface */ + private $logger; - /** - * Module name/ResourceLoaderModule object pairs - * @var array - */ + /** @var ResourceLoaderModule[] Map of (module name => ResourceLoaderModule) */ protected $modules = []; - - /** - * Associative array mapping module name to info associative array - * @var array - */ + /** @var array[] Map of (module name => associative info array) */ protected $moduleInfos = []; - - /** @var Config $config */ - protected $config; - /** * Associative array mapping framework ids to a list of names of test suite modules * like [ 'qunit' => [ 'mediawiki.tests.qunit.suites', 'ext.foo.tests', ... ], ... ] * @var array */ protected $testModuleNames = []; + /** @var string[] List of module names that contain QUnit test suites */ + protected $testSuiteModuleNames = []; - /** - * E.g. [ 'source-id' => 'http://.../load.php' ] - * @var array - */ + /** @var array Map of (source => path); E.g. [ 'source-id' => 'http://.../load.php' ] */ protected $sources = []; - - /** - * Errors accumulated during current respond() call. - * @var array - */ + /** @var array Errors accumulated during current respond() call */ protected $errors = []; - - /** - * List of extra HTTP response headers provided by loaded modules. - * - * Populated by makeModuleResponse(). - * - * @var array - */ + /** @var string[] Extra HTTP response headers from modules loaded in makeModuleResponse() */ protected $extraHeaders = []; - /** - * @var MessageBlobStore - */ - protected $blobStore; + /** @var bool */ + protected static $debugMode = null; - /** - * @var LoggerInterface - */ - private $logger; + /** @var int */ + const CACHE_VERSION = 8; - /** @var string JavaScript / CSS pragma to disable minification. **/ + /** @var string JavaScript / CSS pragma to disable minification. * */ const FILTER_NOMIN = '/*@nomin*/'; /** @@ -297,13 +272,13 @@ class ResourceLoader implements LoggerAwareInterface { /** * Register a module with the ResourceLoader system. * - * @param mixed $name Name of module as a string or List of name/object pairs as an array - * @param array|null $info Module info array. For backwards compatibility with 1.17alpha, - * this may also be a ResourceLoaderModule object. Optional when using - * multiple-registration calling style. + * @param string|array[] $name Module name as a string or, array of module info arrays + * keyed by name. + * @param array|null $info Module info array. When using the first parameter to register + * multiple modules at once, this parameter is optional. * @throws MWException If a duplicate module registration is attempted * @throws MWException If a module name contains illegal characters (pipes or commas) - * @throws MWException If something other than a ResourceLoaderModule is being registered + * @throws InvalidArgumentException If the module info is not an array */ public function register( $name, $info = null ) { $moduleSkinStyles = $this->config->get( 'ResourceModuleSkinStyles' ); @@ -320,29 +295,21 @@ class ResourceLoader implements LoggerAwareInterface { ); } - // Check $name for validity + // Check validity if ( !self::isValidModuleName( $name ) ) { throw new MWException( "ResourceLoader module name '$name' is invalid, " . "see ResourceLoader::isValidModuleName()" ); } - - // Attach module - if ( $info instanceof ResourceLoaderModule ) { - $this->moduleInfos[$name] = [ 'object' => $info ]; - $info->setName( $name ); - $this->modules[$name] = $info; - } elseif ( is_array( $info ) ) { - // New calling convention - $this->moduleInfos[$name] = $info; - } else { - throw new MWException( - 'ResourceLoader module info type error for module \'' . $name . - '\': expected ResourceLoaderModule or array (got: ' . gettype( $info ) . ')' + if ( !is_array( $info ) ) { + throw new InvalidArgumentException( + 'Invalid module info for "' . $name . '": expected array, got ' . gettype( $info ) ); } - // Last-minute changes + // Attach module + $this->moduleInfos[$name] = $info; + // Last-minute changes // Apply custom skin-defined styles to existing modules. if ( $this->isFileModule( $name ) ) { foreach ( $moduleSkinStyles as $skinName => $skinStyles ) { @@ -382,6 +349,7 @@ class ResourceLoader implements LoggerAwareInterface { /** * @internal For use by ServiceWiring only + * @codeCoverageIgnore */ public function registerTestModules() { global $IP; @@ -392,39 +360,37 @@ class ResourceLoader implements LoggerAwareInterface { . 'Edit your LocalSettings.php to enable it.' ); } - $testModules = [ - 'qunit' => [], - ]; + // This has a 'qunit' key for compat with the below hook. + $testModulesMeta = [ 'qunit' => [] ]; // Get test suites from extensions // Avoid PHP 7.1 warning from passing $this by reference $rl = $this; - Hooks::run( 'ResourceLoaderTestModules', [ &$testModules, &$rl ] ); + Hooks::run( 'ResourceLoaderTestModules', [ &$testModulesMeta, &$rl ] ); $extRegistry = ExtensionRegistry::getInstance(); // In case of conflict, the deprecated hook has precedence. - $testModules['qunit'] += $extRegistry->getAttribute( 'QUnitTestModules' ); + $testModules = $testModulesMeta['qunit'] + $extRegistry->getAttribute( 'QUnitTestModules' ); - // Add the QUnit testrunner as implicit dependency to extension test suites. - foreach ( $testModules['qunit'] as &$module ) { - // Shuck any single-module dependency as an array + $testSuiteModuleNames = []; + foreach ( $testModules as $name => &$module ) { + // Turn any single-module dependency into an array if ( isset( $module['dependencies'] ) && is_string( $module['dependencies'] ) ) { $module['dependencies'] = [ $module['dependencies'] ]; } + // Ensure the testrunner loads before any test suites $module['dependencies'][] = 'test.mediawiki.qunit.testrunner'; - } - // Get core test suites - $testModules['qunit'] = - ( include "$IP/tests/qunit/QUnitTestResources.php" ) + $testModules['qunit']; + // Keep track of the test suites to load on SpecialJavaScriptTest + $testSuiteModuleNames[] = $name; + } - foreach ( $testModules as $id => $names ) { - // Register test modules - $this->register( $testModules[$id] ); + // Core test suites (their names have further precedence). + $testModules = ( include "$IP/tests/qunit/QUnitTestResources.php" ) + $testModules; + $testSuiteModuleNames[] = 'test.mediawiki.qunit.suites'; - // Keep track of their names so that they can be loaded together - $this->testModuleNames[$id] = array_keys( $testModules[$id] ); - } + $this->register( $testModules ); + $this->testSuiteModuleNames = $testSuiteModuleNames; } /** @@ -478,26 +444,14 @@ class ResourceLoader implements LoggerAwareInterface { } /** - * Get a list of test module names for one (or all) frameworks. - * - * If the given framework id is unknkown, or if the in-object variable is not an array, - * then it will return an empty array. + * Get a list of module names with QUnit test suites. * - * @param string $framework Get only the test module names for one - * particular framework (optional) + * @internal For use by SpecialJavaScriptTest only * @return array + * @codeCoverageIgnore */ - public function getTestModuleNames( $framework = 'all' ) { - /** @todo api siteinfo prop testmodulenames modulenames */ - if ( $framework == 'all' ) { - return $this->testModuleNames; - } elseif ( isset( $this->testModuleNames[$framework] ) - && is_array( $this->testModuleNames[$framework] ) - ) { - return $this->testModuleNames[$framework]; - } else { - return []; - } + public function getTestSuiteModuleNames() { + return $this->testSuiteModuleNames; } /** @@ -528,23 +482,18 @@ class ResourceLoader implements LoggerAwareInterface { // No such module return null; } - // Construct the requested object + // Construct the requested module object $info = $this->moduleInfos[$name]; - /** @var ResourceLoaderModule $object */ - if ( isset( $info['object'] ) ) { - // Object given in info array - $object = $info['object']; - } elseif ( isset( $info['factory'] ) ) { + if ( isset( $info['factory'] ) ) { + /** @var ResourceLoaderModule $object */ $object = call_user_func( $info['factory'], $info ); - $object->setConfig( $this->getConfig() ); - $object->setLogger( $this->logger ); } else { $class = $info['class'] ?? ResourceLoaderFileModule::class; /** @var ResourceLoaderModule $object */ $object = new $class( $info ); - $object->setConfig( $this->getConfig() ); - $object->setLogger( $this->logger ); } + $object->setConfig( $this->getConfig() ); + $object->setLogger( $this->logger ); $object->setName( $name ); $this->modules[$name] = $object; } @@ -563,9 +512,6 @@ class ResourceLoader implements LoggerAwareInterface { return false; } $info = $this->moduleInfos[$name]; - if ( isset( $info['object'] ) ) { - return false; - } return !isset( $info['factory'] ) && ( // The implied default for 'class' is ResourceLoaderFileModule !isset( $info['class'] ) || @@ -755,6 +701,8 @@ class ResourceLoader implements LoggerAwareInterface { if ( $this->tryRespondFromFileCache( $fileCache, $context, $etag ) ) { return; // output handled } + } else { + $fileCache = null; } // Generate a response @@ -769,15 +717,17 @@ class ResourceLoader implements LoggerAwareInterface { } } - // Save response to file cache unless there are errors - if ( isset( $fileCache ) && !$this->errors && $missing === [] ) { - // Cache single modules and images...and other requests if there are enough hits - if ( ResourceFileCache::useFileCache( $context ) ) { - if ( $fileCache->isCacheWorthy() ) { - $fileCache->saveText( $response ); - } else { - $fileCache->incrMissesRecent( $context->getRequest() ); - } + // Consider saving the response to file cache (unless there are errors). + if ( $fileCache && + !$this->errors && + $missing === [] && + ResourceFileCache::useFileCache( $context ) + ) { + if ( $fileCache->isCacheWorthy() ) { + // There were enough hits, save the response to the cache + $fileCache->saveText( $response ); + } else { + $fileCache->incrMissesRecent( $context->getRequest() ); } } @@ -1259,11 +1209,9 @@ MESSAGE; * @return string JavaScript code */ public static function makeMessageSetScript( $messages ) { - return Xml::encodeJsCall( - 'mw.messages.set', - [ (object)$messages ], - self::inDebugMode() - ); + return 'mw.messages.set(' + . self::encodeJsonForScript( (object)$messages ) + . ');'; } /** @@ -1347,11 +1295,9 @@ MESSAGE; if ( !is_array( $states ) ) { $states = [ $states => $state ]; } - return Xml::encodeJsCall( - 'mw.loader.state', - [ $states ], - self::inDebugMode() - ); + return 'mw.loader.state(' + . self::encodeJsonForScript( $states ) + . ');'; } private static function isEmptyObject( stdClass $obj ) { @@ -1435,11 +1381,9 @@ MESSAGE; array_walk( $modules, [ self::class, 'trimArray' ] ); - return Xml::encodeJsCall( - 'mw.loader.register', - [ $modules ], - self::inDebugMode() - ); + return 'mw.loader.register(' + . self::encodeJsonForScript( $modules ) + . ');'; } /** @@ -1460,11 +1404,9 @@ MESSAGE; if ( !is_array( $sources ) ) { $sources = [ $sources => $loadUrl ]; } - return Xml::encodeJsCall( - 'mw.loader.addSource', - [ $sources ], - self::inDebugMode() - ); + return 'mw.loader.addSource(' + . self::encodeJsonForScript( $sources ) + . ');'; } /**