MediaWiki  master
GenderCache.php
Go to the documentation of this file.
1 <?php
28 
35 class GenderCache {
36  protected $cache = [];
37  protected $default;
38  protected $misses = 0;
39  protected $missLimit = 1000;
40 
42  private $nsInfo;
43 
45  private $dbProvider;
46 
48  private $userOptionsLookup;
49 
50  public function __construct(
51  NamespaceInfo $nsInfo = null,
52  IConnectionProvider $dbProvider = null,
53  UserOptionsLookup $userOptionsLookup = null
54  ) {
55  $this->nsInfo = $nsInfo ?? MediaWikiServices::getInstance()->getNamespaceInfo();
56  $this->dbProvider = $dbProvider;
57  $this->userOptionsLookup = $userOptionsLookup ?? MediaWikiServices::getInstance()->getUserOptionsLookup();
58  }
59 
64  protected function getDefault() {
65  $this->default ??= $this->userOptionsLookup->getDefaultOption( 'gender' );
66 
67  return $this->default;
68  }
69 
76  public function getGenderOf( $username, $caller = '' ) {
77  if ( $username instanceof UserIdentity ) {
78  $username = $username->getName();
79  }
80 
81  $username = self::normalizeUsername( $username );
82  if ( !isset( $this->cache[$username] ) ) {
83  if ( $this->misses >= $this->missLimit &&
84  RequestContext::getMain()->getUser()->getName() !== $username
85  ) {
86  if ( $this->misses === $this->missLimit ) {
87  $this->misses++;
88  wfDebug( __METHOD__ . ": too many misses, returning default onwards" );
89  }
90 
91  return $this->getDefault();
92  } else {
93  $this->misses++;
94  $this->doQuery( $username, $caller );
95  }
96  }
97 
98  /* Undefined if there is a valid username which for some reason doesn't
99  * exist in the database.
100  */
101  return $this->cache[$username] ?? $this->getDefault();
102  }
103 
110  public function doLinkBatch( array $data, $caller = '' ) {
111  $users = [];
112  foreach ( $data as $ns => $pagenames ) {
113  if ( $this->nsInfo->hasGenderDistinction( $ns ) ) {
114  $users += $pagenames;
115  }
116  }
117  $this->doQuery( array_keys( $users ), $caller );
118  }
119 
127  public function doTitlesArray( $titles, $caller = '' ) {
128  $users = [];
129  foreach ( $titles as $titleObj ) {
130  if ( $this->nsInfo->hasGenderDistinction( $titleObj->getNamespace() ) ) {
131  $users[] = $titleObj->getText();
132  }
133  }
134  $this->doQuery( $users, $caller );
135  }
136 
142  public function doQuery( $users, $caller = '' ) {
143  $default = $this->getDefault();
144 
145  $usersToCheck = [];
146  foreach ( (array)$users as $value ) {
147  $name = self::normalizeUsername( $value );
148  // Skip users whose gender setting we already know
149  if ( !isset( $this->cache[$name] ) ) {
150  // For existing users, this value will be overwritten by the correct value
151  $this->cache[$name] = $default;
152  // We no longer verify that only valid names are checked for, T267054
153  $usersToCheck[] = $name;
154  }
155  }
156 
157  if ( count( $usersToCheck ) === 0 ) {
158  return;
159  }
160 
161  // Only query database, when db provider is provided by service wiring
162  // This maybe not happen when running as part of the installer
163  if ( $this->dbProvider === null ) {
164  return;
165  }
166 
167  $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
168  ->select( [ 'user_name', 'up_value' ] )
169  ->from( 'user' )
170  ->leftJoin( 'user_properties', null, [ 'user_id = up_user', 'up_property' => 'gender' ] )
171  ->where( [ 'user_name' => $usersToCheck ] );
172 
173  $comment = __METHOD__;
174  if ( strval( $caller ) !== '' ) {
175  $comment .= "/$caller";
176  }
177  $res = $queryBuilder->caller( $comment )->fetchResultSet();
178 
179  foreach ( $res as $row ) {
180  $this->cache[$row->user_name] = $row->up_value ?: $default;
181  }
182  }
183 
184  private static function normalizeUsername( $username ) {
185  // Strip off subpages
186  $indexSlash = strpos( $username, '/' );
187  if ( $indexSlash !== false ) {
188  $username = substr( $username, 0, $indexSlash );
189  }
190 
191  // normalize underscore/spaces
192  return strtr( $username, '_', ' ' );
193  }
194 }
getUser()
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Caches user genders when needed to use correct namespace aliases.
Definition: GenderCache.php:35
__construct(NamespaceInfo $nsInfo=null, IConnectionProvider $dbProvider=null, UserOptionsLookup $userOptionsLookup=null)
Definition: GenderCache.php:50
getGenderOf( $username, $caller='')
Returns the gender for given username.
Definition: GenderCache.php:76
doLinkBatch(array $data, $caller='')
Wrapper for doQuery that processes raw LinkBatch data.
getDefault()
Returns the default gender option in this wiki.
Definition: GenderCache.php:64
doTitlesArray( $titles, $caller='')
Wrapper for doQuery that processes a title array.
doQuery( $users, $caller='')
Preloads genders for given list of users.
Service locator for MediaWiki core services.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Provides access to user options.
static getMain()
Get the RequestContext object associated with the main request.
Represents the target of a wiki link.
Definition: LinkTarget.php:30
Interface for objects representing user identity.
Provide primary and replica IDatabase connections.