Completed
Pull Request — develop (#1328)
by Naveen
02:57
created

Analysis_Background_Process   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 207
Duplicated Lines 2.9 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 6
loc 207
rs 10
c 0
b 0
f 0
wmc 23
lcom 1
cbo 4

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A task() 3 15 4
A start() 3 22 4
A request_cancel() 0 5 1
A get_state() 0 9 2
A is_started() 0 3 3
A must_cancel() 0 4 1
A cancel() 0 16 1
B sync_items() 0 45 6

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
namespace Wordlift\Vocabulary;
4
5
class Analysis_Background_Process extends \Wordlift_Plugin_WP_Background_Process {
6
7
	const WL_CMKG_ANALYSIS_BACKGROUND_PROCESS = '_wl_cmkg_analysis_background_process';
8
9
10
	protected $action = 'wl_cmkg_analysis_background__analysis';
11
12
	/**
13
	 * @var Analysis_Background_Service
14
	 */
15
	private $analysis_background_service;
16
17
	/**
18
	 * @var \Wordlift_Log_Service
19
	 */
20
	private $log;
21
22
	/**
23
	 * Analysis_Background_Process constructor.
24
	 *
25
	 * @param $analysis_background_service Analysis_Background_Service A {@link Analysis_Background_Service} instance providing the supporting functions to this background process.
26
	 */
27
	public function __construct( $analysis_background_service ) {
28
		parent::__construct();
29
30
		$this->log = \Wordlift_Log_Service::get_logger( get_class() );
31
32
		$this->analysis_background_service = $analysis_background_service;
33
34
35
	}
36
37
	/**
38
	 * This function is called:
39
	 *  - To start a new Synchronization, by passing a {@link Sync_Start_Message} instance.
40
	 *  - To synchronize a post, by passing a numeric ID.
41
	 *
42
	 * This function returns the parameter for the next call or NULL if there are no more posts to process.
43
	 *
44
	 * @param int[] $term_ids An array of term IDs.
45
	 *
46
	 * @return int[]|false The next term IDs or false if there are no more.
47
	 */
48
	protected function task( $term_ids ) {
49
50
		// Check if we must cancel.
51
		if ( $this->must_cancel() ) {
52
			$this->cancel();
53
54
			return false;
55
		}
56
57 View Code Duplication
		if ( $term_ids && is_array($term_ids) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $term_ids of type integer[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Duplication introduced by
This code seems to be duplicated across 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...
58
			$this->log->debug( sprintf( "Synchronizing terms %s...", implode( ', ', $term_ids ) ) );
59
		}
60
		// Sync the item.
61
		return $this->sync_items( $term_ids );
62
	}
63
64
	/**
65
	 * Start the background processing.
66
	 *
67
	 * @return bool True if the process has been started, otherwise false.
68
	 */
69
	public function start() {
70
		$this->log->debug( "Trying to start analysis bg service..." );
71
		// Create a new Sync_Model state of `started`.
72
		if ( ! $this->is_started( self::get_state() ) ) {
73
			$this->log->debug( "Starting..." );
74
75
			$sync_state = new Sync_State( time(), 0, $this->analysis_background_service->count(), time(), 'started' );
76
			update_option( self::WL_CMKG_ANALYSIS_BACKGROUND_PROCESS, $sync_state, false );
77
78
			$next = $this->analysis_background_service->next();
79
80
			$this->push_to_queue( $next );
81
			$this->save()->dispatch();
82
83 View Code Duplication
			if ( $next && is_array($next) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
84
				$this->log->debug( sprintf( 'Started with term IDs %s.', implode( ', ', $next ) ) );
85
			}
86
			return true;
87
		}
88
89
		return false;
90
	}
91
92
	/**
93
	 * Set the transient to cancel the process. The next time the process runs, it'll check whether this transient is
94
	 * set and will stop processing.
95
	 */
96
	public function request_cancel() {
97
98
		set_transient( "{$this->action}__cancel", true );
99
100
	}
101
102
	/**
103
	 * Get the sync state.
104
	 *
105
	 * @return Sync_State The {@link Sync_State}.
106
	 */
107
	public static function get_state() {
108
109
		try {
110
			return get_option( self::WL_CMKG_ANALYSIS_BACKGROUND_PROCESS, Sync_State::unknown() );
111
		} catch ( \Exception $e ) {
112
			return Sync_State::unknown();
113
		}
114
115
	}
116
117
	/**
118
	 * Check whether the provided state is `started` or not.
119
	 *
120
	 * @param Sync_State $state The {@link Sync_State}.
121
	 *
122
	 * @return bool True if the state is started.
123
	 */
124
	private function is_started( $state ) {
125
		return $state instanceof Sync_State && 'started' === $state->state && 30 > ( time() - $state->last_update );
126
	}
127
128
	/**
129
	 * Check whether the process must cancel or not.
130
	 *
131
	 * @return bool Whether to cancel or not the process.
132
	 */
133
	private function must_cancel() {
134
135
		return get_transient( "{$this->action}__cancel" );
136
	}
137
138
	/**
139
	 * Cancels the current process.
140
	 */
141
	public function cancel() {
142
143
		$this->log->debug( "Cancelling synchronization..." );
144
145
		// Cleanup the process data.
146
		$this->cancel_process();
147
148
		// Set the state to cancelled.
149
		$state = self::get_state();
150
		$state->set_state( 'cancelled' );
151
		update_option( self::WL_CMKG_ANALYSIS_BACKGROUND_PROCESS, $state, false );
152
153
		// Finally delete the transient.
154
		delete_transient( "{$this->action}__cancel" );
155
156
	}
157
158
	/**
159
	 * Push the post with the provided ID to the remote platform.
160
	 *
161
	 * @param int[] $term_ids The term IDs.
162
	 *
163
	 * @return int[]|false The next term ID to process or false if processing is complete.
164
	 */
165
	private function sync_items( $term_ids ) {
166
167
168
		$this->log->debug( "sync_items called with term ids : " . join( ",", $term_ids ) );
169
170
		if (! $term_ids ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $term_ids of type integer[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
171
			$this->cancel_process();
172
			return false;
173
		}
174
175
		if ( ! is_array( $term_ids ) ) {
176
			$this->log->error( '$term_ids must be an array, received: ' . var_export( $term_ids, true ) );
177
178
			return false;
179
		}
180
181
		// Sync this item.
182
		if ( $this->analysis_background_service->perform_analysis_for_terms( $term_ids ) ) {
183
184
			$next       = $this->analysis_background_service->next();
185
			$next_state = isset( $next ) ? 'started' : 'ended';
186
187
			/**
188
			 * Update the synchronization meta data, by increasing the current index.
189
			 *
190
			 * @var Sync_State $sync The {@link Sync_State}.
191
			 */
192
			$state = self::get_state()
193
			             ->increment_index( $this->analysis_background_service->get_batch_size() )
194
			             ->set_state( $next_state );
195
			update_option( self::WL_CMKG_ANALYSIS_BACKGROUND_PROCESS . '', $state, false );
196
197
198
			// Return the next IDs or false if there aren't.
199
			return isset( $next ) ? $next : false;
200
		} else {
201
			// Retry.
202
			// @@todo: put a limit to the number of retries.
203
204
			$this->log->error( sprintf( "Sync failed for terms %s.", implode( ', ', $term_ids ) ) );
205
206
			return $term_ids;
207
		}
208
209
	}
210
211
}
212