registration: Allow setting $wgNamespaceProtection
[lhc/web/wiklou.git] / includes / registration / ExtensionProcessor.php
1 <?php
2
3 class ExtensionProcessor implements Processor {
4
5 /**
6 * Keys that should be set to $GLOBALS
7 *
8 * @var array
9 */
10 protected static $globalSettings = array(
11 'ResourceLoaderSources',
12 'ResourceLoaderLESSVars',
13 'ResourceLoaderLESSImportPaths',
14 'DefaultUserOptions',
15 'HiddenPrefs',
16 'GroupPermissions',
17 'RevokePermissions',
18 'ImplicitGroups',
19 'GroupsAddToSelf',
20 'GroupsRemoveFromSelf',
21 'AddGroups',
22 'RemoveGroups',
23 'AvailableRights',
24 'ContentHandlers',
25 'ConfigRegistry',
26 'RateLimits',
27 'RecentChangesFlags',
28 'MediaHandlers',
29 'ExtensionFunctions',
30 'ExtensionEntryPointListFiles',
31 'SpecialPages',
32 'JobClasses',
33 'LogTypes',
34 'LogRestrictions',
35 'FilterLogTypes',
36 'LogNames',
37 'LogHeaders',
38 'LogActions',
39 'LogActionsHandlers',
40 'Actions',
41 'APIModules',
42 'APIFormatModules',
43 'APIMetaModules',
44 'APIPropModules',
45 'APIListModules',
46 'ValidSkinNames',
47 );
48
49 /**
50 * Mapping of global settings to their specific merge strategies.
51 *
52 * @see ExtensionRegistry::exportExtractedData
53 * @see getExtractedInfo
54 * @var array
55 */
56 protected static $mergeStrategies = array(
57 'wgGroupPermissions' => 'array_plus_2d',
58 'wgRevokePermissions' => 'array_plus_2d',
59 'wgHooks' => 'array_merge_recursive',
60 'wgExtensionCredits' => 'array_merge_recursive',
61 'wgExtraNamespaces' => 'array_plus',
62 'wgExtraGenderNamespaces' => 'array_plus',
63 'wgNamespacesWithSubpages' => 'array_plus',
64 'wgNamespaceContentModels' => 'array_plus',
65 'wgNamespaceProtection' => 'array_plus',
66 );
67
68 /**
69 * Keys that are part of the extension credits
70 *
71 * @var array
72 */
73 protected static $creditsAttributes = array(
74 'name',
75 'namemsg',
76 'author',
77 'version',
78 'url',
79 'description',
80 'descriptionmsg',
81 'license-name',
82 );
83
84 /**
85 * Things that are not 'attributes', but are not in
86 * $globalSettings or $creditsAttributes.
87 *
88 * @var array
89 */
90 protected static $notAttributes = array(
91 'callback',
92 'Hooks',
93 'namespaces',
94 'ResourceFileModulePaths',
95 'ResourceModules',
96 'ResourceModuleSkinStyles',
97 'ExtensionMessagesFiles',
98 'MessagesDirs',
99 'type',
100 'config',
101 'ParserTestFiles',
102 'AutoloadClasses',
103 'manifest_version',
104 );
105
106 /**
107 * Stuff that is going to be set to $GLOBALS
108 *
109 * Some keys are pre-set to arrays so we can += to them
110 *
111 * @var array
112 */
113 protected $globals = array(
114 'wgExtensionMessagesFiles' => array(),
115 'wgMessagesDirs' => array(),
116 );
117
118 /**
119 * Things that should be define()'d
120 *
121 * @var array
122 */
123 protected $defines = array();
124
125 /**
126 * Things to be called once registration of these extensions are done
127 *
128 * @var callable[]
129 */
130 protected $callbacks = array();
131
132 /**
133 * @var array
134 */
135 protected $credits = array();
136
137 /**
138 * Any thing else in the $info that hasn't
139 * already been processed
140 *
141 * @var array
142 */
143 protected $attributes = array();
144
145 /**
146 * @param string $path
147 * @param array $info
148 * @param int $version manifest_version for info
149 * @return array
150 */
151 public function extractInfo( $path, array $info, $version ) {
152 $this->extractConfig( $info );
153 $this->extractHooks( $info );
154 $dir = dirname( $path );
155 $this->extractExtensionMessagesFiles( $dir, $info );
156 $this->extractMessagesDirs( $dir, $info );
157 $this->extractNamespaces( $info );
158 $this->extractResourceLoaderModules( $dir, $info );
159 $this->extractParserTestFiles( $dir, $info );
160 if ( isset( $info['callback'] ) ) {
161 $this->callbacks[] = $info['callback'];
162 }
163
164 $this->extractCredits( $path, $info );
165 foreach ( $info as $key => $val ) {
166 if ( in_array( $key, self::$globalSettings ) ) {
167 $this->storeToArray( "wg$key", $val, $this->globals );
168 // Ignore anything that starts with a @
169 } elseif ( $key[0] !== '@' && !in_array( $key, self::$notAttributes )
170 && !in_array( $key, self::$creditsAttributes )
171 ) {
172 $this->storeToArray( $key, $val, $this->attributes );
173 }
174 }
175 }
176
177 public function getExtractedInfo() {
178 // Make sure the merge strategies are set
179 foreach ( $this->globals as $key => $val ) {
180 if ( isset( self::$mergeStrategies[$key] ) ) {
181 $this->globals[$key][ExtensionRegistry::MERGE_STRATEGY] = self::$mergeStrategies[$key];
182 }
183 }
184
185 return array(
186 'globals' => $this->globals,
187 'defines' => $this->defines,
188 'callbacks' => $this->callbacks,
189 'credits' => $this->credits,
190 'attributes' => $this->attributes,
191 );
192 }
193
194 protected function extractHooks( array $info ) {
195 if ( isset( $info['Hooks'] ) ) {
196 foreach ( $info['Hooks'] as $name => $value ) {
197 foreach ( (array)$value as $callback ) {
198 $this->globals['wgHooks'][$name][] = $callback;
199 }
200 }
201 }
202 }
203
204 /**
205 * Register namespaces with the appropriate global settings
206 *
207 * @param array $info
208 */
209 protected function extractNamespaces( array $info ) {
210 if ( isset( $info['namespaces'] ) ) {
211 foreach ( $info['namespaces'] as $ns ) {
212 $id = $ns['id'];
213 $this->defines[$ns['constant']] = $id;
214 $this->globals['wgExtraNamespaces'][$id] = $ns['name'];
215 if ( isset( $ns['gender'] ) ) {
216 $this->globals['wgExtraGenderNamespaces'][$id] = $ns['gender'];
217 }
218 if ( isset( $ns['subpages'] ) && $ns['subpages'] ) {
219 $this->globals['wgNamespacesWithSubpages'][$id] = true;
220 }
221 if ( isset( $ns['content'] ) && $ns['content'] ) {
222 $this->globals['wgContentNamespaces'][] = $id;
223 }
224 if ( isset( $ns['defaultcontentmodel'] ) ) {
225 $this->globals['wgNamespaceContentModels'][$id] = $ns['defaultcontentmodel'];
226 }
227 if ( isset( $ns['protection'] ) ) {
228 $this->globals['wgNamespaceProtection'][$id] = $ns['protection'];
229 }
230 }
231 }
232 }
233
234 protected function extractResourceLoaderModules( $dir, array $info ) {
235 $defaultPaths = isset( $info['ResourceFileModulePaths'] )
236 ? $info['ResourceFileModulePaths']
237 : false;
238 if ( isset( $defaultPaths['localBasePath'] ) ) {
239 $defaultPaths['localBasePath'] = "$dir/{$defaultPaths['localBasePath']}";
240 }
241
242 foreach ( array( 'ResourceModules', 'ResourceModuleSkinStyles' ) as $setting ) {
243 if ( isset( $info[$setting] ) ) {
244 foreach ( $info[$setting] as $name => $data ) {
245 if ( isset( $data['localBasePath'] ) ) {
246 $data['localBasePath'] = "$dir/{$data['localBasePath']}";
247 }
248 if ( $defaultPaths ) {
249 $data += $defaultPaths;
250 }
251 $this->globals["wg$setting"][$name] = $data;
252 }
253 }
254 }
255 }
256
257 protected function extractExtensionMessagesFiles( $dir, array $info ) {
258 if ( isset( $info['ExtensionMessagesFiles'] ) ) {
259 $this->globals["wgExtensionMessagesFiles"] += array_map( function( $file ) use ( $dir ) {
260 return "$dir/$file";
261 }, $info['ExtensionMessagesFiles'] );
262 }
263 }
264
265 /**
266 * Set message-related settings, which need to be expanded to use
267 * absolute paths
268 *
269 * @param string $dir
270 * @param array $info
271 */
272 protected function extractMessagesDirs( $dir, array $info ) {
273 if ( isset( $info['MessagesDirs'] ) ) {
274 foreach ( $info['MessagesDirs'] as $name => $files ) {
275 foreach ( (array)$files as $file ) {
276 $this->globals["wgMessagesDirs"][$name][] = "$dir/$file";
277 }
278 }
279 }
280 }
281
282 protected function extractCredits( $path, array $info ) {
283 $credits = array(
284 'path' => $path,
285 'type' => isset( $info['type'] ) ? $info['type'] : 'other',
286 );
287 foreach ( self::$creditsAttributes as $attr ) {
288 if ( isset( $info[$attr] ) ) {
289 $credits[$attr] = $info[$attr];
290 }
291 }
292
293 $this->credits[$credits['name']] = $credits;
294 }
295
296 /**
297 * Set configuration settings
298 * @todo In the future, this should be done via Config interfaces
299 *
300 * @param array $info
301 */
302 protected function extractConfig( array $info ) {
303 if ( isset( $info['config'] ) ) {
304 foreach ( $info['config'] as $key => $val ) {
305 if ( $key[0] !== '@' ) {
306 $this->globals["wg$key"] = $val;
307 }
308 }
309 }
310 }
311
312 protected function extractParserTestFiles( $dir, array $info ) {
313 if ( isset( $info['ParserTestFiles'] ) ) {
314 foreach ( $info['ParserTestFiles'] as $path ) {
315 $this->globals['wgParserTestFiles'][] = "$dir/$path";
316 }
317 }
318 }
319
320 /**
321 * @param string $name
322 * @param array $value
323 * @param array &$array
324 * @throws InvalidArgumentException
325 */
326 protected function storeToArray( $name, $value, &$array ) {
327 if ( !is_array( $value ) ) {
328 throw new InvalidArgumentException( "The value for '$name' should be an array" );
329 }
330 if ( isset( $array[$name] ) ) {
331 $array[$name] = array_merge_recursive( $array[$name], $value );
332 } else {
333 $array[$name] = $value;
334 }
335 }
336 }