Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.22% covered (warning)
82.22%
37 / 45
75.00% covered (warning)
75.00%
6 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
MediaWikiConfigReader
82.22% covered (warning)
82.22%
37 / 45
75.00% covered (warning)
75.00%
6 / 8
15.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 addMediaWikiConfigProviderKeysToMap
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 computeVariableToProviderMap
58.33% covered (warning)
58.33%
7 / 12
0.00% covered (danger)
0.00%
0 / 1
3.65
 getVariableToProviderMap
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 getMediaWikiConfigProviderByName
50.00% covered (danger)
50.00%
3 / 6
0.00% covered (danger)
0.00%
0 / 1
2.50
 getConfigByVariableName
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 has
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Extension\CommunityConfiguration\Access;
4
5use BagOStuff;
6use LogicException;
7use MediaWiki\Config\Config;
8use MediaWiki\Config\ConfigException;
9use MediaWiki\Extension\CommunityConfiguration\Provider\ConfigurationProviderFactory;
10use MediaWiki\Extension\CommunityConfiguration\Provider\MediaWikiConfigProvider;
11use Psr\Log\LoggerAwareTrait;
12use Psr\Log\NullLogger;
13use Wikimedia\LightweightObjectStore\ExpirationAwareness;
14
15class MediaWikiConfigReader implements Config {
16    use LoggerAwareTrait;
17
18    private BagOStuff $cache;
19    private ConfigurationProviderFactory $providerFactory;
20    private Config $fallbackConfig;
21
22    public function __construct(
23        BagOStuff $cache,
24        ConfigurationProviderFactory $providerFactory,
25        Config $fallbackConfig
26    ) {
27        $this->cache = $cache;
28        $this->providerFactory = $providerFactory;
29        $this->fallbackConfig = $fallbackConfig;
30
31        $this->setLogger( new NullLogger() );
32    }
33
34    private function addMediaWikiConfigProviderKeysToMap(
35        MediaWikiConfigProvider $provider,
36        array &$map
37    ): void {
38        $supportedConfigKeys = $provider->getSupportedConfigVariableNames();
39        foreach ( $supportedConfigKeys as $configKey ) {
40            if ( isset( $map[$configKey] ) ) {
41                throw new ConfigException(
42                    'Config variable ' . $configKey
43                    . ' is registered by multiple CommunityConfiguration providers.'
44                );
45            }
46            $map[$configKey] = $provider->getId();
47        }
48    }
49
50    /**
51     * Calculate the config key => configuration provider map
52     *
53     * @return string[]
54     */
55    private function computeVariableToProviderMap(): array {
56        $map = [];
57        $providerKeys = $this->providerFactory->getSupportedKeys();
58        foreach ( $providerKeys as $providerKey ) {
59            $provider = $this->providerFactory->newProvider( $providerKey );
60            if ( $provider instanceof MediaWikiConfigProvider ) {
61                $this->addMediaWikiConfigProviderKeysToMap( $provider, $map );
62            } else {
63                // TODO: Add some support for other providers
64                $this->logger->debug(
65                    __CLASS__ . ' skipped {provider}, because '
66                    . 'it is not a MediaWikiConfigProvider.',
67                    [ 'provider' => $provider->getId() ]
68                );
69            }
70        }
71        return $map;
72    }
73
74    /**
75     * Get the cached variable to configuration provider map
76     *
77     * This is used to determine which config key can be handled by which configuration provider.
78     *
79     * @return string[] Config key => provider key
80     */
81    private function getVariableToProviderMap(): array {
82        return $this->cache->getWithSetCallback(
83            $this->cache->makeKey( __CLASS__,
84                'VariableToProviderMap'
85            ),
86            ExpirationAwareness::TTL_DAY,
87            function () {
88                return $this->computeVariableToProviderMap();
89            }
90        );
91    }
92
93    /**
94     * Create a configuration provider from given key and ensure it is a MediaWikiConfigProvider
95     *
96     * @param string $providerKey
97     * @return MediaWikiConfigProvider
98     */
99    private function getMediaWikiConfigProviderByName( string $providerKey ): MediaWikiConfigProvider {
100        $provider = $this->providerFactory->newProvider( $providerKey );
101        if ( !$provider instanceof MediaWikiConfigProvider ) {
102            throw new LogicException(
103                $providerKey . ' is expected to be a MediaWikiConfigProvider'
104            );
105        }
106        return $provider;
107    }
108
109    /**
110     * Get Config instance to handle requests for $name config key
111     *
112     * @param string $name
113     * @return Config
114     */
115    private function getConfigByVariableName( string $name ): Config {
116        $map = $this->getVariableToProviderMap();
117        if ( isset( $map[$name] ) ) {
118            return $this->getMediaWikiConfigProviderByName( $map[$name] );
119        } else {
120            return $this->fallbackConfig;
121        }
122    }
123
124    /**
125     * @inheritDoc
126     */
127    public function get( $name ) {
128        return $this->getConfigByVariableName( $name )->get( $name );
129    }
130
131    /**
132     * @inheritDoc
133     */
134    public function has( $name ) {
135        return $this->getConfigByVariableName( $name )->has( $name );
136    }
137}