Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
78.57% |
44 / 56 |
|
28.57% |
2 / 7 |
CRAP | |
0.00% |
0 / 1 |
CheckConstraintsRdf | |
78.57% |
44 / 56 |
|
28.57% |
2 / 7 |
17.21 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
newFromGlobalState | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
getName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
requiresWrite | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
requiresUnblock | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
cleanupGuid | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
onView | |
95.12% |
39 / 41 |
|
0.00% |
0 / 1 |
9 |
1 | <?php |
2 | |
3 | namespace WikibaseQuality\ConstraintReport\Api; |
4 | |
5 | use Article; |
6 | use FormlessAction; |
7 | use MediaWiki\Context\IContextSource; |
8 | use Wikibase\Lib\Store\EntityIdLookup; |
9 | use Wikibase\Repo\Rdf\RdfVocabulary; |
10 | use Wikibase\Repo\WikibaseRepo; |
11 | use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult; |
12 | use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\NullResult; |
13 | use WikibaseQuality\ConstraintReport\ConstraintsServices; |
14 | use Wikimedia\Purtle\RdfWriterFactory; |
15 | |
16 | /** |
17 | * Produce constraint check results in RDF. |
18 | * Only returns cached constraint check results for now. |
19 | * |
20 | * @license GPL-2.0-or-later |
21 | */ |
22 | class CheckConstraintsRdf extends FormlessAction { |
23 | |
24 | /** |
25 | * @var EntityIdLookup |
26 | */ |
27 | private $entityIdLookup; |
28 | /** |
29 | * @var ResultsSource |
30 | */ |
31 | private $resultsSource; |
32 | /** |
33 | * @var RdfVocabulary |
34 | */ |
35 | private $rdfVocabulary; |
36 | |
37 | /** |
38 | * @param Article $page |
39 | * @param IContextSource $context |
40 | * @param ResultsSource $resultsSource |
41 | * @param EntityIdLookup $entityIdLookup |
42 | * @param RdfVocabulary $rdfVocabulary |
43 | */ |
44 | public function __construct( |
45 | object $page, |
46 | IContextSource $context, |
47 | ResultsSource $resultsSource, |
48 | EntityIdLookup $entityIdLookup, |
49 | RdfVocabulary $rdfVocabulary |
50 | ) { |
51 | parent::__construct( $page, $context ); |
52 | $this->resultsSource = $resultsSource; |
53 | $this->entityIdLookup = $entityIdLookup; |
54 | $this->rdfVocabulary = $rdfVocabulary; |
55 | } |
56 | |
57 | /** |
58 | * @param Article $page |
59 | * @param IContextSource $context |
60 | * @return CheckConstraintsRdf |
61 | */ |
62 | public static function newFromGlobalState( |
63 | object $page, |
64 | IContextSource $context |
65 | ) { |
66 | return new static( |
67 | $page, |
68 | $context, |
69 | ConstraintsServices::getResultsSource(), |
70 | WikibaseRepo::getEntityIdLookup(), |
71 | WikibaseRepo::getRdfVocabulary() |
72 | ); |
73 | } |
74 | |
75 | /** |
76 | * Return the name of the action this object responds to |
77 | * @since 1.17 |
78 | * |
79 | * @return string Lowercase name |
80 | */ |
81 | public function getName() { |
82 | return 'constraintsrdf'; |
83 | } |
84 | |
85 | /** |
86 | * Whether this action requires the wiki not to be locked |
87 | * @since 1.17 |
88 | * |
89 | * @return bool |
90 | */ |
91 | public function requiresWrite() { |
92 | return false; |
93 | } |
94 | |
95 | /** |
96 | * @see Action::requiresUnblock |
97 | * |
98 | * @return bool Always false. |
99 | */ |
100 | public function requiresUnblock() { |
101 | return false; |
102 | } |
103 | |
104 | /** |
105 | * Cleanup GUID string so it's OK for RDF. |
106 | * Should match what we're doing on RDF generation. |
107 | * @param string $guid |
108 | * @return string |
109 | */ |
110 | private function cleanupGuid( $guid ) { |
111 | return preg_replace( '/[^\w-]/', '-', $guid ); |
112 | } |
113 | |
114 | /** |
115 | * Show something on GET request. |
116 | * @return string|null Will be added to the HTMLForm if present, or just added to the |
117 | * output if not. Return null to not add anything |
118 | */ |
119 | public function onView() { |
120 | $response = $this->getRequest()->response(); |
121 | $this->getOutput()->disable(); |
122 | |
123 | if ( !$this->resultsSource instanceof CachingResultsSource ) { |
124 | // TODO: make configurable whether only cached results are returned |
125 | $response->statusHeader( 501 ); // Not Implemented |
126 | return null; |
127 | } |
128 | |
129 | $entityId = $this->entityIdLookup->getEntityIdForTitle( $this->getTitle() ); |
130 | if ( $entityId === null ) { |
131 | $response->statusHeader( 404 ); // Not Found |
132 | return null; |
133 | } |
134 | $revId = $this->getRequest()->getInt( 'revision' ); |
135 | |
136 | $results = $this->resultsSource->getStoredResults( $entityId, $revId ); |
137 | if ( $results === null ) { |
138 | $response->statusHeader( 204 ); // No Content |
139 | return null; |
140 | } |
141 | |
142 | $format = 'ttl'; // TODO: make format an option |
143 | |
144 | $writerFactory = new RdfWriterFactory(); |
145 | $formatName = $writerFactory->getFormatName( $format ); |
146 | $contentType = $writerFactory->getMimeTypes( $formatName )[0]; |
147 | |
148 | $writer = $writerFactory->getWriter( $formatName ); |
149 | foreach ( [ RdfVocabulary::NS_STATEMENT, RdfVocabulary::NS_ONTOLOGY ] as $ns ) { |
150 | $writer->prefix( $ns, $this->rdfVocabulary->getNamespaceURI( $ns ) ); |
151 | } |
152 | $writer->start(); |
153 | $writtenAny = false; |
154 | |
155 | foreach ( $results->getArray() as $checkResult ) { |
156 | if ( $checkResult instanceof NullResult ) { |
157 | continue; |
158 | } |
159 | if ( $checkResult->getStatus() === CheckResult::STATUS_BAD_PARAMETERS ) { |
160 | continue; |
161 | } |
162 | $writtenAny = true; |
163 | $writer->about( RdfVocabulary::NS_STATEMENT, |
164 | $this->cleanupGuid( $checkResult->getContextCursor()->getStatementGuid() ) ) |
165 | ->say( RdfVocabulary::NS_ONTOLOGY, 'hasViolationForConstraint' ) |
166 | ->is( RdfVocabulary::NS_STATEMENT, |
167 | $this->cleanupGuid( $checkResult->getConstraint()->getConstraintId() ) ); |
168 | } |
169 | $writer->finish(); |
170 | if ( $writtenAny ) { |
171 | $response->header( "Content-Type: $contentType; charset=UTF-8" ); |
172 | echo $writer->drain(); |
173 | } else { |
174 | // Do not output RDF if we haven't written any actual statements. Output 204 instead |
175 | $writer->drain(); |
176 | $response->statusHeader( 204 ); // No Content |
177 | } |
178 | return null; |
179 | } |
180 | |
181 | } |