Passed
Push — master ( 750c68...36913a )
by
unknown
02:38
created

DatabaseTermIdsAcquirer::mapToTextInLangIds()   B

Complexity

Conditions 7
Paths 16

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 8.4746
c 0
b 0
f 0
cc 7
nc 16
nop 1
1
<?php
2
3
namespace Wikibase\TermStore\MediaWiki\PackagePrivate;
4
5
use AppendIterator;
6
use ArrayIterator;
7
use Wikibase\TermStore\MediaWiki\PackagePrivate\Util\ReplicaMasterAwareRecordIdsAcquirer;
8
use Wikimedia\Rdbms\IDatabase;
9
10
class DatabaseTermIdsAcquirer implements TermIdsAcquirer {
11
12
	const TABLE_TEXT = 'wbt_text';
13
	const TABLE_TEXT_IN_LANG = 'wbt_text_in_lang';
14
	const TABLE_TERM_IN_LANG = 'wbt_term_in_lang';
15
16
	/**
17
	 * @var Database $dbw
18
	 */
19
	private $dbw;
20
21
	/**
22
	 * @var Database $dbr
23
	 */
24
	private $dbr;
25
26
	public function __construct(
27
		IDatabase $dbw,
28
		IDatabase $dbr,
29
		TypeIdsAcquirer $typeIdsAcquirer
30
	) {
31
		$this->dbw = $dbw;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dbw of type object<Wikimedia\Rdbms\IDatabase> is incompatible with the declared type object<Wikibase\TermStor...ackagePrivate\Database> of property $dbw.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
32
		$this->dbr = $dbr;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dbr of type object<Wikimedia\Rdbms\IDatabase> is incompatible with the declared type object<Wikibase\TermStor...ackagePrivate\Database> of property $dbr.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
33
		$this->typeIdsAcquirer = $typeIdsAcquirer;
0 ignored issues
show
Bug introduced by
The property typeIdsAcquirer does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
34
	}
35
36
	public function acquireTermIds( array $termsArray ): array {
37
		$termsArray = $this->mapToTextIds( $termsArray );
38
		$termsArray = $this->mapToTextInLangIds( $termsArray );
39
		$termsArray = $this->mapToTypeIds( $termsArray );
40
		return $this->mapToTermInLangIds( $termsArray );
41
	}
42
43
	/**
44
	 * replace root keys containing type names in termsArray
45
	 * with their respective ids in wbt_type table
46
	 *
47
	 * @param array $termsArray terms per type per language:
48
	 *	[
49
	 *		'type1' => [ ... ],
50
	 *		'type2' => [ ... ],
51
	 *		...
52
	 *	]
53
	 *
54
	 * @return array
55
	 *	[
56
	 *		<typeId1> => [ ... ],
57
	 *		<typeId2> => [ ... ],
58
	 *		...
59
	 *	]
60
	 */
61
	private function mapToTypeIds( array $termsArray ) {
62
		$typeIds = $this->typeIdsAcquirer->acquireTypeIds( array_keys( $termsArray ) );
63
64
		$termsArrayByTypeId = [];
65
		foreach ( $typeIds as $type => $typeId ) {
66
			$termsArrayByTypeId[$typeId] = $termsArray[$type];
67
		}
68
69
		return $termsArrayByTypeId;
70
	}
71
72
	/**
73
	 * replace text at termsArray leaves with their ids in wbt_text table
74
	 * and return resulting array
75
	 *
76
	 * @param array $termsArray terms per type per language:
77
	 *	[
78
	 *		'type' => [
79
	 *			[ 'language' => 'term' | [ 'term1', 'term2', ... ] ], ...
80
	 *		], ...
81
	 *	]
82
	 *
83
	 * @return array
84
	 *	[
85
	 *		'type' => [
86
	 *			[ 'language' => [ <textId1>, <textId2>, ... ] ], ...
87
	 *		], ...
88
	 *	]
89
	 */
90
	private function mapToTextIds( array $termsArray ) {
91
		$texts = [];
92
93
		array_walk_recursive( $termsArray, function ( $text ) use ( &$texts ) {
94
			$texts[] = $text;
95
		} );
96
97
		$textIds = $this->acquireTextIds( $texts );
98
99
		array_walk_recursive( $termsArray, function ( &$text ) use ( $textIds ) {
100
			$text = $textIds[$text];
101
		} );
102
103
		return $termsArray;
104
	}
105
106
	private function acquireTextIds( array $texts ) {
107
		$textIdsAcquirer = new ReplicaMasterAwareRecordIdsAcquirer(
108
			$this->dbw, $this->dbr, 'wbt_text', 'wbx_id' );
109
110
		$textRecords = [];
111
		foreach ( $texts as $text ) {
112
			$textRecords[] = [ 'wbx_text' => $text ];
113
		}
114
115
		$acquiredIds = $textIdsAcquirer->acquireIds( $textRecords );
116
117
		$textIds = [];
118
		foreach ( $acquiredIds as $acquiredId ) {
119
			$textIds[$acquiredId['wbx_text']] = $acquiredId['wbx_id'];
120
		}
121
122
		return $textIds;
123
	}
124
125
	/**
126
	 * replace ( lang => [ textId, ... ] ) entries with their respective ids
127
	 * in wbt_text_in_lang table and return resulting array
128
	 *
129
	 * @param array $termsArray text ids per type per langauge
130
	 *	[
131
	 *		'type' => [
132
	 *			[ 'language' => [ <textId1>, <textId2>, ... ] ], ...
133
	 *		], ...
134
	 *	]
135
	 *
136
	 * @return array
137
	 *	[
138
	 *		'type' => [ <textInLangId1>, <textInLangId2>, ... ],
139
	 *		...
140
	 *	]
141
	 */
142
	private function mapToTextInLangIds( array $termsArray ) {
143
		$flattenedLangTextIds = [];
144
		foreach ( $termsArray as $langTextIds ) {
145
			foreach ( $langTextIds as $lang => $textIds ) {
146
				if ( !isset( $flattenedLangTextIds[$lang] ) ) {
147
					$flattenedLangTextIds[$lang] = [];
148
				}
149
150
				$flattenedLangTextIds[$lang] = array_unique(
151
					array_merge(
152
						(array)$textIds,
153
						(array)$flattenedLangTextIds[$lang]
154
					)
155
				);
156
157
			}
158
		}
159
160
		$textInLangIds = $this->acquireTextInLangIds( $flattenedLangTextIds );
161
162
		$newTermsArray = [];
163
		foreach ( $termsArray as $type => $langTextIds ) {
164
			$newTermsArray[$type] = [];
165
			foreach ( $langTextIds as $lang => $textIds ) {
166
				foreach ( (array)$textIds as $textId ) {
167
					$newTermsArray[$type][] = $textInLangIds[$lang][$textId];
168
				}
169
			}
170
		}
171
172
		return $newTermsArray;
173
	}
174
175
	private function acquireTextInLangIds( array $langTextIds ) {
176
		$textInLangIdsAcquirer = new ReplicaMasterAwareRecordIdsAcquirer(
177
			$this->dbw, $this->dbr, 'wbt_text_in_lang', 'wbxl_id' );
178
179
		$textInLangRecords = [];
180
		foreach ( $langTextIds as $lang => $textIds ) {
181
			foreach ( $textIds as $textId ) {
182
				$textInLangRecords[] = [ 'wbxl_text_id' => $textId, 'wbxl_language' => $lang ];
183
			}
184
		}
185
186
		$acquiredIds = $textInLangIdsAcquirer->acquireIds( $textInLangRecords );
187
188
		$textInLangIds = [];
189
		foreach ( $acquiredIds as $acquiredId ) {
190
			$textInLangIds[$acquiredId['wbxl_language']][$acquiredId['wbxl_text_id']]
191
				= $acquiredId['wbxl_id'];
192
		}
193
194
		return $textInLangIds;
195
	}
196
197
	/**
198
	 * replace root ( type => [ textInLangId, ... ] ) entries with their respective ids
199
	 * in wbt_term_in_lang table and return resulting array
200
	 *
201
	 * @param array $termsArray text in lang ids per type
202
	 *	[
203
	 *		'type' => [ <textInLangId1>, <textInLangId2>, ... ],
204
	 *		...
205
	 *	]
206
	 *
207
	 * @return array
208
	 *	[
209
	 *		<termInLang1>,
210
	 *		<termInLang2>,
211
	 *		...
212
	 *	]
213
	 */
214
	private function mapToTermInLangIds( array $termsArray ) {
215
		$flattenedTypeTextInLangIds = [];
216
		foreach ( $termsArray as $typeId => $textInLangIds ) {
217
			if ( !isset( $flattenedTypeTextInLangIds[$typeId] ) ) {
218
				$flattenedTypeTextInLangIds[$typeId] = [];
219
			}
220
221
			$flattenedTypeTextInLangIds[$typeId] = array_unique(
222
				array_merge(
223
					(array)$textInLangIds,
224
					(array)$flattenedTypeTextInLangIds[$typeId]
225
				)
226
			);
227
		}
228
229
		$termInLangIds = $this->acquireTermInLangIds( $flattenedTypeTextInLangIds );
230
231
		$newTermsArray = [];
232
		foreach ( $termsArray as $typeId => $textInLangIds ) {
233
			foreach ( $textInLangIds as $textInLangId ) {
234
				$newTermsArray[] = $termInLangIds[$typeId][$textInLangId];
235
			}
236
		}
237
238
		return $newTermsArray;
239
	}
240
241
	private function acquireTermInLangIds( array $typeTextInLangIds ) {
242
		$termInLangIdsAcquirer = new ReplicaMasterAwareRecordIdsAcquirer(
243
			$this->dbw, $this->dbr, 'wbt_term_in_lang', 'wbtl_id' );
244
245
		$termInLangRecords = [];
246
		foreach ( $typeTextInLangIds as $typeId => $textInLangIds ) {
247
			foreach ( $textInLangIds as $textInLangId ) {
248
				$termInLangRecords[] = [
249
					'wbtl_text_in_lang_id' => $textInLangId,
250
					'wbtl_type_id' => (string)$typeId
251
				];
252
			}
253
		}
254
255
		$acquiredIds = $termInLangIdsAcquirer->acquireIds( $termInLangRecords );
256
257
		$termInLangIds = [];
258
		foreach ( $acquiredIds as $acquiredId ) {
259
			$termInLangIds[$acquiredId['wbtl_type_id']][$acquiredId['wbtl_text_in_lang_id']]
260
				= $acquiredId['wbtl_id'];
261
		}
262
263
		return $termInLangIds;
264
	}
265
266
}
267