Completed
Push — master ( f2f357...ccb861 )
by
unknown
02:21
created

CheckConstraints::newFromGlobalState()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 44
rs 9.216
c 0
b 0
f 0
cc 1
nc 1
nop 3
1
<?php
2
3
namespace WikibaseQuality\ConstraintReport\Api;
4
5
use ApiBase;
6
use ApiMain;
7
use IBufferingStatsdDataFactory;
8
use MediaWiki\MediaWikiServices;
9
use RequestContext;
10
use ValueFormatters\FormatterOptions;
11
use Wikibase\DataModel\Entity\EntityId;
12
use Wikibase\DataModel\Entity\EntityIdParser;
13
use Wikibase\DataModel\Entity\EntityIdParsingException;
14
use Wikibase\DataModel\Services\Statement\StatementGuidValidator;
15
use Wikibase\Lib\SnakFormatter;
16
use Wikibase\Repo\Api\ApiErrorReporter;
17
use Wikibase\Repo\Api\ApiHelperFactory;
18
use Wikibase\Repo\Api\ResultBuilder;
19
use Wikibase\Repo\EntityIdLabelFormatterFactory;
20
use Wikibase\Repo\WikibaseRepo;
21
use WikibaseQuality\ConstraintReport\ConstraintCheck\Message\MultilingualTextViolationMessageRenderer;
22
use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
23
use WikibaseQuality\ConstraintReport\ConstraintReportFactory;
24
25
/**
26
 * API module that performs constraint check of entities, claims and constraint ID
27
 *
28
 * @author Olga Bode
29
 * @license GPL-2.0-or-later
30
 */
31
class CheckConstraints extends ApiBase {
32
33
	const PARAM_ID = 'id';
34
	const PARAM_CLAIM_ID = 'claimid';
35
	const PARAM_CONSTRAINT_ID = 'constraintid';
36
	const PARAM_STATUS = 'status';
37
38
	/**
39
	 * @var EntityIdParser
40
	 */
41
	private $entityIdParser;
42
43
	/**
44
	 * @var StatementGuidValidator
45
	 */
46
	private $statementGuidValidator;
47
48
	/**
49
	 * @var ResultBuilder
50
	 */
51
	private $resultBuilder;
52
53
	/**
54
	 * @var ApiErrorReporter
55
	 */
56
	private $errorReporter;
57
58
	/**
59
	 * @var ResultsSource
60
	 */
61
	private $resultsSource;
62
63
	/**
64
	 * @var CheckResultsRenderer
65
	 */
66
	private $checkResultsRenderer;
67
68
	/**
69
	 * @var IBufferingStatsdDataFactory
70
	 */
71
	private $dataFactory;
72
73
	/**
74
	 * Creates new instance from global state.
75
	 *
76
	 * @param ApiMain $main
77
	 * @param string $name
78
	 * @param string $prefix
79
	 *
80
	 * @return self
81
	 */
82
	public static function newFromGlobalState( ApiMain $main, $name, $prefix = '' ) {
83
		$repo = WikibaseRepo::getDefaultInstance();
84
85
		$language = $repo->getUserLanguage();
86
		$formatterOptions = new FormatterOptions();
87
		$formatterOptions->setOption( SnakFormatter::OPT_LANG, $language->getCode() );
88
		$valueFormatterFactory = $repo->getValueFormatterFactory();
89
		$valueFormatter = $valueFormatterFactory->getValueFormatter( SnakFormatter::FORMAT_HTML, $formatterOptions );
90
91
		$languageFallbackLabelDescriptionLookupFactory = $repo->getLanguageFallbackLabelDescriptionLookupFactory();
92
		$labelDescriptionLookup = $languageFallbackLabelDescriptionLookupFactory->newLabelDescriptionLookup( $language );
93
		$entityIdHtmlLinkFormatterFactory = $repo->getEntityIdHtmlLinkFormatterFactory();
94
		$entityIdHtmlLinkFormatter = $entityIdHtmlLinkFormatterFactory->getEntityIdFormatter( $labelDescriptionLookup );
95
		$entityIdLabelFormatterFactory = new EntityIdLabelFormatterFactory();
96
		$entityIdLabelFormatter = $entityIdLabelFormatterFactory->getEntityIdFormatter( $labelDescriptionLookup );
97
		$config = MediaWikiServices::getInstance()->getMainConfig();
98
		$dataFactory = MediaWikiServices::getInstance()->getStatsdDataFactory();
99
		$constraintReportFactory = ConstraintReportFactory::getDefaultInstance();
100
101
		$checkResultsRenderer = new CheckResultsRenderer(
102
			$repo->getEntityTitleLookup(),
103
			$entityIdLabelFormatter,
104
			new MultilingualTextViolationMessageRenderer(
105
				$entityIdHtmlLinkFormatter,
106
				$valueFormatter,
107
				$main,
108
				$config
109
			),
110
			$config
111
		);
112
		$resultsSource = $constraintReportFactory->getResultsSource();
113
114
		return new CheckConstraints(
115
			$main,
116
			$name,
117
			$prefix,
118
			$repo->getEntityIdParser(),
119
			$repo->getStatementGuidValidator(),
120
			$repo->getApiHelperFactory( RequestContext::getMain() ),
121
			$resultsSource,
122
			$checkResultsRenderer,
123
			$dataFactory
124
		);
125
	}
126
127
	/**
128
	 * @param ApiMain $main
129
	 * @param string $name
130
	 * @param string $prefix
131
	 * @param EntityIdParser $entityIdParser
132
	 * @param StatementGuidValidator $statementGuidValidator
133
	 * @param ApiHelperFactory $apiHelperFactory
134
	 * @param ResultsSource $resultsSource
135
	 * @param CheckResultsRenderer $checkResultsRenderer
136
	 * @param IBufferingStatsdDataFactory $dataFactory
137
	 */
138
	public function __construct(
139
		ApiMain $main,
140
		$name,
141
		$prefix,
142
		EntityIdParser $entityIdParser,
143
		StatementGuidValidator $statementGuidValidator,
144
		ApiHelperFactory $apiHelperFactory,
145
		ResultsSource $resultsSource,
146
		CheckResultsRenderer $checkResultsRenderer,
147
		IBufferingStatsdDataFactory $dataFactory
148
	) {
149
		parent::__construct( $main, $name, $prefix );
150
		$this->entityIdParser = $entityIdParser;
151
		$this->statementGuidValidator = $statementGuidValidator;
152
		$this->resultBuilder = $apiHelperFactory->getResultBuilder( $this );
153
		$this->errorReporter = $apiHelperFactory->getErrorReporter( $this );
154
		$this->resultsSource = $resultsSource;
155
		$this->checkResultsRenderer = $checkResultsRenderer;
156
		$this->dataFactory = $dataFactory;
157
	}
158
159
	/**
160
	 * Evaluates the parameters, runs the requested constraint check, and sets up the result
161
	 */
162
	public function execute() {
163
		$this->dataFactory->increment(
164
			'wikibase.quality.constraints.api.checkConstraints.execute'
165
		);
166
167
		$params = $this->extractRequestParams();
168
169
		$this->validateParameters( $params );
170
		$entityIds = $this->parseEntityIds( $params );
171
		$claimIds = $this->parseClaimIds( $params );
172
		$constraintIDs = $params[self::PARAM_CONSTRAINT_ID];
173
		$statuses = $params[self::PARAM_STATUS];
174
175
		$this->getResult()->addValue(
176
			null,
177
			$this->getModuleName(),
178
			$this->checkResultsRenderer->render(
179
				$this->resultsSource->getResults(
180
					$entityIds,
181
					$claimIds,
182
					$constraintIDs,
183
					$statuses
184
				)
185
			)->getArray()
186
		);
187
		$this->resultBuilder->markSuccess( 1 );
188
	}
189
190
	/**
191
	 * @param array $params
192
	 *
193
	 * @return EntityId[]
194
	 */
195
	private function parseEntityIds( array $params ) {
196
		$ids = $params[self::PARAM_ID];
197
198
		if ( $ids === null ) {
199
			return [];
200
		} elseif ( $ids === [] ) {
201
			$this->errorReporter->dieError(
202
				'If ' . self::PARAM_ID . ' is specified, it must be nonempty.', 'no-data' );
203
		}
204
205
		return array_map( function ( $id ) {
206
			try {
207
				return $this->entityIdParser->parse( $id );
208
			} catch ( EntityIdParsingException $e ) {
209
				$this->errorReporter->dieError(
210
					"Invalid id: $id", 'invalid-entity-id', 0, [ self::PARAM_ID => $id ] );
211
			}
212
		}, $ids );
213
	}
214
215
	/**
216
	 * @param array $params
217
	 *
218
	 * @return string[]
219
	 */
220
	private function parseClaimIds( array $params ) {
221
		$ids = $params[self::PARAM_CLAIM_ID];
222
223
		if ( $ids === null ) {
224
			return [];
225
		} elseif ( $ids === [] ) {
226
			$this->errorReporter->dieError(
227
				'If ' . self::PARAM_CLAIM_ID . ' is specified, it must be nonempty.', 'no-data' );
228
		}
229
230
		foreach ( $ids as $id ) {
231
			if ( !$this->statementGuidValidator->validate( $id ) ) {
232
				$this->errorReporter->dieError(
233
					"Invalid claim id: $id", 'invalid-guid', 0, [ self::PARAM_CLAIM_ID => $id ] );
234
			}
235
		}
236
237
		return $ids;
238
	}
239
240
	private function validateParameters( array $params ) {
241
		if ( $params[self::PARAM_CONSTRAINT_ID] !== null
242
			 && empty( $params[self::PARAM_CONSTRAINT_ID] )
243
		) {
244
			$paramConstraintId = self::PARAM_CONSTRAINT_ID;
245
			$this->errorReporter->dieError(
246
				"If $paramConstraintId is specified, it must be nonempty.", 'no-data' );
247
		}
248
		if ( $params[self::PARAM_ID] === null && $params[self::PARAM_CLAIM_ID] === null ) {
249
			$paramId = self::PARAM_ID;
250
			$paramClaimId = self::PARAM_CLAIM_ID;
251
			$this->errorReporter->dieError(
252
				"At least one of $paramId, $paramClaimId must be specified.", 'no-data' );
253
		}
254
		// contents of PARAM_ID and PARAM_CLAIM_ID are validated by parse{Entity,Claim}Ids()
255
	}
256
257
	/**
258
	 * @return array[]
259
	 * @codeCoverageIgnore
260
	 */
261
	public function getAllowedParams() {
262
		return [
263
			self::PARAM_ID => [
264
				ApiBase::PARAM_TYPE => 'string',
265
				ApiBase::PARAM_ISMULTI => true,
266
			],
267
			self::PARAM_CLAIM_ID => [
268
				ApiBase::PARAM_TYPE => 'string',
269
				ApiBase::PARAM_ISMULTI => true,
270
			],
271
			self::PARAM_CONSTRAINT_ID => [
272
				ApiBase::PARAM_TYPE => 'string',
273
				ApiBase::PARAM_ISMULTI => true,
274
			],
275
			self::PARAM_STATUS => [
276
				ApiBase::PARAM_TYPE => [
277
					CheckResult::STATUS_COMPLIANCE,
278
					CheckResult::STATUS_VIOLATION,
279
					CheckResult::STATUS_WARNING,
280
					CheckResult::STATUS_EXCEPTION,
281
					CheckResult::STATUS_NOT_IN_SCOPE,
282
					CheckResult::STATUS_DEPRECATED,
283
					CheckResult::STATUS_BAD_PARAMETERS,
284
					CheckResult::STATUS_TODO,
285
				],
286
				ApiBase::PARAM_ISMULTI => true,
287
				ApiBase::PARAM_ALL => true,
288
				ApiBase::PARAM_DFLT => implode( '|', [
289
					CheckResult::STATUS_VIOLATION,
290
					CheckResult::STATUS_WARNING,
291
					CheckResult::STATUS_BAD_PARAMETERS,
292
				] ),
293
				ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
294
			],
295
		];
296
	}
297
298
	/**
299
	 * Returns usage examples for this module
300
	 *
301
	 * @return string[]
302
	 * @codeCoverageIgnore
303
	 */
304
	public function getExamplesMessages() {
305
		return [
306
			'action=wbcheckconstraints&id=Q5|Q42'
307
				=> 'apihelp-wbcheckconstraints-example-1',
308
			'action=wbcheckconstraints&claimid=q42%248419C20C-8EF8-4EC0-80D6-AF1CA55E7557'
309
				=> 'apihelp-wbcheckconstraints-example-2',
310
			'action=wbcheckconstraints&format=json&id=Q2&constraintid=P1082%24DA39C2DA-47DA-48FB-8A9A-DA80200FB2DB'
311
				=> 'apihelp-wbcheckconstraints-example-3',
312
		];
313
	}
314
315
}
316