Completed
Push — master ( 37bdb3...5c343e )
by David
03:17 queued 10s
created

Wordlift_Batch_Analysis_Service   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 284
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 284
rs 10
c 0
b 0
f 0
wmc 23
lcom 1
cbo 3

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A get_batch_queues() 0 9 1
A waiting_for_analysis() 0 6 1
A waiting_for_response() 0 6 1
A enqueue_for_analysis() 0 15 3
B handle_waiting_queue() 0 64 6
C handle_response_queue() 0 49 7
A batch_analyze() 0 12 3
1
<?php
2
/**
3
 * Services: Batch Analysis Service.
4
 *
5
 * @since      3.14.0
6
 * @package    Wordlift
7
 * @subpackage Wordlift/includes
8
 */
9
10
/**
11
 * Define the {@link Wordlift_Batch_Analysis_Service} class.
12
 *
13
 * @since      3.14.0
14
 * @package    Wordlift
15
 * @subpackage Wordlift/includes
16
 */
17
class Wordlift_Batch_Analysis_Service {
18
19
	/**
20
	 * Option name.
21
	 *
22
	 * @since  3.14.0
23
	 */
24
	const OPTION_NAME = 'wl_analyze_batch';
25
26
	/**
27
	 * Name of waiting to be processed queue array inside the option.
28
	 *
29
	 * @since  3.14.0
30
	 */
31
	const ANALYZE_QUEUE = 'queue';
32
33
	/**
34
	 * Name of waiting for response queue array inside the option.
35
	 *
36
	 * @since  3.14.0
37
	 */
38
	const RESPONSE_QUEUE = 'processing';
39
40
	/**
41
	 * The {@link Wordlift} plugin instance.
42
	 *
43
	 * @since  3.14.0
44
	 * @access private
45
	 * @var \Wordlift $plugin The {@link Wordlift} plugin instance.
46
	 */
47
	private $plugin;
48
49
	/**
50
	 * The {@link Wordlift_Configuration_Service} instance.
51
	 *
52
	 * @since  3.14.0
53
	 * @access private
54
	 * @var \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
55
	 */
56
	private $configuration_service;
57
58
	/**
59
	 * The {@link Class_Wordlift_Batch_Analys_Service} instance.
60
	 *
61
	 * @since 3.14.0
62
	 *
63
	 * @param \Wordlift                       $plugin                The {@link Wordlift} plugin instance.
64
	 * @param \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
65
	 */
66
	public function __construct( $plugin, $configuration_service ) {
67
68
		$this->plugin                = $plugin;
69
		$this->configuration_service = $configuration_service;
70
		$this->log                   = Wordlift_Log_Service::get_logger( 'Wordlift_Batch_Analysis_Service' );
0 ignored issues
show
Bug introduced by
The property log does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
71
72
		add_action( 'wl_batch_analyze', array( $this, 'batch_analyze' ) );
73
74
	}
75
76
	/**
77
	 * Get the batch queues.
78
	 *
79
	 * Simplifies setting defaults if the option do not exists.
80
	 *
81
	 * @since 3.14.0
82
	 *
83
	 * @return array The batch queues.
84
	 */
85
	private function get_batch_queues() {
86
87
		$batch = get_option( self::OPTION_NAME, array(
88
			self::ANALYZE_QUEUE  => array(),
89
			self::RESPONSE_QUEUE => array(),
90
		) );
91
92
		return $batch;
93
	}
94
95
	/**
96
	 * Get the array of post IDS waiting in the queue to start processing.
97
	 *
98
	 * @since 3.14.0
99
	 *
100
	 * @return array The waiting to be processed post ids queue.
101
	 */
102
	public function waiting_for_analysis() {
103
104
		$batch = $this->get_batch_queues();
105
106
		return $batch[ self::ANALYZE_QUEUE ];
107
	}
108
109
	/**
110
	 * Get the array of post IDS waiting for response.
111
	 *
112
	 * @since 3.14.0
113
	 *
114
	 * @return array The waiting for response post ids queue.
115
	 */
116
	public function waiting_for_response() {
117
118
		$batch = $this->get_batch_queues();
119
120
		return $batch[ self::RESPONSE_QUEUE ];
121
	}
122
123
	/**
124
	 * Enqueue post IDs to be analyzed. For each set a link setting should be supplied.
125
	 *
126
	 * @since 3.14.0
127
	 *
128
	 * @param int|array $post_ids     A post ID of the posts to analyze, or an array of them.
129
	 * @param string    $link_setting The link setting to be applied for the analyzsis of the posts.
130
	 */
131
	public function enqueue_for_analysis( $post_ids, $link_setting ) {
132
		if ( ! is_array( $post_ids ) ) {
133
			$post_ids = array( $post_ids );
134
		}
135
136
		$batch = $this->get_batch_queues();
137
138
		foreach ( $post_ids as $pid ) {
139
			$batch[ self::ANALYZE_QUEUE ][ $pid ] = array(
140
				'id'   => $pid,
141
				'link' => $link_setting,
142
			);
143
		}
144
		update_option( self::OPTION_NAME, $batch );
145
	}
146
147
	/**
148
	 * Helper function to handle the waiting to be analyzed queue.
149
	 *
150
	 * @since 3.14.0
151
	 *
152
	 * @param array &$analyze_queue  reference to the waiting queue.
153
	 * @param array &$response_queue reference to the response queue.
154
	 *
155
	 * @throws Exception
156
	 */
157
	private function handle_waiting_queue( &$analyze_queue, &$response_queue ) {
158
159
		// Bail out if the queue is empty.
160
		if ( empty( $analyze_queue ) ) {
161
			return;
162
		}
163
164
		/*
165
		 * If we have any post waiting in the queue, send a request
166
		 * to the wordlift server to process it, when the requests includes
167
		 * the content and the id of the post.
168
		 */
169
		for ( $i = 0; $i < 10; $i ++ ) {
170
171
			$item = array_pop( $analyze_queue );
172
173
			if ( null === $item ) {
174
				continue;
175
			}
176
177
			$id   = $item['id'];
178
			$post = get_post( $id );
179
180
			if ( empty( $post ) ) {
181
				// Post was possibly deleted, just bailout.
182
				return;
183
			}
184
185
			$url = $this->configuration_service->get_batch_analysis_url();
186
187
			$param = array(
188
				'id'              => $item['id'],
189
				'key'             => $this->configuration_service->get_key(),
190
				'content'         => $post->post_content,
191
				'contentLanguage' => $this->configuration_service->get_language_code(),
192
				'version'         => $this->plugin->get_version(),
193
				'links'           => $item['link'],
194
				'scope'           => 'local',
195
			);
196
			$args  = array_merge_recursive( unserialize( WL_REDLINK_API_HTTP_OPTIONS ), array(
197
				'method'      => 'POST',
198
				'headers'     => array(
199
					'Accept'       => 'application/json',
200
					'Content-type' => 'application/json; charset=UTF-8',
201
				),
202
				// we need to downgrade the HTTP version in this case since chunked encoding is dumping numbers in the response.
203
				'httpversion' => '1.0',
204
				'body'        => wp_json_encode( $param ),
205
			) );
206
207
			$response = wp_remote_post( $url, $args );
208
209
			// If it's an error log it.
210
			if ( is_wp_error( $response ) ) {
211
				$analyze_queue[ $id ] = $item;
212
				$message              = "An error occurred while requesting a batch analysis to $url: {$response->get_error_message()}";
213
				$this->log->error( $message );
214
				throw new Exception( $response->get_error_message(), $response->get_error_code() );
215
			} else {
216
				$response_queue[ $item['id'] ] = $item;
217
			}
218
		}
219
220
	}
221
222
	/**
223
	 * Helper function to handle the waiting for response queue.
224
	 *
225
	 * @since 3.14.0
226
	 *
227
	 * @param array &$analyze_queue  reference to the waiting queue.
228
	 * @param array &$response_queue reference to the response queue.
229
	 *
230
	 * @throws Exception
231
	 */
232
	private function handle_response_queue( &$analyze_queue, &$response_queue ) {
233
234
		// Bail out if the queue is empty.
235
		if ( empty( $response_queue ) ) {
236
			return;
237
		}
238
239
		// If we have any post waiting for a reply to any post, send a status
240
		// request to the server.
241
		for ( $i = 0; $i < 10; $i ++ ) {
242
			$item = array_pop( $response_queue );
243
244
			if ( null === $item ) {
245
				continue;
246
			}
247
248
			$post = get_post( $item['id'] );
249
			if ( empty( $post ) ) {
250
				// Post was possibly deleted, just bailout.
251
				return;
252
			}
253
254
			$apiurl   = $this->configuration_service->get_batch_analysis_url();
255
			$id       = $item['id'];
256
			$key      = $this->configuration_service->get_key();
257
			$url      = $apiurl . '/' . $id . '?key=' . $key;
258
			$response = wp_remote_get( $url, unserialize( WL_REDLINK_API_HTTP_OPTIONS ) );
259
260
			// If it's an error log it.
261
			if ( is_wp_error( $response ) ) {
262
				$analyze_queue[ $id ] = $item;
263
				$message              = "An error occurred while requesting a batch analysis to $url: {$response->get_error_message()}";
264
				$this->log->error( $message );
265
				throw new Exception( $response->get_error_message(), $response->get_error_code() );
266
			} elseif ( 200 != $response['response']['code'] ) {
267
				$analyze_queue[ $id ] = $item;
268
			} else {
269
				// Save the returned content as new revision.
270
				$decode  = json_decode( $response['body'] );
271
				$content = $decode->content;
272
				wp_update_post( array(
273
					'ID'           => $id,
274
					'post_content' => wp_slash( $content ),
275
				) );
276
			}
277
278
		}
279
280
	}
281
282
	/**
283
	 * Execute the batch analysis for the next items in the analyze and response queues.
284
	 *
285
	 * @since 3.14.0
286
	 */
287
	public function batch_analyze() {
288
289
		$batch = $this->get_batch_queues();
290
		$this->handle_waiting_queue( $batch[ self::ANALYZE_QUEUE ], $batch[ self::RESPONSE_QUEUE ] );
291
		$this->handle_response_queue( $batch[ self::ANALYZE_QUEUE ], $batch[ self::RESPONSE_QUEUE ] );
292
		update_option( self::OPTION_NAME, $batch );
293
		
294
		if ( ! empty( $batch[ self::ANALYZE_QUEUE ] ) || ! empty( $batch[ self::RESPONSE_QUEUE ] ) ) {
295
			wp_schedule_single_event( time(), 'wl_batch_analyze' );
296
		}
297
298
	}
299
300
}
301