Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
CentralIdLookupFactory
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
5 / 5
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getProviderIds
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultProviderId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLookup
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 getNonLocalLookup
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6
7namespace MediaWiki\User\CentralId;
8
9use InvalidArgumentException;
10use MediaWiki\Config\ServiceOptions;
11use MediaWiki\MainConfigNames;
12use MediaWiki\MainConfigSchema;
13use MediaWiki\User\UserFactory;
14use MediaWiki\User\UserIdentityLookup;
15use Wikimedia\ObjectFactory\ObjectFactory;
16
17/**
18 * Factory class for CentralIdLookup. Creates instances based on their definitions in
19 * the CentralIdLookupProviders extension.json field.
20 *
21 * @since 1.37
22 * @ingroup User
23 * @see CentralIdLookup
24 * @see MainConfigSchema::CentralIdLookupProviders
25 */
26class CentralIdLookupFactory {
27
28    /**
29     * @internal
30     */
31    public const CONSTRUCTOR_OPTIONS = [
32        MainConfigNames::CentralIdLookupProviders,
33        MainConfigNames::CentralIdLookupProvider,
34    ];
35
36    /** @var array ObjectFactory specs indexed by provider name */
37    private readonly array $providers;
38
39    private readonly string $defaultProvider;
40
41    /** @var CentralIdLookup[] */
42    private $instanceCache = [];
43
44    public function __construct(
45        ServiceOptions $options,
46        private readonly ObjectFactory $objectFactory,
47        private readonly UserIdentityLookup $userIdentityLookup,
48        private readonly UserFactory $userFactory,
49    ) {
50        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
51        $this->providers = $options->get( MainConfigNames::CentralIdLookupProviders );
52        $this->defaultProvider = $options->get( MainConfigNames::CentralIdLookupProvider );
53    }
54
55    /**
56     * Get the IDs of the registered central ID lookup providers.
57     *
58     * @return string[]
59     * @see MainConfigSchema::CentralIdLookupProviders
60     */
61    public function getProviderIds(): array {
62        return array_keys( $this->providers );
63    }
64
65    /**
66     * Get the ID of the default central ID provider.
67     * @see MainConfigSchema::CentralIdLookupProvider
68     */
69    public function getDefaultProviderId(): string {
70        return $this->defaultProvider;
71    }
72
73    /**
74     * Get an instance of a CentralIdLookup.
75     *
76     * @param string|null $providerId Provider ID from $wgCentralIdLookupProviders or null
77     *   to use the provider configured in $wgCentralIdLookupProvider
78     * @return CentralIdLookup
79     * @throws InvalidArgumentException if $providerId is not properly configured
80     */
81    public function getLookup( ?string $providerId = null ): CentralIdLookup {
82        $providerId ??= $this->defaultProvider;
83
84        if ( !array_key_exists( $providerId, $this->instanceCache ) ) {
85            $providerSpec = $this->providers[$providerId] ?? null;
86            if ( !$providerSpec ) {
87                throw new InvalidArgumentException( "Invalid central ID provider $providerId" );
88            }
89            $provider = $this->objectFactory->createObject(
90                $providerSpec,
91                [ 'assertClass' => CentralIdLookup::class ]
92            );
93            $provider->init( $providerId, $this->userIdentityLookup, $this->userFactory );
94            $this->instanceCache[$providerId] = $provider;
95        }
96        return $this->instanceCache[$providerId];
97    }
98
99    /**
100     * Returns a CentralIdLookup that is guaranteed to be non-local.
101     * If no such guarantee can be made, returns null.
102     *
103     * If this function returns a non-null CentralIdLookup, that lookup is expected to provide IDs
104     * that are shared with some set of other wikis. However, you should still be cautious
105     * when using those IDs, as they will not necessarily work with *all* other wikis, and it can be
106     * hard to tell if another wiki is in the same set as this one or not.
107     *
108     * @param string|null $providerID Provider ID from $wgCentralIdLookupProviders or null
109     *   to use the provider configured in $wgCentralIdLookupProvider
110     * @return ?CentralIdLookup
111     * @throws InvalidArgumentException if $providerId is not properly configured
112     */
113    public function getNonLocalLookup( ?string $providerID = null ): ?CentralIdLookup {
114        $centralIdLookup = $this->getLookup( $providerID );
115        if ( $centralIdLookup instanceof LocalIdLookup ) {
116            /*
117             * A LocalIdLookup (which is the default) may actually be non-local,
118             * if shared user tables are used.
119             * However, we cannot know that here, so play it safe and refuse to return it.
120             * See also T163277 and T170996.
121             */
122            return null;
123        }
124        return $centralIdLookup;
125    }
126}