2declare( strict_types = 1 );
4namespace MediaWiki\Extension\Translate\MessageProcessing;
10use Wikimedia\Rdbms\IConnectionProvider;
23 private const MAX_ITEMS_PER_QUERY = 2000;
25 private array $cache = [];
26 private ?array $priorityCache =
null;
28 public function __construct(
private readonly IConnectionProvider $dbProvider ) {
37 $missing = array_keys( array_diff_key( array_flip( $dbGroupIds ), $this->cache ) );
42 $functionName = __METHOD__ .
" (for $caller)";
44 $this->cache += array_fill_keys( $missing,
null );
47 $dbr = Utilities::getSafeReadDB();
48 $chunks = array_chunk( $missing, self::MAX_ITEMS_PER_QUERY );
49 foreach ( $chunks as $chunk ) {
50 $res = $dbr->newSelectQueryBuilder()
51 ->select( [
'tmd_group',
'tmd_key',
'tmd_value' ] )
52 ->from(
'translate_metadata' )
53 ->where( [
'tmd_group' => array_map( strval( ... ), $chunk ) ] )
54 ->caller( $functionName )
56 foreach ( $res as $row ) {
57 $this->cache[$row->tmd_group][$row->tmd_key] = $row->tmd_value;
67 public function get(
MessageGroup|
string $group,
string $key ): string|false {
68 $this->preloadGroups( [ $group ], __METHOD__ );
69 $dbGroupId = MessageGroupSubscriptionStore::getGroupIdForDatabase( $group );
70 return $this->cache[$dbGroupId][$key] ??
false;
78 $value = $this->get( $group, $key );
79 return $value ===
false ? $defaultValue : $value;
89 public function set(
MessageGroup|
string $group,
string $key,
string|
false $value ): void {
90 $dbw = $this->dbProvider->getPrimaryDatabase();
91 $dbGroupId = MessageGroupSubscriptionStore::getGroupIdForDatabase( $group );
92 $data = [
'tmd_group' => $dbGroupId,
'tmd_key' => $key,
'tmd_value' => $value ];
93 if ( $value ===
false ) {
94 unset( $data[
'tmd_value'] );
95 $dbw->newDeleteQueryBuilder()
96 ->deleteFrom(
'translate_metadata' )
98 ->caller( __METHOD__ )
100 unset( $this->cache[$dbGroupId][$key] );
102 $dbw->newReplaceQueryBuilder()
103 ->replaceInto(
'translate_metadata' )
104 ->uniqueIndexFields( [
'tmd_group',
'tmd_key' ] )
106 ->caller( __METHOD__ )
108 $this->cache[$dbGroupId][$key] = $value;
111 $this->priorityCache =
null;
119 $groups = $this->get( $groupId,
'subgroups' );
120 if ( is_string( $groups ) ) {
121 if ( str_contains( $groups,
'|' ) ) {
122 $groups = explode(
'|', $groups );
124 $groups = array_map(
'trim', explode(
',', $groups ) );
127 foreach ( $groups as $index => $id ) {
128 if ( trim( $id ) ===
'' ) {
129 unset( $groups[$index] );
140 public function setSubgroups(
string $groupId, array $subgroupIds ): void {
141 $subgroups = implode(
'|', $subgroupIds );
142 $this->
set( $groupId,
'subgroups', $subgroups );
147 $dbw = $this->dbProvider->getPrimaryDatabase();
149 $dbGroupId = MessageGroupSubscriptionStore::getGroupIdForDatabase( $groupId );
150 $dbw->newDeleteQueryBuilder()
151 ->deleteFrom(
'translate_metadata' )
152 ->where( [
'tmd_group' => $dbGroupId ] )
153 ->caller( __METHOD__ )
155 $this->cache[ $dbGroupId ] =
null;
156 unset( $this->priorityCache[ $dbGroupId ] );
159 public function isExcluded(
MessageGroup|
string $group,
string $code ): bool {
160 if ( $this->priorityCache === null ) {
162 $db = Utilities::getSafeReadDB();
163 $res = $db->newSelectQueryBuilder()
165 'group' =>
'a.tmd_group',
166 'langs' =>
'b.tmd_value',
168 ->from(
'translate_metadata',
'a' )
169 ->leftJoin(
'translate_metadata',
'b', [
170 'a.tmd_group = b.tmd_group',
171 'b.tmd_key' =>
'prioritylangs',
174 'a.tmd_key' =>
'priorityforce',
175 'a.tmd_value' =>
'on'
177 ->caller( __METHOD__ )
180 $this->priorityCache = [];
181 foreach ( $res as $row ) {
182 $this->priorityCache[$row->group] = isset( $row->langs )
183 ? array_flip( explode(
',', $row->langs ) )
188 $dbGroupId = MessageGroupSubscriptionStore::getGroupIdForDatabase( $group );
189 $isDiscouraged = MessageGroups::getPriority( $group ) ===
'discouraged';
190 $hasLimitedLanguages = isset( $this->priorityCache[$dbGroupId] );
191 $isLanguageIncluded = isset( $this->priorityCache[$dbGroupId][$code] );
193 return $isDiscouraged || ( $hasLimitedLanguages && !$isLanguageIncluded );
207 foreach ( $groupIds as $groupId ) {
208 $dbGroupId = MessageGroupSubscriptionStore::getGroupIdForDatabase( $groupId );
209 $dbGroupIdMap[$dbGroupId] = $groupId;
212 $res = $db->newSelectQueryBuilder()
213 ->select( [
'tmd_group',
'tmd_key',
'tmd_value' ] )
214 ->from(
'translate_metadata' )
216 'tmd_group' => array_keys( $dbGroupIdMap ),
219 ->caller( __METHOD__ )
223 foreach ( $res as $row ) {
224 $groupId = $row->tmd_group;
226 $ret[ $dbGroupIdMap[ $groupId ] ][ $row->tmd_key ] = $row->tmd_value;
232 public function moveMetadata(
235 array $metadataKeysToMove
237 $this->preloadGroups( [ $oldGroupId, $newGroupId ], __METHOD__ );
238 foreach ( $metadataKeysToMove as $type ) {
239 $value = $this->
get( $oldGroupId, $type );
240 if ( $value !==
false ) {
241 $this->
set( $oldGroupId, $type, false );
242 $this->
set( $newGroupId, $type, $value );
251 public function clearMetadata(
string $groupId, array $metadataKeys ): void {
253 foreach ( $metadataKeys as $type ) {
254 $this->
set( $groupId, $type, false );
265 return $db->newSelectQueryBuilder()
266 ->select(
'tmd_group' )
267 ->from(
'translate_metadata' )
268 ->where( [
'tmd_key' =>
'subgroups' ] )
269 ->caller( __METHOD__ )
270 ->fetchFieldValues();
Interface for message groups.