Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
82.81% |
53 / 64 |
|
72.22% |
13 / 18 |
CRAP | |
0.00% |
0 / 1 |
UserSelectQueryBuilder | |
82.81% |
53 / 64 |
|
72.22% |
13 / 18 |
29.43 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
whereUserIds | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
userIds | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
whereUserNames | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
userNames | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
whereUserNamePrefix | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
2.02 | |||
userNamePrefix | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
whereRegisteredTimestamp | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
orderByName | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
orderByUserId | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
registered | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
anon | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
named | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
temp | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
hidden | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
fetchUserIdentity | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
fetchUserIdentities | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
fetchUserNames | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\User; |
22 | |
23 | use Iterator; |
24 | use MediaWiki\Block\HideUserUtils; |
25 | use MediaWiki\User\TempUser\TempUserConfig; |
26 | use Wikimedia\Assert\Assert; |
27 | use Wikimedia\Assert\PreconditionException; |
28 | use Wikimedia\Rdbms\IExpression; |
29 | use Wikimedia\Rdbms\IReadableDatabase; |
30 | use Wikimedia\Rdbms\LikeValue; |
31 | use Wikimedia\Rdbms\SelectQueryBuilder; |
32 | |
33 | class UserSelectQueryBuilder extends SelectQueryBuilder { |
34 | |
35 | /** @var ActorStore */ |
36 | private $actorStore; |
37 | private TempUserConfig $tempUserConfig; |
38 | private HideUserUtils $hideUserUtils; |
39 | |
40 | private bool $userJoined = false; |
41 | |
42 | /** |
43 | * @internal |
44 | * @param IReadableDatabase $db |
45 | * @param ActorStore $actorStore |
46 | * @param TempUserConfig $tempUserConfig |
47 | */ |
48 | public function __construct( |
49 | IReadableDatabase $db, |
50 | ActorStore $actorStore, |
51 | TempUserConfig $tempUserConfig, |
52 | HideUserUtils $hideUserUtils |
53 | ) { |
54 | parent::__construct( $db ); |
55 | |
56 | $this->actorStore = $actorStore; |
57 | $this->tempUserConfig = $tempUserConfig; |
58 | $this->hideUserUtils = $hideUserUtils; |
59 | $this->table( 'actor' ); |
60 | } |
61 | |
62 | /** |
63 | * Find by provided user ids. |
64 | * |
65 | * @param int|int[] $userIds |
66 | * @return UserSelectQueryBuilder |
67 | */ |
68 | public function whereUserIds( $userIds ): self { |
69 | Assert::parameterType( [ 'integer', 'array' ], $userIds, '$userIds' ); |
70 | $this->conds( [ 'actor_user' => $userIds ] ); |
71 | return $this; |
72 | } |
73 | |
74 | /** |
75 | * Find by provided user ids. |
76 | * @deprecated since 1.37, use whereUserIds instead |
77 | * @param int|int[] $userIds |
78 | * @return UserSelectQueryBuilder |
79 | */ |
80 | public function userIds( $userIds ): self { |
81 | return $this->whereUserIds( $userIds ); |
82 | } |
83 | |
84 | /** |
85 | * Find by provided user names. |
86 | * |
87 | * @param string|string[] $userNames |
88 | * @return UserSelectQueryBuilder |
89 | */ |
90 | public function whereUserNames( $userNames ): self { |
91 | Assert::parameterType( [ 'string', 'array' ], $userNames, '$userIds' ); |
92 | $userNames = array_map( function ( $name ) { |
93 | return $this->actorStore->normalizeUserName( (string)$name ); |
94 | }, (array)$userNames ); |
95 | $this->conds( [ 'actor_name' => $userNames ] ); |
96 | return $this; |
97 | } |
98 | |
99 | /** |
100 | * Find by provided user names. |
101 | * @deprecated since 1.37, use whereUserNames instead |
102 | * @param string|string[] $userNames |
103 | * @return UserSelectQueryBuilder |
104 | */ |
105 | public function userNames( $userNames ): self { |
106 | return $this->whereUserNames( $userNames ); |
107 | } |
108 | |
109 | /** |
110 | * Find users with names starting from the provided prefix. |
111 | * |
112 | * @note this could produce a huge number of results, like User00000 ... User99999, |
113 | * so you must set a limit when using this condition. |
114 | * |
115 | * @param string $prefix |
116 | * @return UserSelectQueryBuilder |
117 | */ |
118 | public function whereUserNamePrefix( string $prefix ): self { |
119 | if ( !isset( $this->options['LIMIT'] ) ) { |
120 | throw new PreconditionException( 'Must set a limit when using a user name prefix' ); |
121 | } |
122 | $this->conds( |
123 | $this->db->expr( 'actor_name', IExpression::LIKE, new LikeValue( $prefix, $this->db->anyString() ) ) |
124 | ); |
125 | return $this; |
126 | } |
127 | |
128 | /** |
129 | * Find users with names starting from the provided prefix. |
130 | * |
131 | * @note this could produce a huge number of results, like User00000 ... User99999, |
132 | * so you must set a limit when using this condition. |
133 | * @deprecated since 1.37 use whereUserNamePrefix instead |
134 | * @param string $prefix |
135 | * @return UserSelectQueryBuilder |
136 | */ |
137 | public function userNamePrefix( string $prefix ): self { |
138 | return $this->whereUserNamePrefix( $prefix ); |
139 | } |
140 | |
141 | /** |
142 | * Find registered users who registered |
143 | * |
144 | * @param string $timestamp |
145 | * @param bool $direction Direction flag (if true, user_registration must be before $timestamp) |
146 | * @since 1.42 |
147 | * @return UserSelectQueryBuilder |
148 | */ |
149 | public function whereRegisteredTimestamp( string $timestamp, bool $direction ): self { |
150 | if ( !$this->userJoined ) { |
151 | $this->join( 'user', null, [ "actor_user=user_id" ] ); |
152 | $this->userJoined = true; |
153 | } |
154 | |
155 | $this->conds( |
156 | $this->db->expr( 'user_registration', ( $direction ? '<' : '>' ), $this->db->timestamp( $timestamp ) ) |
157 | ); |
158 | return $this; |
159 | } |
160 | |
161 | /** |
162 | * Order results by name in $direction |
163 | * |
164 | * @param string $dir one of self::SORT_ASC or self::SORT_DESC |
165 | * @return UserSelectQueryBuilder |
166 | */ |
167 | public function orderByName( string $dir = self::SORT_ASC ): self { |
168 | $this->orderBy( 'actor_name', $dir ); |
169 | return $this; |
170 | } |
171 | |
172 | /** |
173 | * Order results by user id. |
174 | * |
175 | * @param string $dir one of self::SORT_ASC or self::SORT_DESC |
176 | * @return UserSelectQueryBuilder |
177 | */ |
178 | public function orderByUserId( string $dir = self::SORT_ASC ): self { |
179 | $this->orderBy( 'actor_user', $dir ); |
180 | return $this; |
181 | } |
182 | |
183 | /** |
184 | * Only return registered users. |
185 | * |
186 | * @return UserSelectQueryBuilder |
187 | */ |
188 | public function registered(): self { |
189 | $this->conds( $this->db->expr( 'actor_user', '!=', null ) ); |
190 | return $this; |
191 | } |
192 | |
193 | /** |
194 | * Only return anonymous users. |
195 | * |
196 | * @return UserSelectQueryBuilder |
197 | */ |
198 | public function anon(): self { |
199 | $this->conds( [ 'actor_user' => null ] ); |
200 | return $this; |
201 | } |
202 | |
203 | /** |
204 | * Only return named users. |
205 | * |
206 | * @return UserSelectQueryBuilder |
207 | */ |
208 | public function named(): self { |
209 | if ( !$this->tempUserConfig->isKnown() ) { |
210 | // nothing to do: getMatchCondition throws if temp accounts aren't known |
211 | return $this; |
212 | } |
213 | $this->conds( $this->tempUserConfig->getMatchCondition( $this->db, 'actor_name', IExpression::NOT_LIKE ) ); |
214 | return $this; |
215 | } |
216 | |
217 | /** |
218 | * Only return temp users |
219 | * |
220 | * @return UserSelectQueryBuilder |
221 | */ |
222 | public function temp(): self { |
223 | if ( !$this->tempUserConfig->isKnown() ) { |
224 | // nothing to do: getMatchCondition throws if temp accounts aren't known |
225 | return $this; |
226 | } |
227 | $this->conds( $this->tempUserConfig->getMatchCondition( $this->db, 'actor_name', IExpression::LIKE ) ); |
228 | return $this; |
229 | } |
230 | |
231 | /** |
232 | * Filter based on user hidden status |
233 | * |
234 | * @since 1.38 |
235 | * @param bool $hidden True - only hidden users, false - no hidden users |
236 | * @return $this |
237 | */ |
238 | public function hidden( bool $hidden ): self { |
239 | $this->conds( $this->hideUserUtils->getExpression( |
240 | $this->db, |
241 | 'actor_user', |
242 | $hidden ? HideUserUtils::HIDDEN_USERS : HideUserUtils::SHOWN_USERS |
243 | ) ); |
244 | return $this; |
245 | } |
246 | |
247 | /** |
248 | * Fetch a single UserIdentity that matches specified criteria. |
249 | * |
250 | * @return UserIdentity|null |
251 | */ |
252 | public function fetchUserIdentity(): ?UserIdentity { |
253 | $this->fields( [ 'actor_id', 'actor_name', 'actor_user' ] ); |
254 | $row = $this->fetchRow(); |
255 | if ( !$row ) { |
256 | return null; |
257 | } |
258 | return $this->actorStore->newActorFromRow( $row ); |
259 | } |
260 | |
261 | /** |
262 | * Fetch UserIdentities for the specified query. |
263 | * |
264 | * @return Iterator<UserIdentity> |
265 | */ |
266 | public function fetchUserIdentities(): Iterator { |
267 | $this->fields( [ 'actor_id', 'actor_name', 'actor_user' ] ); |
268 | |
269 | $result = $this->fetchResultSet(); |
270 | foreach ( $result as $row ) { |
271 | yield $this->actorStore->newActorFromRow( $row ); |
272 | } |
273 | $result->free(); |
274 | } |
275 | |
276 | /** |
277 | * Returns an array of user names matching the query. |
278 | * |
279 | * @return string[] |
280 | */ |
281 | public function fetchUserNames(): array { |
282 | $this->field( 'actor_name' ); |
283 | return $this->fetchFieldValues(); |
284 | } |
285 | } |