Merge "mw.Feedback: If the message is posted remotely, link the title correctly"
[lhc/web/wiklou.git] / includes / config / ConfigFactory.php
index 09b0baa..2c7afda 100644 (file)
  *
  * @file
  */
+use MediaWiki\Services\SalvageableService;
+use Wikimedia\Assert\Assert;
 
 /**
  * Factory class to create Config objects
  *
  * @since 1.23
  */
-class ConfigFactory {
+class ConfigFactory implements SalvageableService {
 
        /**
         * Map of config name => callback
@@ -50,6 +52,41 @@ class ConfigFactory {
                return \MediaWiki\MediaWikiServices::getInstance()->getConfigFactory();
        }
 
+       /**
+        * Re-uses existing Cache objects from $other. Cache objects are only re-used if the
+        * registered factory function for both is the same. Cache config is not copied,
+        * and only instances of caches defined on this instance with the same config
+        * are copied.
+        *
+        * @see SalvageableService::salvage()
+        *
+        * @param SalvageableService $other The object to salvage state from. $other must have the
+        * exact same type as $this.
+        */
+       public function salvage( SalvageableService $other ) {
+               Assert::parameterType( self::class, $other, '$other' );
+
+               /** @var ConfigFactory $other */
+               foreach ( $other->factoryFunctions as $name => $otherFunc ) {
+                       if ( !isset( $this->factoryFunctions[$name] ) ) {
+                               continue;
+                       }
+
+                       // if the callback function is the same, salvage the Cache object
+                       // XXX: Closures are never equal!
+                       if ( isset( $other->configs[$name] )
+                               && $this->factoryFunctions[$name] == $otherFunc
+                       ) {
+                               $this->configs[$name] = $other->configs[$name];
+                               unset( $other->configs[$name] );
+                       }
+               }
+
+               // disable $other
+               $other->factoryFunctions = [];
+               $other->configs = [];
+       }
+
        /**
         * @return string[]
         */
@@ -62,28 +99,21 @@ class ConfigFactory {
         * Will override if it's already registered.
         * Use "*" for $name to provide a fallback config for all unknown names.
         * @param string $name
-        * @param callable|Config $callback A factory callabck that takes this ConfigFactory
+        * @param callable|Config $callback A factory callback that takes this ConfigFactory
         *        as an argument and returns a Config instance, or an existing Config instance.
         * @throws InvalidArgumentException If an invalid callback is provided
         */
        public function register( $name, $callback ) {
-               if ( $callback instanceof Config ) {
-                       $instance = $callback;
-
-                       // Register a callback anyway, for consistency. Note that getConfigNames()
-                       // relies on $factoryFunctions to have all config names.
-                       $callback = function() use ( $instance ) {
-                               return $instance;
-                       };
-               } else {
-                       $instance = null;
-               }
-
-               if ( !is_callable( $callback ) ) {
-                       throw new InvalidArgumentException( 'Invalid callback provided' );
+               if ( !is_callable( $callback ) && !( $callback instanceof Config ) ) {
+                       if ( is_array( $callback ) ) {
+                               $callback = '[ ' . implode( ', ', $callback ) . ' ]';
+                       } elseif ( is_object( $callback ) ) {
+                               $callback = 'instanceof ' . get_class( $callback );
+                       }
+                       throw new InvalidArgumentException( 'Invalid callback \'' . $callback . '\' provided' );
                }
 
-               $this->configs[$name] = $instance;
+               unset( $this->configs[$name] );
                $this->factoryFunctions[$name] = $callback;
        }
 
@@ -105,7 +135,13 @@ class ConfigFactory {
                        if ( !isset( $this->factoryFunctions[$key] ) ) {
                                throw new ConfigException( "No registered builder available for $name." );
                        }
-                       $conf = call_user_func( $this->factoryFunctions[$key], $this );
+
+                       if ( $this->factoryFunctions[$key] instanceof Config ) {
+                               $conf = $this->factoryFunctions[$key];
+                       } else {
+                               $conf = call_user_func( $this->factoryFunctions[$key], $this );
+                       }
+
                        if ( $conf instanceof Config ) {
                                $this->configs[$name] = $conf;
                        } else {