Completed
Push — develop ( c483b2...0165dc )
by David
03:10
created

Wordlift_Batch_Analysis_Service   D

Complexity

Total Complexity 37

Size/Duplication

Total Lines 683
Duplicated Lines 9.81 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
dl 67
loc 683
rs 4.6994
c 0
b 0
f 0
wmc 37
lcom 2
cbo 3

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 1
B get_sql() 0 36 1
A submit_auto_selected_posts() 21 21 1
A submit_all_posts() 14 14 1
A submit() 0 17 1
A cancel() 0 15 1
B request() 0 47 4
C complete() 0 68 7
A set_warning_based_on_content() 0 13 2
A clear_warning() 0 7 2
A set_warning() 0 4 2
A get_state() 0 4 1
B set_state() 0 23 4
A get_link() 0 6 2
A waiting_for_analysis() 11 11 1
A waiting_for_response() 11 11 1
A do_request() 0 48 2
A do_complete() 0 15 2
A get_warnings() 10 10 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Services: Batch Analysis Service.
4
 *
5
 * The Batch Analysis service allows to queue analysis operations given a list
6
 * of URLs.
7
 *
8
 * The Batch Analysis service should also allow to queue all the posts/pages
9
 * that do not contain any annotation (example annotation:
10
 * <span id="urn:enhancement-{uuid}"
11
 *       class="textannotation disambiguated wl-{class} [wl-[no-]link]"
12
 *       itemid="{itemid-url}">{label}</span>
13
 *
14
 * We must identify the batch analysis status according to 3 stages:
15
 *  1. BATCH_ANALYSIS_SUBMIT, i.e. a post/page has been submitted for batch
16
 *      analysis.
17
 *  2. BATCH_ANALYSIS_REQUEST, i.e. a post/page batch analysis has been
18
 *      requested to the remote service.
19
 *  3. BATCH_ANALYSIS_SUCCESS / BATCH_ANALYSIS_ERROR: the outcome of the batch
20
 *      analysis.
21
 *
22
 * For each state we record the date time, this is especially useful since the
23
 * remote service doesn't provide a state management, therefore we need to
24
 * define a timeout on the client side.
25
 *
26
 * Upon reception of the results we need to check whether there are some
27
 * potential warning due to interpolation issues, i.e.
28
 *
29
 *  `\w<span id="urn:enhancement-` or `\s</span>` or `</span>\w`
30
 *
31
 * and in such a case, set a warning BATCH_ANALYSIS_WARNING in order to provide
32
 * a list of posts/pages that need manual review and allow the editor to clear
33
 * the warning flag.
34
 *
35
 * All the time-consuming operations must be executed asynchronously.
36
 *
37
 * Since setting the post meta for a large number of posts may be time consuming
38
 * in PHP, we can use prepared queries.
39
 *
40
 * @since      3.14.0
41
 * @package    Wordlift
42
 * @subpackage Wordlift/includes
43
 */
44
45
/**
46
 * Define the {@link Wordlift_Batch_Analysis_Service} class.
47
 *
48
 * @since      3.14.0
49
 * @package    Wordlift
50
 * @subpackage Wordlift/includes
51
 */
52
class Wordlift_Batch_Analysis_Service {
53
54
	/**
55
	 * The list of states for the Batch Analysis:
56
	 *  - STATE_META_KEY: the batch analysis state meta key,
57
	 *  - STATE_SUBMIT: a post/page has been submitted for analysis,
58
	 *  - STATE_REQUEST: the plugin requested an analysis for the submitted
59
	 *      post/page,
60
	 *  - STATE_SUCCESS: the analysis has completed successfully,
61
	 *  - STATE_ERROR: the analysis returned an error.
62
	 *
63
	 * @since 3.14.2
64
	 */
65
	const STATE_META_KEY = '_wl_batch_analysis_state';
66
	const STATE_SUBMIT = 0;
67
	const STATE_REQUEST = 1;
68
	// ### COMPLETE states.
69
	const STATE_SUCCESS = 2;
70
	const STATE_ERROR = 2;
71
72
	/**
73
	 * The submit timestamp meta key. A post may have more than one timestamp.
74
	 *
75
	 * @since 3.14.2
76
	 */
77
	const SUBMIT_TIMESTAMP_META_KEY = '_wl_batch_analysis_submit_timestamp';
78
79
	/**
80
	 * The request timestamp meta key. A post may have more than one timestamp.
81
	 *
82
	 * @since 3.14.2
83
	 */
84
	const REQUEST_TIMESTAMP_META_KEY = '_wl_batch_analysis_request_timestamp';
85
86
	/**
87
	 * The complete (success or error) timestamp meta key. A post may have more
88
	 * than one timestamp.
89
	 *
90
	 * @since 3.14.2
91
	 */
92
	const COMPLETE_TIMESTAMP_META_KEY = '_wl_batch_analysis_complete_timestamp';
93
94
	/**
95
	 * The link setting meta key. A post may have more than one setting.
96
	 *
97
	 * @since 3.14.2
98
	 */
99
	const LINK_META_KEY = '_wl_batch_analysis_link';
100
101
	/**
102
	 * The warning timestamp meta key. A post has only zero/one value.
103
	 *
104
	 * @since 3.14.2
105
	 */
106
	const WARNING_META_KEY = '_wl_batch_analysis_warning';
107
108
	/**
109
	 * Option name.
110
	 *
111
	 * @since  3.14.0
112
	 */
113
	const OPTION_NAME = 'wl_analyze_batch';
114
115
	/**
116
	 * Name of waiting to be processed queue array inside the option.
117
	 *
118
	 * @since  3.14.0
119
	 */
120
	const ANALYZE_QUEUE = 'queue';
121
122
	/**
123
	 * Name of waiting for response queue array inside the option.
124
	 *
125
	 * @since  3.14.0
126
	 */
127
	const RESPONSE_QUEUE = 'processing';
128
129
	/**
130
	 * The {@link Wordlift} plugin instance.
131
	 *
132
	 * @since  3.14.0
133
	 * @access private
134
	 * @var \Wordlift $plugin The {@link Wordlift} plugin instance.
135
	 */
136
	private $plugin;
137
138
	/**
139
	 * The {@link Wordlift_Configuration_Service} instance.
140
	 *
141
	 * @since  3.14.0
142
	 * @access private
143
	 * @var \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
144
	 */
145
	private $configuration_service;
146
147
	/**
148
	 * A {@link Wordlift_Log_Service} instance.
149
	 *
150
	 * @since  3.14.2
151
	 * @access private
152
	 * @var \Wordlift_Log_Service $log A {@link Wordlift_Log_Service} instance.
153
	 */
154
	private $log;
155
156
	/**
157
	 * The {@link Class_Wordlift_Batch_Analys_Service} instance.
158
	 *
159
	 * @since 3.14.0
160
	 *
161
	 * @param \Wordlift                       $plugin                The {@link Wordlift} plugin instance.
162
	 * @param \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
163
	 */
164
	public function __construct( $plugin, $configuration_service ) {
165
166
		$this->plugin                = $plugin;
167
		$this->configuration_service = $configuration_service;
168
		$this->log                   = Wordlift_Log_Service::get_logger( 'Wordlift_Batch_Analysis_Service' );
169
170
		add_action( 'wp_async_wl_batch_analysis_request', array(
171
			$this,
172
			'request',
173
		) );
174
		add_action( 'wp_async_wl_batch_analysis_complete', array(
175
			$this,
176
			'complete',
177
		) );
178
179
	}
180
181
	/**
182
	 * Get the base SQL statement to submit a post for Batch Analysis.
183
	 *
184
	 * Functions may use this base SQL and add their own filters.
185
	 *
186
	 * @since 3.14.2
187
	 *
188
	 * @param string $link The link setting ('yes'/'no').
189
	 *
190
	 * @return string The base SQL.
191
	 */
192
	private function get_sql( $link ) {
193
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
194
195
		// Prepare the statement:
196
		//  1. Insert into `postmeta` the meta keys and values:
197
		//    a) state meta, with value of SUBMIT (0),
198
		//    b) submit timestamp, with value of UTC timestamp,
199
		//    c) link meta, with the provided value.
200
		//  2. Join the current state value, can be used for filters by other
201
		//     functions.
202
		//  3. Filter by `post`/`page` types.
203
		//  4. Filter by `publish` status.
204
		return $wpdb->prepare(
205
			"
206
			INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value )
207
			SELECT p.ID, metas.*
208
			FROM (
209
				SELECT %s, 0 FROM dual
210
				UNION
211
				SELECT %s, UTC_TIMESTAMP() FROM dual
212
				UNION
213
				SELECT %s, %s FROM dual
214
			) metas, $wpdb->posts p
215
			LEFT JOIN $wpdb->postmeta batch_analysis_state
216
				ON batch_analysis_state.post_id = p.ID
217
					AND batch_analysis_state.meta_key = %s
218
			WHERE p.post_type IN ('post', 'page')
219
				AND p.post_status = 'publish'
220
			",
221
			self::STATE_META_KEY,
222
			self::SUBMIT_TIMESTAMP_META_KEY,
223
			self::LINK_META_KEY,
224
			$link,
225
			self::STATE_META_KEY
226
		);
227
	}
228
229
	/**
230
	 * Submit for analysis all the posts/pages which do not have annotations
231
	 * and haven't been analyzed before.
232
	 *
233
	 * @since 3.14.2
234
	 *
235
	 * @param string $link The link setting.
236
	 *
237
	 * @return false|int The number of submitted {@link WP_Post}s or false on
238
	 *                   error.
239
	 */
240 View Code Duplication
	public function submit_auto_selected_posts( $link ) {
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...
241
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
242
243
		// Submit the posts/pages and return the number of affected results.
244
		// We're using a SQL query here because we could have potentially
245
		// thousands of rows.
246
		$count = $wpdb->query( $wpdb->prepare(
247
			$this->get_sql( $link ) .
248
			"
249
				AND batch_analysis_state.meta_value IS NULL
250
				AND p.post_content NOT REGEXP %s;
251
			",
252
			'<[a-z]+ id="urn:[^"]+" class="[^"]+" itemid="[^"]+">'
253
		) );
254
255
		// Request Batch Analysis (the operation is handled asynchronously).
256
		do_action( 'wl_batch_analysis_request' );
257
258
		// Divide the count by 3 to get the number of posts/pages queued.
259
		return $count / 3;
260
	}
261
262
	/**
263
	 * Submit all posts for analysis.
264
	 *
265
	 * @since 3.14.5
266
	 *
267
	 * @param string $link The link setting.
268
	 *
269
	 * @return false|int The number of submitted {@link WP_Post}s or false on
270
	 *                   error.
271
	 */
272 View Code Duplication
	public function submit_all_posts( $link ) {
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...
273
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
274
275
		// Submit the posts/pages and return the number of affected results.
276
		// We're using a SQL query here because we could have potentially
277
		// thousands of rows.
278
		$count = $wpdb->query( $this->get_sql( $link ) );
279
280
		// Request Batch Analysis (the operation is handled asynchronously).
281
		do_action( 'wl_batch_analysis_request' );
282
283
		// Divide the count by 3 to get the number of posts/pages queued.
284
		return $count / 3;
285
	}
286
287
	/**
288
	 * Submit the provided list of {@link WP_Post}s' ids for Batch Analysis.
289
	 *
290
	 * @since 3.14.2
291
	 *
292
	 * @param int|array $post_ids A single {@link WP_Post}'s id or an array of
293
	 *                            {@link WP_Post}s' ids.
294
	 * @param string    $link     The link setting.
295
	 *
296
	 * @return int The number of submitted {@link WP_Post}s or false on error.
297
	 */
298
	public function submit( $post_ids, $link ) {
299
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
300
301
		// Submit the posts/pages and return the number of affected results.
302
		// We're using a SQL query here because we could have potentially
303
		// thousands of rows.
304
		$count = $wpdb->query(
305
			$this->get_sql( $link ) .
306
			' AND p.ID IN ( ' . implode( ',', wp_parse_id_list( $post_ids ) ) . ' )'
307
		);
308
309
		// Request Batch Analysis (the operation is handled asynchronously).
310
		do_action( 'wl_batch_analysis_request' );
311
312
		// Divide the count by 3 to get the number of posts/pages queued.
313
		return $count / 3;
314
	}
315
316
	/**
317
	 * Cancel the Batch Analysis request for the specified {@link WP_Post}s.
318
	 *
319
	 * @since 3.14.2
320
	 *
321
	 * @param int|array $post_ids A single {@link WP_Post}'s id or an array of
322
	 *                            {@link WP_Post}s' ids.
323
	 *
324
	 * @return false|int The number of cancelled {@link WP_Post}s or false on
325
	 *                   error.
326
	 */
327
	public function cancel( $post_ids ) {
328
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
329
330
		return $wpdb->query( $wpdb->prepare(
331
			"
332
			DELETE FROM $wpdb->postmeta
333
			WHERE meta_key = %s
334
				AND meta_value = %s
335
				AND post_id IN ( " . implode( ',', wp_parse_id_list( $post_ids ) ) . " )
336
			",
337
			self::STATE_META_KEY,
338
			self::STATE_REQUEST
339
		) );
340
341
	}
342
343
	/**
344
	 * Request the batch analysis for submitted posts.
345
	 *
346
	 * @since 3.14.2
347
	 */
348
	public function request() {
349
350
		$this->log->debug( "Requesting analysis..." );
351
352
		// By default 5 posts of any post type are returned.
353
		$posts = get_posts( array(
354
			'fields'     => 'ids',
355
			'meta_key'   => self::STATE_META_KEY,
356
			'meta_value' => self::STATE_SUBMIT,
357
			'orderby'    => 'ID',
358
		) );
359
360
		// Bail out if there are no submitted posts.
361
		if ( empty( $posts ) ) {
362
			$this->log->debug( 'No posts to submit found, checking for completed requests...' );
363
364
			do_action( 'wl_batch_analysis_complete' );
365
366
			return;
367
		}
368
369
		// Send a request for each post.
370
		foreach ( $posts as $id ) {
371
			$this->log->debug( "Requesting analysis for post $id..." );
372
373
			// Change the state to `REQUEST`.
374
			$this->set_state( $id, self::STATE_REQUEST );
375
376
			// Send the actual request to the remote service.
377
			$result = $this->do_request( $id );
378
379
			$this->log->debug( "Analysis requested for post $id." );
380
381
			// Set an error if we received an error.
382
			if ( is_wp_error( $result ) ) {
383
				$this->log->error( "Analysis request for post $id returned {$result->get_error_message()}." );
384
385
				$this->set_state( $id, self::STATE_ERROR );
386
			}
387
388
		}
389
390
		// Call the `wl_batch_analysis_request` action again. This is going
391
		// to be handled by the async task.
392
		do_action( 'wl_batch_analysis_request' );
393
394
	}
395
396
	/**
397
	 * Get the results for the Batch Analysis.
398
	 *
399
	 * @since 3.14.2
400
	 */
401
	public function complete() {
402
403
		$this->log->debug( "Requesting results..." );
404
405
		// By default 5 posts of any post type are returned.
406
		$posts = get_posts( array(
407
			'fields'     => 'ids',
408
			'meta_key'   => self::STATE_META_KEY,
409
			'meta_value' => self::STATE_REQUEST,
410
			'orderby'    => 'ID',
411
		) );
412
413
		// Bail out if there are no submitted posts.
414
		if ( empty( $posts ) ) {
415
			$this->log->debug( 'No posts in request state found.' );
416
417
			return;
418
		}
419
420
		// Send a request for each post.
421
		foreach ( $posts as $id ) {
422
			$this->log->debug( "Requesting results for post $id..." );
423
424
			// Send the actual request to the remote service.
425
			$response = $this->do_complete( $id );
426
427
			$this->log->debug( "Results requested for post $id." );
428
429
			// Set an error if we received an error.
430
			if ( ! is_wp_error( $response ) && isset( $response['body'] ) ) {
431
432
				$this->log->debug( "Results received for post $id." );
433
434
				// Save the returned content as new revision.
435
				$json = json_decode( $response['body'] );
436
437
				// Continue if the content isn't set.
438
				if ( ! isset( $json->content ) || empty( $json->content ) ) {
439
					continue;
440
				}
441
442
				$this->set_warning_based_on_content( $id, $json->content );
443
444
				$content = wp_slash( $json->content );
445
446
				wp_update_post( array(
447
					'ID'           => $id,
448
					'post_content' => $content,
449
				) );
450
451
				// Update the status.
452
				$this->set_state( $id, self::STATE_SUCCESS );
453
454
				$this->log->debug( "Post $id updated with batch analysis results." );
455
456
				continue;
457
			}
458
459
			// @todo: implement a kind of timeout that sets an error if the
460
			// results haven't been received after a long time.
461
462
		}
463
464
		// Call the `wl_batch_analysis_request` action again. This is going
465
		// to be handled by the async task.
466
		do_action( 'wl_batch_analysis_complete' );
467
468
	}
469
470
	/**
471
	 * Set a warning flag on the {@link WP_Post} if its content has suspicious
472
	 * interpolations.
473
	 *
474
	 * @since 3.14.2
475
	 *
476
	 * @param int    $post_id The {@link WP_Post}'s id.
477
	 * @param string $content The {@link WP_Post}'s content.
478
	 *
479
	 * @return string The content (for chaining operations).
480
	 */
481
	private function set_warning_based_on_content( $post_id, $content ) {
482
483
		$matches = array();
484
485
		// Check for suspicious interpolations.
486
		$warning = 0 < preg_match_all( '/\w<[a-z]+ id="urn:enhancement-[^"]+" class="[^"]+" itemid="[^"]+">/', $content, $matches )
487
				   || 0 < preg_match_all( '/<[a-z]+ id="urn:enhancement-[^"]+" class="[^"]+" itemid="[^"]+">\s/', $content, $matches );
488
489
		// Set the warning flag accordingly.
490
		$this->set_warning( $post_id, $warning );
491
492
		return $content;
493
	}
494
495
	/**
496
	 * Clear the warning flag for the specified {@link WP_Post}s.
497
	 *
498
	 * @since 3.14.2
499
	 *
500
	 * @param int|array $post_ids A single {@link WP_Post}'s id or an array of
501
	 *                            {@link WP_Post}s' ids.
502
	 */
503
	public function clear_warning( $post_ids ) {
504
505
		foreach ( (array) $post_ids as $post_id ) {
506
			delete_post_meta( $post_id, self::WARNING_META_KEY );
507
		}
508
509
	}
510
511
	/**
512
	 * Set the warning flag for the specified {@link WP_Post}.
513
	 *
514
	 * @since 3.14.2
515
	 *
516
	 * @param int  $post_id The {@link WP_Post}'s id.
517
	 * @param bool $value   The flag's value.
518
	 *
519
	 * @return int|bool Meta ID if the key didn't exist, true on successful update,
520
	 *                  false on failure.
521
	 */
522
	private function set_warning( $post_id, $value ) {
523
524
		return update_post_meta( $post_id, self::WARNING_META_KEY, ( true === $value ? 'yes' : 'no' ) );
525
	}
526
527
	/**
528
	 * Get the post/page batch analysis state.
529
	 *
530
	 * @since 3.14.2
531
	 *
532
	 * @param int $post_id The {@link WP_Post}'s id.
533
	 *
534
	 * @return int|string The post state or an empty string if not set.
535
	 */
536
	public function get_state( $post_id ) {
537
538
		return get_post_meta( $post_id, self::STATE_META_KEY, true );
539
	}
540
541
	/**
542
	 * Set the post/page batch analysis state.
543
	 *
544
	 * @since 3.14.2
545
	 *
546
	 * @param int $post_id The {@link WP_Post}'s id.
547
	 * @param int $value   The new state.
548
	 *
549
	 * @return int|bool Meta ID if the key didn't exist, true on successful update,
550
	 *                  false on failure.
551
	 */
552
	public function set_state( $post_id, $value ) {
553
554
		// Update the state.
555
		$result = update_post_meta( $post_id, self::STATE_META_KEY, $value );
556
557
		// Update timestamps as required.
558
		switch ( $value ) {
559
560
			// ### REQUEST state.
561
			case self::STATE_REQUEST:
562
				add_post_meta( $post_id, self::REQUEST_TIMESTAMP_META_KEY, current_time( 'mysql', true ) );
563
				break;
564
565
			// ### SUCCESS/ERROR state.
566
			case self::STATE_SUCCESS:
567
			case self::STATE_ERROR:
568
				add_post_meta( $post_id, self::COMPLETE_TIMESTAMP_META_KEY, current_time( 'mysql', true ) );
569
				break;
570
		}
571
572
		// Finally return the result.
573
		return $result;
574
	}
575
576
	/**
577
	 * Get the link setting for a {@link WP_Post}.
578
	 *
579
	 * If there are multiple link settings, only the last one is returned.
580
	 *
581
	 * @since 3.14.2
582
	 *
583
	 * @param int $post_id The {@link WP_Post}'s id.
584
	 *
585
	 * @return string The link setting or `default` if not set.
586
	 */
587
	public function get_link( $post_id ) {
588
589
		$values = get_post_meta( $post_id, self::LINK_META_KEY );
590
591
		return end( $values ) ?: 'default';
592
	}
593
594
	/**
595
	 * Get the array of post IDS waiting in the queue to start processing.
596
	 *
597
	 * @since 3.14.0
598
	 *
599
	 * @return array The waiting to be processed post ids queue.
600
	 */
601 View Code Duplication
	public function waiting_for_analysis() {
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...
602
603
		return get_posts( array(
604
			'posts_per_page' => - 1,
605
			'fields'         => 'ids',
606
			'post_status'    => 'any',
607
			'meta_key'       => self::STATE_META_KEY,
608
			'meta_value'     => self::STATE_SUBMIT,
609
			'orderby'        => 'ID',
610
		) );
611
	}
612
613
	/**
614
	 * Get the array of post IDS waiting for response.
615
	 *
616
	 * @deprecated
617
	 * @since 3.14.0
618
	 *
619
	 * @return array The waiting for response post ids queue.
620
	 */
621 View Code Duplication
	public function waiting_for_response() {
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...
622
623
		return get_posts( array(
624
			'posts_per_page' => - 1,
625
			'fields'         => 'ids',
626
			'post_status'    => 'any',
627
			'meta_key'       => self::STATE_META_KEY,
628
			'meta_value'     => self::STATE_REQUEST,
629
			'orderby'        => 'ID',
630
		) );
631
	}
632
633
	/**
634
	 * Request the analysis for the specified {@link WP_Post}.
635
	 *
636
	 * @since 3.14.2
637
	 *
638
	 * @param int $post_id The {@link WP_Post}'s id.
639
	 *
640
	 * @return WP_Error|array The response or WP_Error on failure.
641
	 */
642
	private function do_request( $post_id ) {
643
644
		// Get the post.
645
		$post = get_post( $post_id );
646
647
		// Bail out if the post isn't found.
648
		if ( null === $post ) {
649
			$this->log->warn( "Post $post_id not found." );
650
651
			return new WP_Error( 0, "Cannot find post $post_id." );
652
		}
653
654
		// Get the link setting.
655
		$link = $this->get_link( $post_id );
656
657
		$this->log->debug( "Sending analysis request for post $post_id [ link :: $link ]..." );
658
659
		// Get the batch analysis URL.
660
		$url = $this->configuration_service->get_batch_analysis_url();
661
662
		// Prepare the POST parameters.
663
		$param = array(
664
			'id'              => $post->ID,
665
			'key'             => $this->configuration_service->get_key(),
666
			'content'         => $post->post_content,
667
			'contentLanguage' => $this->configuration_service->get_language_code(),
668
			'version'         => $this->plugin->get_version(),
669
			'links'           => $link,
670
			'scope'           => 'local',
671
		);
672
673
		// Get the HTTP options.
674
		$args = array_merge_recursive( unserialize( WL_REDLINK_API_HTTP_OPTIONS ), array(
675
			'method'      => 'POST',
676
			'headers'     => array(
677
				'Accept'       => 'application/json',
678
				'Content-type' => 'application/json; charset=UTF-8',
679
			),
680
			// we need to downgrade the HTTP version in this case since chunked encoding is dumping numbers in the response.
681
			'httpversion' => '1.0',
682
			'body'        => wp_json_encode( $param ),
683
		) );
684
685
		$this->log->debug( "Posting analysis request for post $post_id to $url..." );
686
687
		// Post the parameter.
688
		return wp_remote_post( $url, $args );
689
	}
690
691
	/**
692
	 * Get the Batch Analysis results for the specified {@link WP_Post}.
693
	 *
694
	 * @since 3.14.2
695
	 *
696
	 * @param int $post_id The {@link WP_Post}'s id.
697
	 *
698
	 * @return WP_Error|array The response or WP_Error on failure.
699
	 */
700
	private function do_complete( $post_id ) {
701
702
		$post = get_post( $post_id );
703
704
		if ( null === $post ) {
705
			// Post was possibly deleted, just bailout.
706
			return new WP_Error( 0, "Post $post_id not found." );
707
		}
708
709
		$url = $this->configuration_service->get_batch_analysis_url();
710
		$key = $this->configuration_service->get_key();
711
		$url = $url . '/' . $post->ID . '?key=' . $key;
712
713
		return wp_remote_get( $url, unserialize( WL_REDLINK_API_HTTP_OPTIONS ) );
714
	}
715
716
	/**
717
	 * Get the {@link WP_Post}s' ids flagged with warnings.
718
	 *
719
	 * @since 3.14.2
720
	 *
721
	 * @return array An array of {@link WP_Post}s' ids.
722
	 */
723 View Code Duplication
	public function get_warnings() {
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...
724
725
		return get_posts( array(
726
			'fields'      => 'ids',
727
			'numberposts' => - 1,
728
			'post_status' => 'any',
729
			'meta_key'    => self::WARNING_META_KEY,
730
			'meta_value'  => 'yes',
731
		) );
732
	}
733
734
}
735