Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
GlobalUserSelectQueryBuilder
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 10
306
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 init
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 whereGlobalUserIds
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 whereUserNames
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 whereLocked
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 whereRegisteredTimestamp
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 named
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 temp
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 fetchCentralAuthUsers
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 fetchLocalUserIdentitites
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace MediaWiki\Extension\CentralAuth\User;
4
5use EmptyIterator;
6use Iterator;
7use MediaWiki\User\ActorStore;
8use MediaWiki\User\TempUser\TempUserConfig;
9use MediaWiki\User\UserIdentity;
10use MediaWiki\User\UserNameUtils;
11use Wikimedia\Assert\Assert;
12use Wikimedia\Rdbms\IExpression;
13use Wikimedia\Rdbms\IReadableDatabase;
14use Wikimedia\Rdbms\SelectQueryBuilder;
15
16/**
17 * @stable
18 */
19class GlobalUserSelectQueryBuilder extends SelectQueryBuilder {
20
21    /** @var ActorStore for the local wiki */
22    private ActorStore $actorStore;
23
24    private UserNameUtils $userNameUtils;
25    private TempUserConfig $tempUserConfig;
26
27    /** @var bool */
28    private bool $initRan = false;
29
30    /**
31     * @param IReadableDatabase $db
32     * @param ActorStore $actorStore
33     * @param UserNameUtils $userNameUtils
34     * @param TempUserConfig $tempUserConfig
35     */
36    public function __construct(
37        IReadableDatabase $db,
38        ActorStore $actorStore,
39        UserNameUtils $userNameUtils,
40        TempUserConfig $tempUserConfig
41    ) {
42        parent::__construct( $db );
43        $this->actorStore = $actorStore;
44        $this->userNameUtils = $userNameUtils;
45        $this->tempUserConfig = $tempUserConfig;
46    }
47
48    /**
49     * Init the SelectQueryBuilder
50     *
51     * Should be called by ::fetch* methods.
52     */
53    private function init(): void {
54        if ( $this->initRan ) {
55            return;
56        }
57
58        // HACK: SelectQueryBuilder::queryInfo expects join conditions to be at the join_conds
59        // key, but CentralAuthUser::selectQueryInfo exposes them as joinConds
60        $queryInfo = CentralAuthUser::selectQueryInfo();
61        $queryInfo['join_conds'] = $queryInfo['joinConds'];
62        $this->queryInfo( $queryInfo );
63
64        $this->initRan = true;
65    }
66
67    /**
68     * Find by provided global user IDs
69     *
70     * @param int|int[] $globalUserIds
71     * @return $this
72     */
73    public function whereGlobalUserIds( $globalUserIds ): self {
74        Assert::parameterType( 'integer|array', $globalUserIds, '$globalUserIds' );
75
76        $this->conds( [ 'gu_id' => $globalUserIds ] );
77        return $this;
78    }
79
80    /**
81     * Find by provided usernames
82     *
83     * @param string|string[] $userNames
84     * @return $this
85     */
86    public function whereUserNames( $userNames ): self {
87        Assert::parameterType( 'string|array', $userNames, '$userIds' );
88
89        $userNames = array_map( function ( $name ) {
90            return $this->userNameUtils->getCanonical( (string)$name );
91        }, (array)$userNames );
92
93        $this->conds( [ 'gu_name' => $userNames ] );
94        return $this;
95    }
96
97    /**
98     * @param bool $isLocked
99     * @return $this
100     */
101    public function whereLocked( bool $isLocked ): self {
102        $this->conds( [ 'gu_locked' => $isLocked ] );
103        return $this;
104    }
105
106    /**
107     * Return users registered before/after $timestamp
108     *
109     * @param string $timestamp
110     * @param bool $before Direction flag (if true, user_registration must be before $timestamp)
111     * @return self
112     */
113    public function whereRegisteredTimestamp( string $timestamp, bool $before ): self {
114        $this->conds(
115            $this->db->expr( 'gu_registration', $before ? '<' : '>',
116                $this->db->timestamp( $timestamp ) )
117        );
118        return $this;
119    }
120
121    /**
122     * Only return named accounts
123     *
124     * @return $this
125     */
126    public function named(): self {
127        if ( !$this->tempUserConfig->isEnabled() ) {
128            // nothing to do: getMatchCondition throws if temp accounts aren't enabled
129            return $this;
130        }
131        $this->conds( $this->tempUserConfig->getMatchCondition( $this->db, 'gu_name', IExpression::NOT_LIKE ) );
132        return $this;
133    }
134
135    /**
136     * Only return temporary accounts
137     *
138     * @return $this
139     */
140    public function temp(): self {
141        if ( !$this->tempUserConfig->isEnabled() ) {
142            // nothing to do: getMatchCondition throws if temp accounts aren't enabled
143            return $this;
144        }
145        $this->conds( $this->tempUserConfig->getMatchCondition( $this->db, 'gu_name', IExpression::LIKE ) );
146        return $this;
147    }
148
149    /**
150     * Fetch CentralAuthUsers for the specified query
151     *
152     * @return Iterator<CentralAuthUser>
153     */
154    public function fetchCentralAuthUsers(): Iterator {
155        $this->init();
156
157        $result = $this->fetchResultSet();
158        foreach ( $result as $row ) {
159            yield CentralAuthUser::newFromRow( $row, [] );
160        }
161        $result->free();
162    }
163
164    /**
165     * Fetch UserIdentities for the current wiki
166     *
167     * @return Iterator<UserIdentity>
168     */
169    public function fetchLocalUserIdentitites(): Iterator {
170        $this->init();
171        $this->field( 'lu_local_id' );
172
173        $result = $this->fetchResultSet();
174        $localUserIds = [];
175        foreach ( $result as $row ) {
176            $localUserIds[] = $row->lu_local_id;
177        }
178
179        if ( $localUserIds === [] ) {
180            return new EmptyIterator();
181        }
182
183        return $this->actorStore->newSelectQueryBuilder()
184            ->whereUserIds( $localUserIds )
185            ->fetchUserIdentities();
186    }
187}