MediaWiki  master
GenderCache.php
Go to the documentation of this file.
1 <?php
29 
35 class GenderCache {
36  protected $cache = [];
37  protected $default;
38  protected $misses = 0;
39  protected $missLimit = 1000;
40 
42  private $nsInfo;
43 
45  private $loadBalancer;
46 
47  public function __construct( NamespaceInfo $nsInfo = null, ILoadBalancer $loadBalancer = null ) {
48  $this->nsInfo = $nsInfo ?? MediaWikiServices::getInstance()->getNamespaceInfo();
49  $this->loadBalancer = $loadBalancer;
50  }
51 
57  public static function singleton() {
58  wfDeprecated( __METHOD__, '1.28' );
59  return MediaWikiServices::getInstance()->getGenderCache();
60  }
61 
66  protected function getDefault() {
67  if ( $this->default === null ) {
68  $this->default = User::getDefaultOption( 'gender' );
69  }
70 
71  return $this->default;
72  }
73 
80  public function getGenderOf( $username, $caller = '' ) {
81  global $wgUser;
82 
83  if ( $username instanceof UserIdentity ) {
84  $username = $username->getName();
85  }
86 
87  $username = self::normalizeUsername( $username );
88  if ( !isset( $this->cache[$username] ) ) {
89  if ( $this->misses >= $this->missLimit && $wgUser->getName() !== $username ) {
90  if ( $this->misses === $this->missLimit ) {
91  $this->misses++;
92  wfDebug( __METHOD__ . ": too many misses, returning default onwards\n" );
93  }
94 
95  return $this->getDefault();
96  } else {
97  $this->misses++;
98  $this->doQuery( $username, $caller );
99  }
100  }
101 
102  /* Undefined if there is a valid username which for some reason doesn't
103  * exist in the database.
104  */
105  return $this->cache[$username] ?? $this->getDefault();
106  }
107 
114  public function doLinkBatch( $data, $caller = '' ) {
115  $users = [];
116  foreach ( $data as $ns => $pagenames ) {
117  if ( !$this->nsInfo->hasGenderDistinction( $ns ) ) {
118  continue;
119  }
120  foreach ( array_keys( $pagenames ) as $username ) {
121  $users[$username] = true;
122  }
123  }
124 
125  $this->doQuery( array_keys( $users ), $caller );
126  }
127 
135  public function doTitlesArray( $titles, $caller = '' ) {
136  $users = [];
137  foreach ( $titles as $titleObj ) {
138  if ( !$this->nsInfo->hasGenderDistinction( $titleObj->getNamespace() ) ) {
139  continue;
140  }
141  $users[] = $titleObj->getText();
142  }
143 
144  $this->doQuery( $users, $caller );
145  }
146 
152  public function doQuery( $users, $caller = '' ) {
153  $default = $this->getDefault();
154 
155  $usersToCheck = [];
156  foreach ( (array)$users as $value ) {
157  $name = self::normalizeUsername( $value );
158  // Skip users whose gender setting we already know
159  if ( !isset( $this->cache[$name] ) ) {
160  // For existing users, this value will be overwritten by the correct value
161  $this->cache[$name] = $default;
162  // query only for valid names, which can be in the database
163  if ( User::isValidUserName( $name ) ) {
164  $usersToCheck[] = $name;
165  }
166  }
167  }
168 
169  if ( count( $usersToCheck ) === 0 ) {
170  return;
171  }
172 
173  // Only query database, when load balancer is provided by service wiring
174  // This maybe not happen when running as part of the installer
175  if ( $this->loadBalancer === null ) {
176  return;
177  }
178 
179  $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
180  $table = [ 'user', 'user_properties' ];
181  $fields = [ 'user_name', 'up_value' ];
182  $conds = [ 'user_name' => $usersToCheck ];
183  $joins = [ 'user_properties' =>
184  [ 'LEFT JOIN', [ 'user_id = up_user', 'up_property' => 'gender' ] ] ];
185 
186  $comment = __METHOD__;
187  if ( strval( $caller ) !== '' ) {
188  $comment .= "/$caller";
189  }
190  $res = $dbr->select( $table, $fields, $conds, $comment, [], $joins );
191 
192  foreach ( $res as $row ) {
193  $this->cache[$row->user_name] = $row->up_value ?: $default;
194  }
195  }
196 
197  private static function normalizeUsername( $username ) {
198  // Strip off subpages
199  $indexSlash = strpos( $username, '/' );
200  if ( $indexSlash !== false ) {
201  $username = substr( $username, 0, $indexSlash );
202  }
203 
204  // normalize underscore/spaces
205  return strtr( $username, '_', ' ' );
206  }
207 }
User\getDefaultOption
static getDefaultOption( $opt)
Get a given default option value.
Definition: User.php:1608
GenderCache\singleton
static singleton()
Definition: GenderCache.php:57
GenderCache\doLinkBatch
doLinkBatch( $data, $caller='')
Wrapper for doQuery that processes raw LinkBatch data.
Definition: GenderCache.php:114
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:144
GenderCache
Caches user genders when needed to use correct namespace aliases.
Definition: GenderCache.php:35
GenderCache\$loadBalancer
ILoadBalancer null $loadBalancer
Definition: GenderCache.php:45
User\isValidUserName
static isValidUserName( $name)
Is the input a valid username?
Definition: User.php:974
$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:80
GenderCache\doTitlesArray
doTitlesArray( $titles, $caller='')
Wrapper for doQuery that processes a title array.
Definition: GenderCache.php:135
$dbr
$dbr
Definition: testCompression.php:54
GenderCache\getDefault
getDefault()
Returns the default gender option in this wiki.
Definition: GenderCache.php:66
GenderCache\$missLimit
$missLimit
Definition: GenderCache.php:39
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1030
GenderCache\$nsInfo
NamespaceInfo $nsInfo
Definition: GenderCache.php:42
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:913
GenderCache\__construct
__construct(NamespaceInfo $nsInfo=null, ILoadBalancer $loadBalancer=null)
Definition: GenderCache.php:47
GenderCache\normalizeUsername
static normalizeUsername( $username)
Definition: GenderCache.php:197
GenderCache\$cache
$cache
Definition: GenderCache.php:36
GenderCache\doQuery
doQuery( $users, $caller='')
Preloads genders for given list of users.
Definition: GenderCache.php:152
GenderCache\$default
$default
Definition: GenderCache.php:37
GenderCache\$misses
$misses
Definition: GenderCache.php:38
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:33
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81