Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 65 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
CategoriesStorageManager | |
0.00% |
0 / 65 |
|
0.00% |
0 / 4 |
110 | |
0.00% |
0 / 1 |
update | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
create | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
20 | |||
save | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
exists | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Storage manager for source and target categories in cx_corpora table. cx_corpora was initially |
4 | * used to store pairs of source and target (translated) sections, but extended to store pairs |
5 | * of source and target category lists, which utilize special section ID of 'CX_CATEGORY_METADATA'. |
6 | * |
7 | * @copyright See AUTHORS.txt |
8 | * @license GPL-2.0-or-later |
9 | */ |
10 | |
11 | namespace ContentTranslation; |
12 | |
13 | use MediaWiki\MediaWikiServices; |
14 | use Wikimedia\Rdbms\IDatabase; |
15 | |
16 | class CategoriesStorageManager { |
17 | private const TYPE_SOURCE = 'source'; |
18 | private const TYPE_USER = 'user'; |
19 | |
20 | private const CATEGORIES_SECTION = [ |
21 | 'cxc_section_id' => 'CX_CATEGORY_METADATA' |
22 | ]; |
23 | |
24 | /** |
25 | * Update source or target categories. Since API doesn't require source nor target categories |
26 | * while performing saving of a draft, if $categories isn't provided, do nothing. |
27 | * |
28 | * @param IDatabase $db |
29 | * @param int $translationId |
30 | * @param string $categories |
31 | * @param string $origin TYPE_SOURCE or TYPE_USER. Defaults to TYPE_USER |
32 | */ |
33 | private static function update( |
34 | IDatabase $db, $translationId, $categories, $origin = self::TYPE_USER |
35 | ) { |
36 | if ( !$categories ) { |
37 | return; |
38 | } |
39 | |
40 | $values = [ |
41 | 'cxc_timestamp' => $db->timestamp(), |
42 | 'cxc_content' => $categories |
43 | ]; |
44 | $conditions = [ |
45 | 'cxc_translation_id' => $translationId, |
46 | 'cxc_origin' => $origin |
47 | ] + self::CATEGORIES_SECTION; |
48 | |
49 | $db->newUpdateQueryBuilder() |
50 | ->update( 'cx_corpora' ) |
51 | ->set( $values ) |
52 | ->where( $conditions ) |
53 | ->caller( __METHOD__ ) |
54 | ->execute(); |
55 | } |
56 | |
57 | /** |
58 | * Insert source and target category list for the given translation identifier. |
59 | * |
60 | * @param IDatabase $db |
61 | * @param int $translationId |
62 | * @param string $sourceCategories |
63 | * @param string $targetCategories |
64 | */ |
65 | private static function create( |
66 | IDatabase $db, $translationId, $sourceCategories, $targetCategories |
67 | ) { |
68 | $values = []; |
69 | $commonValues = [ |
70 | 'cxc_translation_id' => $translationId, |
71 | 'cxc_timestamp' => $db->timestamp() |
72 | ] + self::CATEGORIES_SECTION; |
73 | |
74 | if ( $targetCategories ) { |
75 | $values[] = [ |
76 | 'cxc_origin' => self::TYPE_USER, |
77 | 'cxc_content' => $targetCategories |
78 | ] + $commonValues; |
79 | } |
80 | |
81 | if ( $sourceCategories ) { |
82 | $values[] = [ |
83 | 'cxc_origin' => self::TYPE_SOURCE, |
84 | 'cxc_content' => $sourceCategories |
85 | ] + $commonValues; |
86 | } |
87 | |
88 | if ( $values !== [] ) { |
89 | $db->newInsertQueryBuilder() |
90 | ->insertInto( 'cx_corpora' ) |
91 | ->rows( $values ) |
92 | ->caller( __METHOD__ ) |
93 | ->execute(); |
94 | } |
95 | } |
96 | |
97 | /** |
98 | * Save the source and target category list. |
99 | * If the records exists, update them, otherwise create. |
100 | * |
101 | * @param int $translationId |
102 | * @param string $sourceCategories |
103 | * @param string $targetCategories |
104 | * @param bool $newTranslation Whether these are for a brand new Translation record |
105 | */ |
106 | public static function save( |
107 | $translationId, $sourceCategories, $targetCategories, $newTranslation |
108 | ) { |
109 | /** @var LoadBalancer $lb */ |
110 | $lb = MediaWikiServices::getInstance()->getService( 'ContentTranslation.LoadBalancer' ); |
111 | $db = $lb->getConnection( DB_PRIMARY ); |
112 | |
113 | $db->doAtomicSection( |
114 | __METHOD__, |
115 | function ( IDatabase $db ) use ( |
116 | $translationId, $sourceCategories, $targetCategories, $newTranslation |
117 | ) { |
118 | if ( $newTranslation ) { |
119 | $existing = false; |
120 | } else { |
121 | $existing = self::exists( $translationId ); |
122 | } |
123 | |
124 | if ( $existing ) { |
125 | self::update( $db, $translationId, $sourceCategories, self::TYPE_SOURCE ); |
126 | self::update( $db, $translationId, $targetCategories ); |
127 | } else { |
128 | self::create( $db, $translationId, $sourceCategories, $targetCategories ); |
129 | } |
130 | } |
131 | ); |
132 | } |
133 | |
134 | /** |
135 | * Find if there are records about source and target categories. |
136 | * |
137 | * @param int $translationId |
138 | * @return bool |
139 | */ |
140 | private static function exists( $translationId ) { |
141 | /** @var LoadBalancer $lb */ |
142 | $lb = MediaWikiServices::getInstance()->getService( 'ContentTranslation.LoadBalancer' ); |
143 | $db = $lb->getConnection( DB_PRIMARY ); |
144 | |
145 | $result = $db->newSelectQueryBuilder() |
146 | ->select( 'cxc_content' ) |
147 | ->from( 'cx_corpora' ) |
148 | ->where( [ 'cxc_translation_id' => $translationId ] ) |
149 | ->andWhere( self::CATEGORIES_SECTION ) |
150 | ->forUpdate() |
151 | ->caller( __METHOD__ ) |
152 | ->fetchResultSet(); |
153 | |
154 | return $result->numRows() > 0; |
155 | } |
156 | } |