PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.15.0
Import WP – CSV & XML Import Export for WordPress v2.15.0
2.15.1 2.15.0 2.14.24 2.14.23 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 All 144 releases
← All changes | class/Common/Importer/State/ImporterState.php +160 -238 2.7.3 → 2.15.0 View file →
@@ -5,26 +5,27 @@
5 5 use ImportWP\Common\Util\Logger;
6 6
7 7 class ImporterState
8 8 {
9 + private $data = [];
9 10 private $importer_id;
10 - private $user;
11 - protected $data;
11 + protected static $object_type = 'importer';
12 12
13 - public function __construct($importer_id, $user)
13 + public function __construct($importer_id, $user = '')
14 14 {
15 15 $this->importer_id = $importer_id;
16 - $this->user = $user;
17 16 }
18 17
19 - public function init($session)
18 + protected function default($session_id)
20 19 {
21 - $state = self::wait_for_lock_and_get_state($this->importer_id, $this->user, [
22 - 'id' => $session,
20 + return [
21 + 'id' => $session_id,
22 + 'status' => 'init',
23 23 'version' => 2,
24 - 'status' => 'init',
24 + 'message' => '',
25 + 'timestamp' => time(),
26 + 'duration' => 0,
25 27 'section' => 'import',
26 - 'message' => '',
27 28 'progress' => [
28 29 'import' => [
29 30 'start' => 0,
30 31 'end' => 0,
@@ -35,27 +36,35 @@
35 36 'end' => 0,
36 37 'current_row' => 0,
37 38 ]
38 39 ],
39 - 'updated' => time(),
40 - 'timestamp' => time(),
41 - 'duration' => 0
42 - ]);
40 + ];
41 + }
43 42
43 + public function init($session_id)
44 + {
45 + // get current or set default to new session_id
46 + $state = self::get_state($this->importer_id);
47 + if (!$state) {
48 + $state = $this->default($session_id);
49 + $this->set_state($this->importer_id, $state);
50 + }
51 +
44 52 if (!$state || !isset($state['status'])) {
45 - throw new \Exception("Invalid importer state");
53 + throw new \Exception(__("Invalid state", 'jc-importer'));
46 54 }
47 55
48 56 $this->populate($state);
49 57
50 - if (!$this->validate($session)) {
51 - throw new \Exception("Importer session has changed");
58 + if (!$this->validate($session_id)) {
59 + throw new \Exception(__("Session has changed", 'jc-importer'));
52 60 }
53 61 }
54 62
55 - public function populate($state)
63 +
64 + public function populate($state_data)
56 65 {
57 - foreach ($state as $name => $value) {
66 + foreach ($state_data as $name => $value) {
58 67 $this->data[$name] = $value;
59 68 }
60 69 }
61 70
@@ -71,29 +80,45 @@
71 80
72 81 return $this->data['status'] == $status;
73 82 }
74 83
75 - public function has_section($section)
84 + public function get_session()
76 85 {
77 - if (!isset($this->data['section'])) {
78 - return false;
86 + return isset($this->data['id']) ? $this->data['id'] : false;
87 + }
88 +
89 + public function update($callback)
90 + {
91 + $raw = [];
92 + if (is_callable($callback)) {
93 + $raw = call_user_func($callback, $this->data);
79 94 }
80 95
81 - if (is_array($section)) {
82 - return in_array($this->data['section'], $section);
83 - }
96 + $this->populate($raw);
84 97
85 - return $this->data['section'] == $section;
86 - }
98 + $this->set_state($this->importer_id, $this->data);
87 99
88 - public function get_session()
89 - {
90 - return isset($this->data['id']) ? $this->data['id'] : false;
100 + return $this;
91 101 }
92 102
93 - public function get_status()
103 + public function error($error)
94 104 {
95 - return isset($this->data['status']) ? $this->data['status'] : false;
105 + $this->update(function ($state) use ($error) {
106 + $state['status'] = 'error';
107 + if (is_wp_error($error)) {
108 + /**
109 + * @var \WP_Error $error
110 + */
111 + $state['message'] = $error->get_error_message();
112 + } else if ($error instanceof \Exception) {
113 + /**
114 + * @var \Exception $error
115 + */
116 + $state['message'] = $error->getMessage();
117 + }
118 + return $state;
119 + });
120 + return $this;
96 121 }
97 122
98 123 public function validate($session_id)
99 124 {
@@ -108,128 +133,19 @@
108 133 {
109 134 return $this->data;
110 135 }
111 136
112 - public function get_importer_id()
137 + public static function wait_for_lock($importer_id, $user, $callback)
113 138 {
114 - return $this->importer_id;
115 - }
116 -
117 - public function get_section()
118 - {
119 - if (!isset($this->data['section'])) {
120 - return false;
139 + $result = null;
140 + if (is_callable($callback)) {
141 + $result = call_user_func($callback);
121 142 }
122 143
123 - return $this->data['section'];
124 - }
125 -
126 - public function get_progress($section = null)
127 - {
128 - if (is_null($section)) {
129 - $section = $this->get_section();
130 - }
131 -
132 - return $this->data['progress'][$section];
133 - }
134 -
135 - /**
136 - * Update live state data using callback
137 - *
138 - * @param Closure[array]:array $state
139 - *
140 - * @return $this
141 - */
142 - public function update($callback)
143 - {
144 - $raw = self::wait_for_lock($this->importer_id, $this->user, function () use ($callback) {
145 - $state = self::get_state($this->importer_id);
146 -
147 - if (is_callable($callback)) {
148 - $state = call_user_func($callback, $state);
149 - }
150 -
151 - self::set_state($this->importer_id, $state);
152 - do_action('iwp/importer/status/save', $state);
153 - return $state;
154 - });
155 -
156 - $this->populate($raw);
157 -
158 - return $this;
159 - }
160 -
161 - /**
162 - * Log fatal error
163 - *
164 - * @param \Exception $error
165 - * @return $this
166 - */
167 - public function error($error)
168 - {
169 - return $this->update(function ($data) use ($error) {
170 -
171 - $data['status'] = 'error';
172 - $data['message'] = $error->getMessage();
173 - $data['duration'] = floatval($data['duration']) + Logger::timer();
174 -
175 - return $data;
176 - });
177 - }
178 -
179 - public static function wait_for_lock($id, $user, $callback)
180 - {
181 -
182 - $start = microtime(true);
183 -
184 - do {
185 - list($has_lock, $result) = self::try_get_lock($id, $user, $callback);
186 - } while (!$has_lock && (microtime(true) - $start < 30));
187 -
188 - if (!$has_lock) {
189 - throw new \Exception("Unable to get lock");
190 - }
191 -
192 144 return $result;
193 145 }
194 146
195 - public static function wait_for_lock_and_get_state($id, $user, $default = false)
196 - {
197 - return self::wait_for_lock($id, $user, function () use ($id, $default) {
198 - return self::get_state($id, $default);
199 - });
200 - }
201 -
202 147 /**
203 - * Get importer lock to update state
204 - *
205 - * @param mixed $user current id
206 - * @param mixed $callback Callback triggered when we have a lock.
207 - * @param int $wait_in_microseconds Time to wait in microseconds before retrying
208 - *
209 - * @return false|array
210 - */
211 - public static function try_get_lock($id, $user, $callback)
212 - {
213 - $has_lock = self::get_lock($id, $user);
214 - if ($has_lock) {
215 -
216 - $result = $has_lock;
217 -
218 - if (is_callable($callback)) {
219 - $result = call_user_func($callback);
220 - }
221 -
222 - self::reset_lock($id);
223 -
224 - return [true, $result];
225 - } else {
226 -
227 - return [false, null];
228 - }
229 - }
230 -
231 - /**
232 148 * Update importer state
233 149 *
234 150 * @param mixed $state State to overwrite
235 151 *
@@ -237,10 +153,10 @@
237 153 */
238 154 public static function set_state($id, $state)
239 155 {
240 156 $state['updated'] = time();
241 - self::update_option('iwp_importer_state_' . $id, maybe_serialize($state));
242 - Logger::info('set_state -current=' . $state['id']);
157 + do_action('iwp/' . static::$object_type . '/status/save', $state);
158 + self::update_option('iwp_' . static::$object_type . '_state_' . $id, maybe_serialize($state));
243 159 }
244 160
245 161 /**
246 162 * Get last importer state
@@ -248,9 +164,9 @@
248 164 * @return array Importer state
249 165 */
250 166 public static function get_state($id, $default = false)
251 167 {
252 - $state = self::get_option('iwp_importer_state_' . $id);
168 + $state = self::get_option('iwp_' . static::$object_type . '_state_' . $id);
253 169 if (!$state) {
254 170 $state = $default;
255 171 if ($state !== false) {
256 172 self::set_state($id, $state);
@@ -256,19 +172,12 @@
256 172 self::set_state($id, $state);
257 173 }
258 174 }
259 175
260 - if (isset($state['id'])) {
261 - Logger::info('get_state -current=' . $state['id']);
262 - } else {
263 - Logger::info('get_state -current=n/a');
264 - }
265 -
266 176 return $state;
267 177 }
268 178
269 -
270 - public static function get_lock($id, $user, $timeout_in_seconds = 10)
179 + public static function get_option($key, $default = false)
271 180 {
272 181 /**
273 182 * @var \WPDB $wpdb
274 183 */
@@ -273,127 +182,140 @@
273 182 * @var \WPDB $wpdb
274 183 */
275 184 global $wpdb;
276 185
277 - $lock_option_id = sprintf("iwp_importer_lock_%d", $id);
278 - $existing = self::get_option($lock_option_id, false);
186 + $query = $wpdb->prepare("SELECT option_id as id, option_value as `data` FROM {$wpdb->options} WHERE option_name=%s LIMIT 1", [$key]);
279 187
280 - if ($existing !== false) {
281 - if (is_multisite()) {
282 - $query = $wpdb->prepare(
283 - "UPDATE {$wpdb->sitemeta} SET meta_value=%s WHERE site_id=%d AND meta_key=%s AND meta_value=''",
284 - $user,
285 - $wpdb->siteid,
286 - $lock_option_id
287 - );
288 - } else {
289 - $query = $wpdb->prepare(
290 - "UPDATE {$wpdb->options} SET option_value=%s WHERE option_name=%s AND option_value=''",
291 - $user,
292 - $lock_option_id
293 - );
294 - }
295 - } else {
296 - return self::update_option($lock_option_id, '');
188 + $result = $wpdb->get_row($query, ARRAY_A);
189 + if (!$result) {
190 + return $default;
297 191 }
298 192
299 - $result = $wpdb->query($query);
193 + if (is_serialized($result['data'])) {
194 + return unserialize($result['data']);
195 + }
300 196
301 - if ($result) {
197 + return $result['data'];
198 + }
302 199
303 - self::touch_lock($id);
304 - } else {
200 + public static function update_option($key, $value = '')
201 + {
202 + /**
203 + * @var \WPDB $wpdb
204 + */
205 + global $wpdb;
305 206
306 - // Clear lock if timestamp is greater than timeout.
307 - $last_locked_time = (int)self::get_option('iwp_importer_lock_timestamp_' . $id, 0);
308 - if (current_time('timestamp') > $last_locked_time + $timeout_in_seconds) {
309 - self::reset_lock($id);
310 - }
207 + $result = $wpdb->update($wpdb->options, ['option_value' => $value], ['option_name' => $key], ['%s'], ['%s']);
208 + if (intval($result) < 1) {
209 + $result = $wpdb->insert($wpdb->options, ['option_value' => $value, 'option_name' => $key], ['%s', '%s']);
311 210 }
312 211
313 212 return $result;
314 213 }
315 214
316 - public static function reset_lock($id)
215 + public static function clear_options($id)
317 216 {
318 - self::update_option('iwp_importer_lock_' . $id);
319 - self::touch_lock($id);
320 - }
321 217
322 - public static function touch_lock($id)
323 - {
324 - self::update_option('iwp_importer_lock_timestamp_' . $id, current_time('timestamp'));
325 - }
218 + // clear existing
219 + delete_option('iwp_' . static::$object_type . '_config_' . $id);
220 + delete_option('iwp_' . static::$object_type . '_state_' . $id);
221 + delete_option('iwp_' . static::$object_type . '_lock_' . $id);
222 + delete_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id);
223 + delete_option('iwp_' . static::$object_type . '_flag_' . $id);
326 224
327 - public static function get_option($key, $default = false)
328 - {
329 225 /**
330 226 * @var \WPDB $wpdb
331 227 */
332 228 global $wpdb;
229 + $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'iwp\_" . static::$object_type . "\_state\_" . $id . "\_%'");
230 + }
333 231
334 - if (is_multisite()) {
335 - $query = $wpdb->prepare("SELECT meta_id as id, meta_value as data FROM {$wpdb->sitemeta} WHERE site_id=%s AND meta_key=%s LIMIT 1", [$wpdb->siteid, $key]);
336 - } else {
337 - $query = $wpdb->prepare("SELECT option_id as id, option_value as data FROM {$wpdb->options} WHERE option_name=%s LIMIT 1", [$key]);
232 + public function get_section()
233 + {
234 + if (!isset($this->data['section'])) {
235 + return false;
338 236 }
339 237
340 - $result = $wpdb->get_row($query, ARRAY_A);
341 - if (!$result) {
342 - return $default;
238 + return $this->data['section'];
239 + }
240 +
241 + public function get_progress($section = null)
242 + {
243 + if (is_null($section)) {
244 + $section = $this->get_section();
343 245 }
344 246
345 - if (is_serialized($result['data'])) {
346 - return unserialize($result['data']);
247 + return $this->data['progress'][$section];
248 + }
249 +
250 + function update_importer_stats($stats)
251 + {
252 + if (!isset($this->data['stats'])) {
253 + $this->data['stats'] = [
254 + 'inserts' => 0,
255 + 'updates' => 0,
256 + 'deletes' => 0,
257 + 'skips' => 0,
258 + 'errors' => 0,
259 + ];
347 260 }
348 261
349 - return $result['data'];
262 + $this->data['stats']['inserts'] += $stats['inserts'];
263 + $this->data['stats']['updates'] += $stats['updates'];
264 + $this->data['stats']['deletes'] += $stats['deletes'];
265 + $this->data['stats']['skips'] += $stats['skips'];
266 + $this->data['stats']['errors'] += $stats['errors'];
350 267 }
351 268
352 - public static function update_option($key, $value = '')
269 + function get_stats()
353 270 {
354 - /**
355 - * @var \WPDB $wpdb
356 - */
357 - global $wpdb;
271 + if (!isset($this->data['stats'])) {
272 + $this->data['stats'] = [
273 + 'inserts' => 0,
274 + 'updates' => 0,
275 + 'deletes' => 0,
276 + 'skips' => 0,
277 + 'errors' => 0,
278 + ];
279 + }
358 280
359 - $result = self::get_option($key);
281 + return $this->data['stats'];
282 + }
360 283
361 - if (is_multisite()) {
284 + function increment_current_row($section = null)
285 + {
286 + if (is_null($section)) {
287 + $section = $this->get_section();
288 + }
289 + $this->data['progress'][$section]['current_row']++;
290 + }
362 291
363 - if ($result !== false) {
364 - $result = $wpdb->update($wpdb->sitemeta, ['meta_value' => $value], ['meta_key' => $key, 'site_id' => $wpdb->siteid], ['%s'], ['%s', '%s']);
365 - } else {
366 - $result = $wpdb->insert($wpdb->sitemeta, ['meta_value' => $value, 'meta_key' => $key, 'site_id' => $wpdb->siteid], ['%s', '%s', '%s']);
367 - }
368 - } else {
369 - if ($result !== false) {
370 - $result = $wpdb->update($wpdb->options, ['option_value' => $value], ['option_name' => $key], ['%s'], ['%s']);
371 - } else {
372 - $result = $wpdb->insert($wpdb->options, ['option_value' => $value, 'option_name' => $key], ['%s', '%s']);
373 - }
374 - }
292 + static function get_flag($id)
293 + {
294 + return self::get_option('iwp_' . static::$object_type . '_flag_' . $id);
295 + }
375 296
376 - return $result;
297 + static function is_paused($flag)
298 + {
299 + return $flag == 'paused';
377 300 }
378 301
379 - public static function clear_options($id)
302 + static function is_cancelled($flag)
380 303 {
304 + return $flag == 'cancelled';
305 + }
381 306
382 - // clear existing
383 - delete_site_option('iwp_importer_config_' . $id);
384 - delete_site_option('iwp_importer_state_' . $id);
385 - delete_site_option('iwp_importer_lock_' . $id);
386 - delete_site_option('iwp_importer_lock_timestamp_' . $id);
307 + static function set_paused($id)
308 + {
309 + self::update_option('iwp_' . static::$object_type . '_flag_' . $id, 'paused');
310 + }
387 311
388 - /**
389 - * @var \WPDB $wpdb
390 - */
391 - global $wpdb;
312 + static function set_cancelled($id)
313 + {
314 + self::update_option('iwp_' . static::$object_type . '_flag_' . $id, 'cancelled');
315 + }
392 316
393 - if (is_multisite()) {
394 - $wpdb->query("DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE 'iwp\_importer\_state\_" . $id . "\_%'");
395 - } else {
396 - $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'iwp\_importer\_state\_" . $id . "\_%'");
397 - }
317 + static function clear_flag($id)
318 + {
319 + self::update_option('iwp_' . static::$object_type . '_flag_' . $id, '');
398 320 }
399 321 }