Completed
Branch BUG/fatal-with-paypal-debug-li... (3a6198)
by
unknown
17:52 queued 09:26
created

removeEmailConfirmFromAddressGroup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\domain\entities\notifications\PersistentAdminNotice;
4
use EventEspresso\core\domain\services\custom_post_types\RewriteRules;
5
use EventEspresso\core\exceptions\InvalidDataTypeException;
6
use EventEspresso\core\interfaces\ResettableInterface;
7
8
/**
9
 * EEH_Activation Helper
10
 *
11
 * @package        Event Espresso
12
 * @subpackage     /helpers/
13
 * @author         Brent Christensen
14
 */
15
class EEH_Activation implements ResettableInterface
16
{
17
18
    /**
19
     * constant used to indicate a cron task is no longer in use
20
     */
21
    const cron_task_no_longer_in_use = 'no_longer_in_use';
22
23
    /**
24
     * WP_User->ID
25
     *
26
     * @var int
27
     */
28
    private static $_default_creator_id;
29
30
    /**
31
     * indicates whether or not we've already verified core's default data during this request,
32
     * because after migrations are done, any addons activated while in maintenance mode
33
     * will want to setup their own default data, and they might hook into core's default data
34
     * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
35
     * This prevents doing that for EVERY single addon.
36
     *
37
     * @var boolean
38
     */
39
    protected static $_initialized_db_content_already_in_this_request = false;
40
41
    /**
42
     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
43
     */
44
    private static $table_analysis;
45
46
    /**
47
     * @var \EventEspresso\core\services\database\TableManager $table_manager
48
     */
49
    private static $table_manager;
50
51
52
    /**
53
     * @return \EventEspresso\core\services\database\TableAnalysis
54
     */
55
    public static function getTableAnalysis()
56
    {
57
        if (! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
58
            self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
59
        }
60
        return self::$table_analysis;
61
    }
62
63
64
    /**
65
     * @return \EventEspresso\core\services\database\TableManager
66
     */
67
    public static function getTableManager()
68
    {
69
        if (! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
70
            self::$table_manager = EE_Registry::instance()->create('TableManager', array(), true);
71
        }
72
        return self::$table_manager;
73
    }
74
75
76
    /**
77
     *    _ensure_table_name_has_prefix
78
     *
79
     * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
80
     * @access     public
81
     * @static
82
     * @param $table_name
83
     * @return string
84
     */
85
    public static function ensure_table_name_has_prefix($table_name)
86
    {
87
        return \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
88
    }
89
90
91
    /**
92
     *    system_initialization
93
     *    ensures the EE configuration settings are loaded with at least default options set
94
     *    and that all critical EE pages have been generated with the appropriate shortcodes in place
95
     *
96
     * @access public
97
     * @static
98
     * @return void
99
     */
100
    public static function system_initialization()
101
    {
102
        EEH_Activation::reset_and_update_config();
103
        // which is fired BEFORE activation of plugin anyways
104
        EEH_Activation::verify_default_pages_exist();
105
    }
106
107
108
    /**
109
     * Sets the database schema and creates folders. This should
110
     * be called on plugin activation and reactivation
111
     *
112
     * @return boolean success, whether the database and folders are setup properly
113
     * @throws \EE_Error
114
     */
115
    public static function initialize_db_and_folders()
116
    {
117
        return EEH_Activation::create_database_tables();
118
    }
119
120
121
    /**
122
     * assuming we have an up-to-date database schema, this will populate it
123
     * with default and initial data. This should be called
124
     * upon activation of a new plugin, reactivation, and at the end
125
     * of running migration scripts
126
     *
127
     * @throws \EE_Error
128
     */
129
    public static function initialize_db_content()
130
    {
131
        // let's avoid doing all this logic repeatedly, especially when addons are requesting it
132
        if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
133
            return;
134
        }
135
        EEH_Activation::$_initialized_db_content_already_in_this_request = true;
136
137
        EEH_Activation::initialize_system_questions();
138
        EEH_Activation::insert_default_status_codes();
139
        EEH_Activation::generate_default_message_templates();
140
        EEH_Activation::create_no_ticket_prices_array();
141
        EEH_Activation::removeEmailConfirmFromAddressGroup();
142
143
        EEH_Activation::validate_messages_system();
144
        EEH_Activation::insert_default_payment_methods();
145
        // in case we've
146
        EEH_Activation::remove_cron_tasks();
147
        EEH_Activation::create_cron_tasks();
148
        // remove all TXN locks since that is being done via extra meta now
149
        delete_option('ee_locked_transactions');
150
        // also, check for CAF default db content
151
        do_action('AHEE__EEH_Activation__initialize_db_content');
152
        // also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
153
        // which users really won't care about on initial activation
154
        EE_Error::overwrite_success();
155
    }
156
157
158
    /**
159
     * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
160
     * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
161
     * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
162
     * (null)
163
     *
164
     * @param string $which_to_include can be 'current' (ones that are currently in use),
165
     *                                 'old' (only returns ones that should no longer be used),or 'all',
166
     * @return array
167
     * @throws \EE_Error
168
     */
169
    public static function get_cron_tasks($which_to_include)
170
    {
171
        $cron_tasks = apply_filters(
172
            'FHEE__EEH_Activation__get_cron_tasks',
173
            array(
174
                'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
175
            //              'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions' => EEH_Activation::cron_task_no_longer_in_use, actually this is still in use
176
                'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
177
                // there may have been a bug which prevented from these cron tasks from getting unscheduled, so we might want to remove these for a few updates
178
                'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
179
            )
180
        );
181
        if ($which_to_include === 'old') {
182
            $cron_tasks = array_filter(
183
                $cron_tasks,
184
                function ($value) {
185
                    return $value === EEH_Activation::cron_task_no_longer_in_use;
186
                }
187
            );
188
        } elseif ($which_to_include === 'current') {
189
            $cron_tasks = array_filter($cron_tasks);
190
        } elseif (WP_DEBUG && $which_to_include !== 'all') {
191
            throw new EE_Error(
192
                sprintf(
193
                    __(
194
                        'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
195
                        'event_espresso'
196
                    ),
197
                    $which_to_include
198
                )
199
            );
200
        }
201
        return $cron_tasks;
202
    }
203
204
205
    /**
206
     * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
207
     *
208
     * @throws \EE_Error
209
     */
210
    public static function create_cron_tasks()
211
    {
212
213
        foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
214
            if (! wp_next_scheduled($hook_name)) {
215
                /**
216
                 * This allows client code to define the initial start timestamp for this schedule.
217
                 */
218
                if (is_array($frequency)
219
                    && count($frequency) === 2
220
                    && isset($frequency[0], $frequency[1])
221
                ) {
222
                    $start_timestamp = $frequency[0];
223
                    $frequency = $frequency[1];
224
                } else {
225
                    $start_timestamp = time();
226
                }
227
                wp_schedule_event($start_timestamp, $frequency, $hook_name);
228
            }
229
        }
230
    }
231
232
233
    /**
234
     * Remove the currently-existing and now-removed cron tasks.
235
     *
236
     * @param boolean $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
237
     * @throws \EE_Error
238
     */
239
    public static function remove_cron_tasks($remove_all = true)
240
    {
241
        $cron_tasks_to_remove = $remove_all ? 'all' : 'old';
242
        $crons                = _get_cron_array();
243
        $crons                = is_array($crons) ? $crons : array();
244
        /* reminder of what $crons look like:
245
         * Top-level keys are timestamps, and their values are arrays.
246
         * The 2nd level arrays have keys with each of the cron task hook names to run at that time
247
         * and their values are arrays.
248
         * The 3rd level level arrays are keys which are hashes of the cron task's arguments,
249
         *  and their values are the UN-hashed arguments
250
         * eg
251
         * array (size=13)
252
         *      1429903276 =>
253
         *        array (size=1)
254
         *          'AHEE__EE_Cron_Tasks__update_transaction_with_payment' =>
255
         *            array (size=1)
256
         *              '561299d6e42c8e079285870ade0e47e6' =>
257
         *                array (size=2)
258
         *                  ...
259
         *      ...
260
         */
261
        $ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
262
        foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
263
            if (is_array($hooks_to_fire_at_time)) {
264
                foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
265
                    if (isset($ee_cron_tasks_to_remove[ $hook_name ])
266
                        && is_array($ee_cron_tasks_to_remove[ $hook_name ])
267
                    ) {
268
                        unset($crons[ $timestamp ][ $hook_name ]);
269
                    }
270
                }
271
                // also take care of any empty cron timestamps.
272
                if (empty($hooks_to_fire_at_time)) {
273
                    unset($crons[ $timestamp ]);
274
                }
275
            }
276
        }
277
        _set_cron_array($crons);
278
    }
279
280
281
    /**
282
     *    CPT_initialization
283
     *    registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
284
     *
285
     * @access public
286
     * @static
287
     * @return void
288
     */
289
    public static function CPT_initialization()
290
    {
291
        // register Custom Post Types
292
        EE_Registry::instance()->load_core('Register_CPTs');
293
        flush_rewrite_rules();
294
    }
295
296
297
298
    /**
299
     *    reset_and_update_config
300
     * The following code was moved over from EE_Config so that it will no longer run on every request.
301
     * If there is old calendar config data saved, then it will get converted on activation.
302
     * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
303
     *
304
     * @access public
305
     * @static
306
     * @return void
307
     */
308
    public static function reset_and_update_config()
309
    {
310
        do_action('AHEE__EE_Config___load_core_config__start', array('EEH_Activation', 'load_calendar_config'));
311
        add_filter(
312
            'FHEE__EE_Config___load_core_config__config_settings',
313
            array('EEH_Activation', 'migrate_old_config_data'),
314
            10,
315
            3
316
        );
317
        // EE_Config::reset();
318
        if (! EE_Config::logging_enabled()) {
319
            delete_option(EE_Config::LOG_NAME);
320
        }
321
    }
322
323
324
    /**
325
     *    load_calendar_config
326
     *
327
     * @access    public
328
     * @return    void
329
     */
330
    public static function load_calendar_config()
331
    {
332
        // grab array of all plugin folders and loop thru it
333
        $plugins = glob(WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR);
334
        if (empty($plugins)) {
335
            return;
336
        }
337
        foreach ($plugins as $plugin_path) {
338
            // grab plugin folder name from path
339
            $plugin = basename($plugin_path);
340
            // drill down to Espresso plugins
341
            // then to calendar related plugins
342
            if (strpos($plugin, 'espresso') !== false
343
                || strpos($plugin, 'Espresso') !== false
344
                || strpos($plugin, 'ee4') !== false
345
                || strpos($plugin, 'EE4') !== false
346
                || strpos($plugin, 'calendar') !== false
347
            ) {
348
                // this is what we are looking for
349
                $calendar_config = $plugin_path . '/EE_Calendar_Config.php';
350
                // does it exist in this folder ?
351
                if (is_readable($calendar_config)) {
352
                    // YEAH! let's load it
353
                    require_once($calendar_config);
354
                }
355
            }
356
        }
357
    }
358
359
360
361
    /**
362
     *    _migrate_old_config_data
363
     *
364
     * @access    public
365
     * @param array|stdClass $settings
366
     * @param string         $config
367
     * @param \EE_Config     $EE_Config
368
     * @return \stdClass
369
     */
370
    public static function migrate_old_config_data($settings = array(), $config = '', EE_Config $EE_Config)
371
    {
372
        $convert_from_array = array('addons');
373
        // in case old settings were saved as an array
374
        if (is_array($settings) && in_array($config, $convert_from_array)) {
375
            // convert existing settings to an object
376
            $config_array = $settings;
377
            $settings = new stdClass();
378
            foreach ($config_array as $key => $value) {
379
                if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
380
                    $EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
381
                } else {
382
                    $settings->{$key} = $value;
383
                }
384
            }
385
            add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
386
        }
387
        return $settings;
0 ignored issues
show
Bug Compatibility introduced by
The expression return $settings; of type stdClass|array is incompatible with the return type documented by EEH_Activation::migrate_old_config_data of type stdClass as it can also be of type array which is not included in this return type.
Loading history...
388
    }
389
390
391
    /**
392
     * deactivate_event_espresso
393
     *
394
     * @access public
395
     * @static
396
     * @return void
397
     */
398
    public static function deactivate_event_espresso()
399
    {
400
        // check permissions
401
        if (current_user_can('activate_plugins')) {
402
            deactivate_plugins(EE_PLUGIN_BASENAME, true);
403
        }
404
    }
405
406
407
408
    /**
409
     * verify_default_pages_exist
410
     *
411
     * @access public
412
     * @static
413
     * @return void
414
     * @throws InvalidDataTypeException
415
     */
416
    public static function verify_default_pages_exist()
417
    {
418
        $critical_page_problem = false;
419
        $critical_pages = array(
420
            array(
421
                'id'   => 'reg_page_id',
422
                'name' => __('Registration Checkout', 'event_espresso'),
423
                'post' => null,
424
                'code' => 'ESPRESSO_CHECKOUT',
425
            ),
426
            array(
427
                'id'   => 'txn_page_id',
428
                'name' => __('Transactions', 'event_espresso'),
429
                'post' => null,
430
                'code' => 'ESPRESSO_TXN_PAGE',
431
            ),
432
            array(
433
                'id'   => 'thank_you_page_id',
434
                'name' => __('Thank You', 'event_espresso'),
435
                'post' => null,
436
                'code' => 'ESPRESSO_THANK_YOU',
437
            ),
438
            array(
439
                'id'   => 'cancel_page_id',
440
                'name' => __('Registration Cancelled', 'event_espresso'),
441
                'post' => null,
442
                'code' => 'ESPRESSO_CANCELLED',
443
            ),
444
        );
445
        $EE_Core_Config = EE_Registry::instance()->CFG->core;
446
        foreach ($critical_pages as $critical_page) {
447
            // is critical page ID set in config ?
448
            if ($EE_Core_Config->{$critical_page['id']} !== false) {
449
                // attempt to find post by ID
450
                $critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
451
            }
452
            // no dice?
453
            if ($critical_page['post'] === null) {
454
                // attempt to find post by title
455
                $critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
456
                // still nothing?
457
                if ($critical_page['post'] === null) {
458
                    $critical_page = EEH_Activation::create_critical_page($critical_page);
459
                    // REALLY? Still nothing ??!?!?
460
                    if ($critical_page['post'] === null) {
461
                        $msg = __(
462
                            'The Event Espresso critical page configuration settings could not be updated.',
463
                            'event_espresso'
464
                        );
465
                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
466
                        break;
467
                    }
468
                }
469
            }
470
            // check that Post ID matches critical page ID in config
471
            if (isset($critical_page['post']->ID)
472
                && $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
473
            ) {
474
                // update Config with post ID
475
                $EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
476
                if (! EE_Config::instance()->update_espresso_config(false, false)) {
477
                    $msg = __(
478
                        'The Event Espresso critical page configuration settings could not be updated.',
479
                        'event_espresso'
480
                    );
481
                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
482
                }
483
            }
484
            $critical_page_problem =
485
                ! isset($critical_page['post']->post_status)
486
                || $critical_page['post']->post_status !== 'publish'
487
                || strpos($critical_page['post']->post_content, $critical_page['code']) === false
488
                    ? true
489
                    : $critical_page_problem;
490
        }
491
        if ($critical_page_problem) {
492
            new PersistentAdminNotice(
493
                'critical_page_problem',
494
                sprintf(
495
                    esc_html__(
496
                        'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
497
                        'event_espresso'
498
                    ),
499
                    '<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
500
                    . __('Event Espresso Critical Pages Settings', 'event_espresso')
501
                    . '</a>'
502
                )
503
            );
504
        }
505
        if (EE_Error::has_notices()) {
506
            EE_Error::get_notices(false, true, true);
507
        }
508
    }
509
510
511
512
    /**
513
     * Returns the first post which uses the specified shortcode
514
     *
515
     * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
516
     *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
517
     *                             "[ESPRESSO_THANK_YOU"
518
     *                             (we don't search for the closing shortcode bracket because they might have added
519
     *                             parameter to the shortcode
520
     * @return WP_Post or NULl
521
     */
522
    public static function get_page_by_ee_shortcode($ee_shortcode)
523
    {
524
        global $wpdb;
525
        $shortcode_and_opening_bracket = '[' . $ee_shortcode;
526
        $post_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1");
527
        if ($post_id) {
528
            return get_post($post_id);
529
        } else {
530
            return null;
531
        }
532
    }
533
534
535
    /**
536
     *    This function generates a post for critical espresso pages
537
     *
538
     * @access public
539
     * @static
540
     * @param array $critical_page
541
     * @return array
542
     */
543
    public static function create_critical_page($critical_page)
544
    {
545
546
        $post_args = array(
547
            'post_title'     => $critical_page['name'],
548
            'post_status'    => 'publish',
549
            'post_type'      => 'page',
550
            'comment_status' => 'closed',
551
            'post_content'   => '[' . $critical_page['code'] . ']',
552
        );
553
554
        $post_id = wp_insert_post($post_args);
555
        if (! $post_id) {
556
            $msg = sprintf(
557
                __('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
558
                $critical_page['name']
559
            );
560
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
561
            return $critical_page;
562
        }
563
        // get newly created post's details
564 View Code Duplication
        if (! $critical_page['post'] = get_post($post_id)) {
565
            $msg = sprintf(
566
                __('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
567
                $critical_page['name']
568
            );
569
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
570
        }
571
572
        return $critical_page;
573
    }
574
575
576
577
578
    /**
579
     * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
580
     * The role being used to check is filterable.
581
     *
582
     * @since  4.6.0
583
     * @global WPDB $wpdb
584
     * @return mixed null|int WP_user ID or NULL
585
     */
586
    public static function get_default_creator_id()
587
    {
588
        global $wpdb;
589
        if (! empty(self::$_default_creator_id)) {
590
            return self::$_default_creator_id;
591
        }/**/
592
        $role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
593
        // let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
594
        $pre_filtered_id = apply_filters(
595
            'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
596
            false,
597
            $role_to_check
598
        );
599
        if ($pre_filtered_id !== false) {
600
            return (int) $pre_filtered_id;
601
        }
602
        $capabilities_key = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
603
        $query = $wpdb->prepare(
604
            "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
605
            '%' . $role_to_check . '%'
606
        );
607
        $user_id = $wpdb->get_var($query);
608
        $user_id = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
609
        if ($user_id && (int) $user_id) {
610
            self::$_default_creator_id = (int) $user_id;
611
            return self::$_default_creator_id;
612
        } else {
613
            return null;
614
        }
615
    }
616
617
618
619
    /**
620
     * used by EE and EE addons during plugin activation to create tables.
621
     * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
622
     * but includes extra logic regarding activations.
623
     *
624
     * @access public
625
     * @static
626
     * @param string  $table_name              without the $wpdb->prefix
627
     * @param string  $sql                     SQL for creating the table (contents between brackets in an SQL create
628
     *                                         table query)
629
     * @param string  $engine                  like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
630
     * @param boolean $drop_pre_existing_table set to TRUE when you want to make SURE the table is completely empty
631
     *                                         and new once this function is done (ie, you really do want to CREATE a
632
     *                                         table, and expect it to be empty once you're done) leave as FALSE when
633
     *                                         you just want to verify the table exists and matches this definition
634
     *                                         (and if it HAS data in it you want to leave it be)
635
     * @return void
636
     * @throws EE_Error if there are database errors
637
     */
638
    public static function create_table($table_name, $sql, $engine = 'ENGINE=MyISAM ', $drop_pre_existing_table = false)
639
    {
640
        if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
641
            return;
642
        }
643
        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
644
        if (! function_exists('dbDelta')) {
645
            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
646
        }
647
        $tableAnalysis = \EEH_Activation::getTableAnalysis();
648
        $wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
649
        // do we need to first delete an existing version of this table ?
650
        if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
651
            // ok, delete the table... but ONLY if it's empty
652
            $deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
653
            // table is NOT empty, are you SURE you want to delete this table ???
654
            if (! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $deleted_safely of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
655
                \EEH_Activation::getTableManager()->dropTable($wp_table_name);
656
            } elseif (! $deleted_safely) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $deleted_safely of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
657
                // so we should be more cautious rather than just dropping tables so easily
658
                error_log(
659
                    sprintf(
660
                        __(
661
                            'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
662
                            'event_espresso'
663
                        ),
664
                        $wp_table_name,
665
                        '<br/>',
666
                        'espresso_db_update'
667
                    )
668
                );
669
            }
670
        }
671
        $engine = str_replace('ENGINE=', '', $engine);
672
        \EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
673
    }
674
675
676
677
    /**
678
     *    add_column_if_it_doesn't_exist
679
     *    Checks if this column already exists on the specified table. Handy for addons which want to add a column
680
     *
681
     * @access     public
682
     * @static
683
     * @deprecated instead use TableManager::addColumn()
684
     * @param string $table_name  (without "wp_", eg "esp_attendee"
685
     * @param string $column_name
686
     * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
687
     *                            'VARCHAR(10)'
688
     * @return bool|int
689
     */
690
    public static function add_column_if_it_doesnt_exist(
691
        $table_name,
692
        $column_name,
693
        $column_info = 'INT UNSIGNED NOT NULL'
694
    ) {
695
        return \EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
696
    }
697
698
699
    /**
700
     * get_fields_on_table
701
     * Gets all the fields on the database table.
702
     *
703
     * @access     public
704
     * @deprecated instead use TableManager::getTableColumns()
705
     * @static
706
     * @param string $table_name , without prefixed $wpdb->prefix
707
     * @return array of database column names
708
     */
709
    public static function get_fields_on_table($table_name = null)
710
    {
711
        return \EEH_Activation::getTableManager()->getTableColumns($table_name);
712
    }
713
714
715
    /**
716
     * db_table_is_empty
717
     *
718
     * @access     public\
719
     * @deprecated instead use TableAnalysis::tableIsEmpty()
720
     * @static
721
     * @param string $table_name
722
     * @return bool
723
     */
724
    public static function db_table_is_empty($table_name)
725
    {
726
        return \EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
727
    }
728
729
730
    /**
731
     * delete_db_table_if_empty
732
     *
733
     * @access public
734
     * @static
735
     * @param string $table_name
736
     * @return bool | int
737
     */
738
    public static function delete_db_table_if_empty($table_name)
739
    {
740
        if (\EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
741
            return \EEH_Activation::getTableManager()->dropTable($table_name);
742
        }
743
        return false;
744
    }
745
746
747
    /**
748
     * delete_unused_db_table
749
     *
750
     * @access     public
751
     * @static
752
     * @deprecated instead use TableManager::dropTable()
753
     * @param string $table_name
754
     * @return bool | int
755
     */
756
    public static function delete_unused_db_table($table_name)
757
    {
758
        return \EEH_Activation::getTableManager()->dropTable($table_name);
759
    }
760
761
762
    /**
763
     * drop_index
764
     *
765
     * @access     public
766
     * @static
767
     * @deprecated instead use TableManager::dropIndex()
768
     * @param string $table_name
769
     * @param string $index_name
770
     * @return bool | int
771
     */
772
    public static function drop_index($table_name, $index_name)
773
    {
774
        return \EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
775
    }
776
777
778
779
    /**
780
     * create_database_tables
781
     *
782
     * @access public
783
     * @static
784
     * @throws EE_Error
785
     * @return boolean success (whether database is setup properly or not)
786
     */
787
    public static function create_database_tables()
788
    {
789
        EE_Registry::instance()->load_core('Data_Migration_Manager');
790
        // find the migration script that sets the database to be compatible with the code
791
        $dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
792
        if ($dms_name) {
793
            $current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
794
            $current_data_migration_script->set_migrating(false);
795
            $current_data_migration_script->schema_changes_before_migration();
796
            $current_data_migration_script->schema_changes_after_migration();
797
            if ($current_data_migration_script->get_errors()) {
798
                if (WP_DEBUG) {
799
                    foreach ($current_data_migration_script->get_errors() as $error) {
800
                        EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
801
                    }
802
                } else {
803
                    EE_Error::add_error(
804
                        __(
805
                            'There were errors creating the Event Espresso database tables and Event Espresso has been 
806
                            deactivated. To view the errors, please enable WP_DEBUG in your wp-config.php file.',
807
                            'event_espresso'
808
                        )
809
                    );
810
                }
811
                return false;
812
            }
813
            EE_Data_Migration_Manager::instance()->update_current_database_state_to();
814
        } else {
815
            EE_Error::add_error(
816
                __(
817
                    'Could not determine most up-to-date data migration script from which to pull database schema
818
                     structure. So database is probably not setup properly',
819
                    'event_espresso'
820
                ),
821
                __FILE__,
822
                __FUNCTION__,
823
                __LINE__
824
            );
825
            return false;
826
        }
827
        return true;
828
    }
829
830
831
832
    /**
833
     * initialize_system_questions
834
     *
835
     * @access public
836
     * @static
837
     * @return void
838
     */
839
    public static function initialize_system_questions()
840
    {
841
        // QUESTION GROUPS
842
        global $wpdb;
843
        $table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
844
        $SQL = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
845
        // what we have
846
        $question_groups = $wpdb->get_col($SQL);
847
        // check the response
848
        $question_groups = is_array($question_groups) ? $question_groups : array();
849
        // what we should have
850
        $QSG_systems = array(1, 2);
851
        // loop thru what we should have and compare to what we have
852
        foreach ($QSG_systems as $QSG_system) {
853
            // reset values array
854
            $QSG_values = array();
855
            // if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
856
            if (! in_array("$QSG_system", $question_groups)) {
857
                // add it
858
                switch ($QSG_system) {
859 View Code Duplication
                    case 1:
860
                        $QSG_values = array(
861
                            'QSG_name'            => __('Personal Information', 'event_espresso'),
862
                            'QSG_identifier'      => 'personal-information-' . time(),
863
                            'QSG_desc'            => '',
864
                            'QSG_order'           => 1,
865
                            'QSG_show_group_name' => 1,
866
                            'QSG_show_group_desc' => 1,
867
                            'QSG_system'          => EEM_Question_Group::system_personal,
868
                            'QSG_deleted'         => 0,
869
                        );
870
                        break;
871 View Code Duplication
                    case 2:
872
                        $QSG_values = array(
873
                            'QSG_name'            => __('Address Information', 'event_espresso'),
874
                            'QSG_identifier'      => 'address-information-' . time(),
875
                            'QSG_desc'            => '',
876
                            'QSG_order'           => 2,
877
                            'QSG_show_group_name' => 1,
878
                            'QSG_show_group_desc' => 1,
879
                            'QSG_system'          => EEM_Question_Group::system_address,
880
                            'QSG_deleted'         => 0,
881
                        );
882
                        break;
883
                }
884
                // make sure we have some values before inserting them
885
                if (! empty($QSG_values)) {
886
                    // insert system question
887
                    $wpdb->insert(
888
                        $table_name,
889
                        $QSG_values,
890
                        array('%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d')
891
                    );
892
                    $QSG_IDs[ $QSG_system ] = $wpdb->insert_id;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$QSG_IDs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $QSG_IDs = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
893
                }
894
            }
895
        }
896
        // QUESTIONS
897
        global $wpdb;
898
        $table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
899
        $SQL = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
900
        // what we have
901
        $questions = $wpdb->get_col($SQL);
902
        // all system questions
903
        $personal_system_group_questions = ['fname', 'lname', 'email'];
904
        $address_system_group_questions = ['address', 'address2', 'city', 'country', 'state', 'zip', 'phone'];
905
        $system_questions_not_in_group = ['email_confirm'];
906
        // merge all of the system questions we should have
907
        $QST_systems = array_merge(
908
            $personal_system_group_questions,
909
            $address_system_group_questions,
910
            $system_questions_not_in_group
911
        );
912
        $order_for_group_1 = 1;
913
        $order_for_group_2 = 1;
914
        // loop thru what we should have and compare to what we have
915
        foreach ($QST_systems as $QST_system) {
916
            // reset values array
917
            $QST_values = array();
918
            // if we don't have what we should have
919
            if (! in_array($QST_system, $questions)) {
920
                // add it
921
                switch ($QST_system) {
922 View Code Duplication
                    case 'fname':
923
                        $QST_values = array(
924
                            'QST_display_text'  => __('First Name', 'event_espresso'),
925
                            'QST_admin_label'   => __('First Name - System Question', 'event_espresso'),
926
                            'QST_system'        => 'fname',
927
                            'QST_type'          => 'TEXT',
928
                            'QST_required'      => 1,
929
                            'QST_required_text' => __('This field is required', 'event_espresso'),
930
                            'QST_order'         => 1,
931
                            'QST_admin_only'    => 0,
932
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
933
                            'QST_wp_user'       => self::get_default_creator_id(),
934
                            'QST_deleted'       => 0,
935
                        );
936
                        break;
937 View Code Duplication
                    case 'lname':
938
                        $QST_values = array(
939
                            'QST_display_text'  => __('Last Name', 'event_espresso'),
940
                            'QST_admin_label'   => __('Last Name - System Question', 'event_espresso'),
941
                            'QST_system'        => 'lname',
942
                            'QST_type'          => 'TEXT',
943
                            'QST_required'      => 1,
944
                            'QST_required_text' => __('This field is required', 'event_espresso'),
945
                            'QST_order'         => 2,
946
                            'QST_admin_only'    => 0,
947
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
948
                            'QST_wp_user'       => self::get_default_creator_id(),
949
                            'QST_deleted'       => 0,
950
                        );
951
                        break;
952 View Code Duplication
                    case 'email':
953
                        $QST_values = array(
954
                            'QST_display_text'  => __('Email Address', 'event_espresso'),
955
                            'QST_admin_label'   => __('Email Address - System Question', 'event_espresso'),
956
                            'QST_system'        => 'email',
957
                            'QST_type'          => 'EMAIL',
958
                            'QST_required'      => 1,
959
                            'QST_required_text' => __('This field is required', 'event_espresso'),
960
                            'QST_order'         => 3,
961
                            'QST_admin_only'    => 0,
962
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
963
                            'QST_wp_user'       => self::get_default_creator_id(),
964
                            'QST_deleted'       => 0,
965
                        );
966
                        break;
967 View Code Duplication
                    case 'email_confirm':
968
                        $QST_values = array(
969
                            'QST_display_text'  => __('Confirm Email Address', 'event_espresso'),
970
                            'QST_admin_label'   => __('Confirm Email Address - System Question', 'event_espresso'),
971
                            'QST_system'        => 'email_confirm',
972
                            'QST_type'          => 'EMAIL_CONFIRM',
973
                            'QST_required'      => 1,
974
                            'QST_required_text' => __('This field is required', 'event_espresso'),
975
                            'QST_order'         => 4,
976
                            'QST_admin_only'    => 0,
977
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
978
                            'QST_wp_user'       => self::get_default_creator_id(),
979
                            'QST_deleted'       => 0,
980
                        );
981
                        break;
982 View Code Duplication
                    case 'address':
983
                        $QST_values = array(
984
                            'QST_display_text'  => __('Address', 'event_espresso'),
985
                            'QST_admin_label'   => __('Address - System Question', 'event_espresso'),
986
                            'QST_system'        => 'address',
987
                            'QST_type'          => 'TEXT',
988
                            'QST_required'      => 0,
989
                            'QST_required_text' => __('This field is required', 'event_espresso'),
990
                            'QST_order'         => 5,
991
                            'QST_admin_only'    => 0,
992
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
993
                            'QST_wp_user'       => self::get_default_creator_id(),
994
                            'QST_deleted'       => 0,
995
                        );
996
                        break;
997 View Code Duplication
                    case 'address2':
998
                        $QST_values = array(
999
                            'QST_display_text'  => __('Address2', 'event_espresso'),
1000
                            'QST_admin_label'   => __('Address2 - System Question', 'event_espresso'),
1001
                            'QST_system'        => 'address2',
1002
                            'QST_type'          => 'TEXT',
1003
                            'QST_required'      => 0,
1004
                            'QST_required_text' => __('This field is required', 'event_espresso'),
1005
                            'QST_order'         => 6,
1006
                            'QST_admin_only'    => 0,
1007
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1008
                            'QST_wp_user'       => self::get_default_creator_id(),
1009
                            'QST_deleted'       => 0,
1010
                        );
1011
                        break;
1012 View Code Duplication
                    case 'city':
1013
                        $QST_values = array(
1014
                            'QST_display_text'  => __('City', 'event_espresso'),
1015
                            'QST_admin_label'   => __('City - System Question', 'event_espresso'),
1016
                            'QST_system'        => 'city',
1017
                            'QST_type'          => 'TEXT',
1018
                            'QST_required'      => 0,
1019
                            'QST_required_text' => __('This field is required', 'event_espresso'),
1020
                            'QST_order'         => 7,
1021
                            'QST_admin_only'    => 0,
1022
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1023
                            'QST_wp_user'       => self::get_default_creator_id(),
1024
                            'QST_deleted'       => 0,
1025
                        );
1026
                        break;
1027 View Code Duplication
                    case 'country':
1028
                        $QST_values = array(
1029
                            'QST_display_text'  => __('Country', 'event_espresso'),
1030
                            'QST_admin_label'   => __('Country - System Question', 'event_espresso'),
1031
                            'QST_system'        => 'country',
1032
                            'QST_type'          => 'COUNTRY',
1033
                            'QST_required'      => 0,
1034
                            'QST_required_text' => __('This field is required', 'event_espresso'),
1035
                            'QST_order'         => 8,
1036
                            'QST_admin_only'    => 0,
1037
                            'QST_wp_user'       => self::get_default_creator_id(),
1038
                            'QST_deleted'       => 0,
1039
                        );
1040
                        break;
1041 View Code Duplication
                    case 'state':
1042
                        $QST_values = array(
1043
                            'QST_display_text'  => __('State/Province', 'event_espresso'),
1044
                            'QST_admin_label'   => __('State/Province - System Question', 'event_espresso'),
1045
                            'QST_system'        => 'state',
1046
                            'QST_type'          => 'STATE',
1047
                            'QST_required'      => 0,
1048
                            'QST_required_text' => __('This field is required', 'event_espresso'),
1049
                            'QST_order'         => 9,
1050
                            'QST_admin_only'    => 0,
1051
                            'QST_wp_user'       => self::get_default_creator_id(),
1052
                            'QST_deleted'       => 0,
1053
                        );
1054
                        break;
1055 View Code Duplication
                    case 'zip':
1056
                        $QST_values = array(
1057
                            'QST_display_text'  => __('Zip/Postal Code', 'event_espresso'),
1058
                            'QST_admin_label'   => __('Zip/Postal Code - System Question', 'event_espresso'),
1059
                            'QST_system'        => 'zip',
1060
                            'QST_type'          => 'TEXT',
1061
                            'QST_required'      => 0,
1062
                            'QST_required_text' => __('This field is required', 'event_espresso'),
1063
                            'QST_order'         => 10,
1064
                            'QST_admin_only'    => 0,
1065
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1066
                            'QST_wp_user'       => self::get_default_creator_id(),
1067
                            'QST_deleted'       => 0,
1068
                        );
1069
                        break;
1070 View Code Duplication
                    case 'phone':
1071
                        $QST_values = array(
1072
                            'QST_display_text'  => __('Phone Number', 'event_espresso'),
1073
                            'QST_admin_label'   => __('Phone Number - System Question', 'event_espresso'),
1074
                            'QST_system'        => 'phone',
1075
                            'QST_type'          => 'TEXT',
1076
                            'QST_required'      => 0,
1077
                            'QST_required_text' => __('This field is required', 'event_espresso'),
1078
                            'QST_order'         => 11,
1079
                            'QST_admin_only'    => 0,
1080
                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1081
                            'QST_wp_user'       => self::get_default_creator_id(),
1082
                            'QST_deleted'       => 0,
1083
                        );
1084
                        break;
1085
                }
1086
                if (! empty($QST_values)) {
1087
                    // insert system question
1088
                    $wpdb->insert(
1089
                        $table_name,
1090
                        $QST_values,
1091
                        array('%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d')
1092
                    );
1093
                    $QST_ID = $wpdb->insert_id;
1094
1095
                    // QUESTION GROUP QUESTIONS
1096
                    if (in_array($QST_system, $personal_system_group_questions)) {
1097
                        $system_question_we_want = EEM_Question_Group::system_personal;
1098
                    } elseif (in_array($QST_system, $address_system_group_questions)) {
1099
                        $system_question_we_want = EEM_Question_Group::system_address;
1100
                    } else {
1101
                        // QST_system should not be assigned to any group
1102
                        continue;
1103
                    }
1104
                    if (isset($QSG_IDs[ $system_question_we_want ])) {
1105
                        $QSG_ID = $QSG_IDs[ $system_question_we_want ];
1106
                    } else {
1107
                        $id_col = EEM_Question_Group::instance()
1108
                                                    ->get_col(array(array('QSG_system' => $system_question_we_want)));
1109
                        if (is_array($id_col)) {
1110
                            $QSG_ID = reset($id_col);
1111
                        } else {
1112
                            // ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1113
                            EE_Log::instance()->log(
1114
                                __FILE__,
1115
                                __FUNCTION__,
1116
                                sprintf(
1117
                                    __(
1118
                                        'Could not associate question %1$s to a question group because no system question
1119
                                         group existed',
1120
                                        'event_espresso'
1121
                                    ),
1122
                                    $QST_ID
1123
                                ),
1124
                                'error'
1125
                            );
1126
                            continue;
1127
                        }
1128
                    }
1129
                    // add system questions to groups
1130
                    $wpdb->insert(
1131
                        \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1132
                        array(
1133
                            'QSG_ID'    => $QSG_ID,
1134
                            'QST_ID'    => $QST_ID,
1135
                            'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1136
                        ),
1137
                        array('%d', '%d', '%d')
1138
                    );
1139
                }
1140
            }
1141
        }
1142
    }
1143
1144
1145
    /**
1146
     * Makes sure the default payment method (Invoice) is active.
1147
     * This used to be done automatically as part of constructing the old gateways config
1148
     *
1149
     * @throws \EE_Error
1150
     */
1151
    public static function insert_default_payment_methods()
1152
    {
1153
        if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1154
            EE_Registry::instance()->load_lib('Payment_Method_Manager');
1155
            EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1156
        } else {
1157
            EEM_Payment_Method::instance()->verify_button_urls();
1158
        }
1159
    }
1160
1161
    /**
1162
     * insert_default_status_codes
1163
     *
1164
     * @access public
1165
     * @static
1166
     * @return void
1167
     */
1168
    public static function insert_default_status_codes()
1169
    {
1170
1171
        global $wpdb;
1172
1173
        if (\EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1174
            $table_name = EEM_Status::instance()->table();
1175
1176
            $SQL = "DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1177
            $wpdb->query($SQL);
1178
1179
            $SQL = "INSERT INTO $table_name
1180
					(STS_ID, STS_code, STS_type, STS_can_edit, STS_desc, STS_open) VALUES
1181
					('ACT', 'ACTIVE', 'event', 0, NULL, 1),
1182
					('NAC', 'NOT_ACTIVE', 'event', 0, NULL, 0),
1183
					('NOP', 'REGISTRATION_NOT_OPEN', 'event', 0, NULL, 1),
1184
					('OPN', 'REGISTRATION_OPEN', 'event', 0, NULL, 1),
1185
					('CLS', 'REGISTRATION_CLOSED', 'event', 0, NULL, 0),
1186
					('PND', 'PENDING', 'event', 0, NULL, 1),
1187
					('ONG', 'ONGOING', 'event', 0, NULL, 1),
1188
					('SEC', 'SECONDARY', 'event', 0, NULL, 1),
1189
					('DRF', 'DRAFT', 'event', 0, NULL, 0),
1190
					('DEL', 'DELETED', 'event', 0, NULL, 0),
1191
					('DEN', 'DENIED', 'event', 0, NULL, 0),
1192
					('EXP', 'EXPIRED', 'event', 0, NULL, 0),
1193
					('RPP', 'PENDING_PAYMENT', 'registration', 0, NULL, 1),
1194
					('RAP', 'APPROVED', 'registration', 0, NULL, 1),
1195
					('RCN', 'CANCELLED', 'registration', 0, NULL, 0),
1196
					('RDC', 'DECLINED', 'registration', 0, NULL, 0),
1197
					('RNA', 'NOT_APPROVED', 'registration', 0, NULL, 1),
1198
					('RIC', 'INCOMPLETE', 'registration', 0, NULL, 1),
1199
					('RWL', 'WAIT_LIST', 'registration', 0, NULL, 1),
1200
					('TFL', 'FAILED', 'transaction', 0, NULL, 0),
1201
					('TAB', 'ABANDONED', 'transaction', 0, NULL, 0),
1202
					('TIN', 'INCOMPLETE', 'transaction', 0, NULL, 1),
1203
					('TCM', 'COMPLETE', 'transaction', 0, NULL, 1),
1204
					('TOP',	'OVERPAID', 'transaction', 0, NULL, 1),
1205
					('PAP', 'APPROVED', 'payment', 0, NULL, 1),
1206
					('PPN', 'PENDING', 'payment', 0, NULL, 1),
1207
					('PCN', 'CANCELLED', 'payment', 0, NULL, 0),
1208
					('PFL', 'FAILED', 'payment', 0, NULL, 0),
1209
					('PDC', 'DECLINED', 'payment', 0, NULL, 0),
1210
					('EDR', 'DRAFT', 'email', 0, NULL, 0),
1211
					('ESN', 'SENT', 'email', 0, NULL, 1),
1212
					('MSN', 'SENT', 'message', 0, NULL, 0),
1213
					('MFL', 'FAIL', 'message', 0, NULL, 0),
1214
					('MDO', 'DEBUG_ONLY', 'message', 0, NULL, 0),
1215
					('MEX', 'MESSENGER_EXECUTING', 'message', 0, NULL, 0),
1216
					('MID', 'IDLE', 'message', 0, NULL, 1),
1217
					('MRS', 'RESEND', 'message', 0, NULL, 1),
1218
					('MIC', 'INCOMPLETE', 'message', 0, NULL, 0);";
1219
            $wpdb->query($SQL);
1220
        }
1221
    }
1222
1223
1224
    /**
1225
     * generate_default_message_templates
1226
     *
1227
     * @static
1228
     * @throws EE_Error
1229
     * @return bool     true means new templates were created.
1230
     *                  false means no templates were created.
1231
     *                  This is NOT an error flag. To check for errors you will want
1232
     *                  to use either EE_Error or a try catch for an EE_Error exception.
1233
     */
1234
    public static function generate_default_message_templates()
1235
    {
1236
        /** @type EE_Message_Resource_Manager $message_resource_manager */
1237
        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1238
        /*
1239
         * This first method is taking care of ensuring any default messengers
1240
         * that should be made active and have templates generated are done.
1241
         */
1242
        $new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1243
            $message_resource_manager
1244
        );
1245
        /**
1246
         * This method is verifying there are no NEW default message types
1247
         * for ACTIVE messengers that need activated (and corresponding templates setup).
1248
         */
1249
        $new_templates_created_for_message_type = self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1250
            $message_resource_manager
1251
        );
1252
        // after all is done, let's persist these changes to the db.
1253
        $message_resource_manager->update_has_activated_messengers_option();
1254
        $message_resource_manager->update_active_messengers_option();
1255
        // will return true if either of these are true.  Otherwise will return false.
1256
        return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1257
    }
1258
1259
1260
1261
    /**
1262
     * @param \EE_Message_Resource_Manager $message_resource_manager
1263
     * @return array|bool
1264
     * @throws \EE_Error
1265
     */
1266
    protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1267
        EE_Message_Resource_Manager $message_resource_manager
1268
    ) {
1269
        /** @type EE_messenger[] $active_messengers */
1270
        $active_messengers = $message_resource_manager->active_messengers();
1271
        $installed_message_types = $message_resource_manager->installed_message_types();
1272
        $templates_created = false;
1273
        foreach ($active_messengers as $active_messenger) {
1274
            $default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1275
            $default_message_type_names_to_activate = array();
1276
            // looping through each default message type reported by the messenger
1277
            // and setup the actual message types to activate.
1278
            foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1279
                // if already active or has already been activated before we skip
1280
                // (otherwise we might reactivate something user's intentionally deactivated.)
1281
                // we also skip if the message type is not installed.
1282
                if ($message_resource_manager->has_message_type_been_activated_for_messenger(
1283
                    $default_message_type_name_for_messenger,
1284
                    $active_messenger->name
1285
                )
1286
                    || $message_resource_manager->is_message_type_active_for_messenger(
1287
                        $active_messenger->name,
1288
                        $default_message_type_name_for_messenger
1289
                    )
1290
                    || ! isset($installed_message_types[ $default_message_type_name_for_messenger ])
1291
                ) {
1292
                    continue;
1293
                }
1294
                $default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1295
            }
1296
            // let's activate!
1297
            $message_resource_manager->ensure_message_types_are_active(
1298
                $default_message_type_names_to_activate,
1299
                $active_messenger->name,
1300
                false
1301
            );
1302
            // activate the templates for these message types
1303
            if (! empty($default_message_type_names_to_activate)) {
1304
                $templates_created = EEH_MSG_Template::generate_new_templates(
1305
                    $active_messenger->name,
1306
                    $default_message_type_names_for_messenger,
1307
                    '',
1308
                    true
1309
                );
1310
            }
1311
        }
1312
        return $templates_created;
1313
    }
1314
1315
1316
1317
    /**
1318
     * This will activate and generate default messengers and default message types for those messengers.
1319
     *
1320
     * @param EE_message_Resource_Manager $message_resource_manager
1321
     * @return array|bool  True means there were default messengers and message type templates generated.
1322
     *                     False means that there were no templates generated
1323
     *                     (which could simply mean there are no default message types for a messenger).
1324
     * @throws EE_Error
1325
     */
1326
    protected static function _activate_and_generate_default_messengers_and_message_templates(
1327
        EE_Message_Resource_Manager $message_resource_manager
1328
    ) {
1329
        /** @type EE_messenger[] $messengers_to_generate */
1330
        $messengers_to_generate = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1331
        $installed_message_types = $message_resource_manager->installed_message_types();
1332
        $templates_generated = false;
1333
        foreach ($messengers_to_generate as $messenger_to_generate) {
1334
            $default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1335
            // verify the default message types match an installed message type.
1336
            foreach ($default_message_type_names_for_messenger as $key => $name) {
1337
                if (! isset($installed_message_types[ $name ])
1338
                    || $message_resource_manager->has_message_type_been_activated_for_messenger(
1339
                        $name,
1340
                        $messenger_to_generate->name
1341
                    )
1342
                ) {
1343
                    unset($default_message_type_names_for_messenger[ $key ]);
1344
                }
1345
            }
1346
            // in previous iterations, the active_messengers option in the db
1347
            // needed updated before calling create templates. however with the changes this may not be necessary.
1348
            // This comment is left here just in case we discover that we _do_ need to update before
1349
            // passing off to create templates (after the refactor is done).
1350
            // @todo remove this comment when determined not necessary.
1351
            $message_resource_manager->activate_messenger(
1352
                $messenger_to_generate->name,
1353
                $default_message_type_names_for_messenger,
1354
                false
1355
            );
1356
            // create any templates needing created (or will reactivate templates already generated as necessary).
1357
            if (! empty($default_message_type_names_for_messenger)) {
1358
                $templates_generated = EEH_MSG_Template::generate_new_templates(
1359
                    $messenger_to_generate->name,
1360
                    $default_message_type_names_for_messenger,
1361
                    '',
1362
                    true
1363
                );
1364
            }
1365
        }
1366
        return $templates_generated;
1367
    }
1368
1369
1370
    /**
1371
     * This returns the default messengers to generate templates for on activation of EE.
1372
     * It considers:
1373
     * - whether a messenger is already active in the db.
1374
     * - whether a messenger has been made active at any time in the past.
1375
     *
1376
     * @static
1377
     * @param  EE_Message_Resource_Manager $message_resource_manager
1378
     * @return EE_messenger[]
1379
     */
1380
    protected static function _get_default_messengers_to_generate_on_activation(
1381
        EE_Message_Resource_Manager $message_resource_manager
1382
    ) {
1383
        $active_messengers    = $message_resource_manager->active_messengers();
1384
        $installed_messengers = $message_resource_manager->installed_messengers();
1385
        $has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1386
1387
        $messengers_to_generate = array();
1388
        foreach ($installed_messengers as $installed_messenger) {
1389
            // if installed messenger is a messenger that should be activated on install
1390
            // and is not already active
1391
            // and has never been activated
1392
            if (! $installed_messenger->activate_on_install
1393
                || isset($active_messengers[ $installed_messenger->name ])
1394
                || isset($has_activated[ $installed_messenger->name ])
1395
            ) {
1396
                continue;
1397
            }
1398
            $messengers_to_generate[ $installed_messenger->name ] = $installed_messenger;
1399
        }
1400
        return $messengers_to_generate;
1401
    }
1402
1403
1404
    /**
1405
     * This simply validates active message types to ensure they actually match installed
1406
     * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1407
     * rows are set inactive.
1408
     * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1409
     * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1410
     * are still handled in here.
1411
     *
1412
     * @since 4.3.1
1413
     * @return void
1414
     */
1415
    public static function validate_messages_system()
1416
    {
1417
        /** @type EE_Message_Resource_Manager $message_resource_manager */
1418
        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1419
        $message_resource_manager->validate_active_message_types_are_installed();
1420
        do_action('AHEE__EEH_Activation__validate_messages_system');
1421
    }
1422
1423
1424
    /**
1425
     * create_no_ticket_prices_array
1426
     *
1427
     * @access public
1428
     * @static
1429
     * @return void
1430
     */
1431
    public static function create_no_ticket_prices_array()
1432
    {
1433
        // this creates an array for tracking events that have no active ticket prices created
1434
        // this allows us to warn admins of the situation so that it can be corrected
1435
        $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', false);
1436
        if (! $espresso_no_ticket_prices) {
1437
            add_option('ee_no_ticket_prices', array(), '', false);
1438
        }
1439
    }
1440
1441
1442
    /**
1443
     * plugin_deactivation
1444
     *
1445
     * @access public
1446
     * @static
1447
     * @return void
1448
     */
1449
    public static function plugin_deactivation()
1450
    {
1451
    }
1452
1453
1454
    /**
1455
     * Finds all our EE4 custom post types, and deletes them and their associated data
1456
     * (like post meta or term relations)
1457
     *
1458
     * @global wpdb $wpdb
1459
     * @throws \EE_Error
1460
     */
1461
    public static function delete_all_espresso_cpt_data()
1462
    {
1463
        global $wpdb;
1464
        // get all the CPT post_types
1465
        $ee_post_types = array();
1466
        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1467
            if (method_exists($model_name, 'instance')) {
1468
                $model_obj = call_user_func(array($model_name, 'instance'));
1469
                if ($model_obj instanceof EEM_CPT_Base) {
1470
                    $ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1471
                }
1472
            }
1473
        }
1474
        // get all our CPTs
1475
        $query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1476
        $cpt_ids = $wpdb->get_col($query);
1477
        // delete each post meta and term relations too
1478
        foreach ($cpt_ids as $post_id) {
1479
            wp_delete_post($post_id, true);
1480
        }
1481
    }
1482
1483
    /**
1484
     * Deletes all EE custom tables
1485
     *
1486
     * @return array
1487
     */
1488
    public static function drop_espresso_tables()
1489
    {
1490
        $tables = array();
1491
        // load registry
1492 View Code Duplication
        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1493
            if (method_exists($model_name, 'instance')) {
1494
                $model_obj = call_user_func(array($model_name, 'instance'));
1495
                if ($model_obj instanceof EEM_Base) {
1496
                    foreach ($model_obj->get_tables() as $table) {
1497
                        if (strpos($table->get_table_name(), 'esp_')
1498
                            &&
1499
                            (
1500
                                is_main_site()// main site? nuke them all
1501
                                || ! $table->is_global()// not main site,but not global either. nuke it
1502
                            )
1503
                        ) {
1504
                            $tables[ $table->get_table_name() ] = $table->get_table_name();
1505
                        }
1506
                    }
1507
                }
1508
            }
1509
        }
1510
1511
        // there are some tables whose models were removed.
1512
        // they should be removed when removing all EE core's data
1513
        $tables_without_models = array(
1514
            'esp_promotion',
1515
            'esp_promotion_applied',
1516
            'esp_promotion_object',
1517
            'esp_promotion_rule',
1518
            'esp_rule',
1519
        );
1520
        foreach ($tables_without_models as $table) {
1521
            $tables[ $table ] = $table;
1522
        }
1523
        return \EEH_Activation::getTableManager()->dropTables($tables);
1524
    }
1525
1526
1527
1528
    /**
1529
     * Drops all the tables mentioned in a single MYSQL query. Double-checks
1530
     * each table name provided has a wpdb prefix attached, and that it exists.
1531
     * Returns the list actually deleted
1532
     *
1533
     * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1534
     * @global WPDB $wpdb
1535
     * @param array $table_names
1536
     * @return array of table names which we deleted
1537
     */
1538
    public static function drop_tables($table_names)
1539
    {
1540
        return \EEH_Activation::getTableManager()->dropTables($table_names);
1541
    }
1542
1543
1544
1545
    /**
1546
     * plugin_uninstall
1547
     *
1548
     * @access public
1549
     * @static
1550
     * @param bool $remove_all
1551
     * @return void
1552
     */
1553
    public static function delete_all_espresso_tables_and_data($remove_all = true)
1554
    {
1555
        global $wpdb;
1556
        self::drop_espresso_tables();
1557
        $wp_options_to_delete = array(
1558
            'ee_no_ticket_prices'                => true,
1559
            'ee_active_messengers'               => true,
1560
            'ee_has_activated_messenger'         => true,
1561
            RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES => true,
1562
            'ee_config'                          => false,
1563
            'ee_data_migration_current_db_state' => true,
1564
            'ee_data_migration_mapping_'         => false,
1565
            'ee_data_migration_script_'          => false,
1566
            'ee_data_migrations'                 => true,
1567
            'ee_dms_map'                         => false,
1568
            'ee_notices'                         => true,
1569
            'lang_file_check_'                   => false,
1570
            'ee_maintenance_mode'                => true,
1571
            'ee_ueip_optin'                      => true,
1572
            'ee_ueip_has_notified'               => true,
1573
            'ee_plugin_activation_errors'        => true,
1574
            'ee_id_mapping_from'                 => false,
1575
            'espresso_persistent_admin_notices'  => true,
1576
            'ee_encryption_key'                  => true,
1577
            'pue_force_upgrade_'                 => false,
1578
            'pue_json_error_'                    => false,
1579
            'pue_install_key_'                   => false,
1580
            'pue_verification_error_'            => false,
1581
            'pu_dismissed_upgrade_'              => false,
1582
            'external_updates-'                  => false,
1583
            'ee_extra_data'                      => true,
1584
            'ee_ssn_'                            => false,
1585
            'ee_rss_'                            => false,
1586
            'ee_rte_n_tx_'                       => false,
1587
            'ee_pers_admin_notices'              => true,
1588
            'ee_job_parameters_'                 => false,
1589
            'ee_upload_directories_incomplete'   => true,
1590
            'ee_verified_db_collations'          => true,
1591
        );
1592
        if (is_main_site()) {
1593
            $wp_options_to_delete['ee_network_config'] = true;
1594
        }
1595
        $undeleted_options = array();
1596
        foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1597
            if ($no_wildcard) {
1598
                if (! delete_option($option_name)) {
1599
                    $undeleted_options[] = $option_name;
1600
                }
1601
            } else {
1602
                $option_names_to_delete_from_wildcard = $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1603
                foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1604
                    if (! delete_option($option_name_from_wildcard)) {
1605
                        $undeleted_options[] = $option_name_from_wildcard;
1606
                    }
1607
                }
1608
            }
1609
        }
1610
        // also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1611
        remove_action('shutdown', array(EE_Config::instance(), 'shutdown'), 10);
1612
        if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1613
            $db_update_sans_ee4 = array();
1614
            foreach ($espresso_db_update as $version => $times_activated) {
1615
                if ((string) $version[0] === '3') {// if its NON EE4
1616
                    $db_update_sans_ee4[ $version ] = $times_activated;
1617
                }
1618
            }
1619
            update_option('espresso_db_update', $db_update_sans_ee4);
1620
        }
1621
        $errors = '';
1622
        if (! empty($undeleted_options)) {
1623
            $errors .= sprintf(
1624
                __('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1625
                '<br/>',
1626
                implode(',<br/>', $undeleted_options)
1627
            );
1628
        }
1629
        if (! empty($errors)) {
1630
            EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1631
        }
1632
    }
1633
1634
    /**
1635
     * Gets the mysql error code from the last used query by wpdb
1636
     *
1637
     * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1638
     */
1639
    public static function last_wpdb_error_code()
1640
    {
1641
        // phpcs:disable PHPCompatibility.PHP.RemovedExtensions.mysql_DeprecatedRemoved
1642
        global $wpdb;
1643
        if ($wpdb->use_mysqli) {
1644
            return mysqli_errno($wpdb->dbh);
1645
        } else {
1646
            return mysql_errno($wpdb->dbh);
1647
        }
1648
        // phpcs:enable
1649
    }
1650
1651
    /**
1652
     * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1653
     *
1654
     * @global wpdb  $wpdb
1655
     * @deprecated instead use TableAnalysis::tableExists()
1656
     * @param string $table_name with or without $wpdb->prefix
1657
     * @return boolean
1658
     */
1659
    public static function table_exists($table_name)
1660
    {
1661
        return \EEH_Activation::getTableAnalysis()->tableExists($table_name);
1662
    }
1663
1664
    /**
1665
     * Resets the cache on EEH_Activation
1666
     */
1667
    public static function reset()
1668
    {
1669
        self::$_default_creator_id                             = null;
1670
        self::$_initialized_db_content_already_in_this_request = false;
1671
    }
1672
1673
    /**
1674
     * Removes 'email_confirm' from the Address info question group on activation
1675
     * @return void
1676
     */
1677
    public static function removeEmailConfirmFromAddressGroup()
1678
    {
1679
1680
        // Pull the email_confirm question ID.
1681
        $email_confirm_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(
1682
            EEM_Attendee::system_question_email_confirm
1683
        );
1684
        // Remove the email_confirm question group from the address group questions.
1685
        EEM_Question_Group_Question::instance()->delete(
1686
            array(
1687
                array(
1688
                    'QST_ID' => $email_confirm_question_id,
1689
                    'Question_Group.QSG_system' => EEM_Question_Group::system_address,
1690
                ),
1691
            )
1692
        );
1693
    }
1694
}
1695