Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
93.94% |
31 / 33 |
|
75.00% |
3 / 4 |
CRAP | |
0.00% |
0 / 1 |
ConfigFactory | |
96.88% |
31 / 32 |
|
75.00% |
3 / 4 |
17 | |
0.00% |
0 / 1 |
salvage | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
5 | |||
getConfigNames | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
register | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
5.05 | |||
makeConfig | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
6 |
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 | |
24 | namespace MediaWiki\Config; |
25 | |
26 | use InvalidArgumentException; |
27 | use UnexpectedValueException; |
28 | use Wikimedia\Assert\Assert; |
29 | use Wikimedia\Services\SalvageableService; |
30 | |
31 | /** |
32 | * Factory class to create Config objects |
33 | * |
34 | * @since 1.23 |
35 | */ |
36 | class ConfigFactory implements SalvageableService { |
37 | |
38 | /** |
39 | * Map of config name => callback |
40 | * @var array |
41 | */ |
42 | protected $factoryFunctions = []; |
43 | |
44 | /** |
45 | * Config objects that have already been created |
46 | * name => Config object |
47 | * @var array |
48 | */ |
49 | protected $configs = []; |
50 | |
51 | /** |
52 | * Re-uses existing Cache objects from $other. Cache objects are only re-used if the |
53 | * registered factory function for both is the same. Cache config is not copied, |
54 | * and only instances of caches defined on this instance with the same config |
55 | * are copied. |
56 | * |
57 | * @see SalvageableService::salvage() |
58 | * |
59 | * @param SalvageableService $other The object to salvage state from. $other must have the |
60 | * exact same type as $this. |
61 | */ |
62 | public function salvage( SalvageableService $other ) { |
63 | Assert::parameterType( self::class, $other, '$other' ); |
64 | |
65 | /** @var self $other */ |
66 | '@phan-var self $other'; |
67 | foreach ( $other->factoryFunctions as $name => $otherFunc ) { |
68 | if ( !isset( $this->factoryFunctions[$name] ) ) { |
69 | continue; |
70 | } |
71 | |
72 | // if the callback function is the same, salvage the Cache object |
73 | // XXX: Closures are never equal! |
74 | if ( isset( $other->configs[$name] ) |
75 | && $this->factoryFunctions[$name] == $otherFunc |
76 | ) { |
77 | $this->configs[$name] = $other->configs[$name]; |
78 | unset( $other->configs[$name] ); |
79 | } |
80 | } |
81 | |
82 | // disable $other |
83 | $other->factoryFunctions = []; |
84 | $other->configs = []; |
85 | } |
86 | |
87 | /** |
88 | * @return string[] |
89 | */ |
90 | public function getConfigNames() { |
91 | return array_keys( $this->factoryFunctions ); |
92 | } |
93 | |
94 | /** |
95 | * Register a new config factory function. |
96 | * Will override if it's already registered. |
97 | * Use "*" for $name to provide a fallback config for all unknown names. |
98 | * @param string $name |
99 | * @param callable|Config $callback A factory callback that takes this ConfigFactory |
100 | * as an argument and returns a Config instance, or an existing Config instance. |
101 | * @throws InvalidArgumentException If an invalid callback is provided |
102 | */ |
103 | public function register( $name, $callback ) { |
104 | if ( !is_callable( $callback ) && !( $callback instanceof Config ) ) { |
105 | if ( is_array( $callback ) ) { |
106 | $callback = '[ ' . implode( ', ', $callback ) . ' ]'; |
107 | } elseif ( is_object( $callback ) ) { |
108 | $callback = 'instanceof ' . get_class( $callback ); |
109 | } |
110 | throw new InvalidArgumentException( 'Invalid callback \'' . $callback . '\' provided' ); |
111 | } |
112 | |
113 | unset( $this->configs[$name] ); |
114 | $this->factoryFunctions[$name] = $callback; |
115 | } |
116 | |
117 | /** |
118 | * Create a given Config using the registered callback for $name. |
119 | * If an object was already created, the same Config object is returned. |
120 | * @param string $name Name of the extension/component you want a Config object for |
121 | * 'main' is used for core |
122 | * @throws ConfigException If a factory function isn't registered for $name |
123 | * @throws UnexpectedValueException If the factory function returns a non-Config object |
124 | * @return Config |
125 | */ |
126 | public function makeConfig( $name ) { |
127 | if ( !isset( $this->configs[$name] ) ) { |
128 | $key = $name; |
129 | if ( !isset( $this->factoryFunctions[$key] ) ) { |
130 | $key = '*'; |
131 | } |
132 | if ( !isset( $this->factoryFunctions[$key] ) ) { |
133 | throw new ConfigException( "No registered builder available for $name." ); |
134 | } |
135 | |
136 | if ( $this->factoryFunctions[$key] instanceof Config ) { |
137 | $conf = $this->factoryFunctions[$key]; |
138 | } else { |
139 | $conf = call_user_func( $this->factoryFunctions[$key], $this ); |
140 | } |
141 | |
142 | if ( $conf instanceof Config ) { |
143 | $this->configs[$name] = $conf; |
144 | } else { |
145 | throw new UnexpectedValueException( "The builder for $name returned a non-Config object." ); |
146 | } |
147 | } |
148 | |
149 | return $this->configs[$name]; |
150 | } |
151 | |
152 | } |
153 | |
154 | /** @deprecated class alias since 1.41 */ |
155 | class_alias( ConfigFactory::class, 'ConfigFactory' ); |