Completed
Branch BUG/dont-reuse-DMS-scripts-dur... (c013e6)
by
unknown
04:44 queued 02:40
created
core/EE_Data_Migration_Manager.core.php 2 patches
Indentation   +1239 added lines, -1239 removed lines patch added patch discarded remove patch
@@ -33,1243 +33,1243 @@
 block discarded – undo
33 33
 class EE_Data_Migration_Manager implements ResettableInterface
34 34
 {
35 35
 
36
-    /**
37
-     *
38
-     * @var EE_Registry
39
-     */
40
-    // protected $EE;
41
-    /**
42
-     * name of the wordpress option which stores an array of data about
43
-     */
44
-    const data_migrations_option_name = 'ee_data_migration';
45
-
46
-
47
-    const data_migration_script_option_prefix = 'ee_data_migration_script_';
48
-
49
-    const data_migration_script_mapping_option_prefix = 'ee_dms_map_';
50
-
51
-    /**
52
-     * name of the wordpress option which stores the database' current version. IE, the code may be at version 4.2.0,
53
-     * but as migrations are performed the database will progress from 3.1.35 to 4.1.0 etc.
54
-     */
55
-    const current_database_state = 'ee_data_migration_current_db_state';
56
-
57
-    /**
58
-     * Special status string returned when we're positive there are no more data migration
59
-     * scripts that can be run.
60
-     */
61
-    const status_no_more_migration_scripts = 'no_more_migration_scripts';
62
-    /**
63
-     * string indicating the migration should continue
64
-     */
65
-    const status_continue = 'status_continue';
66
-    /**
67
-     * string indicating the migration has completed and should be ended
68
-     */
69
-    const status_completed = 'status_completed';
70
-    /**
71
-     * string indicating a fatal error occurred and the data migration should be completely aborted
72
-     */
73
-    const status_fatal_error = 'status_fatal_error';
74
-
75
-    /**
76
-     * the number of 'items' (usually DB rows) to migrate on each 'step' (ajax request sent
77
-     * during migration)
78
-     */
79
-    const step_size = 50;
80
-
81
-    /**
82
-     * option name that stores the queue of ee plugins needing to have
83
-     * their data initialized (or re-initialized) once we are done migrations
84
-     */
85
-    const db_init_queue_option_name = 'ee_db_init_queue';
86
-    /**
87
-     * Array of information concerning data migrations that have ran in the history
88
-     * of this EE installation. Keys should be the name of the version the script upgraded to
89
-     *
90
-     * @var EE_Data_Migration_Script_Base[]
91
-     */
92
-    private $_data_migrations_ran = null;
93
-    /**
94
-     * The last ran script. It's nice to store this somewhere accessible, as its easiest
95
-     * to know which was the last run by which is the newest wp option; but in most of the code
96
-     * we just use the local $_data_migration_ran array, which organized the scripts differently
97
-     *
98
-     * @var EE_Data_Migration_Script_Base
99
-     */
100
-    private $_last_ran_script = null;
101
-
102
-    /**
103
-     * Similarly to _last_ran_script, but this is the last INCOMPLETE migration script.
104
-     *
105
-     * @var EE_Data_Migration_Script_Base
106
-     */
107
-    private $_last_ran_incomplete_script = null;
108
-    /**
109
-     * array where keys are classnames, and values are filepaths of all the known migration scripts
110
-     *
111
-     * @var array
112
-     */
113
-    private $_data_migration_class_to_filepath_map;
114
-
115
-    /**
116
-     * the following 4 properties are fully set on construction.
117
-     * Note: the first two apply to whether to continue running ALL migration scripts (ie, even though we're finished
118
-     * one, we may want to start the next one); whereas the last two indicate whether to continue running a single
119
-     * data migration script
120
-     *
121
-     * @var array
122
-     */
123
-    public $stati_that_indicate_to_continue_migrations = array();
124
-
125
-    public $stati_that_indicate_to_stop_migrations = array();
126
-
127
-    public $stati_that_indicate_to_continue_single_migration_script = array();
128
-
129
-    public $stati_that_indicate_to_stop_single_migration_script = array();
130
-
131
-    /**
132
-     * @var \EventEspresso\core\services\database\TableManager $table_manager
133
-     */
134
-    protected $_table_manager;
135
-
136
-    /**
137
-     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
138
-     */
139
-    protected $_table_analysis;
140
-
141
-    /**
142
-     * @var array $script_migration_versions
143
-     */
144
-    protected $script_migration_versions;
145
-
146
-    /**
147
-     * @var EE_Data_Migration_Manager $_instance
148
-     * @access    private
149
-     */
150
-    private static $_instance = null;
151
-
152
-
153
-    /**
154
-     * @singleton method used to instantiate class object
155
-     * @access    public
156
-     * @return EE_Data_Migration_Manager instance
157
-     */
158
-    public static function instance()
159
-    {
160
-        // check if class object is instantiated
161
-        if (! self::$_instance instanceof EE_Data_Migration_Manager) {
162
-            self::$_instance = new self();
163
-        }
164
-        return self::$_instance;
165
-    }
166
-
167
-    /**
168
-     * resets the singleton to its brand-new state (but does NOT delete old references to the old singleton. Meaning,
169
-     * all new usages of the singleton should be made with Classname::instance()) and returns it
170
-     *
171
-     * @return EE_Data_Migration_Manager
172
-     */
173
-    public static function reset()
174
-    {
175
-        self::$_instance = null;
176
-        return self::instance();
177
-    }
178
-
179
-
180
-    /**
181
-     * constructor
182
-     */
183
-    private function __construct()
184
-    {
185
-        $this->stati_that_indicate_to_continue_migrations = array(
186
-            self::status_continue,
187
-            self::status_completed,
188
-        );
189
-        $this->stati_that_indicate_to_stop_migrations = array(
190
-            self::status_fatal_error,
191
-            self::status_no_more_migration_scripts,
192
-        );
193
-        $this->stati_that_indicate_to_continue_single_migration_script = array(
194
-            self::status_continue,
195
-        );
196
-        $this->stati_that_indicate_to_stop_single_migration_script = array(
197
-            self::status_completed,
198
-            self::status_fatal_error
199
-            // note: status_no_more_migration_scripts doesn't apply
200
-        );
201
-        // make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
202
-        // to be defined, because right now it doesn't get autoloaded on its own
203
-        EE_Registry::instance()->load_core('Data_Migration_Class_Base', array(), true);
204
-        EE_Registry::instance()->load_core('Data_Migration_Script_Base', array(), true);
205
-        EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', array(), true);
206
-        EE_Registry::instance()->load_core('Data_Migration_Script_Stage', array(), true);
207
-        EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', array(), true);
208
-        $this->_table_manager = EE_Registry::instance()->create('TableManager', array(), true);
209
-        $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
210
-    }
211
-
212
-
213
-    /**
214
-     * Deciphers, from an option's name, what plugin and version it relates to (see _save_migrations_ran to see what
215
-     * the option names are like, but generally they're like
216
-     * 'ee_data_migration_script_Core.4.1.0' in 4.2 or 'ee_data_migration_script_4.1.0' before that).
217
-     * The option name shouldn't ever be like 'ee_data_migration_script_Core.4.1.0.reg' because it's derived,
218
-     * indirectly, from the data migration's classname, which should always be like EE_DMS_%s_%d_%d_%d.dms.php (eg
219
-     * EE_DMS_Core_4_1_0.dms.php)
220
-     *
221
-     * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
222
-     * @return array where the first item is the plugin slug (eg 'Core','Calendar',etc) and the 2nd is the version of
223
-     *               that plugin (eg '4.1.0')
224
-     */
225
-    private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name)
226
-    {
227
-        $plugin_slug_and_version_string = str_replace(
228
-            EE_Data_Migration_Manager::data_migration_script_option_prefix,
229
-            "",
230
-            $option_name
231
-        );
232
-        // check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
233
-        $parts = explode(".", $plugin_slug_and_version_string);
234
-
235
-        if (count($parts) == 4) {
236
-            // it's 4.2-style.eg Core.4.1.0
237
-            $plugin_slug = $parts[0];// eg Core
238
-            $version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
239
-        } else {
240
-            // it's 4.1-style: eg 4.1.0
241
-            $plugin_slug = 'Core';
242
-            $version_string = $plugin_slug_and_version_string;// eg 4.1.0
243
-        }
244
-        return array($plugin_slug, $version_string);
245
-    }
246
-
247
-    /**
248
-     * Gets the DMS class from the wordpress option, otherwise throws an EE_Error if it's not
249
-     * for a known DMS class.
250
-     *
251
-     * @param string $dms_option_name
252
-     * @param string $dms_option_value (serialized)
253
-     * @return EE_Data_Migration_Script_Base
254
-     * @throws EE_Error
255
-     */
256
-    private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value)
257
-    {
258
-        $data_migration_data = maybe_unserialize($dms_option_value);
259
-        if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
260
-            // During multisite migrations, it's possible we already grabbed another instance of this class
261
-            // but for a different blog. Make sure we don't reuse them (as they store info specific
262
-            // to their respective blog, like which database table to migrate).
263
-            $class = LoaderFactory::getLoader()->getShared($data_migration_data['class'], [], false);
264
-            if ($class instanceof EE_Data_Migration_Script_Base) {
265
-                $class->instantiate_from_array_of_properties($data_migration_data);
266
-                return $class;
267
-            } else {
268
-                // huh, so its an object but not a data migration script?? that shouldn't happen
269
-                // just leave it as an array (which will probably just get ignored)
270
-                throw new EE_Error(
271
-                    sprintf(
272
-                        __(
273
-                            "Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists",
274
-                            'event_espresso'
275
-                        ),
276
-                        $data_migration_data['class']
277
-                    )
278
-                );
279
-            }
280
-        } else {
281
-            // so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
282
-            throw new EE_Error(
283
-                sprintf(__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'), $dms_option_name)
284
-            );
285
-        }
286
-    }
287
-
288
-    /**
289
-     * Gets the array describing what data migrations have run. Also has a side-effect of recording which was the last
290
-     * ran, and which was the last ran which hasn't finished yet
291
-     *
292
-     * @return array where each element should be an array of EE_Data_Migration_Script_Base (but also has a few legacy
293
-     *               arrays in there - which should probably be ignored)
294
-     */
295
-    public function get_data_migrations_ran()
296
-    {
297
-        if (! $this->_data_migrations_ran) {
298
-            // setup autoloaders for each of the scripts in there
299
-            $this->get_all_data_migration_scripts_available();
300
-            $data_migrations_options = $this->get_all_migration_script_options(
301
-            );// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
302
-
303
-            $data_migrations_ran = array();
304
-            // convert into data migration script classes where possible
305
-            foreach ($data_migrations_options as $data_migration_option) {
306
-                list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name(
307
-                    $data_migration_option['option_name']
308
-                );
309
-
310
-                try {
311
-                    $class = $this->_get_dms_class_from_wp_option(
312
-                        $data_migration_option['option_name'],
313
-                        $data_migration_option['option_value']
314
-                    );
315
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
316
-                    // ok so far THIS is the 'last-ran-script'... unless we find another on next iteration
317
-                    $this->_last_ran_script = $class;
318
-                    if (! $class->is_completed()) {
319
-                        // sometimes we also like to know which was the last incomplete script (or if there are any at all)
320
-                        $this->_last_ran_incomplete_script = $class;
321
-                    }
322
-                } catch (EE_Error $e) {
323
-                    // ok so its not a DMS. We'll just keep it, although other code will need to expect non-DMSs
324
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
325
-                        $data_migration_option['option_value']
326
-                    );
327
-                }
328
-            }
329
-            // so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
330
-            $this->_data_migrations_ran = $data_migrations_ran;
331
-            if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
332
-                $this->_data_migrations_ran = array();
333
-            }
334
-        }
335
-        return $this->_data_migrations_ran;
336
-    }
337
-
338
-
339
-    /**
340
-     *
341
-     * @param string $script_name eg 'DMS_Core_4_1_0'
342
-     * @param string $old_table   eg 'wp_events_detail'
343
-     * @param string $old_pk      eg 'wp_esp_posts'
344
-     * @param        $new_table
345
-     * @return mixed string or int
346
-     */
347
-    public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
348
-    {
349
-        $script = EE_Registry::instance()->load_dms($script_name);
350
-        $mapping = $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
351
-        return $mapping;
352
-    }
353
-
354
-    /**
355
-     * Gets all the options containing migration scripts that have been run. Ordering is important: it's assumed that
356
-     * the last option returned in this array is the most-recently ran DMS option
357
-     *
358
-     * @return array
359
-     */
360
-    public function get_all_migration_script_options()
361
-    {
362
-        global $wpdb;
363
-        return $wpdb->get_results(
364
-            "SELECT * FROM {$wpdb->options} WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id ASC",
365
-            ARRAY_A
366
-        );
367
-    }
368
-
369
-    /**
370
-     * Gets the array of folders which contain data migration scripts. Also adds them to be auto-loaded
371
-     *
372
-     * @return array where each value is the full folder path of a folder containing data migration scripts, WITH
373
-     *               slashes at the end of the folder name.
374
-     */
375
-    public function get_data_migration_script_folders()
376
-    {
377
-        return apply_filters(
378
-            'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
379
-            array('Core' => EE_CORE . 'data_migration_scripts')
380
-        );
381
-    }
382
-
383
-    /**
384
-     * Gets the version the migration script upgrades to
385
-     *
386
-     * @param string $migration_script_name eg 'EE_DMS_Core_4_1_0'
387
-     * @return array {
388
-     * @type string  $slug                  like 'Core','Calendar',etc
389
-     * @type string  $version               like 4.3.0
390
-     *                                      }
391
-     * @throws EE_Error
392
-     */
393
-    public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
394
-    {
395
-        if (isset($this->script_migration_versions[ $migration_script_name ])) {
396
-            return $this->script_migration_versions[ $migration_script_name ];
397
-        }
398
-        $dms_info = $this->parse_dms_classname($migration_script_name);
399
-        $this->script_migration_versions[ $migration_script_name ] = array(
400
-            'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
401
-            'version' => $dms_info['major_version'] . "." . $dms_info['minor_version'] . "." . $dms_info['micro_version'],
402
-        );
403
-        return $this->script_migration_versions[ $migration_script_name ];
404
-    }
405
-
406
-    /**
407
-     * Gets the juicy details out of a dms filename like 'EE_DMS_Core_4_1_0'
408
-     *
409
-     * @param string $classname
410
-     * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are ints)
411
-     * @throws EE_Error
412
-     */
413
-    public function parse_dms_classname($classname)
414
-    {
415
-        $matches = array();
416
-        preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
417
-        if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
418
-            throw new EE_Error(
419
-                sprintf(
420
-                    __(
421
-                        "%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ",
422
-                        "event_espresso"
423
-                    ),
424
-                    $classname
425
-                )
426
-            );
427
-        }
428
-        return array(
429
-            'slug'          => $matches[1],
430
-            'major_version' => intval($matches[2]),
431
-            'minor_version' => intval($matches[3]),
432
-            'micro_version' => intval($matches[4]),
433
-        );
434
-    }
435
-
436
-    /**
437
-     * Ensures that the option indicating the current DB version is set. This should only be
438
-     * a concern when activating EE for the first time, THEORETICALLY.
439
-     * If we detect that we're activating EE4 over top of EE3.1, then we set the current db state to 3.1.x, otherwise
440
-     * to 4.1.x.
441
-     *
442
-     * @return string of current db state
443
-     */
444
-    public function ensure_current_database_state_is_set()
445
-    {
446
-        $espresso_db_core_updates = get_option('espresso_db_update', array());
447
-        $db_state = get_option(EE_Data_Migration_Manager::current_database_state);
448
-        if (! $db_state) {
449
-            // mark the DB as being in the state as the last version in there.
450
-            // this is done to trigger maintenance mode and do data migration scripts
451
-            // if the admin installed this version of EE over 3.1.x or 4.0.x
452
-            // otherwise, the normal maintenance mode code is fine
453
-            $previous_versions_installed = array_keys($espresso_db_core_updates);
454
-            $previous_version_installed = end($previous_versions_installed);
455
-            if (version_compare('4.1.0', $previous_version_installed)) {
456
-                // last installed version was less than 4.1
457
-                // so we want the data migrations to happen. SO, we're going to say the DB is at that state
458
-                $db_state = array('Core' => $previous_version_installed);
459
-            } else {
460
-                $db_state = array('Core' => EVENT_ESPRESSO_VERSION);
461
-            }
462
-            update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
463
-        }
464
-        // in 4.1, $db_state would have only been a simple string like '4.1.0',
465
-        // but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
466
-        // db, and possibly other keys for other addons like 'Calendar','Permissions',etc
467
-        if (! is_array($db_state)) {
468
-            $db_state = array('Core' => $db_state);
469
-            update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
470
-        }
471
-        return $db_state;
472
-    }
473
-
474
-    /**
475
-     * Checks if there are any data migration scripts that ought to be run. If found,
476
-     * returns the instantiated classes. If none are found (ie, they've all already been run
477
-     * or they don't apply), returns an empty array
478
-     *
479
-     * @return EE_Data_Migration_Script_Base[]
480
-     */
481
-    public function check_for_applicable_data_migration_scripts()
482
-    {
483
-        // get the option describing what options have already run
484
-        $scripts_ran = $this->get_data_migrations_ran();
485
-        // $scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
486
-        $script_class_and_filepaths_available = $this->get_all_data_migration_scripts_available();
487
-
488
-
489
-        $current_database_state = $this->ensure_current_database_state_is_set();
490
-        // determine which have already been run
491
-        $script_classes_that_should_run_per_iteration = array();
492
-        $iteration = 0;
493
-        $next_database_state_to_consider = $current_database_state;
494
-        $theoretical_database_state = null;
495
-        do {
496
-            // the next state after the currently-considered one will start off looking the same as the current, but we may make additions...
497
-            $theoretical_database_state = $next_database_state_to_consider;
498
-            // the next db state to consider is "what would the DB be like had we run all the scripts we found that applied last time?)
499
-            foreach ($script_class_and_filepaths_available as $classname => $filepath) {
500
-                $migrates_to_version = $this->script_migrates_to_version($classname);
501
-                $script_converts_plugin_slug = $migrates_to_version['slug'];
502
-                $script_converts_to_version = $migrates_to_version['version'];
503
-                // check if this version script is DONE or not; or if it's never been ran
504
-                if (! $scripts_ran ||
505
-                    ! isset($scripts_ran[ $script_converts_plugin_slug ]) ||
506
-                    ! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])) {
507
-                    // we haven't ran this conversion script before
508
-                    // now check if it applies... note that we've added an autoloader for it on get_all_data_migration_scripts_available.
509
-                    // Also, make sure we get a new one. It's possible this is being ran during a multisite migration,
510
-                    // in which case we don't want to reuse a DMS script from a different blog!
511
-                    $script = LoaderFactory::getLoader()->load($classname, [], false);
512
-                    /* @var $script EE_Data_Migration_Script_Base */
513
-                    $can_migrate = $script->can_migrate_from_version($theoretical_database_state);
514
-                    if ($can_migrate) {
515
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
516
-                        $migrates_to_version = $script->migrates_to_version();
517
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
518
-                        unset($script_class_and_filepaths_available[ $classname ]);
519
-                    }
520
-                } elseif ($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ] instanceof EE_Data_Migration_Script_Base) {
521
-                    // this script has been ran, or at least started
522
-                    $script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
523
-                    if ($script->get_status() != self::status_completed) {
524
-                        // this script is already underway... keep going with it
525
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
526
-                        $migrates_to_version = $script->migrates_to_version();
527
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
528
-                        unset($script_class_and_filepaths_available[ $classname ]);
529
-                    } else {
530
-                        // it must have a status that indicates it has finished, so we don't want to try and run it again
531
-                    }
532
-                } else {
533
-                    // it exists but it's not  a proper data migration script
534
-                    // maybe the script got renamed? or was simply removed from EE?
535
-                    // either way, its certainly not runnable!
536
-                }
537
-            }
538
-            $iteration++;
539
-        } while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
540
-        // ok we have all the scripts that should run, now let's make them into flat array
541
-        $scripts_that_should_run = array();
542
-        foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
543
-            ksort($scripts_at_priority);
544
-            foreach ($scripts_at_priority as $scripts) {
545
-                foreach ($scripts as $script) {
546
-                    $scripts_that_should_run[ get_class($script) ] = $script;
547
-                }
548
-            }
549
-        }
550
-
551
-        do_action(
552
-            'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run',
553
-            $scripts_that_should_run
554
-        );
555
-        return $scripts_that_should_run;
556
-    }
557
-
558
-
559
-    /**
560
-     * Gets the script which is currently being ran, if there is one. If $include_completed_scripts is set to TRUE
561
-     * it will return the last ran script even if its complete.
562
-     * This means: if you want to find the currently-executing script, leave it as FALSE.
563
-     * If you really just want to find the script which ran most recently, regardless of status, leave it as TRUE.
564
-     *
565
-     * @param bool $include_completed_scripts
566
-     * @return EE_Data_Migration_Script_Base
567
-     */
568
-    public function get_last_ran_script($include_completed_scripts = false)
569
-    {
570
-        // make sure we've setup the class properties _last_ran_script and _last_ran_incomplete_script
571
-        if (! $this->_data_migrations_ran) {
572
-            $this->get_data_migrations_ran();
573
-        }
574
-        if ($include_completed_scripts) {
575
-            return $this->_last_ran_script;
576
-        } else {
577
-            return $this->_last_ran_incomplete_script;
578
-        }
579
-    }
580
-
581
-
582
-    /**
583
-     * Runs the data migration scripts (well, each request to this method calls one of the
584
-     * data migration scripts' migration_step() functions).
585
-     *
586
-     * @param int   $step_size
587
-     * @throws EE_Error
588
-     * @return array {
589
-     *                                  // where the first item is one EE_Data_Migration_Script_Base's stati,
590
-     *                                  //and the second item is a string describing what was done
591
-     * @type int    $records_to_migrate from the current migration script
592
-     * @type int    $records_migrated
593
-     * @type string $status             one of EE_Data_Migration_Manager::status_*
594
-     * @type string $script             verbose name of the current DMS
595
-     * @type string $message            string describing what was done during this step
596
-     *                                  }
597
-     */
598
-    public function migration_step($step_size = 0)
599
-    {
600
-
601
-        // bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
602
-        if (class_exists('EE_CPT_Strategy')) {
603
-            remove_action('pre_get_posts', array(EE_CPT_Strategy::instance(), 'pre_get_posts'), 5);
604
-        }
605
-
606
-        try {
607
-            $currently_executing_script = $this->get_last_ran_script();
608
-            if (! $currently_executing_script) {
609
-                // Find the next script that needs to execute
610
-                $scripts = $this->check_for_applicable_data_migration_scripts();
611
-                if (! $scripts) {
612
-                    // huh, no more scripts to run... apparently we're done!
613
-                    // but dont forget to make sure initial data is there
614
-                    // we should be good to allow them to exit maintenance mode now
615
-                    EE_Maintenance_Mode::instance()->set_maintenance_level(
616
-                        intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
617
-                    );
618
-                    // saving migrations ran should actually be unnecessary, but leaving in place just in case
619
-                    // remember this migration was finished (even if we timeout initing db for core and plugins)
620
-                    $this->_save_migrations_ran();
621
-                    // make sure DB was updated AFTER we've recorded the migration was done
622
-                    $this->initialize_db_for_enqueued_ee_plugins();
623
-                    return array(
624
-                        'records_to_migrate' => 1,
625
-                        'records_migrated'   => 1,
626
-                        'status'             => self::status_no_more_migration_scripts,
627
-                        'script'             => __("Data Migration Completed Successfully", "event_espresso"),
628
-                        'message'            => __("All done!", "event_espresso"),
629
-                    );
630
-                }
631
-                $currently_executing_script = array_shift($scripts);
632
-                // and add to the array/wp option showing the scripts ran
633
-
634
-                $migrates_to = $this->script_migrates_to_version(get_class($currently_executing_script));
635
-                $plugin_slug = $migrates_to['slug'];
636
-                $version = $migrates_to['version'];
637
-                $this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
638
-            }
639
-            $current_script_name = get_class($currently_executing_script);
640
-        } catch (Exception $e) {
641
-            // an exception occurred while trying to get migration scripts
642
-
643
-            $message = sprintf(
644
-                __("Error Message: %sStack Trace:%s", "event_espresso"),
645
-                $e->getMessage() . '<br>',
646
-                $e->getTraceAsString()
647
-            );
648
-            // record it on the array of data migration scripts ran. This will be overwritten next time we try and try to run data migrations
649
-            // but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
650
-            $this->add_error_to_migrations_ran(
651
-                sprintf(__("Could not run data migrations because: %s", "event_espresso"), $message)
652
-            );
653
-            return array(
654
-                'records_to_migrate' => 1,
655
-                'records_migrated'   => 0,
656
-                'status'             => self::status_fatal_error,
657
-                'script'             => __("Error loading data migration scripts", "event_espresso"),
658
-                'message'            => $message,
659
-            );
660
-        }
661
-        // ok so we definitely have a data migration script
662
-        try {
663
-            // how big of a bite do we want to take? Allow users to easily override via their wp-config
664
-            if (absint($step_size) < 1) {
665
-                $step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE)
666
-                    ? EE_MIGRATION_STEP_SIZE : EE_Data_Migration_Manager::step_size;
667
-            }
668
-            // do what we came to do!
669
-            $currently_executing_script->migration_step($step_size);
670
-            // can we wrap it up and verify default data?
671
-            $init_dbs = false;
672
-            switch ($currently_executing_script->get_status()) {
673
-                case EE_Data_Migration_Manager::status_continue:
674
-                    $response_array = array(
675
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
676
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
677
-                        'status'             => EE_Data_Migration_Manager::status_continue,
678
-                        'message'            => $currently_executing_script->get_feedback_message(),
679
-                        'script'             => $currently_executing_script->pretty_name(),
680
-                    );
681
-                    break;
682
-                case EE_Data_Migration_Manager::status_completed:
683
-                    // ok so THAT script has completed
684
-                    $this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
685
-                    $response_array = array(
686
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
687
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
688
-                        'status'             => EE_Data_Migration_Manager::status_completed,
689
-                        'message'            => $currently_executing_script->get_feedback_message(),
690
-                        'script'             => sprintf(
691
-                            __("%s Completed", 'event_espresso'),
692
-                            $currently_executing_script->pretty_name()
693
-                        ),
694
-                    );
695
-                    // check if there are any more after this one.
696
-                    $scripts_remaining = $this->check_for_applicable_data_migration_scripts();
697
-                    if (! $scripts_remaining) {
698
-                        // we should be good to allow them to exit maintenance mode now
699
-                        EE_Maintenance_Mode::instance()->set_maintenance_level(
700
-                            intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
701
-                        );
702
-                        // huh, no more scripts to run... apparently we're done!
703
-                        // but dont forget to make sure initial data is there
704
-                        $init_dbs = true;
705
-                        $response_array['status'] = self::status_no_more_migration_scripts;
706
-                    }
707
-                    break;
708
-                default:
709
-                    $response_array = array(
710
-                        'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
711
-                        'records_migrated'   => $currently_executing_script->count_records_migrated(),
712
-                        'status'             => $currently_executing_script->get_status(),
713
-                        'message'            => sprintf(
714
-                            __("Minor errors occurred during %s: %s", "event_espresso"),
715
-                            $currently_executing_script->pretty_name(),
716
-                            implode(", ", $currently_executing_script->get_errors())
717
-                        ),
718
-                        'script'             => $currently_executing_script->pretty_name(),
719
-                    );
720
-                    break;
721
-            }
722
-        } catch (Exception $e) {
723
-            // ok so some exception was thrown which killed the data migration script
724
-            // double-check we have a real script
725
-            if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
726
-                $script_name = $currently_executing_script->pretty_name();
727
-                $currently_executing_script->set_broken();
728
-                $currently_executing_script->add_error($e->getMessage());
729
-            } else {
730
-                $script_name = __("Error getting Migration Script", "event_espresso");
731
-            }
732
-            $response_array = array(
733
-                'records_to_migrate' => 1,
734
-                'records_migrated'   => 0,
735
-                'status'             => self::status_fatal_error,
736
-                'message'            => sprintf(
737
-                    __("A fatal error occurred during the migration: %s", "event_espresso"),
738
-                    $e->getMessage()
739
-                ),
740
-                'script'             => $script_name,
741
-            );
742
-        }
743
-        $successful_save = $this->_save_migrations_ran();
744
-        if ($successful_save !== true) {
745
-            // ok so the current wp option didn't save. that's tricky, because we'd like to update it
746
-            // and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
747
-            // however, if we throw an exception, and return that, then the next request
748
-            // won't have as much info in it, and it may be able to save
749
-            throw new EE_Error(
750
-                sprintf(
751
-                    __(
752
-                        "The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.",
753
-                        "event_espresso"
754
-                    ),
755
-                    $successful_save
756
-                )
757
-            );
758
-        }
759
-        // if we're all done, initialize EE plugins' default data etc.
760
-        if ($init_dbs) {
761
-            $this->initialize_db_for_enqueued_ee_plugins();
762
-        }
763
-        return $response_array;
764
-    }
765
-
766
-
767
-    /**
768
-     * Echo out JSON response to migration script AJAX requests. Takes precautions
769
-     * to buffer output so that we don't throw junk into our json.
770
-     *
771
-     * @return array with keys:
772
-     * 'records_to_migrate' which counts ALL the records for the current migration, and should remain constant. (ie,
773
-     * it's NOT the count of hwo many remain)
774
-     * 'records_migrated' which also counts ALL the records which have been migrated (ie, percent_complete =
775
-     * records_migrated/records_to_migrate)
776
-     * 'status'=>a string, one of EE_Data_migration_Manager::status_*
777
-     * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into
778
-     * errors, notifications, and successes
779
-     * 'script'=>a pretty name of the script currently running
780
-     */
781
-    public function response_to_migration_ajax_request()
782
-    {
783
-        ob_start();
784
-        try {
785
-            $response = $this->migration_step();
786
-        } catch (Exception $e) {
787
-            $response = array(
788
-                'records_to_migrate' => 0,
789
-                'records_migrated'   => 0,
790
-                'status'             => EE_Data_Migration_Manager::status_fatal_error,
791
-                'message'            => sprintf(
792
-                    __("Unknown fatal error occurred: %s", "event_espresso"),
793
-                    $e->getMessage()
794
-                ),
795
-                'script'             => 'Unknown',
796
-            );
797
-            $this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
798
-        }
799
-        $warnings_etc = @ob_get_contents();
800
-        ob_end_clean();
801
-        $response['message'] .= $warnings_etc;
802
-        return $response;
803
-    }
804
-
805
-    /**
806
-     * Updates the wordpress option that keeps track of which which EE version the database
807
-     * is at (ie, the code may be at 4.1.0, but the database is still at 3.1.35)
808
-     *
809
-     * @param array $slug_and_version {
810
-     * @type string $slug             like 'Core' or 'Calendar',
811
-     * @type string $version          like '4.1.0'
812
-     *                                }
813
-     * @return void
814
-     */
815
-    public function update_current_database_state_to($slug_and_version = null)
816
-    {
817
-        if (! $slug_and_version) {
818
-            // no version was provided, assume it should be at the current code version
819
-            $slug_and_version = array('slug' => 'Core', 'version' => espresso_version());
820
-        }
821
-        $current_database_state = get_option(self::current_database_state);
822
-        $current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
823
-        update_option(self::current_database_state, $current_database_state);
824
-    }
825
-
826
-    /**
827
-     * Determines if the database is currently at a state matching what's indicated in $slug and $version.
828
-     *
829
-     * @param array $slug_and_version {
830
-     * @type string $slug             like 'Core' or 'Calendar',
831
-     * @type string $version          like '4.1.0'
832
-     *                                }
833
-     * @return boolean
834
-     */
835
-    public function database_needs_updating_to($slug_and_version)
836
-    {
837
-
838
-        $slug = $slug_and_version['slug'];
839
-        $version = $slug_and_version['version'];
840
-        $current_database_state = get_option(self::current_database_state);
841
-        if (! isset($current_database_state[ $slug ])) {
842
-            return true;
843
-        } else {
844
-            // just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
845
-            $version_parts_current_db_state = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
846
-            $version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
847
-            $needs_updating = false;
848
-            foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
849
-                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
850
-                    $needs_updating = true;
851
-                    break;
852
-                }
853
-            }
854
-            return $needs_updating;
855
-        }
856
-    }
857
-
858
-
859
-    /**
860
-     * Gets all the data migration scripts available in the core folder and folders
861
-     * in addons. Has the side effect of adding them for autoloading
862
-     *
863
-     * @return array keys are expected classnames, values are their filepaths
864
-     * @throws InvalidInterfaceException
865
-     * @throws InvalidDataTypeException
866
-     * @throws EE_Error
867
-     * @throws InvalidArgumentException
868
-     */
869
-    public function get_all_data_migration_scripts_available()
870
-    {
871
-        if (! $this->_data_migration_class_to_filepath_map) {
872
-            $this->_data_migration_class_to_filepath_map = array();
873
-            foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
874
-                // strip any placeholders added to classname to make it a unique array key
875
-                $eeAddonClass = trim($eeAddonClass, '*');
876
-                $eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
877
-                    ? $eeAddonClass
878
-                    : '';
879
-                $folder_path = EEH_File::end_with_directory_separator($folder_path);
880
-                $files = glob($folder_path . '*.dms.php');
881
-                if (empty($files)) {
882
-                    continue;
883
-                }
884
-                foreach ($files as $file) {
885
-                    $pos_of_last_slash = strrpos($file, '/');
886
-                    $classname = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
887
-                    $migrates_to = $this->script_migrates_to_version($classname, $eeAddonClass);
888
-                    $slug = $migrates_to['slug'];
889
-                    // check that the slug as contained in the DMS is associated with
890
-                    // the slug of an addon or core
891
-                    if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
892
-                        EE_Error::doing_it_wrong(
893
-                            __FUNCTION__,
894
-                            sprintf(
895
-                                esc_html__(
896
-                                    'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
897
-                                    'event_espresso'
898
-                                ),
899
-                                $classname,
900
-                                $slug,
901
-                                implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
902
-                            ),
903
-                            '4.3.0.alpha.019'
904
-                        );
905
-                    }
906
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
907
-                }
908
-            }
909
-            EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
910
-        }
911
-        return $this->_data_migration_class_to_filepath_map;
912
-    }
913
-
914
-
915
-    /**
916
-     * Once we have an addon that works with EE4.1, we will actually want to fetch the PUE slugs
917
-     * from each addon, and check if they need updating,
918
-     *
919
-     * @return boolean
920
-     */
921
-    public function addons_need_updating()
922
-    {
923
-        return false;
924
-    }
925
-
926
-    /**
927
-     * Adds this error string to the data_migrations_ran array, but we dont necessarily know
928
-     * where to put it, so we just throw it in there... better than nothing...
929
-     *
930
-     * @param string $error_message
931
-     * @throws EE_Error
932
-     */
933
-    public function add_error_to_migrations_ran($error_message)
934
-    {
935
-        // get last-ran migration script
936
-        global $wpdb;
937
-        $last_migration_script_option = $wpdb->get_row(
938
-            "SELECT * FROM $wpdb->options WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id DESC LIMIT 1",
939
-            ARRAY_A
940
-        );
941
-
942
-        $last_ran_migration_script_properties = isset($last_migration_script_option['option_value'])
943
-            ? maybe_unserialize($last_migration_script_option['option_value']) : null;
944
-        // now, tread lightly because we're here because a FATAL non-catchable error
945
-        // was thrown last time when we were trying to run a data migration script
946
-        // so the fatal error could have happened while getting the migration script
947
-        // or doing running it...
948
-        $versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(
949
-            EE_Data_Migration_Manager::data_migration_script_option_prefix,
950
-            "",
951
-            $last_migration_script_option['option_name']
952
-        ) : null;
953
-
954
-        // check if it THINKS its a data migration script and especially if it's one that HASN'T finished yet
955
-        // because if it has finished, then it obviously couldn't be the cause of this error, right? (because its all done)
956
-        if (isset($last_ran_migration_script_properties['class']) && isset($last_ran_migration_script_properties['_status']) && $last_ran_migration_script_properties['_status'] != self::status_completed) {
957
-            // ok then just add this error to its list of errors
958
-            $last_ran_migration_script_properties['_errors'][] = $error_message;
959
-            $last_ran_migration_script_properties['_status'] = self::status_fatal_error;
960
-        } else {
961
-            // so we don't even know which script was last running
962
-            // use the data migration error stub, which is designed specifically for this type of thing
963
-            $general_migration_error = new EE_DMS_Unknown_1_0_0();
964
-            $general_migration_error->add_error($error_message);
965
-            $general_migration_error->set_broken();
966
-            $last_ran_migration_script_properties = $general_migration_error->properties_as_array();
967
-            $versions_migrated_to = 'Unknown.1.0.0';
968
-            // now just to make sure appears as last (in case the were previously a fatal error like this)
969
-            // delete the old one
970
-            delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
971
-        }
972
-        update_option(
973
-            self::data_migration_script_option_prefix . $versions_migrated_to,
974
-            $last_ran_migration_script_properties
975
-        );
976
-    }
977
-
978
-    /**
979
-     * saves what data migrations have ran to the database
980
-     *
981
-     * @return mixed TRUE if successfully saved migrations ran, string if an error occurred
982
-     */
983
-    protected function _save_migrations_ran()
984
-    {
985
-        if ($this->_data_migrations_ran == null) {
986
-            $this->get_data_migrations_ran();
987
-        }
988
-        // now, we don't want to save actual classes to the DB because that's messy
989
-        $successful_updates = true;
990
-        foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
991
-            foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
992
-                $plugin_slug_for_use_in_option_name = $plugin_slug . ".";
993
-                $option_name = self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
994
-                $old_option_value = get_option($option_name);
995
-                if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
996
-                    $script_array_for_saving = $array_or_migration_obj->properties_as_array();
997
-                    if ($old_option_value != $script_array_for_saving) {
998
-                        $successful_updates = update_option($option_name, $script_array_for_saving);
999
-                    }
1000
-                } else {// we don't know what this array-thing is. So just save it as-is
1001
-                    if ($old_option_value != $array_or_migration_obj) {
1002
-                        $successful_updates = update_option($option_name, $array_or_migration_obj);
1003
-                    }
1004
-                }
1005
-                if (! $successful_updates) {
1006
-                    global $wpdb;
1007
-                    return $wpdb->last_error;
1008
-                }
1009
-            }
1010
-        }
1011
-        return true;
1012
-        // $updated = update_option(self::data_migrations_option_name, $array_of_migrations);
1013
-        // if ($updated !== true) {
1014
-        //     global $wpdb;
1015
-        //     return $wpdb->last_error;
1016
-        // } else {
1017
-        //     return true;
1018
-        // }
1019
-        // wp_mail(
1020
-        //     "[email protected]",
1021
-        //     time() . " price debug info",
1022
-        //     "updated: $updated, last error: $last_error, byte length of option: " . strlen(
1023
-        //         serialize($array_of_migrations)
1024
-        //     )
1025
-        // );
1026
-    }
1027
-
1028
-    /**
1029
-     * Takes an array of data migration script properties and re-creates the class from
1030
-     * them. The argument $properties_array is assumed to have been made by
1031
-     * EE_Data_Migration_Script_Base::properties_as_array()
1032
-     *
1033
-     * @param array $properties_array
1034
-     * @return EE_Data_Migration_Script_Base
1035
-     * @throws EE_Error
1036
-     */
1037
-    public function _instantiate_script_from_properties_array($properties_array)
1038
-    {
1039
-        if (! isset($properties_array['class'])) {
1040
-            throw new EE_Error(
1041
-                sprintf(
1042
-                    __("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
1043
-                    implode(",", $properties_array)
1044
-                )
1045
-            );
1046
-        }
1047
-        $class_name = $properties_array['class'];
1048
-        if (! class_exists($class_name)) {
1049
-            throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"), $class_name));
1050
-        }
1051
-        $class = new $class_name;
1052
-        if (! $class instanceof EE_Data_Migration_Script_Base) {
1053
-            throw new EE_Error(
1054
-                sprintf(
1055
-                    __("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"),
1056
-                    $class_name,
1057
-                    get_class($class)
1058
-                )
1059
-            );
1060
-        }
1061
-        $class->instantiate_from_array_of_properties($properties_array);
1062
-        return $class;
1063
-    }
1064
-
1065
-    /**
1066
-     * Gets the classname for the most up-to-date DMS (ie, the one that will finally
1067
-     * leave the DB in a state usable by the current plugin code).
1068
-     *
1069
-     * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
1070
-     * @return string
1071
-     */
1072
-    public function get_most_up_to_date_dms($plugin_slug = 'Core')
1073
-    {
1074
-        $class_to_filepath_map = $this->get_all_data_migration_scripts_available();
1075
-        $most_up_to_date_dms_classname = null;
1076
-        foreach ($class_to_filepath_map as $classname => $filepath) {
1077
-            if ($most_up_to_date_dms_classname === null) {
1078
-                $migrates_to = $this->script_migrates_to_version($classname);
1079
-                $this_plugin_slug = $migrates_to['slug'];
1080
-                if ($this_plugin_slug == $plugin_slug) {
1081
-                    // if it's for core, it wins
1082
-                    $most_up_to_date_dms_classname = $classname;
1083
-                }
1084
-                // if it wasn't for core, we must keep searching for one that is!
1085
-                continue;
1086
-            } else {
1087
-                $champion_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms_classname);
1088
-                $contender_migrates_to = $this->script_migrates_to_version($classname);
1089
-                if ($contender_migrates_to['slug'] == $plugin_slug
1090
-                    && version_compare(
1091
-                        $champion_migrates_to['version'],
1092
-                        $contender_migrates_to['version'],
1093
-                        '<'
1094
-                    )) {
1095
-                    // so the contenders version is higher and its for Core
1096
-                    $most_up_to_date_dms_classname = $classname;
1097
-                }
1098
-            }
1099
-        }
1100
-        return $most_up_to_date_dms_classname;
1101
-    }
1102
-
1103
-    /**
1104
-     * Gets the migration script specified but ONLY if it has already ran.
1105
-     *
1106
-     * Eg, if you wanted to see if 'EE_DMS_Core_4_1_0' has ran, you would run the following code:
1107
-     * <code> $core_4_1_0_dms_ran = EE_Data_Migration_Manager::instance()->get_migration_ran( '4.1.0', 'Core' ) !==
1108
-     * NULL;</code> This is especially useful in addons' data migration scripts, this way they can tell if a core (or
1109
-     * other addon) DMS has ran, in case the current DMS depends on it.
1110
-     *
1111
-     * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1112
-     *                            period. Eg '4.1.0'
1113
-     * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1114
-     * @return EE_Data_Migration_Script_Base
1115
-     */
1116
-    public function get_migration_ran($version, $plugin_slug = 'Core')
1117
-    {
1118
-        $migrations_ran = $this->get_data_migrations_ran();
1119
-        if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1120
-            return $migrations_ran[ $plugin_slug ][ $version ];
1121
-        } else {
1122
-            return null;
1123
-        }
1124
-    }
1125
-
1126
-    /**
1127
-     * Resets the borked data migration scripts so they're no longer borked
1128
-     * so we can again attempt to migrate
1129
-     *
1130
-     * @return bool
1131
-     * @throws EE_Error
1132
-     */
1133
-    public function reattempt()
1134
-    {
1135
-        // find if the last-ran script was borked
1136
-        // set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
1137
-        // add an 'error' saying that we attempted to reset
1138
-        // does it have a stage that was borked too? if so make it no longer borked
1139
-        // add an 'error' saying we attempted to reset
1140
-        $last_ran_script = $this->get_last_ran_script();
1141
-        if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
1142
-            // if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
1143
-            $last_ran_script->set_completed();
1144
-        } elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
1145
-            $last_ran_script->reattempt();
1146
-        } else {
1147
-            throw new EE_Error(
1148
-                sprintf(
1149
-                    __(
1150
-                        'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s',
1151
-                        'event_espresso'
1152
-                    ),
1153
-                    print_r($last_ran_script, true)
1154
-                )
1155
-            );
1156
-        }
1157
-        return $this->_save_migrations_ran();
1158
-    }
1159
-
1160
-    /**
1161
-     * Gets whether or not this particular migration has run or not
1162
-     *
1163
-     * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1164
-     *                            period. Eg '4.1.0'
1165
-     * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1166
-     * @return boolean
1167
-     */
1168
-    public function migration_has_ran($version, $plugin_slug = 'Core')
1169
-    {
1170
-        return $this->get_migration_ran($version, $plugin_slug) !== null;
1171
-    }
1172
-
1173
-    /**
1174
-     * Enqueues this ee plugin to have its data initialized
1175
-     *
1176
-     * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
1177
-     */
1178
-    public function enqueue_db_initialization_for($plugin_slug)
1179
-    {
1180
-        $queue = $this->get_db_initialization_queue();
1181
-        if (! in_array($plugin_slug, $queue)) {
1182
-            $queue[] = $plugin_slug;
1183
-        }
1184
-        update_option(self::db_init_queue_option_name, $queue);
1185
-    }
1186
-
1187
-    /**
1188
-     * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
1189
-     * specified in EE_Data_Migration_Manager::get_db_init_queue(), and if 'Core' is
1190
-     * in the queue, calls EE_System::initialize_db_if_no_migrations_required().
1191
-     */
1192
-    public function initialize_db_for_enqueued_ee_plugins()
1193
-    {
1194
-        $queue = $this->get_db_initialization_queue();
1195
-        foreach ($queue as $plugin_slug) {
1196
-            $most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1197
-            if (! $most_up_to_date_dms) {
1198
-                // if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1199
-                $verify_db = false;
1200
-            } else {
1201
-                $most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1202
-                $verify_db = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1203
-            }
1204
-            if ($plugin_slug == 'Core') {
1205
-                EE_System::instance()->initialize_db_if_no_migrations_required(
1206
-                    false,
1207
-                    $verify_db
1208
-                );
1209
-            } else {
1210
-                // just loop through the addons to make sure their database is setup
1211
-                foreach (EE_Registry::instance()->addons as $addon) {
1212
-                    if ($addon->name() == $plugin_slug) {
1213
-                        $addon->initialize_db_if_no_migrations_required($verify_db);
1214
-                        break;
1215
-                    }
1216
-                }
1217
-            }
1218
-        }
1219
-        // because we just initialized the DBs for the enqueued ee plugins
1220
-        // we don't need to keep remembering which ones needed to be initialized
1221
-        delete_option(self::db_init_queue_option_name);
1222
-    }
1223
-
1224
-    /**
1225
-     * Gets a numerically-indexed array of plugin slugs that need to have their databases
1226
-     * (re-)initialized after migrations are complete. ie, each element should be either
1227
-     * 'Core', or the return value of EE_Addon::name() for an addon
1228
-     *
1229
-     * @return array
1230
-     */
1231
-    public function get_db_initialization_queue()
1232
-    {
1233
-        return get_option(self::db_init_queue_option_name, array());
1234
-    }
1235
-
1236
-    /**
1237
-     * Gets the injected table analyzer, or throws an exception
1238
-     *
1239
-     * @return TableAnalysis
1240
-     * @throws EE_Error
1241
-     */
1242
-    protected function _get_table_analysis()
1243
-    {
1244
-        if ($this->_table_analysis instanceof TableAnalysis) {
1245
-            return $this->_table_analysis;
1246
-        } else {
1247
-            throw new EE_Error(
1248
-                sprintf(
1249
-                    __('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1250
-                    get_class($this)
1251
-                )
1252
-            );
1253
-        }
1254
-    }
1255
-
1256
-    /**
1257
-     * Gets the injected table manager, or throws an exception
1258
-     *
1259
-     * @return TableManager
1260
-     * @throws EE_Error
1261
-     */
1262
-    protected function _get_table_manager()
1263
-    {
1264
-        if ($this->_table_manager instanceof TableManager) {
1265
-            return $this->_table_manager;
1266
-        } else {
1267
-            throw new EE_Error(
1268
-                sprintf(
1269
-                    __('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1270
-                    get_class($this)
1271
-                )
1272
-            );
1273
-        }
1274
-    }
36
+	/**
37
+	 *
38
+	 * @var EE_Registry
39
+	 */
40
+	// protected $EE;
41
+	/**
42
+	 * name of the wordpress option which stores an array of data about
43
+	 */
44
+	const data_migrations_option_name = 'ee_data_migration';
45
+
46
+
47
+	const data_migration_script_option_prefix = 'ee_data_migration_script_';
48
+
49
+	const data_migration_script_mapping_option_prefix = 'ee_dms_map_';
50
+
51
+	/**
52
+	 * name of the wordpress option which stores the database' current version. IE, the code may be at version 4.2.0,
53
+	 * but as migrations are performed the database will progress from 3.1.35 to 4.1.0 etc.
54
+	 */
55
+	const current_database_state = 'ee_data_migration_current_db_state';
56
+
57
+	/**
58
+	 * Special status string returned when we're positive there are no more data migration
59
+	 * scripts that can be run.
60
+	 */
61
+	const status_no_more_migration_scripts = 'no_more_migration_scripts';
62
+	/**
63
+	 * string indicating the migration should continue
64
+	 */
65
+	const status_continue = 'status_continue';
66
+	/**
67
+	 * string indicating the migration has completed and should be ended
68
+	 */
69
+	const status_completed = 'status_completed';
70
+	/**
71
+	 * string indicating a fatal error occurred and the data migration should be completely aborted
72
+	 */
73
+	const status_fatal_error = 'status_fatal_error';
74
+
75
+	/**
76
+	 * the number of 'items' (usually DB rows) to migrate on each 'step' (ajax request sent
77
+	 * during migration)
78
+	 */
79
+	const step_size = 50;
80
+
81
+	/**
82
+	 * option name that stores the queue of ee plugins needing to have
83
+	 * their data initialized (or re-initialized) once we are done migrations
84
+	 */
85
+	const db_init_queue_option_name = 'ee_db_init_queue';
86
+	/**
87
+	 * Array of information concerning data migrations that have ran in the history
88
+	 * of this EE installation. Keys should be the name of the version the script upgraded to
89
+	 *
90
+	 * @var EE_Data_Migration_Script_Base[]
91
+	 */
92
+	private $_data_migrations_ran = null;
93
+	/**
94
+	 * The last ran script. It's nice to store this somewhere accessible, as its easiest
95
+	 * to know which was the last run by which is the newest wp option; but in most of the code
96
+	 * we just use the local $_data_migration_ran array, which organized the scripts differently
97
+	 *
98
+	 * @var EE_Data_Migration_Script_Base
99
+	 */
100
+	private $_last_ran_script = null;
101
+
102
+	/**
103
+	 * Similarly to _last_ran_script, but this is the last INCOMPLETE migration script.
104
+	 *
105
+	 * @var EE_Data_Migration_Script_Base
106
+	 */
107
+	private $_last_ran_incomplete_script = null;
108
+	/**
109
+	 * array where keys are classnames, and values are filepaths of all the known migration scripts
110
+	 *
111
+	 * @var array
112
+	 */
113
+	private $_data_migration_class_to_filepath_map;
114
+
115
+	/**
116
+	 * the following 4 properties are fully set on construction.
117
+	 * Note: the first two apply to whether to continue running ALL migration scripts (ie, even though we're finished
118
+	 * one, we may want to start the next one); whereas the last two indicate whether to continue running a single
119
+	 * data migration script
120
+	 *
121
+	 * @var array
122
+	 */
123
+	public $stati_that_indicate_to_continue_migrations = array();
124
+
125
+	public $stati_that_indicate_to_stop_migrations = array();
126
+
127
+	public $stati_that_indicate_to_continue_single_migration_script = array();
128
+
129
+	public $stati_that_indicate_to_stop_single_migration_script = array();
130
+
131
+	/**
132
+	 * @var \EventEspresso\core\services\database\TableManager $table_manager
133
+	 */
134
+	protected $_table_manager;
135
+
136
+	/**
137
+	 * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
138
+	 */
139
+	protected $_table_analysis;
140
+
141
+	/**
142
+	 * @var array $script_migration_versions
143
+	 */
144
+	protected $script_migration_versions;
145
+
146
+	/**
147
+	 * @var EE_Data_Migration_Manager $_instance
148
+	 * @access    private
149
+	 */
150
+	private static $_instance = null;
151
+
152
+
153
+	/**
154
+	 * @singleton method used to instantiate class object
155
+	 * @access    public
156
+	 * @return EE_Data_Migration_Manager instance
157
+	 */
158
+	public static function instance()
159
+	{
160
+		// check if class object is instantiated
161
+		if (! self::$_instance instanceof EE_Data_Migration_Manager) {
162
+			self::$_instance = new self();
163
+		}
164
+		return self::$_instance;
165
+	}
166
+
167
+	/**
168
+	 * resets the singleton to its brand-new state (but does NOT delete old references to the old singleton. Meaning,
169
+	 * all new usages of the singleton should be made with Classname::instance()) and returns it
170
+	 *
171
+	 * @return EE_Data_Migration_Manager
172
+	 */
173
+	public static function reset()
174
+	{
175
+		self::$_instance = null;
176
+		return self::instance();
177
+	}
178
+
179
+
180
+	/**
181
+	 * constructor
182
+	 */
183
+	private function __construct()
184
+	{
185
+		$this->stati_that_indicate_to_continue_migrations = array(
186
+			self::status_continue,
187
+			self::status_completed,
188
+		);
189
+		$this->stati_that_indicate_to_stop_migrations = array(
190
+			self::status_fatal_error,
191
+			self::status_no_more_migration_scripts,
192
+		);
193
+		$this->stati_that_indicate_to_continue_single_migration_script = array(
194
+			self::status_continue,
195
+		);
196
+		$this->stati_that_indicate_to_stop_single_migration_script = array(
197
+			self::status_completed,
198
+			self::status_fatal_error
199
+			// note: status_no_more_migration_scripts doesn't apply
200
+		);
201
+		// make sure we've included the base migration script, because we may need the EE_DMS_Unknown_1_0_0 class
202
+		// to be defined, because right now it doesn't get autoloaded on its own
203
+		EE_Registry::instance()->load_core('Data_Migration_Class_Base', array(), true);
204
+		EE_Registry::instance()->load_core('Data_Migration_Script_Base', array(), true);
205
+		EE_Registry::instance()->load_core('DMS_Unknown_1_0_0', array(), true);
206
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage', array(), true);
207
+		EE_Registry::instance()->load_core('Data_Migration_Script_Stage_Table', array(), true);
208
+		$this->_table_manager = EE_Registry::instance()->create('TableManager', array(), true);
209
+		$this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
210
+	}
211
+
212
+
213
+	/**
214
+	 * Deciphers, from an option's name, what plugin and version it relates to (see _save_migrations_ran to see what
215
+	 * the option names are like, but generally they're like
216
+	 * 'ee_data_migration_script_Core.4.1.0' in 4.2 or 'ee_data_migration_script_4.1.0' before that).
217
+	 * The option name shouldn't ever be like 'ee_data_migration_script_Core.4.1.0.reg' because it's derived,
218
+	 * indirectly, from the data migration's classname, which should always be like EE_DMS_%s_%d_%d_%d.dms.php (eg
219
+	 * EE_DMS_Core_4_1_0.dms.php)
220
+	 *
221
+	 * @param string $option_name (see EE_Data_Migration_Manage::_save_migrations_ran() where the option name is set)
222
+	 * @return array where the first item is the plugin slug (eg 'Core','Calendar',etc) and the 2nd is the version of
223
+	 *               that plugin (eg '4.1.0')
224
+	 */
225
+	private function _get_plugin_slug_and_version_string_from_dms_option_name($option_name)
226
+	{
227
+		$plugin_slug_and_version_string = str_replace(
228
+			EE_Data_Migration_Manager::data_migration_script_option_prefix,
229
+			"",
230
+			$option_name
231
+		);
232
+		// check if $plugin_slug_and_version_string is like '4.1.0' (4.1-style) or 'Core.4.1.0' (4.2-style)
233
+		$parts = explode(".", $plugin_slug_and_version_string);
234
+
235
+		if (count($parts) == 4) {
236
+			// it's 4.2-style.eg Core.4.1.0
237
+			$plugin_slug = $parts[0];// eg Core
238
+			$version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
239
+		} else {
240
+			// it's 4.1-style: eg 4.1.0
241
+			$plugin_slug = 'Core';
242
+			$version_string = $plugin_slug_and_version_string;// eg 4.1.0
243
+		}
244
+		return array($plugin_slug, $version_string);
245
+	}
246
+
247
+	/**
248
+	 * Gets the DMS class from the wordpress option, otherwise throws an EE_Error if it's not
249
+	 * for a known DMS class.
250
+	 *
251
+	 * @param string $dms_option_name
252
+	 * @param string $dms_option_value (serialized)
253
+	 * @return EE_Data_Migration_Script_Base
254
+	 * @throws EE_Error
255
+	 */
256
+	private function _get_dms_class_from_wp_option($dms_option_name, $dms_option_value)
257
+	{
258
+		$data_migration_data = maybe_unserialize($dms_option_value);
259
+		if (isset($data_migration_data['class']) && class_exists($data_migration_data['class'])) {
260
+			// During multisite migrations, it's possible we already grabbed another instance of this class
261
+			// but for a different blog. Make sure we don't reuse them (as they store info specific
262
+			// to their respective blog, like which database table to migrate).
263
+			$class = LoaderFactory::getLoader()->getShared($data_migration_data['class'], [], false);
264
+			if ($class instanceof EE_Data_Migration_Script_Base) {
265
+				$class->instantiate_from_array_of_properties($data_migration_data);
266
+				return $class;
267
+			} else {
268
+				// huh, so its an object but not a data migration script?? that shouldn't happen
269
+				// just leave it as an array (which will probably just get ignored)
270
+				throw new EE_Error(
271
+					sprintf(
272
+						__(
273
+							"Trying to retrieve DMS class from wp option. No DMS by the name '%s' exists",
274
+							'event_espresso'
275
+						),
276
+						$data_migration_data['class']
277
+					)
278
+				);
279
+			}
280
+		} else {
281
+			// so the data doesn't specify a class. So it must either be a legacy array of info or some array (which we'll probably just ignore), or a class that no longer exists
282
+			throw new EE_Error(
283
+				sprintf(__("The wp option  with key '%s' does not represent a DMS", 'event_espresso'), $dms_option_name)
284
+			);
285
+		}
286
+	}
287
+
288
+	/**
289
+	 * Gets the array describing what data migrations have run. Also has a side-effect of recording which was the last
290
+	 * ran, and which was the last ran which hasn't finished yet
291
+	 *
292
+	 * @return array where each element should be an array of EE_Data_Migration_Script_Base (but also has a few legacy
293
+	 *               arrays in there - which should probably be ignored)
294
+	 */
295
+	public function get_data_migrations_ran()
296
+	{
297
+		if (! $this->_data_migrations_ran) {
298
+			// setup autoloaders for each of the scripts in there
299
+			$this->get_all_data_migration_scripts_available();
300
+			$data_migrations_options = $this->get_all_migration_script_options(
301
+			);// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
302
+
303
+			$data_migrations_ran = array();
304
+			// convert into data migration script classes where possible
305
+			foreach ($data_migrations_options as $data_migration_option) {
306
+				list($plugin_slug, $version_string) = $this->_get_plugin_slug_and_version_string_from_dms_option_name(
307
+					$data_migration_option['option_name']
308
+				);
309
+
310
+				try {
311
+					$class = $this->_get_dms_class_from_wp_option(
312
+						$data_migration_option['option_name'],
313
+						$data_migration_option['option_value']
314
+					);
315
+					$data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
316
+					// ok so far THIS is the 'last-ran-script'... unless we find another on next iteration
317
+					$this->_last_ran_script = $class;
318
+					if (! $class->is_completed()) {
319
+						// sometimes we also like to know which was the last incomplete script (or if there are any at all)
320
+						$this->_last_ran_incomplete_script = $class;
321
+					}
322
+				} catch (EE_Error $e) {
323
+					// ok so its not a DMS. We'll just keep it, although other code will need to expect non-DMSs
324
+					$data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
325
+						$data_migration_option['option_value']
326
+					);
327
+				}
328
+			}
329
+			// so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
330
+			$this->_data_migrations_ran = $data_migrations_ran;
331
+			if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
332
+				$this->_data_migrations_ran = array();
333
+			}
334
+		}
335
+		return $this->_data_migrations_ran;
336
+	}
337
+
338
+
339
+	/**
340
+	 *
341
+	 * @param string $script_name eg 'DMS_Core_4_1_0'
342
+	 * @param string $old_table   eg 'wp_events_detail'
343
+	 * @param string $old_pk      eg 'wp_esp_posts'
344
+	 * @param        $new_table
345
+	 * @return mixed string or int
346
+	 */
347
+	public function get_mapping_new_pk($script_name, $old_table, $old_pk, $new_table)
348
+	{
349
+		$script = EE_Registry::instance()->load_dms($script_name);
350
+		$mapping = $script->get_mapping_new_pk($old_table, $old_pk, $new_table);
351
+		return $mapping;
352
+	}
353
+
354
+	/**
355
+	 * Gets all the options containing migration scripts that have been run. Ordering is important: it's assumed that
356
+	 * the last option returned in this array is the most-recently ran DMS option
357
+	 *
358
+	 * @return array
359
+	 */
360
+	public function get_all_migration_script_options()
361
+	{
362
+		global $wpdb;
363
+		return $wpdb->get_results(
364
+			"SELECT * FROM {$wpdb->options} WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id ASC",
365
+			ARRAY_A
366
+		);
367
+	}
368
+
369
+	/**
370
+	 * Gets the array of folders which contain data migration scripts. Also adds them to be auto-loaded
371
+	 *
372
+	 * @return array where each value is the full folder path of a folder containing data migration scripts, WITH
373
+	 *               slashes at the end of the folder name.
374
+	 */
375
+	public function get_data_migration_script_folders()
376
+	{
377
+		return apply_filters(
378
+			'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
379
+			array('Core' => EE_CORE . 'data_migration_scripts')
380
+		);
381
+	}
382
+
383
+	/**
384
+	 * Gets the version the migration script upgrades to
385
+	 *
386
+	 * @param string $migration_script_name eg 'EE_DMS_Core_4_1_0'
387
+	 * @return array {
388
+	 * @type string  $slug                  like 'Core','Calendar',etc
389
+	 * @type string  $version               like 4.3.0
390
+	 *                                      }
391
+	 * @throws EE_Error
392
+	 */
393
+	public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
394
+	{
395
+		if (isset($this->script_migration_versions[ $migration_script_name ])) {
396
+			return $this->script_migration_versions[ $migration_script_name ];
397
+		}
398
+		$dms_info = $this->parse_dms_classname($migration_script_name);
399
+		$this->script_migration_versions[ $migration_script_name ] = array(
400
+			'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
401
+			'version' => $dms_info['major_version'] . "." . $dms_info['minor_version'] . "." . $dms_info['micro_version'],
402
+		);
403
+		return $this->script_migration_versions[ $migration_script_name ];
404
+	}
405
+
406
+	/**
407
+	 * Gets the juicy details out of a dms filename like 'EE_DMS_Core_4_1_0'
408
+	 *
409
+	 * @param string $classname
410
+	 * @return array with keys 'slug','major_version','minor_version', and 'micro_version' (the last 3 are ints)
411
+	 * @throws EE_Error
412
+	 */
413
+	public function parse_dms_classname($classname)
414
+	{
415
+		$matches = array();
416
+		preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
417
+		if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
418
+			throw new EE_Error(
419
+				sprintf(
420
+					__(
421
+						"%s is not a valid Data Migration Script. The classname should be like EE_DMS_w_x_y_z, where w is either 'Core' or the slug of an addon and x, y and z are numbers, ",
422
+						"event_espresso"
423
+					),
424
+					$classname
425
+				)
426
+			);
427
+		}
428
+		return array(
429
+			'slug'          => $matches[1],
430
+			'major_version' => intval($matches[2]),
431
+			'minor_version' => intval($matches[3]),
432
+			'micro_version' => intval($matches[4]),
433
+		);
434
+	}
435
+
436
+	/**
437
+	 * Ensures that the option indicating the current DB version is set. This should only be
438
+	 * a concern when activating EE for the first time, THEORETICALLY.
439
+	 * If we detect that we're activating EE4 over top of EE3.1, then we set the current db state to 3.1.x, otherwise
440
+	 * to 4.1.x.
441
+	 *
442
+	 * @return string of current db state
443
+	 */
444
+	public function ensure_current_database_state_is_set()
445
+	{
446
+		$espresso_db_core_updates = get_option('espresso_db_update', array());
447
+		$db_state = get_option(EE_Data_Migration_Manager::current_database_state);
448
+		if (! $db_state) {
449
+			// mark the DB as being in the state as the last version in there.
450
+			// this is done to trigger maintenance mode and do data migration scripts
451
+			// if the admin installed this version of EE over 3.1.x or 4.0.x
452
+			// otherwise, the normal maintenance mode code is fine
453
+			$previous_versions_installed = array_keys($espresso_db_core_updates);
454
+			$previous_version_installed = end($previous_versions_installed);
455
+			if (version_compare('4.1.0', $previous_version_installed)) {
456
+				// last installed version was less than 4.1
457
+				// so we want the data migrations to happen. SO, we're going to say the DB is at that state
458
+				$db_state = array('Core' => $previous_version_installed);
459
+			} else {
460
+				$db_state = array('Core' => EVENT_ESPRESSO_VERSION);
461
+			}
462
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
463
+		}
464
+		// in 4.1, $db_state would have only been a simple string like '4.1.0',
465
+		// but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
466
+		// db, and possibly other keys for other addons like 'Calendar','Permissions',etc
467
+		if (! is_array($db_state)) {
468
+			$db_state = array('Core' => $db_state);
469
+			update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
470
+		}
471
+		return $db_state;
472
+	}
473
+
474
+	/**
475
+	 * Checks if there are any data migration scripts that ought to be run. If found,
476
+	 * returns the instantiated classes. If none are found (ie, they've all already been run
477
+	 * or they don't apply), returns an empty array
478
+	 *
479
+	 * @return EE_Data_Migration_Script_Base[]
480
+	 */
481
+	public function check_for_applicable_data_migration_scripts()
482
+	{
483
+		// get the option describing what options have already run
484
+		$scripts_ran = $this->get_data_migrations_ran();
485
+		// $scripts_ran = array('4.1.0.core'=>array('monkey'=>null));
486
+		$script_class_and_filepaths_available = $this->get_all_data_migration_scripts_available();
487
+
488
+
489
+		$current_database_state = $this->ensure_current_database_state_is_set();
490
+		// determine which have already been run
491
+		$script_classes_that_should_run_per_iteration = array();
492
+		$iteration = 0;
493
+		$next_database_state_to_consider = $current_database_state;
494
+		$theoretical_database_state = null;
495
+		do {
496
+			// the next state after the currently-considered one will start off looking the same as the current, but we may make additions...
497
+			$theoretical_database_state = $next_database_state_to_consider;
498
+			// the next db state to consider is "what would the DB be like had we run all the scripts we found that applied last time?)
499
+			foreach ($script_class_and_filepaths_available as $classname => $filepath) {
500
+				$migrates_to_version = $this->script_migrates_to_version($classname);
501
+				$script_converts_plugin_slug = $migrates_to_version['slug'];
502
+				$script_converts_to_version = $migrates_to_version['version'];
503
+				// check if this version script is DONE or not; or if it's never been ran
504
+				if (! $scripts_ran ||
505
+					! isset($scripts_ran[ $script_converts_plugin_slug ]) ||
506
+					! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])) {
507
+					// we haven't ran this conversion script before
508
+					// now check if it applies... note that we've added an autoloader for it on get_all_data_migration_scripts_available.
509
+					// Also, make sure we get a new one. It's possible this is being ran during a multisite migration,
510
+					// in which case we don't want to reuse a DMS script from a different blog!
511
+					$script = LoaderFactory::getLoader()->load($classname, [], false);
512
+					/* @var $script EE_Data_Migration_Script_Base */
513
+					$can_migrate = $script->can_migrate_from_version($theoretical_database_state);
514
+					if ($can_migrate) {
515
+						$script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
516
+						$migrates_to_version = $script->migrates_to_version();
517
+						$next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
518
+						unset($script_class_and_filepaths_available[ $classname ]);
519
+					}
520
+				} elseif ($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ] instanceof EE_Data_Migration_Script_Base) {
521
+					// this script has been ran, or at least started
522
+					$script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
523
+					if ($script->get_status() != self::status_completed) {
524
+						// this script is already underway... keep going with it
525
+						$script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
526
+						$migrates_to_version = $script->migrates_to_version();
527
+						$next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
528
+						unset($script_class_and_filepaths_available[ $classname ]);
529
+					} else {
530
+						// it must have a status that indicates it has finished, so we don't want to try and run it again
531
+					}
532
+				} else {
533
+					// it exists but it's not  a proper data migration script
534
+					// maybe the script got renamed? or was simply removed from EE?
535
+					// either way, its certainly not runnable!
536
+				}
537
+			}
538
+			$iteration++;
539
+		} while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
540
+		// ok we have all the scripts that should run, now let's make them into flat array
541
+		$scripts_that_should_run = array();
542
+		foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
543
+			ksort($scripts_at_priority);
544
+			foreach ($scripts_at_priority as $scripts) {
545
+				foreach ($scripts as $script) {
546
+					$scripts_that_should_run[ get_class($script) ] = $script;
547
+				}
548
+			}
549
+		}
550
+
551
+		do_action(
552
+			'AHEE__EE_Data_Migration_Manager__check_for_applicable_data_migration_scripts__scripts_that_should_run',
553
+			$scripts_that_should_run
554
+		);
555
+		return $scripts_that_should_run;
556
+	}
557
+
558
+
559
+	/**
560
+	 * Gets the script which is currently being ran, if there is one. If $include_completed_scripts is set to TRUE
561
+	 * it will return the last ran script even if its complete.
562
+	 * This means: if you want to find the currently-executing script, leave it as FALSE.
563
+	 * If you really just want to find the script which ran most recently, regardless of status, leave it as TRUE.
564
+	 *
565
+	 * @param bool $include_completed_scripts
566
+	 * @return EE_Data_Migration_Script_Base
567
+	 */
568
+	public function get_last_ran_script($include_completed_scripts = false)
569
+	{
570
+		// make sure we've setup the class properties _last_ran_script and _last_ran_incomplete_script
571
+		if (! $this->_data_migrations_ran) {
572
+			$this->get_data_migrations_ran();
573
+		}
574
+		if ($include_completed_scripts) {
575
+			return $this->_last_ran_script;
576
+		} else {
577
+			return $this->_last_ran_incomplete_script;
578
+		}
579
+	}
580
+
581
+
582
+	/**
583
+	 * Runs the data migration scripts (well, each request to this method calls one of the
584
+	 * data migration scripts' migration_step() functions).
585
+	 *
586
+	 * @param int   $step_size
587
+	 * @throws EE_Error
588
+	 * @return array {
589
+	 *                                  // where the first item is one EE_Data_Migration_Script_Base's stati,
590
+	 *                                  //and the second item is a string describing what was done
591
+	 * @type int    $records_to_migrate from the current migration script
592
+	 * @type int    $records_migrated
593
+	 * @type string $status             one of EE_Data_Migration_Manager::status_*
594
+	 * @type string $script             verbose name of the current DMS
595
+	 * @type string $message            string describing what was done during this step
596
+	 *                                  }
597
+	 */
598
+	public function migration_step($step_size = 0)
599
+	{
600
+
601
+		// bandaid fix for issue https://events.codebasehq.com/projects/event-espresso/tickets/7535
602
+		if (class_exists('EE_CPT_Strategy')) {
603
+			remove_action('pre_get_posts', array(EE_CPT_Strategy::instance(), 'pre_get_posts'), 5);
604
+		}
605
+
606
+		try {
607
+			$currently_executing_script = $this->get_last_ran_script();
608
+			if (! $currently_executing_script) {
609
+				// Find the next script that needs to execute
610
+				$scripts = $this->check_for_applicable_data_migration_scripts();
611
+				if (! $scripts) {
612
+					// huh, no more scripts to run... apparently we're done!
613
+					// but dont forget to make sure initial data is there
614
+					// we should be good to allow them to exit maintenance mode now
615
+					EE_Maintenance_Mode::instance()->set_maintenance_level(
616
+						intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
617
+					);
618
+					// saving migrations ran should actually be unnecessary, but leaving in place just in case
619
+					// remember this migration was finished (even if we timeout initing db for core and plugins)
620
+					$this->_save_migrations_ran();
621
+					// make sure DB was updated AFTER we've recorded the migration was done
622
+					$this->initialize_db_for_enqueued_ee_plugins();
623
+					return array(
624
+						'records_to_migrate' => 1,
625
+						'records_migrated'   => 1,
626
+						'status'             => self::status_no_more_migration_scripts,
627
+						'script'             => __("Data Migration Completed Successfully", "event_espresso"),
628
+						'message'            => __("All done!", "event_espresso"),
629
+					);
630
+				}
631
+				$currently_executing_script = array_shift($scripts);
632
+				// and add to the array/wp option showing the scripts ran
633
+
634
+				$migrates_to = $this->script_migrates_to_version(get_class($currently_executing_script));
635
+				$plugin_slug = $migrates_to['slug'];
636
+				$version = $migrates_to['version'];
637
+				$this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
638
+			}
639
+			$current_script_name = get_class($currently_executing_script);
640
+		} catch (Exception $e) {
641
+			// an exception occurred while trying to get migration scripts
642
+
643
+			$message = sprintf(
644
+				__("Error Message: %sStack Trace:%s", "event_espresso"),
645
+				$e->getMessage() . '<br>',
646
+				$e->getTraceAsString()
647
+			);
648
+			// record it on the array of data migration scripts ran. This will be overwritten next time we try and try to run data migrations
649
+			// but that's ok-- it's just an FYI to support that we couldn't even run any data migrations
650
+			$this->add_error_to_migrations_ran(
651
+				sprintf(__("Could not run data migrations because: %s", "event_espresso"), $message)
652
+			);
653
+			return array(
654
+				'records_to_migrate' => 1,
655
+				'records_migrated'   => 0,
656
+				'status'             => self::status_fatal_error,
657
+				'script'             => __("Error loading data migration scripts", "event_espresso"),
658
+				'message'            => $message,
659
+			);
660
+		}
661
+		// ok so we definitely have a data migration script
662
+		try {
663
+			// how big of a bite do we want to take? Allow users to easily override via their wp-config
664
+			if (absint($step_size) < 1) {
665
+				$step_size = defined('EE_MIGRATION_STEP_SIZE') && absint(EE_MIGRATION_STEP_SIZE)
666
+					? EE_MIGRATION_STEP_SIZE : EE_Data_Migration_Manager::step_size;
667
+			}
668
+			// do what we came to do!
669
+			$currently_executing_script->migration_step($step_size);
670
+			// can we wrap it up and verify default data?
671
+			$init_dbs = false;
672
+			switch ($currently_executing_script->get_status()) {
673
+				case EE_Data_Migration_Manager::status_continue:
674
+					$response_array = array(
675
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
676
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
677
+						'status'             => EE_Data_Migration_Manager::status_continue,
678
+						'message'            => $currently_executing_script->get_feedback_message(),
679
+						'script'             => $currently_executing_script->pretty_name(),
680
+					);
681
+					break;
682
+				case EE_Data_Migration_Manager::status_completed:
683
+					// ok so THAT script has completed
684
+					$this->update_current_database_state_to($this->script_migrates_to_version($current_script_name));
685
+					$response_array = array(
686
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
687
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
688
+						'status'             => EE_Data_Migration_Manager::status_completed,
689
+						'message'            => $currently_executing_script->get_feedback_message(),
690
+						'script'             => sprintf(
691
+							__("%s Completed", 'event_espresso'),
692
+							$currently_executing_script->pretty_name()
693
+						),
694
+					);
695
+					// check if there are any more after this one.
696
+					$scripts_remaining = $this->check_for_applicable_data_migration_scripts();
697
+					if (! $scripts_remaining) {
698
+						// we should be good to allow them to exit maintenance mode now
699
+						EE_Maintenance_Mode::instance()->set_maintenance_level(
700
+							intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
701
+						);
702
+						// huh, no more scripts to run... apparently we're done!
703
+						// but dont forget to make sure initial data is there
704
+						$init_dbs = true;
705
+						$response_array['status'] = self::status_no_more_migration_scripts;
706
+					}
707
+					break;
708
+				default:
709
+					$response_array = array(
710
+						'records_to_migrate' => $currently_executing_script->count_records_to_migrate(),
711
+						'records_migrated'   => $currently_executing_script->count_records_migrated(),
712
+						'status'             => $currently_executing_script->get_status(),
713
+						'message'            => sprintf(
714
+							__("Minor errors occurred during %s: %s", "event_espresso"),
715
+							$currently_executing_script->pretty_name(),
716
+							implode(", ", $currently_executing_script->get_errors())
717
+						),
718
+						'script'             => $currently_executing_script->pretty_name(),
719
+					);
720
+					break;
721
+			}
722
+		} catch (Exception $e) {
723
+			// ok so some exception was thrown which killed the data migration script
724
+			// double-check we have a real script
725
+			if ($currently_executing_script instanceof EE_Data_Migration_Script_Base) {
726
+				$script_name = $currently_executing_script->pretty_name();
727
+				$currently_executing_script->set_broken();
728
+				$currently_executing_script->add_error($e->getMessage());
729
+			} else {
730
+				$script_name = __("Error getting Migration Script", "event_espresso");
731
+			}
732
+			$response_array = array(
733
+				'records_to_migrate' => 1,
734
+				'records_migrated'   => 0,
735
+				'status'             => self::status_fatal_error,
736
+				'message'            => sprintf(
737
+					__("A fatal error occurred during the migration: %s", "event_espresso"),
738
+					$e->getMessage()
739
+				),
740
+				'script'             => $script_name,
741
+			);
742
+		}
743
+		$successful_save = $this->_save_migrations_ran();
744
+		if ($successful_save !== true) {
745
+			// ok so the current wp option didn't save. that's tricky, because we'd like to update it
746
+			// and mark it as having a fatal error, but remember- WE CAN'T SAVE THIS WP OPTION!
747
+			// however, if we throw an exception, and return that, then the next request
748
+			// won't have as much info in it, and it may be able to save
749
+			throw new EE_Error(
750
+				sprintf(
751
+					__(
752
+						"The error '%s' occurred updating the status of the migration. This is a FATAL ERROR, but the error is preventing the system from remembering that. Please contact event espresso support.",
753
+						"event_espresso"
754
+					),
755
+					$successful_save
756
+				)
757
+			);
758
+		}
759
+		// if we're all done, initialize EE plugins' default data etc.
760
+		if ($init_dbs) {
761
+			$this->initialize_db_for_enqueued_ee_plugins();
762
+		}
763
+		return $response_array;
764
+	}
765
+
766
+
767
+	/**
768
+	 * Echo out JSON response to migration script AJAX requests. Takes precautions
769
+	 * to buffer output so that we don't throw junk into our json.
770
+	 *
771
+	 * @return array with keys:
772
+	 * 'records_to_migrate' which counts ALL the records for the current migration, and should remain constant. (ie,
773
+	 * it's NOT the count of hwo many remain)
774
+	 * 'records_migrated' which also counts ALL the records which have been migrated (ie, percent_complete =
775
+	 * records_migrated/records_to_migrate)
776
+	 * 'status'=>a string, one of EE_Data_migration_Manager::status_*
777
+	 * 'message'=>a string, containing any message you want to show to the user. We may decide to split this up into
778
+	 * errors, notifications, and successes
779
+	 * 'script'=>a pretty name of the script currently running
780
+	 */
781
+	public function response_to_migration_ajax_request()
782
+	{
783
+		ob_start();
784
+		try {
785
+			$response = $this->migration_step();
786
+		} catch (Exception $e) {
787
+			$response = array(
788
+				'records_to_migrate' => 0,
789
+				'records_migrated'   => 0,
790
+				'status'             => EE_Data_Migration_Manager::status_fatal_error,
791
+				'message'            => sprintf(
792
+					__("Unknown fatal error occurred: %s", "event_espresso"),
793
+					$e->getMessage()
794
+				),
795
+				'script'             => 'Unknown',
796
+			);
797
+			$this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
798
+		}
799
+		$warnings_etc = @ob_get_contents();
800
+		ob_end_clean();
801
+		$response['message'] .= $warnings_etc;
802
+		return $response;
803
+	}
804
+
805
+	/**
806
+	 * Updates the wordpress option that keeps track of which which EE version the database
807
+	 * is at (ie, the code may be at 4.1.0, but the database is still at 3.1.35)
808
+	 *
809
+	 * @param array $slug_and_version {
810
+	 * @type string $slug             like 'Core' or 'Calendar',
811
+	 * @type string $version          like '4.1.0'
812
+	 *                                }
813
+	 * @return void
814
+	 */
815
+	public function update_current_database_state_to($slug_and_version = null)
816
+	{
817
+		if (! $slug_and_version) {
818
+			// no version was provided, assume it should be at the current code version
819
+			$slug_and_version = array('slug' => 'Core', 'version' => espresso_version());
820
+		}
821
+		$current_database_state = get_option(self::current_database_state);
822
+		$current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
823
+		update_option(self::current_database_state, $current_database_state);
824
+	}
825
+
826
+	/**
827
+	 * Determines if the database is currently at a state matching what's indicated in $slug and $version.
828
+	 *
829
+	 * @param array $slug_and_version {
830
+	 * @type string $slug             like 'Core' or 'Calendar',
831
+	 * @type string $version          like '4.1.0'
832
+	 *                                }
833
+	 * @return boolean
834
+	 */
835
+	public function database_needs_updating_to($slug_and_version)
836
+	{
837
+
838
+		$slug = $slug_and_version['slug'];
839
+		$version = $slug_and_version['version'];
840
+		$current_database_state = get_option(self::current_database_state);
841
+		if (! isset($current_database_state[ $slug ])) {
842
+			return true;
843
+		} else {
844
+			// just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
845
+			$version_parts_current_db_state = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
846
+			$version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
847
+			$needs_updating = false;
848
+			foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
849
+				if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
850
+					$needs_updating = true;
851
+					break;
852
+				}
853
+			}
854
+			return $needs_updating;
855
+		}
856
+	}
857
+
858
+
859
+	/**
860
+	 * Gets all the data migration scripts available in the core folder and folders
861
+	 * in addons. Has the side effect of adding them for autoloading
862
+	 *
863
+	 * @return array keys are expected classnames, values are their filepaths
864
+	 * @throws InvalidInterfaceException
865
+	 * @throws InvalidDataTypeException
866
+	 * @throws EE_Error
867
+	 * @throws InvalidArgumentException
868
+	 */
869
+	public function get_all_data_migration_scripts_available()
870
+	{
871
+		if (! $this->_data_migration_class_to_filepath_map) {
872
+			$this->_data_migration_class_to_filepath_map = array();
873
+			foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
874
+				// strip any placeholders added to classname to make it a unique array key
875
+				$eeAddonClass = trim($eeAddonClass, '*');
876
+				$eeAddonClass = $eeAddonClass === 'Core' || class_exists($eeAddonClass)
877
+					? $eeAddonClass
878
+					: '';
879
+				$folder_path = EEH_File::end_with_directory_separator($folder_path);
880
+				$files = glob($folder_path . '*.dms.php');
881
+				if (empty($files)) {
882
+					continue;
883
+				}
884
+				foreach ($files as $file) {
885
+					$pos_of_last_slash = strrpos($file, '/');
886
+					$classname = str_replace('.dms.php', '', substr($file, $pos_of_last_slash + 1));
887
+					$migrates_to = $this->script_migrates_to_version($classname, $eeAddonClass);
888
+					$slug = $migrates_to['slug'];
889
+					// check that the slug as contained in the DMS is associated with
890
+					// the slug of an addon or core
891
+					if ($slug !== 'Core' && EE_Registry::instance()->get_addon_by_name($slug) === null) {
892
+						EE_Error::doing_it_wrong(
893
+							__FUNCTION__,
894
+							sprintf(
895
+								esc_html__(
896
+									'The data migration script "%s" migrates the "%s" data, but there is no EE addon with that name. There is only: %s. ',
897
+									'event_espresso'
898
+								),
899
+								$classname,
900
+								$slug,
901
+								implode(', ', array_keys(EE_Registry::instance()->get_addons_by_name()))
902
+							),
903
+							'4.3.0.alpha.019'
904
+						);
905
+					}
906
+					$this->_data_migration_class_to_filepath_map[ $classname ] = $file;
907
+				}
908
+			}
909
+			EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
910
+		}
911
+		return $this->_data_migration_class_to_filepath_map;
912
+	}
913
+
914
+
915
+	/**
916
+	 * Once we have an addon that works with EE4.1, we will actually want to fetch the PUE slugs
917
+	 * from each addon, and check if they need updating,
918
+	 *
919
+	 * @return boolean
920
+	 */
921
+	public function addons_need_updating()
922
+	{
923
+		return false;
924
+	}
925
+
926
+	/**
927
+	 * Adds this error string to the data_migrations_ran array, but we dont necessarily know
928
+	 * where to put it, so we just throw it in there... better than nothing...
929
+	 *
930
+	 * @param string $error_message
931
+	 * @throws EE_Error
932
+	 */
933
+	public function add_error_to_migrations_ran($error_message)
934
+	{
935
+		// get last-ran migration script
936
+		global $wpdb;
937
+		$last_migration_script_option = $wpdb->get_row(
938
+			"SELECT * FROM $wpdb->options WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id DESC LIMIT 1",
939
+			ARRAY_A
940
+		);
941
+
942
+		$last_ran_migration_script_properties = isset($last_migration_script_option['option_value'])
943
+			? maybe_unserialize($last_migration_script_option['option_value']) : null;
944
+		// now, tread lightly because we're here because a FATAL non-catchable error
945
+		// was thrown last time when we were trying to run a data migration script
946
+		// so the fatal error could have happened while getting the migration script
947
+		// or doing running it...
948
+		$versions_migrated_to = isset($last_migration_script_option['option_name']) ? str_replace(
949
+			EE_Data_Migration_Manager::data_migration_script_option_prefix,
950
+			"",
951
+			$last_migration_script_option['option_name']
952
+		) : null;
953
+
954
+		// check if it THINKS its a data migration script and especially if it's one that HASN'T finished yet
955
+		// because if it has finished, then it obviously couldn't be the cause of this error, right? (because its all done)
956
+		if (isset($last_ran_migration_script_properties['class']) && isset($last_ran_migration_script_properties['_status']) && $last_ran_migration_script_properties['_status'] != self::status_completed) {
957
+			// ok then just add this error to its list of errors
958
+			$last_ran_migration_script_properties['_errors'][] = $error_message;
959
+			$last_ran_migration_script_properties['_status'] = self::status_fatal_error;
960
+		} else {
961
+			// so we don't even know which script was last running
962
+			// use the data migration error stub, which is designed specifically for this type of thing
963
+			$general_migration_error = new EE_DMS_Unknown_1_0_0();
964
+			$general_migration_error->add_error($error_message);
965
+			$general_migration_error->set_broken();
966
+			$last_ran_migration_script_properties = $general_migration_error->properties_as_array();
967
+			$versions_migrated_to = 'Unknown.1.0.0';
968
+			// now just to make sure appears as last (in case the were previously a fatal error like this)
969
+			// delete the old one
970
+			delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
971
+		}
972
+		update_option(
973
+			self::data_migration_script_option_prefix . $versions_migrated_to,
974
+			$last_ran_migration_script_properties
975
+		);
976
+	}
977
+
978
+	/**
979
+	 * saves what data migrations have ran to the database
980
+	 *
981
+	 * @return mixed TRUE if successfully saved migrations ran, string if an error occurred
982
+	 */
983
+	protected function _save_migrations_ran()
984
+	{
985
+		if ($this->_data_migrations_ran == null) {
986
+			$this->get_data_migrations_ran();
987
+		}
988
+		// now, we don't want to save actual classes to the DB because that's messy
989
+		$successful_updates = true;
990
+		foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
991
+			foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
992
+				$plugin_slug_for_use_in_option_name = $plugin_slug . ".";
993
+				$option_name = self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
994
+				$old_option_value = get_option($option_name);
995
+				if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
996
+					$script_array_for_saving = $array_or_migration_obj->properties_as_array();
997
+					if ($old_option_value != $script_array_for_saving) {
998
+						$successful_updates = update_option($option_name, $script_array_for_saving);
999
+					}
1000
+				} else {// we don't know what this array-thing is. So just save it as-is
1001
+					if ($old_option_value != $array_or_migration_obj) {
1002
+						$successful_updates = update_option($option_name, $array_or_migration_obj);
1003
+					}
1004
+				}
1005
+				if (! $successful_updates) {
1006
+					global $wpdb;
1007
+					return $wpdb->last_error;
1008
+				}
1009
+			}
1010
+		}
1011
+		return true;
1012
+		// $updated = update_option(self::data_migrations_option_name, $array_of_migrations);
1013
+		// if ($updated !== true) {
1014
+		//     global $wpdb;
1015
+		//     return $wpdb->last_error;
1016
+		// } else {
1017
+		//     return true;
1018
+		// }
1019
+		// wp_mail(
1020
+		//     "[email protected]",
1021
+		//     time() . " price debug info",
1022
+		//     "updated: $updated, last error: $last_error, byte length of option: " . strlen(
1023
+		//         serialize($array_of_migrations)
1024
+		//     )
1025
+		// );
1026
+	}
1027
+
1028
+	/**
1029
+	 * Takes an array of data migration script properties and re-creates the class from
1030
+	 * them. The argument $properties_array is assumed to have been made by
1031
+	 * EE_Data_Migration_Script_Base::properties_as_array()
1032
+	 *
1033
+	 * @param array $properties_array
1034
+	 * @return EE_Data_Migration_Script_Base
1035
+	 * @throws EE_Error
1036
+	 */
1037
+	public function _instantiate_script_from_properties_array($properties_array)
1038
+	{
1039
+		if (! isset($properties_array['class'])) {
1040
+			throw new EE_Error(
1041
+				sprintf(
1042
+					__("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
1043
+					implode(",", $properties_array)
1044
+				)
1045
+			);
1046
+		}
1047
+		$class_name = $properties_array['class'];
1048
+		if (! class_exists($class_name)) {
1049
+			throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"), $class_name));
1050
+		}
1051
+		$class = new $class_name;
1052
+		if (! $class instanceof EE_Data_Migration_Script_Base) {
1053
+			throw new EE_Error(
1054
+				sprintf(
1055
+					__("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"),
1056
+					$class_name,
1057
+					get_class($class)
1058
+				)
1059
+			);
1060
+		}
1061
+		$class->instantiate_from_array_of_properties($properties_array);
1062
+		return $class;
1063
+	}
1064
+
1065
+	/**
1066
+	 * Gets the classname for the most up-to-date DMS (ie, the one that will finally
1067
+	 * leave the DB in a state usable by the current plugin code).
1068
+	 *
1069
+	 * @param string $plugin_slug the slug for the ee plugin we are searching for. Default is 'Core'
1070
+	 * @return string
1071
+	 */
1072
+	public function get_most_up_to_date_dms($plugin_slug = 'Core')
1073
+	{
1074
+		$class_to_filepath_map = $this->get_all_data_migration_scripts_available();
1075
+		$most_up_to_date_dms_classname = null;
1076
+		foreach ($class_to_filepath_map as $classname => $filepath) {
1077
+			if ($most_up_to_date_dms_classname === null) {
1078
+				$migrates_to = $this->script_migrates_to_version($classname);
1079
+				$this_plugin_slug = $migrates_to['slug'];
1080
+				if ($this_plugin_slug == $plugin_slug) {
1081
+					// if it's for core, it wins
1082
+					$most_up_to_date_dms_classname = $classname;
1083
+				}
1084
+				// if it wasn't for core, we must keep searching for one that is!
1085
+				continue;
1086
+			} else {
1087
+				$champion_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms_classname);
1088
+				$contender_migrates_to = $this->script_migrates_to_version($classname);
1089
+				if ($contender_migrates_to['slug'] == $plugin_slug
1090
+					&& version_compare(
1091
+						$champion_migrates_to['version'],
1092
+						$contender_migrates_to['version'],
1093
+						'<'
1094
+					)) {
1095
+					// so the contenders version is higher and its for Core
1096
+					$most_up_to_date_dms_classname = $classname;
1097
+				}
1098
+			}
1099
+		}
1100
+		return $most_up_to_date_dms_classname;
1101
+	}
1102
+
1103
+	/**
1104
+	 * Gets the migration script specified but ONLY if it has already ran.
1105
+	 *
1106
+	 * Eg, if you wanted to see if 'EE_DMS_Core_4_1_0' has ran, you would run the following code:
1107
+	 * <code> $core_4_1_0_dms_ran = EE_Data_Migration_Manager::instance()->get_migration_ran( '4.1.0', 'Core' ) !==
1108
+	 * NULL;</code> This is especially useful in addons' data migration scripts, this way they can tell if a core (or
1109
+	 * other addon) DMS has ran, in case the current DMS depends on it.
1110
+	 *
1111
+	 * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1112
+	 *                            period. Eg '4.1.0'
1113
+	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1114
+	 * @return EE_Data_Migration_Script_Base
1115
+	 */
1116
+	public function get_migration_ran($version, $plugin_slug = 'Core')
1117
+	{
1118
+		$migrations_ran = $this->get_data_migrations_ran();
1119
+		if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1120
+			return $migrations_ran[ $plugin_slug ][ $version ];
1121
+		} else {
1122
+			return null;
1123
+		}
1124
+	}
1125
+
1126
+	/**
1127
+	 * Resets the borked data migration scripts so they're no longer borked
1128
+	 * so we can again attempt to migrate
1129
+	 *
1130
+	 * @return bool
1131
+	 * @throws EE_Error
1132
+	 */
1133
+	public function reattempt()
1134
+	{
1135
+		// find if the last-ran script was borked
1136
+		// set it as being non-borked (we shouldn't ever get DMSs that we don't recognize)
1137
+		// add an 'error' saying that we attempted to reset
1138
+		// does it have a stage that was borked too? if so make it no longer borked
1139
+		// add an 'error' saying we attempted to reset
1140
+		$last_ran_script = $this->get_last_ran_script();
1141
+		if ($last_ran_script instanceof EE_DMS_Unknown_1_0_0) {
1142
+			// if it was an error DMS, just mark it as complete (if another error occurs it will overwrite it)
1143
+			$last_ran_script->set_completed();
1144
+		} elseif ($last_ran_script instanceof EE_Data_Migration_Script_Base) {
1145
+			$last_ran_script->reattempt();
1146
+		} else {
1147
+			throw new EE_Error(
1148
+				sprintf(
1149
+					__(
1150
+						'Unable to reattempt the last ran migration script because it was not a valid migration script. || It was %s',
1151
+						'event_espresso'
1152
+					),
1153
+					print_r($last_ran_script, true)
1154
+				)
1155
+			);
1156
+		}
1157
+		return $this->_save_migrations_ran();
1158
+	}
1159
+
1160
+	/**
1161
+	 * Gets whether or not this particular migration has run or not
1162
+	 *
1163
+	 * @param string $version     the version the DMS searched for migrates to. Usually just the content before the 3rd
1164
+	 *                            period. Eg '4.1.0'
1165
+	 * @param string $plugin_slug like 'Core', 'Mailchimp', 'Calendar', etc
1166
+	 * @return boolean
1167
+	 */
1168
+	public function migration_has_ran($version, $plugin_slug = 'Core')
1169
+	{
1170
+		return $this->get_migration_ran($version, $plugin_slug) !== null;
1171
+	}
1172
+
1173
+	/**
1174
+	 * Enqueues this ee plugin to have its data initialized
1175
+	 *
1176
+	 * @param string $plugin_slug either 'Core' or EE_Addon::name()'s return value
1177
+	 */
1178
+	public function enqueue_db_initialization_for($plugin_slug)
1179
+	{
1180
+		$queue = $this->get_db_initialization_queue();
1181
+		if (! in_array($plugin_slug, $queue)) {
1182
+			$queue[] = $plugin_slug;
1183
+		}
1184
+		update_option(self::db_init_queue_option_name, $queue);
1185
+	}
1186
+
1187
+	/**
1188
+	 * Calls EE_Addon::initialize_db_if_no_migrations_required() on each addon
1189
+	 * specified in EE_Data_Migration_Manager::get_db_init_queue(), and if 'Core' is
1190
+	 * in the queue, calls EE_System::initialize_db_if_no_migrations_required().
1191
+	 */
1192
+	public function initialize_db_for_enqueued_ee_plugins()
1193
+	{
1194
+		$queue = $this->get_db_initialization_queue();
1195
+		foreach ($queue as $plugin_slug) {
1196
+			$most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1197
+			if (! $most_up_to_date_dms) {
1198
+				// if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1199
+				$verify_db = false;
1200
+			} else {
1201
+				$most_up_to_date_dms_migrates_to = $this->script_migrates_to_version($most_up_to_date_dms);
1202
+				$verify_db = $this->database_needs_updating_to($most_up_to_date_dms_migrates_to);
1203
+			}
1204
+			if ($plugin_slug == 'Core') {
1205
+				EE_System::instance()->initialize_db_if_no_migrations_required(
1206
+					false,
1207
+					$verify_db
1208
+				);
1209
+			} else {
1210
+				// just loop through the addons to make sure their database is setup
1211
+				foreach (EE_Registry::instance()->addons as $addon) {
1212
+					if ($addon->name() == $plugin_slug) {
1213
+						$addon->initialize_db_if_no_migrations_required($verify_db);
1214
+						break;
1215
+					}
1216
+				}
1217
+			}
1218
+		}
1219
+		// because we just initialized the DBs for the enqueued ee plugins
1220
+		// we don't need to keep remembering which ones needed to be initialized
1221
+		delete_option(self::db_init_queue_option_name);
1222
+	}
1223
+
1224
+	/**
1225
+	 * Gets a numerically-indexed array of plugin slugs that need to have their databases
1226
+	 * (re-)initialized after migrations are complete. ie, each element should be either
1227
+	 * 'Core', or the return value of EE_Addon::name() for an addon
1228
+	 *
1229
+	 * @return array
1230
+	 */
1231
+	public function get_db_initialization_queue()
1232
+	{
1233
+		return get_option(self::db_init_queue_option_name, array());
1234
+	}
1235
+
1236
+	/**
1237
+	 * Gets the injected table analyzer, or throws an exception
1238
+	 *
1239
+	 * @return TableAnalysis
1240
+	 * @throws EE_Error
1241
+	 */
1242
+	protected function _get_table_analysis()
1243
+	{
1244
+		if ($this->_table_analysis instanceof TableAnalysis) {
1245
+			return $this->_table_analysis;
1246
+		} else {
1247
+			throw new EE_Error(
1248
+				sprintf(
1249
+					__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
1250
+					get_class($this)
1251
+				)
1252
+			);
1253
+		}
1254
+	}
1255
+
1256
+	/**
1257
+	 * Gets the injected table manager, or throws an exception
1258
+	 *
1259
+	 * @return TableManager
1260
+	 * @throws EE_Error
1261
+	 */
1262
+	protected function _get_table_manager()
1263
+	{
1264
+		if ($this->_table_manager instanceof TableManager) {
1265
+			return $this->_table_manager;
1266
+		} else {
1267
+			throw new EE_Error(
1268
+				sprintf(
1269
+					__('Table manager class on class %1$s is not set properly.', 'event_espresso'),
1270
+					get_class($this)
1271
+				)
1272
+			);
1273
+		}
1274
+	}
1275 1275
 }
Please login to merge, or discard this patch.
Spacing   +61 added lines, -61 removed lines patch added patch discarded remove patch
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
     public static function instance()
159 159
     {
160 160
         // check if class object is instantiated
161
-        if (! self::$_instance instanceof EE_Data_Migration_Manager) {
161
+        if ( ! self::$_instance instanceof EE_Data_Migration_Manager) {
162 162
             self::$_instance = new self();
163 163
         }
164 164
         return self::$_instance;
@@ -234,12 +234,12 @@  discard block
 block discarded – undo
234 234
 
235 235
         if (count($parts) == 4) {
236 236
             // it's 4.2-style.eg Core.4.1.0
237
-            $plugin_slug = $parts[0];// eg Core
238
-            $version_string = $parts[1] . "." . $parts[2] . "." . $parts[3]; // eg 4.1.0
237
+            $plugin_slug = $parts[0]; // eg Core
238
+            $version_string = $parts[1].".".$parts[2].".".$parts[3]; // eg 4.1.0
239 239
         } else {
240 240
             // it's 4.1-style: eg 4.1.0
241 241
             $plugin_slug = 'Core';
242
-            $version_string = $plugin_slug_and_version_string;// eg 4.1.0
242
+            $version_string = $plugin_slug_and_version_string; // eg 4.1.0
243 243
         }
244 244
         return array($plugin_slug, $version_string);
245 245
     }
@@ -294,11 +294,11 @@  discard block
 block discarded – undo
294 294
      */
295 295
     public function get_data_migrations_ran()
296 296
     {
297
-        if (! $this->_data_migrations_ran) {
297
+        if ( ! $this->_data_migrations_ran) {
298 298
             // setup autoloaders for each of the scripts in there
299 299
             $this->get_all_data_migration_scripts_available();
300 300
             $data_migrations_options = $this->get_all_migration_script_options(
301
-            );// get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
301
+            ); // get_option(EE_Data_Migration_Manager::data_migrations_option_name,get_option('espresso_data_migrations',array()));
302 302
 
303 303
             $data_migrations_ran = array();
304 304
             // convert into data migration script classes where possible
@@ -312,23 +312,23 @@  discard block
 block discarded – undo
312 312
                         $data_migration_option['option_name'],
313 313
                         $data_migration_option['option_value']
314 314
                     );
315
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = $class;
315
+                    $data_migrations_ran[$plugin_slug][$version_string] = $class;
316 316
                     // ok so far THIS is the 'last-ran-script'... unless we find another on next iteration
317 317
                     $this->_last_ran_script = $class;
318
-                    if (! $class->is_completed()) {
318
+                    if ( ! $class->is_completed()) {
319 319
                         // sometimes we also like to know which was the last incomplete script (or if there are any at all)
320 320
                         $this->_last_ran_incomplete_script = $class;
321 321
                     }
322 322
                 } catch (EE_Error $e) {
323 323
                     // ok so its not a DMS. We'll just keep it, although other code will need to expect non-DMSs
324
-                    $data_migrations_ran[ $plugin_slug ][ $version_string ] = maybe_unserialize(
324
+                    $data_migrations_ran[$plugin_slug][$version_string] = maybe_unserialize(
325 325
                         $data_migration_option['option_value']
326 326
                     );
327 327
                 }
328 328
             }
329 329
             // so here the array of $data_migrations_ran is actually a mix of classes and a few legacy arrays
330 330
             $this->_data_migrations_ran = $data_migrations_ran;
331
-            if (! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
331
+            if ( ! $this->_data_migrations_ran || ! is_array($this->_data_migrations_ran)) {
332 332
                 $this->_data_migrations_ran = array();
333 333
             }
334 334
         }
@@ -361,7 +361,7 @@  discard block
 block discarded – undo
361 361
     {
362 362
         global $wpdb;
363 363
         return $wpdb->get_results(
364
-            "SELECT * FROM {$wpdb->options} WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id ASC",
364
+            "SELECT * FROM {$wpdb->options} WHERE option_name like '".EE_Data_Migration_Manager::data_migration_script_option_prefix."%' ORDER BY option_id ASC",
365 365
             ARRAY_A
366 366
         );
367 367
     }
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
     {
377 377
         return apply_filters(
378 378
             'FHEE__EE_Data_Migration_Manager__get_data_migration_script_folders',
379
-            array('Core' => EE_CORE . 'data_migration_scripts')
379
+            array('Core' => EE_CORE.'data_migration_scripts')
380 380
         );
381 381
     }
382 382
 
@@ -392,15 +392,15 @@  discard block
 block discarded – undo
392 392
      */
393 393
     public function script_migrates_to_version($migration_script_name, $eeAddonClass = '')
394 394
     {
395
-        if (isset($this->script_migration_versions[ $migration_script_name ])) {
396
-            return $this->script_migration_versions[ $migration_script_name ];
395
+        if (isset($this->script_migration_versions[$migration_script_name])) {
396
+            return $this->script_migration_versions[$migration_script_name];
397 397
         }
398 398
         $dms_info = $this->parse_dms_classname($migration_script_name);
399
-        $this->script_migration_versions[ $migration_script_name ] = array(
399
+        $this->script_migration_versions[$migration_script_name] = array(
400 400
             'slug'    => $eeAddonClass !== '' ? $eeAddonClass : $dms_info['slug'],
401
-            'version' => $dms_info['major_version'] . "." . $dms_info['minor_version'] . "." . $dms_info['micro_version'],
401
+            'version' => $dms_info['major_version'].".".$dms_info['minor_version'].".".$dms_info['micro_version'],
402 402
         );
403
-        return $this->script_migration_versions[ $migration_script_name ];
403
+        return $this->script_migration_versions[$migration_script_name];
404 404
     }
405 405
 
406 406
     /**
@@ -414,7 +414,7 @@  discard block
 block discarded – undo
414 414
     {
415 415
         $matches = array();
416 416
         preg_match('~EE_DMS_(.*)_([0-9]*)_([0-9]*)_([0-9]*)~', $classname, $matches);
417
-        if (! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
417
+        if ( ! $matches || ! (isset($matches[1]) && isset($matches[2]) && isset($matches[3]))) {
418 418
             throw new EE_Error(
419 419
                 sprintf(
420 420
                     __(
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
     {
446 446
         $espresso_db_core_updates = get_option('espresso_db_update', array());
447 447
         $db_state = get_option(EE_Data_Migration_Manager::current_database_state);
448
-        if (! $db_state) {
448
+        if ( ! $db_state) {
449 449
             // mark the DB as being in the state as the last version in there.
450 450
             // this is done to trigger maintenance mode and do data migration scripts
451 451
             // if the admin installed this version of EE over 3.1.x or 4.0.x
@@ -464,7 +464,7 @@  discard block
 block discarded – undo
464 464
         // in 4.1, $db_state would have only been a simple string like '4.1.0',
465 465
         // but in 4.2+ it should be an array with at least key 'Core' and the value of that plugin's
466 466
         // db, and possibly other keys for other addons like 'Calendar','Permissions',etc
467
-        if (! is_array($db_state)) {
467
+        if ( ! is_array($db_state)) {
468 468
             $db_state = array('Core' => $db_state);
469 469
             update_option(EE_Data_Migration_Manager::current_database_state, $db_state);
470 470
         }
@@ -501,9 +501,9 @@  discard block
 block discarded – undo
501 501
                 $script_converts_plugin_slug = $migrates_to_version['slug'];
502 502
                 $script_converts_to_version = $migrates_to_version['version'];
503 503
                 // check if this version script is DONE or not; or if it's never been ran
504
-                if (! $scripts_ran ||
505
-                    ! isset($scripts_ran[ $script_converts_plugin_slug ]) ||
506
-                    ! isset($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ])) {
504
+                if ( ! $scripts_ran ||
505
+                    ! isset($scripts_ran[$script_converts_plugin_slug]) ||
506
+                    ! isset($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version])) {
507 507
                     // we haven't ran this conversion script before
508 508
                     // now check if it applies... note that we've added an autoloader for it on get_all_data_migration_scripts_available.
509 509
                     // Also, make sure we get a new one. It's possible this is being ran during a multisite migration,
@@ -512,20 +512,20 @@  discard block
 block discarded – undo
512 512
                     /* @var $script EE_Data_Migration_Script_Base */
513 513
                     $can_migrate = $script->can_migrate_from_version($theoretical_database_state);
514 514
                     if ($can_migrate) {
515
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
515
+                        $script_classes_that_should_run_per_iteration[$iteration][$script->priority()][] = $script;
516 516
                         $migrates_to_version = $script->migrates_to_version();
517
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
518
-                        unset($script_class_and_filepaths_available[ $classname ]);
517
+                        $next_database_state_to_consider[$migrates_to_version['slug']] = $migrates_to_version['version'];
518
+                        unset($script_class_and_filepaths_available[$classname]);
519 519
                     }
520
-                } elseif ($scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ] instanceof EE_Data_Migration_Script_Base) {
520
+                } elseif ($scripts_ran[$script_converts_plugin_slug][$script_converts_to_version] instanceof EE_Data_Migration_Script_Base) {
521 521
                     // this script has been ran, or at least started
522
-                    $script = $scripts_ran[ $script_converts_plugin_slug ][ $script_converts_to_version ];
522
+                    $script = $scripts_ran[$script_converts_plugin_slug][$script_converts_to_version];
523 523
                     if ($script->get_status() != self::status_completed) {
524 524
                         // this script is already underway... keep going with it
525
-                        $script_classes_that_should_run_per_iteration[ $iteration ][ $script->priority() ][] = $script;
525
+                        $script_classes_that_should_run_per_iteration[$iteration][$script->priority()][] = $script;
526 526
                         $migrates_to_version = $script->migrates_to_version();
527
-                        $next_database_state_to_consider[ $migrates_to_version['slug'] ] = $migrates_to_version['version'];
528
-                        unset($script_class_and_filepaths_available[ $classname ]);
527
+                        $next_database_state_to_consider[$migrates_to_version['slug']] = $migrates_to_version['version'];
528
+                        unset($script_class_and_filepaths_available[$classname]);
529 529
                     } else {
530 530
                         // it must have a status that indicates it has finished, so we don't want to try and run it again
531 531
                     }
@@ -536,14 +536,14 @@  discard block
 block discarded – undo
536 536
                 }
537 537
             }
538 538
             $iteration++;
539
-        } while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
539
+        }while ($next_database_state_to_consider != $theoretical_database_state && $iteration < 6);
540 540
         // ok we have all the scripts that should run, now let's make them into flat array
541 541
         $scripts_that_should_run = array();
542 542
         foreach ($script_classes_that_should_run_per_iteration as $scripts_at_priority) {
543 543
             ksort($scripts_at_priority);
544 544
             foreach ($scripts_at_priority as $scripts) {
545 545
                 foreach ($scripts as $script) {
546
-                    $scripts_that_should_run[ get_class($script) ] = $script;
546
+                    $scripts_that_should_run[get_class($script)] = $script;
547 547
                 }
548 548
             }
549 549
         }
@@ -568,7 +568,7 @@  discard block
 block discarded – undo
568 568
     public function get_last_ran_script($include_completed_scripts = false)
569 569
     {
570 570
         // make sure we've setup the class properties _last_ran_script and _last_ran_incomplete_script
571
-        if (! $this->_data_migrations_ran) {
571
+        if ( ! $this->_data_migrations_ran) {
572 572
             $this->get_data_migrations_ran();
573 573
         }
574 574
         if ($include_completed_scripts) {
@@ -605,10 +605,10 @@  discard block
 block discarded – undo
605 605
 
606 606
         try {
607 607
             $currently_executing_script = $this->get_last_ran_script();
608
-            if (! $currently_executing_script) {
608
+            if ( ! $currently_executing_script) {
609 609
                 // Find the next script that needs to execute
610 610
                 $scripts = $this->check_for_applicable_data_migration_scripts();
611
-                if (! $scripts) {
611
+                if ( ! $scripts) {
612 612
                     // huh, no more scripts to run... apparently we're done!
613 613
                     // but dont forget to make sure initial data is there
614 614
                     // we should be good to allow them to exit maintenance mode now
@@ -634,7 +634,7 @@  discard block
 block discarded – undo
634 634
                 $migrates_to = $this->script_migrates_to_version(get_class($currently_executing_script));
635 635
                 $plugin_slug = $migrates_to['slug'];
636 636
                 $version = $migrates_to['version'];
637
-                $this->_data_migrations_ran[ $plugin_slug ][ $version ] = $currently_executing_script;
637
+                $this->_data_migrations_ran[$plugin_slug][$version] = $currently_executing_script;
638 638
             }
639 639
             $current_script_name = get_class($currently_executing_script);
640 640
         } catch (Exception $e) {
@@ -642,7 +642,7 @@  discard block
 block discarded – undo
642 642
 
643 643
             $message = sprintf(
644 644
                 __("Error Message: %sStack Trace:%s", "event_espresso"),
645
-                $e->getMessage() . '<br>',
645
+                $e->getMessage().'<br>',
646 646
                 $e->getTraceAsString()
647 647
             );
648 648
             // record it on the array of data migration scripts ran. This will be overwritten next time we try and try to run data migrations
@@ -694,7 +694,7 @@  discard block
 block discarded – undo
694 694
                     );
695 695
                     // check if there are any more after this one.
696 696
                     $scripts_remaining = $this->check_for_applicable_data_migration_scripts();
697
-                    if (! $scripts_remaining) {
697
+                    if ( ! $scripts_remaining) {
698 698
                         // we should be good to allow them to exit maintenance mode now
699 699
                         EE_Maintenance_Mode::instance()->set_maintenance_level(
700 700
                             intval(EE_Maintenance_Mode::level_0_not_in_maintenance)
@@ -794,7 +794,7 @@  discard block
 block discarded – undo
794 794
                 ),
795 795
                 'script'             => 'Unknown',
796 796
             );
797
-            $this->add_error_to_migrations_ran($e->getMessage() . "; Stack trace:" . $e->getTraceAsString());
797
+            $this->add_error_to_migrations_ran($e->getMessage()."; Stack trace:".$e->getTraceAsString());
798 798
         }
799 799
         $warnings_etc = @ob_get_contents();
800 800
         ob_end_clean();
@@ -814,12 +814,12 @@  discard block
 block discarded – undo
814 814
      */
815 815
     public function update_current_database_state_to($slug_and_version = null)
816 816
     {
817
-        if (! $slug_and_version) {
817
+        if ( ! $slug_and_version) {
818 818
             // no version was provided, assume it should be at the current code version
819 819
             $slug_and_version = array('slug' => 'Core', 'version' => espresso_version());
820 820
         }
821 821
         $current_database_state = get_option(self::current_database_state);
822
-        $current_database_state[ $slug_and_version['slug'] ] = $slug_and_version['version'];
822
+        $current_database_state[$slug_and_version['slug']] = $slug_and_version['version'];
823 823
         update_option(self::current_database_state, $current_database_state);
824 824
     }
825 825
 
@@ -838,15 +838,15 @@  discard block
 block discarded – undo
838 838
         $slug = $slug_and_version['slug'];
839 839
         $version = $slug_and_version['version'];
840 840
         $current_database_state = get_option(self::current_database_state);
841
-        if (! isset($current_database_state[ $slug ])) {
841
+        if ( ! isset($current_database_state[$slug])) {
842 842
             return true;
843 843
         } else {
844 844
             // just compare the first 3 parts of version string, eg "4.7.1", not "4.7.1.dev.032" because DBs shouldn't change on nano version changes
845
-            $version_parts_current_db_state = array_slice(explode('.', $current_database_state[ $slug ]), 0, 3);
845
+            $version_parts_current_db_state = array_slice(explode('.', $current_database_state[$slug]), 0, 3);
846 846
             $version_parts_of_provided_db_state = array_slice(explode('.', $version), 0, 3);
847 847
             $needs_updating = false;
848 848
             foreach ($version_parts_current_db_state as $offset => $version_part_in_current_db_state) {
849
-                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[ $offset ]) {
849
+                if ($version_part_in_current_db_state < $version_parts_of_provided_db_state[$offset]) {
850 850
                     $needs_updating = true;
851 851
                     break;
852 852
                 }
@@ -868,7 +868,7 @@  discard block
 block discarded – undo
868 868
      */
869 869
     public function get_all_data_migration_scripts_available()
870 870
     {
871
-        if (! $this->_data_migration_class_to_filepath_map) {
871
+        if ( ! $this->_data_migration_class_to_filepath_map) {
872 872
             $this->_data_migration_class_to_filepath_map = array();
873 873
             foreach ($this->get_data_migration_script_folders() as $eeAddonClass => $folder_path) {
874 874
                 // strip any placeholders added to classname to make it a unique array key
@@ -877,7 +877,7 @@  discard block
 block discarded – undo
877 877
                     ? $eeAddonClass
878 878
                     : '';
879 879
                 $folder_path = EEH_File::end_with_directory_separator($folder_path);
880
-                $files = glob($folder_path . '*.dms.php');
880
+                $files = glob($folder_path.'*.dms.php');
881 881
                 if (empty($files)) {
882 882
                     continue;
883 883
                 }
@@ -903,7 +903,7 @@  discard block
 block discarded – undo
903 903
                             '4.3.0.alpha.019'
904 904
                         );
905 905
                     }
906
-                    $this->_data_migration_class_to_filepath_map[ $classname ] = $file;
906
+                    $this->_data_migration_class_to_filepath_map[$classname] = $file;
907 907
                 }
908 908
             }
909 909
             EEH_Autoloader::register_autoloader($this->_data_migration_class_to_filepath_map);
@@ -935,7 +935,7 @@  discard block
 block discarded – undo
935 935
         // get last-ran migration script
936 936
         global $wpdb;
937 937
         $last_migration_script_option = $wpdb->get_row(
938
-            "SELECT * FROM $wpdb->options WHERE option_name like '" . EE_Data_Migration_Manager::data_migration_script_option_prefix . "%' ORDER BY option_id DESC LIMIT 1",
938
+            "SELECT * FROM $wpdb->options WHERE option_name like '".EE_Data_Migration_Manager::data_migration_script_option_prefix."%' ORDER BY option_id DESC LIMIT 1",
939 939
             ARRAY_A
940 940
         );
941 941
 
@@ -967,10 +967,10 @@  discard block
 block discarded – undo
967 967
             $versions_migrated_to = 'Unknown.1.0.0';
968 968
             // now just to make sure appears as last (in case the were previously a fatal error like this)
969 969
             // delete the old one
970
-            delete_option(self::data_migration_script_option_prefix . $versions_migrated_to);
970
+            delete_option(self::data_migration_script_option_prefix.$versions_migrated_to);
971 971
         }
972 972
         update_option(
973
-            self::data_migration_script_option_prefix . $versions_migrated_to,
973
+            self::data_migration_script_option_prefix.$versions_migrated_to,
974 974
             $last_ran_migration_script_properties
975 975
         );
976 976
     }
@@ -989,8 +989,8 @@  discard block
 block discarded – undo
989 989
         $successful_updates = true;
990 990
         foreach ($this->_data_migrations_ran as $plugin_slug => $migrations_ran_for_plugin) {
991 991
             foreach ($migrations_ran_for_plugin as $version_string => $array_or_migration_obj) {
992
-                $plugin_slug_for_use_in_option_name = $plugin_slug . ".";
993
-                $option_name = self::data_migration_script_option_prefix . $plugin_slug_for_use_in_option_name . $version_string;
992
+                $plugin_slug_for_use_in_option_name = $plugin_slug.".";
993
+                $option_name = self::data_migration_script_option_prefix.$plugin_slug_for_use_in_option_name.$version_string;
994 994
                 $old_option_value = get_option($option_name);
995 995
                 if ($array_or_migration_obj instanceof EE_Data_Migration_Script_Base) {
996 996
                     $script_array_for_saving = $array_or_migration_obj->properties_as_array();
@@ -1002,7 +1002,7 @@  discard block
 block discarded – undo
1002 1002
                         $successful_updates = update_option($option_name, $array_or_migration_obj);
1003 1003
                     }
1004 1004
                 }
1005
-                if (! $successful_updates) {
1005
+                if ( ! $successful_updates) {
1006 1006
                     global $wpdb;
1007 1007
                     return $wpdb->last_error;
1008 1008
                 }
@@ -1036,7 +1036,7 @@  discard block
 block discarded – undo
1036 1036
      */
1037 1037
     public function _instantiate_script_from_properties_array($properties_array)
1038 1038
     {
1039
-        if (! isset($properties_array['class'])) {
1039
+        if ( ! isset($properties_array['class'])) {
1040 1040
             throw new EE_Error(
1041 1041
                 sprintf(
1042 1042
                     __("Properties array  has no 'class' properties. Here's what it has: %s", "event_espresso"),
@@ -1045,11 +1045,11 @@  discard block
 block discarded – undo
1045 1045
             );
1046 1046
         }
1047 1047
         $class_name = $properties_array['class'];
1048
-        if (! class_exists($class_name)) {
1048
+        if ( ! class_exists($class_name)) {
1049 1049
             throw new EE_Error(sprintf(__("There is no migration script named %s", "event_espresso"), $class_name));
1050 1050
         }
1051 1051
         $class = new $class_name;
1052
-        if (! $class instanceof EE_Data_Migration_Script_Base) {
1052
+        if ( ! $class instanceof EE_Data_Migration_Script_Base) {
1053 1053
             throw new EE_Error(
1054 1054
                 sprintf(
1055 1055
                     __("Class '%s' is supposed to be a migration script. Its not, its a '%s'", "event_espresso"),
@@ -1116,8 +1116,8 @@  discard block
 block discarded – undo
1116 1116
     public function get_migration_ran($version, $plugin_slug = 'Core')
1117 1117
     {
1118 1118
         $migrations_ran = $this->get_data_migrations_ran();
1119
-        if (isset($migrations_ran[ $plugin_slug ]) && isset($migrations_ran[ $plugin_slug ][ $version ])) {
1120
-            return $migrations_ran[ $plugin_slug ][ $version ];
1119
+        if (isset($migrations_ran[$plugin_slug]) && isset($migrations_ran[$plugin_slug][$version])) {
1120
+            return $migrations_ran[$plugin_slug][$version];
1121 1121
         } else {
1122 1122
             return null;
1123 1123
         }
@@ -1178,7 +1178,7 @@  discard block
 block discarded – undo
1178 1178
     public function enqueue_db_initialization_for($plugin_slug)
1179 1179
     {
1180 1180
         $queue = $this->get_db_initialization_queue();
1181
-        if (! in_array($plugin_slug, $queue)) {
1181
+        if ( ! in_array($plugin_slug, $queue)) {
1182 1182
             $queue[] = $plugin_slug;
1183 1183
         }
1184 1184
         update_option(self::db_init_queue_option_name, $queue);
@@ -1194,7 +1194,7 @@  discard block
 block discarded – undo
1194 1194
         $queue = $this->get_db_initialization_queue();
1195 1195
         foreach ($queue as $plugin_slug) {
1196 1196
             $most_up_to_date_dms = $this->get_most_up_to_date_dms($plugin_slug);
1197
-            if (! $most_up_to_date_dms) {
1197
+            if ( ! $most_up_to_date_dms) {
1198 1198
                 // if there is NO DMS for this plugin, obviously there's no schema to verify anyways
1199 1199
                 $verify_db = false;
1200 1200
             } else {
Please login to merge, or discard this patch.
core/domain/services/custom_post_types/RewriteRules.php 2 patches
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -13,35 +13,35 @@
 block discarded – undo
13 13
 class RewriteRules
14 14
 {
15 15
 
16
-    const OPTION_KEY_FLUSH_REWRITE_RULES = 'ee_flush_rewrite_rules';
16
+	const OPTION_KEY_FLUSH_REWRITE_RULES = 'ee_flush_rewrite_rules';
17 17
 
18 18
 
19
-    /**
20
-     * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
21
-     *
22
-     * @return void
23
-     */
24
-    public function flush()
25
-    {
26
-        update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true);
27
-    }
19
+	/**
20
+	 * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
21
+	 *
22
+	 * @return void
23
+	 */
24
+	public function flush()
25
+	{
26
+		update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true);
27
+	}
28 28
 
29 29
 
30
-    /**
31
-     * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
32
-     *
33
-     * @return void
34
-     */
35
-    public function flushRewriteRules()
36
-    {
37
-        if (get_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true)) {
38
-            add_action(
39
-                'shutdown',
40
-                static function () {
41
-                    flush_rewrite_rules();
42
-                    update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, false);
43
-                }
44
-            );
45
-        }
46
-    }
30
+	/**
31
+	 * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
32
+	 *
33
+	 * @return void
34
+	 */
35
+	public function flushRewriteRules()
36
+	{
37
+		if (get_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true)) {
38
+			add_action(
39
+				'shutdown',
40
+				static function () {
41
+					flush_rewrite_rules();
42
+					update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, false);
43
+				}
44
+			);
45
+		}
46
+	}
47 47
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@
 block discarded – undo
37 37
         if (get_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true)) {
38 38
             add_action(
39 39
                 'shutdown',
40
-                static function () {
40
+                static function() {
41 41
                     flush_rewrite_rules();
42 42
                     update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, false);
43 43
                 }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since           4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 } else {
64
-    define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
-        /**
67
-         * espresso_minimum_php_version_error
68
-         *
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
64
+	define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+		/**
67
+		 * espresso_minimum_php_version_error
68
+		 *
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.10.13.rc.006');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.10.13.rc.006');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
Please login to merge, or discard this patch.