Completed
Branch master (13ece3)
by
unknown
22:07
created

ConfigFactory::salvage()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 5
eloc 11
nc 4
nop 1
dl 0
loc 23
rs 8.5906
1
<?php
2
3
/**
4
 * Copyright 2014
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * with this program; if not, write to the Free Software Foundation, Inc.,
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 * http://www.gnu.org/copyleft/gpl.html
20
 *
21
 * @file
22
 */
23
use MediaWiki\Services\SalvageableService;
24
use Wikimedia\Assert\Assert;
25
26
/**
27
 * Factory class to create Config objects
28
 *
29
 * @since 1.23
30
 */
31
class ConfigFactory implements SalvageableService {
32
33
	/**
34
	 * Map of config name => callback
35
	 * @var array
36
	 */
37
	protected $factoryFunctions = [];
38
39
	/**
40
	 * Config objects that have already been created
41
	 * name => Config object
42
	 * @var array
43
	 */
44
	protected $configs = [];
45
46
	/**
47
	 * @deprecated since 1.27, use MediaWikiServices::getConfigFactory() instead.
48
	 *
49
	 * @return ConfigFactory
50
	 */
51
	public static function getDefaultInstance() {
52
		return \MediaWiki\MediaWikiServices::getInstance()->getConfigFactory();
53
	}
54
55
	/**
56
	 * Re-uses existing Cache objects from $other. Cache objects are only re-used if the
57
	 * registered factory function for both is the same. Cache config is not copied,
58
	 * and only instances of caches defined on this instance with the same config
59
	 * are copied.
60
	 *
61
	 * @see SalvageableService::salvage()
62
	 *
63
	 * @param SalvageableService $other The object to salvage state from. $other must have the
64
	 * exact same type as $this.
65
	 */
66
	public function salvage( SalvageableService $other ) {
67
		Assert::parameterType( self::class, $other, '$other' );
68
69
		/** @var ConfigFactory $other */
70
		foreach ( $other->factoryFunctions as $name => $otherFunc ) {
71
			if ( !isset( $this->factoryFunctions[$name] ) ) {
72
				continue;
73
			}
74
75
			// if the callback function is the same, salvage the Cache object
76
			// XXX: Closures are never equal!
77
			if ( isset( $other->configs[$name] )
78
				&& $this->factoryFunctions[$name] == $otherFunc
79
			) {
80
				$this->configs[$name] = $other->configs[$name];
81
				unset( $other->configs[$name] );
82
			}
83
		}
84
85
		// disable $other
86
		$other->factoryFunctions = [];
87
		$other->configs = [];
88
	}
89
90
	/**
91
	 * @return string[]
92
	 */
93
	public function getConfigNames() {
94
		return array_keys( $this->factoryFunctions );
95
	}
96
97
	/**
98
	 * Register a new config factory function.
99
	 * Will override if it's already registered.
100
	 * Use "*" for $name to provide a fallback config for all unknown names.
101
	 * @param string $name
102
	 * @param callable|Config $callback A factory callabck that takes this ConfigFactory
103
	 *        as an argument and returns a Config instance, or an existing Config instance.
104
	 * @throws InvalidArgumentException If an invalid callback is provided
105
	 */
106
	public function register( $name, $callback ) {
107
		if ( !is_callable( $callback ) && !( $callback instanceof Config ) ) {
108
			throw new InvalidArgumentException( 'Invalid callback provided' );
109
		}
110
111
		unset( $this->configs[$name] );
112
		$this->factoryFunctions[$name] = $callback;
113
	}
114
115
	/**
116
	 * Create a given Config using the registered callback for $name.
117
	 * If an object was already created, the same Config object is returned.
118
	 * @param string $name Name of the extension/component you want a Config object for
119
	 *                     'main' is used for core
120
	 * @throws ConfigException If a factory function isn't registered for $name
121
	 * @throws UnexpectedValueException If the factory function returns a non-Config object
122
	 * @return Config
123
	 */
124
	public function makeConfig( $name ) {
125
		if ( !isset( $this->configs[$name] ) ) {
126
			$key = $name;
127
			if ( !isset( $this->factoryFunctions[$key] ) ) {
128
				$key = '*';
129
			}
130
			if ( !isset( $this->factoryFunctions[$key] ) ) {
131
				throw new ConfigException( "No registered builder available for $name." );
132
			}
133
134
			if ( $this->factoryFunctions[$key] instanceof Config ) {
135
				$conf = $this->factoryFunctions[$key];
136
			} else {
137
				$conf = call_user_func( $this->factoryFunctions[$key], $this );
138
			}
139
140
			if ( $conf instanceof Config ) {
141
				$this->configs[$name] = $conf;
142
			} else {
143
				throw new UnexpectedValueException( "The builder for $name returned a non-Config object." );
144
			}
145
		}
146
147
		return $this->configs[$name];
148
	}
149
150
}
151