MediaWiki master
GenderCache.php
Go to the documentation of this file.
1<?php
22namespace MediaWiki\Cache;
23
31
44 protected $cache = [];
46 protected $default = null;
48 protected $misses = 0;
53 protected $missLimit = 1000;
54
55 private NamespaceInfo $nsInfo;
56 private ?IConnectionProvider $dbProvider;
57 private UserOptionsLookup $userOptionsLookup;
58
59 public function __construct(
60 ?NamespaceInfo $nsInfo = null,
61 ?IConnectionProvider $dbProvider = null,
62 ?UserOptionsLookup $userOptionsLookup = null
63 ) {
64 $this->nsInfo = $nsInfo ?? MediaWikiServices::getInstance()->getNamespaceInfo();
65 $this->dbProvider = $dbProvider;
66 $this->userOptionsLookup = $userOptionsLookup ?? MediaWikiServices::getInstance()->getUserOptionsLookup();
67 }
68
74 protected function getDefault() {
75 $this->default ??= $this->userOptionsLookup->getDefaultOption( 'gender' );
76 return $this->default;
77 }
78
86 public function getGenderOf( $username, $caller = '' ) {
87 if ( $username instanceof UserIdentity ) {
88 $username = $username->getName();
89 }
90
91 $username = self::normalizeUsername( $username );
92 if ( !isset( $this->cache[$username] ) ) {
93 if ( $this->misses < $this->missLimit ||
94 RequestContext::getMain()->getUser()->getName() === $username
95 ) {
96 $this->misses++;
97 $this->doQuery( $username, $caller );
98 }
99 if ( $this->misses === $this->missLimit ) {
100 // Log only once and don't bother incrementing beyond limit+1
101 $this->misses++;
102 wfDebug( __METHOD__ . ': too many misses, returning default onwards' );
103 }
104 }
105
106 return $this->cache[$username] ?? $this->getDefault();
107 }
108
115 public function doLinkBatch( array $data, $caller = '' ) {
116 $users = [];
117 foreach ( $data as $ns => $pagenames ) {
118 if ( $this->nsInfo->hasGenderDistinction( $ns ) ) {
119 $users += $pagenames;
120 }
121 }
122 $this->doQuery( array_keys( $users ), $caller );
123 }
124
132 public function doTitlesArray( $titles, $caller = '' ) {
133 $users = [];
134 foreach ( $titles as $titleObj ) {
135 if ( $this->nsInfo->hasGenderDistinction( $titleObj->getNamespace() ) ) {
136 $users[] = $titleObj->getText();
137 }
138 }
139 $this->doQuery( $users, $caller );
140 }
141
148 public function doQuery( $users, $caller = '' ) {
149 $default = $this->getDefault();
150
151 $usersToFetch = [];
152 foreach ( (array)$users as $value ) {
153 $name = self::normalizeUsername( $value );
154 if ( !isset( $this->cache[$name] ) ) {
155 // This may be overwritten below by a fetched value
156 $this->cache[$name] = $default;
157 // T267054: We don't need to fetch data for invalid usernames, but filtering breaks DI
158 $usersToFetch[] = $name;
159 }
160 }
161
162 // Skip query when database is unavailable (e.g. via the installer)
163 if ( !$usersToFetch || !$this->dbProvider ) {
164 return;
165 }
166
167 $caller = __METHOD__ . ( $caller ? "/$caller" : '' );
168
169 $res = $queryBuilder = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
170 ->select( [ 'user_name', 'up_value' ] )
171 ->from( 'user' )
172 ->leftJoin( 'user_properties', null, [ 'user_id = up_user', 'up_property' => 'gender' ] )
173 ->where( [ 'user_name' => $usersToFetch ] )
174 ->caller( $caller )
175 ->fetchResultSet();
176
177 foreach ( $res as $row ) {
178 $this->cache[$row->user_name] = $row->up_value ?: $default;
179 }
180 }
181
182 private static function normalizeUsername( $username ) {
183 // Strip off subpages
184 $indexSlash = strpos( $username, '/' );
185 if ( $indexSlash !== false ) {
186 $username = substr( $username, 0, $indexSlash );
187 }
188
189 // normalize underscore/spaces
190 return strtr( $username, '_', ' ' );
191 }
192}
193
195class_alias( GenderCache::class, 'GenderCache' );
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Look up "gender" user preference.
__construct(?NamespaceInfo $nsInfo=null, ?IConnectionProvider $dbProvider=null, ?UserOptionsLookup $userOptionsLookup=null)
doQuery( $users, $caller='')
Preload gender option for multiple user names.
getDefault()
Get the default gender option on this wiki.
getGenderOf( $username, $caller='')
Get the gender option for given username.
doTitlesArray( $titles, $caller='')
Wrapper for doQuery that processes a title array.
doLinkBatch(array $data, $caller='')
Wrapper for doQuery that processes raw LinkBatch data.
Group all the pieces relevant to the context of a request into one instance.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Provides access to user options.
Represents the target of a wiki link.
Interface for objects representing user identity.
Provide primary and replica IDatabase connections.