Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MessageGroupReviewStore.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\MessageGroupProcessing;
5
6use InvalidArgumentException;
7use ManualLogEntry;
10use SpecialPage;
11use User;
12use Wikimedia\Rdbms\ILoadBalancer;
13use Wikimedia\Rdbms\IResultWrapper;
14
21 private HookRunner $hookRunner;
22 private ILoadBalancer $loadBalancer;
23 private const TABLE_NAME = 'translate_groupreviews';
25 private ?array $priorityCache = null;
26
27 public function __construct( ILoadBalancer $loadBalancer, HookRunner $hookRunner ) {
28 $this->loadBalancer = $loadBalancer;
29 $this->hookRunner = $hookRunner;
30 }
31
33 public function getState( MessageGroup $group, string $code ) {
34 $dbw = $this->loadBalancer->getConnection( DB_PRIMARY );
35 return $dbw->newSelectQueryBuilder()
36 ->select( 'tgr_state' )
37 ->from( self::TABLE_NAME )
38 ->where( [
39 'tgr_group' => self::getGroupIdForDatabase( $group->getId() ),
40 'tgr_lang' => $code
41 ] )->fetchField();
42 }
43
45 public function changeState( MessageGroup $group, string $code, string $newState, User $user ): bool {
46 $currentState = $this->getState( $group, $code );
47 if ( $currentState === $newState ) {
48 return false;
49 }
50
51 $index = [ 'tgr_group', 'tgr_lang' ];
52 $row = [
53 'tgr_group' => self::getGroupIdForDatabase( $group->getId() ),
54 'tgr_lang' => $code,
55 'tgr_state' => $newState,
56 ];
57 $dbw = $this->loadBalancer->getConnection( DB_PRIMARY );
58 $dbw->replace( self::TABLE_NAME, [ $index ], $row, __METHOD__ );
59
60 $entry = new ManualLogEntry( 'translationreview', 'group' );
61 $entry->setPerformer( $user );
62 $entry->setTarget( SpecialPage::getTitleFor( 'Translate', $group->getId() ) );
63 $entry->setParameters( [
64 '4::language' => $code,
65 '5::group-label' => $group->getLabel(),
66 '6::old-state' => $currentState,
67 '7::new-state' => $newState,
68 ] );
69 // @todo
70 // $entry->setComment( $comment );
71
72 $logId = $entry->insert();
73 $entry->publish( $logId );
74
75 $this->hookRunner->onTranslateEventMessageGroupStateChange( $group, $code, $currentState, $newState );
76
77 return true;
78 }
79
80 public function getGroupPriority( string $group ): ?string {
81 $this->preloadGroupPriorities( __METHOD__ );
82 return $this->priorityCache[self::getGroupIdForDatabase( $group )] ?? null;
83 }
84
86 public function setGroupPriority( string $groupId, ?string $priority ): void {
87 $dbGroupId = self::getGroupIdForDatabase( $groupId );
88 if ( isset( $this->priorityCache ) ) {
89 $this->priorityCache[$dbGroupId] = $priority;
90 }
91
92 $dbw = $this->loadBalancer->getConnection( DB_PRIMARY );
93 $row = [
94 'tgr_group' => $dbGroupId,
95 'tgr_lang' => '*priority',
96 'tgr_state' => $priority
97 ];
98
99 if ( $priority === null ) {
100 unset( $row['tgr_state'] );
101 $dbw->delete( self::TABLE_NAME, $row, __METHOD__ );
102 } else {
103 $index = [ 'tgr_group', 'tgr_lang' ];
104 $dbw->replace( self::TABLE_NAME, [ $index ], $row, __METHOD__ );
105 }
106 }
107
108 private function preloadGroupPriorities( string $caller ): void {
109 if ( isset( $this->priorityCache ) ) {
110 return;
111 }
112
113 $dbr = $this->loadBalancer->getConnection( DB_REPLICA );
114 $res = $dbr->newSelectQueryBuilder()
115 ->select( [ 'tgr_group', 'tgr_state' ] )
116 ->from( self::TABLE_NAME )
117 ->where( [ 'tgr_lang' => '*priority' ] )
118 ->caller( $caller )
119 ->fetchResultSet();
120
121 $this->priorityCache = $this->result2map( $res, 'tgr_group', 'tgr_state' );
122 }
123
130 public function getWorkflowState( string $groupId, string $languageCode ): ?string {
131 $result = $this->getWorkflowStates( [ $groupId ], [ $languageCode ] );
132 return $result->fetchRow()['tgr_state'] ?? null;
133 }
134
135 public function getWorkflowStatesForLanguage( string $languageCode, array $groupIds ): array {
136 $result = $this->getWorkflowStates( $groupIds, [ $languageCode ] );
137 $states = $this->result2map( $result, 'tgr_group', 'tgr_state' );
138
139 $finalResult = [];
140 foreach ( $groupIds as $groupId ) {
141 $dbGroupId = self::getGroupIdForDatabase( $groupId );
142 if ( isset( $states[ $dbGroupId ] ) ) {
143 $finalResult[ $groupId ] = $states[ $dbGroupId ];
144 }
145 }
146
147 return $finalResult;
148 }
149
150 public function getWorkflowStatesForGroup( string $groupId ): array {
151 $result = $this->getWorkflowStates( [ $groupId ], null );
152 return $this->result2map( $result, 'tgr_lang', 'tgr_state' );
153 }
154
155 private function getWorkflowStates( ?array $groupIds, ?array $languageCodes ): IResultWrapper {
156 $dbr = $this->loadBalancer->getConnection( DB_REPLICA );
157 $conditions = array_filter(
158 [ 'tgr_group' => $groupIds, 'tgr_lang' => $languageCodes ],
159 static fn ( $x ) => $x !== null && $x !== ''
160 );
161
162 if ( $conditions === [] ) {
163 throw new InvalidArgumentException( 'Either the $groupId or the $languageCode should be provided' );
164 }
165
166 if ( isset( $conditions['tgr_group'] ) ) {
167 $conditions['tgr_group'] = array_map( [ self::class, 'getGroupIdForDatabase' ], $groupIds );
168 }
169
170 return $dbr->newSelectQueryBuilder()
171 ->select( [ 'tgr_state', 'tgr_group', 'tgr_lang' ] )
172 ->from( self::TABLE_NAME )
173 ->where( $conditions )
174 ->caller( __METHOD__ )
175 ->fetchResultSet();
176 }
177
178 private function result2map( IResultWrapper $result, string $keyValue, string $valueValue ): array {
179 $map = [];
180 foreach ( $result as $row ) {
181 $map[$row->$keyValue] = $row->$valueValue;
182 }
183
184 return $map;
185 }
186
187 private static function getGroupIdForDatabase( $groupId ): string {
188 $groupId = strval( $groupId );
189
190 // Check if length is more than 200 bytes
191 if ( strlen( $groupId ) <= 200 ) {
192 return $groupId;
193 }
194
195 // We take 160 bytes of the original string and append the md5 hash (32 bytes)
196 return mb_strcut( $groupId, 0, 160 ) . '||' . hash( 'md5', $groupId );
197 }
198}
Hook runner for the Translate extension.
Provides methods to get and change the state of a message group.
changeState(MessageGroup $group, string $code, string $newState, User $user)
getWorkflowState(string $groupId, string $languageCode)
Get the current workflow state for the given message group for the given language.
setGroupPriority(string $groupId, ?string $priority)
Store priority for message group.
Interface for message groups.
getId()
Returns the unique identifier for this group.
getLabel(IContextSource $context=null)
Returns the human readable label (as plain text).