EditEntity::validateEntitySpecificParameters()   B
last analyzed

Complexity

Conditions 9
Paths 12

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 46
rs 7.6226
c 0
b 0
f 0
cc 9
nc 12
nop 3
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace Wikibase\Repo\Api;
6
7
use ApiMain;
8
use ApiUsageException;
9
use Deserializers\Deserializer;
10
use Title;
11
use Wikibase\DataModel\Entity\ClearableEntity;
12
use Wikibase\DataModel\Entity\EntityDocument;
13
use Wikibase\DataModel\Entity\EntityId;
14
use Wikibase\DataModel\Entity\EntityIdParser;
15
use Wikibase\DataModel\Entity\Item;
16
use Wikibase\DataModel\Entity\Property;
17
use Wikibase\DataModel\Statement\StatementListProvider;
18
use Wikibase\DataModel\Term\AliasesProvider;
19
use Wikibase\DataModel\Term\DescriptionsProvider;
20
use Wikibase\DataModel\Term\LabelsProvider;
21
use Wikibase\Lib\ContentLanguages;
22
use Wikibase\Lib\EntityFactory;
23
use Wikibase\Lib\Store\EntityRevisionLookup;
24
use Wikibase\Lib\Store\LookupConstants;
25
use Wikibase\Lib\Summary;
26
use Wikibase\Repo\ChangeOp\ChangedLanguagesCollector;
27
use Wikibase\Repo\ChangeOp\ChangedLanguagesCounter;
28
use Wikibase\Repo\ChangeOp\ChangeOp;
29
use Wikibase\Repo\ChangeOp\ChangeOpException;
30
use Wikibase\Repo\ChangeOp\ChangeOpResult;
31
use Wikibase\Repo\ChangeOp\Deserialization\ChangeOpDeserializationException;
32
use Wikibase\Repo\ChangeOp\EntityChangeOpProvider;
33
use Wikibase\Repo\ChangeOp\FingerprintChangeOpFactory;
34
use Wikibase\Repo\ChangeOp\NonLanguageBoundChangesCounter;
35
use Wikibase\Repo\ChangeOp\SiteLinkChangeOpFactory;
36
use Wikibase\Repo\ChangeOp\StatementChangeOpFactory;
37
use Wikibase\Repo\Store\Store;
38
use Wikibase\Repo\WikibaseRepo;
39
40
/**
41
 * Derived class for API modules modifying a single entity identified by id xor a combination of
42
 * site and page title.
43
 *
44
 * @license GPL-2.0-or-later
45
 */
46
class EditEntity extends ModifyEntity {
47
48
	const PARAM_DATA = 'data';
49
50
	const PARAM_CLEAR = 'clear';
51
52
	/**
53
	 * @var ContentLanguages
54
	 */
55
	private $termsLanguages;
56
57
	/**
58
	 * @var FingerprintChangeOpFactory
59
	 */
60
	private $termChangeOpFactory;
61
62
	/**
63
	 * @var StatementChangeOpFactory
64
	 */
65
	private $statementChangeOpFactory;
66
67
	/**
68
	 * @var SiteLinkChangeOpFactory
69
	 */
70
	private $siteLinkChangeOpFactory;
71
72
	/**
73
	 * @var EntityRevisionLookup
74
	 */
75
	private $revisionLookup;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
76
77
	/**
78
	 * @var Deserializer
79
	 */
80
	private $statementDeserializer;
81
82
	/**
83
	 * @var EntityIdParser
84
	 */
85
	private $idParser;
86
87
	/**
88
	 * @var EntityFactory
89
	 */
90
	private $entityFactory;
91
92
	/**
93
	 * @var string[]
94
	 */
95
	private $propertyDataTypes;
96
97
	/**
98
	 * @var EntityChangeOpProvider
99
	 */
100
	private $entityChangeOpProvider;
101
102
	/**
103
	 * @var EditSummaryHelper
104
	 */
105
	private $editSummaryHelper;
106
107
	/**
108
	 * @see ModifyEntity::__construct
109
	 *
110
	 * @param ApiMain $mainModule
111
	 * @param string $moduleName
112
	 * @param ContentLanguages $termsLanguages
113
	 * @param EntityRevisionLookup $revisionLookup
114
	 * @param EntityIdParser $idParser
115
	 * @param EntityFactory $entityFactory
116
	 * @param Deserializer $statementDeserializer
117
	 * @param string[] $propertyDataTypes
118
	 * @param FingerprintChangeOpFactory $termChangeOpFactory
119
	 * @param StatementChangeOpFactory $statementChangeOpFactory
120
	 * @param SiteLinkChangeOpFactory $siteLinkChangeOpFactory
121
	 * @param EntityChangeOpProvider $entityChangeOpProvider
122
	 * @param EditSummaryHelper $editSummaryHelper
123
	 * @param bool $federatedPropertiesEnabled
124
	 *
125
	 */
126
	public function __construct(
127
		ApiMain $mainModule,
128
		string $moduleName,
129
		ContentLanguages $termsLanguages,
130
		EntityRevisionLookup $revisionLookup,
131
		EntityIdParser $idParser,
132
		EntityFactory $entityFactory,
133
		Deserializer $statementDeserializer,
134
		array $propertyDataTypes,
135
		FingerprintChangeOpFactory $termChangeOpFactory,
136
		StatementChangeOpFactory $statementChangeOpFactory,
137
		SiteLinkChangeOpFactory $siteLinkChangeOpFactory,
138
		EntityChangeOpProvider $entityChangeOpProvider,
139
		EditSummaryHelper $editSummaryHelper,
140
		bool $federatedPropertiesEnabled
141
	) {
142
		parent::__construct( $mainModule, $moduleName, $federatedPropertiesEnabled );
143
144
		$this->termsLanguages = $termsLanguages;
145
		$this->revisionLookup = $revisionLookup;
146
		$this->idParser = $idParser;
147
		$this->entityFactory = $entityFactory;
148
		$this->statementDeserializer = $statementDeserializer;
149
		$this->propertyDataTypes = $propertyDataTypes;
150
151
		$this->termChangeOpFactory = $termChangeOpFactory;
152
		$this->statementChangeOpFactory = $statementChangeOpFactory;
153
		$this->siteLinkChangeOpFactory = $siteLinkChangeOpFactory;
154
		$this->entityChangeOpProvider = $entityChangeOpProvider;
155
		$this->editSummaryHelper = $editSummaryHelper;
156
	}
157
158
	public static function factory( ApiMain $mainModule, string $moduleName ): self {
159
		$wikibaseRepo = WikibaseRepo::getDefaultInstance();
160
		$changeOpFactoryProvider = $wikibaseRepo->getChangeOpFactoryProvider();
161
		return new self(
162
			$mainModule,
163
			$moduleName,
164
			$wikibaseRepo->getTermsLanguages(),
165
			$wikibaseRepo->getEntityRevisionLookup( Store::LOOKUP_CACHING_DISABLED ),
166
			$wikibaseRepo->getEntityIdParser(),
167
			$wikibaseRepo->getEntityFactory(),
168
			$wikibaseRepo->getExternalFormatStatementDeserializer(),
169
			$wikibaseRepo->getDataTypeDefinitions()->getTypeIds(),
170
			$changeOpFactoryProvider->getFingerprintChangeOpFactory(),
171
			$changeOpFactoryProvider->getStatementChangeOpFactory(),
172
			$changeOpFactoryProvider->getSiteLinkChangeOpFactory(),
173
			$wikibaseRepo->getEntityChangeOpProvider(),
174
			new EditSummaryHelper(
175
				new ChangedLanguagesCollector(),
176
				new ChangedLanguagesCounter(),
177
				new NonLanguageBoundChangesCounter()
178
			),
179
			$wikibaseRepo->inFederatedPropertyMode()
180
		);
181
	}
182
183
	/**
184
	 * @see ApiBase::needsToken
185
	 *
186
	 * @return string
187
	 */
188
	public function needsToken(): string {
189
		return 'csrf';
190
	}
191
192
	/**
193
	 * @see ApiBase::isWriteMode()
194
	 *
195
	 * @return bool Always true.
196
	 */
197
	public function isWriteMode(): bool {
198
		return true;
199
	}
200
201
	/**
202
	 * @param EntityId $entityId
203
	 *
204
	 * @return bool
205
	 */
206
	private function entityExists( EntityId $entityId ): bool {
207
		$title = $this->getTitleLookup()->getTitleForId( $entityId );
208
		return ( $title !== null && $title->exists() );
209
	}
210
211
	protected function prepareParameters( array $params ): array {
212
		$this->validateDataParameter( $params );
213
		$params[self::PARAM_DATA] = json_decode( $params[self::PARAM_DATA], true );
214
		return parent::prepareParameters( $params );
215
	}
216
217
	protected function validateEntitySpecificParameters(
218
		array $preparedParameters,
219
		EntityDocument $entity,
220
		int $baseRevId
221
	): void {
222
		$data = $preparedParameters[self::PARAM_DATA];
223
		$this->validateDataProperties( $data, $entity, $baseRevId );
224
225
		$exists = $this->entityExists( $entity->getId() );
226
227
		if ( $preparedParameters[self::PARAM_CLEAR] ) {
228
			if ( $preparedParameters['baserevid'] && $exists ) {
229
				$latestRevisionResult = $this->revisionLookup->getLatestRevisionId(
230
					$entity->getId(),
0 ignored issues
show
Bug introduced by
It seems like $entity->getId() can be null; however, getLatestRevisionId() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
231
					 LookupConstants::LATEST_FROM_MASTER
232
				);
233
234
				$returnFalse = function () {
235
					return false;
236
				};
237
				$latestRevision = $latestRevisionResult->onConcreteRevision( 'intval' )
238
					->onRedirect( $returnFalse )
239
					->onNonexistentEntity( $returnFalse )
240
					->map();
241
242
				if ( !$baseRevId === $latestRevision ) {
243
					$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
244
						'Tried to clear entity using baserevid of entity not equal to current revision',
245
						'editconflict'
246
					);
247
				}
248
			}
249
		}
250
251
		// if we create a new property, make sure we set the datatype
252
		if ( !$exists && $entity instanceof Property ) {
253
			if ( !isset( $data['datatype'] )
254
				|| !in_array( $data['datatype'], $this->propertyDataTypes )
255
			) {
256
				$this->errorReporter->dieWithError(
257
					'wikibase-api-not-recognized-datatype',
258
					'param-illegal'
259
				);
260
			}
261
		}
262
	}
263
264
	protected function modifyEntity( EntityDocument $entity, ChangeOp $changeOp, array $preparedParameters ): Summary {
265
		$data = $preparedParameters[self::PARAM_DATA];
266
267
		$exists = $this->entityExists( $entity->getId() );
268
269
		if ( $preparedParameters[self::PARAM_CLEAR] ) {
270
			$this->dieIfNotClearable( $entity );
271
			$this->getStats()->increment( 'wikibase.api.EditEntity.modifyEntity.clear' );
272
		} else {
273
			$this->getStats()->increment( 'wikibase.api.EditEntity.modifyEntity.no-clear' );
274
		}
275
276
		if ( !$exists ) {
277
			// if we create a new property, make sure we set the datatype
278
			if ( $entity instanceof Property ) {
279
				$entity->setDataTypeId( $data['datatype'] );
280
			}
281
282
			$this->getStats()->increment( 'wikibase.api.EditEntity.modifyEntity.create' );
283
		}
284
285
		if ( $preparedParameters[self::PARAM_CLEAR] ) {
286
			$oldEntity = clone $entity;
287
			$entity->clear();
288
289
			// Validate it only by applying the changeOp on the current entity
290
			// instead of an empty one due avoid issues like T243158.
291
			// We are going to save the cleared entity instead,
292
			$changeOpResult = $this->applyChangeOp( $changeOp, $oldEntity );
293
294
			try {
295
				$changeOp->apply( $entity );
296
			} catch ( ChangeOpException $ex ) {
297
				$this->errorReporter->dieException( $ex, 'modification-failed' );
298
			}
299
300
		} else {
301
			$changeOpResult = $this->applyChangeOp( $changeOp, $entity );
302
		}
303
304
		$this->buildResult( $entity );
305
		return $this->getSummary( $preparedParameters, $entity, $changeOpResult );
306
	}
307
308
	private function getSummary(
309
		array $preparedParameters,
310
		EntityDocument $entity,
311
		ChangeOpResult $changeOpResult
312
	): Summary {
313
		$summary = $this->createSummary( $preparedParameters );
314
315
		if ( $this->isUpdatingExistingEntity( $preparedParameters ) ) {
316
			if ( $preparedParameters[self::PARAM_CLEAR] !== false ) {
317
				$summary->setAction( 'override' );
318
			} else {
319
				$this->editSummaryHelper->prepareEditSummary( $summary, $changeOpResult );
320
			}
321
		} else {
322
			$summary->setAction( 'create-' . $entity->getType() );
323
		}
324
325
		return $summary;
326
	}
327
328
	private function isUpdatingExistingEntity( array $preparedParameters ): bool {
329
		$isTargetingEntity = isset( $preparedParameters['id'] );
330
		$isTargetingPage = isset( $preparedParameters['site'] ) && isset( $preparedParameters['title'] );
331
332
		return $isTargetingEntity xor $isTargetingPage;
333
	}
334
335
	/**
336
	 * @param array $preparedParameters
337
	 * @param EntityDocument $entity
338
	 *
339
	 * @throws ApiUsageException
340
	 * @return ChangeOp
341
	 */
342
	protected function getChangeOp( array $preparedParameters, EntityDocument $entity ): ChangeOp {
343
		$data = $preparedParameters[self::PARAM_DATA];
344
345
		try {
346
			return $this->entityChangeOpProvider->newEntityChangeOp( $entity->getType(), $data );
347
		} catch ( ChangeOpDeserializationException $exception ) {
348
			$this->errorReporter->dieException( $exception, $exception->getErrorCode() );
349
		}
350
	}
351
352
	private function buildResult( EntityDocument $entity ): void {
353
		$builder = $this->getResultBuilder();
354
355
		if ( $entity instanceof LabelsProvider ) {
356
			$builder->addLabels( $entity->getLabels(), 'entity' );
357
		}
358
359
		if ( $entity instanceof DescriptionsProvider ) {
360
			$builder->addDescriptions( $entity->getDescriptions(), 'entity' );
361
		}
362
363
		if ( $entity instanceof AliasesProvider ) {
364
			$builder->addAliasGroupList( $entity->getAliasGroups(), 'entity' );
365
		}
366
367
		if ( $entity instanceof Item ) {
368
			$builder->addSiteLinkList( $entity->getSiteLinkList(), 'entity' );
369
		}
370
371
		if ( $entity instanceof StatementListProvider ) {
372
			$builder->addStatements( $entity->getStatements(), 'entity' );
373
		}
374
	}
375
376
	private function validateDataParameter( array $params ): void {
377
		if ( !isset( $params[self::PARAM_DATA] ) ) {
378
			$this->errorReporter->dieError( 'No data to operate upon', 'no-data' );
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
379
		}
380
	}
381
382
	/**
383
	 * @param mixed $data
384
	 * @param EntityDocument $entity
385
	 * @param int $revisionId
386
	 */
387
	private function validateDataProperties( $data, EntityDocument $entity, int $revisionId ): void {
388
		$entityId = $entity->getId();
389
		$title = $entityId === null ? null : $this->getTitleLookup()->getTitleForId( $entityId );
390
391
		$this->checkValidJson( $data );
392
		$this->checkEntityId( $data, $entityId );
393
		$this->checkEntityType( $data, $entity );
394
		$this->checkPageIdProp( $data, $title );
395
		$this->checkNamespaceProp( $data, $title );
396
		$this->checkTitleProp( $data, $title );
397
		$this->checkRevisionProp( $data, $revisionId );
398
	}
399
400
	/**
401
	 * @param mixed $data
402
	 */
403
	private function checkValidJson( $data ): void {
404
		if ( $data === null ) {
405
			$this->errorReporter->dieError( 'Invalid json: The supplied JSON structure could not be parsed or '
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
406
				. 'recreated as a valid structure', 'invalid-json' );
407
		}
408
409
		// NOTE: json_decode will decode any JS literal or structure, not just objects!
410
		$this->assertArray( $data, 'Top level structure must be a JSON object' );
411
412
		foreach ( $data as $prop => $args ) {
413
			// Catch json_decode returning an indexed array (list).
414
			$this->assertString( $prop, 'Top level structure must be a JSON object (no keys found)' );
415
416
			if ( $prop === 'remove' ) {
417
				$this->errorReporter->dieWithError(
418
					'wikibase-api-illegal-entity-remove',
419
					'not-recognized'
420
				);
421
			}
422
		}
423
	}
424
425
	private function checkPageIdProp( array $data, ?Title $title ): void {
426
		if ( isset( $data['pageid'] )
427
			&& ( $title === null || $title->getArticleID() !== $data['pageid'] )
428
		) {
429
			$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
430
				'Illegal field used in call, "pageid", must either be correct or not given',
431
				'param-illegal'
432
			);
433
		}
434
	}
435
436
	private function checkNamespaceProp( array $data, ?Title $title ): void {
437
		// not completely convinced that we can use title to get the namespace in this case
438
		if ( isset( $data['ns'] )
439
			&& ( $title === null || $title->getNamespace() !== $data['ns'] )
440
		) {
441
			$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
442
				'Illegal field used in call: "namespace", must either be correct or not given',
443
				'param-illegal'
444
			);
445
		}
446
	}
447
448
	private function checkTitleProp( array $data, ?Title $title ): void {
449
		if ( isset( $data['title'] )
450
			&& ( $title === null || $title->getPrefixedText() !== $data['title'] )
451
		) {
452
			$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
453
				'Illegal field used in call: "title", must either be correct or not given',
454
				'param-illegal'
455
			);
456
		}
457
	}
458
459
	private function checkRevisionProp( array $data, int $revisionId ): void {
460
		if ( isset( $data['lastrevid'] )
461
			&& ( $revisionId !== $data['lastrevid'] )
462
		) {
463
			$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
464
				'Illegal field used in call: "lastrevid", must either be correct or not given',
465
				'param-illegal'
466
			);
467
		}
468
	}
469
470
	private function checkEntityId( array $data, ?EntityId $entityId ): void {
471
		if ( isset( $data['id'] ) ) {
472
			if ( !$entityId ) {
473
				$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
474
					'Illegal field used in call: "id", must not be given when creating a new entity',
475
					'param-illegal'
476
				);
477
			}
478
479
			$dataId = $this->idParser->parse( $data['id'] );
480
			if ( !$entityId->equals( $dataId ) ) {
481
				$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
482
					'Invalid field used in call: "id", must match id parameter',
483
					'param-invalid'
484
				);
485
			}
486
		}
487
	}
488
489
	private function checkEntityType( array $data, EntityDocument $entity ): void {
490
		if ( isset( $data['type'] )
491
			&& $entity->getType() !== $data['type']
492
		) {
493
			$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
494
				'Invalid field used in call: "type", must match type associated with id',
495
				'param-invalid'
496
			);
497
		}
498
	}
499
500
	/**
501
	 * @inheritDoc
502
	 */
503
	protected function getAllowedParams(): array {
504
		return array_merge(
505
			parent::getAllowedParams(),
506
			[
507
				self::PARAM_DATA => [
508
					self::PARAM_TYPE => 'text',
509
					self::PARAM_REQUIRED => true,
510
				],
511
				self::PARAM_CLEAR => [
512
					self::PARAM_TYPE => 'boolean',
513
					self::PARAM_DFLT => false
514
				],
515
			]
516
		);
517
	}
518
519
	/**
520
	 * @inheritDoc
521
	 */
522
	protected function getExamplesMessages(): array {
523
		return [
524
			// Creating new entities
525
			'action=wbeditentity&new=item&data={}'
526
				=> 'apihelp-wbeditentity-example-1',
527
			'action=wbeditentity&new=item&data={"labels":{'
528
				. '"de":{"language":"de","value":"de-value"},'
529
				. '"en":{"language":"en","value":"en-value"}}}'
530
				=> 'apihelp-wbeditentity-example-2',
531
			'action=wbeditentity&new=property&data={'
532
				. '"labels":{"en-gb":{"language":"en-gb","value":"Propertylabel"}},'
533
				. '"descriptions":{"en-gb":{"language":"en-gb","value":"Propertydescription"}},'
534
				. '"datatype":"string"}'
535
				=> 'apihelp-wbeditentity-example-3',
536
			// Clearing entities
537
			'action=wbeditentity&clear=true&id=Q42&data={}'
538
				=> 'apihelp-wbeditentity-example-4',
539
			'action=wbeditentity&clear=true&id=Q42&data={'
540
				. '"labels":{"en":{"language":"en","value":"en-value"}}}'
541
				=> 'apihelp-wbeditentity-example-5',
542
			// Adding term
543
			'action=wbeditentity&id=Q42&data='
544
				. '{"labels":[{"language":"no","value":"Bar","add":""}]}'
545
				=> 'apihelp-wbeditentity-example-11',
546
			// Removing term
547
			'action=wbeditentity&id=Q42&data='
548
				. '{"labels":[{"language":"en","value":"Foo","remove":""}]}'
549
				=> 'apihelp-wbeditentity-example-12',
550
			// Setting stuff
551
			'action=wbeditentity&id=Q42&data={'
552
				. '"sitelinks":{"nowiki":{"site":"nowiki","title":"København"}}}'
553
				=> 'apihelp-wbeditentity-example-6',
554
			'action=wbeditentity&id=Q42&data={'
555
				. '"descriptions":{"nb":{"language":"nb","value":"nb-Description-Here"}}}'
556
				=> 'apihelp-wbeditentity-example-7',
557
			'action=wbeditentity&id=Q42&data={"claims":[{"mainsnak":{"snaktype":"value",'
558
				. '"property":"P56","datavalue":{"value":"ExampleString","type":"string"}},'
559
				. '"type":"statement","rank":"normal"}]}'
560
				=> 'apihelp-wbeditentity-example-8',
561
			'action=wbeditentity&id=Q42&data={"claims":['
562
				. '{"id":"Q42$D8404CDA-25E4-4334-AF13-A3290BCD9C0F","remove":""},'
563
				. '{"id":"Q42$GH678DSA-01PQ-28XC-HJ90-DDFD9990126X","remove":""}]}'
564
				=> 'apihelp-wbeditentity-example-9',
565
			'action=wbeditentity&id=Q42&data={"claims":[{'
566
				. '"id":"Q42$GH678DSA-01PQ-28XC-HJ90-DDFD9990126X","mainsnak":{"snaktype":"value",'
567
				. '"property":"P56","datavalue":{"value":"ChangedString","type":"string"}},'
568
				. '"type":"statement","rank":"normal"}]}'
569
				=> 'apihelp-wbeditentity-example-10',
570
		];
571
	}
572
573
	/**
574
	 * @param mixed $value
575
	 * @param string $message
576
	 */
577
	private function assertArray( $value, string $message ): void {
578
		$this->assertType( 'array', $value, $message );
579
	}
580
581
	/**
582
	 * @param mixed $value
583
	 * @param string $message
584
	 */
585
	private function assertString( $value, string $message ): void {
586
		$this->assertType( 'string', $value, $message );
587
	}
588
589
	/**
590
	 * @param string $type
591
	 * @param mixed $value
592
	 * @param string $message
593
	 */
594
	private function assertType( string $type, $value, string $message ): void {
595
		if ( gettype( $value ) !== $type ) {
596
			$this->errorReporter->dieError( $message, 'not-recognized-' . $type );
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
597
		}
598
	}
599
600
	private function dieIfNotClearable( EntityDocument $entity ): void {
601
		if ( !( $entity instanceof ClearableEntity ) ) {
602
			$this->errorReporter->dieError(
0 ignored issues
show
Deprecated Code introduced by
The method Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
603
				'Cannot clear an entity of type ' . $entity->getType(),
604
				'param-illegal'
605
			);
606
		}
607
	}
608
609
}
610