MediaWiki  master
GenderCache.php
Go to the documentation of this file.
1 <?php
30 
36 class GenderCache {
37  protected $cache = [];
38  protected $default;
39  protected $misses = 0;
40  protected $missLimit = 1000;
41 
43  private $nsInfo;
44 
46  private $loadBalancer;
47 
50 
51  public function __construct(
52  NamespaceInfo $nsInfo = null,
55  ) {
56  $this->nsInfo = $nsInfo ?? MediaWikiServices::getInstance()->getNamespaceInfo();
57  $this->loadBalancer = $loadBalancer;
58  $this->userOptionsLookup = $userOptionsLookup ?? MediaWikiServices::getInstance()->getUserOptionsLookup();
59  }
60 
66  public static function singleton() {
67  wfDeprecated( __METHOD__, '1.28' );
68  return MediaWikiServices::getInstance()->getGenderCache();
69  }
70 
75  protected function getDefault() {
76  if ( $this->default === null ) {
77  $this->default = $this->userOptionsLookup->getDefaultOption( 'gender' );
78  }
79 
80  return $this->default;
81  }
82 
89  public function getGenderOf( $username, $caller = '' ) {
90  if ( $username instanceof UserIdentity ) {
91  $username = $username->getName();
92  }
93 
94  $username = self::normalizeUsername( $username );
95  if ( !isset( $this->cache[$username] ) ) {
96  if ( $this->misses >= $this->missLimit &&
97  RequestContext::getMain()->getUser()->getName() !== $username
98  ) {
99  if ( $this->misses === $this->missLimit ) {
100  $this->misses++;
101  wfDebug( __METHOD__ . ": too many misses, returning default onwards" );
102  }
103 
104  return $this->getDefault();
105  } else {
106  $this->misses++;
107  $this->doQuery( $username, $caller );
108  }
109  }
110 
111  /* Undefined if there is a valid username which for some reason doesn't
112  * exist in the database.
113  */
114  return $this->cache[$username] ?? $this->getDefault();
115  }
116 
123  public function doLinkBatch( $data, $caller = '' ) {
124  $users = [];
125  foreach ( $data as $ns => $pagenames ) {
126  if ( !$this->nsInfo->hasGenderDistinction( $ns ) ) {
127  continue;
128  }
129  foreach ( array_keys( $pagenames ) as $username ) {
130  $users[$username] = true;
131  }
132  }
133 
134  $this->doQuery( array_keys( $users ), $caller );
135  }
136 
144  public function doTitlesArray( $titles, $caller = '' ) {
145  $users = [];
146  foreach ( $titles as $titleObj ) {
147  if ( !$this->nsInfo->hasGenderDistinction( $titleObj->getNamespace() ) ) {
148  continue;
149  }
150  $users[] = $titleObj->getText();
151  }
152 
153  $this->doQuery( $users, $caller );
154  }
155 
161  public function doQuery( $users, $caller = '' ) {
162  $default = $this->getDefault();
163 
164  $usersToCheck = [];
165  foreach ( (array)$users as $value ) {
166  $name = self::normalizeUsername( $value );
167  // Skip users whose gender setting we already know
168  if ( !isset( $this->cache[$name] ) ) {
169  // For existing users, this value will be overwritten by the correct value
170  $this->cache[$name] = $default;
171  // query only for valid names, which can be in the database
172  if ( User::isValidUserName( $name ) ) {
173  $usersToCheck[] = $name;
174  }
175  }
176  }
177 
178  if ( count( $usersToCheck ) === 0 ) {
179  return;
180  }
181 
182  // Only query database, when load balancer is provided by service wiring
183  // This maybe not happen when running as part of the installer
184  if ( $this->loadBalancer === null ) {
185  return;
186  }
187 
188  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
189  $table = [ 'user', 'user_properties' ];
190  $fields = [ 'user_name', 'up_value' ];
191  $conds = [ 'user_name' => $usersToCheck ];
192  $joins = [ 'user_properties' =>
193  [ 'LEFT JOIN', [ 'user_id = up_user', 'up_property' => 'gender' ] ] ];
194 
195  $comment = __METHOD__;
196  if ( strval( $caller ) !== '' ) {
197  $comment .= "/$caller";
198  }
199  $res = $dbr->select( $table, $fields, $conds, $comment, [], $joins );
200 
201  foreach ( $res as $row ) {
202  $this->cache[$row->user_name] = $row->up_value ?: $default;
203  }
204  }
205 
206  private static function normalizeUsername( $username ) {
207  // Strip off subpages
208  $indexSlash = strpos( $username, '/' );
209  if ( $indexSlash !== false ) {
210  $username = substr( $username, 0, $indexSlash );
211  }
212 
213  // normalize underscore/spaces
214  return strtr( $username, '_', ' ' );
215  }
216 }
GenderCache\singleton
static singleton()
Definition: GenderCache.php:66
GenderCache\doLinkBatch
doLinkBatch( $data, $caller='')
Wrapper for doQuery that processes raw LinkBatch data.
Definition: GenderCache.php:123
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:163
GenderCache\__construct
__construct(NamespaceInfo $nsInfo=null, ILoadBalancer $loadBalancer=null, UserOptionsLookup $userOptionsLookup=null)
Definition: GenderCache.php:51
getUser
getUser()
GenderCache
Caches user genders when needed to use correct namespace aliases.
Definition: GenderCache.php:36
GenderCache\$loadBalancer
ILoadBalancer null $loadBalancer
Definition: GenderCache.php:46
User\isValidUserName
static isValidUserName( $name)
Is the input a valid username?
Definition: User.php:959
$res
$res
Definition: testCompression.php:57
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:32
GenderCache\getGenderOf
getGenderOf( $username, $caller='')
Returns the gender for given username.
Definition: GenderCache.php:89
GenderCache\doTitlesArray
doTitlesArray( $titles, $caller='')
Wrapper for doQuery that processes a title array.
Definition: GenderCache.php:144
$dbr
$dbr
Definition: testCompression.php:54
GenderCache\getDefault
getDefault()
Returns the default gender option in this wiki.
Definition: GenderCache.php:75
GenderCache\$missLimit
$missLimit
Definition: GenderCache.php:40
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1027
GenderCache\$nsInfo
NamespaceInfo $nsInfo
Definition: GenderCache.php:43
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:910
GenderCache\normalizeUsername
static normalizeUsername( $username)
Definition: GenderCache.php:206
GenderCache\$cache
$cache
Definition: GenderCache.php:37
GenderCache\doQuery
doQuery( $users, $caller='')
Preloads genders for given list of users.
Definition: GenderCache.php:161
GenderCache\$default
$default
Definition: GenderCache.php:38
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:454
MediaWiki\User\UserOptionsLookup
Provides access to user options.
Definition: UserOptionsLookup.php:29
GenderCache\$misses
$misses
Definition: GenderCache.php:39
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
GenderCache\$userOptionsLookup
UserOptionsLookup $userOptionsLookup
Definition: GenderCache.php:49
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81