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