1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare( strict_types = 1 ); |
4
|
|
|
|
5
|
|
|
namespace Wikibase\Repo\Api; |
6
|
|
|
|
7
|
|
|
use ApiBase; |
8
|
|
|
use ApiMain; |
9
|
|
|
use Wikibase\DataModel\Entity\PropertyId; |
10
|
|
|
use Wikibase\DataModel\Services\Statement\StatementGuidParser; |
11
|
|
|
use Wikibase\DataModel\Statement\Statement; |
12
|
|
|
use Wikibase\Repo\ChangeOp\ChangeOp; |
13
|
|
|
use Wikibase\Repo\ChangeOp\StatementChangeOpFactory; |
14
|
|
|
use Wikibase\Repo\WikibaseRepo; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* API module for creating a qualifier or setting the value of an existing one. |
18
|
|
|
* |
19
|
|
|
* @license GPL-2.0-or-later |
20
|
|
|
* @author Jeroen De Dauw < [email protected] > |
21
|
|
|
* @author Daniel Kinzler |
22
|
|
|
* @author Tobias Gritschacher < [email protected] > |
23
|
|
|
*/ |
24
|
|
|
class SetQualifier extends ApiBase { |
25
|
|
|
|
26
|
|
|
use FederatedPropertyApiValidatorTrait; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var StatementChangeOpFactory |
30
|
|
|
*/ |
31
|
|
|
private $statementChangeOpFactory; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var ApiErrorReporter |
35
|
|
|
*/ |
36
|
|
|
protected $errorReporter; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var StatementModificationHelper |
40
|
|
|
*/ |
41
|
|
|
private $modificationHelper; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var StatementGuidParser |
45
|
|
|
*/ |
46
|
|
|
private $guidParser; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var ResultBuilder |
50
|
|
|
*/ |
51
|
|
|
private $resultBuilder; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var EntitySavingHelper |
55
|
|
|
*/ |
56
|
|
|
private $entitySavingHelper; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @param ApiMain $mainModule |
60
|
|
|
* @param string $moduleName |
61
|
|
|
* @param callable $errorReporterInstantiator |
62
|
|
|
* @param StatementChangeOpFactory $statementChangeOpFactory |
63
|
|
|
* @param StatementModificationHelper $modificationHelper |
64
|
|
|
* @param StatementGuidParser $guidParser |
65
|
|
|
* @param callable $resultBuilderInstantiator |
66
|
|
|
* @param callable $entitySavingHelperInstantiator |
67
|
|
|
* |
68
|
|
|
* @note Using callable for several arguments because of circular dependency and unability to inject object to constructor |
69
|
|
|
*/ |
70
|
|
|
public function __construct( |
71
|
|
|
ApiMain $mainModule, |
72
|
|
|
string $moduleName, |
73
|
|
|
callable $errorReporterInstantiator, |
74
|
|
|
StatementChangeOpFactory $statementChangeOpFactory, |
75
|
|
|
StatementModificationHelper $modificationHelper, |
76
|
|
|
StatementGuidParser $guidParser, |
77
|
|
|
callable $resultBuilderInstantiator, |
78
|
|
|
callable $entitySavingHelperInstantiator, |
79
|
|
|
bool $federatedPropertiesEnabled |
80
|
|
|
) { |
81
|
|
|
parent::__construct( $mainModule, $moduleName ); |
82
|
|
|
|
83
|
|
|
$this->errorReporter = $errorReporterInstantiator( $this ); |
84
|
|
|
$this->statementChangeOpFactory = $statementChangeOpFactory; |
85
|
|
|
|
86
|
|
|
$this->modificationHelper = $modificationHelper; |
87
|
|
|
$this->guidParser = $guidParser; |
88
|
|
|
$this->resultBuilder = $resultBuilderInstantiator( $this ); |
89
|
|
|
$this->entitySavingHelper = $entitySavingHelperInstantiator( $this ); |
90
|
|
|
$this->federatedPropertiesEnabled = $federatedPropertiesEnabled; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
public static function factory( ApiMain $mainModule, string $moduleName ): self { |
94
|
|
|
$wikibaseRepo = WikibaseRepo::getDefaultInstance(); |
95
|
|
|
$apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $mainModule->getContext() ); |
96
|
|
|
$changeOpFactoryProvider = $wikibaseRepo->getChangeOpFactoryProvider(); |
97
|
|
|
|
98
|
|
|
$modificationHelper = new StatementModificationHelper( |
99
|
|
|
$wikibaseRepo->getSnakFactory(), |
100
|
|
|
$wikibaseRepo->getEntityIdParser(), |
101
|
|
|
$wikibaseRepo->getStatementGuidValidator(), |
102
|
|
|
$apiHelperFactory->getErrorReporter( $mainModule ) |
103
|
|
|
); |
104
|
|
|
|
105
|
|
|
return new self( |
106
|
|
|
$mainModule, |
107
|
|
|
$moduleName, |
108
|
|
|
function ( $module ) use ( $apiHelperFactory ) { |
109
|
|
|
return $apiHelperFactory->getErrorReporter( $module ); |
110
|
|
|
}, |
111
|
|
|
$changeOpFactoryProvider->getStatementChangeOpFactory(), |
112
|
|
|
$modificationHelper, |
113
|
|
|
$wikibaseRepo->getStatementGuidParser(), |
114
|
|
|
function ( $module ) use ( $apiHelperFactory ) { |
115
|
|
|
return $apiHelperFactory->getResultBuilder( $module ); |
116
|
|
|
}, |
117
|
|
|
function ( $module ) use ( $apiHelperFactory ) { |
118
|
|
|
return $apiHelperFactory->getEntitySavingHelper( $module ); |
119
|
|
|
}, |
120
|
|
|
$wikibaseRepo->inFederatedPropertyMode() |
121
|
|
|
); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* @inheritDoc |
126
|
|
|
*/ |
127
|
|
|
public function execute(): void { |
128
|
|
|
$params = $this->extractRequestParams(); |
129
|
|
|
$this->validateParameters( $params ); |
130
|
|
|
|
131
|
|
|
$entityId = $this->guidParser->parse( $params['claim'] )->getEntityId(); |
132
|
|
|
$this->validateAlteringEntityById( $entityId ); |
133
|
|
|
|
134
|
|
|
$entity = $this->entitySavingHelper->loadEntity( $entityId ); |
135
|
|
|
|
136
|
|
|
$summary = $this->modificationHelper->createSummary( $params, $this ); |
137
|
|
|
|
138
|
|
|
$statement = $this->modificationHelper->getStatementFromEntity( $params['claim'], $entity ); |
139
|
|
|
|
140
|
|
|
if ( isset( $params['snakhash'] ) ) { |
141
|
|
|
$this->validateQualifierHash( $statement, $params['snakhash'] ); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
$changeOp = $this->getChangeOp(); |
145
|
|
|
$this->modificationHelper->applyChangeOp( $changeOp, $entity, $summary ); |
146
|
|
|
|
147
|
|
|
$status = $this->entitySavingHelper->attemptSaveEntity( $entity, $summary ); |
148
|
|
|
$this->resultBuilder->addRevisionIdFromStatusToResult( $status, 'pageinfo' ); |
149
|
|
|
$this->resultBuilder->markSuccess(); |
150
|
|
|
$this->resultBuilder->addStatement( $statement ); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Checks if the required parameters are set and the ones that make no sense given the |
155
|
|
|
* snaktype value are not set. |
156
|
|
|
* |
157
|
|
|
* @param array $params |
158
|
|
|
*/ |
159
|
|
|
private function validateParameters( array $params ): void { |
160
|
|
|
if ( !( $this->modificationHelper->validateStatementGuid( $params['claim'] ) ) ) { |
161
|
|
|
$this->errorReporter->dieError( 'Invalid claim guid', 'invalid-guid' ); |
|
|
|
|
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
if ( !isset( $params['snakhash'] ) ) { |
165
|
|
|
if ( !isset( $params['snaktype'] ) ) { |
166
|
|
|
$this->errorReporter->dieWithError( [ 'param-missing', 'snaktype' ], |
167
|
|
|
'param-missing' |
168
|
|
|
); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
if ( !isset( $params['property'] ) ) { |
172
|
|
|
$this->errorReporter->dieWithError( [ 'param-missing', 'property' ], |
173
|
|
|
'param-missing' |
174
|
|
|
); |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
if ( isset( $params['snaktype'] ) && $params['snaktype'] === 'value' && !isset( $params['value'] ) ) { |
179
|
|
|
$this->errorReporter->dieWithError( [ 'param-missing', 'value' ], |
180
|
|
|
'param-missing' |
181
|
|
|
); |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
private function validateQualifierHash( Statement $statement, string $qualifierHash ): void { |
186
|
|
|
if ( !$statement->getQualifiers()->hasSnakHash( $qualifierHash ) ) { |
187
|
|
|
$this->errorReporter->dieError( |
|
|
|
|
188
|
|
|
'Claim does not have a qualifier with the given hash', |
189
|
|
|
'no-such-qualifier' |
190
|
|
|
); |
191
|
|
|
} |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
private function getChangeOp(): ChangeOp { |
195
|
|
|
$params = $this->extractRequestParams(); |
196
|
|
|
|
197
|
|
|
$guid = $params['claim']; |
198
|
|
|
|
199
|
|
|
$propertyId = $this->modificationHelper->getEntityIdFromString( $params['property'] ); |
200
|
|
|
if ( !( $propertyId instanceof PropertyId ) ) { |
201
|
|
|
$this->errorReporter->dieWithError( |
202
|
|
|
[ 'wikibase-api-invalid-property-id', $propertyId->getSerialization() ], |
203
|
|
|
'param-illegal' |
204
|
|
|
); |
205
|
|
|
} |
206
|
|
|
$newQualifier = $this->modificationHelper->getSnakInstance( $params, $propertyId ); |
|
|
|
|
207
|
|
|
|
208
|
|
|
$snakHash = $params['snakhash'] ?? ''; |
209
|
|
|
$changeOp = $this->statementChangeOpFactory->newSetQualifierOp( $guid, $newQualifier, $snakHash ); |
210
|
|
|
|
211
|
|
|
return $changeOp; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* @inheritDoc |
216
|
|
|
*/ |
217
|
|
|
public function isWriteMode(): bool { |
218
|
|
|
return true; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* @see ApiBase::needsToken |
223
|
|
|
* |
224
|
|
|
* @return string |
225
|
|
|
*/ |
226
|
|
|
public function needsToken(): string { |
227
|
|
|
return 'csrf'; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* @inheritDoc |
232
|
|
|
*/ |
233
|
|
|
protected function getAllowedParams(): array { |
234
|
|
|
return array_merge( |
235
|
|
|
[ |
236
|
|
|
'claim' => [ |
237
|
|
|
self::PARAM_TYPE => 'string', |
238
|
|
|
self::PARAM_REQUIRED => true, |
239
|
|
|
], |
240
|
|
|
'property' => [ |
241
|
|
|
self::PARAM_TYPE => 'string', |
242
|
|
|
self::PARAM_REQUIRED => false, |
243
|
|
|
], |
244
|
|
|
'value' => [ |
245
|
|
|
self::PARAM_TYPE => 'text', |
246
|
|
|
self::PARAM_REQUIRED => false, |
247
|
|
|
], |
248
|
|
|
'snaktype' => [ |
249
|
|
|
self::PARAM_TYPE => [ 'value', 'novalue', 'somevalue' ], |
250
|
|
|
self::PARAM_REQUIRED => false, |
251
|
|
|
], |
252
|
|
|
'snakhash' => [ |
253
|
|
|
self::PARAM_TYPE => 'string', |
254
|
|
|
self::PARAM_REQUIRED => false, |
255
|
|
|
], |
256
|
|
|
'summary' => [ |
257
|
|
|
self::PARAM_TYPE => 'string', |
258
|
|
|
], |
259
|
|
|
'tags' => [ |
260
|
|
|
self::PARAM_TYPE => 'tags', |
261
|
|
|
self::PARAM_ISMULTI => true, |
262
|
|
|
], |
263
|
|
|
'token' => null, |
264
|
|
|
'baserevid' => [ |
265
|
|
|
self::PARAM_TYPE => 'integer', |
266
|
|
|
], |
267
|
|
|
'bot' => false, |
268
|
|
|
], |
269
|
|
|
parent::getAllowedParams() |
270
|
|
|
); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* @inheritDoc |
275
|
|
|
*/ |
276
|
|
|
protected function getExamplesMessages(): array { |
277
|
|
|
return [ |
278
|
|
|
'action=wbsetqualifier&claim=Q2$4554c0f4-47b2-1cd9-2db9-aa270064c9f3&property=P1' |
279
|
|
|
. '&value="GdyjxP8I6XB3"&snaktype=value&token=foobar' |
280
|
|
|
=> 'apihelp-wbsetqualifier-example-1', |
281
|
|
|
]; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
} |
285
|
|
|
|
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.