Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
91.18% |
31 / 34 |
|
85.71% |
6 / 7 |
CRAP | |
0.00% |
0 / 1 |
SkinFactory | |
91.18% |
31 / 34 |
|
85.71% |
6 / 7 |
14.13 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
register | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
6 | |||
getSkinNames | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
makeSkin | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
getAllowedSkins | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getInstalledSkins | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSkinOptions | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 |
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 | use Wikimedia\ObjectFactory\ObjectFactory; |
25 | |
26 | /** |
27 | * Factory class to create Skin objects |
28 | * |
29 | * @since 1.24 |
30 | */ |
31 | class SkinFactory { |
32 | private const SKIP_BY_SITECONFIG = 1; |
33 | private const SKIP_BY_REGISTER = 2; |
34 | |
35 | /** |
36 | * Map of skin name to object factory spec or factory function. |
37 | * |
38 | * @var array<string,array|callable> |
39 | */ |
40 | private $factoryFunctions = []; |
41 | /** |
42 | * Map of name => fallback human-readable name, used when the 'skinname-<skin>' message is not |
43 | * available |
44 | * |
45 | * @var array |
46 | */ |
47 | private $displayNames = []; |
48 | /** |
49 | * @var ObjectFactory |
50 | */ |
51 | private $objectFactory; |
52 | |
53 | /** |
54 | * Array of skins that should not be presented in the list of |
55 | * available skins in user preferences, while they're still installed. |
56 | * |
57 | * @var array<string,int> |
58 | */ |
59 | private $skipSkins; |
60 | |
61 | /** |
62 | * @internal For ServiceWiring only |
63 | * |
64 | * @param ObjectFactory $objectFactory |
65 | * @param string[] $skipSkins |
66 | */ |
67 | public function __construct( ObjectFactory $objectFactory, array $skipSkins ) { |
68 | $this->objectFactory = $objectFactory; |
69 | $this->skipSkins = array_fill_keys( $skipSkins, self::SKIP_BY_SITECONFIG ); |
70 | } |
71 | |
72 | /** |
73 | * Register a new skin. |
74 | * |
75 | * This will replace any previously registered skin by the same name. |
76 | * |
77 | * @param string $name Internal skin name. See also Skin::__construct. |
78 | * @param string $displayName For backwards-compatibility with old skin loading system. This is |
79 | * the text used as skin's human-readable name when the 'skinname-<skin>' message is not |
80 | * available. |
81 | * @param array|callable $spec ObjectFactory spec to construct a Skin object, |
82 | * or callback that takes a skin name and returns a Skin object. |
83 | * See Skin::__construct for the constructor arguments. |
84 | * @param true|null $skippable Whether the skin is skippable and should be hidden |
85 | * from user preferences. By default, this is determined based by $wgSkipSkins. |
86 | */ |
87 | public function register( $name, $displayName, $spec, ?bool $skippable = null ) { |
88 | if ( !is_callable( $spec ) ) { |
89 | if ( is_array( $spec ) ) { |
90 | if ( !isset( $spec['args'] ) ) { |
91 | // make sure name option is set: |
92 | $spec['args'] = [ |
93 | [ 'name' => $name ] |
94 | ]; |
95 | } |
96 | } else { |
97 | throw new InvalidArgumentException( 'Invalid callback provided' ); |
98 | } |
99 | } |
100 | $this->factoryFunctions[$name] = $spec; |
101 | $this->displayNames[$name] = $displayName; |
102 | |
103 | // If skipped by site config, leave as-is. |
104 | if ( ( $this->skipSkins[$name] ?? null ) !== self::SKIP_BY_SITECONFIG ) { |
105 | if ( $skippable === true ) { |
106 | $this->skipSkins[$name] = self::SKIP_BY_REGISTER; |
107 | } else { |
108 | // Make sure the register() call is unaffected by previous calls. |
109 | unset( $this->skipSkins[$name] ); |
110 | } |
111 | } |
112 | } |
113 | |
114 | /** |
115 | * Return an associative array of `skin name => human readable name`. |
116 | * |
117 | * @deprecated since 1.37 Use getInstalledSkins instead |
118 | * @return array |
119 | */ |
120 | public function getSkinNames() { |
121 | wfDeprecated( __METHOD__, '1.37' ); |
122 | return $this->displayNames; |
123 | } |
124 | |
125 | /** |
126 | * Create a given Skin using the registered callback for $name. |
127 | * |
128 | * @param string $name Name of the skin you want |
129 | * @throws SkinException If a factory function isn't registered for $name |
130 | * @return Skin |
131 | */ |
132 | public function makeSkin( $name ) { |
133 | if ( !isset( $this->factoryFunctions[$name] ) ) { |
134 | throw new SkinException( "No registered builder available for $name." ); |
135 | } |
136 | |
137 | return $this->objectFactory->createObject( |
138 | $this->factoryFunctions[$name], |
139 | [ |
140 | 'allowCallable' => true, |
141 | 'assertClass' => Skin::class, |
142 | ] |
143 | ); |
144 | } |
145 | |
146 | /** |
147 | * Get the list of user-selectable skins. |
148 | * |
149 | * Useful for Special:Preferences and other places where you |
150 | * only want to show skins users _can_ select from preferences page, |
151 | * thus excluding those as configured by $wgSkipSkins. |
152 | * |
153 | * @return string[] |
154 | * @since 1.36 |
155 | */ |
156 | public function getAllowedSkins() { |
157 | $skins = $this->getInstalledSkins(); |
158 | |
159 | foreach ( $this->skipSkins as $name => $_ ) { |
160 | unset( $skins[$name] ); |
161 | } |
162 | |
163 | return $skins; |
164 | } |
165 | |
166 | /** |
167 | * Get the list of installed skins. |
168 | * |
169 | * Returns an associative array of skin name => human readable name |
170 | * |
171 | * @return string[] |
172 | * @since 1.37 |
173 | */ |
174 | public function getInstalledSkins() { |
175 | return $this->displayNames; |
176 | } |
177 | |
178 | /** |
179 | * Return options provided for a given skin name |
180 | * |
181 | * For documentation about keys you can expect to exist, |
182 | * and their default values, refer to the Skin constructor. |
183 | * |
184 | * @since 1.38 |
185 | * @param string $name Name of the skin you want options from |
186 | * @return array |
187 | */ |
188 | public function getSkinOptions( string $name ): array { |
189 | $skin = $this->makeSkin( $name ); |
190 | $options = $skin->getOptions(); |
191 | return $options; |
192 | } |
193 | } |