X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/config/ConfigFactory.php diff --git a/includes/config/ConfigFactory.php b/includes/config/ConfigFactory.php new file mode 100644 index 00000000..cd25352d --- /dev/null +++ b/includes/config/ConfigFactory.php @@ -0,0 +1,150 @@ + callback + * @var array + */ + protected $factoryFunctions = []; + + /** + * Config objects that have already been created + * name => Config object + * @var array + */ + protected $configs = []; + + /** + * @deprecated since 1.27, use MediaWikiServices::getConfigFactory() instead. + * + * @return ConfigFactory + */ + public static function getDefaultInstance() { + 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[] + */ + public function getConfigNames() { + return array_keys( $this->factoryFunctions ); + } + + /** + * Register a new config factory function. + * 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 + * 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 ( !is_callable( $callback ) && !( $callback instanceof Config ) ) { + throw new InvalidArgumentException( 'Invalid callback provided' ); + } + + unset( $this->configs[$name] ); + $this->factoryFunctions[$name] = $callback; + } + + /** + * Create a given Config using the registered callback for $name. + * If an object was already created, the same Config object is returned. + * @param string $name Name of the extension/component you want a Config object for + * 'main' is used for core + * @throws ConfigException If a factory function isn't registered for $name + * @throws UnexpectedValueException If the factory function returns a non-Config object + * @return Config + */ + public function makeConfig( $name ) { + if ( !isset( $this->configs[$name] ) ) { + $key = $name; + if ( !isset( $this->factoryFunctions[$key] ) ) { + $key = '*'; + } + if ( !isset( $this->factoryFunctions[$key] ) ) { + throw new ConfigException( "No registered builder available for $name." ); + } + + 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 { + throw new UnexpectedValueException( "The builder for $name returned a non-Config object." ); + } + } + + return $this->configs[$name]; + } + +}