/** * Get a string identifying the current version of this module in a given context. * * Whenever anything happens that changes the module's response (e.g. scripts, styles, and * messages) this value must change. This value is used to store module responses in cache. * (Both client-side and server-side.) * * It is not recommended to override this directly. Use getDefinitionSummary() instead. * If overridden, one must call the parent getVersionHash(), append data and re-hash. * * This method should be quick because it is frequently run by ResourceLoaderStartUpModule to * propagate changes to the client and effectively invalidate cache. * * For backward-compatibility, the following optional data providers are automatically included: * * - getModifiedTime() * - getModifiedHash() * * @since 1.26 * @param ResourceLoaderContext $context * @return string Hash (should use ResourceLoader::makeHash) */ public function getVersionHash(ResourceLoaderContext $context) { // The startup module produces a manifest with versions representing the entire module. // Typically, the request for the startup module itself has only=scripts. That must apply // only to the startup module content, and not to the module version computed here. $context = new DerivativeResourceLoaderContext($context); $context->setModules(array()); // Version hash must cover all resources, regardless of startup request itself. $context->setOnly(null); // Compute version hash based on content, not debug urls. $context->setDebug(false); // Cache this somewhat expensive operation. Especially because some classes // (e.g. startup module) iterate more than once over all modules to get versions. $contextHash = $context->getHash(); if (!array_key_exists($contextHash, $this->versionHash)) { if ($this->enableModuleContentVersion()) { // Detect changes directly $str = json_encode($this->getModuleContent($context)); } else { // Infer changes based on definition and other metrics $summary = $this->getDefinitionSummary($context); if (!isset($summary['_cacheEpoch'])) { throw new LogicException('getDefinitionSummary must call parent method'); } $str = json_encode($summary); $mtime = $this->getModifiedTime($context); if ($mtime !== null) { // Support: MediaWiki 1.25 and earlier $str .= strval($mtime); } $mhash = $this->getModifiedHash($context); if ($mhash !== null) { // Support: MediaWiki 1.25 and earlier $str .= strval($mhash); } } $this->versionHash[$contextHash] = ResourceLoader::makeHash($str); } return $this->versionHash[$contextHash]; }
/** * Get registration code for all modules. * * @param ResourceLoaderContext $context * @return string JavaScript code for registering all modules with the client loader */ public function getModuleRegistrations(ResourceLoaderContext $context) { $resourceLoader = $context->getResourceLoader(); $target = $context->getRequest()->getVal('target', 'desktop'); // Bypass target filter if this request is Special:JavaScriptTest. // To prevent misuse in production, this is only allowed if testing is enabled server-side. $byPassTargetFilter = $this->getConfig()->get('EnableJavaScriptTest') && $target === 'test'; $out = ''; $registryData = []; // Get registry data foreach ($resourceLoader->getModuleNames() as $name) { $module = $resourceLoader->getModule($name); $moduleTargets = $module->getTargets(); if (!$byPassTargetFilter && !in_array($target, $moduleTargets)) { continue; } if ($module->isRaw()) { // Don't register "raw" modules (like 'jquery' and 'mediawiki') client-side because // depending on them is illegal anyway and would only lead to them being reloaded // causing any state to be lost (like jQuery plugins, mw.config etc.) continue; } $versionHash = $module->getVersionHash($context); if (strlen($versionHash) !== 8) { $context->getLogger()->warning("Module '{module}' produced an invalid version hash: '{version}'.", ['module' => $name, 'version' => $versionHash]); // Module implementation either broken or deviated from ResourceLoader::makeHash // Asserted by tests/phpunit/structure/ResourcesTest. $versionHash = ResourceLoader::makeHash($versionHash); } $skipFunction = $module->getSkipFunction(); if ($skipFunction !== null && !ResourceLoader::inDebugMode()) { $skipFunction = ResourceLoader::filter('minify-js', $skipFunction); } $registryData[$name] = ['version' => $versionHash, 'dependencies' => $module->getDependencies($context), 'group' => $module->getGroup(), 'source' => $module->getSource(), 'skip' => $skipFunction]; } self::compileUnresolvedDependencies($registryData); // Register sources $out .= ResourceLoader::makeLoaderSourcesScript($resourceLoader->getSources()); // Figure out the different call signatures for mw.loader.register $registrations = []; foreach ($registryData as $name => $data) { // Call mw.loader.register(name, version, dependencies, group, source, skip) $registrations[] = [$name, $data['version'], $data['dependencies'], $data['group'], $data['source'] === 'local' ? null : $data['source'], $data['skip']]; } // Register modules $out .= "\n" . ResourceLoader::makeLoaderRegisterScript($registrations); return $out; }
/** * Get registration code for all modules. * * @param ResourceLoaderContext $context * @return string JavaScript code for registering all modules with the client loader */ public function getModuleRegistrations(ResourceLoaderContext $context) { $resourceLoader = $context->getResourceLoader(); $target = $context->getRequest()->getVal('target', 'desktop'); $out = ''; $registryData = array(); // Get registry data foreach ($resourceLoader->getModuleNames() as $name) { $module = $resourceLoader->getModule($name); $moduleTargets = $module->getTargets(); if (!in_array($target, $moduleTargets)) { continue; } if ($module->isRaw()) { // Don't register "raw" modules (like 'jquery' and 'mediawiki') client-side because // depending on them is illegal anyway and would only lead to them being reloaded // causing any state to be lost (like jQuery plugins, mw.config etc.) continue; } $versionHash = $module->getVersionHash($context); if (strlen($versionHash) !== 8) { // Module implementation either broken or deviated from ResourceLoader::makeHash // Asserted by tests/phpunit/structure/ResourcesTest. $versionHash = ResourceLoader::makeHash($versionHash); } $skipFunction = $module->getSkipFunction(); if ($skipFunction !== null && !ResourceLoader::inDebugMode()) { $skipFunction = $resourceLoader->filter('minify-js', $skipFunction, false); } $registryData[$name] = array('version' => $versionHash, 'dependencies' => $module->getDependencies($context), 'group' => $module->getGroup(), 'source' => $module->getSource(), 'loader' => $module->getLoaderScript(), 'skip' => $skipFunction); } self::compileUnresolvedDependencies($registryData); // Register sources $out .= ResourceLoader::makeLoaderSourcesScript($resourceLoader->getSources()); // Concatenate module loader scripts and figure out the different call // signatures for mw.loader.register $registrations = array(); foreach ($registryData as $name => $data) { if ($data['loader'] !== false) { $out .= ResourceLoader::makeCustomLoaderScript($name, $data['version'], $data['dependencies'], $data['group'], $data['source'], $data['loader']); continue; } // Call mw.loader.register(name, version, dependencies, group, source, skip) $registrations[] = array($name, $data['version'], $data['dependencies'], $data['group'], $data['source'] === 'local' ? null : $data['source'], $data['skip']); } // Register modules $out .= "\n" . ResourceLoader::makeLoaderRegisterScript($registrations); return $out; }