Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
32 / 32 |
|
100.00% |
3 / 3 |
CRAP | |
100.00% |
1 / 1 |
ServiceOptions | |
100.00% |
32 / 32 |
|
100.00% |
3 / 3 |
17 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
8 | |||
assertRequiredOptions | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
7 | |||
get | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Config; |
4 | |
5 | use InvalidArgumentException; |
6 | use Wikimedia\Assert\Assert; |
7 | |
8 | /** |
9 | * A class for passing options to services. It can be constructed from a Config, and in practice |
10 | * most options will be taken from site configuration, but they don't have to be. The options passed |
11 | * are copied and will not reflect subsequent updates to site configuration (assuming they're not |
12 | * objects). |
13 | * |
14 | * Services that take this type as a parameter to their constructor should specify a list of the |
15 | * keys they expect to receive in an array. The convention is to make it a public const called |
16 | * CONSTRUCTOR_OPTIONS. In the constructor, they should call assertRequiredOptions() to make sure |
17 | * that they weren't passed too few or too many options. This way it's clear what each class |
18 | * depends on, and that it's getting passed the correct set of options. (This means there are no |
19 | * optional options. This makes sense for services, since they shouldn't be constructed by |
20 | * outside code.) |
21 | * |
22 | * @newable since 1.36 |
23 | * |
24 | * @since 1.34 |
25 | */ |
26 | class ServiceOptions { |
27 | private $keys; |
28 | private $options = []; |
29 | |
30 | /** |
31 | * @stable to call since 1.36 |
32 | * |
33 | * @param string[] $keys Which keys to extract from $sources |
34 | * @param Config|ServiceOptions|array ...$sources Each source is either a Config object or an array. If the |
35 | * same key is present in two sources, the first one takes precedence. Keys that are not in |
36 | * $keys are ignored. |
37 | * @throws InvalidArgumentException if one of $keys is not found in any of $sources |
38 | */ |
39 | public function __construct( array $keys, ...$sources ) { |
40 | $this->keys = $keys; |
41 | foreach ( $keys as $key ) { |
42 | foreach ( $sources as $source ) { |
43 | if ( $source instanceof Config ) { |
44 | if ( $source->has( $key ) ) { |
45 | $this->options[$key] = $source->get( $key ); |
46 | continue 2; |
47 | } |
48 | } elseif ( $source instanceof ServiceOptions ) { |
49 | if ( array_key_exists( $key, $source->options ) ) { |
50 | $this->options[$key] = $source->get( $key ); |
51 | continue 2; |
52 | } |
53 | } else { |
54 | if ( array_key_exists( $key, $source ) ) { |
55 | $this->options[$key] = $source[$key]; |
56 | continue 2; |
57 | } |
58 | } |
59 | } |
60 | throw new InvalidArgumentException( "Key \"$key\" not found in input sources" ); |
61 | } |
62 | } |
63 | |
64 | /** |
65 | * Assert that the list of options provided in this instance exactly match $expectedKeys, |
66 | * without regard for order. |
67 | * |
68 | * @param string[] $expectedKeys |
69 | */ |
70 | public function assertRequiredOptions( array $expectedKeys ) { |
71 | if ( $this->keys !== $expectedKeys ) { |
72 | $extraKeys = array_diff( $this->keys, $expectedKeys ); |
73 | $missingKeys = array_diff( $expectedKeys, $this->keys ); |
74 | Assert::precondition( !$extraKeys && !$missingKeys, |
75 | ( |
76 | $extraKeys |
77 | ? 'Unsupported options passed: ' . implode( ', ', $extraKeys ) . '!' |
78 | : '' |
79 | ) . ( $extraKeys && $missingKeys ? ' ' : '' ) . ( |
80 | $missingKeys |
81 | ? 'Required options missing: ' . implode( ', ', $missingKeys ) . '!' |
82 | : '' |
83 | ) |
84 | ); |
85 | } |
86 | } |
87 | |
88 | /** |
89 | * @param string $key |
90 | * @return mixed |
91 | */ |
92 | public function get( $key ) { |
93 | if ( !array_key_exists( $key, $this->options ) ) { |
94 | throw new InvalidArgumentException( "Unrecognized option \"$key\"" ); |
95 | } |
96 | return $this->options[$key]; |
97 | } |
98 | } |