|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Services: Linked Data Service. |
|
4
|
|
|
* |
|
5
|
|
|
* A service to handle data to be pushed to the remote Linked Data store. |
|
6
|
|
|
* |
|
7
|
|
|
* @since 3.15.0 |
|
8
|
|
|
* @package Wordlift |
|
9
|
|
|
* @subpackage Wordlift/includes |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
/** |
|
13
|
|
|
* Define the {@link Wordlift_Linked_Data_Service} class. |
|
14
|
|
|
* |
|
15
|
|
|
* @since 3.15.0 |
|
16
|
|
|
* @package Wordlift |
|
17
|
|
|
* @subpackage Wordlift/includes |
|
18
|
|
|
*/ |
|
19
|
|
|
class Wordlift_Linked_Data_Service { |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* A {@link Wordlift_Log_Service} instance. |
|
23
|
|
|
* |
|
24
|
|
|
* @since 3.15.0 |
|
25
|
|
|
* @access private |
|
26
|
|
|
* @var \Wordlift_Log_Service $log A {@link Wordlift_Log_Service} instance. |
|
27
|
|
|
*/ |
|
28
|
|
|
private $log; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* The {@link Wordlift_Entity_Service} instance. |
|
32
|
|
|
* |
|
33
|
|
|
* @since 3.15.0 |
|
34
|
|
|
* @access private |
|
35
|
|
|
* @var \Wordlift_Entity_Service $entity_service The {@link Wordlift_Entity_Service} instance. |
|
36
|
|
|
*/ |
|
37
|
|
|
private $entity_service; |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* The {@link Wordlift_Entity_Type_Service} instance. |
|
41
|
|
|
* |
|
42
|
|
|
* @since 3.15.0 |
|
43
|
|
|
* @access private |
|
44
|
|
|
* @var \Wordlift_Entity_Type_Service $entity_type_service The {@link Wordlift_Entity_Type_Service} instance. |
|
45
|
|
|
*/ |
|
46
|
|
|
private $entity_type_service; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* The {@link Wordlift_Schema_Service} instance. |
|
50
|
|
|
* |
|
51
|
|
|
* @since 3.15.0 |
|
52
|
|
|
* @access private |
|
53
|
|
|
* @var \Wordlift_Schema_Service $schema_service The {@link Wordlift_Schema_Service} instance. |
|
54
|
|
|
*/ |
|
55
|
|
|
private $schema_service; |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* The {@link Wordlift_Linked_Data_Service} singleton instance. |
|
59
|
|
|
* |
|
60
|
|
|
* @since 3.15.0 |
|
61
|
|
|
* @access private |
|
62
|
|
|
* @var \Wordlift_Linked_Data_Service $instance The {@link Wordlift_Linked_Data_Service} singleton instance. |
|
63
|
|
|
*/ |
|
64
|
|
|
private static $instance; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* The {@link Wordlift_Sparql_Service} instance. |
|
68
|
|
|
* |
|
69
|
|
|
* @since 3.15.0 |
|
70
|
|
|
* @access private |
|
71
|
|
|
* @var \Wordlift_Sparql_Service $sparql_service The {@link Wordlift_Sparql_Service} instance. |
|
72
|
|
|
*/ |
|
73
|
|
|
private $sparql_service; |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* Create a {@link Wordlift_Linked_Data_Service} instance. |
|
77
|
|
|
* |
|
78
|
|
|
* @since 3.15.0 |
|
79
|
|
|
* |
|
80
|
|
|
* @param \Wordlift_Entity_Service $entity_service The {@link Wordlift_Entity_Service} instance. |
|
81
|
|
|
* @param \Wordlift_Entity_Type_Service $entity_type_service The {@link Wordlift_Entity_Type_Service} instance. |
|
82
|
|
|
* @param \Wordlift_Schema_Service $schema_service The {@link Wordlift_Schema_Service} instance. |
|
83
|
|
|
* @param \Wordlift_Sparql_Service $sparql_service The {@link Wordlift_Sparql_Service} instance. |
|
84
|
|
|
*/ |
|
85
|
|
View Code Duplication |
public function __construct( $entity_service, $entity_type_service, $schema_service, $sparql_service ) { |
|
|
|
|
|
|
86
|
|
|
|
|
87
|
|
|
$this->log = Wordlift_Log_Service::get_logger( 'Wordlift_Linked_Data_Service' ); |
|
88
|
|
|
|
|
89
|
|
|
$this->entity_service = $entity_service; |
|
90
|
|
|
$this->entity_type_service = $entity_type_service; |
|
91
|
|
|
$this->schema_service = $schema_service; |
|
92
|
|
|
$this->sparql_service = $sparql_service; |
|
93
|
|
|
|
|
94
|
|
|
self::$instance = $this; |
|
95
|
|
|
|
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* Get the singleton instance of {@link Wordlift_Linked_Data_Service}. |
|
100
|
|
|
* |
|
101
|
|
|
* @since 3.15.0 |
|
102
|
|
|
* |
|
103
|
|
|
* @return Wordlift_Linked_Data_Service The singleton instance of <a href='psi_element://Wordlift_Linked_Data_Service'>Wordlift_Linked_Data_Service</a>. |
|
104
|
|
|
*/ |
|
105
|
|
|
public static function get_instance() { |
|
106
|
|
|
|
|
107
|
|
|
return self::$instance; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
/** |
|
111
|
|
|
* Push a {@link WP_Post} to the Linked Data store. |
|
112
|
|
|
* |
|
113
|
|
|
* If the {@link WP_Post} is an entity and it's not of the `Article` type, |
|
114
|
|
|
* then it is pushed to the remote Linked Data store. |
|
115
|
|
|
* |
|
116
|
|
|
* @since 3.15.0 |
|
117
|
|
|
* |
|
118
|
|
|
* @param int $post_id The {@link WP_Post}'s id. |
|
119
|
|
|
*/ |
|
120
|
|
|
public function push( $post_id ) { |
|
121
|
|
|
|
|
122
|
|
|
$this->log->debug( "Pushing post $post_id..." ); |
|
123
|
|
|
|
|
124
|
|
|
// Bail out if it's not an entity: we do NOT publish non entities or |
|
125
|
|
|
// entities of type `Article`s. |
|
126
|
|
|
if ( ! $this->entity_service->is_entity( $post_id ) ) { |
|
127
|
|
|
$this->log->debug( "Post $post_id is not an entity." ); |
|
128
|
|
|
|
|
129
|
|
|
return; |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
// Bail out if the entity type is `Article`. |
|
133
|
|
|
if ( $this->entity_type_service->has_entity_type( $post_id, 'http://schema.org/Article' ) ) { |
|
134
|
|
|
$this->log->debug( "Post $post_id is an `Article`." ); |
|
135
|
|
|
|
|
136
|
|
|
return; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
// Get the post and push it to the Linked Data store. |
|
140
|
|
|
$this->do_push( $post_id ); |
|
141
|
|
|
|
|
142
|
|
|
// Reindex the triple store if buffering is turned off. |
|
143
|
|
|
if ( false === WL_ENABLE_SPARQL_UPDATE_QUERIES_BUFFERING ) { |
|
144
|
|
|
wordlift_reindex_triple_store(); |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
/** |
|
150
|
|
|
* Remove the specified {@link WP_Post} from the Linked Data. |
|
151
|
|
|
* |
|
152
|
|
|
* @since 3.15.0 |
|
153
|
|
|
* |
|
154
|
|
|
* @param int $post_id The {@link WP_Post}'s id. |
|
155
|
|
|
*/ |
|
156
|
|
|
public function remove( $post_id ) { |
|
157
|
|
|
|
|
158
|
|
|
// Get the delete statements. |
|
159
|
|
|
$deletes = $this->get_delete_statements( $post_id ); |
|
160
|
|
|
$delete_query = implode( "\n", $deletes ); |
|
161
|
|
|
$this->sparql_service->execute( $delete_query ); |
|
162
|
|
|
|
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* Push an entity to the Linked Data store. |
|
167
|
|
|
* |
|
168
|
|
|
* @since 3.15.0 |
|
169
|
|
|
* |
|
170
|
|
|
* @param int $post_id The {@link WP_Post}'s id. |
|
171
|
|
|
*/ |
|
172
|
|
|
private function do_push( $post_id ) { |
|
173
|
|
|
$this->log->debug( "Doing post $post_id push..." ); |
|
174
|
|
|
|
|
175
|
|
|
// Get the post. |
|
176
|
|
|
$post = get_post( $post_id ); |
|
177
|
|
|
|
|
178
|
|
|
// Bail out if the post isn't found. |
|
179
|
|
|
if ( null === $post ) { |
|
180
|
|
|
$this->log->debug( "Post $post_id not found." ); |
|
181
|
|
|
|
|
182
|
|
|
return; |
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
// Bail out if the post isn't published. |
|
186
|
|
|
if ( 'publish' !== $post->post_status ) { |
|
187
|
|
|
$this->log->debug( "Post $post_id not published." ); |
|
188
|
|
|
|
|
189
|
|
|
return; |
|
190
|
|
|
} |
|
191
|
|
|
|
|
192
|
|
|
// Bail out if the URI isn't valid. |
|
193
|
|
|
if ( ! $this->has_valid_uri( $post_id ) ) { |
|
194
|
|
|
$this->log->debug( "Post $post_id URI invalid." ); |
|
195
|
|
|
|
|
196
|
|
|
return; |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
|
|
// First remove the post data. |
|
200
|
|
|
$this->remove( $post_id ); |
|
201
|
|
|
|
|
202
|
|
|
// Get the insert statements. |
|
203
|
|
|
$insert_tuples = $this->get_insert_tuples( $post_id ); |
|
204
|
|
|
$insert_query_body = implode( "\n", $insert_tuples ); |
|
205
|
|
|
$insert_query = "INSERT DATA { $insert_query_body };"; |
|
206
|
|
|
$this->sparql_service->execute( $insert_query ); |
|
207
|
|
|
|
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* Check if an entity's {@link WP_Post} has a valid URI. |
|
212
|
|
|
* |
|
213
|
|
|
* @since 3.15.0 |
|
214
|
|
|
* |
|
215
|
|
|
* @param int $post_id The entity's {@link WP_Post}'s id. |
|
216
|
|
|
* |
|
217
|
|
|
* @return bool True if the URI is valid otherwise false. |
|
218
|
|
|
*/ |
|
219
|
|
|
private function has_valid_uri( $post_id ) { |
|
220
|
|
|
|
|
221
|
|
|
// Get the entity's URI. |
|
222
|
|
|
$uri = $this->entity_service->get_uri( $post_id ); |
|
223
|
|
|
|
|
224
|
|
|
// If the URI isn't found, return false. |
|
225
|
|
|
if ( null === $uri ) { |
|
226
|
|
|
return false; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
// If the URI ends with a trailing slash, return false. |
|
230
|
|
|
if ( '/' === substr( $uri, - 1 ) ) { |
|
231
|
|
|
return false; |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
// URI is valid. |
|
235
|
|
|
return true; |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
/** |
|
239
|
|
|
* Get the delete statements. |
|
240
|
|
|
* |
|
241
|
|
|
* @since 3.15.0 |
|
242
|
|
|
* |
|
243
|
|
|
* @param int $post_id The {@link WP_Post}'s id. |
|
244
|
|
|
* |
|
245
|
|
|
* @return array An array of delete statements. |
|
246
|
|
|
*/ |
|
247
|
|
|
private function get_delete_statements( $post_id ) { |
|
248
|
|
|
|
|
249
|
|
|
// Get the entity URI. |
|
250
|
|
|
$uri = $this->entity_service->get_uri( $post_id ); |
|
251
|
|
|
|
|
252
|
|
|
// Prepare the delete statements with the entity as subject. |
|
253
|
|
|
$as_subject = array_map( function ( $item ) use ( $uri ) { |
|
254
|
|
|
return Wordlift_Query_Builder::new_instance() |
|
255
|
|
|
->delete() |
|
256
|
|
|
->statement( $uri, $item, '?o' ) |
|
257
|
|
|
->build(); |
|
258
|
|
|
}, $this->schema_service->get_all_predicates() ); |
|
259
|
|
|
|
|
260
|
|
|
// Prepare the delete statements with the entity as object. |
|
261
|
|
|
$as_object = array_map( function ( $item ) use ( $uri ) { |
|
262
|
|
|
return Wordlift_Query_Builder::new_instance() |
|
263
|
|
|
->delete() |
|
264
|
|
|
->statement( '?s', $item, $uri, Wordlift_Query_Builder::OBJECT_URI ) |
|
265
|
|
|
->build(); |
|
266
|
|
|
}, $this->schema_service->get_all_predicates() ); |
|
267
|
|
|
|
|
268
|
|
|
// Merge the delete statements and return them. |
|
269
|
|
|
return array_merge( $as_subject, $as_object ); |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
/** |
|
273
|
|
|
* Get the SPARQL insert tuples ( ?s ?p ?o ) for the specified {@link WP_Post}. |
|
274
|
|
|
* |
|
275
|
|
|
* @since 3.15.0 |
|
276
|
|
|
* |
|
277
|
|
|
* @param int $post_id The {@link WP_Post}'s id. |
|
278
|
|
|
* |
|
279
|
|
|
* @return array An array of insert tuples. |
|
280
|
|
|
*/ |
|
281
|
|
|
private function get_insert_tuples( $post_id ) { |
|
282
|
|
|
|
|
283
|
|
|
// Get the entity type. |
|
284
|
|
|
$type = $this->entity_type_service->get( $post_id ); |
|
285
|
|
|
|
|
286
|
|
|
// Get the Linked Data properties. |
|
287
|
|
|
$properties = $type['linked_data']; |
|
288
|
|
|
|
|
289
|
|
|
// Accumulate the tuples. |
|
290
|
|
|
$tuples = array(); |
|
291
|
|
|
/** @var Wordlift_Sparql_Tuple_Rendition $property */ |
|
292
|
|
|
foreach ( $properties as $property ) { |
|
293
|
|
|
foreach ( $property->get( $post_id ) as $tuple ) { |
|
294
|
|
|
$tuples[] = $tuple; |
|
295
|
|
|
} |
|
296
|
|
|
} |
|
297
|
|
|
|
|
298
|
|
|
// Finally return the tuples. |
|
299
|
|
|
return $tuples; |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
} |
|
303
|
|
|
|
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.