PluginProbe
YayMail – WooCommerce Email Customizer / 4.3.2
YayMail – WooCommerce Email Customizer v4.3.2
4.4.4 4.4.3 4.4.2 4.4.1 trunk 1.9.6 2.1.4 2.1.5 3.2.2 3.2.6 3.2.7.1 3.2.8.1 3.2.9 3.3 3.3.1 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4 3.4.1 3.4.2 3.4.3 All 55 releases
yaymail / src / Models / MigrationModel.php

MigrationModel.php in YayMail – WooCommerce Email Customizer 4.3.2, at src/Models/MigrationModel.php

277 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace YayMail\Models;
3
4 use YayMail\Migrations\AbstractMigration;
5 use YayMail\Utils\SingletonTrait;
6 use YayMail\Utils\Logger;
7 use YayMail\Migrations\MainMigration;
8 use YayMail\Migrations\MigrationHelper;
9
10 /**
11 * Migration Model
12 *
13 * @method static MigrationModel get_instance()
14 */
15 class MigrationModel {
16 use SingletonTrait;
17
18 /** @var Logger */
19 private $logger;
20
21 private function __construct() {
22 $this->logger = new Logger();
23 }
24
25 public function get_onload_data() {
26 return [
27 'required_migrations' => $this->get_required_migration_names(),
28 'backups' => $this->get_backups(),
29 ];
30 }
31
32 public function migrate() {
33 $is_migration_succeeded = MainMigration::get_instance()->migrate();
34 if ( ! $is_migration_succeeded ) {
35 throw new \Exception( esc_html__( 'Migration failed, please contact our Customer Support for help!', 'yaymail' ), 500 );
36 }
37 return [ 'is_critical_migration_required' => $this->check_if_critical_migration_required() ];
38 }
39
40 /**
41 * Restore backup to a specific version
42 *
43 * @param array $backup Backup data containing posts, postmeta, options, metadata, and version.
44 *
45 * @return array Returns array with 'is_critical_migration_required' boolean flag.
46 * @throws \Exception When backup doesn't exist or restoration fails.
47 */
48 public function reset( $backup ) {
49 global $wpdb;
50
51 if ( ! $backup || ! $backup['version'] || ! $backup['name'] ) {
52 throw new \Exception( 'Back up does not exist', 500 );
53 }
54
55 try {
56 $backup_name = $backup['name'];
57 $version = $backup['version'];
58
59 $wpdb->query( 'START TRANSACTION' );
60 $this->logger->log( '***** Start reset transaction ****' );
61 $this->logger->log( "Backup name: $backup_name" );
62
63 // Get IDs of posts to be deleted
64 $post_ids_to_delete = $wpdb->get_col(
65 $wpdb->prepare(
66 "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s",
67 'yaymail_template'
68 )
69 );
70 if ( $post_ids_to_delete ) {
71 // Delete current post meta data
72 $delete_postmeta_query = sprintf(
73 "DELETE FROM {$wpdb->postmeta} WHERE post_id IN (%s)",
74 implode( ',', array_map( 'intval', $post_ids_to_delete ) )
75 );
76 $this->logger->log( $delete_postmeta_query );
77 $wpdb->query( $delete_postmeta_query );// phpcs:ignore
78
79 // Delete the posts
80 $delete_template_posts_query = sprintf(
81 "DELETE FROM {$wpdb->posts} WHERE ID IN (%s)",
82 implode( ',', array_map( 'intval', $post_ids_to_delete ) )
83 );
84 $this->logger->log( $delete_template_posts_query );
85 $wpdb->query( $delete_template_posts_query );// phpcs:ignore
86 }
87
88 $delete_template_posts_query = $wpdb->prepare(
89 "DELETE FROM {$wpdb->posts} WHERE post_type = %s",
90 'yaymail_template'
91 );
92 $this->logger->log( $delete_template_posts_query );
93 $wpdb->query( $delete_template_posts_query );// phpcs:ignore
94
95 // Restore the backed-up posts
96 $backed_up_posts = $backup['posts'];
97 $backed_up_postmeta = $backup['postmeta'];
98 foreach ( $backed_up_posts as $post ) {
99 $wpdb->insert(
100 $wpdb->posts,
101 [
102 'post_author' => $post->post_author,
103 'post_date' => $post->post_date,
104 'post_date_gmt' => $post->post_date_gmt,
105 'post_content' => $post->post_content,
106 'post_title' => $post->post_title,
107 'post_excerpt' => $post->post_excerpt,
108 'post_status' => $post->post_status,
109 'comment_status' => $post->comment_status,
110 'ping_status' => $post->ping_status,
111 'post_password' => $post->post_password,
112 'post_name' => $post->post_name,
113 'to_ping' => $post->to_ping,
114 'pinged' => $post->pinged,
115 'post_modified' => $post->post_modified,
116 'post_modified_gmt' => $post->post_modified_gmt,
117 'post_content_filtered' => $post->post_content_filtered,
118 'post_parent' => $post->post_parent,
119 'guid' => $post->guid,
120 'menu_order' => $post->menu_order,
121 'post_type' => $post->post_type,
122 'post_mime_type' => $post->post_mime_type,
123 'comment_count' => $post->comment_count,
124 ]
125 );
126
127 // Insert post meta data
128 $inserted_post_id = $wpdb->insert_id;
129 $postmetas_for_current_post = array_filter(
130 $backed_up_postmeta,
131 function( $postmeta ) use ( $post ) {
132 return $postmeta->post_id === $post->ID;
133 }
134 );
135 if ( ! empty( $postmetas_for_current_post ) ) {
136 foreach ( $postmetas_for_current_post as $postmeta ) {
137 add_post_meta( $inserted_post_id, $postmeta->meta_key, maybe_unserialize( $postmeta->meta_value ) );
138 }
139 }
140 }//end foreach
141
142 // Restore backed-up options
143 foreach ( $backup['options'] as $option ) {
144 update_option( $option->option_name, maybe_unserialize( $option->option_value ) );
145 }
146
147 // Remove the succeeded migration log from db
148 $successful_migrations = get_option( AbstractMigration::SUCCESSFUL_MIGRATIONS, null );
149 $removed_migrations = [];
150 if ( ! empty( $successful_migrations ) ) {
151 $filtered_successful_migrations = array_filter(
152 $successful_migrations,
153 function( $migration ) use ( $version, $backup ) {
154 $backup_date = new \DateTime( $backup['created_date'], wp_timezone() );
155 $migration_date = new \DateTime( $migration['created_date'], wp_timezone() );
156 $should_remove = $migration_date >= $backup_date;
157
158 return ! $should_remove;
159 }
160 );
161
162 update_option( AbstractMigration::SUCCESSFUL_MIGRATIONS, $filtered_successful_migrations );
163 $removed_migrations = array_udiff(
164 $successful_migrations,
165 $filtered_successful_migrations,
166 function( $a, $b ) {
167 return strcmp( serialize( $a ), serialize( $b ) );
168 }
169 );
170 }//end if
171
172 // Restore core version
173 update_option( 'yaymail_version', $version );
174 wp_cache_delete( 'yaymail_version', 'options' );
175
176 // Restore addon versions
177 $addon_versions = get_option( 'yaymail_addon_versions', [] );
178 $restored_addon_versions = array_filter(
179 $addon_versions,
180 function( $addon_version, $addon_namespace ) use ( $removed_migrations ) {
181 foreach ( $removed_migrations as $migration ) {
182 if ( ! empty( $migration['addon_namespace'] ) && $migration['addon_namespace'] === $addon_namespace && version_compare( $addon_version, $migration['to_version'], '<=' ) ) {
183 return false;
184 }
185 }
186 return true;
187 },
188 ARRAY_FILTER_USE_BOTH
189 );
190 update_option( 'yaymail_addon_versions', $restored_addon_versions );
191
192 do_action( 'yaymail_before_reset_migration_commit', $backup, $removed_migrations );
193
194 $wpdb->query( 'COMMIT' );
195 $this->logger->log( '***** Finish reset transaction ****' );
196 $this->logger->log( "$backup_name restored successfully!" );
197
198 return [ 'is_critical_migration_required' => $this->check_if_critical_migration_required() ];
199
200 } catch ( \Exception $e ) {
201 $wpdb->query( 'ROLLBACK' );
202 $this->logger->log( '***** Transaction rolled back. ' . $e->getMessage() );
203 throw new \Exception( esc_html__( 'Restoration failed', 'yaymail' ), 500 );
204 }//end try
205 }
206
207 public function check_if_critical_migration_required() {
208 $old_version = get_option( 'yaymail_version' );
209 if ( $old_version ) {
210 return version_compare( $old_version, '4.0.0', '<' );
211 }
212 return false;
213 }
214
215 private function get_required_migration_names() {
216 $old_version = MigrationHelper::format_version_number( get_option( 'yaymail_version' ) );
217 $new_version = MigrationHelper::format_version_number( YAYMAIL_VERSION );
218 $successful_migrations = get_option( AbstractMigration::SUCCESSFUL_MIGRATIONS, [] );
219
220 // If freshly installed or already on latest version with no migrations needed
221 if ( ( version_compare( $old_version, $new_version, '>=' ) && empty( $successful_migrations ) ) ) {
222 return apply_filters( 'yaymail_required_migration_names', [] );
223 }
224
225 $args = [
226 'post_type' => 'yaymail_template',
227 'post_status' => 'any',
228 'posts_per_page' => -1,
229 ];
230
231 $query = new \WP_Query( $args );
232
233 $has_yaymail_template = $query->have_posts();
234 if ( ( $old_version == null && ! $has_yaymail_template ) && empty( $successful_migrations ) ) {
235 return [];
236 }
237
238 // Check if any migrations have already been run up to current version
239 foreach ( $successful_migrations as $migration ) {
240 if ( empty( $migration['addon_namespace'] ) && version_compare( $migration['to_version'], YAYMAIL_VERSION, '>=' ) ) {
241 return apply_filters( 'yaymail_required_migration_names', [] );
242 }
243 }
244
245 // Get available migrations that need to be run
246 $core_migrations = MainMigration::CORE_MIGRATIONS;
247 $filtered_migrations = MigrationHelper::filter_migrations( $core_migrations, $old_version, $new_version );
248
249 $needed_migrations = empty( $filtered_migrations ) ? [] : [ 'YayMail' ];
250
251 return apply_filters( 'yaymail_required_migration_names', $needed_migrations );
252 }
253
254 private function get_backups() {
255 global $wpdb;
256
257 $backup_prefix = AbstractMigration::BACKUP_PREFIX;
258
259 $backup_options_query = $wpdb->prepare(
260 "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE %s",
261 $backup_prefix . '%'
262 );
263 $backups_result = $wpdb->get_results( $backup_options_query );// phpcs:ignore
264
265 $backups = [];
266 foreach ( $backups_result as $backup ) {
267 $data = maybe_unserialize( $backup->option_value );
268 $backups[] = [
269 'created_date' => $data['created_date'] ?? 'created_date not found',
270 'name' => $backup->option_name ?? 'backup name not found',
271 ];
272 }
273
274 return $backups;
275 }
276 }
277