|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* A builder to build SPARQL queries. |
|
5
|
|
|
* |
|
6
|
|
|
* @since 3.1.7 |
|
7
|
|
|
*/ |
|
8
|
|
|
class Wordlift_Query_Builder { |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* The INSERT statement template. |
|
12
|
|
|
* |
|
13
|
|
|
* @since 3.1.7 |
|
14
|
|
|
*/ |
|
15
|
|
|
const INSERT = 'INSERT DATA { %s };'; |
|
16
|
|
|
|
|
17
|
|
|
/** |
|
18
|
|
|
* The DELETE statement template (it repeats the statements in the WHERE clause. |
|
19
|
|
|
* |
|
20
|
|
|
* @since 3.1.7 |
|
21
|
|
|
*/ |
|
22
|
|
|
const DELETE = 'DELETE { %s } WHERE { %1$s };'; |
|
23
|
|
|
|
|
24
|
|
|
/** |
|
25
|
|
|
* Tell the statement function to guess the object type (URI, value or parameter). |
|
26
|
|
|
* |
|
27
|
|
|
* @since 3.1.7 |
|
28
|
|
|
*/ |
|
29
|
|
|
const OBJECT_AUTO = - 1; |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* Tell the statement function that the object is a URI. |
|
33
|
|
|
* |
|
34
|
|
|
* @since 3.1.7 |
|
35
|
|
|
*/ |
|
36
|
|
|
const OBJECT_URI = 0; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* Tell the statement function that the object is a value. |
|
40
|
|
|
* |
|
41
|
|
|
* @since 3.1.7 |
|
42
|
|
|
*/ |
|
43
|
|
|
const OBJECT_VALUE = 1; |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Tell the statement function that the object is a parameter. |
|
47
|
|
|
* |
|
48
|
|
|
* @since 3.1.7 |
|
49
|
|
|
*/ |
|
50
|
|
|
const OBJECT_PARAMETER = 2; |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* The RDFS type. |
|
54
|
|
|
* |
|
55
|
|
|
* @since 3.1.7 |
|
56
|
|
|
*/ |
|
57
|
|
|
const RDFS_TYPE_URI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* The schema.org/Person type. |
|
61
|
|
|
* |
|
62
|
|
|
* @since 3.1.7 |
|
63
|
|
|
*/ |
|
64
|
|
|
const SCHEMA_PERSON_URI = 'http://schema.org/Person'; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* The schema.org given name predicate. |
|
68
|
|
|
* |
|
69
|
|
|
* @since 3.1.7 |
|
70
|
|
|
*/ |
|
71
|
|
|
const SCHEMA_GIVEN_NAME_URI = 'http://schema.org/givenName'; |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* The schema.org family name predicate. |
|
75
|
|
|
* |
|
76
|
|
|
* @since 3.1.7 |
|
77
|
|
|
*/ |
|
78
|
|
|
const SCHEMA_FAMILY_NAME_URI = 'http://schema.org/familyName'; |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* The schema.org url predicate. |
|
82
|
|
|
* |
|
83
|
|
|
* @since 3.1.7 |
|
84
|
|
|
*/ |
|
85
|
|
|
const SCHEMA_URL_URI = 'http://schema.org/url'; |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* @since 3.14.0 |
|
89
|
|
|
*/ |
|
90
|
|
|
const SCHEMA_IMAGE_URI = 'http://schema.org/image'; |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* The location created predicate. |
|
94
|
|
|
* |
|
95
|
|
|
* @since 3.14.0 |
|
96
|
|
|
*/ |
|
97
|
|
|
const SCHEMA_LOCATION_CREATED_URI = 'http://schema.org/locationCreated'; |
|
98
|
|
|
|
|
99
|
|
|
/** |
|
100
|
|
|
* @since 3.14.0 |
|
101
|
|
|
*/ |
|
102
|
|
|
const SCHEMA_AUTHOR_URI = 'http://schema.org/author'; |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* @since 3.14.0 |
|
106
|
|
|
*/ |
|
107
|
|
|
const SCHEMA_INTERACTION_COUNT_URI = 'http://schema.org/interactionCount'; |
|
108
|
|
|
|
|
109
|
|
|
/** |
|
110
|
|
|
* @since 3.14.0 |
|
111
|
|
|
*/ |
|
112
|
|
|
const DCTERMS_SUBJECT_URI = 'http://purl.org/dc/terms/subject'; |
|
113
|
|
|
|
|
114
|
|
|
/** |
|
115
|
|
|
* @since 3.14.0 |
|
116
|
|
|
*/ |
|
117
|
|
|
const DCTERMS_REFERENCES_URI = 'http://purl.org/dc/terms/references'; |
|
118
|
|
|
|
|
119
|
|
|
/** |
|
120
|
|
|
* The RDF label. |
|
121
|
|
|
* |
|
122
|
|
|
* @since 3.1.7 |
|
123
|
|
|
*/ |
|
124
|
|
|
const RDFS_LABEL_URI = 'http://www.w3.org/2000/01/rdf-schema#label'; |
|
125
|
|
|
|
|
126
|
|
|
/** |
|
127
|
|
|
* Hold the template (INSERT or DELETE). |
|
128
|
|
|
* |
|
129
|
|
|
* @since 3.1.7 |
|
130
|
|
|
* @access private |
|
131
|
|
|
* @var string $template The query template. |
|
132
|
|
|
*/ |
|
133
|
|
|
private $template; |
|
134
|
|
|
|
|
135
|
|
|
/** |
|
136
|
|
|
* An array of statements (in the form of subject, predicate, object). |
|
137
|
|
|
* |
|
138
|
|
|
* @since 3.1.7 |
|
139
|
|
|
* @access private |
|
140
|
|
|
* @var array $statements An array of statements. |
|
141
|
|
|
*/ |
|
142
|
|
|
private $statements = array(); |
|
143
|
|
|
|
|
144
|
|
|
/** |
|
145
|
|
|
* Create a new instance of the Query builder (compatible with PHP 5.3). |
|
146
|
|
|
* |
|
147
|
|
|
* @since 3.1.7 |
|
148
|
|
|
* @return Wordlift_Query_Builder A new instance of the Query builder. |
|
149
|
|
|
*/ |
|
150
|
|
|
public static function new_instance() { |
|
151
|
|
|
|
|
152
|
|
|
return new Wordlift_Query_Builder(); |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* Set the query to INSERT. |
|
157
|
|
|
* |
|
158
|
|
|
* @since 3.1.7 |
|
159
|
|
|
* @return Wordlift_Query_Builder The Query builder. |
|
160
|
|
|
*/ |
|
161
|
|
|
public function insert() { |
|
162
|
|
|
|
|
163
|
|
|
$this->template = self::INSERT; |
|
164
|
|
|
|
|
165
|
|
|
return $this; |
|
166
|
|
|
} |
|
167
|
|
|
|
|
168
|
|
|
/** |
|
169
|
|
|
* Set the query to DELETE. |
|
170
|
|
|
* |
|
171
|
|
|
* @since 3.1.7 |
|
172
|
|
|
* @return $this \Wordlift_Query_Builder The Query builder. |
|
173
|
|
|
*/ |
|
174
|
|
|
public function delete() { |
|
175
|
|
|
|
|
176
|
|
|
$this->template = self::DELETE; |
|
177
|
|
|
|
|
178
|
|
|
return $this; |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
/** |
|
182
|
|
|
* Set the query to SELECT. |
|
183
|
|
|
* |
|
184
|
|
|
* @since 3.12.2 |
|
185
|
|
|
* |
|
186
|
|
|
* @param string $props The list of properties to read. |
|
187
|
|
|
* |
|
188
|
|
|
* @return $this \Wordlift_Query_Builder The Query builder. |
|
189
|
|
|
*/ |
|
190
|
|
|
public function select( $props = '*' ) { |
|
191
|
|
|
|
|
192
|
|
|
$this->template = "SELECT $props WHERE { %s }"; |
|
193
|
|
|
|
|
194
|
|
|
return $this; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
/** |
|
198
|
|
|
* Add a statement. |
|
199
|
|
|
* |
|
200
|
|
|
* @since 3.1.7 |
|
201
|
|
|
* |
|
202
|
|
|
* @param string $subject The subject of the statement (must be a URI). |
|
203
|
|
|
* @param string $predicate The predicate (must be a URI). |
|
204
|
|
|
* @param string $object The object, can be a URI or a value. |
|
205
|
|
|
* @param int $object_type The object type, either a {@link OBJECT_URI} or a value {@link OBJECT_VALUE}. If set to {@link OBJECT_AUTO}, the Query builder will try to guess. |
|
206
|
|
|
* @param string|null $data_type The data type (or null). |
|
207
|
|
|
* @param string|null $language The language code (or null). |
|
208
|
|
|
* |
|
209
|
|
|
* @return $this \Wordlift_Query_Builder The Query builder. |
|
210
|
|
|
*/ |
|
211
|
|
|
public function statement( $subject, $predicate, $object, $object_type = self::OBJECT_AUTO, $data_type = null, $language = null ) { |
|
212
|
|
|
|
|
213
|
|
|
// If no value has been provided, we don't set any statement. |
|
214
|
|
|
if ( empty( $object ) ) { |
|
215
|
|
|
return $this; |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
// Guess the subject type. |
|
219
|
|
|
$subject_value_type = $this->guess_object_type( $predicate, $object ); |
|
220
|
|
|
|
|
221
|
|
|
// Get the object type if set, otherwise try to guess it. |
|
222
|
|
|
$object_value_type = ( self::OBJECT_AUTO === $object_type ? $this->guess_object_type( $predicate, $object ) : $object_type ); |
|
223
|
|
|
|
|
224
|
|
|
// Prepare the statement template. |
|
225
|
|
|
$template = |
|
226
|
|
|
// Subject as a parameter, no `<`, `>`. |
|
227
|
|
|
( self::OBJECT_PARAMETER === $subject_value_type ? '%1$s' : '<%1$s>' ) . |
|
228
|
|
|
// Predicate. |
|
229
|
|
|
' <%2$s> ' . |
|
230
|
|
|
// Object. |
|
231
|
|
|
( self::OBJECT_URI === $object_value_type ? '<%3$s>' : |
|
232
|
|
|
( self::OBJECT_PARAMETER === $object_value_type ? '%3$s' : |
|
233
|
|
|
// self::OBJECT_VALUE === $object_value_type |
|
|
|
|
|
|
234
|
|
|
'"%3$s"' . ( isset( $data_type ) ? '^^%4$s' : '' ) . ( isset( $language ) ? '@%5$s' : '' ) ) ); |
|
235
|
|
|
|
|
236
|
|
|
// Escape the subject, predicate and object. |
|
237
|
|
|
$escaped_subject = Wordlift_Sparql_Service::escape_uri( $subject ); |
|
238
|
|
|
$escaped_predicate = Wordlift_Sparql_Service::escape_uri( $predicate ); |
|
239
|
|
|
$escaped_object = ( self::OBJECT_URI === $object_value_type ? Wordlift_Sparql_Service::escape_uri( $object ) : Wordlift_Sparql_Service::escape( $object ) ); |
|
240
|
|
|
|
|
241
|
|
|
// Prepare the statement and add it to the list of statements. |
|
242
|
|
|
$this->statements[] = sprintf( $template, $escaped_subject, $escaped_predicate, $escaped_object, $data_type, $language ); |
|
243
|
|
|
|
|
244
|
|
|
return $this; |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
/** |
|
248
|
|
|
* Build the query. |
|
249
|
|
|
* |
|
250
|
|
|
* @since 3.1.7 |
|
251
|
|
|
* @return string The query string. |
|
252
|
|
|
*/ |
|
253
|
|
|
public function build() { |
|
254
|
|
|
|
|
255
|
|
|
// If there are no statements return an empty string. |
|
256
|
|
|
if ( 0 === count( $this->statements ) ) { |
|
257
|
|
|
return ''; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
return sprintf( $this->template, implode( ' . ', $this->statements ) ) . "\n"; |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
/** |
|
264
|
|
|
* Guess the statement object type. |
|
265
|
|
|
* |
|
266
|
|
|
* @since 3.1.7 |
|
267
|
|
|
* |
|
268
|
|
|
* @param string $predicate The predicate. |
|
269
|
|
|
* @param string $object The object. |
|
270
|
|
|
* |
|
271
|
|
|
* @return int {@link Wordlift_Query_Builder::OBJECT_URI} if the Query builder thinks the object must be an URI, {@link Wordlift_Query_Builder::OBJECT_VALUE} otherwise. |
|
272
|
|
|
*/ |
|
273
|
|
|
private function guess_object_type( $predicate, $object ) { |
|
274
|
|
|
|
|
275
|
|
|
// If the object starts with a question mark, it's a parameter. |
|
276
|
|
|
if ( 0 === strpos( $object, '?' ) ) { |
|
277
|
|
|
return self::OBJECT_PARAMETER; |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
// Guess based on the predicate. |
|
281
|
|
|
switch ( $predicate ) { |
|
282
|
|
|
|
|
283
|
|
|
case self::DCTERMS_REFERENCES_URI: |
|
284
|
|
|
case self::DCTERMS_SUBJECT_URI: |
|
285
|
|
|
case self::RDFS_TYPE_URI: |
|
286
|
|
|
case self::SCHEMA_AUTHOR_URI: |
|
287
|
|
|
case self::SCHEMA_LOCATION_CREATED_URI: |
|
288
|
|
|
case self::SCHEMA_URL_URI: |
|
289
|
|
|
case self::SCHEMA_IMAGE_URI: |
|
290
|
|
|
return self::OBJECT_URI; |
|
291
|
|
|
|
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
|
return self::OBJECT_VALUE; |
|
295
|
|
|
} |
|
296
|
|
|
|
|
297
|
|
|
} |
|
298
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.