Completed
Pull Request — develop (#740)
by David
03:26
created

Wordlift_Batch_Analysis_Service::submit_posts()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 1
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
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 options setting meta key. A post may have more than one setting.
96
	 *
97
	 * @since 3.14.2
98
	 */
99
	const BATCH_ANALYSIS_OPTIONS_META_KEY = '_wl_batch_analysis_options';
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
	 * Regular expressions that match interpolation errors.
131
	 *
132
	 * @since  3.17.0
133
	 */
134
	const INTERPOLATION_PATTERNS = array(
135
		// Matches word before the annotation.
136
		'~(\w)<[a-z]+ id="urn:[^"]+" class="[^"]+" itemid="[^"]+">(.*?)<\/[a-z]+>~',
137
		// Matches word after the annotation.
138
		'~<[a-z]+ id="urn:[^"]+" class="[^"]+" itemid="[^"]+">(.*?)<\/[a-z]+>(\w)~',
139
		// Matches space in the beginning of annotation name.
140
		'~<[a-z]+ id="urn:[^"]+" class="[^"]+" itemid="[^"]+">(\s)(.*?)<\/[a-z]+>~',
141
	);
142
143
	/**
144
	 * The {@link Wordlift} plugin instance.
145
	 *
146
	 * @since  3.14.0
147
	 * @access private
148
	 * @var \Wordlift $plugin The {@link Wordlift} plugin instance.
149
	 */
150
	private $plugin;
151
152
	/**
153
	 * The {@link Wordlift_Configuration_Service} instance.
154
	 *
155
	 * @since  3.14.0
156
	 * @access private
157
	 * @var \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
158
	 */
159
	private $configuration_service;
160
161
	/**
162
	 * A {@link Wordlift_Log_Service} instance.
163
	 *
164
	 * @since  3.14.2
165
	 * @access private
166
	 * @var \Wordlift_Log_Service $log A {@link Wordlift_Log_Service} instance.
167
	 */
168
	private $log;
169
170
	/**
171
	 * The {@link Class_Wordlift_Batch_Analys_Service} instance.
172
	 *
173
	 * @since 3.14.0
174
	 *
175
	 * @param \Wordlift                       $plugin                The {@link Wordlift} plugin instance.
176
	 * @param \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
177
	 */
178
	public function __construct( $plugin, $configuration_service ) {
179
180
		$this->plugin                = $plugin;
181
		$this->configuration_service = $configuration_service;
182
		$this->log                   = Wordlift_Log_Service::get_logger( 'Wordlift_Batch_Analysis_Service' );
183
184
		add_action( 'wl_async_wl_batch_analysis_request', array(
185
			$this,
186
			'request',
187
		) );
188
		add_action( 'wl_async_wl_batch_analysis_complete', array(
189
			$this,
190
			'complete',
191
		) );
192
193
	}
194
195
	/**
196
	 * Submit posts for Batch Analysis.
197
	 *
198
	 * @since 3.14.2
199
	 *
200
	 * @param array       $args               {
201
	 *                                        A list of options for the Batch Analysis.
202
	 *
203
	 * @type string       $link               Either `default`, `no` or `yes` (`default` is used if not specified):
204
	 *                                        * `default` doesn't set the link option - entities
205
	 *                                           will be linked if configured so in WordLift settings.
206
	 *                                        * `yes` links the entities.
207
	 *                                        * `no` doesn't link the entities.
208
	 *                                        This value is forwarded to WLS' Batch Analysis end-point.
209
	 * @type int          $min_occurrences    The minimum number of occurrences to select
210
	 *                                        an entity. Default `1`.
211
	 * @type bool         $include_annotated  Whether to include annotated posts in selection.
212
	 *                                        Default `false`.
213
	 * @type array|int    $include            Explicitly include the specified {@link WP_Post}s.
214
	 * @type array|int    $exclude            Explicitly exclude the specified {@link WP_Post}s.
215
	 * @type string|null  $from               An optional date from filter (used in `post_date_gmt`).
216
	 * @type string|null  $to                 An optional date from filter (used in `post_date_gmt`).
217
	 * @type array|string $post_type          Specify the post type(s), by default only `post`.
218
	 *                      }
219
	 *
220
	 * @return int The number of submitted {@link WP_Post}s or false on error.
221
	 */
222
	public function submit( $args ) {
223
		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...
224
225
		// Parse the parameters.
226
		$params = wp_parse_args( $args, array(
227
			'link'              => 'default',
228
			'min_occurrences'   => 1,
229
			'include_annotated' => false,
230
			'exclude'           => array(),
231
			'from'              => null,
232
			'to'                => null,
233
			'post_type'         => 'post',
234
		) );
235
236
		// Validation.
237
		if ( ! in_array( $params['link'], array( 'default', 'yes', 'no' ) ) ) {
238
			wp_die( '`link` must be one of the following: `default`, `yes` or `no`.' );
239
		}
240
241
		if ( ! is_numeric( $params['min_occurrences'] ) || 1 > $params['min_occurrences'] ) {
242
			wp_die( '`min_occurrences` must greater or equal 1.' );
243
		}
244
245
		// Submit the posts/pages and return the number of affected results.
246
		// We're using a SQL query here because we could have potentially
247
		// thousands of rows.
248
		$count = $wpdb->query( Wordlift_Batch_Analysis_Sql_Helper::get_sql( $params ) ); // WPCS: cache ok, db call ok.
249
250
		// Request Batch Analysis (the operation is handled asynchronously).
251
		do_action( 'wl_batch_analysis_request' );
252
253
		// Divide the count by 3 to get the number of posts/pages queued.
254
		return $count / 3;
255
	}
256
257
	/**
258
	 * Submit one or more {@link WP_Posts} for Batch Analysis.
259
	 *
260
	 * @param array    $args            {
261
	 *                                  An array of arguments.
262
	 *
263
	 * @type string    $link            The link option: `default`, `yes` or
264
	 *                                  `no`. If not set `default`.
265
	 * @type int       $min_occurrences The minimum number of occurrences. If
266
	 *                                  not set `1`.
267
	 * @type array|int $ids             An array of {@link WP_Post}s' ids or one
268
	 *                                  single numeric {@link WP_Post} id.
269
	 *                    }
270
	 *
271
	 * @return float|int
272
	 */
273
	public function submit_posts( $args ) {
274
		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...
275
276
		// Parse the parameters.
277
		$params = wp_parse_args( $args, array(
278
			'link'            => 'default',
279
			'min_occurrences' => 1,
280
			'ids'             => array(),
281
		) );
282
283
		// Validation.
284
		if ( empty( $params['ids'] ) ) {
285
			wp_die( '`ids` cannot be empty.' );
286
		}
287
288
		// Submit the posts/pages and return the number of affected results.
289
		// We're using a SQL query here because we could have potentially
290
		// thousands of rows.
291
		$count = $wpdb->query( Wordlift_Batch_Analysis_Sql_Helper::get_sql_for_ids( $params ) ); // WPCS: cache ok, db call ok.
292
293
		// Request Batch Analysis (the operation is handled asynchronously).
294
		do_action( 'wl_batch_analysis_request' );
295
296
		// Divide the count by 3 to get the number of posts/pages queued.
297
		return $count / 3;
298
	}
299
300
	/**
301
	 * Cancel the Batch Analysis request for the specified {@link WP_Post}s.
302
	 *
303
	 * @since 3.14.2
304
	 *
305
	 * @param int|array $post_ids A single {@link WP_Post}'s id or an array of
306
	 *                            {@link WP_Post}s' ids.
307
	 *
308
	 * @return false|int The number of cancelled {@link WP_Post}s or false on
309
	 *                   error.
310
	 */
311
	public function cancel( $post_ids ) {
312
		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...
313
314
		return $wpdb->query( $wpdb->prepare(
315
			"
316
			DELETE FROM $wpdb->postmeta
317
			WHERE meta_key = %s
318
				AND meta_value IN ( %d, %d )
319
				AND post_id IN( " . implode( ',', wp_parse_id_list( $post_ids ) ) . " )
320
			",
321
			self::STATE_META_KEY,
322
			self::STATE_SUBMIT,
323
			self::STATE_REQUEST
324
		) ); // WPCS: cache ok, db call ok.
325
326
	}
327
328
	/**
329
	 * Request the batch analysis for submitted posts.
330
	 *
331
	 * @since 3.14.2
332
	 */
333
	public function request() {
334
335
		$this->log->debug( 'Requesting analysis...' );
336
337
		// By default 5 posts of any post type are returned.
338
		$posts = get_posts( array(
339
			'fields'     => 'ids',
340
			'meta_key'   => self::STATE_META_KEY,
341
			'meta_value' => self::STATE_SUBMIT,
342
			'orderby'    => 'ID',
343
			'post_type'  => 'any',
344
		) );
345
346
		// Bail out if there are no submitted posts.
347
		if ( empty( $posts ) ) {
348
			$this->log->debug( 'No posts to submit found, checking for completed requests...' );
349
350
			do_action( 'wl_batch_analysis_complete' );
351
352
			return;
353
		}
354
355
		// Send a request for each post.
356
		foreach ( $posts as $id ) {
357
358
			$this->log->debug( "Requesting analysis for post $id..." );
359
360
			// Send the actual request to the remote service.
361
			$result = $this->do_request( $id );
362
363
			// Set an error if we received an error.
364
			if ( is_wp_error( $result ) ) {
365
				$this->log->error( "An error occurred while requesting a batch analysis for post $id: " . $result->get_error_message() );
366
367
				$this->set_state( $id, self::STATE_ERROR );
368
			}
369
370
		}
371
372
		// Call the `wl_batch_analysis_request` action again. This is going
373
		// to be handled by the async task.
374
		do_action( 'wl_batch_analysis_request' );
375
376
	}
377
378
	/**
379
	 * Get the results for the Batch Analysis.
380
	 *
381
	 * @since 3.14.2
382
	 */
383
	public function complete() {
384
385
		$this->log->debug( 'Requesting results...' );
386
387
		// By default 5 posts of any post type are returned.
388
		$posts = get_posts( array(
389
			'fields'     => 'ids',
390
			'meta_key'   => self::STATE_META_KEY,
391
			'meta_value' => self::STATE_REQUEST,
392
			'orderby'    => 'ID',
393
			'post_type'  => 'any',
394
		) );
395
396
		// Bail out if there are no submitted posts.
397
		if ( empty( $posts ) ) {
398
			$this->log->debug( 'No posts in request state found.' );
399
400
			return;
401
		}
402
403
		// Send a request for each post.
404
		foreach ( $posts as $id ) {
405
			$this->log->debug( "Requesting results for post $id..." );
406
407
			// Send the actual request to the remote service.
408
			$response = $this->do_complete( $id );
409
410
			// Move to the next item if we don't have a reply for this one.
411
			if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
412
				continue;
413
			}
414
415
			$this->log->debug( "Results received for post $id." );
416
417
			// Save the returned content as new revision.
418
			$json = json_decode( $response['body'] );
419
420
			// Continue if the content isn't set.
421
			if ( empty( $json->content ) ) {
422
				// The post content is empty, so is should be marked as completed.
423
				$this->log->error( "An error occurred while decoding the batch analysis response for post $id." );
424
425
				$this->set_state( $id, self::STATE_ERROR );
426
				continue;
427
			}
428
429
			// Set the warning flag if needed.
430
			$this->set_warning_based_on_content( $json->content, $id );
431
432
			// Get the content, cleaned up if there are interpolation errors.
433
			$pre_content = $this->fix_interpolation_errors( $json->content, $id );
434
435
			/**
436
			 * Filter: 'wl_batch_analysis_update_post_content' - Allow third
437
			 * parties to perform additional actions when the post content is
438
			 * updated.
439
			 *
440
			 * @since  3.17.0
441
			 * @api    string $data The {@link WP_Post}'s content.
442
			 * @api    int    $id   The {@link WP_Post}'s id.
443
			 */
444
			$content = apply_filters( 'wl_batch_analysis_update_post_content', $pre_content, $id );
445
446
			// Update the post content.
447
			wp_update_post( array(
448
				'ID'           => $id,
449
				'post_content' => wp_slash( $content ),
450
			) );
451
452
			// Update the status.
453
			$this->set_state( $id, self::STATE_SUCCESS );
454
455
			$this->log->debug( "Post $id updated with batch analysis results." );
456
457
			// Set default entity type term for posts that didn't have any.
458
			$this->maybe_set_default_term( $id );
459
460
			// @todo: implement a kind of timeout that sets an error if the
461
			// results haven't been received after a long time.
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 string $content The {@link WP_Post}'s content.
477
	 * @param int    $post_id The {@link WP_Post}'s id.
478
	 *
479
	 * @return string The content (for chaining operations).
480
	 */
481
	protected function set_warning_based_on_content( $content, $post_id ) {
482
483
		// Check for suspicious interpolations.
484
		$is_warning = $this->has_interpolation_errors( $content );
485
486
		// Set the warning flag accordingly.
487
		$this->set_warning( $post_id, $is_warning );
488
489
	}
490
491
	private function has_interpolation_errors( $content ) {
492
		$matches = array();
493
494
		return 0 < preg_match_all( '/\w<[a-z]+ id="urn:enhancement - [^"]+" class="[^"]+ " itemid="[^"]+" >/', $content, $matches )
495
			   || 0 < preg_match_all( ' /<[ a - z ] + id = "urn:enhancement-[^"]+ " class="[^"]+" itemid = "[^"]+ ">\s/', $content, $matches );
496
	}
497
498
	/**
499
	 * Fix interpolation errors raised by Batch Analysis
500
	 *
501
	 * @param string $content The {@link WP_Post}'s content.
502
	 * @param int    $id      The {@link WP_Post}'s id.
503
	 *
504
	 * @since 3.17.0
505
	 *
506
	 * @return string Post content without interpolations.
507
	 */
508
	private function fix_interpolation_errors( $content, $id ) {
509
510
		// Bail out if there are no interpolation errors.
511
		if ( ! $this->has_interpolation_errors( $content ) ) {
512
			return $content;
513
		}
514
515
		$this->log->debug( "Fixing post $id interpolations..." );
516
517
		// Remove all interpolations from the content.
518
		return preg_replace( self::INTERPOLATION_PATTERNS, '$1$2', $content );
519
	}
520
521
	/**
522
	 * Clear the warning flag for the specified {@link WP_Post}s.
523
	 *
524
	 * @since 3.14.2
525
	 *
526
	 * @param int|array $post_ids A single {@link WP_Post}'s id or an array of
527
	 *                            {@link WP_Post}s' ids.
528
	 */
529
	public function clear_warning( $post_ids ) {
530
531
		foreach ( (array) $post_ids as $post_id ) {
532
			delete_post_meta( $post_id, self::WARNING_META_KEY );
533
		}
534
535
	}
536
537
	/**
538
	 * Set the warning flag for the specified {@link WP_Post}.
539
	 *
540
	 * @since 3.14.2
541
	 *
542
	 * @param int  $post_id The {@link WP_Post}'s id.
543
	 * @param bool $value   The flag's value.
544
	 *
545
	 * @return int|bool Meta ID if the key didn't exist, true on successful update,
546
	 *                  false on failure.
547
	 */
548
	private function set_warning( $post_id, $value ) {
549
550
		return update_post_meta( $post_id, self::WARNING_META_KEY, ( true === $value ? 'yes' : 'no' ) );
551
	}
552
553
//	/**
554
//	 * Get the post/page batch analysis state.
555
//	 *
556
//	 * @since 3.14.2
557
//	 *
558
//	 * @param int $post_id The {@link WP_Post}'s id.
559
//	 *
560
//	 * @return int|string The post state or an empty string if not set.
561
//	 */
562
//	public function get_state( $post_id ) {
563
//
564
//		return get_post_meta( $post_id, self::STATE_META_KEY, true );
565
//	}
566
567
	/**
568
	 * Set the post/page batch analysis state.
569
	 *
570
	 * @since 3.14.2
571
	 *
572
	 * @param int $post_id The {@link WP_Post}'s id.
573
	 * @param int $value   The new state.
574
	 *
575
	 * @return int|bool Meta ID if the key didn't exist, true on successful update,
576
	 *                  false on failure.
577
	 */
578
	private function set_state( $post_id, $value ) {
579
580
		// Update the state.
581
		$result = update_post_meta( $post_id, self::STATE_META_KEY, $value );
582
583
		// Update timestamps as required.
584
		switch ( $value ) {
585
586
			// ### REQUEST state.
587
			case self::STATE_REQUEST:
588
				add_post_meta( $post_id, self::REQUEST_TIMESTAMP_META_KEY, current_time( 'mysql', true ) );
589
				break;
590
591
			// ### SUCCESS/ERROR state.
592
			case self::STATE_SUCCESS:
593
			case self::STATE_ERROR:
594
				add_post_meta( $post_id, self::COMPLETE_TIMESTAMP_META_KEY, current_time( 'mysql', true ) );
595
				break;
596
		}
597
598
		// Finally return the result.
599
		return $result;
600
	}
601
602
	/**
603
	 * Get the options setting for a {@link WP_Post}.
604
	 *
605
	 * If there are multiple link settings, only the last one is returned.
606
	 *
607
	 * @since 3.14.2
608
	 *
609
	 * @param int $post_id The {@link WP_Post}'s id.
610
	 *
611
	 * @return array The link settings.
612
	 */
613
	private function get_options( $post_id ) {
614
615
		$values = get_post_meta( $post_id, self::BATCH_ANALYSIS_OPTIONS_META_KEY );
616
617
		return end( $values ) ?: array(
618
			'links'           => 'default',
619
			'min_occurrences' => 1,
620
		);
621
	}
622
623
	/**
624
	 * Get the array of post IDS waiting in the queue to start processing.
625
	 *
626
	 * @since 3.14.0
627
	 *
628
	 * @return array The waiting to be processed post ids queue.
629
	 */
630 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...
631
632
		return get_posts( array(
633
			'posts_per_page' => - 1,
634
			'fields'         => 'ids',
635
			'post_status'    => 'any',
636
			'meta_key'       => self::STATE_META_KEY,
637
			'meta_value'     => self::STATE_SUBMIT,
638
			'orderby'        => 'ID',
639
			'post_type'      => 'any',
640
			// Add any because posts from multiple posts types may be waiting.
641
		) );
642
	}
643
644
	/**
645
	 * Get the array of post IDS waiting for response.
646
	 *
647
	 * @deprecated
648
	 * @since 3.14.0
649
	 *
650
	 * @return array The waiting for response post ids queue.
651
	 */
652 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...
653
654
		return get_posts( array(
655
			'posts_per_page' => - 1,
656
			'fields'         => 'ids',
657
			'post_status'    => 'any',
658
			'meta_key'       => self::STATE_META_KEY,
659
			'meta_value'     => self::STATE_REQUEST,
660
			'orderby'        => 'ID',
661
			'post_type'      => 'any',
662
			// Add any because posts from multiple posts types may be waiting.
663
		) );
664
	}
665
666
	/**
667
	 * Request the analysis for the specified {@link WP_Post}.
668
	 *
669
	 * @since 3.14.2
670
	 *
671
	 * @param int $post_id The {@link WP_Post}'s id.
672
	 *
673
	 * @return WP_Error|array The response or WP_Error on failure.
674
	 */
675
	private function do_request( $post_id ) {
676
677
		// Change the state to `REQUEST`.
678
		$this->set_state( $post_id, self::STATE_REQUEST );
679
680
		// Get the post.
681
		$post = get_post( $post_id );
682
683
		// Bail out if the post isn't found.
684
		if ( null === $post ) {
685
			$this->log->warn( "Post $post_id not found." );
686
687
			return new WP_Error( 0, "Cannot find post $post_id." );
688
		}
689
690
		// Get the link setting.
691
		$options = $this->get_options( $post_id );
692
693
		$this->log->debug( 'Sending analysis request for post $post_id [ link :: ' . $options['link'] . ', min_occurrences :: ' . $options['min_occurrences'] . ' ] ...' );
694
695
		// Get the batch analysis URL.
696
		$url = $this->configuration_service->get_batch_analysis_url();
697
698
		// Prepare the POST parameters.
699
		$params = array(
700
			'id'              => $post->ID,
701
			'key'             => $this->configuration_service->get_key(),
702
			'content'         => $post->post_content,
703
			'contentLanguage' => $this->configuration_service->get_language_code(),
704
			'version'         => $this->plugin->get_version(),
705
			'scope'           => 'local',
706
			'link'            => $options['link'],
707
			'minOccurrences'  => $options['min_occurrences'],
708
		);
709
710
		// Get the HTTP options.
711
		$args = array_merge_recursive( unserialize( WL_REDLINK_API_HTTP_OPTIONS ), array(
712
			'method'      => 'POST',
713
			'headers'     => array(
714
				'Accept'       => 'application/json',
715
				'Content-type' => 'application/json; charset=UTF-8',
716
			),
717
			// we need to downgrade the HTTP version in this case since chunked encoding is dumping numbers in the response.
718
			'httpversion' => '1.0',
719
			'body'        => wp_json_encode( $params ),
720
		) );
721
722
		$this->log->debug( "Posting analysis request for post $post_id to $url..." );
723
724
		// Post the parameter.
725
		return wp_remote_post( $url, $args );
726
	}
727
728
	/**
729
	 * Get the Batch Analysis results for the specified {@link WP_Post}.
730
	 *
731
	 * @since 3.14.2
732
	 *
733
	 * @param int $post_id The {@link WP_Post}'s id.
734
	 *
735
	 * @return WP_Error|array The response or WP_Error on failure.
736
	 */
737
	private function do_complete( $post_id ) {
738
739
		$post = get_post( $post_id );
740
741
		if ( null === $post ) {
742
			// Post was possibly deleted, just bailout.
743
			return new WP_Error( 0, "Post $post_id not found . " );
744
		}
745
746
		$url = $this->configuration_service->get_batch_analysis_url();
747
		$key = $this->configuration_service->get_key();
748
		$url = $url . '/' . $post->ID . '?key=' . $key;
749
750
		return wp_remote_get( $url, unserialize( WL_REDLINK_API_HTTP_OPTIONS ) );
751
	}
752
753
	/**
754
	 * Get the {@link WP_Post}s' ids flagged with warnings.
755
	 *
756
	 * @since 3.14.2
757
	 *
758
	 * @return array An array of {@link WP_Post}s' ids.
759
	 */
760 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...
761
762
		return get_posts( array(
763
			'fields'      => 'ids',
764
			'numberposts' => - 1,
765
			'post_status' => 'any',
766
			'meta_key'    => self::WARNING_META_KEY,
767
			'meta_value'  => 'yes',
768
			'post_type'   => 'any',
769
			// Add any because posts from multiple posts types may be waiting.
770
		) );
771
	}
772
773
	/**
774
	 * Check whether the term has entity type associated and set default term if it hasn't.
775
	 *
776
	 * @since 3.17.0
777
	 *
778
	 * @param int $id The {@link WP_Post}'s id.
779
	 */
780
	private function maybe_set_default_term( $id ) {
781
		// Check whether the post has any of the WordLift entity types.
782
		$has_term = has_term( '', Wordlift_Entity_Types_Taxonomy_Service::TAXONOMY_NAME, $id );
783
784
		// Bail if the term is associated with entity types already.
785
		if ( ! empty( $has_term ) ) {
786
			return;
787
		}
788
789
		// Set the default `article` term.
790
		wp_set_object_terms( $id, 'article', Wordlift_Entity_Types_Taxonomy_Service::TAXONOMY_NAME );
791
792
	}
793
794
}
795