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