PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.2
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.2
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
easy-invoice / includes / Migration / MigrationRunner.php

MigrationRunner.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.2, at includes/Migration/MigrationRunner.php

399 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Migration Runner for Easy Invoice
4 *
5 * @package EasyInvoice
6 * @subpackage Migration
7 * @since 2.0.0
8 */
9
10 namespace EasyInvoice\Migration;
11
12 use EasyInvoice\Migration\Src\SettingsMigration;
13 use EasyInvoice\Migration\Src\ClientMigration;
14 use EasyInvoice\Migration\Src\PostTypeMigration;
15 use EasyInvoice\Migration\Src\MetaMigration;
16 use EasyInvoice\Migration\Src\ProOptionsMigration;
17 use EasyInvoice\Migration\Src\DataCleanupMigration;
18
19 /**
20 * Migration Runner Class
21 *
22 * Orchestrates the migration process.
23 *
24 * @since 2.0.0
25 */
26 class MigrationRunner {
27
28 /**
29 * Version checker instance.
30 *
31 * @since 2.0.0
32 * @var VersionChecker
33 */
34 private $version_checker;
35
36 /**
37 * Migration steps.
38 *
39 * @since 2.0.0
40 * @var array
41 */
42 private $migration_steps = [
43 'settings' => [
44 'class' => SettingsMigration::class,
45 'dependencies' => []
46 ],
47 'clients' => [
48 'class' => ClientMigration::class,
49 'dependencies' => ['settings']
50 ],
51 'post_types' => [
52 'class' => PostTypeMigration::class,
53 'dependencies' => ['clients']
54 ],
55 'meta' => [
56 'class' => MetaMigration::class,
57 'dependencies' => ['clients', 'post_types']
58 ],
59 'pro_options' => [
60 'class' => ProOptionsMigration::class,
61 'dependencies' => ['settings']
62 ],
63 'cleanup' => [
64 'class' => DataCleanupMigration::class,
65 'dependencies' => ['post_types', 'meta']
66 ]
67 ];
68
69 /**
70 * Constructor.
71 *
72 * @since 2.0.0
73 * @param VersionChecker $version_checker Version checker instance
74 */
75 public function __construct(VersionChecker $version_checker) {
76 $this->version_checker = $version_checker;
77 }
78
79 /**
80 * Check if migration is needed.
81 *
82 * @since 2.0.0
83 * @return bool
84 */
85 public function should_run_migration(): bool {
86 // Get current version
87 $current_version = $this->version_checker->get_stored_version();
88
89 // Get target version
90 $target_version = $this->version_checker->get_target_version();
91
92 // Compare versions
93 if (version_compare($current_version, $target_version, '<')) {
94 $this->log_migration_check(true, $current_version, $target_version);
95 return true;
96 }
97
98 $this->log_migration_check(false, $current_version, $target_version);
99 return false;
100 }
101
102 /**
103 * Run the migration.
104 *
105 * @since 2.0.0
106 * @return array
107 */
108 public function run_migration(): array {
109 try {
110 // Set migration running flag
111 $this->set_migration_running(true);
112
113 // Initialize results
114 $results = [];
115 $errors = [];
116
117 // Get migration order based on dependencies
118 $migration_order = $this->get_migration_order();
119
120 // Run each migration step in order
121 foreach ($migration_order as $step) {
122 $result = $this->run_migration_step($step);
123 $results[$step] = $result;
124
125 // Check for errors
126 if (!$result['success']) {
127 $errors[] = sprintf('%s migration failed: %s', $step, $result['message']);
128 break; // Stop on first error
129 }
130
131 // Store step completion
132 update_option('easy_invoice_migration_step_' . $step . '_completed', true);
133 }
134
135 // Update version after successful migration
136 if (empty($errors)) {
137 $this->update_version();
138 $this->set_migration_completed(true);
139 $this->log_migration_success($results);
140 } else {
141 $this->log_migration_error($errors);
142 }
143
144 // Clear migration running flag
145 $this->set_migration_running(false);
146
147 return [
148 'success' => empty($errors),
149 'results' => $results,
150 'errors' => $errors
151 ];
152
153 } catch (\Exception $e) {
154 // Log error and clear flags
155 $this->log_migration_error([$e->getMessage()]);
156 $this->set_migration_running(false);
157
158 return [
159 'success' => false,
160 'message' => $e->getMessage(),
161 'errors' => [$e->getMessage()]
162 ];
163 }
164 }
165
166 /**
167 * Get migration order based on dependencies.
168 *
169 * @since 2.0.0
170 * @return array
171 */
172 private function get_migration_order(): array {
173 $order = [];
174 $visited = [];
175
176 foreach (array_keys($this->migration_steps) as $step) {
177 if (!isset($visited[$step])) {
178 $this->visit_step($step, $visited, $order);
179 }
180 }
181
182 return $order;
183 }
184
185 /**
186 * Visit migration step for topological sort.
187 *
188 * @since 2.0.0
189 * @param string $step Step name
190 * @param array $visited Visited steps
191 * @param array $order Migration order
192 * @return void
193 */
194 private function visit_step(string $step, array &$visited, array &$order): void {
195 $visited[$step] = true;
196
197 foreach ($this->migration_steps[$step]['dependencies'] as $dependency) {
198 if (!isset($visited[$dependency])) {
199 $this->visit_step($dependency, $visited, $order);
200 }
201 }
202
203 $order[] = $step;
204 }
205
206 /**
207 * Check if a migration step is completed.
208 *
209 * @since 2.0.0
210 * @param string $step Migration step
211 * @return bool
212 */
213 private function is_step_completed(string $step): bool {
214 return get_option('easy_invoice_migration_step_' . $step . '_completed', false);
215 }
216
217 /**
218 * Run a specific migration step.
219 *
220 * @since 2.0.0
221 * @param string $step Migration step
222 * @return array
223 */
224 public function run_migration_step(string $step): array {
225 if (!isset($this->migration_steps[$step])) {
226 return [
227 'success' => false,
228 'message' => sprintf('Invalid migration step: %s', $step)
229 ];
230 }
231
232 try {
233 // Check dependencies
234 foreach ($this->migration_steps[$step]['dependencies'] as $dependency) {
235 if (!$this->is_step_completed($dependency)) {
236 return [
237 'success' => false,
238 'message' => sprintf('Dependency %s must be migrated first', $dependency)
239 ];
240 }
241 }
242
243 $class = $this->migration_steps[$step]['class'];
244 $migration = new $class();
245
246 if (!$migration->is_needed()) {
247 // Mark step as completed even if not needed
248 update_option('easy_invoice_migration_step_' . $step . '_completed', true);
249
250 return [
251 'success' => true,
252 'message' => sprintf('%s migration not needed', $step)
253 ];
254 }
255
256 $result = $migration->migrate();
257
258 if ($result['success']) {
259 // Mark step as completed on success
260 update_option('easy_invoice_migration_step_' . $step . '_completed', true);
261 }
262
263 return $result;
264
265 } catch (\Exception $e) {
266 return [
267 'success' => false,
268 'message' => $e->getMessage()
269 ];
270 }
271 }
272
273 /**
274 * Set migration running flag.
275 *
276 * @since 2.0.0
277 * @param bool $running Running state
278 * @return void
279 */
280 private function set_migration_running(bool $running): void {
281 update_option('easy_invoice_migration_running', $running);
282 }
283
284 /**
285 * Set migration completed flag.
286 *
287 * @since 2.0.0
288 * @param bool $completed Completed state
289 * @return void
290 */
291 private function set_migration_completed(bool $completed): void {
292 update_option('easy_invoice_migration_completed', $completed);
293 if ($completed) {
294 update_option('easy_invoice_migration_completed_time', current_time('mysql'));
295 }
296 }
297
298 /**
299 * Update version after successful migration.
300 *
301 * @since 2.0.0
302 * @return void
303 */
304 private function update_version(): void {
305 $target_version = $this->version_checker->get_target_version();
306 update_option('easy_invoice_version', $target_version);
307 }
308
309 /**
310 * Log migration check.
311 *
312 * @since 2.0.0
313 * @param bool $needed Whether migration is needed
314 * @param string $current_version Current version
315 * @param string $target_version Target version
316 * @return void
317 */
318 private function log_migration_check(bool $needed, string $current_version, string $target_version): void {
319 $message = $needed
320 ? sprintf('Migration needed: Current version %s is less than target version %s', $current_version, $target_version)
321 : sprintf('Migration not needed: Current version %s is greater than or equal to target version %s', $current_version, $target_version);
322
323 $this->log($message);
324 }
325
326 /**
327 * Log migration success.
328 *
329 * @since 2.0.0
330 * @param array $results Migration results
331 * @return void
332 */
333 private function log_migration_success(array $results): void {
334 $message = 'Migration completed successfully:' . PHP_EOL;
335
336 foreach ($results as $step => $result) {
337 $message .= sprintf('- %s: %s' . PHP_EOL, $step, $result['message']);
338 }
339
340 $message .= PHP_EOL . 'System Information:' . PHP_EOL;
341 $message .= sprintf('- WordPress Version: %s' . PHP_EOL, get_bloginfo('version'));
342 $message .= sprintf('- PHP Version: %s' . PHP_EOL, PHP_VERSION);
343 $message .= sprintf('- MySQL Version: %s' . PHP_EOL, $this->get_mysql_version());
344 $message .= sprintf('- Memory Limit: %s' . PHP_EOL, WP_MEMORY_LIMIT);
345 $message .= sprintf('- Max Execution Time: %s' . PHP_EOL, ini_get('max_execution_time'));
346
347 $this->log($message);
348 }
349
350 /**
351 * Log migration error.
352 *
353 * @since 2.0.0
354 * @param array $errors Error messages
355 * @return void
356 */
357 private function log_migration_error(array $errors): void {
358 $message = 'Migration failed:' . PHP_EOL;
359
360 foreach ($errors as $error) {
361 $message .= '- ' . $error . PHP_EOL;
362 }
363
364 $this->log($message, 'error');
365 }
366
367 /**
368 * Get MySQL version.
369 *
370 * @since 2.0.0
371 * @return string
372 */
373 private function get_mysql_version(): string {
374 global $wpdb;
375 return $wpdb->get_var('SELECT VERSION()');
376 }
377
378 /**
379 * Log a message.
380 *
381 * @since 2.0.0
382 * @param string $message Message to log
383 * @param string $level Log level
384 * @return void
385 */
386 private function log(string $message, string $level = 'info'): void {
387 $log = [
388 'message' => $message,
389 'level' => $level,
390 'timestamp' => current_time('mysql')
391 ];
392
393 $logs = get_option('easy_invoice_migration_logs', []);
394 $logs[] = $log;
395
396 update_option('easy_invoice_migration_logs', $logs);
397 }
398 }
399