MediaWiki  master
ActorStore.php
Go to the documentation of this file.
1 <?php
21 namespace MediaWiki\User;
22 
26 use InvalidArgumentException;
28 use Psr\Log\LoggerInterface;
29 use stdClass;
30 use User;
31 use Wikimedia\Assert\Assert;
32 use Wikimedia\IPUtils;
36 
44 
45  public const UNKNOWN_USER_NAME = 'Unknown user';
46 
47  private const LOCAL_CACHE_SIZE = 100;
48 
50  private $loadBalancer;
51 
53  private $userNameUtils;
54 
56  private $logger;
57 
59  private $wikiId;
60 
62  private $cache;
63 
70  public function __construct(
73  LoggerInterface $logger,
74  $wikiId = WikiAwareEntity::LOCAL
75  ) {
76  Assert::parameterType( 'string|boolean', $wikiId, '$wikiId' );
77  Assert::parameter( $wikiId !== true, '$wikiId', 'must be false or a string' );
78 
79  $this->loadBalancer = $loadBalancer;
80  $this->userNameUtils = $userNameUtils;
81  $this->logger = $logger;
82  $this->wikiId = $wikiId;
83 
84  $this->cache = new ActorCache( self::LOCAL_CACHE_SIZE );
85  }
86 
101  public function newActorFromRow( stdClass $row ): UserIdentity {
102  $actorId = (int)$row->actor_id;
103  $userId = isset( $row->actor_user ) ? (int)$row->actor_user : 0;
104  if ( $actorId === 0 ) {
105  throw new InvalidArgumentException( "Actor ID is 0 for {$row->actor_name} and {$userId}" );
106  }
107 
108  $normalizedName = $this->normalizeUserName( $row->actor_name );
109  if ( $normalizedName === null ) {
110  $this->logger->warning( 'Encountered invalid actor name in database', [
111  'user_id' => $userId,
112  'actor_id' => $actorId,
113  'actor_name' => $row->actor_name,
114  'wiki_id' => $this->wikiId ?: 'local'
115  ] );
116  // TODO: once we have guaranteed db only contains valid actor names,
117  // we can skip normalization here - T273933
118  if ( $row->actor_name === '' ) {
119  throw new InvalidArgumentException( "Actor name can not be empty for {$userId} and {$actorId}" );
120  }
121  }
122 
123  $actor = new UserIdentityValue( $userId, $row->actor_name, $this->wikiId );
124  $this->cache->add( $actorId, $actor );
125  return $actor;
126  }
127 
144  public function newActorFromRowFields( $userId, $name, $actorId ): UserIdentity {
145  // For backwards compatibility we are quite relaxed about what to accept,
146  // but try not to create entirely incorrect objects. As we move more code
147  // from ActorMigration aliases to proper join with the actor table,
148  // we should use ::newActorFromRow more, and eventually deprecate this method.
149  $userId = $userId === null ? 0 : (int)$userId;
150  $name = $name ?? '';
151  if ( $actorId === null ) {
152  throw new InvalidArgumentException( "Actor ID is null for {$name} and {$userId}" );
153  }
154  if ( (int)$actorId === 0 ) {
155  throw new InvalidArgumentException( "Actor ID is 0 for {$name} and {$userId}" );
156  }
157 
158  $normalizedName = $this->normalizeUserName( $name );
159  if ( $normalizedName === null ) {
160  $this->logger->warning( 'Encountered invalid actor name in database', [
161  'user_id' => $userId,
162  'actor_id' => $actorId,
163  'actor_name' => $name,
164  'wiki_id' => $this->wikiId ?: 'local'
165  ] );
166  // TODO: once we have guaranteed the DB entries only exist for normalized names,
167  // we can skip normalization here - T273933
168  if ( $name === '' ) {
169  throw new InvalidArgumentException( "Actor name can not be empty for {$userId} and {$actorId}" );
170  }
171  }
172 
173  $actorId = (int)$actorId;
174  $actor = new UserIdentityValue(
175  $userId,
176  $name,
177  $this->wikiId
178  );
179 
180  $this->cache->add( $actorId, $actor );
181  return $actor;
182  }
183 
188  public function deleteUserIdentityFromCache( UserIdentity $actor ) {
189  $this->cache->remove( $actor );
190  }
191 
200  public function getActorById( int $actorId, IDatabase $db ): ?UserIdentity {
201  $this->checkDatabaseDomain( $db );
202 
203  if ( !$actorId ) {
204  return null;
205  }
206 
207  return $this->cache->getActor( ActorCache::KEY_ACTOR_ID, $actorId ) ??
208  $this->newSelectQueryBuilder( $db )
209  ->caller( __METHOD__ )
210  ->conds( [ 'actor_id' => $actorId ] )
211  ->fetchUserIdentity() ??
212  // The actor ID mostly comes from DB, so if we can't find an actor by ID,
213  // it's most likely due to lagged replica and not cause it doesn't actually exist.
214  // Probably we just inserted it? Try primary database.
215  $this->newSelectQueryBuilder( self::READ_LATEST )
216  ->caller( __METHOD__ )
217  ->conds( [ 'actor_id' => $actorId ] )
218  ->fetchUserIdentity();
219  }
220 
228  public function getUserIdentityByName( string $name, int $queryFlags = self::READ_NORMAL ): ?UserIdentity {
229  $normalizedName = $this->normalizeUserName( $name );
230  if ( $normalizedName === null ) {
231  return null;
232  }
233 
234  return $this->cache->getActor( ActorCache::KEY_USER_NAME, $normalizedName ) ??
235  $this->newSelectQueryBuilder( $queryFlags )
236  ->caller( __METHOD__ )
237  ->whereUserNames( $normalizedName )
238  ->fetchUserIdentity();
239  }
240 
248  public function getUserIdentityByUserId( int $userId, int $queryFlags = self::READ_NORMAL ): ?UserIdentity {
249  if ( !$userId ) {
250  return null;
251  }
252 
253  return $this->cache->getActor( ActorCache::KEY_USER_ID, $userId ) ??
254  $this->newSelectQueryBuilder( $queryFlags )
255  ->caller( __METHOD__ )
256  ->whereUserIds( $userId )
257  ->fetchUserIdentity();
258  }
259 
269  private function attachActorId( UserIdentity $user, int $id, bool $assigned ) {
270  if ( $user instanceof User ) {
271  $user->setActorId( $id );
272  if ( $assigned ) {
273  $user->invalidateCache();
274  }
275  }
276  }
277 
285  private function detachActorId( UserIdentity $user ) {
286  if ( $user instanceof User ) {
287  $user->setActorId( 0 );
288  }
289  }
290 
299  public function findActorId( UserIdentity $user, IDatabase $db ): ?int {
300  // TODO: we want to assert this user belongs to the correct wiki,
301  // but User objects are always local and we used to use them
302  // on a non-local DB connection. We need to first deprecate this
303  // possibility and then throw on mismatching User object - T273972
304  // $user->assertWiki( $this->wikiId );
305  $this->deprecateInvalidCrossWikiParam( $user );
306 
307  // TODO: In the future we would be able to assume UserIdentity name is ok
308  // and will be able to skip normalization here - T273933
309  $name = $this->normalizeUserName( $user->getName() );
310  if ( $name === null ) {
311  $this->logger->warning( 'Encountered a UserIdentity with invalid name', [
312  'user_name' => $user->getName()
313  ] );
314  return null;
315  }
316 
317  $id = $this->findActorIdInternal( $name, $db );
318 
319  // Set the actor ID in the User object. To be removed, see T274148.
320  if ( $id && $user instanceof User ) {
321  $user->setActorId( $id );
322  }
323 
324  return $id;
325  }
326 
335  public function findActorIdByName( $name, IDatabase $db ): ?int {
336  $name = $this->normalizeUserName( $name );
337  if ( $name === null ) {
338  return null;
339  }
340 
341  return $this->findActorIdInternal( $name, $db );
342  }
343 
353  private function findActorIdInternal(
354  string $name,
355  IDatabase $db,
356  array $queryOptions = []
357  ): ?int {
358  // Note: UserIdentity::getActorId will be deprecated and removed,
359  // and this is the replacement for it. Can't call User::getActorId, cause
360  // User always thinks it's local, so we could end up fetching the ID
361  // from the wrong database.
362 
363  $cachedValue = $this->cache->getActorId( ActorCache::KEY_USER_NAME, $name );
364  if ( $cachedValue ) {
365  return $cachedValue;
366  }
367 
368  $row = $db->selectRow(
369  'actor',
370  [ 'actor_user', 'actor_name', 'actor_id' ],
371  [ 'actor_name' => $name ],
372  __METHOD__,
373  $queryOptions
374  );
375 
376  if ( !$row || !$row->actor_id ) {
377  return null;
378  }
379  // to cache row
380  $this->newActorFromRow( $row );
381 
382  return (int)$row->actor_id;
383  }
384 
399  public function acquireActorId( UserIdentity $user, IDatabase $dbw ): int {
400  $this->checkDatabaseDomain( $dbw );
401  [ $userId, $userName ] = $this->validateActorForInsertion( $user );
402 
403  // allow cache to be used, because if it is in the cache, it already has an actor ID
404  $existingActorId = $this->findActorIdInternal( $userName, $dbw );
405  if ( $existingActorId ) {
406  $this->attachActorId( $user, $existingActorId, false );
407  return $existingActorId;
408  }
409 
410  $dbw->insert(
411  'actor',
412  [
413  'actor_user' => $userId,
414  'actor_name' => $userName,
415  ],
416  __METHOD__,
417  [ 'IGNORE' ]
418  );
419 
420  if ( $dbw->affectedRows() ) {
421  $actorId = $dbw->insertId();
422  } else {
423  // Outdated cache?
424  // Use LOCK IN SHARE MODE to bypass any MySQL REPEATABLE-READ snapshot.
425  $actorId = $this->findActorIdInternal(
426  $userName,
427  $dbw,
428  [ 'LOCK IN SHARE MODE' ]
429  );
430  if ( !$actorId ) {
431  throw new CannotCreateActorException(
432  "Failed to create actor ID for " .
433  "user_id={$userId} user_name=\"{$userName}\""
434  );
435  }
436  }
437 
438  $this->attachActorId( $user, $actorId, true );
439  // Cache row we've just created
440  $cachedUserIdentity = $this->newActorFromRowFields( $userId, $userName, $actorId );
441  $this->setUpRollbackHandler( $dbw, $cachedUserIdentity, $user );
442  return $actorId;
443  }
444 
459  public function createNewActor( UserIdentity $user, IDatabase $dbw ): int {
460  $this->checkDatabaseDomain( $dbw );
461  [ $userId, $userName ] = $this->validateActorForInsertion( $user );
462 
463  try {
464  $dbw->insert(
465  'actor',
466  [
467  'actor_user' => $userId,
468  'actor_name' => $userName,
469  ],
470  __METHOD__
471  );
472  } catch ( DBQueryError $e ) {
473  // We rely on the database to crash on unique actor_name constraint.
474  throw new CannotCreateActorException( $e->getMessage() );
475  }
476  $actorId = $dbw->insertId();
477 
478  $this->attachActorId( $user, $actorId, true );
479  // Cache row we've just created
480  $cachedUserIdentity = $this->newActorFromRowFields( $userId, $userName, $actorId );
481  $this->setUpRollbackHandler( $dbw, $cachedUserIdentity, $user );
482 
483  return $actorId;
484  }
485 
503  public function acquireSystemActorId( UserIdentity $user, IDatabase $dbw ): int {
504  $this->checkDatabaseDomain( $dbw );
505  [ $userId, $userName ] = $this->validateActorForInsertion( $user );
506 
507  $existingActorId = $this->findActorIdInternal( $userName, $dbw );
508  if ( $existingActorId ) {
509  // It certainly will be cached if we just found it.
510  $existingActor = $this->cache->getActor( ActorCache::KEY_ACTOR_ID, $existingActorId );
511 
512  // If we already have an existing actor with a matching user ID
513  // just return it, nothing to do here.
514  if ( $existingActor->getId( $this->wikiId ) === $user->getId( $this->wikiId ) ) {
515  return $existingActorId;
516  }
517 
518  // Allow overwriting user ID for already existing actor with reserved user name, see T236444
519  if ( $this->userNameUtils->isUsable( $userName ) || $existingActor->isRegistered() ) {
520  throw new CannotCreateActorException(
521  'Cannot replace user for existing actor: ' .
522  "actor_id=$existingActorId, new user_id=$userId"
523  );
524  }
525  }
526 
527  $dbw->upsert(
528  'actor',
529  [ 'actor_name' => $userName, 'actor_user' => $userId ],
530  [ 'actor_name' ],
531  [ 'actor_user' => $userId ],
532  __METHOD__
533  );
534  if ( !$dbw->affectedRows() ) {
535  throw new CannotCreateActorException(
536  'Failed to replace user for actor: ' .
537  "actor_id=$existingActorId, new user_id=$userId"
538  );
539  }
540  $actorId = $dbw->insertId() ?: $existingActorId;
541 
542  $this->cache->remove( $user );
543  $this->attachActorId( $user, $actorId, true );
544  // Cache row we've just created
545  $cachedUserIdentity = $this->newActorFromRowFields( $userId, $userName, $actorId );
546  $this->setUpRollbackHandler( $dbw, $cachedUserIdentity, $user );
547  return $actorId;
548  }
549 
562  public function deleteActor( UserIdentity $actor, IDatabase $dbw ): bool {
563  $this->checkDatabaseDomain( $dbw );
564  $this->deprecateInvalidCrossWikiParam( $actor );
565 
566  $normalizedName = $this->normalizeUserName( $actor->getName() );
567  if ( $normalizedName === null ) {
568  throw new InvalidArgumentException(
569  "Unable to normalize the provided actor name {$actor->getName()}"
570  );
571  }
572  $dbw->delete(
573  'actor',
574  [ 'actor_name' => $normalizedName ],
575  __METHOD__
576  );
577  if ( $dbw->affectedRows() !== 0 ) {
578  $this->cache->remove( $actor );
579  return true;
580  }
581  return false;
582  }
583 
592  public function normalizeUserName( string $name ): ?string {
593  if ( $this->userNameUtils->isIP( $name ) ) {
594  return IPUtils::sanitizeIP( $name );
595  } elseif ( ExternalUserNames::isExternal( $name ) ) {
596  // TODO: ideally, we should probably canonicalize external usernames,
597  // but it was not done before, so we can not start doing it unless we
598  // fix existing DB rows - T273933
599  return $name;
600  } else {
601  $normalized = $this->userNameUtils->getCanonical( $name );
602  return $normalized === false ? null : $normalized;
603  }
604  }
605 
612  private function validateActorForInsertion( UserIdentity $user ): array {
613  // TODO: we want to assert this user belongs to the correct wiki,
614  // but User objects are always local and we used to use them
615  // on a non-local DB connection. We need to first deprecate this
616  // possibility and then throw on mismatching User object - T273972
617  // $user->assertWiki( $this->wikiId );
618  $this->deprecateInvalidCrossWikiParam( $user );
619 
620  $userName = $this->normalizeUserName( $user->getName() );
621  if ( $userName === null || $userName === '' ) {
622  $userIdForErrorMessage = $user->getId( $this->wikiId );
623  throw new CannotCreateActorException(
624  'Cannot create an actor for a user with no name: ' .
625  "user_id={$userIdForErrorMessage} user_name=\"{$user->getName()}\""
626  );
627  }
628 
629  $userId = $user->getId( $this->wikiId ) ?: null;
630  if ( $userId === null && $this->userNameUtils->isUsable( $user->getName() ) ) {
631  throw new CannotCreateActorException(
632  'Cannot create an actor for a usable name that is not an existing user: ' .
633  "user_name=\"{$user->getName()}\""
634  );
635  }
636  return [ $userId, $userName ];
637  }
638 
646  private function setUpRollbackHandler(
647  IDatabase $dbw,
648  UserIdentity $cachedActor,
649  UserIdentity $originalActor
650  ) {
651  if ( $dbw->trxLevel() ) {
652  // If called within a transaction and it was rolled back, the cached actor ID
653  // becomes invalid, so cache needs to be invalidated as well. See T277795.
655  function ( int $trigger ) use ( $cachedActor, $originalActor ) {
656  if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
657  $this->cache->remove( $cachedActor );
658  $this->detachActorId( $originalActor );
659  }
660  },
661  __METHOD__
662  );
663  }
664  }
665 
670  private function getDBConnectionRefForQueryFlags( int $queryFlags ): array {
671  [ $mode, $options ] = DBAccessObjectUtils::getDBOptions( $queryFlags );
672  return [ $this->loadBalancer->getConnectionRef( $mode, [], $this->wikiId ), $options ];
673  }
674 
681  private function checkDatabaseDomain( IDatabase $db ) {
682  $dbDomain = $db->getDomainID();
683  $storeDomain = $this->loadBalancer->resolveDomainID( $this->wikiId );
684  if ( $dbDomain !== $storeDomain ) {
685  throw new InvalidArgumentException(
686  "DB connection domain '$dbDomain' does not match '$storeDomain'"
687  );
688  }
689  }
690 
697  public function getUnknownActor(): UserIdentity {
698  $actor = $this->getUserIdentityByName( self::UNKNOWN_USER_NAME );
699  if ( $actor ) {
700  return $actor;
701  }
702  $actor = new UserIdentityValue( 0, self::UNKNOWN_USER_NAME, $this->wikiId );
703 
704  [ $db, ] = $this->getDBConnectionRefForQueryFlags( self::READ_LATEST );
705  $this->acquireActorId( $actor, $db );
706  return $actor;
707  }
708 
716  public function newSelectQueryBuilder( $dbOrQueryFlags = self::READ_NORMAL ): UserSelectQueryBuilder {
717  if ( $dbOrQueryFlags instanceof IDatabase ) {
718  [ $db, $options ] = [ $dbOrQueryFlags, [] ];
719  $this->checkDatabaseDomain( $db );
720  } else {
721  [ $db, $options ] = $this->getDBConnectionRefForQueryFlags( $dbOrQueryFlags );
722  }
723 
724  return ( new UserSelectQueryBuilder( $db, $this ) )->options( $options );
725  }
726 
733  private function deprecateInvalidCrossWikiParam( UserIdentity $user ) {
734  if ( $user->getWikiId() !== $this->wikiId ) {
735  $expected = $this->wikiIdToString( $user->getWikiId() );
736  $actual = $this->wikiIdToString( $this->wikiId );
738  'Deprecated passing invalid cross-wiki user. ' .
739  "Expected: {$expected}, Actual: {$actual}.",
740  '1.37'
741  );
742  }
743  }
744 
751  private function wikiIdToString( $wikiId ): string {
752  return $wikiId === WikiAwareEntity::LOCAL ? 'the local wiki' : "'{$wikiId}'";
753  }
754 }
MediaWiki\User\UserIdentityValue
Value object representing a user's identity.
Definition: UserIdentityValue.php:35
MediaWiki\User\ActorStore\__construct
__construct(ILoadBalancer $loadBalancer, UserNameUtils $userNameUtils, LoggerInterface $logger, $wikiId=WikiAwareEntity::LOCAL)
Definition: ActorStore.php:70
MediaWiki\User\ActorStore\validateActorForInsertion
validateActorForInsertion(UserIdentity $user)
Validates actor before insertion.
Definition: ActorStore.php:612
Wikimedia\Rdbms\IDatabase\affectedRows
affectedRows()
Get the number of rows affected by the last write query.
MediaWiki\User\ActorStore\newActorFromRowFields
newActorFromRowFields( $userId, $name, $actorId)
Instantiate a new UserIdentity object based on field values from a DB row.
Definition: ActorStore.php:144
if
if(ini_get( 'mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
Definition: Setup.php:92
MediaWiki\User\ActorStore\deleteUserIdentityFromCache
deleteUserIdentityFromCache(UserIdentity $actor)
Definition: ActorStore.php:188
Wikimedia\Rdbms\IDatabase\upsert
upsert( $table, array $rows, $uniqueKeys, array $set, $fname=__METHOD__)
Upsert the given row(s) into a table.
Wikimedia\Rdbms\IDatabase\trxLevel
trxLevel()
Gets the current transaction level.
ExternalUserNames
Class to parse and build external user names.
Definition: ExternalUserNames.php:30
MediaWiki\User\ActorStore\wikiIdToString
wikiIdToString( $wikiId)
Convert $wikiId to a string for logging.
Definition: ActorStore.php:751
MediaWiki\User\ActorStore\setUpRollbackHandler
setUpRollbackHandler(IDatabase $dbw, UserIdentity $cachedActor, UserIdentity $originalActor)
Clear in-process caches if transaction gets rolled back.
Definition: ActorStore.php:646
MediaWiki\User\UserIdentity\getId
getId( $wikiId=self::LOCAL)
DBAccessObjectUtils\getDBOptions
static getDBOptions( $bitfield)
Get an appropriate DB index, options, and fallback DB index for a query.
Definition: DBAccessObjectUtils.php:52
MediaWiki\User\ActorStore\findActorIdInternal
findActorIdInternal(string $name, IDatabase $db, array $queryOptions=[])
Find actor_id of the given $user using the passed $db connection.
Definition: ActorStore.php:353
MediaWiki\DAO\WikiAwareEntity
Marker interface for entities aware of the wiki they belong to.
Definition: WikiAwareEntity.php:35
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:39
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
MediaWiki\User\ActorStore\normalizeUserName
normalizeUserName(string $name)
Returns a canonical form of user name suitable for storage.
Definition: ActorStore.php:592
wfDeprecatedMsg
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
Definition: GlobalFunctions.php:1028
MediaWiki\User\ActorStore\$loadBalancer
ILoadBalancer $loadBalancer
Definition: ActorStore.php:50
MediaWiki\User\ActorStore\findActorIdByName
findActorIdByName( $name, IDatabase $db)
Find the actor_id of the given $name.
Definition: ActorStore.php:335
MediaWiki\User\ActorStore\$wikiId
string false $wikiId
Definition: ActorStore.php:59
MediaWiki\User\ActorStore\acquireActorId
acquireActorId(UserIdentity $user, IDatabase $dbw)
Attempt to assign an actor ID to the given $user.
Definition: ActorStore.php:399
MediaWiki\User\ActorStore\acquireSystemActorId
acquireSystemActorId(UserIdentity $user, IDatabase $dbw)
Attempt to assign an ID to an actor for a system user.
Definition: ActorStore.php:503
MediaWiki\User\UserIdentity\getName
getName()
MediaWiki\User\ActorStore\getDBConnectionRefForQueryFlags
getDBConnectionRefForQueryFlags(int $queryFlags)
Definition: ActorStore.php:670
MediaWiki\User\ActorStore\newSelectQueryBuilder
newSelectQueryBuilder( $dbOrQueryFlags=self::READ_NORMAL)
Returns a specialized SelectQueryBuilder for querying the UserIdentity objects.
Definition: ActorStore.php:716
MediaWiki\User\ActorCache
Definition: ActorCache.php:36
DBAccessObjectUtils
Helper class for DAO classes.
Definition: DBAccessObjectUtils.php:29
Wikimedia\Rdbms\DBQueryError
Definition: DBQueryError.php:29
MediaWiki\User\ActorStore\attachActorId
attachActorId(UserIdentity $user, int $id, bool $assigned)
Attach the actor ID to $user for backwards compatibility.
Definition: ActorStore.php:269
MediaWiki\User\ActorStore\deleteActor
deleteActor(UserIdentity $actor, IDatabase $dbw)
Delete the actor from the actor table.
Definition: ActorStore.php:562
MediaWiki\User\ActorStore\UNKNOWN_USER_NAME
const UNKNOWN_USER_NAME
Definition: ActorStore.php:45
MediaWiki\User\ActorStore\LOCAL_CACHE_SIZE
const LOCAL_CACHE_SIZE
Definition: ActorStore.php:47
MediaWiki\User\ActorStore\getUserIdentityByName
getUserIdentityByName(string $name, int $queryFlags=self::READ_NORMAL)
Find an actor by $name.
Definition: ActorStore.php:228
MediaWiki\User\UserIdentityLookup
Definition: UserIdentityLookup.php:33
MediaWiki\DAO\WikiAwareEntity\getWikiId
getWikiId()
Get the ID of the wiki this page belongs to.
Wikimedia\Rdbms\IDatabase\selectRow
selectRow( $table, $vars, $conds, $fname=__METHOD__, $options=[], $join_conds=[])
Wrapper to IDatabase::select() that only fetches one row (via LIMIT)
Wikimedia\Rdbms\IDatabase\getDomainID
getDomainID()
Return the currently selected domain ID.
CannotCreateActorException
Exception thrown when an actor can't be created.
Definition: CannotCreateActorException.php:29
MediaWiki\User
Definition: ActorCache.php:21
MediaWiki\User\ActorStore\createNewActor
createNewActor(UserIdentity $user, IDatabase $dbw)
Create a new actor for the given $user.
Definition: ActorStore.php:459
MediaWiki\User\ActorStore\getUnknownActor
getUnknownActor()
In case all reasonable attempts of initializing a proper actor from the database have failed,...
Definition: ActorStore.php:697
MediaWiki\User\ActorStore\$logger
LoggerInterface $logger
Definition: ActorStore.php:56
Wikimedia\Rdbms\IDatabase\insert
insert( $table, $rows, $fname=__METHOD__, $options=[])
Insert the given row(s) into a table.
MediaWiki\User\ActorStore\$cache
ActorCache $cache
Definition: ActorStore.php:62
MediaWiki\User\UserSelectQueryBuilder
Definition: UserSelectQueryBuilder.php:29
MediaWiki\User\UserNameUtils
UserNameUtils service.
Definition: UserNameUtils.php:42
MediaWiki\User\ActorStore\getActorById
getActorById(int $actorId, IDatabase $db)
Find an actor by $id.
Definition: ActorStore.php:200
MediaWiki\User\ActorStore\detachActorId
detachActorId(UserIdentity $user)
Detach the actor ID from $user for backwards compatibility.
Definition: ActorStore.php:285
MediaWiki\User\ActorStore\checkDatabaseDomain
checkDatabaseDomain(IDatabase $db)
Throws an exception if the given database connection does not belong to the wiki this RevisionStore i...
Definition: ActorStore.php:681
MediaWiki\User\ActorStore\deprecateInvalidCrossWikiParam
deprecateInvalidCrossWikiParam(UserIdentity $user)
Emits a deprecation warning if $user does not belong to the same wiki this store belongs to.
Definition: ActorStore.php:733
Wikimedia\Rdbms\IDatabase\insertId
insertId()
Get the inserted value of an auto-increment row.
Wikimedia\Rdbms\IDatabase\onTransactionResolution
onTransactionResolution(callable $callback, $fname=__METHOD__)
Run a callback when the current transaction commits or rolls back.
MediaWiki\User\ActorStore\$userNameUtils
UserNameUtils $userNameUtils
Definition: ActorStore.php:53
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:67
ExternalUserNames\isExternal
static isExternal( $username)
Tells whether the username is external or not.
Definition: ExternalUserNames.php:149
Wikimedia\Rdbms\IDatabase\delete
delete( $table, $conds, $fname=__METHOD__)
Delete all rows in a table that match a condition.
MediaWiki\User\ActorStore\findActorId
findActorId(UserIdentity $user, IDatabase $db)
Find the actor_id of the given $user.
Definition: ActorStore.php:299
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81
MediaWiki\User\ActorStore
Definition: ActorStore.php:43
MediaWiki\User\ActorStore\newActorFromRow
newActorFromRow(stdClass $row)
Instantiate a new UserIdentity object based on a $row from the actor table.
Definition: ActorStore.php:101
MediaWiki\User\ActorStore\getUserIdentityByUserId
getUserIdentityByUserId(int $userId, int $queryFlags=self::READ_NORMAL)
Find an actor by $userId.
Definition: ActorStore.php:248
MediaWiki\User\ActorNormalization
Service for dealing with the actor table.
Definition: ActorNormalization.php:32