Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
RevTagStore.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\MessageGroupProcessing;
5
7use MediaWiki\Page\PageIdentity;
8use Wikimedia\Rdbms\IConnectionProvider;
9use Wikimedia\Rdbms\SelectQueryBuilder;
10
20 public const FUZZY_TAG = 'fuzzy';
22 public const TRANSVER_PROP = 'tp:transver';
24 public const TP_MARK_TAG = 'tp:mark';
26 public const TP_READY_TAG = 'tp:tag';
28 public const MB_VALID_TAG = 'mb:valid';
29
30 private IConnectionProvider $dbProvider;
31 private array $tagCache = [];
32
33 public function __construct( IConnectionProvider $dbProvider ) {
34 $this->dbProvider = $dbProvider;
35 }
36
38 public function replaceTag(
39 PageIdentity $identity,
40 string $tag,
41 int $revisionId,
42 ?array $value = null
43 ): void {
44 if ( !$identity->exists() ) {
45 return;
46 }
47
48 $articleId = $identity->getId();
49
50 $dbw = $this->dbProvider->getPrimaryDatabase();
51 $conditions = [
52 'rt_page' => $articleId,
53 'rt_type' => $tag
54 ];
55 $dbw->newDeleteQueryBuilder()
56 ->deleteFrom( 'revtag' )
57 ->where( $conditions )
58 ->caller( __METHOD__ )
59 ->execute();
60
61 if ( $value !== null ) {
62 $conditions['rt_value'] = serialize( implode( '|', $value ) );
63 }
64
65 $conditions['rt_revision'] = $revisionId;
66 $dbw->newInsertQueryBuilder()
67 ->insertInto( 'revtag' )
68 ->row( $conditions )
69 ->caller( __METHOD__ )
70 ->execute();
71
72 $this->tagCache[$articleId][$tag] = $revisionId;
73 }
74
75 public function getLatestRevisionWithTag( PageIdentity $identity, string $tag ): ?int {
76 $response = $this->getLatestRevisionsForTags( $identity, $tag );
77 return $response[$tag] ?? null;
78 }
79
81 public function getLatestRevisionsForTags( PageIdentity $identity, string ...$tags ): ?array {
82 if ( !$identity->exists() ) {
83 return null;
84 }
85
86 $articleId = $identity->getId();
87
88 $response = [];
89 $remainingTags = [];
90
91 // ATTENTION: Cache should only be updated on POST requests.
92 foreach ( $tags as $tag ) {
93 if ( isset( $this->tagCache[$articleId][$tag] ) ) {
94 $response[$tag] = $this->tagCache[$articleId][$tag];
95 } else {
96 $remainingTags[] = $tag;
97 }
98 }
99
100 if ( !$remainingTags ) {
101 // All tags were available in the cache, no need to run any queries.
102 return $response;
103 }
104
105 $dbr = Utilities::getSafeReadDB();
106 $results = $dbr->newSelectQueryBuilder()
107 ->select( [ 'rt_revision' => 'MAX(rt_revision)', 'rt_type' ] )
108 ->from( 'revtag' )
109 ->where( [
110 'rt_page' => $articleId,
111 'rt_type' => $remainingTags
112 ] )
113 ->groupBy( 'rt_type' )
114 ->caller( __METHOD__ )
115 ->fetchResultSet();
116
117 foreach ( $results as $row ) {
118 $response[$row->rt_type] = (int)$row->rt_revision;
119 }
120
121 return $response;
122 }
123
124 public function removeTags( PageIdentity $identity, string ...$tag ): void {
125 if ( !$identity->exists() ) {
126 return;
127 }
128
129 $articleId = $identity->getId();
130
131 $dbw = $this->dbProvider->getPrimaryDatabase();
132 $dbw->newDeleteQueryBuilder()
133 ->deleteFrom( 'revtag' )
134 ->where( [
135 'rt_page' => $articleId,
136 'rt_type' => $tag,
137 ] )
138 ->caller( __METHOD__ )
139 ->execute();
140
141 unset( $this->tagCache[$articleId] );
142 }
143
144 public function isRevIdFuzzy( int $articleId, int $revisionId ): bool {
145 $dbw = $this->dbProvider->getPrimaryDatabase();
146 $res = $dbw->newSelectQueryBuilder()
147 ->select( 'rt_type' )
148 ->from( 'revtag' )
149 ->where( [
150 'rt_page' => $articleId,
151 'rt_type' => self::FUZZY_TAG,
152 'rt_revision' => $revisionId
153 ] )
154 ->caller( __METHOD__ )
155 ->fetchField();
156
157 return $res !== false;
158 }
159
172 public function getTransver( PageIdentity $identity, ?int $revid = null ): ?int {
173 $db = Utilities::getSafeReadDB();
174 $query = $db->newSelectQueryBuilder()
175 ->select( 'rt_value' )
176 ->from( 'revtag' )
177 ->where( [
178 'rt_page' => $identity->getId(),
179 'rt_type' => self::TRANSVER_PROP,
180 ] );
181 if ( $revid !== null ) {
182 $query->where( $db->expr( 'rt_revision', '<=', $revid ) );
183 }
184 $result = $query
185 ->orderBy( 'rt_revision', SelectQueryBuilder::SORT_DESC )
186 ->caller( __METHOD__ )
187 ->fetchField();
188 if ( $result === false ) {
189 return null;
190 } else {
191 // The revtag database is defined to store a string in rt_value,
192 // but tp:transver is always an integer
193 return (int)$result;
194 }
195 }
196
205 public function setTransver( PageIdentity $identity, int $translationRevision, int $transver ) {
206 $dbw = $this->dbProvider->getPrimaryDatabase();
207
208 $conds = [
209 'rt_page' => $identity->getId(),
210 'rt_type' => self::TRANSVER_PROP,
211 'rt_revision' => $translationRevision,
212 'rt_value' => $transver,
213 ];
214 $dbw->newReplaceQueryBuilder()
215 ->replaceInto( 'revtag' )
216 ->uniqueIndexFields( [ 'rt_type', 'rt_page', 'rt_revision' ] )
217 ->row( $conds )
218 ->caller( __METHOD__ )
219 ->execute();
220 }
221
223 public static function getTranslatableBundleIds( string ...$revTags ): array {
224 $dbr = Utilities::getSafeReadDB();
225 $res = $dbr->newSelectQueryBuilder()
226 ->select( 'rt_page' )
227 ->from( 'revtag' )
228 ->join(
229 'page',
230 null,
231 [ 'rt_page = page_id', 'rt_revision = page_latest', 'rt_type' => $revTags ]
232 )
233 ->groupBy( 'rt_page' )
234 ->caller( __METHOD__ )
235 ->fetchResultSet();
236 $results = [];
237 foreach ( $res as $row ) {
238 $results[] = (int)$row->rt_page;
239 }
240
241 return $results;
242 }
243}
Class to manage revision tags for translatable bundles.
getTransver(PageIdentity $identity, ?int $revid=null)
Get the revision ID of the original message that was live the last time a non-fuzzy translation was s...
const TRANSVER_PROP
Stores the revision id of the corresponding source text.
const MB_VALID_TAG
Indicates a revision of a page that is a valid message bundle.
const FUZZY_TAG
Indicates that a translation is fuzzy (outdated or not passing validation).
static getTranslatableBundleIds(string ... $revTags)
Get a list of page ids where the latest revision is either tagged or marked.
setTransver(PageIdentity $identity, int $translationRevision, int $transver)
Sets the tp:transver revtag of the given page/revision.
replaceTag(PageIdentity $identity, string $tag, int $revisionId, ?array $value=null)
Add tag for the given revisionId, while deleting it from others.
const TP_READY_TAG
Indicates a revision of a translatable page that is marked for translation.
const TP_MARK_TAG
Indicates a revision of a page that can be marked for translation.
getLatestRevisionsForTags(PageIdentity $identity, string ... $tags)
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Definition Utilities.php:29