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