Merge "Add $revision to TitleMoveCompleting for completeness"
[lhc/web/wiklou.git] / includes / resourceloader / ResourceLoader.php
index 5208c23..1f3085a 100644 (file)
@@ -101,11 +101,11 @@ class ResourceLoader implements LoggerAwareInterface {
         * requests its own information. This sacrifice of modularity yields a substantial
         * performance improvement.
         *
-        * @param array $modules List of module names to preload information for
+        * @param array $moduleNames List of module names to preload information for
         * @param ResourceLoaderContext $context Context to load the information within
         */
-       public function preloadModuleInfo( array $modules, ResourceLoaderContext $context ) {
-               if ( !count( $modules ) ) {
+       public function preloadModuleInfo( array $moduleNames, ResourceLoaderContext $context ) {
+               if ( !$moduleNames ) {
                        // Or else Database*::select() will explode, plus it's cheaper!
                        return;
                }
@@ -116,11 +116,12 @@ class ResourceLoader implements LoggerAwareInterface {
                // Batched version of ResourceLoaderModule::getFileDependencies
                $vary = "$skin|$lang";
                $res = $dbr->select( 'module_deps', array( 'md_module', 'md_deps' ), array(
-                               'md_module' => $modules,
+                               'md_module' => $moduleNames,
                                'md_skin' => $vary,
                        ), __METHOD__
                );
-               // Prime in-object cache values for each module
+
+               // Prime in-object cache for file dependencies
                $modulesWithDeps = array();
                foreach ( $res as $row ) {
                        $module = $this->getModule( $row->md_module );
@@ -132,41 +133,25 @@ class ResourceLoader implements LoggerAwareInterface {
                        }
                }
                // Register the absence of a dependency row too
-               foreach ( array_diff( $modules, $modulesWithDeps ) as $name ) {
+               foreach ( array_diff( $moduleNames, $modulesWithDeps ) as $name ) {
                        $module = $this->getModule( $name );
                        if ( $module ) {
                                $this->getModule( $name )->setFileDependencies( $context, array() );
                        }
                }
 
-               // Get message blob mtimes. Only do this for modules with messages
-               $modulesWithMessages = array();
-               foreach ( $modules as $name ) {
+               // Prime in-object cache for message blobs for modules with messages
+               $modules = array();
+               foreach ( $moduleNames as $name ) {
                        $module = $this->getModule( $name );
-                       if ( $module && count( $module->getMessages() ) ) {
-                               $modulesWithMessages[] = $name;
-                       }
-               }
-               $modulesWithoutMessages = array_flip( $modules ); // Will be trimmed down by the loop below
-               if ( count( $modulesWithMessages ) ) {
-                       $res = $dbr->select( 'msg_resource', array( 'mr_resource', 'mr_timestamp' ), array(
-                                       'mr_resource' => $modulesWithMessages,
-                                       'mr_lang' => $lang
-                               ), __METHOD__
-                       );
-                       foreach ( $res as $row ) {
-                               $module = $this->getModule( $row->mr_resource );
-                               if ( $module ) {
-                                       $module->setMsgBlobMtime( $lang, wfTimestamp( TS_UNIX, $row->mr_timestamp ) );
-                                       unset( $modulesWithoutMessages[$row->mr_resource] );
-                               }
+                       if ( $module && $module->getMessages() ) {
+                               $modules[$name] = $module;
                        }
                }
-               foreach ( array_keys( $modulesWithoutMessages ) as $name ) {
-                       $module = $this->getModule( $name );
-                       if ( $module ) {
-                               $module->setMsgBlobMtime( $lang, 1 );
-                       }
+               $store = $this->getMessageBlobStore();
+               $blobs = $store->getBlobs( $modules, $lang );
+               foreach ( $blobs as $name => $blob ) {
+                       $modules[$name]->setMessageBlob( $blob, $lang );
                }
        }
 
@@ -197,7 +182,7 @@ class ResourceLoader implements LoggerAwareInterface {
                }
 
                $stats = RequestContext::getMain()->getStats();
-               $cache = ObjectCache::newAccelerator( CACHE_ANYTHING );
+               $cache = ObjectCache::getLocalServerInstance( CACHE_ANYTHING );
 
                $key = $cache->makeGlobalKey(
                        'resourceloader',
@@ -241,15 +226,13 @@ class ResourceLoader implements LoggerAwareInterface {
 
        /**
         * Register core modules and runs registration hooks.
-        * @param Config|null $config
+        * @param Config $config [optional]
+        * @param LoggerInterface $logger [optional]
         */
        public function __construct( Config $config = null, LoggerInterface $logger = null ) {
                global $IP;
 
-               if ( !$logger ) {
-                       $logger = new NullLogger();
-               }
-               $this->setLogger( $logger );
+               $this->logger = $logger ?: new NullLogger();
 
                if ( !$config ) {
                        $this->logger->debug( __METHOD__ . ' was called without providing a Config instance' );
@@ -274,7 +257,7 @@ class ResourceLoader implements LoggerAwareInterface {
                        $this->registerTestModules();
                }
 
-               $this->setMessageBlobStore( new MessageBlobStore() );
+               $this->setMessageBlobStore( new MessageBlobStore( $this, $this->logger ) );
        }
 
        /**
@@ -284,10 +267,22 @@ class ResourceLoader implements LoggerAwareInterface {
                return $this->config;
        }
 
+       /**
+        * @since 1.26
+        * @param LoggerInterface $logger
+        */
        public function setLogger( LoggerInterface $logger ) {
                $this->logger = $logger;
        }
 
+       /**
+        * @since 1.27
+        * @return LoggerInterface
+        */
+       public function getLogger() {
+               return $this->logger;
+       }
+
        /**
         * @since 1.26
         * @return MessageBlobStore
@@ -435,6 +430,8 @@ class ResourceLoader implements LoggerAwareInterface {
        /**
         * Add a foreign source of modules.
         *
+        * Source IDs are typically the same as the Wiki ID or database name (e.g. lowercase a-z).
+        *
         * @param array|string $id Source ID (string), or array( id1 => loadUrl, id2 => loadUrl, ... )
         * @param string|array $loadUrl load.php url (string), or array with loadUrl key for
         *  backwards-compatibility.
@@ -546,6 +543,7 @@ class ResourceLoader implements LoggerAwareInterface {
                                /** @var ResourceLoaderModule $object */
                                $object = new $class( $info );
                                $object->setConfig( $this->getConfig() );
+                               $object->setLogger( $this->logger );
                        }
                        $object->setName( $name );
                        $this->modules[$name] = $object;
@@ -664,7 +662,7 @@ class ResourceLoader implements LoggerAwareInterface {
                }
 
                try {
-                       // Preload for getCombinedVersion()
+                       // Preload for getCombinedVersion() and for batch makeModuleResponse()
                        $this->preloadModuleInfo( array_keys( $modules ), $context );
                } catch ( Exception $e ) {
                        MWExceptionHandler::logException( $e );
@@ -708,8 +706,11 @@ class ResourceLoader implements LoggerAwareInterface {
 
                // Capture any PHP warnings from the output buffer and append them to the
                // error list if we're in debug mode.
-               if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) {
-                       $this->errors[] = $warnings;
+               if ( $context->getDebug() ) {
+                       $warnings = ob_get_contents();
+                       if ( strlen( $warnings ) ) {
+                               $this->errors[] = $warnings;
+                       }
                }
 
                // Save response to file cache unless there are errors
@@ -799,11 +800,6 @@ class ResourceLoader implements LoggerAwareInterface {
                        $exp = min( $maxage, $smaxage );
                        header( 'Expires: ' . wfTimestamp( TS_RFC2822, $exp + time() ) );
                }
-
-               // Send the current time expressed as fractional seconds since epoch,
-               // with microsecond precision. This helps distinguish hits from misses
-               // in edge caches.
-               header( 'MediaWiki-Timestamp: ' . microtime( true ) );
        }
 
        /**
@@ -877,8 +873,11 @@ class ResourceLoader implements LoggerAwareInterface {
                        $response = $fileCache->fetchText();
                        // Capture any PHP warnings from the output buffer and append them to the
                        // response in a comment if we're in debug mode.
-                       if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) {
-                               $response = self::makeComment( $warnings ) . $response;
+                       if ( $context->getDebug() ) {
+                               $warnings = ob_get_contents();
+                               if ( strlen( $warnings ) ) {
+                                       $response = self::makeComment( $warnings ) . $response;
+                               }
                        }
                        // Remove the output buffer and output the response
                        ob_end_clean();
@@ -963,19 +962,6 @@ MESSAGE;
                        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';
                }
@@ -1068,6 +1054,23 @@ MESSAGE;
                return $out;
        }
 
+       /**
+        * Get names of modules that use a certain message.
+        *
+        * @param string $messageKey
+        * @return array List of module names
+        */
+       public function getModulesByMessage( $messageKey ) {
+               $moduleNames = array();
+               foreach ( $this->getModuleNames() as $moduleName ) {
+                       $module = $this->getModule( $moduleName );
+                       if ( in_array( $messageKey, $module->getMessages() ) ) {
+                               $moduleNames[] = $moduleName;
+                       }
+               }
+               return $moduleNames;
+       }
+
        /* Static Methods */
 
        /**