|
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() ) { |
|
|
|
|
|
|
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 ++ ) { |
|
|
|
|
|
|
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
|
|
|
|
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.