Completed
Push — master ( 0dfa46...acf0fe )
by
unknown
02:06 queued 10s
created

CheckConstraints::getExamplesMessages()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace WikibaseQuality\ConstraintReport\Api;
4
5
use ApiBase;
6
use ApiMain;
7
use Config;
8
use IBufferingStatsdDataFactory;
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\Formatters\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
24
/**
25
 * API module that performs constraint check of entities, claims and constraint ID
26
 *
27
 * @author Olga Bode
28
 * @license GPL-2.0-or-later
29
 */
30
class CheckConstraints extends ApiBase {
31
32
	const PARAM_ID = 'id';
33
	const PARAM_CLAIM_ID = 'claimid';
34
	const PARAM_CONSTRAINT_ID = 'constraintid';
35
	const PARAM_STATUS = 'status';
36
37
	/**
38
	 * @var EntityIdParser
39
	 */
40
	private $entityIdParser;
41
42
	/**
43
	 * @var StatementGuidValidator
44
	 */
45
	private $statementGuidValidator;
46
47
	/**
48
	 * @var ResultBuilder
49
	 */
50
	private $resultBuilder;
51
52
	/**
53
	 * @var ApiErrorReporter
54
	 */
55
	private $errorReporter;
56
57
	/**
58
	 * @var ResultsSource
59
	 */
60
	private $resultsSource;
61
62
	/**
63
	 * @var CheckResultsRenderer
64
	 */
65
	private $checkResultsRenderer;
66
67
	/**
68
	 * @var IBufferingStatsdDataFactory
69
	 */
70
	private $dataFactory;
71
72
	public static function factory(
73
		ApiMain $main,
74
		string $name,
75
		Config $config,
76
		IBufferingStatsdDataFactory $dataFactory,
77
		EntityIdParser $entityIdParser,
78
		ResultsSource $resultsSource
79
	): self {
80
		$repo = WikibaseRepo::getDefaultInstance();
81
82
		$language = $repo->getUserLanguage();
83
		$formatterOptions = new FormatterOptions();
84
		$formatterOptions->setOption( SnakFormatter::OPT_LANG, $language->getCode() );
85
		$valueFormatterFactory = $repo->getValueFormatterFactory();
86
		$valueFormatter = $valueFormatterFactory->getValueFormatter( SnakFormatter::FORMAT_HTML, $formatterOptions );
87
88
		$entityIdHtmlLinkFormatterFactory = $repo->getEntityIdHtmlLinkFormatterFactory();
89
		$entityIdHtmlLinkFormatter = $entityIdHtmlLinkFormatterFactory->getEntityIdFormatter( $language );
90
		$entityIdLabelFormatterFactory = new EntityIdLabelFormatterFactory();
91
		$entityIdLabelFormatter = $entityIdLabelFormatterFactory->getEntityIdFormatter( $language );
92
93
		$checkResultsRenderer = new CheckResultsRenderer(
94
			$repo->getEntityTitleLookup(),
95
			$entityIdLabelFormatter,
96
			new MultilingualTextViolationMessageRenderer(
97
				$entityIdHtmlLinkFormatter,
98
				$valueFormatter,
99
				$main,
100
				$config
101
			)
102
		);
103
104
		return new self(
105
			$main,
106
			$name,
107
			$entityIdParser,
108
			$repo->getStatementGuidValidator(),
109
			$repo->getApiHelperFactory( RequestContext::getMain() ),
110
			$resultsSource,
111
			$checkResultsRenderer,
112
			$dataFactory
113
		);
114
	}
115
116
	/**
117
	 * @param ApiMain $main
118
	 * @param string $name
119
	 * @param EntityIdParser $entityIdParser
120
	 * @param StatementGuidValidator $statementGuidValidator
121
	 * @param ApiHelperFactory $apiHelperFactory
122
	 * @param ResultsSource $resultsSource
123
	 * @param CheckResultsRenderer $checkResultsRenderer
124
	 * @param IBufferingStatsdDataFactory $dataFactory
125
	 */
126
	public function __construct(
127
		ApiMain $main,
128
		$name,
129
		EntityIdParser $entityIdParser,
130
		StatementGuidValidator $statementGuidValidator,
131
		ApiHelperFactory $apiHelperFactory,
132
		ResultsSource $resultsSource,
133
		CheckResultsRenderer $checkResultsRenderer,
134
		IBufferingStatsdDataFactory $dataFactory
135
	) {
136
		parent::__construct( $main, $name );
137
		$this->entityIdParser = $entityIdParser;
138
		$this->statementGuidValidator = $statementGuidValidator;
139
		$this->resultBuilder = $apiHelperFactory->getResultBuilder( $this );
140
		$this->errorReporter = $apiHelperFactory->getErrorReporter( $this );
141
		$this->resultsSource = $resultsSource;
142
		$this->checkResultsRenderer = $checkResultsRenderer;
143
		$this->dataFactory = $dataFactory;
144
	}
145
146
	/**
147
	 * Evaluates the parameters, runs the requested constraint check, and sets up the result
148
	 */
149
	public function execute() {
150
		$this->dataFactory->increment(
151
			'wikibase.quality.constraints.api.checkConstraints.execute'
152
		);
153
154
		$params = $this->extractRequestParams();
155
156
		$this->validateParameters( $params );
157
		$entityIds = $this->parseEntityIds( $params );
158
		$claimIds = $this->parseClaimIds( $params );
159
		$constraintIDs = $params[self::PARAM_CONSTRAINT_ID];
160
		$statuses = $params[self::PARAM_STATUS];
161
162
		$this->getResult()->addValue(
163
			null,
164
			$this->getModuleName(),
165
			$this->checkResultsRenderer->render(
166
				$this->resultsSource->getResults(
167
					$entityIds,
168
					$claimIds,
169
					$constraintIDs,
170
					$statuses
171
				)
172
			)->getArray()
173
		);
174
		$this->resultBuilder->markSuccess( 1 );
175
	}
176
177
	/**
178
	 * @param array $params
179
	 *
180
	 * @return EntityId[]
181
	 */
182
	private function parseEntityIds( array $params ) {
183
		$ids = $params[self::PARAM_ID];
184
185 View Code Duplication
		if ( $ids === null ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
			return [];
187
		} elseif ( $ids === [] ) {
188
			$this->errorReporter->dieError(
189
				'If ' . self::PARAM_ID . ' is specified, it must be nonempty.', 'no-data' );
190
		}
191
192
		return array_map( function ( $id ) {
193
			try {
194
				return $this->entityIdParser->parse( $id );
195
			} catch ( EntityIdParsingException $e ) {
196
				$this->errorReporter->dieError(
197
					"Invalid id: $id", 'invalid-entity-id', 0, [ self::PARAM_ID => $id ] );
198
			}
199
		}, $ids );
200
	}
201
202
	/**
203
	 * @param array $params
204
	 *
205
	 * @return string[]
206
	 */
207
	private function parseClaimIds( array $params ) {
208
		$ids = $params[self::PARAM_CLAIM_ID];
209
210 View Code Duplication
		if ( $ids === null ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
			return [];
212
		} elseif ( $ids === [] ) {
213
			$this->errorReporter->dieError(
214
				'If ' . self::PARAM_CLAIM_ID . ' is specified, it must be nonempty.', 'no-data' );
215
		}
216
217
		foreach ( $ids as $id ) {
218
			if ( !$this->statementGuidValidator->validate( $id ) ) {
219
				$this->errorReporter->dieError(
220
					"Invalid claim id: $id", 'invalid-guid', 0, [ self::PARAM_CLAIM_ID => $id ] );
221
			}
222
		}
223
224
		return $ids;
225
	}
226
227
	private function validateParameters( array $params ) {
228
		if ( $params[self::PARAM_CONSTRAINT_ID] !== null
229
			 && empty( $params[self::PARAM_CONSTRAINT_ID] )
230
		) {
231
			$paramConstraintId = self::PARAM_CONSTRAINT_ID;
232
			$this->errorReporter->dieError(
233
				"If $paramConstraintId is specified, it must be nonempty.", 'no-data' );
234
		}
235
		if ( $params[self::PARAM_ID] === null && $params[self::PARAM_CLAIM_ID] === null ) {
236
			$paramId = self::PARAM_ID;
237
			$paramClaimId = self::PARAM_CLAIM_ID;
238
			$this->errorReporter->dieError(
239
				"At least one of $paramId, $paramClaimId must be specified.", 'no-data' );
240
		}
241
		// contents of PARAM_ID and PARAM_CLAIM_ID are validated by parse{Entity,Claim}Ids()
242
	}
243
244
	/**
245
	 * @return array[]
246
	 * @codeCoverageIgnore
247
	 */
248
	public function getAllowedParams() {
249
		return [
250
			self::PARAM_ID => [
251
				ApiBase::PARAM_TYPE => 'string',
252
				ApiBase::PARAM_ISMULTI => true,
253
			],
254
			self::PARAM_CLAIM_ID => [
255
				ApiBase::PARAM_TYPE => 'string',
256
				ApiBase::PARAM_ISMULTI => true,
257
			],
258
			self::PARAM_CONSTRAINT_ID => [
259
				ApiBase::PARAM_TYPE => 'string',
260
				ApiBase::PARAM_ISMULTI => true,
261
			],
262
			self::PARAM_STATUS => [
263
				ApiBase::PARAM_TYPE => [
264
					CheckResult::STATUS_COMPLIANCE,
265
					CheckResult::STATUS_VIOLATION,
266
					CheckResult::STATUS_WARNING,
267
					CheckResult::STATUS_SUGGESTION,
268
					CheckResult::STATUS_EXCEPTION,
269
					CheckResult::STATUS_NOT_IN_SCOPE,
270
					CheckResult::STATUS_DEPRECATED,
271
					CheckResult::STATUS_BAD_PARAMETERS,
272
					CheckResult::STATUS_TODO,
273
				],
274
				ApiBase::PARAM_ISMULTI => true,
275
				ApiBase::PARAM_ALL => true,
276
				ApiBase::PARAM_DFLT => implode( '|', CachingResultsSource::CACHED_STATUSES ),
277
				ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
278
			],
279
		];
280
	}
281
282
	/**
283
	 * Returns usage examples for this module
284
	 *
285
	 * @return string[]
286
	 * @codeCoverageIgnore
287
	 */
288
	public function getExamplesMessages() {
289
		return [
290
			'action=wbcheckconstraints&id=Q5|Q42'
291
				=> 'apihelp-wbcheckconstraints-example-1',
292
			'action=wbcheckconstraints&claimid=q42%248419C20C-8EF8-4EC0-80D6-AF1CA55E7557'
293
				=> 'apihelp-wbcheckconstraints-example-2',
294
			'action=wbcheckconstraints&format=json&id=Q2&constraintid=P1082%24DA39C2DA-47DA-48FB-8A9A-DA80200FB2DB'
295
				=> 'apihelp-wbcheckconstraints-example-3',
296
		];
297
	}
298
299
}
300