1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace WikibaseQuality\ConstraintReport\Api; |
4
|
|
|
|
5
|
|
|
use FormlessAction; |
6
|
|
|
use IContextSource; |
7
|
|
|
use Page; |
8
|
|
|
use Wikibase\Rdf\RdfVocabulary; |
9
|
|
|
use Wikibase\Repo\WikibaseRepo; |
10
|
|
|
use Wikibase\Store\EntityIdLookup; |
11
|
|
|
use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult; |
12
|
|
|
use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\NullResult; |
13
|
|
|
use WikibaseQuality\ConstraintReport\ConstraintReportFactory; |
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
|
|
|
class CheckConstraintsRdf extends FormlessAction { |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var EntityIdLookup |
24
|
|
|
*/ |
25
|
|
|
private $entityIdLookup; |
26
|
|
|
/** |
27
|
|
|
* @var ResultsSource |
28
|
|
|
*/ |
29
|
|
|
private $resultsSource; |
30
|
|
|
/** |
31
|
|
|
* @var RdfVocabulary |
32
|
|
|
*/ |
33
|
|
|
private $rdfVocabulary; |
34
|
|
|
|
35
|
|
|
public function __construct( |
36
|
|
|
Page $page, |
37
|
|
|
IContextSource $context, |
38
|
|
|
ResultsSource $resultsSource, |
39
|
|
|
EntityIdLookup $entityIdLookup, |
40
|
|
|
RdfVocabulary $rdfVocabulary |
41
|
|
|
) { |
42
|
|
|
parent::__construct( $page, $context ); |
43
|
|
|
$this->resultsSource = $resultsSource; |
44
|
|
|
$this->entityIdLookup = $entityIdLookup; |
45
|
|
|
$this->rdfVocabulary = $rdfVocabulary; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
public static function newFromGlobalState( Page $page, IContextSource $context = null ) { |
49
|
|
|
$repo = WikibaseRepo::getDefaultInstance(); |
50
|
|
|
$constraintReportFactory = ConstraintReportFactory::getDefaultInstance(); |
51
|
|
|
|
52
|
|
|
return new static( |
53
|
|
|
$page, |
54
|
|
|
$context, |
55
|
|
|
$constraintReportFactory->getResultsSource(), |
56
|
|
|
$repo->getEntityIdLookup(), |
57
|
|
|
$repo->getRdfVocabulary() |
58
|
|
|
); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Return the name of the action this object responds to |
63
|
|
|
* @since 1.17 |
64
|
|
|
* |
65
|
|
|
* @return string Lowercase name |
66
|
|
|
*/ |
67
|
|
|
public function getName() { |
68
|
|
|
return 'constraintsrdf'; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Whether this action requires the wiki not to be locked |
73
|
|
|
* @since 1.17 |
74
|
|
|
* |
75
|
|
|
* @return bool |
76
|
|
|
*/ |
77
|
|
|
public function requiresWrite() { |
78
|
|
|
return false; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @see Action::requiresUnblock |
83
|
|
|
* |
84
|
|
|
* @return bool Always false. |
85
|
|
|
*/ |
86
|
|
|
public function requiresUnblock() { |
87
|
|
|
return false; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Cleanup GUID string so it's OK for RDF. |
92
|
|
|
* Should match what we're doing on RDF generation. |
93
|
|
|
* @param string $guid |
94
|
|
|
* @return string |
95
|
|
|
*/ |
96
|
|
|
private function cleanupGuid( $guid ) { |
97
|
|
|
return preg_replace( '/[^\w-]/', '-', $guid ); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Show something on GET request. |
102
|
|
|
* @return string|null Will be added to the HTMLForm if present, or just added to the |
103
|
|
|
* output if not. Return null to not add anything |
104
|
|
|
*/ |
105
|
|
|
public function onView() { |
106
|
|
|
$response = $this->getRequest()->response(); |
107
|
|
|
$this->getOutput()->disable(); |
108
|
|
|
|
109
|
|
|
if ( !$this->resultsSource instanceof CachingResultsSource ) { |
110
|
|
|
// TODO: make configurable whether only cached results are returned |
111
|
|
|
$response->statusHeader( 501 ); // Not Implemented |
112
|
|
|
return null; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$entityId = $this->entityIdLookup->getEntityIdForTitle( $this->getTitle() ); |
116
|
|
|
if ( $entityId === null ) { |
117
|
|
|
$response->statusHeader( 404 ); // Not Found |
118
|
|
|
return null; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
$results = $this->resultsSource->getStoredResults( $entityId ); |
122
|
|
|
if ( $results === null ) { |
123
|
|
|
$response->statusHeader( 204 ); // No Content |
124
|
|
|
return null; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
$format = 'ttl'; // TODO: make format an option |
128
|
|
|
|
129
|
|
|
$writerFactory = new RdfWriterFactory(); |
130
|
|
|
$formatName = $writerFactory->getFormatName( $format ); |
131
|
|
|
$contentType = $writerFactory->getMimeTypes( $formatName )[0]; |
|
|
|
|
132
|
|
|
|
133
|
|
|
$response->header( "Content-Type: $contentType; charset=UTF-8" ); |
134
|
|
|
|
135
|
|
|
$writer = $writerFactory->getWriter( $formatName ); |
|
|
|
|
136
|
|
|
foreach ( [ RdfVocabulary::NS_STATEMENT, RdfVocabulary::NS_ONTOLOGY ] as $ns ) { |
137
|
|
|
$writer->prefix( $ns, $this->rdfVocabulary->getNamespaceURI( $ns ) ); |
138
|
|
|
} |
139
|
|
|
$writer->start(); |
140
|
|
|
|
141
|
|
|
foreach ( $results->getArray() as $checkResult ) { |
142
|
|
|
if ( $checkResult instanceof NullResult ) { |
143
|
|
|
continue; |
144
|
|
|
} |
145
|
|
|
if ( $checkResult->getStatus() === CheckResult::STATUS_BAD_PARAMETERS ) { |
146
|
|
|
continue; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$writer->about( RdfVocabulary::NS_STATEMENT, |
150
|
|
|
$this->cleanupGuid( $checkResult->getContextCursor()->getStatementGuid() ) ) |
151
|
|
|
->say( RdfVocabulary::NS_ONTOLOGY, 'hasViolationForConstraint' ) |
152
|
|
|
->is( RdfVocabulary::NS_STATEMENT, |
153
|
|
|
$this->cleanupGuid( $checkResult->getConstraint()->getConstraintId() ) ); |
154
|
|
|
} |
155
|
|
|
$writer->finish(); |
156
|
|
|
echo $writer->drain(); |
157
|
|
|
return null; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
} |
161
|
|
|
|
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.