Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
60.49% |
49 / 81 |
|
33.33% |
2 / 6 |
CRAP | |
0.00% |
0 / 1 |
CheckConstraints | |
60.49% |
49 / 81 |
|
33.33% |
2 / 6 |
41.26 | |
0.00% |
0 / 1 |
factory | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
__construct | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
1 | |||
parseEntityIds | |
58.33% |
7 / 12 |
|
0.00% |
0 / 1 |
5.16 | |||
parseClaimIds | |
63.64% |
7 / 11 |
|
0.00% |
0 / 1 |
6.20 | |||
validateParameters | |
30.00% |
3 / 10 |
|
0.00% |
0 / 1 |
13.57 | |||
getAllowedParams | n/a |
0 / 0 |
n/a |
0 / 0 |
1 | |||||
getExamplesMessages | n/a |
0 / 0 |
n/a |
0 / 0 |
1 |
1 | <?php |
2 | |
3 | declare( strict_types = 1 ); |
4 | |
5 | namespace WikibaseQuality\ConstraintReport\Api; |
6 | |
7 | use MediaWiki\Api\ApiBase; |
8 | use MediaWiki\Api\ApiMain; |
9 | use Wikibase\DataModel\Entity\EntityId; |
10 | use Wikibase\DataModel\Entity\EntityIdParser; |
11 | use Wikibase\DataModel\Entity\EntityIdParsingException; |
12 | use Wikibase\DataModel\Services\Statement\StatementGuidValidator; |
13 | use Wikibase\Lib\LanguageFallbackChainFactory; |
14 | use Wikibase\Lib\Store\EntityTitleLookup; |
15 | use Wikibase\Repo\Api\ApiErrorReporter; |
16 | use Wikibase\Repo\Api\ApiHelperFactory; |
17 | use Wikibase\Repo\Api\ResultBuilder; |
18 | use Wikibase\Repo\EntityIdLabelFormatterFactory; |
19 | use WikibaseQuality\ConstraintReport\ConstraintCheck\Message\ViolationMessageRendererFactory; |
20 | use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult; |
21 | use Wikimedia\ParamValidator\ParamValidator; |
22 | use Wikimedia\Stats\IBufferingStatsdDataFactory; |
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 | public const PARAM_ID = 'id'; |
33 | public const PARAM_CLAIM_ID = 'claimid'; |
34 | public const PARAM_CONSTRAINT_ID = 'constraintid'; |
35 | public const PARAM_STATUS = 'status'; |
36 | |
37 | private EntityIdParser $entityIdParser; |
38 | private StatementGuidValidator $statementGuidValidator; |
39 | private ResultBuilder $resultBuilder; |
40 | private ApiErrorReporter $errorReporter; |
41 | private ResultsSource $resultsSource; |
42 | private CheckResultsRendererFactory $checkResultsRendererFactory; |
43 | private IBufferingStatsdDataFactory $dataFactory; |
44 | |
45 | public static function factory( |
46 | ApiMain $main, |
47 | string $name, |
48 | IBufferingStatsdDataFactory $dataFactory, |
49 | ApiHelperFactory $apiHelperFactory, |
50 | EntityIdLabelFormatterFactory $entityIdLabelFormatterFactory, |
51 | EntityIdParser $entityIdParser, |
52 | EntityTitleLookup $entityTitleLookup, |
53 | LanguageFallbackChainFactory $languageFallbackChainFactory, |
54 | StatementGuidValidator $statementGuidValidator, |
55 | ResultsSource $resultsSource, |
56 | ViolationMessageRendererFactory $violationMessageRendererFactory |
57 | ): self { |
58 | $checkResultsRendererFactory = new CheckResultsRendererFactory( |
59 | $entityTitleLookup, |
60 | $entityIdLabelFormatterFactory, |
61 | $languageFallbackChainFactory, |
62 | $violationMessageRendererFactory |
63 | ); |
64 | |
65 | return new self( |
66 | $main, |
67 | $name, |
68 | $entityIdParser, |
69 | $statementGuidValidator, |
70 | $apiHelperFactory, |
71 | $resultsSource, |
72 | $checkResultsRendererFactory, |
73 | $dataFactory |
74 | ); |
75 | } |
76 | |
77 | public function __construct( |
78 | ApiMain $main, |
79 | string $name, |
80 | EntityIdParser $entityIdParser, |
81 | StatementGuidValidator $statementGuidValidator, |
82 | ApiHelperFactory $apiHelperFactory, |
83 | ResultsSource $resultsSource, |
84 | CheckResultsRendererFactory $checkResultsRendererFactory, |
85 | IBufferingStatsdDataFactory $dataFactory |
86 | ) { |
87 | parent::__construct( $main, $name ); |
88 | $this->entityIdParser = $entityIdParser; |
89 | $this->statementGuidValidator = $statementGuidValidator; |
90 | $this->resultBuilder = $apiHelperFactory->getResultBuilder( $this ); |
91 | $this->errorReporter = $apiHelperFactory->getErrorReporter( $this ); |
92 | $this->resultsSource = $resultsSource; |
93 | $this->checkResultsRendererFactory = $checkResultsRendererFactory; |
94 | $this->dataFactory = $dataFactory; |
95 | } |
96 | |
97 | /** |
98 | * Evaluates the parameters, runs the requested constraint check, and sets up the result |
99 | */ |
100 | public function execute() { |
101 | $this->dataFactory->increment( |
102 | 'wikibase.quality.constraints.api.checkConstraints.execute' |
103 | ); |
104 | |
105 | $params = $this->extractRequestParams(); |
106 | |
107 | $this->validateParameters( $params ); |
108 | $entityIds = $this->parseEntityIds( $params ); |
109 | $claimIds = $this->parseClaimIds( $params ); |
110 | $constraintIDs = $params[self::PARAM_CONSTRAINT_ID]; |
111 | $statuses = $params[self::PARAM_STATUS]; |
112 | |
113 | $checkResultsRenderer = $this->checkResultsRendererFactory |
114 | ->getCheckResultsRenderer( $this->getLanguage(), $this ); |
115 | |
116 | $this->getResult()->addValue( |
117 | null, |
118 | $this->getModuleName(), |
119 | $checkResultsRenderer->render( |
120 | $this->resultsSource->getResults( |
121 | $entityIds, |
122 | $claimIds, |
123 | $constraintIDs, |
124 | $statuses |
125 | ) |
126 | )->getArray() |
127 | ); |
128 | $this->resultBuilder->markSuccess( 1 ); |
129 | } |
130 | |
131 | /** |
132 | * @param array $params |
133 | * |
134 | * @return EntityId[] |
135 | */ |
136 | private function parseEntityIds( array $params ): array { |
137 | $ids = $params[self::PARAM_ID]; |
138 | |
139 | if ( $ids === null ) { |
140 | return []; |
141 | } elseif ( $ids === [] ) { |
142 | $this->errorReporter->dieError( |
143 | 'If ' . self::PARAM_ID . ' is specified, it must be nonempty.', 'no-data' ); |
144 | } |
145 | |
146 | return array_map( function ( $id ) { |
147 | try { |
148 | return $this->entityIdParser->parse( $id ); |
149 | } catch ( EntityIdParsingException $e ) { |
150 | $this->errorReporter->dieError( |
151 | "Invalid id: $id", 'invalid-entity-id', 0, [ self::PARAM_ID => $id ] ); |
152 | } |
153 | }, $ids ); |
154 | } |
155 | |
156 | /** |
157 | * @param array $params |
158 | * |
159 | * @return string[] |
160 | */ |
161 | private function parseClaimIds( array $params ): array { |
162 | $ids = $params[self::PARAM_CLAIM_ID]; |
163 | |
164 | if ( $ids === null ) { |
165 | return []; |
166 | } elseif ( $ids === [] ) { |
167 | $this->errorReporter->dieError( |
168 | 'If ' . self::PARAM_CLAIM_ID . ' is specified, it must be nonempty.', 'no-data' ); |
169 | } |
170 | |
171 | foreach ( $ids as $id ) { |
172 | if ( !$this->statementGuidValidator->validate( $id ) ) { |
173 | $this->errorReporter->dieError( |
174 | "Invalid claim id: $id", 'invalid-guid', 0, [ self::PARAM_CLAIM_ID => $id ] ); |
175 | } |
176 | } |
177 | |
178 | return $ids; |
179 | } |
180 | |
181 | private function validateParameters( array $params ): void { |
182 | if ( $params[self::PARAM_CONSTRAINT_ID] !== null |
183 | && empty( $params[self::PARAM_CONSTRAINT_ID] ) |
184 | ) { |
185 | $paramConstraintId = self::PARAM_CONSTRAINT_ID; |
186 | $this->errorReporter->dieError( |
187 | "If $paramConstraintId is specified, it must be nonempty.", 'no-data' ); |
188 | } |
189 | if ( $params[self::PARAM_ID] === null && $params[self::PARAM_CLAIM_ID] === null ) { |
190 | $paramId = self::PARAM_ID; |
191 | $paramClaimId = self::PARAM_CLAIM_ID; |
192 | $this->errorReporter->dieError( |
193 | "At least one of $paramId, $paramClaimId must be specified.", 'no-data' ); |
194 | } |
195 | // contents of PARAM_ID and PARAM_CLAIM_ID are validated by parse{Entity,Claim}Ids() |
196 | } |
197 | |
198 | /** |
199 | * @return array[] |
200 | * @codeCoverageIgnore |
201 | */ |
202 | public function getAllowedParams() { |
203 | return [ |
204 | self::PARAM_ID => [ |
205 | ParamValidator::PARAM_TYPE => 'string', |
206 | ParamValidator::PARAM_ISMULTI => true, |
207 | ], |
208 | self::PARAM_CLAIM_ID => [ |
209 | ParamValidator::PARAM_TYPE => 'string', |
210 | ParamValidator::PARAM_ISMULTI => true, |
211 | ], |
212 | self::PARAM_CONSTRAINT_ID => [ |
213 | ParamValidator::PARAM_TYPE => 'string', |
214 | ParamValidator::PARAM_ISMULTI => true, |
215 | ], |
216 | self::PARAM_STATUS => [ |
217 | ParamValidator::PARAM_TYPE => [ |
218 | CheckResult::STATUS_COMPLIANCE, |
219 | CheckResult::STATUS_VIOLATION, |
220 | CheckResult::STATUS_WARNING, |
221 | CheckResult::STATUS_SUGGESTION, |
222 | CheckResult::STATUS_EXCEPTION, |
223 | CheckResult::STATUS_NOT_IN_SCOPE, |
224 | CheckResult::STATUS_DEPRECATED, |
225 | CheckResult::STATUS_BAD_PARAMETERS, |
226 | CheckResult::STATUS_TODO, |
227 | ], |
228 | ParamValidator::PARAM_ISMULTI => true, |
229 | ParamValidator::PARAM_ALL => true, |
230 | ParamValidator::PARAM_DEFAULT => implode( '|', CachingResultsSource::CACHED_STATUSES ), |
231 | ApiBase::PARAM_HELP_MSG_PER_VALUE => [], |
232 | ], |
233 | ]; |
234 | } |
235 | |
236 | /** |
237 | * Returns usage examples for this module |
238 | * |
239 | * @return string[] |
240 | * @codeCoverageIgnore |
241 | */ |
242 | public function getExamplesMessages() { |
243 | return [ |
244 | 'action=wbcheckconstraints&id=Q5|Q42' |
245 | => 'apihelp-wbcheckconstraints-example-1', |
246 | 'action=wbcheckconstraints&claimid=q42%248419C20C-8EF8-4EC0-80D6-AF1CA55E7557' |
247 | => 'apihelp-wbcheckconstraints-example-2', |
248 | 'action=wbcheckconstraints&format=json&id=Q2&constraintid=P1082%24DA39C2DA-47DA-48FB-8A9A-DA80200FB2DB' |
249 | => 'apihelp-wbcheckconstraints-example-3', |
250 | ]; |
251 | } |
252 | |
253 | } |