Completed
Branch EDTR/master (0d7008)
by
unknown
34:37 queued 26:06
created

EE_System   F

Complexity

Total Complexity 155

Size/Duplication

Total Lines 1357
Duplicated Lines 1.4 %

Coupling/Cohesion

Components 1
Dependencies 27

Importance

Changes 0
Metric Value
dl 19
loc 1357
rs 0.8
c 0
b 0
f 0
wmc 155
lcom 1
cbo 27

44 Methods

Rating   Name   Duplication   Size   Complexity  
A loadCommandBus() 0 16 1
A detect_activations_or_upgrades() 0 11 3
A instance() 0 12 2
A reset() 0 11 1
B __construct() 0 74 1
A loadCapabilities() 0 10 1
A loadPluginApi() 0 7 1
A deactivateIncompatibleAddon() 0 34 5
B load_espresso_addons() 0 36 7
B detect_if_activation_or_upgrade() 0 34 6
A _handle_core_version_change() 0 9 1
B fix_espresso_db_upgrade_option() 0 39 7
B initialize_db_if_no_migrations_required() 0 31 8
A initialize_addons() 0 9 3
A update_list_of_installed_versions() 0 12 3
A detect_req_type() 0 16 3
A _detect_major_version_change() 0 11 3
A is_major_version_change() 0 4 1
B detect_req_type_given_activation_history() 19 48 9
A _new_version_is_higher() 0 7 1
B _get_most_recently_active_version_from_activation_history() 0 28 9
B redirect_to_about_ee() 0 23 6
A load_core_configuration() 0 29 3
A _parse_model_names() 0 22 4
A _maybe_brew_regular() 0 16 2
A loadRouteMatchSpecifications() 0 11 2
B register_shortcodes_modules_and_widgets() 0 22 6
A _incompatible_addon_error() 0 32 4
A brew_espresso() 0 19 3
B loadWpGraphql() 0 30 8
A set_hooks_for_core() 0 9 1
A _deactivate_incompatible_addons() 0 15 5
A perform_activations_upgrades_and_migrations() 0 4 1
A load_CPTs_and_session() 0 22 1
B load_controllers() 0 17 7
B core_loaded_and_ready() 0 33 10
A initialize() 0 4 1
A initialize_last() 0 15 4
A addEspressoToolbar() 0 7 1
A do_not_cache() 0 19 4
A extra_nocache_headers() 0 8 1
A nocache_headers() 0 4 1
A remove_pages_from_wp_list_pages() 0 4 1
A canLoadBlocks() 0 8 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_System often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_System, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use EventEspresso\core\domain\Domain;
4
use EventEspresso\core\domain\DomainFactory;
5
use EventEspresso\core\domain\services\contexts\RequestTypeContextCheckerInterface;
6
use EventEspresso\core\domain\values\FilePath;
7
use EventEspresso\core\domain\values\FullyQualifiedName;
8
use EventEspresso\core\domain\values\Version;
9
use EventEspresso\core\exceptions\ExceptionStackTraceDisplay;
10
use EventEspresso\core\exceptions\InvalidClassException;
11
use EventEspresso\core\exceptions\InvalidDataTypeException;
12
use EventEspresso\core\exceptions\InvalidFilePathException;
13
use EventEspresso\core\exceptions\InvalidInterfaceException;
14
use EventEspresso\core\interfaces\ResettableInterface;
15
use EventEspresso\core\services\loaders\LoaderFactory;
16
use EventEspresso\core\services\loaders\LoaderInterface;
17
use EventEspresso\core\services\request\RequestInterface;
18
use EventEspresso\core\services\route_match\RouteMatchSpecificationManager;
19
20
/**
21
 * EE_System
22
 * The backbone of the core application that the rest of the system builds off of once bootstrapping is complete
23
 *
24
 * @package        Event Espresso
25
 * @subpackage     core/
26
 * @author         Brent Christensen, Michael Nelson
27
 */
28
final class EE_System implements ResettableInterface
29
{
30
31
    /**
32
     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
33
     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
34
     */
35
    const req_type_normal = 0;
36
37
    /**
38
     * Indicates this is a brand new installation of EE so we should install
39
     * tables and default data etc
40
     */
41
    const req_type_new_activation = 1;
42
43
    /**
44
     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
45
     * and we just exited maintenance mode). We MUST check the database is setup properly
46
     * and that default data is setup too
47
     */
48
    const req_type_reactivation = 2;
49
50
    /**
51
     * indicates that EE has been upgraded since its previous request.
52
     * We may have data migration scripts to call and will want to trigger maintenance mode
53
     */
54
    const req_type_upgrade = 3;
55
56
    /**
57
     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
58
     */
59
    const req_type_downgrade = 4;
60
61
    /**
62
     * @deprecated since version 4.6.0.dev.006
63
     * Now whenever a new_activation is detected the request type is still just
64
     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
65
     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
66
     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
67
     * (Specifically, when the migration manager indicates migrations are finished
68
     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
69
     */
70
    const req_type_activation_but_not_installed = 5;
71
72
    /**
73
     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
74
     */
75
    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
76
77
    /**
78
     * @var EE_System $_instance
79
     */
80
    private static $_instance;
81
82
    /**
83
     * @var EE_Registry $registry
84
     */
85
    private $registry;
86
87
    /**
88
     * @var LoaderInterface $loader
89
     */
90
    private $loader;
91
92
    /**
93
     * @var EE_Capabilities $capabilities
94
     */
95
    private $capabilities;
96
97
    /**
98
     * @var RequestInterface $request
99
     */
100
    private $request;
101
102
    /**
103
     * @var RouteMatchSpecificationManager $route_manager
104
     */
105
    private $route_manager;
106
107
    /**
108
     * @var EE_Maintenance_Mode $maintenance_mode
109
     */
110
    private $maintenance_mode;
111
112
    /**
113
     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
114
     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
115
     *
116
     * @var int $_req_type
117
     */
118
    private $_req_type;
119
120
    /**
121
     * Whether or not there was a non-micro version change in EE core version during this request
122
     *
123
     * @var boolean $_major_version_change
124
     */
125
    private $_major_version_change = false;
126
127
    /**
128
     * A Context DTO dedicated solely to identifying the current request type.
129
     *
130
     * @var RequestTypeContextCheckerInterface $request_type
131
     */
132
    private $request_type;
133
134
135
    /**
136
     * @singleton method used to instantiate class object
137
     * @param EE_Registry|null         $registry
138
     * @param LoaderInterface|null     $loader
139
     * @param RequestInterface|null    $request
140
     * @param EE_Maintenance_Mode|null $maintenance_mode
141
     * @return EE_System
142
     */
143
    public static function instance(
144
        EE_Registry $registry = null,
145
        LoaderInterface $loader = null,
146
        RequestInterface $request = null,
147
        EE_Maintenance_Mode $maintenance_mode = null
148
    ) {
149
        // check if class object is instantiated
150
        if (! self::$_instance instanceof EE_System) {
151
            self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
0 ignored issues
show
Bug introduced by
It seems like $registry defined by parameter $registry on line 144 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
Bug introduced by
It seems like $loader defined by parameter $loader on line 145 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
Bug introduced by
It seems like $request defined by parameter $request on line 146 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
Bug introduced by
It seems like $maintenance_mode defined by parameter $maintenance_mode on line 147 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
152
        }
153
        return self::$_instance;
154
    }
155
156
157
    /**
158
     * resets the instance and returns it
159
     *
160
     * @return EE_System
161
     */
162
    public static function reset()
163
    {
164
        self::$_instance->_req_type = null;
165
        // make sure none of the old hooks are left hanging around
166
        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
167
        // we need to reset the migration manager in order for it to detect DMSs properly
168
        EE_Data_Migration_Manager::reset();
169
        self::instance()->detect_activations_or_upgrades();
170
        self::instance()->perform_activations_upgrades_and_migrations();
171
        return self::instance();
172
    }
173
174
175
    /**
176
     * sets hooks for running rest of system
177
     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
178
     * starting EE Addons from any other point may lead to problems
179
     *
180
     * @param EE_Registry         $registry
181
     * @param LoaderInterface     $loader
182
     * @param RequestInterface    $request
183
     * @param EE_Maintenance_Mode $maintenance_mode
184
     */
185
    private function __construct(
186
        EE_Registry $registry,
187
        LoaderInterface $loader,
188
        RequestInterface $request,
189
        EE_Maintenance_Mode $maintenance_mode
190
    ) {
191
        $this->registry = $registry;
192
        $this->loader = $loader;
193
        $this->request = $request;
194
        $this->maintenance_mode = $maintenance_mode;
195
        do_action('AHEE__EE_System__construct__begin', $this);
196
        add_action(
197
            'AHEE__EE_Bootstrap__load_espresso_addons',
198
            array($this, 'loadCapabilities'),
199
            5
200
        );
201
        add_action(
202
            'AHEE__EE_Bootstrap__load_espresso_addons',
203
            array($this, 'loadCommandBus'),
204
            7
205
        );
206
        add_action(
207
            'AHEE__EE_Bootstrap__load_espresso_addons',
208
            array($this, 'loadPluginApi'),
209
            9
210
        );
211
        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
212
        add_action(
213
            'AHEE__EE_Bootstrap__load_espresso_addons',
214
            array($this, 'load_espresso_addons')
215
        );
216
        // when an ee addon is activated, we want to call the core hook(s) again
217
        // because the newly-activated addon didn't get a chance to run at all
218
        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
219
        // detect whether install or upgrade
220
        add_action(
221
            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
222
            array($this, 'detect_activations_or_upgrades'),
223
            3
224
        );
225
        // load EE_Config, EE_Textdomain, etc
226
        add_action(
227
            'AHEE__EE_Bootstrap__load_core_configuration',
228
            array($this, 'load_core_configuration'),
229
            5
230
        );
231
        // load specifications for matching routes to current request
232
        add_action(
233
            'AHEE__EE_Bootstrap__load_core_configuration',
234
            array($this, 'loadRouteMatchSpecifications')
235
        );
236
        // load EE_Config, EE_Textdomain, etc
237
        add_action(
238
            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
239
            array($this, 'register_shortcodes_modules_and_widgets'),
240
            7
241
        );
242
        // you wanna get going? I wanna get going... let's get going!
243
        add_action(
244
            'AHEE__EE_Bootstrap__brew_espresso',
245
            array($this, 'brew_espresso'),
246
            9
247
        );
248
        // other housekeeping
249
        // exclude EE critical pages from wp_list_pages
250
        add_filter(
251
            'wp_list_pages_excludes',
252
            array($this, 'remove_pages_from_wp_list_pages'),
253
            10
254
        );
255
        // ALL EE Addons should use the following hook point to attach their initial setup too
256
        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
257
        do_action('AHEE__EE_System__construct__complete', $this);
258
    }
259
260
261
    /**
262
     * load and setup EE_Capabilities
263
     *
264
     * @return void
265
     * @throws EE_Error
266
     */
267
    public function loadCapabilities()
268
    {
269
        $this->capabilities = $this->loader->getShared('EE_Capabilities');
270
        add_action(
271
            'AHEE__EE_Capabilities__init_caps__before_initialization',
272
            function () {
273
                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
274
            }
275
        );
276
    }
277
278
279
    /**
280
     * create and cache the CommandBus, and also add middleware
281
     * The CapChecker middleware requires the use of EE_Capabilities
282
     * which is why we need to load the CommandBus after Caps are set up
283
     *
284
     * @return void
285
     * @throws EE_Error
286
     */
287
    public function loadCommandBus()
288
    {
289
        $this->loader->getShared(
290
            'CommandBusInterface',
291
            array(
292
                null,
293
                apply_filters(
294
                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
295
                    array(
296
                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
297
                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
298
                    )
299
                ),
300
            )
301
        );
302
    }
303
304
305
    /**
306
     * @return void
307
     * @throws EE_Error
308
     */
309
    public function loadPluginApi()
310
    {
311
        // set autoloaders for all of the classes implementing EEI_Plugin_API
312
        // which provide helpers for EE plugin authors to more easily register certain components with EE.
313
        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
314
        $this->loader->getShared('EE_Request_Handler');
315
    }
316
317
318
    /**
319
     * @param string $addon_name
320
     * @param string $version_constant
321
     * @param string $min_version_required
322
     * @param string $load_callback
323
     * @param string $plugin_file_constant
324
     * @return void
325
     */
326
    private function deactivateIncompatibleAddon(
327
        $addon_name,
328
        $version_constant,
329
        $min_version_required,
330
        $load_callback,
331
        $plugin_file_constant
332
    ) {
333
        if (! defined($version_constant)) {
334
            return;
335
        }
336
        $addon_version = constant($version_constant);
337
        if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
338
            remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
339
            if (! function_exists('deactivate_plugins')) {
340
                require_once ABSPATH . 'wp-admin/includes/plugin.php';
341
            }
342
            deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
343
            unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
344
            EE_Error::add_error(
345
                sprintf(
346
                    esc_html__(
347
                        'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
348
                        'event_espresso'
349
                    ),
350
                    $addon_name,
351
                    $min_version_required
352
                ),
353
                __FILE__,
354
                __FUNCTION__ . "({$addon_name})",
355
                __LINE__
356
            );
357
            EE_Error::get_notices(false, true);
358
        }
359
    }
360
361
362
    /**
363
     * load_espresso_addons
364
     * allow addons to load first so that they can set hooks for running DMS's, etc
365
     * this is hooked into both:
366
     *    'AHEE__EE_Bootstrap__load_core_configuration'
367
     *        which runs during the WP 'plugins_loaded' action at priority 5
368
     *    and the WP 'activate_plugin' hook point
369
     *
370
     * @access public
371
     * @return void
372
     */
373
    public function load_espresso_addons()
374
    {
375
        $this->deactivateIncompatibleAddon(
376
            'Wait Lists',
377
            'EE_WAIT_LISTS_VERSION',
378
            '1.0.0.beta.074',
379
            'load_espresso_wait_lists',
380
            'EE_WAIT_LISTS_PLUGIN_FILE'
381
        );
382
        $this->deactivateIncompatibleAddon(
383
            'Automated Upcoming Event Notifications',
384
            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
385
            '1.0.0.beta.091',
386
            'load_espresso_automated_upcoming_event_notification',
387
            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
388
        );
389
        do_action('AHEE__EE_System__load_espresso_addons');
390
        // if the WP API basic auth plugin isn't already loaded, load it now.
391
        // We want it for mobile apps. Just include the entire plugin
392
        // also, don't load the basic auth when a plugin is getting activated, because
393
        // it could be the basic auth plugin, and it doesn't check if its methods are already defined
394
        // and causes a fatal error
395
        if (($this->request->isWordPressApi() || $this->request->isApi())
396
            && $this->request->getRequestParam('activate') !== 'true'
397
            && ! function_exists('json_basic_auth_handler')
398
            && ! function_exists('json_basic_auth_error')
399
            && ! in_array(
400
                $this->request->getRequestParam('action'),
401
                array('activate', 'activate-selected'),
402
                true
403
            )
404
        ) {
405
            include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
406
        }
407
        do_action('AHEE__EE_System__load_espresso_addons__complete');
408
    }
409
410
411
    /**
412
     * detect_activations_or_upgrades
413
     * Checks for activation or upgrade of core first;
414
     * then also checks if any registered addons have been activated or upgraded
415
     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
416
     * which runs during the WP 'plugins_loaded' action at priority 3
417
     *
418
     * @access public
419
     * @return void
420
     */
421
    public function detect_activations_or_upgrades()
422
    {
423
        // first off: let's make sure to handle core
424
        $this->detect_if_activation_or_upgrade();
425
        foreach ($this->registry->addons as $addon) {
426
            if ($addon instanceof EE_Addon) {
427
                // detect teh request type for that addon
428
                $addon->detect_activation_or_upgrade();
429
            }
430
        }
431
    }
432
433
434
    /**
435
     * detect_if_activation_or_upgrade
436
     * Takes care of detecting whether this is a brand new install or code upgrade,
437
     * and either setting up the DB or setting up maintenance mode etc.
438
     *
439
     * @access public
440
     * @return void
441
     */
442
    public function detect_if_activation_or_upgrade()
443
    {
444
        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
445
        // check if db has been updated, or if its a brand-new installation
446
        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
447
        $request_type = $this->detect_req_type($espresso_db_update);
448
        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
449
        switch ($request_type) {
450
            case EE_System::req_type_new_activation:
451
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
452
                $this->_handle_core_version_change($espresso_db_update);
453
                break;
454
            case EE_System::req_type_reactivation:
455
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
456
                $this->_handle_core_version_change($espresso_db_update);
457
                break;
458
            case EE_System::req_type_upgrade:
459
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
460
                // migrations may be required now that we've upgraded
461
                $this->maintenance_mode->set_maintenance_mode_if_db_old();
462
                $this->_handle_core_version_change($espresso_db_update);
463
                break;
464
            case EE_System::req_type_downgrade:
465
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
466
                // its possible migrations are no longer required
467
                $this->maintenance_mode->set_maintenance_mode_if_db_old();
468
                $this->_handle_core_version_change($espresso_db_update);
469
                break;
470
            case EE_System::req_type_normal:
471
            default:
472
                break;
473
        }
474
        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
475
    }
476
477
478
    /**
479
     * Updates the list of installed versions and sets hooks for
480
     * initializing the database later during the request
481
     *
482
     * @param array $espresso_db_update
483
     */
484
    private function _handle_core_version_change($espresso_db_update)
485
    {
486
        $this->update_list_of_installed_versions($espresso_db_update);
487
        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
488
        add_action(
489
            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
490
            array($this, 'initialize_db_if_no_migrations_required')
491
        );
492
    }
493
494
495
    /**
496
     * standardizes the wp option 'espresso_db_upgrade' which actually stores
497
     * information about what versions of EE have been installed and activated,
498
     * NOT necessarily the state of the database
499
     *
500
     * @param mixed $espresso_db_update           the value of the WordPress option.
501
     *                                            If not supplied, fetches it from the options table
502
     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
503
     */
504
    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
505
    {
506
        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
507
        if (! $espresso_db_update) {
508
            $espresso_db_update = get_option('espresso_db_update');
509
        }
510
        // check that option is an array
511
        if (! is_array($espresso_db_update)) {
512
            // if option is FALSE, then it never existed
513
            if ($espresso_db_update === false) {
514
                // make $espresso_db_update an array and save option with autoload OFF
515
                $espresso_db_update = array();
516
                add_option('espresso_db_update', $espresso_db_update, '', 'no');
517
            } else {
518
                // option is NOT FALSE but also is NOT an array, so make it an array and save it
519
                $espresso_db_update = array($espresso_db_update => array());
520
                update_option('espresso_db_update', $espresso_db_update);
521
            }
522
        } else {
523
            $corrected_db_update = array();
524
            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
525
            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
526
                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
527
                    // the key is an int, and the value IS NOT an array
528
                    // so it must be numerically-indexed, where values are versions installed...
529
                    // fix it!
530
                    $version_string = $should_be_array;
531
                    $corrected_db_update[ $version_string ] = array('unknown-date');
532
                } else {
533
                    // ok it checks out
534
                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
535
                }
536
            }
537
            $espresso_db_update = $corrected_db_update;
538
            update_option('espresso_db_update', $espresso_db_update);
539
        }
540
        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
541
        return $espresso_db_update;
542
    }
543
544
545
    /**
546
     * Does the traditional work of setting up the plugin's database and adding default data.
547
     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
548
     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
549
     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
550
     * so that it will be done when migrations are finished
551
     *
552
     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
553
     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
554
     *                                       This is a resource-intensive job
555
     *                                       so we prefer to only do it when necessary
556
     * @return void
557
     * @throws EE_Error
558
     */
559
    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
560
    {
561
        $request_type = $this->detect_req_type();
562
        // only initialize system if we're not in maintenance mode.
563
        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
564
            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
565
            $rewrite_rules = $this->loader->getShared(
566
                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
567
            );
568
            $rewrite_rules->flush();
569
            if ($verify_schema) {
570
                EEH_Activation::initialize_db_and_folders();
571
            }
572
            EEH_Activation::initialize_db_content();
573
            EEH_Activation::system_initialization();
574
            if ($initialize_addons_too) {
575
                $this->initialize_addons();
576
            }
577
        } else {
578
            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
579
        }
580
        if ($request_type === EE_System::req_type_new_activation
581
            || $request_type === EE_System::req_type_reactivation
582
            || (
583
                $request_type === EE_System::req_type_upgrade
584
                && $this->is_major_version_change()
585
            )
586
        ) {
587
            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
588
        }
589
    }
590
591
592
    /**
593
     * Initializes the db for all registered addons
594
     *
595
     * @throws EE_Error
596
     */
597
    public function initialize_addons()
598
    {
599
        // foreach registered addon, make sure its db is up-to-date too
600
        foreach ($this->registry->addons as $addon) {
601
            if ($addon instanceof EE_Addon) {
602
                $addon->initialize_db_if_no_migrations_required();
603
            }
604
        }
605
    }
606
607
608
    /**
609
     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
610
     *
611
     * @param    array  $version_history
612
     * @param    string $current_version_to_add version to be added to the version history
613
     * @return    boolean success as to whether or not this option was changed
614
     */
615
    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
616
    {
617
        if (! $version_history) {
618
            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
619
        }
620
        if ($current_version_to_add === null) {
621
            $current_version_to_add = espresso_version();
622
        }
623
        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
624
        // re-save
625
        return update_option('espresso_db_update', $version_history);
626
    }
627
628
629
    /**
630
     * Detects if the current version indicated in the has existed in the list of
631
     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
632
     *
633
     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
634
     *                                  If not supplied, fetches it from the options table.
635
     *                                  Also, caches its result so later parts of the code can also know whether
636
     *                                  there's been an update or not. This way we can add the current version to
637
     *                                  espresso_db_update, but still know if this is a new install or not
638
     * @return int one of the constants on EE_System::req_type_
639
     */
640
    public function detect_req_type($espresso_db_update = null)
641
    {
642
        if ($this->_req_type === null) {
643
            $espresso_db_update = ! empty($espresso_db_update)
644
                ? $espresso_db_update
645
                : $this->fix_espresso_db_upgrade_option();
646
            $this->_req_type = EE_System::detect_req_type_given_activation_history(
647
                $espresso_db_update,
648
                'ee_espresso_activation',
649
                espresso_version()
650
            );
651
            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
652
            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
653
        }
654
        return $this->_req_type;
655
    }
656
657
658
    /**
659
     * Returns whether or not there was a non-micro version change (ie, change in either
660
     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
661
     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
662
     *
663
     * @param $activation_history
664
     * @return bool
665
     */
666
    private function _detect_major_version_change($activation_history)
667
    {
668
        $previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
669
        $previous_version_parts = explode('.', $previous_version);
670
        $current_version_parts = explode('.', espresso_version());
671
        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
672
               && (
673
                   $previous_version_parts[0] !== $current_version_parts[0]
674
                   || $previous_version_parts[1] !== $current_version_parts[1]
675
               );
676
    }
677
678
679
    /**
680
     * Returns true if either the major or minor version of EE changed during this request.
681
     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
682
     *
683
     * @return bool
684
     */
685
    public function is_major_version_change()
686
    {
687
        return $this->_major_version_change;
688
    }
689
690
691
    /**
692
     * Determines the request type for any ee addon, given three piece of info: the current array of activation
693
     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
694
     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
695
     * just activated to (for core that will always be espresso_version())
696
     *
697
     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
698
     *                                                 ee plugin. for core that's 'espresso_db_update'
699
     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
700
     *                                                 indicate that this plugin was just activated
701
     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
702
     *                                                 espresso_version())
703
     * @return int one of the constants on EE_System::req_type_*
704
     */
705
    public static function detect_req_type_given_activation_history(
706
        $activation_history_for_addon,
707
        $activation_indicator_option_name,
708
        $version_to_upgrade_to
709
    ) {
710
        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
711
        if ($activation_history_for_addon) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $activation_history_for_addon of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
712
            // it exists, so this isn't a completely new install
713
            // check if this version already in that list of previously installed versions
714
            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
715
                // it a version we haven't seen before
716
                if ($version_is_higher === 1) {
717
                    $req_type = EE_System::req_type_upgrade;
718
                } else {
719
                    $req_type = EE_System::req_type_downgrade;
720
                }
721
                delete_option($activation_indicator_option_name);
722
            } else {
723
                // its not an update. maybe a reactivation?
724
                if (get_option($activation_indicator_option_name, false)) {
725 View Code Duplication
                    if ($version_is_higher === -1) {
726
                        $req_type = EE_System::req_type_downgrade;
727
                    } elseif ($version_is_higher === 0) {
728
                        // we've seen this version before, but it's an activation. must be a reactivation
729
                        $req_type = EE_System::req_type_reactivation;
730
                    } else {// $version_is_higher === 1
731
                        $req_type = EE_System::req_type_upgrade;
732
                    }
733
                    delete_option($activation_indicator_option_name);
734 View Code Duplication
                } else {
735
                    // we've seen this version before and the activation indicate doesn't show it was just activated
736
                    if ($version_is_higher === -1) {
737
                        $req_type = EE_System::req_type_downgrade;
738
                    } elseif ($version_is_higher === 0) {
739
                        // we've seen this version before and it's not an activation. its normal request
740
                        $req_type = EE_System::req_type_normal;
741
                    } else {// $version_is_higher === 1
742
                        $req_type = EE_System::req_type_upgrade;
743
                    }
744
                }
745
            }
746
        } else {
747
            // brand new install
748
            $req_type = EE_System::req_type_new_activation;
749
            delete_option($activation_indicator_option_name);
750
        }
751
        return $req_type;
752
    }
753
754
755
    /**
756
     * Detects if the $version_to_upgrade_to is higher than the most recent version in
757
     * the $activation_history_for_addon
758
     *
759
     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
760
     *                                             sometimes containing 'unknown-date'
761
     * @param string $version_to_upgrade_to        (current version)
762
     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
763
     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
764
     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
765
     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
766
     */
767
    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
768
    {
769
        // find the most recently-activated version
770
        $most_recently_active_version =
771
            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
772
        return version_compare($version_to_upgrade_to, $most_recently_active_version);
773
    }
774
775
776
    /**
777
     * Gets the most recently active version listed in the activation history,
778
     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
779
     *
780
     * @param array $activation_history  (keys are versions, values are arrays of times activated,
781
     *                                   sometimes containing 'unknown-date'
782
     * @return string
783
     */
784
    private static function _get_most_recently_active_version_from_activation_history($activation_history)
785
    {
786
        $most_recently_active_version_activation = '1970-01-01 00:00:00';
787
        $most_recently_active_version = '0.0.0.dev.000';
788
        if (is_array($activation_history)) {
789
            foreach ($activation_history as $version => $times_activated) {
790
                // check there is a record of when this version was activated. Otherwise,
791
                // mark it as unknown
792
                if (! $times_activated) {
793
                    $times_activated = array('unknown-date');
794
                }
795
                if (is_string($times_activated)) {
796
                    $times_activated = array($times_activated);
797
                }
798
                foreach ($times_activated as $an_activation) {
799
                    if ($an_activation !== 'unknown-date'
800
                        && $an_activation
801
                           > $most_recently_active_version_activation) {
802
                        $most_recently_active_version = $version;
803
                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
804
                            ? '1970-01-01 00:00:00'
805
                            : $an_activation;
806
                    }
807
                }
808
            }
809
        }
810
        return $most_recently_active_version;
811
    }
812
813
814
    /**
815
     * This redirects to the about EE page after activation
816
     *
817
     * @return void
818
     */
819
    public function redirect_to_about_ee()
820
    {
821
        $notices = EE_Error::get_notices(false);
822
        // if current user is an admin and it's not an ajax or rest request
823
        if (! isset($notices['errors'])
824
            && $this->request->isAdmin()
825
            && apply_filters(
826
                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
827
                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
828
            )
829
        ) {
830
            $query_params = array('page' => 'espresso_about');
831
            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
832
                $query_params['new_activation'] = true;
833
            }
834
            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
835
                $query_params['reactivation'] = true;
836
            }
837
            $url = add_query_arg($query_params, admin_url('admin.php'));
838
            wp_safe_redirect($url);
839
            exit();
840
        }
841
    }
842
843
844
    /**
845
     * load_core_configuration
846
     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
847
     * which runs during the WP 'plugins_loaded' action at priority 5
848
     *
849
     * @return void
850
     * @throws ReflectionException
851
     * @throws Exception
852
     */
853
    public function load_core_configuration()
854
    {
855
        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
856
        $this->loader->getShared('EE_Load_Textdomain');
857
        // load textdomain
858
        EE_Load_Textdomain::load_textdomain();
859
        // load caf stuff a chance to play during the activation process too.
860
        $this->_maybe_brew_regular();
861
        // load and setup EE_Config and EE_Network_Config
862
        $config = $this->loader->getShared('EE_Config');
863
        $this->loader->getShared('EE_Network_Config');
864
        // setup autoloaders
865
        // enable logging?
866
        if ($config->admin->use_remote_logging) {
867
            $this->loader->getShared('EE_Log');
868
        }
869
        // check for activation errors
870
        $activation_errors = get_option('ee_plugin_activation_errors', false);
871
        if ($activation_errors) {
872
            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
873
            update_option('ee_plugin_activation_errors', false);
874
        }
875
        // get model names
876
        $this->_parse_model_names();
877
        // configure custom post type definitions
878
        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
879
        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
880
        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
881
    }
882
883
884
    /**
885
     * cycles through all of the models/*.model.php files, and assembles an array of model names
886
     *
887
     * @return void
888
     * @throws ReflectionException
889
     */
890
    private function _parse_model_names()
891
    {
892
        // get all the files in the EE_MODELS folder that end in .model.php
893
        $models = glob(EE_MODELS . '*.model.php');
894
        $model_names = array();
895
        $non_abstract_db_models = array();
896
        foreach ($models as $model) {
897
            // get model classname
898
            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
899
            $short_name = str_replace('EEM_', '', $classname);
900
            $reflectionClass = new ReflectionClass($classname);
901
            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
902
                $non_abstract_db_models[ $short_name ] = $classname;
903
            }
904
            $model_names[ $short_name ] = $classname;
905
        }
906
        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
907
        $this->registry->non_abstract_db_models = apply_filters(
908
            'FHEE__EE_System__parse_implemented_model_names',
909
            $non_abstract_db_models
910
        );
911
    }
912
913
914
    /**
915
     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
916
     * that need to be setup before our EE_System launches.
917
     *
918
     * @return void
919
     * @throws DomainException
920
     * @throws InvalidArgumentException
921
     * @throws InvalidDataTypeException
922
     * @throws InvalidInterfaceException
923
     * @throws InvalidClassException
924
     * @throws InvalidFilePathException
925
     */
926
    private function _maybe_brew_regular()
927
    {
928
        /** @var Domain $domain */
929
        $domain = DomainFactory::getShared(
930
            new FullyQualifiedName(
931
                'EventEspresso\core\domain\Domain'
932
            ),
933
            array(
934
                new FilePath(EVENT_ESPRESSO_MAIN_FILE),
935
                Version::fromString(espresso_version()),
936
            )
937
        );
938
        if ($domain->isCaffeinated()) {
939
            require_once EE_CAFF_PATH . 'brewing_regular.php';
940
        }
941
    }
942
943
944
    /**
945
     * @since 4.9.71.p
946
     * @throws Exception
947
     */
948
    public function loadRouteMatchSpecifications()
949
    {
950
        try {
951
            $this->route_manager = $this->loader->getShared(
952
                'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
953
            );
954
        } catch (Exception $exception) {
955
            new ExceptionStackTraceDisplay($exception);
956
        }
957
        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
958
    }
959
960
961
    /**
962
     * register_shortcodes_modules_and_widgets
963
     * generate lists of shortcodes and modules, then verify paths and classes
964
     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
965
     * which runs during the WP 'plugins_loaded' action at priority 7
966
     *
967
     * @access public
968
     * @return void
969
     * @throws Exception
970
     */
971
    public function register_shortcodes_modules_and_widgets()
972
    {
973
        if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
974
            try {
975
                // load, register, and add shortcodes the new way
976
                $this->loader->getShared(
977
                    'EventEspresso\core\services\shortcodes\ShortcodesManager',
978
                    array(
979
                        // and the old way, but we'll put it under control of the new system
980
                        EE_Config::getLegacyShortcodesManager(),
981
                    )
982
                );
983
            } catch (Exception $exception) {
984
                new ExceptionStackTraceDisplay($exception);
985
            }
986
        }
987
        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
988
        // check for addons using old hook point
989
        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
990
            $this->_incompatible_addon_error();
991
        }
992
    }
993
994
995
    /**
996
     * _incompatible_addon_error
997
     *
998
     * @access public
999
     * @return void
1000
     */
1001
    private function _incompatible_addon_error()
1002
    {
1003
        // get array of classes hooking into here
1004
        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
1005
            'AHEE__EE_System__register_shortcodes_modules_and_addons'
1006
        );
1007
        if (! empty($class_names)) {
1008
            $msg = __(
1009
                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1010
                'event_espresso'
1011
            );
1012
            $msg .= '<ul>';
1013
            foreach ($class_names as $class_name) {
1014
                $msg .= '<li><b>Event Espresso - '
1015
                        . str_replace(
1016
                            array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1017
                            '',
1018
                            $class_name
1019
                        ) . '</b></li>';
1020
            }
1021
            $msg .= '</ul>';
1022
            $msg .= __(
1023
                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1024
                'event_espresso'
1025
            );
1026
            // save list of incompatible addons to wp-options for later use
1027
            add_option('ee_incompatible_addons', $class_names, '', 'no');
1028
            if (is_admin()) {
1029
                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1030
            }
1031
        }
1032
    }
1033
1034
1035
    /**
1036
     * brew_espresso
1037
     * begins the process of setting hooks for initializing EE in the correct order
1038
     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1039
     * which runs during the WP 'plugins_loaded' action at priority 9
1040
     *
1041
     * @return void
1042
     * @throws Exception
1043
     */
1044
    public function brew_espresso()
1045
    {
1046
        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1047
        // load some final core systems
1048
        add_action('init', array($this, 'set_hooks_for_core'), 1);
1049
        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1050
        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1051
        add_action('init', array($this, 'load_controllers'), 7);
1052
        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1053
        add_action('init', array($this, 'initialize'), 10);
1054
        add_action('init', array($this, 'initialize_last'), 100);
1055
        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1056
            // pew pew pew
1057
            $this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1058
            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1059
        }
1060
        $this->loadWpGraphql();
1061
        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1062
    }
1063
1064
1065
    /**
1066
     * @return void
1067
     * @throws Exception
1068
     */
1069
    public function loadWpGraphql()
1070
    {
1071
        if (PHP_VERSION_ID < 70000) {
1072
            return;
1073
        }
1074
        // @todo get rid of this.
1075
        $thisIsTemporarilyHereForTests = true;
1076
        try {
1077
            if ($this->request->isGQL()
1078
                || (
1079
                    $this->route_manager instanceof RouteMatchSpecificationManager
1080
                    && $this->route_manager->routeMatchesCurrentRequest(
1081
                        'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoEventEditor'
1082
                    )
1083
                )
1084
                || $thisIsTemporarilyHereForTests
1085
            ) {
1086
                if (! class_exists('WPGraphQL')) {
1087
                    require_once EE_THIRD_PARTY . 'wp-graphql/wp-graphql.php';
1088
                }
1089
                // load handler for EE GraphQL requests
1090
                $graphQL_manager = $this->loader->getShared(
1091
                    'EventEspresso\core\services\graphql\GraphQLManager'
1092
                );
1093
                $graphQL_manager->init();
1094
            }
1095
        } catch (Exception $exception) {
1096
            new ExceptionStackTraceDisplay($exception);
1097
        }
1098
    }
1099
1100
1101
    /**
1102
     *    set_hooks_for_core
1103
     *
1104
     * @access public
1105
     * @return    void
1106
     * @throws EE_Error
1107
     */
1108
    public function set_hooks_for_core()
1109
    {
1110
        $this->_deactivate_incompatible_addons();
1111
        do_action('AHEE__EE_System__set_hooks_for_core');
1112
        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1113
        // caps need to be initialized on every request so that capability maps are set.
1114
        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1115
        $this->registry->CAP->init_caps();
1116
    }
1117
1118
1119
    /**
1120
     * Using the information gathered in EE_System::_incompatible_addon_error,
1121
     * deactivates any addons considered incompatible with the current version of EE
1122
     */
1123
    private function _deactivate_incompatible_addons()
1124
    {
1125
        $incompatible_addons = get_option('ee_incompatible_addons', array());
1126
        if (! empty($incompatible_addons)) {
1127
            $active_plugins = get_option('active_plugins', array());
1128
            foreach ($active_plugins as $active_plugin) {
1129
                foreach ($incompatible_addons as $incompatible_addon) {
1130
                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1131
                        unset($_GET['activate']);
1132
                        espresso_deactivate_plugin($active_plugin);
1133
                    }
1134
                }
1135
            }
1136
        }
1137
    }
1138
1139
1140
    /**
1141
     *    perform_activations_upgrades_and_migrations
1142
     *
1143
     * @access public
1144
     * @return    void
1145
     */
1146
    public function perform_activations_upgrades_and_migrations()
1147
    {
1148
        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1149
    }
1150
1151
1152
    /**
1153
     * @return void
1154
     * @throws DomainException
1155
     */
1156
    public function load_CPTs_and_session()
1157
    {
1158
        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1159
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies $register_custom_taxonomies */
1160
        $register_custom_taxonomies = $this->loader->getShared(
1161
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
1162
        );
1163
        $register_custom_taxonomies->registerCustomTaxonomies();
1164
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes $register_custom_post_types */
1165
        $register_custom_post_types = $this->loader->getShared(
1166
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
1167
        );
1168
        $register_custom_post_types->registerCustomPostTypes();
1169
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms */
1170
        $register_custom_taxonomy_terms = $this->loader->getShared(
1171
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
1172
        );
1173
        $register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1174
        // load legacy Custom Post Types and Taxonomies
1175
        $this->loader->getShared('EE_Register_CPTs');
1176
        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1177
    }
1178
1179
1180
    /**
1181
     * load_controllers
1182
     * this is the best place to load any additional controllers that needs access to EE core.
1183
     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1184
     * time
1185
     *
1186
     * @access public
1187
     * @return void
1188
     */
1189
    public function load_controllers()
1190
    {
1191
        do_action('AHEE__EE_System__load_controllers__start');
1192
        // let's get it started
1193
        if (! $this->maintenance_mode->level()
1194
            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1195
        ) {
1196
            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1197
            $this->loader->getShared('EE_Front_Controller');
1198
        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1199
            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1200
            $this->loader->getShared('EE_Admin');
1201
        } elseif ($this->request->isWordPressHeartbeat()) {
1202
            $this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1203
        }
1204
        do_action('AHEE__EE_System__load_controllers__complete');
1205
    }
1206
1207
1208
    /**
1209
     * core_loaded_and_ready
1210
     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1211
     *
1212
     * @access public
1213
     * @return void
1214
     * @throws Exception
1215
     */
1216
    public function core_loaded_and_ready()
1217
    {
1218
        if ($this->request->isAdmin()
1219
            || $this->request->isFrontend()
1220
            || $this->request->isIframe()
1221
            || $this->request->isWordPressApi()
1222
        ) {
1223
            try {
1224
                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1225
                $this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1226
                if ($this->canLoadBlocks()) {
1227
                    $this->loader->getShared(
1228
                        'EventEspresso\core\services\editor\BlockRegistrationManager'
1229
                    );
1230
                }
1231
            } catch (Exception $exception) {
1232
                new ExceptionStackTraceDisplay($exception);
1233
            }
1234
        }
1235
        if ($this->request->isAdmin()
1236
            || $this->request->isEeAjax()
1237
            || $this->request->isFrontend()
1238
        ) {
1239
            $this->loader->getShared('EE_Session');
1240
        }
1241
        // integrate WP_Query with the EE models
1242
        $this->loader->getShared('EE_CPT_Strategy');
1243
        do_action('AHEE__EE_System__core_loaded_and_ready');
1244
        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1245
        // builders require these even on the front-end
1246
        require_once EE_PUBLIC . 'template_tags.php';
1247
        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1248
    }
1249
1250
1251
    /**
1252
     * initialize
1253
     * this is the best place to begin initializing client code
1254
     *
1255
     * @access public
1256
     * @return void
1257
     */
1258
    public function initialize()
1259
    {
1260
        do_action('AHEE__EE_System__initialize');
1261
    }
1262
1263
1264
    /**
1265
     * initialize_last
1266
     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1267
     * initialize has done so
1268
     *
1269
     * @access public
1270
     * @return void
1271
     */
1272
    public function initialize_last()
1273
    {
1274
        do_action('AHEE__EE_System__initialize_last');
1275
        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1276
        $rewrite_rules = $this->loader->getShared(
1277
            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1278
        );
1279
        $rewrite_rules->flushRewriteRules();
1280
        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1281
        if (($this->request->isAjax() || $this->request->isAdmin())
1282
            && $this->maintenance_mode->models_can_query()) {
1283
            $this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1284
            $this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1285
        }
1286
    }
1287
1288
1289
    /**
1290
     * @return void
1291
     * @throws EE_Error
1292
     */
1293
    public function addEspressoToolbar()
1294
    {
1295
        $this->loader->getShared(
1296
            'EventEspresso\core\domain\services\admin\AdminToolBar',
1297
            array($this->registry->CAP)
1298
        );
1299
    }
1300
1301
1302
    /**
1303
     * do_not_cache
1304
     * sets no cache headers and defines no cache constants for WP plugins
1305
     *
1306
     * @access public
1307
     * @return void
1308
     */
1309
    public static function do_not_cache()
1310
    {
1311
        // set no cache constants
1312
        if (! defined('DONOTCACHEPAGE')) {
1313
            define('DONOTCACHEPAGE', true);
1314
        }
1315
        if (! defined('DONOTCACHCEOBJECT')) {
1316
            define('DONOTCACHCEOBJECT', true);
1317
        }
1318
        if (! defined('DONOTCACHEDB')) {
1319
            define('DONOTCACHEDB', true);
1320
        }
1321
        // add no cache headers
1322
        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1323
        // plus a little extra for nginx and Google Chrome
1324
        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1325
        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1326
        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1327
    }
1328
1329
1330
    /**
1331
     *    extra_nocache_headers
1332
     *
1333
     * @access    public
1334
     * @param $headers
1335
     * @return    array
1336
     */
1337
    public static function extra_nocache_headers($headers)
1338
    {
1339
        // for NGINX
1340
        $headers['X-Accel-Expires'] = 0;
1341
        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1342
        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1343
        return $headers;
1344
    }
1345
1346
1347
    /**
1348
     *    nocache_headers
1349
     *
1350
     * @access    public
1351
     * @return    void
1352
     */
1353
    public static function nocache_headers()
1354
    {
1355
        nocache_headers();
1356
    }
1357
1358
1359
    /**
1360
     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1361
     * never returned with the function.
1362
     *
1363
     * @param  array $exclude_array any existing pages being excluded are in this array.
1364
     * @return array
1365
     */
1366
    public function remove_pages_from_wp_list_pages($exclude_array)
1367
    {
1368
        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1369
    }
1370
1371
1372
    /**
1373
     * Return whether blocks can be registered/loaded or not.
1374
     * @return bool
1375
     */
1376
    private function canLoadBlocks()
1377
    {
1378
        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1379
               && function_exists('register_block_type')
1380
               // don't load blocks if in the Divi page builder editor context
1381
               // @see https://github.com/eventespresso/event-espresso-core/issues/814
1382
               && ! $this->request->getRequestParam('et_fb', false);
1383
    }
1384
}
1385