3 * Factory for creating User objects without static coupling.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 namespace MediaWiki\User
;
25 use DBAccessObjectUtils
;
27 use InvalidArgumentException
;
28 use MediaWiki\Permissions\Authority
;
31 use Wikimedia\Rdbms\ILoadBalancer
;
34 * Creates User objects.
36 * For now, there is nothing much interesting in this class. It was meant for preventing static User
37 * methods causing problems in unit tests.
41 class UserFactory
implements IDBAccessObject
, UserRigorOptions
{
44 * RIGOR_* constants are inherited from UserRigorOptions
45 * READ_* constants are inherited from IDBAccessObject
48 /** @var ILoadBalancer */
49 private $loadBalancer;
51 /** @var UserNameUtils */
52 private $userNameUtils;
55 * @param ILoadBalancer $loadBalancer
56 * @param UserNameUtils $userNameUtils
58 public function __construct(
59 ILoadBalancer
$loadBalancer,
60 UserNameUtils
$userNameUtils
62 $this->loadBalancer
= $loadBalancer;
63 $this->userNameUtils
= $userNameUtils;
67 * Factory method for creating users by name, replacing static User::newFromName
69 * This is slightly less efficient than newFromId(), so use newFromId() if
70 * you have both an ID and a name handy.
72 * @note unlike User::newFromName, this returns null instead of false for invalid usernames
75 * @since 1.36 returns null instead of false for invalid user names
77 * @param string $name Username, validated by Title::newFromText
78 * @param string $validate Validation strategy, one of the RIGOR_* constants. For no
79 * validation, use RIGOR_NONE.
80 * @return ?User User object, or null if the username is invalid (e.g. if it contains
81 * illegal characters or is an IP address). If the username is not present in the database,
82 * the result will be a user object with a name, a user id of 0, and default settings.
84 public function newFromName(
86 string $validate = self
::RIGOR_VALID
88 // RIGOR_* constants are the same here and in the UserNameUtils class
89 $canonicalName = $this->userNameUtils
->getCanonical( $name, $validate );
90 if ( $canonicalName === false ) {
95 $user->mName
= $canonicalName;
96 $user->mFrom
= 'name';
97 $user->setItemLoaded( 'name' );
102 * Returns a new anonymous User based on ip.
106 * @param string|null $ip IP address
109 public function newAnonymous( $ip = null ) : User
{
111 $validIp = $this->userNameUtils
->isIP( $ip );
113 $user = $this->newFromName( $ip, self
::RIGOR_NONE
);
115 throw new InvalidArgumentException( 'Invalid IP address' );
124 * Factory method for creation from a given user ID, replacing User::newFromId
128 * @param int $id Valid user ID
129 * @return User The corresponding User object
131 public function newFromId( int $id ) : User
{
135 $user->setItemLoaded( 'id' );
140 * Factory method for creation from a given actor ID, replacing User::newFromActorId
144 * @param int $actorId
147 public function newFromActorId( int $actorId ) : User
{
149 $user->mActorId
= $actorId;
150 $user->mFrom
= 'actor';
151 $user->setItemLoaded( 'actor' );
156 * Factory method for creation fom a given UserIdentity, replacing User::newFromIdentity
160 * @param UserIdentity $userIdentity
163 public function newFromUserIdentity( UserIdentity
$userIdentity ) : User
{
164 if ( $userIdentity instanceof User
) {
165 return $userIdentity;
168 return $this->newFromAnyId(
169 $userIdentity->getId() === 0 ?
null : $userIdentity->getId(),
170 $userIdentity->getName() === '' ?
null : $userIdentity->getName(),
171 $userIdentity->getActorId() === 0 ?
null : $userIdentity->getActorId()
176 * Factory method for creation from an ID, name, and/or actor ID, replacing User::newFromAnyId
178 * @note This does not check that the ID, name, and actor ID all correspond to
183 * @param ?int $userId
184 * @param ?string $userName
185 * @param ?int $actorId
186 * @param bool|string $dbDomain
188 * @throws InvalidArgumentException if none of userId, userName, and actorId are specified
190 public function newFromAnyId(
196 // Stop-gap solution for the problem described in T222212.
197 // Force the User ID and Actor ID to zero for users loaded from the database
198 // of another wiki, to prevent subtle data corruption and confusing failure modes.
199 if ( $dbDomain !== false ) {
205 $user->mFrom
= 'defaults';
207 if ( $actorId !== null ) {
208 $user->mActorId
= $actorId;
209 if ( $actorId !== 0 ) {
210 $user->mFrom
= 'actor';
212 $user->setItemLoaded( 'actor' );
215 if ( $userName !== null && $userName !== '' ) {
216 $user->mName
= $userName;
217 $user->mFrom
= 'name';
218 $user->setItemLoaded( 'name' );
221 if ( $userId !== null ) {
222 $user->mId
= $userId;
223 if ( $userId !== 0 ) {
226 $user->setItemLoaded( 'id' );
229 if ( $user->mFrom
=== 'defaults' ) {
230 throw new InvalidArgumentException(
231 'Cannot create a user with no name, no ID, and no actor ID'
239 * Factory method to fetch the user for a given email confirmation code, replacing User::newFromConfirmationCode
241 * This code is generated when an account is created or its e-mail address has changed.
242 * If the code is invalid or has expired, returns null.
246 * @param string $confirmationCode
250 public function newFromConfirmationCode(
251 string $confirmationCode,
252 int $flags = self
::READ_NORMAL
254 list( $index, $options ) = DBAccessObjectUtils
::getDBOptions( $flags );
256 $db = $this->loadBalancer
->getConnectionRef( $index );
258 $id = $db->selectField(
262 'user_email_token' => md5( $confirmationCode ),
263 'user_email_token_expires > ' . $db->addQuotes( $db->timestamp() ),
273 return $this->newFromId( (int)$id );
277 * @see User::newFromRow
281 * @param stdClass $row A row from the user table
282 * @param array|null $data Further data to load into the object
285 public function newFromRow( $row, $data = null ) {
286 return User
::newFromRow( $row, $data );
290 * @internal for transition from User to Authority as performer concept.
291 * @param Authority $authority
294 public function newFromAuthority( Authority
$authority ): User
{
295 if ( $authority instanceof User
) {
298 return $this->newFromUserIdentity( $authority->getActor() );