Completed
Pull Request — develop (#1350)
by Naveen
02:56
created

Videoobject_Background_Process::is_started()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 3

Duplication

Lines 3
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 3
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Wordlift\Videoobject;
4
5 View Code Duplication
class Videoobject_Background_Process extends \Wordlift_Plugin_WP_Background_Process {
0 ignored issues
show
Duplication introduced by
This class 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...
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
		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...
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
			if ( $next && is_array($next) ) {
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;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term_ids; (array) is incompatible with the return type documented by Wordlift\Videoobject\Vid...und_Process::sync_items of type integer[]|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
207
		}
208
209
	}
210
211
}
212