Completed
Push — master ( 5db201...585add )
by David
08:20
created

Wordlift_Linked_Data_Service::push()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 28
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 1
dl 0
loc 28
rs 8.5806
c 0
b 0
f 0
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 ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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
255
				::new_instance()
256
				->delete()
257
				->statement( $uri, $item, '?o' )
258
				->build();
259
		}, $this->schema_service->get_all_predicates() );
260
261
		// Prepare the delete statements with the entity as object.
262
		$as_object = array_map( function ( $item ) use ( $uri ) {
263
			return Wordlift_Query_Builder
264
				::new_instance()
265
				->delete()
266
				->statement( '?s', $item, $uri, Wordlift_Query_Builder::OBJECT_URI )
267
				->build();
268
		}, $this->schema_service->get_all_predicates() );
269
270
		// Merge the delete statements and return them.
271
		return array_merge( $as_subject, $as_object );
272
	}
273
274
	/**
275
	 * Get the SPARQL insert tuples ( ?s ?p ?o ) for the specified {@link WP_Post}.
276
	 *
277
	 * @since 3.15.0
278
	 *
279
	 * @param int $post_id The {@link WP_Post}'s id.
280
	 *
281
	 * @return array An array of insert tuples.
282
	 */
283
	private function get_insert_tuples( $post_id ) {
284
285
		// Get the entity type.
286
		$type = $this->entity_type_service->get( $post_id );
287
288
		// Get the Linked Data properties.
289
		$properties = $type['linked_data'];
290
291
		// Accumulate the tuples.
292
		$tuples = array();
293
		/** @var Wordlift_Sparql_Tuple_Rendition $property A {@link Wordlift_Sparql_Tuple_Rendition} instance. */
294
		foreach ( $properties as $property ) {
295
			foreach ( $property->get( $post_id ) as $tuple ) {
296
				$tuples[] = $tuple;
297
			}
298
		}
299
300
		// Finally return the tuples.
301
		return $tuples;
302
	}
303
304
}
305