Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
59.09% covered (warning)
59.09%
13 / 22
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserRegistrationLookup
59.09% covered (warning)
59.09%
13 / 22
80.00% covered (warning)
80.00%
4 / 5
16.85
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 isRegistered
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getProvider
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 getRegistration
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFirstRegistration
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace MediaWiki\User\Registration;
4
5use InvalidArgumentException;
6use MediaWiki\Config\ServiceOptions;
7use MediaWiki\MainConfigNames;
8use MediaWiki\MainConfigSchema;
9use MediaWiki\User\UserIdentity;
10use Wikimedia\ObjectFactory\ObjectFactory;
11
12/**
13 * @since 1.41
14 */
15class UserRegistrationLookup {
16
17    /**
18     * @internal for use in ServiceWiring
19     * @var string[] Config names to require
20     */
21    public const CONSTRUCTOR_OPTIONS = [
22        MainConfigNames::UserRegistrationProviders,
23    ];
24
25    /** @var array ObjectFactory specs indexed by provider name */
26    private array $providersSpecs;
27
28    /** @var IUserRegistrationProvider[] Constructed registration providers indexed by name */
29    private array $providers = [];
30
31    private ObjectFactory $objectFactory;
32
33    public function __construct(
34        ServiceOptions $options,
35        ObjectFactory $objectFactory
36    ) {
37        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
38        $this->providersSpecs = $options->get( MainConfigNames::UserRegistrationProviders );
39        $this->objectFactory = $objectFactory;
40    }
41
42    /**
43     * Is a registration provider registered?
44     *
45     * @see MainConfigSchema::UserRegistrationLookupProviders
46     * @param string $type
47     * @return bool
48     */
49    public function isRegistered( string $type ): bool {
50        return array_key_exists( $type, $this->providersSpecs );
51    }
52
53    /**
54     * Construct a registration provider, if needed
55     *
56     * @param string $type
57     * @return IUserRegistrationProvider
58     */
59    private function getProvider( string $type ): IUserRegistrationProvider {
60        if ( !$this->isRegistered( $type ) ) {
61            throw new InvalidArgumentException( 'Registration provider ' . $type . ' is not registered' );
62        }
63        if ( !array_key_exists( $type, $this->providers ) ) {
64            $this->providers[$type] = $this->objectFactory->createObject(
65                $this->providersSpecs[$type],
66                [ 'assertClass' => IUserRegistrationProvider::class ]
67            );
68        }
69        return $this->providers[$type];
70    }
71
72    /**
73     * @param UserIdentity $user User for which registration should be fetched.
74     * @param string $type Name of a registered registration provider
75     * @return string|null|false Registration timestamp, null if not available or false if it
76     * cannot be fetched (anonymous users, for example).
77     */
78    public function getRegistration(
79        UserIdentity $user,
80        string $type = LocalUserRegistrationProvider::TYPE
81    ) {
82        return $this->getProvider( $type )->fetchRegistration( $user );
83    }
84
85    /**
86     * Find the first registration timestamp for a given user
87     *
88     * Note this invokes _all_ registered providers.
89     *
90     * @param UserIdentity $user
91     * @return string|null Earliest registration timestamp, null if not available.
92     */
93    public function getFirstRegistration( UserIdentity $user ): ?string {
94        $registrationTimestampsUnix = [];
95        foreach ( $this->providersSpecs as $providerKey => $_ ) {
96            $registrationTimestampRaw = $this->getRegistration( $user, $providerKey );
97            if ( !is_string( $registrationTimestampRaw ) ) {
98                // Provider was unable to return a registration timestamp for $providerKey, skip
99                // them.
100                continue;
101            }
102            $registrationTimestampsUnix[] = (int)wfTimestamp( TS_UNIX, $registrationTimestampRaw );
103        }
104
105        if ( $registrationTimestampsUnix === [] ) {
106            return null;
107        }
108
109        return wfTimestamp( TS_MW, min( $registrationTimestampsUnix ) );
110    }
111}