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