1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* |
4
|
|
|
* Class BatchRequetProcessor |
5
|
|
|
* |
6
|
|
|
* Responsible for receiving a request to start a job and assign it a job Id. |
7
|
|
|
* Then when subsequent requests come in to continue that job, dispatches |
8
|
|
|
* the request to the appropriate JobHandler, which processes a step of the batch, |
9
|
|
|
* and then returns the job's new status. |
10
|
|
|
* This class is used by controller code, and the controller code is sent HTTP |
11
|
|
|
* requests from the batch_runner.js library |
12
|
|
|
* |
13
|
|
|
* @package Event Espresso |
14
|
|
|
* @subpackage batch |
15
|
|
|
* @author Mike Nelson |
16
|
|
|
* @since 4.8.26 |
17
|
|
|
* |
18
|
|
|
*/ |
19
|
|
|
namespace EventEspressoBatchRequest; |
20
|
|
|
|
21
|
|
|
use EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerInterface; |
22
|
|
|
use EventEspressoBatchRequest\Helpers\BatchRequestException; |
23
|
|
|
use EventEspressoBatchRequest\Helpers\JobParameters; |
24
|
|
|
use EventEspressoBatchRequest\Helpers\JobStepResponse; |
25
|
|
|
|
26
|
|
|
if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) { |
27
|
|
|
exit( 'No direct script access allowed' ); |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
|
31
|
|
|
|
32
|
|
|
class BatchRequestProcessor { |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Current job's ID (if assigned) |
36
|
|
|
* @var string|null |
37
|
|
|
*/ |
38
|
|
|
protected $_job_id; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Current job's parameters |
42
|
|
|
* @var JobParameters|null |
43
|
|
|
*/ |
44
|
|
|
protected $_job_parameters; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Creates a job for the specified batch handler class (which should be autoloaded) |
48
|
|
|
* and the specified request data |
49
|
|
|
* @param string $batch_job_handler_class of an auto-loaded class implementing JobHandlerInterface |
50
|
|
|
* @param array $request_data to be used by the batch job handler |
51
|
|
|
* @return JobStepResponse |
52
|
|
|
*/ |
53
|
|
|
public function create_job( $batch_job_handler_class, $request_data ) { |
54
|
|
|
try { |
55
|
|
|
$this->_job_id = wp_generate_password( 15, false ); |
56
|
|
|
$obj = $this->instantiate_batch_job_handler_from_classname( $batch_job_handler_class ); |
57
|
|
|
$this->_job_parameters = new JobParameters( $this->_job_id, $batch_job_handler_class, $request_data ); |
58
|
|
|
$response = $obj->create_job( $this->_job_parameters ); |
59
|
|
View Code Duplication |
if( ! $response instanceof JobStepResponse ) { |
|
|
|
|
60
|
|
|
throw new BatchRequestException( |
61
|
|
|
sprintf( |
62
|
|
|
__( 'The class implementing JobHandlerInterface did not return a JobStepResponse when create_job was called with %1$s. It needs to return one or throw an Exception', 'event_espresso' ), |
63
|
|
|
wp_json_encode( $request_data ) |
64
|
|
|
) |
65
|
|
|
); |
66
|
|
|
} |
67
|
|
|
$success = $this->_job_parameters->save( true ); |
68
|
|
View Code Duplication |
if( ! $success ) { |
|
|
|
|
69
|
|
|
throw new BatchRequestException( |
70
|
|
|
sprintf( |
71
|
|
|
__('Could not save job %1$s to the Wordpress Options table. These were the arguments used: %2$s', 'event_espresso'), |
72
|
|
|
$this->_job_id, |
73
|
|
|
wp_json_encode( $request_data ) |
74
|
|
|
) |
75
|
|
|
); |
76
|
|
|
} |
77
|
|
|
} catch( \Exception $e ) { |
78
|
|
|
$response = $this->_get_error_response( $e, 'create_job' ); |
79
|
|
|
} |
80
|
|
|
return $response; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
|
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Retrieves the job's arguments |
87
|
|
|
* @param string $job_id |
88
|
|
|
* @param int $batch_size |
89
|
|
|
* @return JobStepResponse |
90
|
|
|
*/ |
91
|
|
|
public function continue_job( $job_id, $batch_size = 50 ) { |
92
|
|
|
try { |
93
|
|
|
$this->_job_id = $job_id; |
94
|
|
|
$batch_size = defined( 'EE_BATCHRUNNER_BATCH_SIZE' ) ? EE_BATCHRUNNER_BATCH_SIZE : $batch_size; |
95
|
|
|
//get the corresponding WordPress option for the job |
96
|
|
|
$this->_job_parameters = JobParameters::load( $this->_job_id ); |
97
|
|
|
$handler_obj = $this->instantiate_batch_job_handler_from_classname( $this->_job_parameters->classname() ); |
98
|
|
|
//continue it |
99
|
|
|
$response = $handler_obj->continue_job( $this->_job_parameters, $batch_size ); |
100
|
|
View Code Duplication |
if( ! $response instanceof JobStepResponse ) { |
|
|
|
|
101
|
|
|
throw new BatchRequestException( |
102
|
|
|
sprintf( |
103
|
|
|
__( 'The class implementing JobHandlerInterface did not return a JobStepResponse when continue_job was called with job %1$s. It needs to return one or throw an Exception', 'event_espresso' ), |
104
|
|
|
$this->_job_id |
105
|
|
|
) |
106
|
|
|
); |
107
|
|
|
} |
108
|
|
|
$this->_job_parameters->save(); |
109
|
|
|
} catch( \Exception $e ) { |
110
|
|
|
$response = $this->_get_error_response( $e, 'continue_job' ); |
111
|
|
|
} |
112
|
|
|
return $response; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
|
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Instantiates an object of type $classname, which implements |
119
|
|
|
* JobHandlerInterface |
120
|
|
|
* |
121
|
|
|
* @param string $classname |
122
|
|
|
* @return JobHandlerInterface |
123
|
|
|
* @throws BatchRequestException |
124
|
|
|
*/ |
125
|
|
|
public function instantiate_batch_job_handler_from_classname( $classname ) { |
126
|
|
|
if( ! class_exists( $classname ) ) { |
127
|
|
|
throw new BatchRequestException( |
128
|
|
|
sprintf( |
129
|
|
|
__('The class %1$s does not exist, and so could not be used for running a job. It should implement JobHandlerInterface.', 'event_espresso'), |
130
|
|
|
$classname |
131
|
|
|
) |
132
|
|
|
); |
133
|
|
|
} |
134
|
|
|
$obj = new $classname; |
135
|
|
|
if( ! $obj instanceof JobHandlerInterface ) { |
136
|
|
|
throw new BatchRequestException( |
137
|
|
|
sprintf( |
138
|
|
|
__('The class %1$s does not implement JobHandlerInterface and so could not be used for running a job', 'event_espresso'), |
139
|
|
|
$classname |
140
|
|
|
) |
141
|
|
|
); |
142
|
|
|
} |
143
|
|
|
return $obj; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
|
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Forces a job to be cleaned up |
150
|
|
|
* |
151
|
|
|
* @param string $job_id |
152
|
|
|
* @return JobStepResponse |
153
|
|
|
* @throws BatchRequestException |
154
|
|
|
*/ |
155
|
|
|
public function cleanup_job( $job_id ) { |
156
|
|
|
try{ |
157
|
|
|
$this->_job_id = $job_id; |
158
|
|
|
$job_parameters = JobParameters::load( $this->_job_id ); |
159
|
|
|
$handler_obj = $this->instantiate_batch_job_handler_from_classname( $job_parameters->classname() ); |
160
|
|
|
//continue it |
161
|
|
|
$response = $handler_obj->cleanup_job( $job_parameters ); |
162
|
|
View Code Duplication |
if( ! $response instanceof JobStepResponse ) { |
|
|
|
|
163
|
|
|
throw new BatchRequestException( |
164
|
|
|
sprintf( |
165
|
|
|
__( 'The class implementing JobHandlerInterface did not return a JobStepResponse when cleanup_job was called with job %1$s. It needs to return one or throw an Exception', 'event_espresso' ), |
166
|
|
|
$this->_job_id |
167
|
|
|
) |
168
|
|
|
); |
169
|
|
|
} |
170
|
|
|
$job_parameters->set_status( JobParameters::status_cleaned_up ); |
171
|
|
|
$job_parameters->delete(); |
172
|
|
|
return $response; |
173
|
|
|
} catch( \Exception $e ) { |
174
|
|
|
$response = $this->_get_error_response( $e, 'cleanup_job' ); |
175
|
|
|
} |
176
|
|
|
return $response; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
|
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Creates a valid JobStepResponse object from an exception and method name. |
183
|
|
|
* @param \Exception $exception |
184
|
|
|
* @param string $method_name |
185
|
|
|
* @return JobStepResponse |
186
|
|
|
*/ |
187
|
|
|
protected function _get_error_response( \Exception $exception, $method_name ) { |
188
|
|
|
if( ! $this->_job_parameters instanceof JobParameters ) { |
189
|
|
|
$this->_job_parameters = new JobParameters( $this->_job_id, __( '__Unknown__', 'event_espresso' ), array() ); |
190
|
|
|
} |
191
|
|
|
$this->_job_parameters->set_status( JobParameters::status_error ); |
192
|
|
|
return new JobStepResponse( |
193
|
|
|
$this->_job_parameters, |
194
|
|
|
sprintf( |
195
|
|
|
__('An exception of type %1$s occurred while running %2$s. Its message was %3$s and had trace %4$s', 'event_espresso'), |
196
|
|
|
get_class( $exception ), |
197
|
|
|
'BatchRunner::' . $method_name . '()', |
198
|
|
|
$exception->getMessage(), |
199
|
|
|
$exception->getTraceAsString() |
200
|
|
|
) |
201
|
|
|
); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
|
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
|
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.