MediaWiki REL1_40
ApiQueryUsers.php
Go to the documentation of this file.
1<?php
30
38
39 private $prop;
40
42 private $userNameUtils;
43
45 private $userFactory;
46
48 private $userGroupManager;
49
51 private $genderCache;
52
54 private $authManager;
55
61 protected static $publicProps = [
62 // everything except 'blockinfo' which might show hidden records if the user
63 // making the request has the appropriate permissions
64 'groups',
65 'groupmemberships',
66 'implicitgroups',
67 'rights',
68 'editcount',
69 'registration',
70 'emailable',
71 'gender',
72 'centralids',
73 'cancreate',
74 ];
75
85 public function __construct(
86 ApiQuery $query,
87 $moduleName,
88 UserNameUtils $userNameUtils,
89 UserFactory $userFactory,
90 UserGroupManager $userGroupManager,
91 GenderCache $genderCache,
92 AuthManager $authManager
93 ) {
94 parent::__construct( $query, $moduleName, 'us' );
95 $this->userNameUtils = $userNameUtils;
96 $this->userFactory = $userFactory;
97 $this->userGroupManager = $userGroupManager;
98 $this->genderCache = $genderCache;
99 $this->authManager = $authManager;
100 }
101
102 public function execute() {
103 $db = $this->getDB();
104 $params = $this->extractRequestParams();
105 $this->requireMaxOneParameter( $params, 'userids', 'users' );
106
107 if ( $params['prop'] !== null ) {
108 $this->prop = array_fill_keys( $params['prop'], true );
109 } else {
110 $this->prop = [];
111 }
112 $useNames = $params['users'] !== null;
113
114 $users = (array)$params['users'];
115 $userids = (array)$params['userids'];
116
117 $goodNames = $done = [];
118 $result = $this->getResult();
119 // Canonicalize user names
120 foreach ( $users as $u ) {
121 $n = $this->userNameUtils->getCanonical( $u );
122 if ( $n === false || $n === '' ) {
123 $vals = [ 'name' => $u, 'invalid' => true ];
124 $fit = $result->addValue( [ 'query', $this->getModuleName() ],
125 null, $vals );
126 if ( !$fit ) {
127 $this->setContinueEnumParameter( 'users',
128 implode( '|', array_diff( $users, $done ) ) );
129 $goodNames = [];
130 break;
131 }
132 $done[] = $u;
133 } else {
134 $goodNames[] = $n;
135 }
136 }
137
138 if ( $useNames ) {
139 $parameters = &$goodNames;
140 } else {
141 $parameters = &$userids;
142 }
143
144 $result = $this->getResult();
145
146 if ( count( $parameters ) ) {
147 $userQuery = User::getQueryInfo();
148 $this->addTables( $userQuery['tables'] );
149 $this->addFields( $userQuery['fields'] );
150 $this->addJoinConds( $userQuery['joins'] );
151 if ( $useNames ) {
152 $this->addWhereFld( 'user_name', $goodNames );
153 } else {
154 $this->addWhereFld( 'user_id', $userids );
155 }
156
157 $this->addBlockInfoToQuery( isset( $this->prop['blockinfo'] ) );
158
159 $data = [];
160 $res = $this->select( __METHOD__ );
161 $this->resetQueryParams();
162
163 // get user groups if needed
164 if ( isset( $this->prop['groups'] ) || isset( $this->prop['rights'] ) ) {
165 $userGroups = [];
166
167 $this->addTables( 'user' );
168 if ( $useNames ) {
169 $this->addWhereFld( 'user_name', $goodNames );
170 } else {
171 $this->addWhereFld( 'user_id', $userids );
172 }
173
174 $this->addTables( 'user_groups' );
175 $this->addJoinConds( [ 'user_groups' => [ 'JOIN', 'ug_user=user_id' ] ] );
176 $this->addFields( [ 'user_name' ] );
177 $this->addFields( [ 'ug_user', 'ug_group', 'ug_expiry' ] );
178 $this->addWhere( 'ug_expiry IS NULL OR ug_expiry >= ' .
179 $db->addQuotes( $db->timestamp() ) );
180 $userGroupsRes = $this->select( __METHOD__ );
181
182 foreach ( $userGroupsRes as $row ) {
183 $userGroups[$row->user_name][] = $row;
184 }
185 }
186 if ( isset( $this->prop['gender'] ) ) {
187 $userNames = [];
188 foreach ( $res as $row ) {
189 $userNames[] = $row->user_name;
190 }
191 $this->genderCache->doQuery( $userNames, __METHOD__ );
192 }
193
194 foreach ( $res as $row ) {
195 // create user object and pass along $userGroups if set
196 // that reduces the number of database queries needed in User dramatically
197 if ( !isset( $userGroups ) ) {
198 $user = $this->userFactory->newFromRow( $row );
199 } else {
200 if ( !isset( $userGroups[$row->user_name] ) || !is_array( $userGroups[$row->user_name] ) ) {
201 $userGroups[$row->user_name] = [];
202 }
203 $user = $this->userFactory->newFromRow( $row, [ 'user_groups' => $userGroups[$row->user_name] ] );
204 }
205 if ( $useNames ) {
206 $key = $user->getName();
207 } else {
208 $key = $user->getId();
209 }
210 $data[$key]['userid'] = $user->getId();
211 $data[$key]['name'] = $user->getName();
212
213 if ( isset( $this->prop['editcount'] ) ) {
214 $data[$key]['editcount'] = $user->getEditCount();
215 }
216
217 if ( isset( $this->prop['registration'] ) ) {
218 $data[$key]['registration'] = wfTimestampOrNull( TS_ISO_8601, $user->getRegistration() );
219 }
220
221 if ( isset( $this->prop['groups'] ) ) {
222 $data[$key]['groups'] = $this->userGroupManager->getUserEffectiveGroups( $user );
223 }
224
225 if ( isset( $this->prop['groupmemberships'] ) ) {
226 $data[$key]['groupmemberships'] = array_map( static function ( $ugm ) {
227 return [
228 'group' => $ugm->getGroup(),
229 'expiry' => ApiResult::formatExpiry( $ugm->getExpiry() ),
230 ];
231 }, $this->userGroupManager->getUserGroupMemberships( $user ) );
232 }
233
234 if ( isset( $this->prop['implicitgroups'] ) ) {
235 $data[$key]['implicitgroups'] = $this->userGroupManager->getUserImplicitGroups( $user );
236 }
237
238 if ( isset( $this->prop['rights'] ) ) {
239 $data[$key]['rights'] = $this->getPermissionManager()
240 ->getUserPermissions( $user );
241 }
242 if ( $row->ipb_deleted ) {
243 $data[$key]['hidden'] = true;
244 }
245 if ( isset( $this->prop['blockinfo'] ) && $row->ipb_by_text !== null ) {
246 $data[$key] += $this->getBlockDetails( DatabaseBlock::newFromRow( $row ) );
247 }
248
249 if ( isset( $this->prop['emailable'] ) ) {
250 $data[$key]['emailable'] = $user->canReceiveEmail();
251 }
252
253 if ( isset( $this->prop['gender'] ) ) {
254 $data[$key]['gender'] = $this->genderCache->getGenderOf( $user, __METHOD__ );
255 }
256
257 if ( isset( $this->prop['centralids'] ) ) {
259 $this->getConfig(), $user, $params['attachedwiki']
260 );
261 }
262 }
263 }
264
265 $context = $this->getContext();
266 // Second pass: add result data to $retval
267 foreach ( $parameters as $u ) {
268 if ( !isset( $data[$u] ) ) {
269 if ( $useNames ) {
270 $data[$u] = [ 'name' => $u ];
271 $urPage = new SpecialUserRights;
272 $urPage->setContext( $context );
273
274 $iwUser = $urPage->fetchUser( $u );
275
276 if ( $iwUser instanceof UserRightsProxy ) {
277 $data[$u]['interwiki'] = true;
278 } else {
279 $data[$u]['missing'] = true;
280 if ( isset( $this->prop['cancreate'] ) ) {
281 $status = $this->authManager->canCreateAccount( $u );
282 $data[$u]['cancreate'] = $status->isGood();
283 if ( !$status->isGood() ) {
284 $data[$u]['cancreateerror'] = $this->getErrorFormatter()->arrayFromStatus( $status );
285 }
286 }
287 }
288 } else {
289 $data[$u] = [ 'userid' => $u, 'missing' => true ];
290 }
291
292 } else {
293 if ( isset( $this->prop['groups'] ) && isset( $data[$u]['groups'] ) ) {
294 ApiResult::setArrayType( $data[$u]['groups'], 'array' );
295 ApiResult::setIndexedTagName( $data[$u]['groups'], 'g' );
296 }
297 if ( isset( $this->prop['groupmemberships'] ) && isset( $data[$u]['groupmemberships'] ) ) {
298 ApiResult::setArrayType( $data[$u]['groupmemberships'], 'array' );
299 ApiResult::setIndexedTagName( $data[$u]['groupmemberships'], 'groupmembership' );
300 }
301 if ( isset( $this->prop['implicitgroups'] ) && isset( $data[$u]['implicitgroups'] ) ) {
302 ApiResult::setArrayType( $data[$u]['implicitgroups'], 'array' );
303 ApiResult::setIndexedTagName( $data[$u]['implicitgroups'], 'g' );
304 }
305 if ( isset( $this->prop['rights'] ) && isset( $data[$u]['rights'] ) ) {
306 ApiResult::setArrayType( $data[$u]['rights'], 'array' );
307 ApiResult::setIndexedTagName( $data[$u]['rights'], 'r' );
308 }
309 }
310
311 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $data[$u] );
312 if ( !$fit ) {
313 if ( $useNames ) {
314 $this->setContinueEnumParameter( 'users',
315 implode( '|', array_diff( $users, $done ) ) );
316 } else {
317 $this->setContinueEnumParameter( 'userids',
318 implode( '|', array_diff( $userids, $done ) ) );
319 }
320 break;
321 }
322 $done[] = $u;
323 }
324 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'user' );
325 }
326
327 public function getCacheMode( $params ) {
328 if ( array_diff( (array)$params['prop'], static::$publicProps ) ) {
329 return 'anon-public-user-private';
330 } else {
331 return 'public';
332 }
333 }
334
335 public function getAllowedParams() {
336 return [
337 'prop' => [
338 ParamValidator::PARAM_ISMULTI => true,
339 ParamValidator::PARAM_TYPE => [
340 'blockinfo',
341 'groups',
342 'groupmemberships',
343 'implicitgroups',
344 'rights',
345 'editcount',
346 'registration',
347 'emailable',
348 'gender',
349 'centralids',
350 'cancreate',
351 // When adding a prop, consider whether it should be added
352 // to self::$publicProps
353 ],
355 ],
356 'attachedwiki' => null,
357 'users' => [
358 ParamValidator::PARAM_ISMULTI => true
359 ],
360 'userids' => [
361 ParamValidator::PARAM_ISMULTI => true,
362 ParamValidator::PARAM_TYPE => 'integer'
363 ],
364 ];
365 }
366
367 protected function getExamplesMessages() {
368 return [
369 'action=query&list=users&ususers=Example&usprop=groups|editcount|gender'
370 => 'apihelp-query+users-example-simple',
371 ];
372 }
373
374 public function getHelpUrls() {
375 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Users';
376 }
377}
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
getErrorFormatter()
Definition ApiBase.php:648
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:694
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:204
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:946
getResult()
Get the result object.
Definition ApiBase.php:637
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:773
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:506
This is a base class for all Query modules.
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
resetQueryParams()
Blank the internal arrays with query parameters.
addFields( $value)
Add a set of fields to select to the internal array.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
getDB()
Get the Query database connection (read-only)
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
addWhere( $value)
Add a set of WHERE clauses to the internal array.
static getCentralUserInfo(Config $config, UserIdentity $user, $attachedWiki=UserIdentity::LOCAL)
Get central user info.
Query module to get information about a list of users.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
static array $publicProps
Properties whose contents does not depend on who is looking at them.
getHelpUrls()
Return links to more detailed help pages about the module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getExamplesMessages()
Returns usage examples for this module.
__construct(ApiQuery $query, $moduleName, UserNameUtils $userNameUtils, UserFactory $userFactory, UserGroupManager $userGroupManager, GenderCache $genderCache, AuthManager $authManager)
getCacheMode( $params)
Get the cache mode for the data generated by this module.
This is the main query class.
Definition ApiQuery.php:42
getContext()
Get the base IContextSource object.
Caches user genders when needed to use correct namespace aliases.
This serves as the entry point to the authentication system.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Special page to allow managing user group membership.
Creates User objects.
UserNameUtils service.
setContext( $context)
Sets the context this SpecialPage is executed in.
Cut-down copy of User interface for local-interwiki-database user rights manipulation.
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object.
Definition User.php:3368
Service for formatting and validating API parameters.
trait ApiQueryBlockInfoTrait
return true
Definition router.php:92