wiki.techinc.nl/includes/user/UserSelectQueryBuilder.php
thiemowmde bebd255f1e rdbms: Use more narrow IReadableDatabase in SelectQueryBuilder
Turned out to be much easier to do than expected.

It's literally a reader, isn't it? This change will make it possible
to use the more narrow IReadableDatabase interface in many more
places in our codebases. Some additional changes had to be made in
this patch already (most notably in ActorStore) to make Phan happy.

Bug: T326274
Change-Id: I5a886ad741f3abeadf0242039bfcce266e9c086b
2023-06-05 17:58:46 +01:00

221 lines
5.8 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\User;
use Iterator;
use Wikimedia\Assert\Assert;
use Wikimedia\Assert\PreconditionException;
use Wikimedia\Rdbms\IReadableDatabase;
use Wikimedia\Rdbms\SelectQueryBuilder;
class UserSelectQueryBuilder extends SelectQueryBuilder {
/** @var ActorStore */
private $actorStore;
/**
* @internal
* @param IReadableDatabase $db
* @param ActorStore $actorStore
*/
public function __construct( IReadableDatabase $db, ActorStore $actorStore ) {
parent::__construct( $db );
$this->actorStore = $actorStore;
$this->table( 'actor' );
}
/**
* Find by provided user ids.
*
* @param int|int[] $userIds
* @return UserSelectQueryBuilder
*/
public function whereUserIds( $userIds ): self {
Assert::parameterType( [ 'integer', 'array' ], $userIds, '$userIds' );
$this->conds( [ 'actor_user' => $userIds ] );
return $this;
}
/**
* Find by provided user ids.
* @deprecated since 1.37, use whereUserIds instead
* @param int|int[] $userIds
* @return UserSelectQueryBuilder
*/
public function userIds( $userIds ): self {
return $this->whereUserIds( $userIds );
}
/**
* Find by provided user names.
*
* @param string|string[] $userNames
* @return UserSelectQueryBuilder
*/
public function whereUserNames( $userNames ): self {
Assert::parameterType( [ 'string', 'array' ], $userNames, '$userIds' );
$userNames = array_map( function ( $name ) {
return $this->actorStore->normalizeUserName( (string)$name );
}, (array)$userNames );
$this->conds( [ 'actor_name' => $userNames ] );
return $this;
}
/**
* Find by provided user names.
* @deprecated since 1.37, use whereUserNames instead
* @param string|string[] $userNames
* @return UserSelectQueryBuilder
*/
public function userNames( $userNames ): self {
return $this->whereUserNames( $userNames );
}
/**
* Find users with names starting from the provided prefix.
*
* @note this could produce a huge number of results, like User00000 ... User99999,
* so you must set a limit when using this condition.
*
* @param string $prefix
* @return UserSelectQueryBuilder
*/
public function whereUserNamePrefix( string $prefix ): self {
if ( !isset( $this->options['LIMIT'] ) ) {
throw new PreconditionException( 'Must set a limit when using a user name prefix' );
}
$this->conds( 'actor_name' . $this->db->buildLike( $prefix, $this->db->anyString() ) );
return $this;
}
/**
* Find users with names starting from the provided prefix.
*
* @note this could produce a huge number of results, like User00000 ... User99999,
* so you must set a limit when using this condition.
* @deprecated since 1.37 use whereUserNamePrefix instead
* @param string $prefix
* @return UserSelectQueryBuilder
*/
public function userNamePrefix( string $prefix ): self {
return $this->whereUserNamePrefix( $prefix );
}
/**
* Order results by name in $direction
*
* @param string $dir one of self::SORT_ACS or self::SORT_DESC
* @return UserSelectQueryBuilder
*/
public function orderByName( string $dir = self::SORT_ASC ): self {
$this->orderBy( 'actor_name', $dir );
return $this;
}
/**
* Order results by user id.
*
* @param string $dir one of self::SORT_ACS or self::SORT_DESC
* @return UserSelectQueryBuilder
*/
public function orderByUserId( string $dir = self::SORT_ASC ): self {
$this->orderBy( 'actor_user', $dir );
return $this;
}
/**
* Only return registered users.
*
* @return UserSelectQueryBuilder
*/
public function registered(): self {
$this->conds( [ 'actor_user != 0' ] );
return $this;
}
/**
* Only return anonymous users.
*
* @return UserSelectQueryBuilder
*/
public function anon(): self {
$this->conds( [ 'actor_user' => null ] );
return $this;
}
/**
* Filter based on user hidden status
*
* @since 1.38
* @param bool $hidden True - only hidden users, false - no hidden users
* @return $this
*/
public function hidden( bool $hidden ): self {
$this->leftJoin( 'ipblocks', null, [ "actor_user=ipb_user" ] );
if ( $hidden ) {
// only hidden users
$this->conds( [ 'ipb_deleted = 1' ] );
} else {
// filter out hidden users
$this->conds( [ 'ipb_deleted = 0 OR ipb_deleted IS NULL' ] );
}
return $this;
}
/**
* Fetch a single UserIdentity that matches specified criteria.
*
* @return UserIdentity|null
*/
public function fetchUserIdentity(): ?UserIdentity {
$this->fields( [ 'actor_id', 'actor_name', 'actor_user' ] );
$row = $this->fetchRow();
if ( !$row ) {
return null;
}
return $this->actorStore->newActorFromRow( $row );
}
/**
* Fetch UserIdentities for the specified query.
*
* @return Iterator<UserIdentity>
*/
public function fetchUserIdentities(): Iterator {
$this->fields( [ 'actor_id', 'actor_name', 'actor_user' ] );
$result = $this->fetchResultSet();
foreach ( $result as $row ) {
yield $this->actorStore->newActorFromRow( $row );
}
$result->free();
}
/**
* Returns an array of user names matching the query.
*
* @return string[]
*/
public function fetchUserNames(): array {
$this->field( 'actor_name' );
return $this->fetchFieldValues();
}
}