Completed
Push — develop ( 1d4633...83eb6a )
by David
02:35 queued 10s
created

Task_Single_Instance_Task_Runner   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 194
Duplicated Lines 4.64 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 9
loc 194
rs 10
c 0
b 0
f 0
wmc 18
lcom 1
cbo 3

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 9 9 1
A get_running_transient() 0 4 1
A is_running() 0 3 1
A set_running() 0 3 2
A start() 0 31 4
A set_count() 0 11 3
A set_progress() 0 11 3
A finish() 0 11 3

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
 * This file defines the Task_Single_Instance_Task_Runner class
4
 * and the Task_Another_Instance_Is_Running_Exception exception.
5
 *
6
 * The single runner executes a non-concurrent {@link Task}
7
 * ensuring that only one instance of this task is executed. It does so by using WordPress
8
 * transients.
9
 *
10
 * This file is part of the task sub-folder.
11
 *
12
 * @since 1.0.0
13
 * @package Wordlift_Framework\Tasks
14
 */
15
16
namespace Wordlift\Tasks;
17
18
use Wordlift_Log_Service;
19
20
/**
21
 * Define the Task_Single_Instance_Task_Runner class.
22
 *
23
 * @since 1.0.0
24
 */
25
class Task_Single_Instance_Task_Runner {
26
27
	/**
28
	 * Define the transient prefix.
29
	 *
30
	 * @since 1.0.0
31
	 */
32
	const IS_RUNNING_PREFIX = '_wf_task_runner__';
33
34
	/**
35
	 * A {@link Wordlift_Log_Service} instance.
36
	 *
37
	 * @since 1.0.0
38
	 * @var Wordlift_Log_Service A {@link Wordlift_Log_Service} instance.
39
	 * @access private
40
	 */
41
	private $log;
42
43
	/**
44
	 * The {@link Task} to execute.
45
	 *
46
	 * @since 1.0.0
47
	 * @var Task $task The {@link Task} to execute.
48
	 * @access private
49
	 */
50
	private $task;
51
52
	/**
53
	 * One or more callbacks to call to update about the task progress.
54
	 *
55
	 * @since 1.0.0
56
	 * @var Task_Progress[] $callbacks An array of {@link Wordlift_For_Bungalowparkoverzicht_Progress}.
57
	 * @access private
58
	 */
59
	private $callbacks;
60
61
	/**
62
	 * Whether to force starting a task even if another instance of the task is already running.
63
	 *
64
	 * @since 1.0.0
65
	 * @var bool $force Whether to force starting a task even if another instance of the task is already running.
66
	 * @access private
67
	 */
68
	private $force;
69
70
	/**
71
	 * Create a {@link Task_Single_Instance_Task_Runner} instance.
72
	 *
73
	 * @param Task $task The {@link Task} instance.
74
	 * @param bool $force Whether to force starting a task even if another instance of the task is already running, default `false`.
75
	 * @param array $callbacks An array of {@link Wordlift_For_Bungalowparkoverzicht_Progress}.
76
	 *
77
	 * @since 1.0.0
78
	 */
79 View Code Duplication
	public function __construct( $task, $force = false, $callbacks = array() ) {
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...
80
81
		$this->log = Wordlift_Log_Service::get_logger( get_class() );
82
83
		$this->task      = $task;
84
		$this->force     = $force;
85
		$this->callbacks = $callbacks;
86
87
	}
88
89
	/**
90
	 * Get the transient name for running flag.
91
	 *
92
	 * @return string The transient name.
93
	 * @since 1.0.0
94
	 */
95
	private function get_running_transient() {
96
97
		return self::IS_RUNNING_PREFIX . $this->task->get_id();
98
	}
99
100
	/**
101
	 * Check whether a task is running.
102
	 *
103
	 * @return bool
104
	 * @since 1.0.0
105
	 */
106
	public function is_running() {
107
		return 'yes' === get_transient( $this->get_running_transient() );
108
	}
109
110
	/**
111
	 * Set whether the task is running or not.
112
	 *
113
	 * @param bool $value Whether the task is running or not.
114
	 *
115
	 * @since 1.0.0
116
	 */
117
	public function set_running( $value ) {
118
		set_transient( $this->get_running_transient(), $value ? 'yes' : 'no' );
119
	}
120
121
	/**
122
	 * Start the task.
123
	 *
124
	 * @param int $limit The maximum number of items to process.
125
	 * @param int $offset The starting offset.
126
	 *
127
	 * @throws Task_Another_Instance_Is_Running_Exception if the task is already running.
128
	 * @since 1.0.0
129
	 */
130
	public function start( $limit = 0, $offset = 0 ) {
131
132
		// Bail out if the task is already running.
133
		if ( ! $this->force && $this->is_running() ) {
134
			throw new Task_Another_Instance_Is_Running_Exception();
135
		}
136
137
		// Set the task as running.
138
		$this->set_running( true );
139
140
		// List the chunk of elements to process.
141
		$items = $this->task->list_items( $limit, $offset );
142
143
		for ( $i = 0; $i < count( $items ); $i ++ ) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
144
			// Process the item.
145
			$this->task->process_item( $items[ $i ] );
146
147
			// Update the progress.
148
			$this->set_progress( $offset + $i, $items[ $i ] );
149
		}
150
151
		// Set the total number of elements to process.
152
		$this->set_count( $this->task->count_items() );
153
154
		// Unset the running flag.
155
		$this->set_running( false );
156
157
		// Set the task to complete.
158
		$this->finish();
159
160
	}
161
162
	/**
163
	 * Set the total number of items to process.
164
	 *
165
	 * @param int $value The total number of items to process.
166
	 *
167
	 * @since 1.0.0
168
	 */
169
	private function set_count( $value ) {
170
171
		if ( empty( $this->callbacks ) ) {
172
			return;
173
		}
174
175
		foreach ( $this->callbacks as $callback ) {
176
			call_user_func( array( $callback, 'set_count' ), $value );
177
		}
178
179
	}
180
181
	/**
182
	 * Set the task progress.
183
	 *
184
	 * @param int $index The current item index.
185
	 * @param mixed $item The current item.
186
	 *
187
	 * @since 1.0.0
188
	 */
189
	private function set_progress( $index, $item ) {
190
191
		if ( empty( $this->callbacks ) ) {
192
			return;
193
		}
194
195
		foreach ( $this->callbacks as $callback ) {
196
			call_user_func( array( $callback, 'set_progress' ), $index, $item );
197
		}
198
199
	}
200
201
	/**
202
	 * Inform the callbacks that the task completed.
203
	 *
204
	 * @since 1.0.0
205
	 */
206
	private function finish() {
207
208
		if ( empty( $this->callbacks ) ) {
209
			return;
210
		}
211
212
		foreach ( $this->callbacks as $callback ) {
213
			call_user_func( array( $callback, 'finish' ) );
214
		}
215
216
	}
217
218
}
219