/** * @param ResourceLoaderContext $context * @return array */ protected function getConfigSettings($context) { $hash = $context->getHash(); if (isset($this->configVars[$hash])) { return $this->configVars[$hash]; } global $wgContLang; $mainPage = Title::newMainPage(); /** * Namespace related preparation * - wgNamespaceIds: Key-value pairs of all localized, canonical and aliases for namespaces. * - wgCaseSensitiveNamespaces: Array of namespaces that are case-sensitive. */ $namespaceIds = $wgContLang->getNamespaceIds(); $caseSensitiveNamespaces = array(); foreach (MWNamespace::getCanonicalNamespaces() as $index => $name) { $namespaceIds[$wgContLang->lc($name)] = $index; if (!MWNamespace::isCapitalized($index)) { $caseSensitiveNamespaces[] = $index; } } $conf = $this->getConfig(); // Build list of variables $vars = array('wgLoadScript' => wfScript('load'), 'debug' => $context->getDebug(), 'skin' => $context->getSkin(), 'stylepath' => $conf->get('StylePath'), 'wgUrlProtocols' => wfUrlProtocols(), 'wgArticlePath' => $conf->get('ArticlePath'), 'wgScriptPath' => $conf->get('ScriptPath'), 'wgScriptExtension' => '.php', 'wgScript' => wfScript(), 'wgSearchType' => $conf->get('SearchType'), 'wgVariantArticlePath' => $conf->get('VariantArticlePath'), 'wgActionPaths' => (object) $conf->get('ActionPaths'), 'wgServer' => $conf->get('Server'), 'wgServerName' => $conf->get('ServerName'), 'wgUserLanguage' => $context->getLanguage(), 'wgContentLanguage' => $wgContLang->getCode(), 'wgTranslateNumerals' => $conf->get('TranslateNumerals'), 'wgVersion' => $conf->get('Version'), 'wgEnableAPI' => $conf->get('EnableAPI'), 'wgEnableWriteAPI' => $conf->get('EnableWriteAPI'), 'wgMainPageTitle' => $mainPage->getPrefixedText(), 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(), 'wgNamespaceIds' => $namespaceIds, 'wgContentNamespaces' => MWNamespace::getContentNamespaces(), 'wgSiteName' => $conf->get('Sitename'), 'wgDBname' => $conf->get('DBname'), 'wgExtraSignatureNamespaces' => $conf->get('ExtraSignatureNamespaces'), 'wgAvailableSkins' => Skin::getSkinNames(), 'wgExtensionAssetsPath' => $conf->get('ExtensionAssetsPath'), 'wgCookiePrefix' => $conf->get('CookiePrefix'), 'wgCookieDomain' => $conf->get('CookieDomain'), 'wgCookiePath' => $conf->get('CookiePath'), 'wgCookieExpiration' => $conf->get('CookieExpiration'), 'wgResourceLoaderMaxQueryLength' => $conf->get('ResourceLoaderMaxQueryLength'), 'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces, 'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass(Title::legalChars()), 'wgResourceLoaderStorageVersion' => $conf->get('ResourceLoaderStorageVersion'), 'wgResourceLoaderStorageEnabled' => $conf->get('ResourceLoaderStorageEnabled'), 'wgResourceLoaderLegacyModules' => self::getLegacyModules(), 'wgForeignUploadTargets' => $conf->get('ForeignUploadTargets'), 'wgEnableUploads' => $conf->get('EnableUploads')); Hooks::run('ResourceLoaderGetConfigVars', array(&$vars)); $this->configVars[$hash] = $vars; return $this->configVars[$hash]; }
/** * @param ResourceLoaderContext $context * @return array|int|mixed */ public function getModifiedTime(ResourceLoaderContext $context) { $hash = $context->getHash(); if (!isset($this->modifiedTime[$hash])) { $this->modifiedTime[$hash] = wfTimestamp(TS_UNIX, $context->getUserObj()->getTouched()); } return $this->modifiedTime[$hash]; }
/** * @param $context ResourceLoaderContext * @return array|int|Mixed */ public function getModifiedTime(ResourceLoaderContext $context) { $hash = $context->getHash(); if (isset($this->modifiedTime[$hash])) { return $this->modifiedTime[$hash]; } global $wgUser; return $this->modifiedTime[$hash] = wfTimestamp(TS_UNIX, $wgUser->getTouched()); }
public function getModifiedTime(ResourceLoaderContext $context) { $hash = $context->getHash(); if (isset($this->modifiedTime[$hash])) { return $this->modifiedTime[$hash]; } global $wgUser; if ($context->getUser() === $wgUser->getName()) { return $this->modifiedTime[$hash] = $wgUser->getTouched(); } else { return 1; } }
public function testTypicalRequest() { $ctx = new ResourceLoaderContext($this->getResourceLoader(), new FauxRequest(['debug' => 'false', 'lang' => 'zh', 'modules' => 'foo|foo.quux,baz,bar|baz.quux', 'only' => 'styles', 'skin' => 'fallback'])); // Request parameters $this->assertEquals($ctx->getModules(), ['foo', 'foo.quux', 'foo.baz', 'foo.bar', 'baz.quux']); $this->assertEquals(false, $ctx->getDebug()); $this->assertEquals('zh', $ctx->getLanguage()); $this->assertEquals('styles', $ctx->getOnly()); $this->assertEquals('fallback', $ctx->getSkin()); $this->assertEquals(null, $ctx->getUser()); // Misc $this->assertEquals('ltr', $ctx->getDirection()); $this->assertEquals('zh|fallback|||styles|||||', $ctx->getHash()); }
/** * Construct an ResourceFileCache from a context * @param $context ResourceLoaderContext * @return ResourceFileCache */ public static function newFromContext(ResourceLoaderContext $context) { $cache = new self(); if ($context->getOnly() === 'styles') { $cache->mType = 'css'; } else { $cache->mType = 'js'; } $modules = array_unique($context->getModules()); // remove duplicates sort($modules); // normalize the order (permutation => combination) $cache->mKey = sha1($context->getHash() . implode('|', $modules)); if (count($modules) == 1) { $cache->mCacheWorthy = true; // won't take up much space } return $cache; }
/** * @param $context ResourceLoaderContext * @return array|mixed */ public function getModifiedTime(ResourceLoaderContext $context) { global $IP, $wgCacheEpoch; $hash = $context->getHash(); if (isset($this->modifiedTime[$hash])) { return $this->modifiedTime[$hash]; } // Call preloadModuleInfo() on ALL modules as we're about // to call getModifiedTime() on all of them $loader = $context->getResourceLoader(); $loader->preloadModuleInfo($loader->getModuleNames(), $context); $this->modifiedTime[$hash] = filemtime("{$IP}/resources/startup.js"); // ATTENTION!: Because of the line above, this is not going to cause // infinite recursion - think carefully before making changes to this // code! $time = wfTimestamp(TS_UNIX, $wgCacheEpoch); foreach ($loader->getModuleNames() as $name) { $module = $loader->getModule($name); $time = max($time, $module->getModifiedTime($context)); } return $this->modifiedTime[$hash] = $time; }
/** * Get the modification times of all titles that would be loaded for * a given context. * @param $context ResourceLoaderContext: Context object * @return array( prefixed DB key => UNIX timestamp ), nonexistent titles are dropped */ protected function getTitleMtimes(ResourceLoaderContext $context) { $dbr = $this->getDB(); if (!$dbr) { // We're dealing with a subclass that doesn't have a DB return array(); } $hash = $context->getHash(); if (isset($this->titleMtimes[$hash])) { return $this->titleMtimes[$hash]; } $this->titleMtimes[$hash] = array(); $batch = new LinkBatch(); foreach ($this->getPages($context) as $titleText => $options) { $batch->addObj(Title::newFromText($titleText)); } if (!$batch->isEmpty()) { $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_touched'), $batch->constructSet('page', $dbr), __METHOD__); foreach ($res as $row) { $title = Title::makeTitle($row->page_namespace, $row->page_title); $this->titleMtimes[$hash][$title->getPrefixedDBkey()] = wfTimestamp(TS_UNIX, $row->page_touched); } } return $this->titleMtimes[$hash]; }
/** * Get the last modified timestamp of this module. * * Last modified timestamps are calculated from the highest last modified * timestamp of this module's constituent files as well as the files it * depends on. This function is context-sensitive, only performing * calculations on files relevant to the given language, skin and debug * mode. * * @param $context ResourceLoaderContext: Context in which to calculate * the modified time * @return Integer: UNIX timestamp * @see ResourceLoaderModule::getFileDependencies */ public function getModifiedTime(ResourceLoaderContext $context) { if (isset($this->modifiedTime[$context->getHash()])) { return $this->modifiedTime[$context->getHash()]; } wfProfileIn(__METHOD__); $files = array(); // Flatten style files into $files $styles = self::collateFilePathListByOption($this->styles, 'media', 'all'); foreach ($styles as $styleFiles) { $files = array_merge($files, $styleFiles); } $skinFiles = self::tryForKey(self::collateFilePathListByOption($this->skinStyles, 'media', 'all'), $context->getSkin(), 'default'); foreach ($skinFiles as $styleFiles) { $files = array_merge($files, $styleFiles); } // Final merge, this should result in a master list of dependent files $files = array_merge($files, $this->scripts, $context->getDebug() ? $this->debugScripts : array(), self::tryForKey($this->languageScripts, $context->getLanguage()), self::tryForKey($this->skinScripts, $context->getSkin(), 'default'), $this->loaderScripts); $files = array_map(array($this, 'getLocalPath'), $files); // File deps need to be treated separately because they're already prefixed $files = array_merge($files, $this->getFileDependencies($context->getSkin())); // If a module is nothing but a list of dependencies, we need to avoid // giving max() an empty array if (count($files) === 0) { wfProfileOut(__METHOD__); return $this->modifiedTime[$context->getHash()] = 1; } wfProfileIn(__METHOD__ . '-filemtime'); $filesMtime = max(array_map(array(__CLASS__, 'safeFilemtime'), $files)); wfProfileOut(__METHOD__ . '-filemtime'); $this->modifiedTime[$context->getHash()] = max($filesMtime, $this->getMsgBlobMtime($context->getLanguage())); wfProfileOut(__METHOD__); return $this->modifiedTime[$context->getHash()]; }
/** * @param ResourceLoaderContext $context * @return array|mixed */ public function getModifiedTime(ResourceLoaderContext $context) { global $IP, $wgCacheEpoch; $hash = $context->getHash(); if (isset($this->modifiedTime[$hash])) { return $this->modifiedTime[$hash]; } // Call preloadModuleInfo() on ALL modules as we're about // to call getModifiedTime() on all of them $loader = $context->getResourceLoader(); $loader->preloadModuleInfo($loader->getModuleNames(), $context); $time = max(wfTimestamp(TS_UNIX, $wgCacheEpoch), filemtime("{$IP}/resources/src/startup.js"), $this->getHashMtime($context)); // ATTENTION!: Because of the line below, this is not going to cause // infinite recursion - think carefully before making changes to this // code! // Pre-populate modifiedTime with something because the the loop over // all modules below includes the the startup module (this module). $this->modifiedTime[$hash] = 1; foreach ($loader->getModuleNames() as $name) { $module = $loader->getModule($name); $time = max($time, $module->getModifiedTime($context)); } $this->modifiedTime[$hash] = $time; return $this->modifiedTime[$hash]; }
/** * Get an array of this module's resources. Ready for serving to the web. * * @since 1.26 * @param ResourceLoaderContext $context * @return array */ public function getModuleContent(ResourceLoaderContext $context) { $contextHash = $context->getHash(); // Cache this expensive operation. This calls builds the scripts, styles, and messages // content which typically involves filesystem and/or database access. if (!array_key_exists($contextHash, $this->contents)) { $this->contents[$contextHash] = $this->buildContent($context); } return $this->contents[$contextHash]; }
/** * Get the modification times of all titles that would be loaded for * a given context. * Caches data from underlying layers. * * @param $context ResourceLoaderContext: Context object * @return array( prefixed DB key => UNIX timestamp ), nonexistent titles are dropped */ protected function getTitleMtimes(ResourceLoaderContext $context) { $hash = $context->getHash(); if (isset($this->titleMtimes[$hash])) { return $this->titleMtimes[$hash]; } $this->titleMtimes[$hash] = $this->reallyGetTitleMtimes($context); return $this->titleMtimes[$hash]; }
/** * Get the modification times of all titles that would be loaded for * a given context. * Caches data from underlying layers. * * @param $context ResourceLoaderContext: Context object * @return array( prefixed DB key => UNIX timestamp ), nonexistent titles are dropped */ protected function getTitleMtimes(ResourceLoaderContext $context) { global $wgMemc; wfProfileIn(__METHOD__); $hash = $context->getHash(); if (isset($this->titleMtimes[$hash])) { wfProfileOut(__METHOD__); return $this->titleMtimes[$hash]; } // Wikia change - begin - @author: wladek $memcKey = null; // silence PHPStorm if (!$context->getDebug()) { $memcKey = wfMemcKey('ResourceLoaderWikiModule', 'mtimes', $this->getName(), md5($hash)); $mtimes = $wgMemc->get($memcKey); if (is_array($mtimes)) { wfProfileOut(__METHOD__); return $mtimes; } } // Wikia change - end $this->titleMtimes[$hash] = $this->reallyGetTitleMtimes($context); // Wikia change - begin - @author: wladek if (!$context->getDebug()) { $wgMemc->set($memcKey, $this->titleMtimes[$hash], self::MTIMES_CACHE_TTL); } // Wikia change - end wfProfileOut(__METHOD__); return $this->titleMtimes[$hash]; }
/** * Get the last modified timestamp of this module. * * Last modified timestamps are calculated from the highest last modified * timestamp of this module's constituent files as well as the files it * depends on. This function is context-sensitive, only performing * calculations on files relevant to the given language, skin and debug * mode. * * @param ResourceLoaderContext $context Context in which to calculate * the modified time * @return int UNIX timestamp * @see ResourceLoaderModule::getFileDependencies */ public function getModifiedTime(ResourceLoaderContext $context) { if (isset($this->modifiedTime[$context->getHash()])) { return $this->modifiedTime[$context->getHash()]; } $files = array(); // Flatten style files into $files $styles = self::collateFilePathListByOption($this->styles, 'media', 'all'); foreach ($styles as $styleFiles) { $files = array_merge($files, $styleFiles); } $skinFiles = self::collateFilePathListByOption(self::tryForKey($this->skinStyles, $context->getSkin(), 'default'), 'media', 'all'); foreach ($skinFiles as $styleFiles) { $files = array_merge($files, $styleFiles); } // Final merge, this should result in a master list of dependent files $files = array_merge($files, $this->scripts, $this->templates, $context->getDebug() ? $this->debugScripts : array(), $this->getLanguageScripts($context->getLanguage()), self::tryForKey($this->skinScripts, $context->getSkin(), 'default'), $this->loaderScripts); if ($this->skipFunction) { $files[] = $this->skipFunction; } $files = array_map(array($this, 'getLocalPath'), $files); // File deps need to be treated separately because they're already prefixed $files = array_merge($files, $this->getFileDependencies($context->getSkin())); // Filter out any duplicates from getFileDependencies() and others. // Most commonly introduced by compileLessFile(), which always includes the // entry point Less file we already know about. $files = array_values(array_unique($files)); // If a module is nothing but a list of dependencies, we need to avoid // giving max() an empty array if (count($files) === 0) { $this->modifiedTime[$context->getHash()] = 1; return $this->modifiedTime[$context->getHash()]; } $filesMtime = max(array_map(array(__CLASS__, 'safeFilemtime'), $files)); $this->modifiedTime[$context->getHash()] = max($filesMtime, $this->getMsgBlobMtime($context->getLanguage()), $this->getDefinitionMtime($context)); return $this->modifiedTime[$context->getHash()]; }
/** * Hook handler. * * If mode equals 'articles' in the request, bootstraps fake module and reinitialize * ResourceLoaderContext object to include the just-defined fake module. * * @param $resourceLoader ResourceLoader * @param $context ResourceLoaderContext * @return bool */ public function onResourceLoaderBeforeRespond($resourceLoader, ResourceLoaderContext &$context) { /* @var $request WebRequest */ $request = $context->getRequest(); if ($request->getVal('mode') !== 'articles') { return true; } $only = $context->getOnly(); $type = $this->getTypeByOnly($only); if (empty($type)) { return true; } $articles = $request->getVal('articles'); $articles = explode('|', $articles); if (empty($articles)) { return true; } // prepare fake ResourceLoader module metadata $moduleName = md5(serialize(array($articles, $only, $context->getHash()))); $moduleFullName = 'wikia.fake.articles.' . $moduleName; $moduleInfo = array('class' => 'ResourceLoaderCustomWikiModule', 'articles' => $this->parseArticleNames($articles), 'type' => $type); // register new fake module $resourceLoader->register($moduleFullName, $moduleInfo); // reinitialize ResourceLoader context $request->setVal('modules', $moduleFullName); $context = new ResourceLoaderContext($resourceLoader, $request); return true; }