PluginProbe
Tutor LMS – eLearning and online course solution / 3.9.2
Tutor LMS – eLearning and online course solution v3.9.2
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 All 191 releases
tutor / migrations / BatchProcessor.php

BatchProcessor.php in Tutor LMS – eLearning and online course solution 3.9.2, at migrations/BatchProcessor.php

297 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class to handle process large amount of data with batch.
4 *
5 * @package Tutor
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 3.8.0
9 */
10
11 namespace Tutor\Migrations;
12
13 use Tutor\Migrations\Contracts\BulkProcessor;
14 use Tutor\Migrations\Contracts\SingleProcessor;
15
16 /**
17 * Class BatchProcessor
18 *
19 * @since 3.8.0
20 */
21 abstract class BatchProcessor {
22 /**
23 * Batch size.
24 *
25 * @since 3.8.0
26 *
27 * @var int
28 */
29 protected $batch_size;
30
31 /**
32 * Schedule interval
33 *
34 * @since 3.8.0
35 *
36 * @var int
37 */
38 protected $schedule_interval;
39
40 /**
41 * Progress option name to keep track of each process status.
42 *
43 * @since 3.8.0
44 *
45 * @var string
46 */
47 protected $progress_option;
48
49 /**
50 * Manage child class as singleton behavior.
51 *
52 * @since 3.8.0
53 *
54 * @var object
55 */
56 protected static $instances = array();
57
58 /**
59 * Action name to invoke wp-cron.
60 *
61 * @since 3.8.0
62 *
63 * @var string
64 */
65 protected $action;
66
67 /**
68 * Name of the process.
69 *
70 * @since 3.8.0
71 *
72 * @var string
73 */
74 protected $name;
75
76 /**
77 * Constructor.
78 *
79 * @since 3.8.0
80 *
81 * @throws \Exception If action is not set.
82 */
83 protected function __construct() {
84 if ( empty( $this->action ) ) {
85 throw new \Exception( 'Action property must be defined in the subclass.' );
86 }
87
88 $this->progress_option = "tutor_batch_processor_{$this->action}";
89 add_action( $this->action, array( $this, 'process_batch' ) );
90 }
91
92 /**
93 * Get child class instance.
94 *
95 * @since 3.8.0
96 *
97 * @return object
98 */
99 public static function instance() {
100 if ( ! isset( static::$instances[ static::class ] ) ) {
101 static::$instances[ static::class ] = new static();
102 }
103 return static::$instances[ static::class ];
104 }
105
106 /**
107 * Get items to process.
108 * Must be implemented in child class.
109 *
110 * @since 3.8.0
111 *
112 * @param int $offset offset.
113 * @param int $limit limit.
114 *
115 * @return array
116 */
117 abstract protected function get_items( $offset, $limit) : array;
118
119 /**
120 * Get total items to process.
121 * Must be implemented in child class.
122 *
123 * @since 3.8.0
124 *
125 * @return int
126 */
127 abstract protected function get_total_items() : int;
128
129 /**
130 * Schedule the batch processing.
131 *
132 * This method checks if the action is already scheduled, and if not, it schedules a single event
133 * to trigger the batch processing after the specified interval.
134 *
135 * @since 3.8.0
136 *
137 * @return void
138 */
139 public function schedule() {
140 if ( ! wp_next_scheduled( $this->action ) ) {
141 wp_schedule_single_event( time() + $this->schedule_interval, $this->action );
142 }
143 }
144
145 /**
146 * Process a batch of items.
147 *
148 * This method retrieves a batch of items based on the current offset and batch size,
149 * processes each item, updates the progress, and schedules the next batch processing.
150 *
151 * @since 3.8.0
152 *
153 * @return void
154 *
155 * @throws \Exception If not implemented any interface on child class..
156 */
157 public function process_batch() {
158 $progress = get_option(
159 $this->progress_option,
160 array(
161 'name' => $this->name,
162 'started_at' => gmdate( 'Y-m-d H:i:s' ),
163 'completed_at' => null,
164 'offset' => 0,
165 'completed' => false,
166 'total_items' => null,
167 'total_batch' => null,
168 'per_batch' => $this->batch_size,
169 'current_batch' => 1,
170 )
171 );
172
173 if ( $progress['completed'] ) {
174 return;
175 }
176
177 // Set total_items and total_batch if not already set.
178 if ( is_null( $progress['total_items'] ) ) {
179 $progress['total_items'] = $this->get_total_items();
180 $progress['total_batch'] = (int) ceil( $progress['total_items'] / $progress['per_batch'] );
181 }
182
183 $items = $this->get_items( $progress['offset'], $this->batch_size );
184
185 if ( empty( $items ) ) {
186 $this->mark_complete();
187 return;
188 }
189
190 if ( $this instanceof BulkProcessor ) {
191 $this->process_items( $items );
192 } elseif ( $this instanceof SingleProcessor ) {
193 foreach ( $items as $item ) {
194 $this->process_item( $item );
195 }
196 } else {
197 throw new \Exception( 'Child class must implement SingleProcessor or BulkProcessor interface.' );
198 }
199
200 $progress['offset'] += count( $items );
201 $progress['current_batch'] = (int) ceil( $progress['offset'] / $progress['per_batch'] );
202 update_option( $this->progress_option, $progress );
203
204 wp_schedule_single_event( time() + $this->schedule_interval, $this->action );
205 }
206
207 /**
208 * Mark the batch processing as complete.
209 *
210 * This method updates the progress option to indicate that the batch processing is complete
211 * and calls the optional `on_complete` method for any additional actions needed upon completion.
212 *
213 * @since 3.8.0
214 *
215 * @return void
216 */
217 protected function mark_complete() {
218 $data = wp_parse_args(
219 array(
220 'offset' => 0,
221 'completed' => true,
222 'completed_at' => gmdate( 'Y-m-d H:i:s' ),
223 ),
224 $this->get_stats()
225 );
226
227 update_option( $this->progress_option, $data );
228
229 $this->on_complete();
230 }
231
232 /**
233 * Optional method to override in child classes to perform actions when the batch processing is complete.
234 *
235 * @since 3.8.0
236 *
237 * @return void
238 */
239 protected function on_complete() {}
240
241 /**
242 * Check is complete.
243 *
244 * @since 3.8.0
245 *
246 * @return boolean
247 */
248 public function is_completed(): bool {
249 $progress = get_option( $this->progress_option, array() );
250 return ! empty( $progress['completed'] );
251 }
252
253 /**
254 * Get the progress option name.
255 *
256 * @since 3.8.0
257 *
258 * @return string
259 */
260 public function get_progress_option_name() {
261 return $this->progress_option;
262 }
263
264 /**
265 * Get the progress stats.
266 *
267 * @since 3.8.0
268 *
269 * @return array
270 */
271 public function get_stats(): array {
272 $progress = get_option( $this->progress_option, array() );
273 return wp_parse_args(
274 $progress,
275 array(
276 'offset' => 0,
277 'completed' => false,
278 'total_items' => 0,
279 'total_batch' => 0,
280 'per_batch' => $this->batch_size,
281 'current_batch' => 1,
282 )
283 );
284 }
285
286 /**
287 * Reset the progress option.
288 *
289 * @since 3.8.0
290 *
291 * @return void
292 */
293 public function reset() {
294 delete_option( $this->progress_option );
295 }
296 }
297