コード例 #1
0
 /**
  * Updates cache as necessary when message page is changed
  *
  * @param string|bool $title Name of the page changed (false if deleted)
  * @param mixed $text New contents of the page.
  */
 public function replace($title, $text)
 {
     global $wgMaxMsgCacheEntrySize, $wgContLang, $wgLanguageCode;
     if ($this->mDisable) {
         return;
     }
     list($msg, $code) = $this->figureMessage($title);
     if (strpos($title, '/') !== false && $code === $wgLanguageCode) {
         // Content language overrides do not use the /<code> suffix
         return;
     }
     // Note that if the cache is volatile, load() may trigger a DB fetch.
     // In that case we reenter/reuse the existing cache key lock to avoid
     // a self-deadlock. This is safe as no reads happen *directly* in this
     // method between getReentrantScopedLock() and load() below. There is
     // no risk of data "changing under our feet" for replace().
     $cacheKey = wfMemcKey('messages', $code);
     $scopedLock = $this->getReentrantScopedLock($cacheKey);
     $this->load($code, self::FOR_UPDATE);
     $titleKey = wfMemcKey('messages', 'individual', $title);
     if ($text === false) {
         // Article was deleted
         $this->mCache[$code][$title] = '!NONEXISTENT';
         $this->wanCache->delete($titleKey);
     } elseif (strlen($text) > $wgMaxMsgCacheEntrySize) {
         // Check for size
         $this->mCache[$code][$title] = '!TOO BIG';
         $this->wanCache->set($titleKey, ' ' . $text, $this->mExpiry);
     } else {
         $this->mCache[$code][$title] = ' ' . $text;
         $this->wanCache->delete($titleKey);
     }
     // Mark this cache as definitely "latest" (non-volatile) so
     // load() calls do try to refresh the cache with slave data
     $this->mCache[$code]['LATEST'] = time();
     // Update caches if the lock was acquired
     if ($scopedLock) {
         $this->saveToCaches($this->mCache[$code], 'all', $code);
     }
     ScopedCallback::consume($scopedLock);
     // Relay the purge to APC and other DCs
     $this->wanCache->touchCheckKey(wfMemcKey('messages', $code));
     // Also delete cached sidebar... just in case it is affected
     $codes = array($code);
     if ($code === 'en') {
         // Delete all sidebars, like for example on action=purge on the
         // sidebar messages
         $codes = array_keys(Language::fetchLanguageNames());
     }
     foreach ($codes as $code) {
         $sidebarKey = wfMemcKey('sidebar', $code);
         $this->wanCache->delete($sidebarKey, 5);
     }
     // Update the message in the message blob store
     $blobStore = new MessageBlobStore();
     $blobStore->updateMessage($wgContLang->lcfirst($msg));
     Hooks::run('MessageCacheReplace', array($title, $text));
 }
コード例 #2
0
 /**
  * Load localisation data for a given language for both core and extensions
  * and save it to the persistent cache store and the process cache
  * @param $code
  * @throws MWException
  */
 public function recache($code)
 {
     global $wgExtensionMessagesFiles, $wgMessagesDirs;
     wfProfileIn(__METHOD__);
     if (!$code) {
         wfProfileOut(__METHOD__);
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_combine(self::$allKeys, array_fill(0, count(self::$allKeys), null));
     $coreData = $initialData;
     $deps = array();
     # Load the primary localisation from the source file
     $data = $this->readSourceFilesAndRegisterDeps($code, $deps);
     if ($data === false) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         wfDebug(__METHOD__ . ": got localisation for {$code} from source\n");
         # Merge primary localisation
         foreach ($data as $key => $value) {
             $this->mergeItem($key, $coreData[$key], $value);
         }
     }
     # Fill in the fallback if it's not there already
     if (is_null($coreData['fallback'])) {
         $coreData['fallback'] = $code === 'en' ? false : 'en';
     }
     if ($coreData['fallback'] === false) {
         $coreData['fallbackSequence'] = array();
     } else {
         $coreData['fallbackSequence'] = array_map('trim', explode(',', $coreData['fallback']));
         $len = count($coreData['fallbackSequence']);
         # Ensure that the sequence ends at en
         if ($coreData['fallbackSequence'][$len - 1] !== 'en') {
             $coreData['fallbackSequence'][] = 'en';
         }
         # Load the fallback localisation item by item and merge it
         foreach ($coreData['fallbackSequence'] as $fbCode) {
             # Load the secondary localisation from the source file to
             # avoid infinite cycles on cyclic fallbacks
             $fbData = $this->readSourceFilesAndRegisterDeps($fbCode, $deps);
             if ($fbData === false) {
                 continue;
             }
             foreach (self::$allKeys as $key) {
                 if (!isset($fbData[$key])) {
                     continue;
                 }
                 if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                     $this->mergeItem($key, $coreData[$key], $fbData[$key]);
                 }
             }
         }
     }
     $codeSequence = array_merge(array($code), $coreData['fallbackSequence']);
     # Load core messages and the extension localisations.
     wfProfileIn(__METHOD__ . '-extensions');
     $allData = $initialData;
     foreach ($wgMessagesDirs as $dirs) {
         foreach ((array) $dirs as $dir) {
             foreach ($codeSequence as $csCode) {
                 $fileName = "{$dir}/{$csCode}.json";
                 $data = $this->readJSONFile($fileName);
                 foreach ($data as $key => $item) {
                     $this->mergeItem($key, $allData[$key], $item);
                 }
                 $deps[] = new FileDependency($fileName);
             }
         }
     }
     foreach ($wgExtensionMessagesFiles as $extension => $fileName) {
         if (isset($wgMessagesDirs[$extension])) {
             # Already loaded the JSON files for this extension; skip the PHP shim
             continue;
         }
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             if ($this->mergeExtensionItem($codeSequence, $key, $allData[$key], $item)) {
                 $used = true;
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Merge core data into extension data
     foreach ($coreData as $key => $item) {
         $this->mergeItem($key, $allData[$key], $item);
     }
     wfProfileOut(__METHOD__ . '-extensions');
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     $deps['wgMessagesDirs'] = new GlobalDependency('wgMessagesDirs');
     $deps['version'] = new ConstantDependency('MW_LC_VERSION');
     # Add dependencies to the cache entry
     $allData['deps'] = $deps;
     # Replace spaces with underscores in namespace names
     $allData['namespaceNames'] = str_replace(' ', '_', $allData['namespaceNames']);
     # And do the same for special page aliases. $page is an array.
     foreach ($allData['specialPageAliases'] as &$page) {
         $page = str_replace(' ', '_', $page);
     }
     # Decouple the reference to prevent accidental damage
     unset($page);
     # If there were no plural rules, return an empty array
     if ($allData['pluralRules'] === null) {
         $allData['pluralRules'] = array();
     }
     if ($allData['compiledPluralRules'] === null) {
         $allData['compiledPluralRules'] = array();
     }
     # If there were no plural rule types, return an empty array
     if ($allData['pluralRuleTypes'] === null) {
         $allData['pluralRuleTypes'] = array();
     }
     # Set the list keys
     $allData['list'] = array();
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     $purgeBlobs = true;
     wfRunHooks('LocalisationCacheRecache', array($this, $code, &$allData, &$purgeBlobs));
     if (is_null($allData['namespaceNames'])) {
         wfProfileOut(__METHOD__);
         throw new MWException(__METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.');
     }
     # Set the preload key
     $allData['preload'] = $this->buildPreload($allData);
     # Save to the process cache and register the items loaded
     $this->data[$code] = $allData;
     foreach ($allData as $key => $item) {
         $this->loadedItems[$code][$key] = true;
     }
     # Save to the persistent cache
     wfProfileIn(__METHOD__ . '-write');
     $this->store->startWrite($code);
     foreach ($allData as $key => $value) {
         if (in_array($key, self::$splitKeys)) {
             foreach ($value as $subkey => $subvalue) {
                 $this->store->set("{$key}:{$subkey}", $subvalue);
             }
         } else {
             $this->store->set($key, $value);
         }
     }
     $this->store->finishWrite();
     wfProfileOut(__METHOD__ . '-write');
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if ($purgeBlobs && !$this->store instanceof LCStoreNull) {
         MessageBlobStore::clear();
     }
     wfProfileOut(__METHOD__);
 }
コード例 #3
0
ファイル: DatabaseUpdater.php プロジェクト: whysasse/kmwiki
 /**
  * Purge the objectcache table
  */
 public function purgeCache()
 {
     global $wgLocalisationCacheConf;
     # We can't guarantee that the user will be able to use TRUNCATE,
     # but we know that DELETE is available to us
     $this->output("Purging caches...");
     $this->db->delete('objectcache', '*', __METHOD__);
     if ($wgLocalisationCacheConf['manualRecache']) {
         $this->rebuildLocalisationCache();
     }
     MessageBlobStore::getInstance()->clear();
     $this->output("done.\n");
 }
コード例 #4
0
ファイル: ResourceLoader.php プロジェクト: ErdemA/mediawiki
    /**
     * Generate code for a response.
     *
     * @param ResourceLoaderContext $context Context in which to generate a response
     * @param array $modules List of module objects keyed by module name
     * @param array $missing List of requested module names that are unregistered (optional)
     * @return string Response data
     */
    public function makeModuleResponse(ResourceLoaderContext $context, array $modules, array $missing = array())
    {
        $out = '';
        $states = array();
        if (!count($modules) && !count($missing)) {
            return <<<MESSAGE
/* This file is the Web entry point for MediaWiki's ResourceLoader:
   <https://www.mediawiki.org/wiki/ResourceLoader>. In this request,
   no modules were requested. Max made me put this here. */
MESSAGE;
        }
        $image = $context->getImageObj();
        if ($image) {
            $data = $image->getImageData($context);
            if ($data === false) {
                $data = '';
                $this->errors[] = 'Image generation failed';
            }
            return $data;
        }
        // Pre-fetch blobs
        if ($context->shouldIncludeMessages()) {
            try {
                $this->blobStore->get($this, $modules, $context->getLanguage());
            } catch (Exception $e) {
                MWExceptionHandler::logException($e);
                $this->logger->warning('Prefetching MessageBlobStore failed: {exception}', array('exception' => $e));
                $this->errors[] = self::formatExceptionNoComment($e);
            }
        }
        foreach ($missing as $name) {
            $states[$name] = 'missing';
        }
        // Generate output
        $isRaw = false;
        foreach ($modules as $name => $module) {
            try {
                $content = $module->getModuleContent($context);
                // Append output
                switch ($context->getOnly()) {
                    case 'scripts':
                        $scripts = $content['scripts'];
                        if (is_string($scripts)) {
                            // Load scripts raw...
                            $out .= $scripts;
                        } elseif (is_array($scripts)) {
                            // ...except when $scripts is an array of URLs
                            $out .= self::makeLoaderImplementScript($name, $scripts, array(), array());
                        }
                        break;
                    case 'styles':
                        $styles = $content['styles'];
                        // We no longer seperate into media, they are all combined now with
                        // custom media type groups into @media .. {} sections as part of the css string.
                        // Module returns either an empty array or a numerical array with css strings.
                        $out .= isset($styles['css']) ? implode('', $styles['css']) : '';
                        break;
                    default:
                        $out .= self::makeLoaderImplementScript($name, isset($content['scripts']) ? $content['scripts'] : '', isset($content['styles']) ? $content['styles'] : array(), isset($content['messagesBlob']) ? new XmlJsCode($content['messagesBlob']) : array(), isset($content['templates']) ? $content['templates'] : array());
                        break;
                }
            } catch (Exception $e) {
                MWExceptionHandler::logException($e);
                $this->logger->warning('Generating module package failed: {exception}', array('exception' => $e));
                $this->errors[] = self::formatExceptionNoComment($e);
                // Respond to client with error-state instead of module implementation
                $states[$name] = 'error';
                unset($modules[$name]);
            }
            $isRaw |= $module->isRaw();
        }
        // Update module states
        if ($context->shouldIncludeScripts() && !$context->getRaw() && !$isRaw) {
            if (count($modules) && $context->getOnly() === 'scripts') {
                // Set the state of modules loaded as only scripts to ready as
                // they don't have an mw.loader.implement wrapper that sets the state
                foreach ($modules as $name => $module) {
                    $states[$name] = 'ready';
                }
            }
            // Set the state of modules we didn't respond to with mw.loader.implement
            if (count($states)) {
                $out .= self::makeLoaderStateScript($states);
            }
        } else {
            if (count($states)) {
                $this->errors[] = 'Problematic modules: ' . FormatJson::encode($states, ResourceLoader::inDebugMode());
            }
        }
        $enableFilterCache = true;
        if (count($modules) === 1 && reset($modules) instanceof ResourceLoaderUserTokensModule) {
            // If we're building the embedded user.tokens, don't cache (T84960)
            $enableFilterCache = false;
        }
        if (!$context->getDebug()) {
            if ($context->getOnly() === 'styles') {
                $out = $this->filter('minify-css', $out);
            } else {
                $out = $this->filter('minify-js', $out, array('cache' => $enableFilterCache));
            }
        }
        return $out;
    }
コード例 #5
0
ファイル: ResourceLoader.php プロジェクト: seedbank/old-repo
 /**
  * Generates code for a response
  *
  * @param $context ResourceLoaderContext: Context in which to generate a response
  * @param $modules Array: List of module objects keyed by module name
  * @param $missing Array: List of unavailable modules (optional)
  * @return String: Response data
  */
 public function makeModuleResponse(ResourceLoaderContext $context, array $modules, $missing = array())
 {
     $out = '';
     $exceptions = '';
     if ($modules === array() && $missing === array()) {
         return '/* No modules requested. Max made me put this here */';
     }
     wfProfileIn(__METHOD__);
     // Pre-fetch blobs
     if ($context->shouldIncludeMessages()) {
         try {
             $blobs = MessageBlobStore::get($this, $modules, $context->getLanguage());
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $exceptions .= $this->makeComment($e->__toString());
         }
     } else {
         $blobs = array();
     }
     // Generate output
     $isRaw = false;
     foreach ($modules as $name => $module) {
         /**
          * @var $module ResourceLoaderModule
          */
         wfProfileIn(__METHOD__ . '-' . $name);
         try {
             $scripts = '';
             if ($context->shouldIncludeScripts()) {
                 // If we are in debug mode, we'll want to return an array of URLs if possible
                 // However, we can't do this if the module doesn't support it
                 // We also can't do this if there is an only= parameter, because we have to give
                 // the module a way to return a load.php URL without causing an infinite loop
                 if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) {
                     $scripts = $module->getScriptURLsForDebug($context);
                 } else {
                     $scripts = $module->getScript($context);
                     if (is_string($scripts) && strlen($scripts) && substr($scripts, -1) !== ';') {
                         // bug 27054: Append semicolon to prevent weird bugs
                         // caused by files not terminating their statements right
                         $scripts .= ";\n";
                     }
                 }
             }
             // Styles
             $styles = array();
             if ($context->shouldIncludeStyles()) {
                 // Don't create empty stylesheets like array( '' => '' ) for modules
                 // that don't *have* any stylesheets (bug 38024).
                 $stylePairs = $module->getStyles($context);
                 if (count($stylePairs)) {
                     // If we are in debug mode without &only= set, we'll want to return an array of URLs
                     // See comment near shouldIncludeScripts() for more details
                     if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) {
                         $styles = array('url' => $module->getStyleURLsForDebug($context));
                     } else {
                         // Minify CSS before embedding in mw.loader.implement call
                         // (unless in debug mode)
                         if (!$context->getDebug()) {
                             foreach ($stylePairs as $media => $style) {
                                 // Can be either a string or an array of strings.
                                 if (is_array($style)) {
                                     $stylePairs[$media] = array();
                                     foreach ($style as $cssText) {
                                         if (is_string($cssText)) {
                                             $stylePairs[$media][] = $this->filter('minify-css', $cssText);
                                         }
                                     }
                                 } elseif (is_string($style)) {
                                     $stylePairs[$media] = $this->filter('minify-css', $style);
                                 }
                             }
                         }
                         // Wrap styles into @media groups as needed and flatten into a numerical array
                         $styles = array('css' => self::makeCombinedStyles($stylePairs));
                     }
                 }
             }
             // Messages
             $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}';
             // Append output
             switch ($context->getOnly()) {
                 case 'scripts':
                     if (is_string($scripts)) {
                         // Load scripts raw...
                         $out .= $scripts;
                     } elseif (is_array($scripts)) {
                         // ...except when $scripts is an array of URLs
                         $out .= self::makeLoaderImplementScript($name, $scripts, array(), array());
                     }
                     break;
                 case 'styles':
                     // We no longer seperate into media, they are all combined now with
                     // custom media type groups into @media .. {} sections as part of the css string.
                     // Module returns either an empty array or a numerical array with css strings.
                     $out .= isset($styles['css']) ? implode('', $styles['css']) : '';
                     break;
                 case 'messages':
                     $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob));
                     break;
                 default:
                     $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob));
                     break;
             }
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $exceptions .= $this->makeComment($e->__toString());
             // Register module as missing
             $missing[] = $name;
             unset($modules[$name]);
         }
         $isRaw |= $module->isRaw();
         wfProfileOut(__METHOD__ . '-' . $name);
     }
     // Update module states
     if ($context->shouldIncludeScripts() && !$context->getRaw() && !$isRaw) {
         // Set the state of modules loaded as only scripts to ready
         if (count($modules) && $context->getOnly() === 'scripts') {
             $out .= self::makeLoaderStateScript(array_fill_keys(array_keys($modules), 'ready'));
         }
         // Set the state of modules which were requested but unavailable as missing
         if (is_array($missing) && count($missing)) {
             $out .= self::makeLoaderStateScript(array_fill_keys($missing, 'missing'));
         }
     }
     if (!$context->getDebug()) {
         if ($context->getOnly() === 'styles') {
             $out = $this->filter('minify-css', $out);
         } else {
             $out = $this->filter('minify-js', $out);
         }
     }
     wfProfileOut(__METHOD__);
     return $exceptions . $out;
 }
コード例 #6
0
    /**
     * Generate code for a response.
     *
     * @param ResourceLoaderContext $context Context in which to generate a response
     * @param array $modules List of module objects keyed by module name
     * @param array $missing List of requested module names that are unregistered (optional)
     * @return string Response data
     */
    public function makeModuleResponse(ResourceLoaderContext $context, array $modules, array $missing = array())
    {
        $out = '';
        $states = array();
        if (!count($modules) && !count($missing)) {
            return <<<MESSAGE
/* This file is the Web entry point for MediaWiki's ResourceLoader:
   <https://www.mediawiki.org/wiki/ResourceLoader>. In this request,
   no modules were requested. Max made me put this here. */
MESSAGE;
        }
        $image = $context->getImageObj();
        if ($image) {
            $data = $image->getImageData($context);
            if ($data === false) {
                $data = '';
                $this->errors[] = 'Image generation failed';
            }
            return $data;
        }
        // Pre-fetch blobs
        if ($context->shouldIncludeMessages()) {
            try {
                $blobs = $this->blobStore->get($this, $modules, $context->getLanguage());
            } catch (Exception $e) {
                MWExceptionHandler::logException($e);
                wfDebugLog('resourceloader', __METHOD__ . ": pre-fetching blobs from MessageBlobStore failed: {$e}");
                $this->errors[] = self::formatExceptionNoComment($e);
            }
        } else {
            $blobs = array();
        }
        foreach ($missing as $name) {
            $states[$name] = 'missing';
        }
        // Generate output
        $isRaw = false;
        foreach ($modules as $name => $module) {
            /**
             * @var $module ResourceLoaderModule
             */
            try {
                $scripts = '';
                if ($context->shouldIncludeScripts()) {
                    // If we are in debug mode, we'll want to return an array of URLs if possible
                    // However, we can't do this if the module doesn't support it
                    // We also can't do this if there is an only= parameter, because we have to give
                    // the module a way to return a load.php URL without causing an infinite loop
                    if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) {
                        $scripts = $module->getScriptURLsForDebug($context);
                    } else {
                        $scripts = $module->getScript($context);
                        // rtrim() because there are usually a few line breaks
                        // after the last ';'. A new line at EOF, a new line
                        // added by ResourceLoaderFileModule::readScriptFiles, etc.
                        if (is_string($scripts) && strlen($scripts) && substr(rtrim($scripts), -1) !== ';') {
                            // Append semicolon to prevent weird bugs caused by files not
                            // terminating their statements right (bug 27054)
                            $scripts .= ";\n";
                        }
                    }
                }
                // Styles
                $styles = array();
                if ($context->shouldIncludeStyles()) {
                    // Don't create empty stylesheets like array( '' => '' ) for modules
                    // that don't *have* any stylesheets (bug 38024).
                    $stylePairs = $module->getStyles($context);
                    if (count($stylePairs)) {
                        // If we are in debug mode without &only= set, we'll want to return an array of URLs
                        // See comment near shouldIncludeScripts() for more details
                        if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) {
                            $styles = array('url' => $module->getStyleURLsForDebug($context));
                        } else {
                            // Minify CSS before embedding in mw.loader.implement call
                            // (unless in debug mode)
                            if (!$context->getDebug()) {
                                foreach ($stylePairs as $media => $style) {
                                    // Can be either a string or an array of strings.
                                    if (is_array($style)) {
                                        $stylePairs[$media] = array();
                                        foreach ($style as $cssText) {
                                            if (is_string($cssText)) {
                                                $stylePairs[$media][] = $this->filter('minify-css', $cssText);
                                            }
                                        }
                                    } elseif (is_string($style)) {
                                        $stylePairs[$media] = $this->filter('minify-css', $style);
                                    }
                                }
                            }
                            // Wrap styles into @media groups as needed and flatten into a numerical array
                            $styles = array('css' => self::makeCombinedStyles($stylePairs));
                        }
                    }
                }
                // Messages
                $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}';
                // Append output
                switch ($context->getOnly()) {
                    case 'scripts':
                        if (is_string($scripts)) {
                            // Load scripts raw...
                            $out .= $scripts;
                        } elseif (is_array($scripts)) {
                            // ...except when $scripts is an array of URLs
                            $out .= self::makeLoaderImplementScript($name, $scripts, array(), array());
                        }
                        break;
                    case 'styles':
                        // We no longer seperate into media, they are all combined now with
                        // custom media type groups into @media .. {} sections as part of the css string.
                        // Module returns either an empty array or a numerical array with css strings.
                        $out .= isset($styles['css']) ? implode('', $styles['css']) : '';
                        break;
                    case 'messages':
                        $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob));
                        break;
                    case 'templates':
                        $out .= Xml::encodeJsCall('mw.templates.set', array($name, (object) $module->getTemplates()), ResourceLoader::inDebugMode());
                        break;
                    default:
                        $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob), $module->getTemplates());
                        break;
                }
            } catch (Exception $e) {
                MWExceptionHandler::logException($e);
                wfDebugLog('resourceloader', __METHOD__ . ": generating module package failed: {$e}");
                $this->errors[] = self::formatExceptionNoComment($e);
                // Respond to client with error-state instead of module implementation
                $states[$name] = 'error';
                unset($modules[$name]);
            }
            $isRaw |= $module->isRaw();
        }
        // Update module states
        if ($context->shouldIncludeScripts() && !$context->getRaw() && !$isRaw) {
            if (count($modules) && $context->getOnly() === 'scripts') {
                // Set the state of modules loaded as only scripts to ready as
                // they don't have an mw.loader.implement wrapper that sets the state
                foreach ($modules as $name => $module) {
                    $states[$name] = 'ready';
                }
            }
            // Set the state of modules we didn't respond to with mw.loader.implement
            if (count($states)) {
                $out .= self::makeLoaderStateScript($states);
            }
        } else {
            if (count($states)) {
                $this->errors[] = 'Problematic modules: ' . FormatJson::encode($states, ResourceLoader::inDebugMode());
            }
        }
        if (!$context->getDebug()) {
            if ($context->getOnly() === 'styles') {
                $out = $this->filter('minify-css', $out);
            } else {
                $out = $this->filter('minify-js', $out);
            }
        }
        return $out;
    }
コード例 #7
0
 /**
  * Updates cache as necessary when message page is changed
  *
  * @param string $title name of the page changed.
  * @param $text Mixed: new contents of the page.
  */
 public function replace($title, $text)
 {
     global $wgMaxMsgCacheEntrySize;
     wfProfileIn(__METHOD__);
     if ($this->mDisable) {
         wfProfileOut(__METHOD__);
         return;
     }
     list($msg, $code) = $this->figureMessage($title);
     $cacheKey = wfMemcKey('messages', $code);
     $this->load($code);
     $this->lock($cacheKey);
     $titleKey = wfMemcKey('messages', 'individual', $title);
     if ($text === false) {
         # Article was deleted
         $this->mCache[$code][$title] = '!NONEXISTENT';
         $this->mMemc->delete($titleKey);
     } elseif (strlen($text) > $wgMaxMsgCacheEntrySize) {
         # Check for size
         $this->mCache[$code][$title] = '!TOO BIG';
         $this->mMemc->set($titleKey, ' ' . $text, $this->mExpiry);
     } else {
         $this->mCache[$code][$title] = ' ' . $text;
         $this->mMemc->delete($titleKey);
     }
     # Update caches
     $this->saveToCaches($this->mCache[$code], true, $code);
     $this->unlock($cacheKey);
     // Also delete cached sidebar... just in case it is affected
     $codes = array($code);
     if ($code === 'en') {
         // Delete all sidebars, like for example on action=purge on the
         // sidebar messages
         $codes = array_keys(Language::fetchLanguageNames());
     }
     global $wgMemc;
     foreach ($codes as $code) {
         $sidebarKey = wfMemcKey('sidebar', $code);
         $wgMemc->delete($sidebarKey);
     }
     // Update the message in the message blob store
     global $wgContLang;
     MessageBlobStore::updateMessage($wgContLang->lcfirst($msg));
     wfRunHooks('MessageCacheReplace', array($title, $text));
     wfProfileOut(__METHOD__);
 }
コード例 #8
0
ファイル: ResourceLoader.php プロジェクト: Tjorriemorrie/app
 /**
  * Generates code for a response
  *
  * @param $context ResourceLoaderContext: Context in which to generate a response
  * @param $modules Array: List of module objects keyed by module name
  * @param $missing Array: List of unavailable modules (optional)
  * @return String: Response data
  */
 public function makeModuleResponse(ResourceLoaderContext $context, array $modules, $missing = array())
 {
     $out = '';
     $exceptions = '';
     if ($modules === array() && $missing === array()) {
         return '/* No modules requested. Max made me put this here */';
     }
     wfProfileIn(__METHOD__);
     // Pre-fetch blobs
     if ($context->shouldIncludeMessages()) {
         try {
             $blobs = MessageBlobStore::get($this, $modules, $context->getLanguage());
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $exceptions .= $this->formatException($e);
         }
     } else {
         $blobs = array();
     }
     // Generate output
     foreach ($modules as $name => $module) {
         /**
          * @var $module ResourceLoaderModule
          */
         wfProfileIn(__METHOD__ . '-' . $name);
         try {
             $scripts = '';
             if ($context->shouldIncludeScripts()) {
                 // If we are in debug mode, we'll want to return an array of URLs if possible
                 // However, we can't do this if the module doesn't support it
                 // We also can't do this if there is an only= parameter, because we have to give
                 // the module a way to return a load.php URL without causing an infinite loop
                 if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) {
                     $scripts = $module->getScriptURLsForDebug($context);
                 } else {
                     $scripts = $module->getScript($context);
                     if (is_string($scripts)) {
                         // bug 27054: Append semicolon to prevent weird bugs
                         // caused by files not terminating their statements right
                         $scripts .= ";\n";
                     }
                 }
             }
             // Styles
             $styles = array();
             if ($context->shouldIncludeStyles()) {
                 // If we are in debug mode, we'll want to return an array of URLs
                 // See comment near shouldIncludeScripts() for more details
                 if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) {
                     $styles = $module->getStyleURLsForDebug($context);
                 } else {
                     $styles = $module->getStyles($context);
                 }
             }
             // Messages
             $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}';
             // Append output
             switch ($context->getOnly()) {
                 case 'scripts':
                     if (is_string($scripts)) {
                         // Load scripts raw...
                         $out .= $scripts;
                     } elseif (is_array($scripts)) {
                         // ...except when $scripts is an array of URLs
                         $out .= self::makeLoaderImplementScript($name, $scripts, array(), array());
                     }
                     break;
                 case 'styles':
                     $out .= self::makeCombinedStyles($styles);
                     break;
                 case 'messages':
                     $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob));
                     break;
                 default:
                     // Minify CSS before embedding in mw.loader.implement call
                     // (unless in debug mode)
                     if (!$context->getDebug()) {
                         foreach ($styles as $media => $style) {
                             if (is_string($style)) {
                                 $styles[$media] = $this->filter('minify-css', $style);
                             }
                         }
                     }
                     $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob));
                     break;
             }
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $exceptions .= $this->formatException($e);
             // Register module as missing
             $missing[] = $name;
             unset($modules[$name]);
         }
         wfProfileOut(__METHOD__ . '-' . $name);
     }
     // Update module states
     if ($context->shouldIncludeScripts()) {
         // Set the state of modules loaded as only scripts to ready
         if (count($modules) && $context->getOnly() === 'scripts' && !isset($modules['startup'])) {
             $out .= self::makeLoaderStateScript(array_fill_keys(array_keys($modules), 'ready'));
         }
         // Set the state of modules which were requested but unavailable as missing
         if (is_array($missing) && count($missing)) {
             $out .= self::makeLoaderStateScript(array_fill_keys($missing, 'missing'));
         }
     }
     if (!$context->getDebug()) {
         if ($context->getOnly() === 'styles') {
             $out = $this->filter('minify-css', $out);
         } else {
             $out = $this->filter('minify-js', $out);
         }
     }
     wfProfileOut(__METHOD__);
     return $exceptions . $out;
 }
コード例 #9
0
 /**
  * Load localisation data for a given language for both core and extensions
  * and save it to the persistent cache store and the process cache
  */
 public function recache($code)
 {
     static $recursionGuard = array();
     global $wgExtensionMessagesFiles, $wgExtensionAliasesFiles;
     wfProfileIn(__METHOD__);
     if (!$code) {
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_combine(self::$allKeys, array_fill(0, count(self::$allKeys), null));
     $coreData = $initialData;
     $deps = array();
     # Load the primary localisation from the source file
     $fileName = Language::getMessagesFileName($code);
     if (!file_exists($fileName)) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         $deps[] = new FileDependency($fileName);
         $data = $this->readPHPFile($fileName, 'core');
         wfDebug(__METHOD__ . ": got localisation for {$code} from source\n");
         # Merge primary localisation
         foreach ($data as $key => $value) {
             $this->mergeItem($key, $coreData[$key], $value);
         }
     }
     # Fill in the fallback if it's not there already
     if (is_null($coreData['fallback'])) {
         $coreData['fallback'] = $code === 'en' ? false : 'en';
     }
     if ($coreData['fallback'] !== false) {
         # Guard against circular references
         if (isset($recursionGuard[$code])) {
             throw new MWException("Error: Circular fallback reference in language code {$code}");
         }
         $recursionGuard[$code] = true;
         # Load the fallback localisation item by item and merge it
         $deps = array_merge($deps, $this->getItem($coreData['fallback'], 'deps'));
         foreach (self::$allKeys as $key) {
             if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                 $fallbackValue = $this->getItem($coreData['fallback'], $key);
                 $this->mergeItem($key, $coreData[$key], $fallbackValue);
             }
         }
         $fallbackSequence = $this->getItem($coreData['fallback'], 'fallbackSequence');
         array_unshift($fallbackSequence, $coreData['fallback']);
         $coreData['fallbackSequence'] = $fallbackSequence;
         unset($recursionGuard[$code]);
     } else {
         $coreData['fallbackSequence'] = array();
     }
     $codeSequence = array_merge(array($code), $coreData['fallbackSequence']);
     # Load the extension localisations
     # This is done after the core because we know the fallback sequence now.
     # But it has a higher precedence for merging so that we can support things
     # like site-specific message overrides.
     $allData = $initialData;
     foreach ($wgExtensionMessagesFiles as $fileName) {
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             if ($this->mergeExtensionItem($codeSequence, $key, $allData[$key], $item)) {
                 $used = true;
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Load deprecated $wgExtensionAliasesFiles
     foreach ($wgExtensionAliasesFiles as $fileName) {
         $data = $this->readPHPFile($fileName, 'aliases');
         if (!isset($data['aliases'])) {
             continue;
         }
         $used = $this->mergeExtensionItem($codeSequence, 'specialPageAliases', $allData['specialPageAliases'], $data['aliases']);
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Merge core data into extension data
     foreach ($coreData as $key => $item) {
         $this->mergeItem($key, $allData[$key], $item);
     }
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     $deps['wgExtensionAliasesFiles'] = new GlobalDependency('wgExtensionAliasesFiles');
     $deps['version'] = new ConstantDependency('MW_LC_VERSION');
     # Add dependencies to the cache entry
     $allData['deps'] = $deps;
     # Replace spaces with underscores in namespace names
     $allData['namespaceNames'] = str_replace(' ', '_', $allData['namespaceNames']);
     # And do the same for special page aliases. $page is an array.
     foreach ($allData['specialPageAliases'] as &$page) {
         $page = str_replace(' ', '_', $page);
     }
     # Decouple the reference to prevent accidental damage
     unset($page);
     # Fix broken defaultUserOptionOverrides
     if (!is_array($allData['defaultUserOptionOverrides'])) {
         $allData['defaultUserOptionOverrides'] = array();
     }
     # Set the list keys
     $allData['list'] = array();
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     wfRunHooks('LocalisationCacheRecache', array($this, $code, &$allData));
     if (is_null($allData['defaultUserOptionOverrides'])) {
         throw new MWException(__METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.');
     }
     # Set the preload key
     $allData['preload'] = $this->buildPreload($allData);
     # Save to the process cache and register the items loaded
     $this->data[$code] = $allData;
     foreach ($allData as $key => $item) {
         $this->loadedItems[$code][$key] = true;
     }
     # Save to the persistent cache
     $this->store->startWrite($code);
     foreach ($allData as $key => $value) {
         if (in_array($key, self::$splitKeys)) {
             foreach ($value as $subkey => $subvalue) {
                 $this->store->set("{$key}:{$subkey}", $subvalue);
             }
         } else {
             $this->store->set($key, $value);
         }
     }
     $this->store->finishWrite();
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if (!$this->store instanceof LCStore_Null) {
         MessageBlobStore::clear();
     }
     wfProfileOut(__METHOD__);
 }
コード例 #10
0
 /**
  * Load localisation data for a given language for both core and extensions
  * and save it to the persistent cache store and the process cache
  * @param string $code
  * @throws MWException
  */
 public function recache($code)
 {
     global $wgExtensionMessagesFiles;
     if (!$code) {
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_fill_keys(self::$allKeys, null);
     $coreData = $initialData;
     $deps = [];
     # Load the primary localisation from the source file
     $data = $this->readSourceFilesAndRegisterDeps($code, $deps);
     if ($data === false) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         wfDebug(__METHOD__ . ": got localisation for {$code} from source\n");
         # Merge primary localisation
         foreach ($data as $key => $value) {
             $this->mergeItem($key, $coreData[$key], $value);
         }
     }
     # Fill in the fallback if it's not there already
     if (is_null($coreData['fallback'])) {
         $coreData['fallback'] = $code === 'en' ? false : 'en';
     }
     if ($coreData['fallback'] === false) {
         $coreData['fallbackSequence'] = [];
     } else {
         $coreData['fallbackSequence'] = array_map('trim', explode(',', $coreData['fallback']));
         $len = count($coreData['fallbackSequence']);
         # Ensure that the sequence ends at en
         if ($coreData['fallbackSequence'][$len - 1] !== 'en') {
             $coreData['fallbackSequence'][] = 'en';
         }
     }
     $codeSequence = array_merge([$code], $coreData['fallbackSequence']);
     $messageDirs = $this->getMessagesDirs();
     # Load non-JSON localisation data for extensions
     $extensionData = array_fill_keys($codeSequence, $initialData);
     foreach ($wgExtensionMessagesFiles as $extension => $fileName) {
         if (isset($messageDirs[$extension])) {
             # This extension has JSON message data; skip the PHP shim
             continue;
         }
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             foreach ($codeSequence as $csCode) {
                 if (isset($item[$csCode])) {
                     $this->mergeItem($key, $extensionData[$csCode][$key], $item[$csCode]);
                     $used = true;
                 }
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Load the localisation data for each fallback, then merge it into the full array
     $allData = $initialData;
     foreach ($codeSequence as $csCode) {
         $csData = $initialData;
         # Load core messages and the extension localisations.
         foreach ($messageDirs as $dirs) {
             foreach ((array) $dirs as $dir) {
                 $fileName = "{$dir}/{$csCode}.json";
                 $data = $this->readJSONFile($fileName);
                 foreach ($data as $key => $item) {
                     $this->mergeItem($key, $csData[$key], $item);
                 }
                 $deps[] = new FileDependency($fileName);
             }
         }
         # Merge non-JSON extension data
         if (isset($extensionData[$csCode])) {
             foreach ($extensionData[$csCode] as $key => $item) {
                 $this->mergeItem($key, $csData[$key], $item);
             }
         }
         if ($csCode === $code) {
             # Merge core data into extension data
             foreach ($coreData as $key => $item) {
                 $this->mergeItem($key, $csData[$key], $item);
             }
         } else {
             # Load the secondary localisation from the source file to
             # avoid infinite cycles on cyclic fallbacks
             $fbData = $this->readSourceFilesAndRegisterDeps($csCode, $deps);
             if ($fbData !== false) {
                 # Only merge the keys that make sense to merge
                 foreach (self::$allKeys as $key) {
                     if (!isset($fbData[$key])) {
                         continue;
                     }
                     if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                         $this->mergeItem($key, $csData[$key], $fbData[$key]);
                     }
                 }
             }
         }
         # Allow extensions an opportunity to adjust the data for this
         # fallback
         Hooks::run('LocalisationCacheRecacheFallback', [$this, $csCode, &$csData]);
         # Merge the data for this fallback into the final array
         if ($csCode === $code) {
             $allData = $csData;
         } else {
             foreach (self::$allKeys as $key) {
                 if (!isset($csData[$key])) {
                     continue;
                 }
                 if (is_null($allData[$key]) || $this->isMergeableKey($key)) {
                     $this->mergeItem($key, $allData[$key], $csData[$key]);
                 }
             }
         }
     }
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     // The 'MessagesDirs' config setting is used in LocalisationCache::getMessagesDirs().
     // We use the key 'wgMessagesDirs' for historical reasons.
     $deps['wgMessagesDirs'] = new MainConfigDependency('MessagesDirs');
     $deps['version'] = new ConstantDependency('LocalisationCache::VERSION');
     # Add dependencies to the cache entry
     $allData['deps'] = $deps;
     # Replace spaces with underscores in namespace names
     $allData['namespaceNames'] = str_replace(' ', '_', $allData['namespaceNames']);
     # And do the same for special page aliases. $page is an array.
     foreach ($allData['specialPageAliases'] as &$page) {
         $page = str_replace(' ', '_', $page);
     }
     # Decouple the reference to prevent accidental damage
     unset($page);
     # If there were no plural rules, return an empty array
     if ($allData['pluralRules'] === null) {
         $allData['pluralRules'] = [];
     }
     if ($allData['compiledPluralRules'] === null) {
         $allData['compiledPluralRules'] = [];
     }
     # If there were no plural rule types, return an empty array
     if ($allData['pluralRuleTypes'] === null) {
         $allData['pluralRuleTypes'] = [];
     }
     # Set the list keys
     $allData['list'] = [];
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     $purgeBlobs = true;
     Hooks::run('LocalisationCacheRecache', [$this, $code, &$allData, &$purgeBlobs]);
     if (is_null($allData['namespaceNames'])) {
         throw new MWException(__METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.');
     }
     # Set the preload key
     $allData['preload'] = $this->buildPreload($allData);
     # Save to the process cache and register the items loaded
     $this->data[$code] = $allData;
     foreach ($allData as $key => $item) {
         $this->loadedItems[$code][$key] = true;
     }
     # Save to the persistent cache
     $this->store->startWrite($code);
     foreach ($allData as $key => $value) {
         if (in_array($key, self::$splitKeys)) {
             foreach ($value as $subkey => $subvalue) {
                 $this->store->set("{$key}:{$subkey}", $subvalue);
             }
         } else {
             $this->store->set($key, $value);
         }
     }
     $this->store->finishWrite();
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if ($purgeBlobs && !$this->store instanceof LCStoreNull) {
         $blobStore = new MessageBlobStore();
         $blobStore->clear();
     }
 }
コード例 #11
0
ファイル: MessageCache.php プロジェクト: D66Ha/mediawiki
 /**
  * Updates cache as necessary when message page is changed
  *
  * @param string $title Name of the page changed.
  * @param mixed $text New contents of the page.
  */
 public function replace($title, $text)
 {
     global $wgMaxMsgCacheEntrySize, $wgContLang, $wgLanguageCode;
     if ($this->mDisable) {
         return;
     }
     list($msg, $code) = $this->figureMessage($title);
     if (strpos($title, '/') !== false && $code === $wgLanguageCode) {
         # Content language overrides do not use the /<code> suffix
         return;
     }
     $cacheKey = wfMemcKey('messages', $code);
     $this->lock($cacheKey);
     $this->load($code, self::FOR_UPDATE);
     $titleKey = wfMemcKey('messages', 'individual', $title);
     if ($text === false) {
         # Article was deleted
         $this->mCache[$code][$title] = '!NONEXISTENT';
         $this->mMemc->delete($titleKey);
     } elseif (strlen($text) > $wgMaxMsgCacheEntrySize) {
         # Check for size
         $this->mCache[$code][$title] = '!TOO BIG';
         $this->mMemc->set($titleKey, ' ' . $text, $this->mExpiry);
     } else {
         $this->mCache[$code][$title] = ' ' . $text;
         $this->mMemc->delete($titleKey);
     }
     # Update caches
     $this->saveToCaches($this->mCache[$code], 'all', $code);
     $this->unlock($cacheKey);
     $this->wanCache->touchCheckKey(wfMemcKey('messages', $code));
     // Also delete cached sidebar... just in case it is affected
     $codes = array($code);
     if ($code === 'en') {
         // Delete all sidebars, like for example on action=purge on the
         // sidebar messages
         $codes = array_keys(Language::fetchLanguageNames());
     }
     foreach ($codes as $code) {
         $sidebarKey = wfMemcKey('sidebar', $code);
         $this->wanCache->delete($sidebarKey, 5);
     }
     // Update the message in the message blob store
     $blobStore = new MessageBlobStore();
     $blobStore->updateMessage($wgContLang->lcfirst($msg));
     Hooks::run('MessageCacheReplace', array($title, $text));
 }
コード例 #12
0
ファイル: ResourceLoader.php プロジェクト: GodelDesign/Godel
 /**
  * Generates code for a response
  * 
  * @param $context ResourceLoaderContext: Context in which to generate a response
  * @param $modules Array: List of module objects keyed by module name
  * @param $missing Array: List of unavailable modules (optional)
  * @return String: Response data
  */
 public function makeModuleResponse(ResourceLoaderContext $context, array $modules, $missing = array())
 {
     $out = '';
     $exceptions = '';
     if ($modules === array() && $missing === array()) {
         return '/* No modules requested. Max made me put this here */';
     }
     wfProfileIn(__METHOD__);
     // Pre-fetch blobs
     if ($context->shouldIncludeMessages()) {
         try {
             $blobs = MessageBlobStore::get($this, $modules, $context->getLanguage());
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $exceptions .= "/*\n{$e->__toString()}\n*/\n";
         }
     } else {
         $blobs = array();
     }
     // Generate output
     foreach ($modules as $name => $module) {
         wfProfileIn(__METHOD__ . '-' . $name);
         try {
             // Scripts
             $scripts = '';
             if ($context->shouldIncludeScripts()) {
                 // bug 27054: Append semicolon to prevent weird bugs
                 // caused by files not terminating their statements right
                 $scripts .= $module->getScript($context) . ";\n";
             }
             // Styles
             $styles = array();
             if ($context->shouldIncludeStyles()) {
                 $styles = $module->getStyles($context);
             }
             // Messages
             $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}';
             // Append output
             switch ($context->getOnly()) {
                 case 'scripts':
                     $out .= $scripts;
                     break;
                 case 'styles':
                     $out .= self::makeCombinedStyles($styles);
                     break;
                 case 'messages':
                     $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob));
                     break;
                 default:
                     // Minify CSS before embedding in mediaWiki.loader.implement call
                     // (unless in debug mode)
                     if (!$context->getDebug()) {
                         foreach ($styles as $media => $style) {
                             $styles[$media] = $this->filter('minify-css', $style);
                         }
                     }
                     $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob));
                     break;
             }
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $exceptions .= "/*\n{$e->__toString()}\n*/\n";
             // Register module as missing
             $missing[] = $name;
             unset($modules[$name]);
         }
         wfProfileOut(__METHOD__ . '-' . $name);
     }
     // Update module states
     if ($context->shouldIncludeScripts()) {
         // Set the state of modules loaded as only scripts to ready
         if (count($modules) && $context->getOnly() === 'scripts' && !isset($modules['startup'])) {
             $out .= self::makeLoaderStateScript(array_fill_keys(array_keys($modules), 'ready'));
         }
         // Set the state of modules which were requested but unavailable as missing
         if (is_array($missing) && count($missing)) {
             $out .= self::makeLoaderStateScript(array_fill_keys($missing, 'missing'));
         }
     }
     if (!$context->getDebug()) {
         if ($context->getOnly() === 'styles') {
             $out = $this->filter('minify-css', $out);
         } else {
             $out = $this->filter('minify-js', $out);
         }
     }
     wfProfileOut(__METHOD__);
     return $exceptions . $out;
 }
コード例 #13
0
 /**
  * Load localisation data for a given language for both core and extensions
  * and save it to the persistent cache store and the process cache
  * @param $code
  */
 public function recache($code)
 {
     global $wgExtensionMessagesFiles;
     wfProfileIn(__METHOD__);
     if (!$code) {
         throw new MWException("Invalid language code requested");
     }
     $this->recachedLangs[$code] = true;
     # Initial values
     $initialData = array_combine(self::$allKeys, array_fill(0, count(self::$allKeys), null));
     $coreData = $initialData;
     $deps = array();
     # Load the primary localisation from the source file
     $fileName = Language::getMessagesFileName($code);
     $addFileName = Language::getAdditionalMessagesFileName($code, 'core');
     if (!file_exists($fileName)) {
         wfDebug(__METHOD__ . ": no localisation file for {$code}, using fallback to en\n");
         $coreData['fallback'] = 'en';
     } else {
         $deps[] = new FileDependency($fileName);
         $data = $this->readPHPFile($fileName, 'core');
         // wikia changes begin
         if (file_exists($addFileName)) {
             $deps[] = new FileDependency($addFileName);
             $addData = $this->readPHPFile($addFileName, 'core');
             if (!empty($addData['messages'])) {
                 $data['messages'] = array_merge($data['messages'], $addData['messages']);
             }
         }
         // wikia changes end
         wfDebug(__METHOD__ . ": got localisation for {$code} from source\n");
         # Merge primary localisation
         foreach ($data as $key => $value) {
             $this->mergeItem($key, $coreData[$key], $value);
         }
     }
     # Fill in the fallback if it's not there already
     if (is_null($coreData['fallback'])) {
         $coreData['fallback'] = $code === 'en' ? false : 'en';
     }
     if ($coreData['fallback'] === false) {
         $coreData['fallbackSequence'] = array();
     } else {
         $coreData['fallbackSequence'] = array_map('trim', explode(',', $coreData['fallback']));
         $len = count($coreData['fallbackSequence']);
         # Ensure that the sequence ends at en
         if ($coreData['fallbackSequence'][$len - 1] !== 'en') {
             $coreData['fallbackSequence'][] = 'en';
         }
         # Load the fallback localisation item by item and merge it
         foreach ($coreData['fallbackSequence'] as $fbCode) {
             # Load the secondary localisation from the source file to
             # avoid infinite cycles on cyclic fallbacks
             $fbFilename = Language::getMessagesFileName($fbCode);
             $fbAddFileName = Language::getAdditionalMessagesFileName($fbCode, 'core');
             if (!file_exists($fbFilename)) {
                 continue;
             }
             $deps[] = new FileDependency($fbFilename);
             $fbData = $this->readPHPFile($fbFilename, 'core');
             // wikia changes begin
             if (file_exists($fbAddFileName)) {
                 $deps[] = new FileDependency($fbAddFileName);
                 $addData = $this->readPHPFile($fbAddFileName, 'core');
                 if (!empty($addData['messages'])) {
                     $fbData['messages'] = array_merge($fbData['messages'], $addData['messages']);
                 }
             }
             // wikia changes end
             wfDebug(__METHOD__ . ": got fallback localisation for {$fbCode} from source\n");
             foreach (self::$allKeys as $key) {
                 if (!isset($fbData[$key])) {
                     continue;
                 }
                 if (is_null($coreData[$key]) || $this->isMergeableKey($key)) {
                     $this->mergeItem($key, $coreData[$key], $fbData[$key]);
                 }
             }
         }
     }
     $codeSequence = array_merge(array($code), $coreData['fallbackSequence']);
     // wikia change begin
     // author: mech
     // allow extensions to use hook to add messages files
     // this can be used in cases when enumerating message files is expensive so it shouldn't be done in setup file
     wfRunHooks('BeforeExtensionMessagesRecache', array(&$wgExtensionMessagesFiles));
     // wikia change end
     # Load the extension localisations
     # This is done after the core because we know the fallback sequence now.
     # But it has a higher precedence for merging so that we can support things
     # like site-specific message overrides.
     $allData = $initialData;
     foreach ($wgExtensionMessagesFiles as $fileName) {
         $data = $this->readPHPFile($fileName, 'extension');
         $used = false;
         foreach ($data as $key => $item) {
             if ($this->mergeExtensionItem($codeSequence, $key, $allData[$key], $item)) {
                 $used = true;
             }
         }
         if ($used) {
             $deps[] = new FileDependency($fileName);
         }
     }
     # Merge core data into extension data
     foreach ($coreData as $key => $item) {
         $this->mergeItem($key, $allData[$key], $item);
     }
     # Add cache dependencies for any referenced globals
     $deps['wgExtensionMessagesFiles'] = new GlobalDependency('wgExtensionMessagesFiles');
     $deps['version'] = new ConstantDependency('MW_LC_VERSION');
     # Add dependencies to the cache entry
     $allData['deps'] = $deps;
     # Replace spaces with underscores in namespace names
     $allData['namespaceNames'] = str_replace(' ', '_', $allData['namespaceNames']);
     # And do the same for special page aliases. $page is an array.
     foreach ($allData['specialPageAliases'] as &$page) {
         $page = str_replace(' ', '_', $page);
     }
     # Decouple the reference to prevent accidental damage
     unset($page);
     # Set the list keys
     $allData['list'] = array();
     foreach (self::$splitKeys as $key) {
         $allData['list'][$key] = array_keys($allData[$key]);
     }
     # Run hooks
     wfRunHooks('LocalisationCacheRecache', array($this, $code, &$allData));
     if (is_null($allData['namespaceNames'])) {
         throw new MWException(__METHOD__ . ': Localisation data failed sanity check! ' . 'Check that your languages/messages/MessagesEn.php file is intact.');
     }
     # Set the preload key
     $allData['preload'] = $this->buildPreload($allData);
     # Save to the process cache and register the items loaded
     $this->data[$code] = $allData;
     foreach ($allData as $key => $item) {
         $this->loadedItems[$code][$key] = true;
     }
     # Save to the persistent cache
     $this->store->startWrite($code);
     foreach ($allData as $key => $value) {
         if (in_array($key, self::$splitKeys)) {
             foreach ($value as $subkey => $subvalue) {
                 $this->store->set("{$key}:{$subkey}", $subvalue);
             }
         } else {
             $this->store->set($key, $value);
         }
     }
     $this->store->finishWrite();
     # Clear out the MessageBlobStore
     # HACK: If using a null (i.e. disabled) storage backend, we
     # can't write to the MessageBlobStore either
     if (!$this->store instanceof LCStore_Null) {
         MessageBlobStore::clear();
     }
     wfProfileOut(__METHOD__);
 }