getEntityModuleName()   A
last analyzed

Complexity

Conditions 2
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 2
nc 4
nop 1
1
<?php
2
3
namespace Wikibase\Client\DataAccess\Scribunto;
4
5
use Deserializers\Exceptions\DeserializationException;
6
use Exception;
7
use Language;
8
use MediaWiki\MediaWikiServices;
9
use Scribunto_LuaError;
10
use Scribunto_LuaLibraryBase;
11
use ScribuntoException;
12
use Wikibase\Client\DataAccess\DataAccessSnakFormatterFactory;
13
use Wikibase\Client\DataAccess\PropertyIdResolver;
14
use Wikibase\Client\PropertyLabelNotResolvedException;
15
use Wikibase\Client\RepoLinker;
16
use Wikibase\Client\Usage\EntityUsageFactory;
17
use Wikibase\Client\Usage\ParserOutputUsageAccumulator;
18
use Wikibase\Client\Usage\UsageTrackingLanguageFallbackLabelDescriptionLookup;
19
use Wikibase\Client\WikibaseClient;
20
use Wikibase\DataModel\Entity\EntityId;
21
use Wikibase\DataModel\Entity\EntityIdParser;
22
use Wikibase\DataModel\Entity\EntityIdParsingException;
23
use Wikibase\DataModel\Entity\PropertyId;
24
use Wikibase\DataModel\Services\Lookup\EntityAccessLimitException;
25
use Wikibase\DataModel\Services\Lookup\EntityRetrievingClosestReferencedEntityIdLookup;
26
use Wikibase\Lib\Store\CachingFallbackLabelDescriptionLookup;
27
use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookup;
28
use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory;
29
use Wikibase\Lib\Store\PropertyOrderProvider;
30
use Wikibase\Lib\Store\RedirectResolvingLatestRevisionLookup;
31
use Wikibase\Lib\TermLanguageFallbackChain;
32
33
/**
34
 * Registers and defines functions to access Wikibase through the Scribunto extension
35
 *
36
 * @license GPL-2.0-or-later
37
 */
38
class Scribunto_LuaWikibaseLibrary extends Scribunto_LuaLibraryBase {
39
40
	/**
41
	 * @var WikibaseLanguageIndependentLuaBindings|null
42
	 */
43
	private $languageIndependentLuaBindings = null;
44
45
	/**
46
	 * @var WikibaseLanguageDependentLuaBindings|null
47
	 */
48
	private $languageDependentLuaBindings = null;
49
50
	/**
51
	 * @var EntityAccessor|null
52
	 */
53
	private $entityAccessor = null;
54
55
	/**
56
	 * @var SnakSerializationRenderer[]
57
	 */
58
	private $snakSerializationRenderers = [];
59
60
	/**
61
	 * @var TermLanguageFallbackChain|null
62
	 */
63
	private $termFallbackChain = null;
64
65
	/**
66
	 * @var ParserOutputUsageAccumulator|null
67
	 */
68
	private $usageAccumulator = null;
69
70
	/**
71
	 * @var PropertyIdResolver|null
72
	 */
73
	private $propertyIdResolver = null;
74
75
	/**
76
	 * @var PropertyOrderProvider|null
77
	 */
78
	private $propertyOrderProvider = null;
79
80
	/**
81
	 * @var EntityIdParser|null
82
	 */
83
	private $entityIdParser = null;
84
85
	/**
86
	 * @var RepoLinker|null
87
	 */
88
	private $repoLinker = null;
89
90
	/**
91
	 * @var LuaFunctionCallTracker|null
92
	 */
93
	private $luaFunctionCallTracker = null;
94
95
	/**
96
	 * @var string[]|null
97
	 */
98
	private $luaEntityModules = null;
99
100
	/**
101
	 * @return WikibaseLanguageIndependentLuaBindings
102
	 */
103
	private function getLanguageIndependentLuaBindings() {
104
		if ( $this->languageIndependentLuaBindings === null ) {
105
			$this->languageIndependentLuaBindings = $this->newLanguageIndependentLuaBindings();
106
		}
107
108
		return $this->languageIndependentLuaBindings;
109
	}
110
111
	/**
112
	 * @return WikibaseLanguageDependentLuaBindings
113
	 */
114
	private function getLanguageDependentLuaBindings() {
115
		if ( $this->languageDependentLuaBindings === null ) {
116
			$this->languageDependentLuaBindings = $this->newLanguageDependentLuaBindings();
117
		}
118
119
		return $this->languageDependentLuaBindings;
120
	}
121
122
	/**
123
	 * @return EntityAccessor
124
	 */
125
	private function getEntityAccessor() {
126
		if ( $this->entityAccessor === null ) {
127
			$this->entityAccessor = $this->newEntityAccessor();
128
		}
129
130
		return $this->entityAccessor;
131
	}
132
133
	/**
134
	 * @param string $type One of DataAccessSnakFormatterFactory::TYPE_*
135
	 *
136
	 * @return SnakSerializationRenderer
137
	 */
138
	private function getSnakSerializationRenderer( $type ) {
139
		if ( !array_key_exists( $type, $this->snakSerializationRenderers ) ) {
140
			$this->snakSerializationRenderers[$type] = $this->newSnakSerializationRenderer( $type );
141
		}
142
143
		return $this->snakSerializationRenderers[$type];
144
	}
145
146
	/**
147
	 * @return TermLanguageFallbackChain
148
	 */
149
	private function getLanguageFallbackChain() {
150
		if ( $this->termFallbackChain === null ) {
151
			$this->termFallbackChain = WikibaseClient::getDefaultInstance()->
152
				getDataAccessLanguageFallbackChain( $this->getLanguage() );
153
		}
154
155
		return $this->termFallbackChain;
156
	}
157
158
	/**
159
	 * @return ParserOutputUsageAccumulator
160
	 */
161
	public function getUsageAccumulator() {
162
		if ( $this->usageAccumulator === null ) {
163
			$parserOutput = $this->getParser()->getOutput();
164
			$this->usageAccumulator = new ParserOutputUsageAccumulator(
165
				$parserOutput,
166
				new EntityUsageFactory( WikibaseClient::getDefaultInstance()->getEntityIdParser() )
167
			);
168
		}
169
170
		return $this->usageAccumulator;
171
	}
172
173
	/**
174
	 * @return PropertyIdResolver
175
	 */
176
	private function getPropertyIdResolver() {
177
		if ( $this->propertyIdResolver === null ) {
178
			$wikibaseClient = WikibaseClient::getDefaultInstance();
179
			$entityLookup = $wikibaseClient->getStore()->getEntityLookup();
180
			$propertyLabelResolver = $wikibaseClient->getPropertyLabelResolver();
181
182
			$this->propertyIdResolver = new PropertyIdResolver(
183
				$entityLookup,
184
				$propertyLabelResolver,
185
				$this->getUsageAccumulator()
186
			);
187
		}
188
189
		return $this->propertyIdResolver;
190
	}
191
192
	/**
193
	 * Returns the language to use. If we are on a multilingual wiki
194
	 * (allowDataAccessInUserLanguage is true) this will be the user's interface
195
	 * language, otherwise it will be the content language.
196
	 * In a perfect world, this would equal Parser::getTargetLanguage.
197
	 *
198
	 * This can probably be removed after T114640 has been implemented.
199
	 *
200
	 * Please note, that this splits the parser cache by user language, if
201
	 * allowDataAccessInUserLanguage is true.
202
	 *
203
	 * @return Language
204
	 */
205
	private function getLanguage() {
206
		if ( $this->allowDataAccessInUserLanguage() ) {
207
			return $this->getParserOptions()->getUserLangObj();
208
		}
209
210
		return MediaWikiServices::getInstance()->getContentLanguage();
211
	}
212
213
	/**
214
	 * @return LuaFunctionCallTracker
215
	 */
216
	private function getLuaFunctionCallTracker() {
217
		if ( !$this->luaFunctionCallTracker ) {
218
			$mwServices = MediaWikiServices::getInstance();
219
			$wikibaseClient = WikibaseClient::getDefaultInstance();
220
			$settings = $wikibaseClient->getSettings();
221
222
			$this->luaFunctionCallTracker = new LuaFunctionCallTracker(
223
				$mwServices->getStatsdDataFactory(),
224
				$settings->getSetting( 'siteGlobalID' ),
225
				$wikibaseClient->getSiteGroup(),
226
				$settings->getSetting( 'trackLuaFunctionCallsPerSiteGroup' ),
227
				$settings->getSetting( 'trackLuaFunctionCallsPerWiki' )
228
			);
229
		}
230
231
		return $this->luaFunctionCallTracker;
232
	}
233
234
	/**
235
	 * @return bool
236
	 */
237
	private function allowDataAccessInUserLanguage() {
238
		$settings = WikibaseClient::getDefaultInstance()->getSettings();
239
240
		return $settings->getSetting( 'allowDataAccessInUserLanguage' );
241
	}
242
243
	private function newEntityAccessor() {
244
		$wikibaseClient = WikibaseClient::getDefaultInstance();
245
		$settings = $wikibaseClient->getSettings();
246
		return new EntityAccessor(
247
			$this->getEntityIdParser(),
248
			$wikibaseClient->getRestrictedEntityLookup(),
249
			$this->getUsageAccumulator(),
250
			$wikibaseClient->getCompactEntitySerializer(),
251
			$wikibaseClient->getCompactBaseDataModelSerializerFactory()->newStatementListSerializer(),
252
			$wikibaseClient->getPropertyDataTypeLookup(),
253
			$this->getLanguageFallbackChain(),
254
			$this->getLanguage(),
255
			$wikibaseClient->getTermsLanguages(),
256
			$settings->getSetting( 'fineGrainedLuaTracking' ),
257
			$wikibaseClient->getLogger()
258
		);
259
	}
260
261
	/**
262
	 * @param string $type One of DataAccessSnakFormatterFactory::TYPE_*
263
	 *
264
	 * @return SnakSerializationRenderer
265
	 */
266
	private function newSnakSerializationRenderer( $type ) {
267
		$wikibaseClient = WikibaseClient::getDefaultInstance();
268
269
		$snakFormatterFactory = $wikibaseClient->getDataAccessSnakFormatterFactory();
270
		$snakFormatter = $snakFormatterFactory->newWikitextSnakFormatter(
271
			$this->getLanguage(),
272
			$this->getUsageAccumulator(),
273
			$type
274
		);
275
		if ( $type === DataAccessSnakFormatterFactory::TYPE_RICH_WIKITEXT ) {
276
			// As Scribunto doesn't strip parser tags (like <mapframe>) itself,
277
			// we need to take care of that.
278
			$snakFormatter = new WikitextPreprocessingSnakFormatter(
279
				$snakFormatter,
280
				$this->getParser()
281
			);
282
		}
283
284
		$snakDeserializer = $wikibaseClient->getBaseDataModelDeserializerFactory()->newSnakDeserializer();
285
		$snaksDeserializer = $wikibaseClient->getBaseDataModelDeserializerFactory()->newSnakListDeserializer();
286
287
		return new SnakSerializationRenderer(
288
			$snakFormatter,
289
			$snakDeserializer,
290
			$this->getLanguage(),
291
			$snaksDeserializer
292
		);
293
	}
294
295
	private function newLanguageDependentLuaBindings() {
296
		$wikibaseClient = WikibaseClient::getDefaultInstance();
297
298
		$nonCachingLookup = new LanguageFallbackLabelDescriptionLookup(
299
			$wikibaseClient->getTermLookup(),
300
			$this->getLanguageFallbackChain()
301
		);
302
303
		$labelDescriptionLookup = new CachingFallbackLabelDescriptionLookup(
304
			$wikibaseClient->getTermFallbackCache(),
305
			new RedirectResolvingLatestRevisionLookup( $wikibaseClient->getStore()->getEntityRevisionLookup() ),
306
			$nonCachingLookup,
307
			$this->getLanguageFallbackChain()
308
		);
309
310
		$usageTrackingLabelDescriptionLookup = new UsageTrackingLanguageFallbackLabelDescriptionLookup(
311
			$labelDescriptionLookup,
312
			$this->getUsageAccumulator(),
313
			$this->getLanguageFallbackChain(),
314
			$this->allowDataAccessInUserLanguage()
315
		);
316
317
		return new WikibaseLanguageDependentLuaBindings(
318
			$this->getEntityIdParser(),
319
			$usageTrackingLabelDescriptionLookup
320
		);
321
	}
322
323
	private function newLanguageIndependentLuaBindings() {
324
		$mediaWikiServices = MediaWikiServices::getInstance();
325
		$wikibaseClient = WikibaseClient::getDefaultInstance();
326
		$settings = $wikibaseClient->getSettings();
327
328
		$termLookup = new CachingFallbackBasedTermLookup(
329
			$wikibaseClient->getTermFallbackCache(),
330
			new RedirectResolvingLatestRevisionLookup( $wikibaseClient->getStore()->getEntityRevisionLookup() ),
331
			new LanguageFallbackLabelDescriptionLookupFactory(
332
				$wikibaseClient->getLanguageFallbackChainFactory(),
333
				$wikibaseClient->getTermLookup()
334
			),
335
			$mediaWikiServices->getLanguageFactory(),
336
			$wikibaseClient->getTermsLanguages()
337
		);
338
339
		return new WikibaseLanguageIndependentLuaBindings(
340
			$wikibaseClient->getStore()->getSiteLinkLookup(),
341
			$wikibaseClient->getEntityIdLookup(),
342
			$settings,
343
			$this->getUsageAccumulator(),
344
			$this->getEntityIdParser(),
345
			$termLookup,
346
			$wikibaseClient->getTermsLanguages(),
347
			new EntityRetrievingClosestReferencedEntityIdLookup(
348
				$wikibaseClient->getStore()->getEntityLookup(),
349
				$wikibaseClient->getStore()->getEntityPrefetcher(),
350
				$settings->getSetting( 'referencedEntityIdMaxDepth' ),
351
				$settings->getSetting( 'referencedEntityIdMaxReferencedEntityVisits' )
352
			),
353
			$mediaWikiServices->getTitleFormatter(),
354
			$mediaWikiServices->getTitleParser(),
355
			$settings->getSetting( 'siteGlobalID' )
356
		);
357
	}
358
359
	/**
360
	 * @return EntityIdParser
361
	 */
362
	private function getEntityIdParser() {
363
		if ( !$this->entityIdParser ) {
364
			$wikibaseClient = WikibaseClient::getDefaultInstance();
365
			$this->entityIdParser = $wikibaseClient->getEntityIdParser();
366
		}
367
		return $this->entityIdParser;
368
	}
369
370
	/**
371
	 * @throws \ScribuntoException
372
	 * @return EntityId
373
	 */
374
	private function parseUserGivenEntityId( $idSerialization ) {
375
		try {
376
			return $this->getEntityIdParser()->parse( $idSerialization );
377
		} catch ( EntityIdParsingException $ex ) {
378
			throw new ScribuntoException(
379
				'wikibase-error-invalid-entity-id',
380
				[ 'args' => [ $idSerialization ] ]
381
			);
382
		}
383
	}
384
385
	/**
386
	 * Register mw.wikibase.lua library
387
	 *
388
	 * @return array
389
	 */
390
	public function register() {
391
		// These functions will be exposed to the Lua module.
392
		// They are member functions on a Lua table which is private to the module, thus
393
		// these can't be called from user code, unless explicitly exposed in Lua.
394
		$lib = [
395
			'getLabel' => [ $this, 'getLabel' ],
396
			'getLabelByLanguage' => [ $this, 'getLabelByLanguage' ],
397
			'getEntity' => [ $this, 'getEntity' ],
398
			'entityExists' => [ $this, 'entityExists' ],
399
			'getEntityStatements' => [ $this, 'getEntityStatements' ],
400
			'getSetting' => [ $this, 'getSetting' ],
401
			'getEntityUrl' => [ $this, 'getEntityUrl' ],
402
			'renderSnak' => [ $this, 'renderSnak' ],
403
			'formatValue' => [ $this, 'formatValue' ],
404
			'renderSnaks' => [ $this, 'renderSnaks' ],
405
			'formatValues' => [ $this, 'formatValues' ],
406
			'getEntityId' => [ $this, 'getEntityId' ],
407
			'getReferencedEntityId' => [ $this, 'getReferencedEntityId' ],
408
			'getUserLang' => [ $this, 'getUserLang' ],
409
			'getDescription' => [ $this, 'getDescription' ],
410
			'resolvePropertyId' => [ $this, 'resolvePropertyId' ],
411
			'getSiteLinkPageName' => [ $this, 'getSiteLinkPageName' ],
412
			'incrementExpensiveFunctionCount' => [ $this, 'incrementExpensiveFunctionCount' ],
413
			'isValidEntityId' => [ $this, 'isValidEntityId' ],
414
			'getPropertyOrder' => [ $this, 'getPropertyOrder' ],
415
			'orderProperties' => [ $this, 'orderProperties' ],
416
			'incrementStatsKey' => [ $this, 'incrementStatsKey' ],
417
			'getEntityModuleName' => [ $this, 'getEntityModuleName' ],
418
		];
419
420
		return $this->getEngine()->registerInterface(
421
			__DIR__ . '/mw.wikibase.lua', $lib, []
422
		);
423
	}
424
425
	/**
426
	 * Wrapper for getEntity in EntityAccessor
427
	 *
428
	 * @param string $prefixedEntityId
429
	 *
430
	 * @throws ScribuntoException
431
	 * @return array
432
	 */
433
	public function getEntity( $prefixedEntityId ) {
434
		$this->checkType( 'getEntity', 1, $prefixedEntityId, 'string' );
435
436
		try {
437
			$entityArr = $this->getEntityAccessor()->getEntity( $prefixedEntityId );
438
			return [ $entityArr ];
439
		} catch ( EntityIdParsingException $ex ) {
440
			throw new ScribuntoException(
441
				'wikibase-error-invalid-entity-id',
442
				[ 'args' => [ $prefixedEntityId ] ]
443
			);
444
		} catch ( EntityAccessLimitException $ex ) {
445
			throw new ScribuntoException( 'wikibase-error-exceeded-entity-access-limit' );
446
		} catch ( Exception $ex ) {
447
			throw new ScribuntoException( 'wikibase-error-serialize-error' );
448
		}
449
	}
450
451
	/**
452
	 * Wrapper for getReferencedEntityId in WikibaseLanguageIndependentLuaBindings
453
	 *
454
	 * @param string $prefixedFromEntityId
455
	 * @param string $prefixedPropertyId
456
	 * @param string[] $prefixedToIds
457
	 *
458
	 * @throws ScribuntoException
459
	 * @return array
460
	 */
461
	public function getReferencedEntityId( $prefixedFromEntityId, $prefixedPropertyId, $prefixedToIds ) {
462
		$parserOutput = $this->getEngine()->getParser()->getOutput();
463
		$key = 'wikibase-referenced-entity-id-limit';
464
465
		$accesses = (int)$parserOutput->getExtensionData( $key );
466
		$accesses++;
467
		$parserOutput->setExtensionData( $key, $accesses );
468
469
		$limit = WikibaseClient::getDefaultInstance()->getSettings()->getSetting( 'referencedEntityIdAccessLimit' );
470
		if ( $accesses > $limit ) {
471
			throw new Scribunto_LuaError(
472
				wfMessage( 'wikibase-error-exceeded-referenced-entity-id-limit' )->params( 'IGNORED' )->numParams( 3 )->text()
473
			);
474
		}
475
476
		$this->checkType( 'getReferencedEntityId', 1, $prefixedFromEntityId, 'string' );
477
		$this->checkType( 'getReferencedEntityId', 2, $prefixedPropertyId, 'string' );
478
		$this->checkType( 'getReferencedEntityId', 3, $prefixedToIds, 'table' );
479
480
		$fromId = $this->parseUserGivenEntityId( $prefixedFromEntityId );
481
		$propertyId = $this->parseUserGivenEntityId( $prefixedPropertyId );
482
		$toIds = array_map(
483
			[ $this, 'parseUserGivenEntityId' ],
484
			$prefixedToIds
485
		);
486
487
		if ( !( $propertyId instanceof PropertyId ) ) {
488
			return [ null ];
489
		}
490
491
		return [
492
			$this->getLanguageIndependentLuaBindings()->getReferencedEntityId( $fromId, $propertyId, $toIds )
493
		];
494
	}
495
496
	/**
497
	 * Wrapper for entityExists in EntityAccessor
498
	 *
499
	 * @param string $prefixedEntityId
500
	 *
501
	 * @throws ScribuntoException
502
	 * @return bool[]
503
	 */
504
	public function entityExists( $prefixedEntityId ) {
505
		$this->checkType( 'entityExists', 1, $prefixedEntityId, 'string' );
506
507
		try {
508
			return [ $this->getEntityAccessor()->entityExists( $prefixedEntityId ) ];
509
		} catch ( EntityIdParsingException $ex ) {
510
			throw new ScribuntoException(
511
				'wikibase-error-invalid-entity-id',
512
				[ 'args' => [ $prefixedEntityId ] ]
513
			);
514
		}
515
	}
516
517
	/**
518
	 * Wrapper for getEntityStatements in EntityAccessor
519
	 *
520
	 * @param string $prefixedEntityId
521
	 * @param string $propertyId
522
	 * @param string $rank Which statements to include. Either "best" or "all".
523
	 *
524
	 * @throws ScribuntoException
525
	 * @return array
526
	 */
527
	public function getEntityStatements( $prefixedEntityId, $propertyId, $rank ) {
528
		$this->checkType( 'getEntityStatements', 1, $prefixedEntityId, 'string' );
529
		$this->checkType( 'getEntityStatements', 2, $propertyId, 'string' );
530
		$this->checkType( 'getEntityStatements', 3, $rank, 'string' );
531
532
		try {
533
			$statements = $this->getEntityAccessor()->getEntityStatements( $prefixedEntityId, $propertyId, $rank );
534
		} catch ( EntityAccessLimitException $ex ) {
535
			throw new ScribuntoException( 'wikibase-error-exceeded-entity-access-limit' );
536
		} catch ( EntityIdParsingException $ex ) {
537
			throw new ScribuntoException(
538
				'wikibase-error-invalid-entity-id',
539
				[ 'args' => [ $prefixedEntityId ] ]
540
			);
541
		} catch ( Exception $ex ) {
542
			throw new ScribuntoException( 'wikibase-error-serialize-error' );
543
		}
544
		return [ $statements ];
545
	}
546
547
	/**
548
	 * Wrapper for getEntityId in WikibaseLanguageIndependentLuaBindings
549
	 *
550
	 * @param string $pageTitle
551
	 * @param string|null $globalSiteId
552
	 *
553
	 * @return array
554
	 */
555
	public function getEntityId( $pageTitle, $globalSiteId = null ) {
556
		$this->checkType( 'getEntityId', 1, $pageTitle, 'string' );
557
		$this->checkTypeOptional( 'getEntityId', 2, $globalSiteId, 'string', null );
558
559
		return [ $this->getLanguageIndependentLuaBindings()->getEntityId( $pageTitle, $globalSiteId ) ];
560
	}
561
562
	/**
563
	 * Wrapper for getSetting in WikibaseLanguageIndependentLuaBindings
564
	 *
565
	 * @param string $setting
566
	 *
567
	 * @return array
568
	 */
569
	public function getSetting( $setting ) {
570
		$this->checkType( 'setting', 1, $setting, 'string' );
571
		return [ $this->getLanguageIndependentLuaBindings()->getSetting( $setting ) ];
572
	}
573
574
	/**
575
	 * @param string $entityIdSerialization entity ID serialization
576
	 *
577
	 * @return string[]|null[]
578
	 */
579
	public function getEntityUrl( $entityIdSerialization ) {
580
		$this->checkType( 'getEntityUrl', 1, $entityIdSerialization, 'string' );
581
582
		try {
583
			$url = $this->getRepoLinker()->getEntityUrl(
584
				$this->getEntityIdParser()->parse( $entityIdSerialization )
585
			);
586
		} catch ( EntityIdParsingException $ex ) {
587
			$url = null;
588
		}
589
590
		return [ $url ];
591
	}
592
593
	/**
594
	 * @return RepoLinker
595
	 */
596
	private function getRepoLinker() {
597
		if ( !$this->repoLinker ) {
598
			$wikibaseClient = WikibaseClient::getDefaultInstance();
599
			$this->repoLinker = $wikibaseClient->newRepoLinker();
600
		}
601
		return $this->repoLinker;
602
	}
603
604
	public function setRepoLinker( RepoLinker $repoLinker ) {
605
		$this->repoLinker = $repoLinker;
606
	}
607
608
	/**
609
	 * Wrapper for getLabel in WikibaseLanguageDependentLuaBindings
610
	 *
611
	 * @param string $prefixedEntityId
612
	 *
613
	 * @return string[]|null[]
614
	 */
615
	public function getLabel( $prefixedEntityId ) {
616
		$this->checkType( 'getLabel', 1, $prefixedEntityId, 'string' );
617
618
		return $this->getLanguageDependentLuaBindings()->getLabel( $prefixedEntityId );
619
	}
620
621
	/**
622
	 * Wrapper for getLabelByLanguage in WikibaseLanguageIndependentLuaBindings
623
	 *
624
	 * @param string $prefixedEntityId
625
	 * @param string $languageCode
626
	 *
627
	 * @return string[]|null[]
628
	 */
629
	public function getLabelByLanguage( $prefixedEntityId, $languageCode ) {
630
		$this->checkType( 'getLabelByLanguage', 1, $prefixedEntityId, 'string' );
631
		$this->checkType( 'getLabelByLanguage', 2, $languageCode, 'string' );
632
633
		return [ $this->getLanguageIndependentLuaBindings()->getLabelByLanguage( $prefixedEntityId, $languageCode ) ];
634
	}
635
636
	/**
637
	 * Wrapper for getDescription in WikibaseLanguageDependentLuaBindings
638
	 *
639
	 * @param string $prefixedEntityId
640
	 *
641
	 * @return string[]|null[]
642
	 */
643
	public function getDescription( $prefixedEntityId ) {
644
		$this->checkType( 'getDescription', 1, $prefixedEntityId, 'string' );
645
646
		return $this->getLanguageDependentLuaBindings()->getDescription( $prefixedEntityId );
647
	}
648
649
	/**
650
	 * Wrapper for getSiteLinkPageName in WikibaseLanguageIndependentLuaBindings
651
	 *
652
	 * @param string $prefixedItemId
653
	 * @param string|null $globalSiteId
654
	 *
655
	 * @return string[]
656
	 */
657
	public function getSiteLinkPageName( $prefixedItemId, $globalSiteId ) {
658
		$this->checkType( 'getSiteLinkPageName', 1, $prefixedItemId, 'string' );
659
		$this->checkTypeOptional( 'getSiteLinkPageName', 2, $globalSiteId, 'string', null );
660
661
		return [ $this->getLanguageIndependentLuaBindings()->getSiteLinkPageName( $prefixedItemId, $globalSiteId ) ];
662
	}
663
664
	/**
665
	 * Wrapper for WikibaseLanguageIndependentLuaBindings::isValidEntityId
666
	 *
667
	 * @param string $entityIdSerialization
668
	 *
669
	 * @throws ScribuntoException
670
	 * @return bool[] One bool telling whether the entity id is valid (parseable).
671
	 */
672
	public function isValidEntityId( $entityIdSerialization ) {
673
		$this->checkType( 'isValidEntityId', 1, $entityIdSerialization, 'string' );
674
675
		return [ $this->getLanguageIndependentLuaBindings()->isValidEntityId( $entityIdSerialization ) ];
676
	}
677
678
	/**
679
	 * Wrapper for SnakSerializationRenderer::renderSnak, set to output wikitext escaped plain text.
680
	 *
681
	 * @param array $snakSerialization
682
	 *
683
	 * @throws ScribuntoException
684
	 * @return string[] Wikitext
685
	 */
686
	public function renderSnak( $snakSerialization ) {
687
		$this->checkType( 'renderSnak', 1, $snakSerialization, 'table' );
688
689
		try {
690
			return [
691
				$this->getSnakSerializationRenderer(
692
					DataAccessSnakFormatterFactory::TYPE_ESCAPED_PLAINTEXT
693
				)->renderSnak( $snakSerialization )
694
			];
695
		} catch ( DeserializationException $e ) {
696
			throw new ScribuntoException( 'wikibase-error-deserialize-error' );
697
		}
698
	}
699
700
	/**
701
	 * Wrapper for SnakSerializationRenderer::renderSnak, set to output rich wikitext.
702
	 *
703
	 * @param array $snakSerialization
704
	 *
705
	 * @throws ScribuntoException
706
	 * @return string[] Wikitext
707
	 */
708
	public function formatValue( $snakSerialization ) {
709
		$this->checkType( 'formatValue', 1, $snakSerialization, 'table' );
710
711
		try {
712
			return [
713
				$this->getSnakSerializationRenderer(
714
					DataAccessSnakFormatterFactory::TYPE_RICH_WIKITEXT
715
				)->renderSnak( $snakSerialization )
716
			];
717
		} catch ( DeserializationException $e ) {
718
			throw new ScribuntoException( 'wikibase-error-deserialize-error' );
719
		}
720
	}
721
722
	/**
723
	 * Wrapper for SnakSerializationRenderer::renderSnaks, set to output wikitext escaped plain text.
724
	 *
725
	 * @param array[] $snaksSerialization
726
	 *
727
	 * @throws ScribuntoException
728
	 * @return string[] Wikitext
729
	 */
730
	public function renderSnaks( $snaksSerialization ) {
731
		$this->checkType( 'renderSnaks', 1, $snaksSerialization, 'table' );
732
733
		try {
734
			return [
735
				$this->getSnakSerializationRenderer(
736
					DataAccessSnakFormatterFactory::TYPE_ESCAPED_PLAINTEXT
737
				)->renderSnaks( $snaksSerialization )
738
			];
739
		} catch ( DeserializationException $e ) {
740
			throw new ScribuntoException( 'wikibase-error-deserialize-error' );
741
		}
742
	}
743
744
	/**
745
	 * Wrapper for SnakSerializationRenderer::renderSnaks, set to output rich wikitext.
746
	 *
747
	 * @param array[] $snaksSerialization
748
	 *
749
	 * @throws ScribuntoException
750
	 * @return string[] Wikitext
751
	 */
752
	public function formatValues( $snaksSerialization ) {
753
		$this->checkType( 'formatValues', 1, $snaksSerialization, 'table' );
754
755
		try {
756
			return [
757
				$this->getSnakSerializationRenderer(
758
					DataAccessSnakFormatterFactory::TYPE_RICH_WIKITEXT
759
				)->renderSnaks( $snaksSerialization )
760
			];
761
		} catch ( DeserializationException $e ) {
762
			throw new ScribuntoException( 'wikibase-error-deserialize-error' );
763
		}
764
	}
765
766
	/**
767
	 * Wrapper for PropertyIdResolver
768
	 *
769
	 * @param string $propertyLabelOrId
770
	 *
771
	 * @return string[]|null[]
772
	 */
773
	public function resolvePropertyId( $propertyLabelOrId ) {
774
		$this->checkType( 'resolvePropertyId', 1, $propertyLabelOrId, 'string' );
775
		try {
776
			$propertyId = $this->getPropertyIdResolver()->resolvePropertyId(
777
				$propertyLabelOrId,
778
				MediaWikiServices::getInstance()->getContentLanguage()->getCode()
779
			);
780
			$ret = [ $propertyId->getSerialization() ];
781
			return $ret;
782
		} catch ( PropertyLabelNotResolvedException $e ) {
783
			return [ null ];
784
		}
785
	}
786
787
	/**
788
	 * @param string[] $propertyIds
789
	 *
790
	 * @return array[]
791
	 */
792
	public function orderProperties( array $propertyIds ) {
793
		if ( $propertyIds === [] ) {
794
			return [ [] ];
795
		}
796
797
		$orderedPropertiesPart = [];
798
		$unorderedProperties = [];
799
800
		$propertyOrder = $this->getPropertyOrderProvider()->getPropertyOrder();
801
		foreach ( $propertyIds as $propertyId ) {
802
			if ( isset( $propertyOrder[$propertyId] ) ) {
803
				$orderedPropertiesPart[ $propertyOrder[ $propertyId ] ] = $propertyId;
804
			} else {
805
				$unorderedProperties[] = $propertyId;
806
			}
807
		}
808
		ksort( $orderedPropertiesPart );
809
		$orderedProperties = array_merge( $orderedPropertiesPart, $unorderedProperties );
810
811
		// Lua tables start at 1
812
		$orderedPropertiesResult = array_combine(
813
				range( 1, count( $orderedProperties ) ), array_values( $orderedProperties )
814
		);
815
		return [ $orderedPropertiesResult ];
816
	}
817
818
	/**
819
	 * Return the order of properties as provided by the PropertyOrderProvider
820
	 * @return array[] either int[][] or null[][]
821
	 */
822
	public function getPropertyOrder() {
823
		return [ $this->getPropertyOrderProvider()->getPropertyOrder() ];
824
	}
825
826
	/**
827
	 * Increment the given stats key.
828
	 *
829
	 * @param string $key
830
	 */
831
	public function incrementStatsKey( $key ) {
832
		$this->getLuaFunctionCallTracker()->incrementKey( $key );
833
	}
834
835
	/**
836
	 * Get the entity module name to use for the entity with this ID.
837
	 *
838
	 * @param string $prefixedEntityId
839
	 * @return string[]
840
	 */
841
	public function getEntityModuleName( $prefixedEntityId ) {
842
		$this->checkType( 'getEntityModuleName', 1, $prefixedEntityId, 'string' );
843
844
		try {
845
			$entityId = $this->getEntityIdParser()->parse( $prefixedEntityId );
846
			$type = $entityId->getEntityType();
847
			$moduleName = $this->getLuaEntityModules()[$type] ?? 'mw.wikibase.entity';
848
		} catch ( EntityIdParsingException $e ) {
849
			$moduleName = 'mw.wikibase.entity';
850
		}
851
		return [ $moduleName ];
852
	}
853
854
	/**
855
	 * @return PropertyOrderProvider
856
	 */
857
	private function getPropertyOrderProvider() {
858
		if ( !$this->propertyOrderProvider ) {
859
			$wikibaseClient = WikibaseClient::getDefaultInstance();
860
			$this->propertyOrderProvider = $wikibaseClient->getPropertyOrderProvider();
861
		}
862
		return $this->propertyOrderProvider;
863
	}
864
865
	public function setPropertyOrderProvider( PropertyOrderProvider $propertyOrderProvider ) {
866
		$this->propertyOrderProvider = $propertyOrderProvider;
867
	}
868
869
	private function getLuaEntityModules() {
870
		if ( !$this->luaEntityModules ) {
871
			$wikibaseClient = WikibaseClient::getDefaultInstance();
872
			$this->luaEntityModules = $wikibaseClient->getLuaEntityModules();
873
		}
874
		return $this->luaEntityModules;
875
	}
876
877
}
878