diff --git a/admin_pages/messages/Messages_Admin_Page.core.php b/admin_pages/messages/Messages_Admin_Page.core.php index 8c03283c028..e2760ab3620 100644 --- a/admin_pages/messages/Messages_Admin_Page.core.php +++ b/admin_pages/messages/Messages_Admin_Page.core.php @@ -990,7 +990,7 @@ public function load_scripts_styles_settings() [], EVENT_ESPRESSO_VERSION ); - wp_enqueue_style('ee-text-links'); + wp_enqueue_style('ee-text-links-css'); wp_enqueue_style('ee-message-settings'); wp_enqueue_script('ee-messages-settings'); } diff --git a/admin_pages/payments/Payments_Admin_Page.core.php b/admin_pages/payments/Payments_Admin_Page.core.php index 93d267172da..26e11a2117a 100644 --- a/admin_pages/payments/Payments_Admin_Page.core.php +++ b/admin_pages/payments/Payments_Admin_Page.core.php @@ -242,6 +242,7 @@ public function load_scripts_styles() { // styles wp_enqueue_style('espresso-ui-theme'); + wp_enqueue_style('ee-text-links-css'); wp_register_style( 'espresso_payments', EE_PAYMENTS_ASSETS_URL . 'ee-payments.css', @@ -250,7 +251,7 @@ public function load_scripts_styles() ); // scripts wp_enqueue_script('ee_admin_js'); - wp_enqueue_script('ee-text-links'); + wp_enqueue_script('ee-text-links-js'); wp_enqueue_script( 'espresso_payments', EE_PAYMENTS_ASSETS_URL . 'espresso_payments_admin.js', @@ -264,7 +265,7 @@ public function load_scripts_styles() public function load_scripts_styles_default() { wp_enqueue_style('espresso_payments'); - wp_enqueue_style('ee-text-links'); + wp_enqueue_style('ee-text-links-css'); } diff --git a/core/EE_Dependency_Map.core.php b/core/EE_Dependency_Map.core.php index 257795f4281..d5b32d30562 100644 --- a/core/EE_Dependency_Map.core.php +++ b/core/EE_Dependency_Map.core.php @@ -485,6 +485,9 @@ protected function _register_core_dependencies() 'EventEspresso\core\services\session\SessionStartHandler' => EE_Dependency_Map::load_from_cache, 'EE_Encryption' => EE_Dependency_Map::load_from_cache, ], + 'EventEspresso\core\services\session\SessionStartHandler' => [ + 'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache, + ], 'EE_Cart' => [ 'EE_Session' => EE_Dependency_Map::load_from_cache, ], diff --git a/core/EE_Registry.core.php b/core/EE_Registry.core.php index b2280358c51..20c1a9601a3 100644 --- a/core/EE_Registry.core.php +++ b/core/EE_Registry.core.php @@ -1020,12 +1020,12 @@ public function clear_cached_class( ): bool { $class_abbreviation = $this->get_class_abbreviation($class_name); // check if class has already been loaded, and return it if it has been - if (isset($this->{$class_abbreviation})) { + if (isset($this->{$class_abbreviation}) && ! $this->{$class_abbreviation} instanceof InterminableInterface) { $this->{$class_abbreviation} = null; return true; } $class_name = str_replace('\\', '_', $class_name); - if (isset($this->{$class_name})) { + if (isset($this->{$class_name}) && ! $this->{$class_name} instanceof InterminableInterface) { $this->{$class_name} = null; return true; } @@ -1033,9 +1033,12 @@ public function clear_cached_class( $this->addons->remove($class_name); return true; } - $class_name = $this->object_identifier->getIdentifier($class_name, $arguments); - if ($this->LIB->has($class_name)) { - $this->LIB->remove($class_name); + $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments); + if ( + $this->LIB->has($object_identifier) + && ! $this->LIB->get($object_identifier) instanceof InterminableInterface + ) { + $this->LIB->remove($object_identifier); return true; } return false; @@ -1382,9 +1385,7 @@ protected function _resolve_dependencies( $param_class = str_replace(' ', '_', $param_class); } // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime) - $param_class = $this->class_cache->isAlias($param_class, $class_name) - ? $this->class_cache->getFqnForAlias($param_class, $class_name) - : $param_class; + $param_class = $this->class_cache->getFqnForAlias($param_class, $class_name); if ( // param is not even a class ($param_class === null || $this->parameterIsPrimitive($param_class)) @@ -1498,7 +1499,7 @@ protected function _resolve_dependency(string $class_name, string $param_class, * in the EE_Dependency_Map::$_class_loaders array, * including the class prefix, ie: "EE_", "EEM_", "EEH_", etc * @param array $arguments - * @return object + * @return mixed */ public static function factory(string $classname, array $arguments = []) { @@ -1522,6 +1523,10 @@ public static function factory(string $classname, array $arguments = []) public function getAddon(string $class_name): ?EE_Addon { $class_name = str_replace('\\', '_', $class_name); + $addon = $this->_get_cached_class($class_name); + if ($addon) { + return $addon; + } return $this->addons->{$class_name} ?? null; } @@ -1648,28 +1653,59 @@ public function reset_model(string $model_name): ?EEM_Base * @return EE_Registry * @throws EE_Error * @throws ReflectionException + * @throws InvalidArgumentException */ public static function reset(bool $hard = false, bool $reinstantiate = true, bool $reset_models = true): EE_Registry { - $instance = self::instance(); - $instance->_cache_on = true; - // reset some "special" classes - EEH_Activation::reset(); - $hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard); - $instance->CFG = EE_Config::reset($hard, $reinstantiate); - $instance->CART = null; - $instance->MRM = null; - // messages reset - EED_Messages::reset(); - // handle of objects cached on LIB - foreach (['LIB', 'modules'] as $cache) { - foreach ($instance->{$cache} as $class_name => $class) { - if (self::_reset_and_unset_object($class, $reset_models)) { - unset($instance->{$cache}->{$class_name}); + $hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard); + $cached_properties = [ + 'BUS', + 'CART', + 'CFG', + 'LIB', + 'MRM', + 'REQ', + 'SSN', + 'AssetsRegistry', + // 'addons', + // 'models', + 'modules', + 'shortcodes', + 'widgets', + ]; + foreach ($cached_properties as $cached_property) { + // if (EE_UnitTestCase::$debug) { + // echo "\n\n" . __LINE__ . ') ' . strtoupper($cached_property); + // } + if ( + ! property_exists(self::$_instance, $cached_property) + || ! isset(self::$_instance->{$cached_property}) + ) { + continue; + } + $cached = self::$_instance->{$cached_property}; + if (is_array($cached) || $cached instanceof RegistryContainer) { + foreach ($cached as $class_name => $class) { + if (self::_reset_object($class_name, $class, $reset_models, $hard, $reinstantiate)) { + // because unset() doesn't guarantee object destruction + self::$_instance->{$cached_property}->{$class_name} = null; + unset(self::$_instance->{$cached_property}->{$class_name}); + } + } + continue; + } + if (is_object($cached)) { + if (self::_reset_object(get_class($cached), $cached, $reset_models, $hard, $reinstantiate)) { + // because unset() doesn't guarantee object destruction + self::$_instance->{$cached_property} = null; + unset(self::$_instance->{$cached_property}); } } } - return $instance; + // if (EE_UnitTestCase::$debug) { + // echo "\n\n"; + // } + return self::$_instance; } @@ -1678,37 +1714,82 @@ public static function reset(bool $hard = false, bool $reinstantiate = true, boo * if passed object implements InterminableInterface, then return false, * to indicate that it should NOT be cleared from the Registry cache * - * @param $object - * @param bool $reset_models + * @param string $class_name + * @param $object + * @param bool $reset_models + * @param bool $hard + * @param bool $reinstantiate * @return bool returns true if cached object should be unset * @throws EE_Error * @throws ReflectionException */ - private static function _reset_and_unset_object($object, bool $reset_models): bool - { + private static function _reset_object( + string $class_name, + $object, + bool $reset_models, + bool $hard, + bool $reinstantiate + ): bool { + // if (EE_UnitTestCase::$debug) { + // echo "\n\n - reset $class_name"; + // } if (! is_object($object)) { + // if (EE_UnitTestCase::$debug) { + // echo "\n --> not an object"; + // } // don't unset anything that's not an object return false; } + if ($object instanceof InterminableInterface) { + // if (EE_UnitTestCase::$debug) { + // echo "\n --> NO (interminable)"; + // } + // don't unset anything that's not terminable + return false; + } if ($object instanceof EED_Module) { $object::reset(); + // if (EE_UnitTestCase::$debug) { + // echo "\n --> NO (module)"; + // } // don't unset modules return false; } if ($object instanceof ResettableInterface) { + // reset some "special" classes + if ($object instanceof EE_Config) { + EE_Config::reset($hard, $reinstantiate); + // if (EE_UnitTestCase::$debug) { + // echo "\n --> NO (config)"; + // } + return false; + } + if ($object instanceof EEH_Activation) { + EEH_Activation::reset(); + // if (EE_UnitTestCase::$debug) { + // echo "\n --> NO (activation)"; + // } + return false; + } if ($object instanceof EEM_Base) { if ($reset_models) { - $object->reset(); - return true; + self::$_instance->reset_model($class_name); } return false; } - $object->reset(); - return true; - } - if (! $object instanceof InterminableInterface) { - return true; + if (method_exists($object, 'reset') && is_callable([$object, 'reset'])) { + // if (EE_UnitTestCase::$debug) { + // echo "\n --> NO (has reset)"; + // } + $object->reset(); + return false; + } } + // if (EE_UnitTestCase::$debug) { + // echo "\n --> YES ??? " . get_class($object); + // } + // at least clear object from cache + self::$_instance->clear_cached_class(get_class($object)); return false; } diff --git a/core/EE_Session.core.php b/core/EE_Session.core.php index 74b7919eb10..8f51842ef15 100644 --- a/core/EE_Session.core.php +++ b/core/EE_Session.core.php @@ -23,18 +23,19 @@ */ class EE_Session implements SessionIdentifierInterface { - const session_id_prefix = 'ee_ssn_'; + const session_id_prefix = 'ee_ssn_'; - const hash_check_prefix = 'ee_shc_'; + const hash_check_prefix = 'ee_shc_'; const OPTION_NAME_SETTINGS = 'ee_session_settings'; - const STATUS_CLOSED = 0; + const STATUS_CLOSED = 0; - const STATUS_OPEN = 1; + const STATUS_OPEN = 1; - const SAVE_STATE_CLEAN = 'clean'; - const SAVE_STATE_DIRTY = 'dirty'; + const SAVE_STATE_CLEAN = 'clean'; + + const SAVE_STATE_DIRTY = 'dirty'; /** @@ -78,7 +79,7 @@ class EE_Session implements SessionIdentifierInterface * * @var array */ - private $_session_data = array(); + private $_session_data = []; /** * how long an EE session lasts @@ -142,7 +143,7 @@ class EE_Session implements SessionIdentifierInterface * * @var array */ - private $_default_session_vars = array( + private $_default_session_vars = [ 'id' => null, 'user_id' => null, 'ip_address' => null, @@ -150,8 +151,8 @@ class EE_Session implements SessionIdentifierInterface 'init_access' => null, 'last_access' => null, 'expiration' => null, - 'pages_visited' => array(), - ); + 'pages_visited' => [], + ]; /** * timestamp for when last garbage collection cycle was performed @@ -182,15 +183,12 @@ class EE_Session implements SessionIdentifierInterface /** * @singleton method used to instantiate class object - * @param CacheStorageInterface $cache_storage - * @param SessionLifespan|null $lifespan - * @param RequestInterface $request - * @param SessionStartHandler $session_start_handler - * @param EE_Encryption $encryption - * @return EE_Session - * @throws InvalidArgumentException - * @throws InvalidDataTypeException - * @throws InvalidInterfaceException + * @param CacheStorageInterface|null $cache_storage + * @param SessionLifespan|null $lifespan + * @param RequestInterface|null $request + * @param SessionStartHandler|null $session_start_handler + * @param EE_Encryption|null $encryption + * @return EE_Session|null */ public static function instance( CacheStorageInterface $cache_storage = null, @@ -198,7 +196,7 @@ public static function instance( RequestInterface $request = null, SessionStartHandler $session_start_handler = null, EE_Encryption $encryption = null - ) { + ): ?EE_Session { // check if class object is instantiated // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via: // add_filter( 'FHEE_load_EE_Session', '__return_false' ); @@ -229,10 +227,7 @@ public static function instance( * @param SessionLifespan $lifespan * @param RequestInterface $request * @param SessionStartHandler $session_start_handler - * @param EE_Encryption $encryption - * @throws InvalidArgumentException - * @throws InvalidDataTypeException - * @throws InvalidInterfaceException + * @param EE_Encryption|null $encryption */ protected function __construct( CacheStorageInterface $cache_storage, @@ -249,18 +244,18 @@ protected function __construct( return; } $this->session_start_handler = $session_start_handler; - $this->session_lifespan = $lifespan; - $this->request = $request; + $this->session_lifespan = $lifespan; + $this->request = $request; if (! defined('ESPRESSO_SESSION')) { define('ESPRESSO_SESSION', true); } // retrieve session options from db - $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array()); + $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, []); if (! empty($session_settings)) { // cycle though existing session options foreach ($session_settings as $var_name => $session_setting) { // set values for class properties - $var_name = '_' . $var_name; + $var_name = '_' . $var_name; $this->{$var_name} = $session_setting; } } @@ -271,16 +266,15 @@ protected function __construct( // encrypt data via: $this->encryption->encrypt(); $this->encryption = $encryption; // filter hook allows outside functions/classes/plugins to change default empty cart - $extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array()); - array_merge($this->_default_session_vars, $extra_default_session_vars); + $this->_default_session_vars += apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', []); // apply default session vars $this->_set_defaults(); - add_action('AHEE__EE_System__initialize', array($this, 'open_session')); + add_action('AHEE__EE_System__initialize', [$this, 'open_session']); // check request for 'clear_session' param - add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded')); + add_action('AHEE__EE_Request_Handler__construct__complete', [$this, 'wp_loaded']); // once everything is all said and done, - add_action('shutdown', array($this, 'update'), 100); - add_action('shutdown', array($this, 'garbageCollection'), 1000); + add_action('shutdown', [$this, 'update'], 100); + add_action('shutdown', [$this, 'garbageCollection'], 1000); $this->configure_garbage_collection_filters(); } @@ -291,7 +285,7 @@ protected function __construct( * @throws InvalidDataTypeException * @throws InvalidInterfaceException */ - public static function isLoadedAndActive() + public static function isLoadedAndActive(): bool { return did_action('AHEE__EE_System__core_loaded_and_ready') && EE_Session::instance() instanceof EE_Session @@ -302,7 +296,7 @@ public static function isLoadedAndActive() /** * @return bool */ - public function isActive() + public function isActive(): bool { return $this->status === EE_Session::STATUS_OPEN; } @@ -331,7 +325,7 @@ public function open_session() /** * @return bool */ - public function expired() + public function expired(): bool { return $this->_expired; } @@ -349,7 +343,7 @@ public function reset_expired() /** * @return int */ - public function expiration() + public function expiration(): int { return $this->_expiration; } @@ -358,7 +352,7 @@ public function expiration() /** * @return int */ - public function extension() + public function extension(): int { return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS); } @@ -367,9 +361,9 @@ public function extension() /** * @param int $time number of seconds to add to session expiration */ - public function extend_expiration($time = 0) + public function extend_expiration(int $time = 0) { - $time = $time ? $time : $this->extension(); + $time = $time ?: $this->extension(); $this->_expiration += absint($time); } @@ -377,7 +371,7 @@ public function extend_expiration($time = 0) /** * @return int */ - public function lifespan() + public function lifespan(): int { return $this->session_lifespan->inSeconds(); } @@ -392,7 +386,7 @@ public function lifespan() * * @param string $save_state */ - public function setSaveState($save_state = EE_Session::SAVE_STATE_DIRTY) + public function setSaveState(string $save_state = EE_Session::SAVE_STATE_DIRTY) { $valid_save_states = [ EE_Session::SAVE_STATE_CLEAN, @@ -405,7 +399,6 @@ public function setSaveState($save_state = EE_Session::SAVE_STATE_DIRTY) } - /** * This just sets some defaults for the _session data property * @@ -416,7 +409,7 @@ private function _set_defaults() // set some defaults foreach ($this->_default_session_vars as $key => $default_var) { if (is_array($default_var)) { - $this->_session_data[ $key ] = array(); + $this->_session_data[ $key ] = []; } else { $this->_session_data[ $key ] = ''; } @@ -428,17 +421,17 @@ private function _set_defaults() * @retrieve session data * @return string */ - public function id() + public function id(): string { return $this->_sid; } /** - * @param \EE_Cart $cart + * @param EE_Cart $cart * @return bool */ - public function set_cart(EE_Cart $cart) + public function set_cart(EE_Cart $cart): bool { $this->_session_data['cart'] = $cart; $this->setSaveState(); @@ -458,9 +451,9 @@ public function reset_cart() /** - * @return \EE_Cart + * @return EE_Cart */ - public function cart() + public function cart(): ?EE_Cart { return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart ? $this->_session_data['cart'] @@ -469,10 +462,10 @@ public function cart() /** - * @param \EE_Checkout $checkout + * @param EE_Checkout $checkout * @return bool */ - public function set_checkout(EE_Checkout $checkout) + public function set_checkout(EE_Checkout $checkout): bool { $this->_session_data['checkout'] = $checkout; $this->setSaveState(); @@ -492,9 +485,9 @@ public function reset_checkout() /** - * @return \EE_Checkout + * @return EE_Checkout */ - public function checkout() + public function checkout(): ?EE_Checkout { return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout ? $this->_session_data['checkout'] @@ -503,11 +496,12 @@ public function checkout() /** - * @param \EE_Transaction $transaction + * @param EE_Transaction $transaction * @return bool * @throws EE_Error + * @throws ReflectionException */ - public function set_transaction(EE_Transaction $transaction) + public function set_transaction(EE_Transaction $transaction): bool { // first remove the session from the transaction before we save the transaction in the session $transaction->set_txn_session_data(null); @@ -529,9 +523,9 @@ public function reset_transaction() /** - * @return \EE_Transaction + * @return EE_Transaction */ - public function transaction() + public function transaction(): ?EE_Transaction { return isset($this->_session_data['transaction']) && $this->_session_data['transaction'] instanceof EE_Transaction @@ -545,9 +539,9 @@ public function transaction() * * @param null $key * @param bool $reset_cache - * @return array + * @return mixed */ - public function get_session_data($key = null, $reset_cache = false) + public function get_session_data($key = null, bool $reset_cache = false) { if ($reset_cache) { $this->reset_cart(); @@ -555,7 +549,7 @@ public function get_session_data($key = null, $reset_cache = false) $this->reset_transaction(); } if (! empty($key)) { - return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null; + return $this->_session_data[ $key ] ?? null; } return $this->_session_data; } @@ -564,10 +558,10 @@ public function get_session_data($key = null, $reset_cache = false) /** * Returns TRUE on success, FALSE on fail * - * @param array $data + * @param array|null $data * @return bool */ - public function set_session_data($data) + public function set_session_data(?array $data): bool { // nothing ??? bad data ??? go home! if (empty($data) || ! is_array($data)) { @@ -616,7 +610,7 @@ public function set_session_data($data) * @throws RuntimeException * @throws ReflectionException */ - private function _espresso_session() + private function _espresso_session(): bool { do_action('AHEE_log', __FILE__, __FUNCTION__, ''); $this->session_start_handler->startSession(); @@ -633,9 +627,7 @@ private function _espresso_session() // get the current time in UTC $this->_time = $this->_time !== null ? $this->_time : time(); // and reset the session expiration - $this->_expiration = isset($session_data['expiration']) - ? $session_data['expiration'] - : $this->_time + $this->session_lifespan->inSeconds(); + $this->_expiration = $session_data['expiration'] ?? $this->_time + $this->session_lifespan->inSeconds(); } else { // set initial site access time and the session expiration $this->_set_init_access_and_expiration(); @@ -675,15 +667,16 @@ private function _espresso_session() * @throws InvalidDataTypeException * @throws InvalidInterfaceException * @throws RuntimeException + * @throws ReflectionException */ - protected function _retrieve_session_data() + protected function _retrieve_session_data(): array { $ssn_key = EE_Session::session_id_prefix . $this->_sid; try { // we're using WP's Transient API to store session data using the PHP session ID as the option name $session_data = $this->cache_storage->get($ssn_key, false); if (empty($session_data)) { - return array(); + return []; } if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) { $hash_check = $this->cache_storage->get( @@ -708,7 +701,7 @@ protected function _retrieve_session_data() } catch (Exception $e) { // let's just eat that error for now and attempt to correct any corrupted data global $wpdb; - $row = $wpdb->get_row( + $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1", '_transient_' . $ssn_key @@ -781,7 +774,7 @@ function ($match) { * * @return string */ - protected function _generate_session_id() + protected function _generate_session_id(): string { // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length $session_id = $this->request->requestParamIsSet('EESID') @@ -792,11 +785,9 @@ protected function _generate_session_id() /** - * _get_sid_salt - * * @return string */ - protected function _get_sid_salt() + protected function _get_sid_salt(): string { // was session id salt already saved to db ? if (empty($this->_sid_salt)) { @@ -810,20 +801,18 @@ protected function _get_sid_salt() $this->_sid_salt = wp_generate_password(64); } // and save it as a permanent session setting - $this->updateSessionSettings(array('sid_salt' => $this->_sid_salt)); + $this->updateSessionSettings(['sid_salt' => $this->_sid_salt]); } return $this->_sid_salt; } /** - * _set_init_access_and_expiration - * * @return void */ protected function _set_init_access_and_expiration() { - $this->_time = time(); + $this->_time = time(); $this->_expiration = $this->_time + $this->session_lifespan->inSeconds(); // set initial site access time $this->_session_data['init_access'] = $this->_time; @@ -842,15 +831,15 @@ protected function _set_init_access_and_expiration() * @throws InvalidInterfaceException * @throws ReflectionException */ - public function update($new_session = false) + public function update(bool $new_session = false): bool { $this->_session_data = is_array($this->_session_data) && isset($this->_session_data['id']) ? $this->_session_data - : array(); + : []; if (empty($this->_session_data)) { $this->_set_defaults(); } - $session_data = array(); + $session_data = []; foreach ($this->_session_data as $key => $value) { switch ($key) { case 'id': @@ -925,13 +914,15 @@ private function _create_espresso_session() $this->update(true); } + /** * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good * too). This is used when determining if we want to save the session or not. - * @since 4.9.67.p + * * @return bool + * @since 4.9.67.p */ - private function sessionHasStuffWorthSaving() + private function sessionHasStuffWorthSaving(): bool { return $this->save_state === EE_Session::SAVE_STATE_DIRTY // we may want to eventually remove the following @@ -959,7 +950,7 @@ private function sessionHasStuffWorthSaving() * @throws InvalidInterfaceException * @throws ReflectionException */ - private function _save_session_to_db($clear_session = false) + private function _save_session_to_db(bool $clear_session = false): bool { // don't save sessions for crawlers // and unless we're deleting the session data, don't save anything if there isn't a cart @@ -1009,17 +1000,17 @@ private function _save_session_to_db($clear_session = false) * @get the full page request the visitor is accessing * @return string */ - public function _get_page_visit() + public function _get_page_visit(): string { $page_visit = home_url('/') . 'wp-admin/admin-ajax.php'; // check for request url if ($this->request->serverParamIsSet('REQUEST_URI')) { - $page_id = '?'; - $e_reg = ''; + $page_id = '?'; + $e_reg = ''; $request_uri = $this->request->getServerParam('REQUEST_URI'); - $ru_bits = explode('?', $request_uri); + $ru_bits = explode('?', $request_uri); $request_uri = $ru_bits[0]; - $http_host = $this->request->getServerParam('HTTP_HOST'); + $http_host = $this->request->getServerParam('HTTP_HOST'); // check for page_id in SERVER REQUEST if ($this->request->requestParamIsSet('page_id')) { // rebuild $e_reg without any of the extra parameters @@ -1040,7 +1031,7 @@ public function _get_page_visit() * @the current wp user id * @return int */ - public function _wp_user_id() + public function _wp_user_id(): ?int { // if I need to explain the following lines of code, then you shouldn't be looking at this! $this->_wp_user_id = get_current_user_id(); @@ -1060,13 +1051,13 @@ public function _wp_user_id() * @throws InvalidInterfaceException * @throws ReflectionException */ - public function clear_session($class = '', $function = '') + public function clear_session(string $class = '', string $function = '') { -// echo ' -//

-// ' . __CLASS__ . '::' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )
-// ' . __FILE__ . ' ' . __LINE__ . ' -//

'; + // echo ' + //

+ // ' . __CLASS__ . '::' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )
+ // ' . __FILE__ . ' ' . __LINE__ . ' + //

'; do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()'); $this->reset_cart(); $this->reset_checkout(); @@ -1087,11 +1078,11 @@ public function clear_session($class = '', $function = '') * @param bool $show_all_notices * @return bool */ - public function reset_data($data_to_reset = array(), $show_all_notices = false) + public function reset_data($data_to_reset = [], bool $show_all_notices = false): bool { // if $data_to_reset is not in an array, then put it in one if (! is_array($data_to_reset)) { - $data_to_reset = array($data_to_reset); + $data_to_reset = [$data_to_reset]; } // nothing ??? go home! if (empty($data_to_reset)) { @@ -1186,12 +1177,12 @@ public function wp_loaded() /** * Used to reset the entire object (for tests). * - * @since 4.3.0 * @throws EE_Error * @throws InvalidDataTypeException * @throws InvalidInterfaceException * @throws InvalidArgumentException * @throws ReflectionException + * @since 4.3.0 */ public function reset_instance() { @@ -1230,7 +1221,7 @@ function () use ($expired_session_transient_delete_query_limit) { * @param $data1 * @return string */ - private function find_serialize_error($data1) + private function find_serialize_error($data1): string { $error = '
';
         $data2 = preg_replace_callback(
@@ -1246,39 +1237,39 @@ function ($match) {
             },
             $data1
         );
-        $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
+        $max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
         $error .= $data1 . PHP_EOL;
         $error .= $data2 . PHP_EOL;
         for ($i = 0; $i < $max; $i++) {
             if (@$data1[ $i ] !== @$data2[ $i ]) {
-                $error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
-                $error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
-                $error .= "\t-> Line Number = $i" . PHP_EOL;
-                $start = ($i - 20);
-                $start = ($start < 0) ? 0 : $start;
+                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
+                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
+                $error  .= "\t-> Line Number = $i" . PHP_EOL;
+                $start  = ($i - 20);
+                $start  = ($start < 0) ? 0 : $start;
                 $length = 40;
-                $point = $max - $i;
+                $point  = $max - $i;
                 if ($point < 20) {
-                    $rlength = 1;
-                    $rpoint = -$point;
+                    $rLength = 1;
+                    $rPoint  = -$point;
                 } else {
-                    $rpoint = $length - 20;
-                    $rlength = 1;
+                    $rPoint  = $length - 20;
+                    $rLength = 1;
                 }
                 $error .= "\t-> Section Data1  = ";
                 $error .= substr_replace(
                     substr($data1, $start, $length),
                     "{$data1[ $i ]}",
-                    $rpoint,
-                    $rlength
+                    $rPoint,
+                    $rLength
                 );
                 $error .= PHP_EOL;
                 $error .= "\t-> Section Data2  = ";
                 $error .= substr_replace(
                     substr($data2, $start, $length),
                     "{$data2[ $i ]}",
-                    $rpoint,
-                    $rlength
+                    $rPoint,
+                    $rLength
                 );
                 $error .= PHP_EOL;
             }
@@ -1293,10 +1284,10 @@ function ($match) {
      *
      * @param array $updated_settings
      */
-    private function updateSessionSettings(array $updated_settings = array())
+    private function updateSessionSettings(array $updated_settings = [])
     {
         // add existing settings, but only if not included in incoming $updated_settings array
-        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
+        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, []);
         update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
     }
 
@@ -1309,7 +1300,7 @@ public function garbageCollection()
         // only perform during regular requests if last garbage collection was over an hour ago
         if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
             $this->_last_gc = time();
-            $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
+            $this->updateSessionSettings(['last_gc' => $this->_last_gc]);
             /** @type WPDB $wpdb */
             global $wpdb;
             // filter the query limit. Set to 0 to turn off garbage collection
@@ -1321,12 +1312,12 @@ public function garbageCollection()
             );
             // non-zero LIMIT means take out the trash
             if ($expired_session_transient_delete_query_limit) {
-                $session_key = str_replace('_', '\_', EE_Session::session_id_prefix);
+                $session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
                 $hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
                 // since transient expiration timestamps are set in the future, we can compare against NOW
                 // but we only want to pick up any trash that's been around for more than a day
                 $expiration = time() - DAY_IN_SECONDS;
-                $SQL = "
+                $SQL        = "
                     SELECT option_name
                     FROM {$wpdb->options}
                     WHERE
@@ -1342,7 +1333,7 @@ public function garbageCollection()
                 // AND option_value < 1508368198 LIMIT 50
                 $expired_sessions = $wpdb->get_col($SQL);
                 // valid results?
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
+                if (! empty($expired_sessions)) {
                     $this->cache_storage->deleteMany($expired_sessions, true);
                 }
             }
diff --git a/core/db_classes/EE_Base_Class.class.php b/core/db_classes/EE_Base_Class.class.php
index 8e313c0b010..87acd886c3c 100644
--- a/core/db_classes/EE_Base_Class.class.php
+++ b/core/db_classes/EE_Base_Class.class.php
@@ -1848,9 +1848,8 @@ public function save($set_cols_n_values = array())
         // if the object already has an ID, update it. Otherwise, insert it
         // also: change the assumption about values passed to the model NOT being prepare dby the model object.
         // They have been
-        $old_assumption_concerning_value_preparation = $model
-            ->get_assumption_concerning_values_already_prepared_by_model_object();
-        $model->assume_values_already_prepared_by_model_object(true);
+        $old_assumption_concerning_value_preparation = $model->get_assumption_concerning_values_already_prepared_by_model_object();
+        $model->assume_values_already_prepared_by_model_object(EEM_Base::prepared_by_model_object);
         // does this model have an autoincrement PK?
         if ($model->has_primary_key_field()) {
             if ($model->get_primary_key_field()->is_auto_increment()) {
diff --git a/core/db_models/EEM_Base.model.php b/core/db_models/EEM_Base.model.php
index 6e33d961471..2db1361d005 100644
--- a/core/db_models/EEM_Base.model.php
+++ b/core/db_models/EEM_Base.model.php
@@ -45,7 +45,7 @@ abstract class EEM_Base extends EE_Base implements ResettableInterface
      *
      * @var boolean
      */
-    private $_values_already_prepared_by_model_object = 0;
+    private $_values_already_prepared_by_model_object = EEM_Base::not_prepared_by_model_object;
 
     /**
      * when $_values_already_prepared_by_model_object equals this, we assume
@@ -581,6 +581,7 @@ protected function __construct($timezone = null)
         if (empty(EEM_Base::$_model_query_blog_id)) {
             EEM_Base::set_model_query_blog_id();
         }
+        $this->_values_already_prepared_by_model_object = EEM_Base::not_prepared_by_model_object;
         /**
          * Filters the list of tables on a model. It is best to NOT use this directly and instead
          * just use EE_Register_Model_Extension
@@ -1552,9 +1553,10 @@ public function get_formats_for($field_name, $pretty = false)
      *                                 formatted string matching the set format for the field in the set timezone will
      *                                 be returned.
      * @param string $what             Whether to return the string in just the time format, the date format, or both.
-     * @return int|string  If the given field_name is not of the EE_Datetime_Field type, then an EE_Error
+     * @return string  If the given field_name is not of the EE_Datetime_Field type, then an EE_Error
      *                                 exception is triggered.
-     * @throws EE_Error    If the given field_name is not of the EE_Datetime_Field type.
+     * @throws Exception
+     * @throws EE_Error    If the given field_name is not of the EE_Datetime_Field type.*
      * @since 4.6.x
      */
     public function current_time_for_query($field_name, $timestamp = false, $what = 'both')
@@ -1568,13 +1570,10 @@ public function current_time_for_query($field_name, $timestamp = false, $what =
         switch ($what) {
             case 'time':
                 return $DateTime->format($formats[1]);
-                break;
             case 'date':
                 return $DateTime->format($formats[0]);
-                break;
             default:
                 return $DateTime->format(implode(' ', $formats));
-                break;
         }
     }
 
@@ -1835,9 +1834,9 @@ public function get_col($query_params = [], $field_to_select = null)
         } elseif ($this->has_primary_key_field()) {
             $field = $this->get_primary_key_field();
         } else {
-            // no primary key, just grab the first column
             $field_settings = $this->field_settings();
-            $field          = reset($field_settings);
+            // no primary key, just grab the first column
+            $field = reset($field_settings);
         }
         $model_query_info   = $this->_create_model_query_info_carrier($query_params);
         $select_expressions = $field->get_qualified_column();
@@ -2459,7 +2458,6 @@ private function _process_wpdb_query($wpdb_method, $arguments_to_provide)
                 case EEM_Base::db_verified_addons:
                     // ummmm... you in trouble
                     return $result;
-                    break;
             }
             if (! empty($error_message)) {
                 EE_Log::instance()->log(__FILE__, __FUNCTION__, $error_message, 'error');
@@ -2478,6 +2476,7 @@ private function _process_wpdb_query($wpdb_method, $arguments_to_provide)
      * @param string $wpdb_method
      * @param array  $arguments_to_provide
      * @return string
+     * @throws EE_Error
      */
     private function _verify_core_db($wpdb_method, $arguments_to_provide)
     {
@@ -5830,7 +5829,7 @@ public function ensure_is_ID($base_class_obj_or_id)
      * @return void
      */
     public function assume_values_already_prepared_by_model_object(
-        $values_already_prepared = self::not_prepared_by_model_object
+        int $values_already_prepared = self::not_prepared_by_model_object
     ) {
         $this->_values_already_prepared_by_model_object = $values_already_prepared;
     }
diff --git a/core/db_models/EEM_Event.model.php b/core/db_models/EEM_Event.model.php
index 189f4e3005b..0e17ed27c11 100644
--- a/core/db_models/EEM_Event.model.php
+++ b/core/db_models/EEM_Event.model.php
@@ -87,9 +87,10 @@ protected function __construct($timezone = null)
                 ),
             )
         );
-        self::$_default_reg_status = empty(self::$_default_reg_status)
+        self::$_default_reg_status = empty(EE_Registry::instance()->CFG->registration->default_STS_ID)
             ? EEM_Registration::status_id_pending_payment
-            : self::$_default_reg_status;
+            : EE_Registry::instance()->CFG->registration->default_STS_ID;
+
         $this->_tables = array(
             'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
             'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
diff --git a/core/db_models/EEM_Payment.model.php b/core/db_models/EEM_Payment.model.php
index be2de1d2212..06cb4ad3e9d 100644
--- a/core/db_models/EEM_Payment.model.php
+++ b/core/db_models/EEM_Payment.model.php
@@ -1,49 +1,39 @@
 singular_item = esc_html__('Payment', 'event_espresso');
-        $this->plural_item = esc_html__('Payments', 'event_espresso');
-
-        $this->_tables = array(
-            'Payment' => new EE_Primary_Table('esp_payment', 'PAY_ID')
-        );
-        $this->_fields = array(
-            'Payment' => array(
-                'PAY_ID' => new EE_Primary_Key_Int_Field('PAY_ID', esc_html__('Payment ID', 'event_espresso')),
-                'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', esc_html__('Transaction ID', 'event_espresso'), false, 0, 'Transaction'),
-                'STS_ID' => new EE_Foreign_Key_String_Field('STS_ID', esc_html__('Status ID', 'event_espresso'), false, EEM_Payment::status_id_failed, 'Status'),
-                'PAY_timestamp' => new EE_Datetime_Field('PAY_timestamp', esc_html__('Timestamp of when payment was attempted', 'event_espresso'), false, EE_Datetime_Field::now, $timezone),
-                'PAY_source' => new EE_All_Caps_Text_Field('PAY_source', esc_html__('User-friendly description of payment', 'event_espresso'), false, 'CART'),
-                'PAY_amount' => new EE_Money_Field('PAY_amount', esc_html__('Amount Payment should be for', 'event_espresso'), false, 0),
-                'PMD_ID' => new EE_Foreign_Key_Int_Field('PMD_ID', esc_html__("Payment Method ID", 'event_espresso'), false, null, 'Payment_Method'),
-                'PAY_gateway_response' => new EE_Plain_Text_Field('PAY_gateway_response', esc_html__('Response from Gateway about the payment', 'event_espresso'), false, ''),
-                'PAY_txn_id_chq_nmbr' => new EE_Plain_Text_Field('PAY_txn_id_chq_nmbr', esc_html__('Gateway Transaction ID or Cheque Number', 'event_espresso'), true, ''),
-                'PAY_po_number' => new EE_Plain_Text_Field('PAY_po_number', esc_html__('Purchase or Sales Number', 'event_espresso'), true, ''),
-                'PAY_extra_accntng' => new EE_Simple_HTML_Field('PAY_extra_accntng', esc_html__('Extra Account Info', 'event_espresso'), true, ''),
-                'PAY_details' => new EE_Serialized_Text_Field('PAY_details', esc_html__('Full Gateway response about payment', 'event_espresso'), true, ''),
-                'PAY_redirect_url' => new EE_Plain_Text_Field('PAY_redirect_url', esc_html__("Redirect URL", 'event_espresso'), true),
-                'PAY_redirect_args' => new EE_Serialized_Text_Field('PAY_redirect_args', esc_html__("Key-Value POST vars to send along with redirect", 'event_espresso'), true)
-            )
-        );
-        $this->_model_relations = array(
-            'Transaction' => new EE_Belongs_To_Relation(),
-            'Status' => new EE_Belongs_To_Relation(),
-            'Payment_Method' => new EE_Belongs_To_Relation(),
+        $this->plural_item   = esc_html__('Payments', 'event_espresso');
+
+        $this->_tables = [
+            'Payment' => new EE_Primary_Table('esp_payment', 'PAY_ID'),
+        ];
+        $this->_fields = [
+            'Payment' => [
+                'PAY_ID'               => new EE_Primary_Key_Int_Field(
+                    'PAY_ID',
+                    esc_html__('Payment ID', 'event_espresso')
+                ),
+                'TXN_ID'               => new EE_Foreign_Key_Int_Field(
+                    'TXN_ID',
+                    esc_html__('Transaction ID', 'event_espresso'),
+                    false,
+                    0,
+                    'Transaction'
+                ),
+                'STS_ID'               => new EE_Foreign_Key_String_Field(
+                    'STS_ID',
+                    esc_html__('Status ID', 'event_espresso'),
+                    false,
+                    EEM_Payment::status_id_failed,
+                    'Status'
+                ),
+                'PAY_timestamp'        => new EE_Datetime_Field(
+                    'PAY_timestamp',
+                    esc_html__(
+                        'Timestamp of when payment was attempted',
+                        'event_espresso'
+                    ),
+                    false,
+                    EE_Datetime_Field::now,
+                    $timezone
+                ),
+                'PAY_source'           => new EE_All_Caps_Text_Field(
+                    'PAY_source',
+                    esc_html__(
+                        'User-friendly description of payment',
+                        'event_espresso'
+                    ),
+                    false,
+                    'CART'
+                ),
+                'PAY_amount'           => new EE_Money_Field(
+                    'PAY_amount',
+                    esc_html__('Amount Payment should be for', 'event_espresso'),
+                    false
+                ),
+                'PMD_ID'               => new EE_Foreign_Key_Int_Field(
+                    'PMD_ID',
+                    esc_html__("Payment Method ID", 'event_espresso'),
+                    false,
+                    null,
+                    'Payment_Method'
+                ),
+                'PAY_gateway_response' => new EE_Plain_Text_Field(
+                    'PAY_gateway_response',
+                    esc_html__(
+                        'Response from Gateway about the payment',
+                        'event_espresso'
+                    ),
+                    false,
+                    ''
+                ),
+                'PAY_txn_id_chq_nmbr'  => new EE_Plain_Text_Field(
+                    'PAY_txn_id_chq_nmbr',
+                    esc_html__(
+                        'Gateway Transaction ID or Cheque Number',
+                        'event_espresso'
+                    ),
+                    true,
+                    ''
+                ),
+                'PAY_po_number'        => new EE_Plain_Text_Field(
+                    'PAY_po_number',
+                    esc_html__(
+                        'Purchase or Sales Number',
+                        'event_espresso'
+                    ),
+                    true,
+                    ''
+                ),
+                'PAY_extra_accntng'    => new EE_Simple_HTML_Field(
+                    'PAY_extra_accntng',
+                    esc_html__('Extra Account Info', 'event_espresso'),
+                    true,
+                    ''
+                ),
+                'PAY_details'          => new EE_Serialized_Text_Field(
+                    'PAY_details',
+                    esc_html__(
+                        'Full Gateway response about payment',
+                        'event_espresso'
+                    ),
+                    true,
+                    ''
+                ),
+                'PAY_redirect_url'     => new EE_Plain_Text_Field(
+                    'PAY_redirect_url',
+                    esc_html__("Redirect URL", 'event_espresso'),
+                    true
+                ),
+                'PAY_redirect_args'    => new EE_Serialized_Text_Field(
+                    'PAY_redirect_args',
+                    esc_html__(
+                        "Key-Value POST vars to send along with redirect",
+                        'event_espresso'
+                    ),
+                    true
+                ),
+            ],
+        ];
+
+        $this->_model_relations        = [
+            'Transaction'          => new EE_Belongs_To_Relation(),
+            'Status'               => new EE_Belongs_To_Relation(),
+            'Payment_Method'       => new EE_Belongs_To_Relation(),
             'Registration_Payment' => new EE_Has_Many_Relation(),
-            'Registration' => new EE_HABTM_Relation('Registration_Payment'),
-        );
+            'Registration'         => new EE_HABTM_Relation('Registration_Payment'),
+        ];
         $this->_model_chain_to_wp_user = 'Payment_Method';
-        $this->_caps_slug = 'transactions';
+        $this->_caps_slug              = 'transactions';
         parent::__construct($timezone);
     }
 
 
-
-
     /**
      * Gets the payment by the gateway server's unique ID. Eg, the unique ID PayPal assigned
      * to the payment. This is handy for verifying an IPN hasn't already been processed.
+     *
      * @param string $PAY_txn_id_chq_nmbr
-     * @return EE_Payment
+     * @return EE_Payment|null
+     * @throws EE_Error
      */
-    public function get_payment_by_txn_id_chq_nmbr($PAY_txn_id_chq_nmbr)
+    public function get_payment_by_txn_id_chq_nmbr($PAY_txn_id_chq_nmbr): ?EE_Payment
     {
-        return $this->get_one(array(array('PAY_txn_id_chq_nmbr' => $PAY_txn_id_chq_nmbr)));
+        return $this->get_one([['PAY_txn_id_chq_nmbr' => $PAY_txn_id_chq_nmbr]]);
     }
 
 
-
-
     /**
-    *       retrieve  all payments from db for a particular transaction, optionally with
-     *      a particular status
-    *
-    *       @access     public
-    *       @param      $TXN_ID
-     *      @param  string  $status_of_payment one of EEM_Payment::status_id_*, like 'PAP','PCN',etc. If none is provided, gets payments with any status
-    *       @return     EE_Payment[]
-    */
-    public function get_payments_for_transaction($TXN_ID = false, $status_of_payment = null)
+     * retrieve  all payments from db for a particular transaction, optionally with a particular status
+     *
+     * @param int         $TXN_ID
+     * @param string|null $status_of_payment one of EEM_Payment::status_id_*, like 'PAP','PCN',etc. If none is provided,
+     *                                       gets
+     *                                       payments with any status
+     * @return EE_Payment[]
+     * @throws EE_Error
+     */
+    public function get_payments_for_transaction(int $TXN_ID = 0, ?string $status_of_payment = null): array
     {
         // all payments for a TXN ordered chronologically
-        $query_params = array( array( 'TXN_ID' => $TXN_ID ), 'order_by' => array( 'PAY_timestamp' => 'ASC' ));
+        $query_params = [['TXN_ID' => $TXN_ID], 'order_by' => ['PAY_timestamp' => 'ASC']];
         // if provided with a status, search specifically for that status. Otherwise get them all
         if ($status_of_payment) {
             $query_params[0]['STS_ID'] = $status_of_payment;
@@ -135,44 +222,51 @@ public function get_payments_for_transaction($TXN_ID = false, $status_of_payment
     }
 
 
-
     /**
      * Only gets payments which have been approved
+     *
      * @param int $TXN_ID
      * @return EE_Payment[]
+     * @throws EE_Error
      */
-    public function get_approved_payments_for_transaction($TXN_ID = 0)
+    public function get_approved_payments_for_transaction(int $TXN_ID = 0): array
     {
         return $this->get_payments_for_transaction($TXN_ID, EEM_Payment::status_id_approved);
     }
 
 
-
-
-
     /**
      * retrieve  all payments from db between two dates,
      *
-     * @param string $start_date incoming start date. If empty the beginning of today is used.
-     * @param string $end_date   incoming end date. If empty the end of today is used.
-     * @param string $format    If you include $start_date or $end_date then you must include the format string
-     *                              for the format your date is in.
-     * @param string $timezone   If your range is in a different timezone then the current setting on this
+     * @param string $start_date        incoming start date. If empty the beginning of today is used.
+     * @param string $end_date          incoming end date. If empty the end of today is used.
+     * @param string $format            If you include $start_date or $end_date then you must include the format string
+     *                                  for the format your date is in.
+     * @param string $timezone          If your range is in a different timezone then the current setting on this
      *                                  WordPress install, then include it here.
+     * @return EE_Payment[]
      * @throws EE_Error
      *
-     * @return EE_Payment[]
      */
-    public function get_payments_made_between_dates($start_date = '', $end_date = '', $format = '', $timezone = '')
-    {
+    public function get_payments_made_between_dates(
+        string $start_date = '',
+        string $end_date = '',
+        string $format = '',
+        string $timezone = ''
+    ): array {
         $timezone = empty($timezone) ? EEH_DTT_Helper::get_timezone() : $timezone;
         // if $start_date or $end date, verify $format is included.
-        if (( ! empty($start_date) || ! empty($end_date) ) && empty($format)) {
-            throw new EE_Error(esc_html__('You included a start date and/or a end date for this method but did not include a format string.  The format string is needed for setting up the query', 'event_espresso'));
+        if ((! empty($start_date) || ! empty($end_date)) && empty($format)) {
+            throw new EE_Error(
+                esc_html__(
+                    'You included a start date and/or a end date for this method but did not include a format string.  The format string is needed for setting up the query',
+                    'event_espresso'
+                )
+            );
         }
         $now = new DateTime('now');
         // setup timezone objects once
-        $modelDateTimeZone = new DateTimeZone($this->_timezone);
+        $modelDateTimeZone  = new DateTimeZone($this->_timezone);
         $passedDateTimeZone = new DateTimeZone($timezone);
         // setup start date
         $start_date = ! empty($start_date) ? date_create_from_format($format, $start_date, $passedDateTimeZone) : $now;
@@ -187,55 +281,77 @@ public function get_payments_made_between_dates($start_date = '', $end_date = ''
 
         // make sure our start date is the lowest value and vice versa
         $start = min($start_date, $end_date);
-        $end = max($start_date, $end_date);
-
-        // yes we generated the date and time string in utc but we WANT this start date and time used in the set timezone on the model.
-        $start_date = $this->convert_datetime_for_query('PAY_timestamp', date('Y-m-d', $start) . ' 00:00:00', 'Y-m-d H:i:s', $this->get_timezone());
-        $end_date = $this->convert_datetime_for_query('PAY_timestamp', date('Y-m-d', $end) . ' 23:59:59', 'Y-m-d H:i:s', $this->get_timezone());
+        $end   = max($start_date, $end_date);
+
+        // yes we generated the date and time string in utc
+        // but we WANT this start date and time used in the set timezone on the model.
+        $start_date = $this->convert_datetime_for_query(
+            'PAY_timestamp',
+            date('Y-m-d', $start) . ' 00:00:00',
+            'Y-m-d H:i:s',
+            $this->get_timezone()
+        );
+        $end_date   = $this->convert_datetime_for_query(
+            'PAY_timestamp',
+            date('Y-m-d', $end) . ' 23:59:59',
+            'Y-m-d H:i:s',
+            $this->get_timezone()
+        );
 
-        return $this->get_all(array(array('PAY_timestamp' => array('>=',$start_date),'PAY_timestamp*' => array('<=',$end_date))));
+        return $this->get_all([['PAY_timestamp' => ['>=', $start_date], 'PAY_timestamp*' => ['<=', $end_date]]]);
     }
 
-    /**
-     * methods for EEMI_Payment
-     */
+
     /**
      * returns a string for the approved status
-     * @return  string
+     *
+     * @return string
      */
-    public function approved_status()
+    public function approved_status(): string
     {
         return self::status_id_approved;
     }
+
+
     /**
      * returns a string for the pending status
-     * @return  string
+     *
+     * @return string
      */
-    public function pending_status()
+    public function pending_status(): string
     {
         return self::status_id_pending;
     }
+
+
     /**
      * returns a string for the cancelled status
-     * @return  string
+     *
+     * @return string
      */
-    public function cancelled_status()
+    public function cancelled_status(): string
     {
         return self::status_id_cancelled;
     }
+
+
     /**
      * returns a string for the failed status
-     * @return  string
+     *
+     * @return string
      */
-    public function failed_status()
+    public function failed_status(): string
     {
         return self::status_id_failed;
     }
+
+
     /**
      * returns a string for the declined status
-     * @return  string
+     *
+     * @return string
      */
-    public function declined_status()
+    public function declined_status(): string
     {
         return self::status_id_declined;
     }
diff --git a/core/db_models/EEM_WP_User.model.php b/core/db_models/EEM_WP_User.model.php
index 59c7c0f3590..114549a04ac 100644
--- a/core/db_models/EEM_WP_User.model.php
+++ b/core/db_models/EEM_WP_User.model.php
@@ -65,7 +65,8 @@ protected function __construct($timezone, ModelFieldFactory $model_field_factory
                 'user_registered'     => $model_field_factory->createDatetimeField(
                     'user_registered',
                     esc_html__('Date User Registered', 'event_espresso'),
-                    $timezone
+                    $timezone,
+                    false
                 ),
                 'user_activation_key' => $model_field_factory->createPlainTextField(
                     'user_activation_key',
@@ -125,7 +126,7 @@ protected function __construct($timezone, ModelFieldFactory $model_field_factory
      * @return string
      * @throws EE_Error
      */
-    public function wp_user_field_name()
+    public function wp_user_field_name(): string
     {
         return $this->primary_key_name();
     }
@@ -136,7 +137,7 @@ public function wp_user_field_name()
      *
      * @return boolean
      */
-    public function is_owned()
+    public function is_owned(): bool
     {
         return true;
     }
diff --git a/core/domain/entities/custom_post_types/CustomTaxonomyDefinitions.php b/core/domain/entities/custom_post_types/CustomTaxonomyDefinitions.php
index f82fc2f5db1..7c4b25d192a 100644
--- a/core/domain/entities/custom_post_types/CustomTaxonomyDefinitions.php
+++ b/core/domain/entities/custom_post_types/CustomTaxonomyDefinitions.php
@@ -3,6 +3,7 @@
 namespace EventEspresso\core\domain\entities\custom_post_types;
 
 use EEH_URL;
+use EventEspresso\core\interfaces\InterminableInterface;
 
 /**
  * Class CustomTaxonomyDefinitions
@@ -12,7 +13,7 @@
  * @author  Darren Ethier / Brent Christensen
  * @since   4.9.62.p
  */
-class CustomTaxonomyDefinitions
+class CustomTaxonomyDefinitions implements InterminableInterface
 {
     /**
      * @var array $taxonomies
@@ -104,7 +105,7 @@ private function setTaxonomies()
     /**
      * @return array
      */
-    public function getCustomTaxonomyDefinitions()
+    public function getCustomTaxonomyDefinitions(): array
     {
         return (array) apply_filters(
             'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies',
@@ -121,7 +122,7 @@ public function getCustomTaxonomyDefinitions()
     /**
      * @return array
      */
-    public function getCustomTaxonomySlugs()
+    public function getCustomTaxonomySlugs(): array
     {
         return array_keys($this->getCustomTaxonomyDefinitions());
     }
@@ -142,7 +143,7 @@ public function getCustomTaxonomySlugs()
      * @param string $taxonomy    The taxonomy name for the taxonomy being filtered.
      * @return string
      */
-    public function filterCustomTermDescription($description, $taxonomy)
+    public function filterCustomTermDescription(string $description, string $taxonomy): string
     {
         // get a list of EE taxonomies
         $custom_taxonomies = $this->getCustomTaxonomySlugs();
diff --git a/core/domain/entities/routing/specifications/RouteMatchSpecificationInterface.php b/core/domain/entities/routing/specifications/RouteMatchSpecificationInterface.php
index 615a25be96e..6e79b1efddf 100644
--- a/core/domain/entities/routing/specifications/RouteMatchSpecificationInterface.php
+++ b/core/domain/entities/routing/specifications/RouteMatchSpecificationInterface.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\domain\entities\routing\specifications;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Class RouteMatchSpecificationInterface
  * Variation of the Specification design pattern for matching current request to specific routes
@@ -10,7 +12,7 @@
  * @author  Brent Christensen
  * @since   4.9.71.p
  */
-interface RouteMatchSpecificationInterface
+interface RouteMatchSpecificationInterface extends InterminableInterface
 {
     /**
      * returns true if current request matches specification
diff --git a/core/domain/services/assets/CoreAssetManager.php b/core/domain/services/assets/CoreAssetManager.php
index 8c39bf23b22..0bad03bb679 100644
--- a/core/domain/services/assets/CoreAssetManager.php
+++ b/core/domain/services/assets/CoreAssetManager.php
@@ -30,15 +30,17 @@ class CoreAssetManager extends AssetManager
 {
 
     // WordPress core / Third party JS asset handles
-    const JS_HANDLE_JS_CORE = 'eejs-core';
-
     const JS_HANDLE_CORE    = 'espresso_core';
 
+    const JS_HANDLE_JS_CORE = 'eejs-core';
+
     const JS_HANDLE_I18N    = 'eei18n';
 
+    const JS_HANDLE_RAMDA  = 'ramda';
+
     const JS_HANDLE_VENDOR  = 'eventespresso-vendor';
 
-    const JS_HANDLE_RAMDA  = 'ramda';
+    const JS_HANDLE_WP_PLUGINS_PAGE = 'eventespresso-wp-plugins-page-js';
 
     const RAMDA_VERSION = '0.27.1';
 
@@ -47,6 +49,8 @@ class CoreAssetManager extends AssetManager
 
     const CSS_HANDLE_CUSTOM  = 'espresso_custom_css';
 
+    const CSS_HANDLE_WP_PLUGINS_PAGE = 'eventespresso-wp-plugins-page-css';
+
     /**
      * @var EE_Currency_Config $currency_config
      */
diff --git a/core/domain/services/assets/EspressoLegacyAdminAssetManager.php b/core/domain/services/assets/EspressoLegacyAdminAssetManager.php
index 30cf4d2ce8c..1016ffc7efa 100644
--- a/core/domain/services/assets/EspressoLegacyAdminAssetManager.php
+++ b/core/domain/services/assets/EspressoLegacyAdminAssetManager.php
@@ -35,7 +35,7 @@ class EspressoLegacyAdminAssetManager extends AssetManager
 
     const JS_HANDLE_PARSE_URI               = 'ee-parse-uri';
 
-    const JS_HANDLE_EE_TEXT_LINKS           = 'ee-text-links';
+    const JS_HANDLE_EE_TEXT_LINKS           = 'ee-text-links-js';
 
     const JS_HANDLE_EE_SERIALIZE_FULL_ARRAY = 'ee-serialize-full-array';
 
@@ -47,7 +47,7 @@ class EspressoLegacyAdminAssetManager extends AssetManager
 
     const CSS_HANDLE_EE_JOYRIDE             = 'ee-joyride-css';
 
-    const CSS_HANDLE_EE_TEXT_LINKS          = 'ee-text-links';
+    const CSS_HANDLE_EE_TEXT_LINKS          = 'ee-text-links-css';
 
     const CSS_HANDLE_EE_UI_THEME            = 'espresso-ui-theme';
 
diff --git a/core/domain/services/contexts/RequestTypeContextCheckerInterface.php b/core/domain/services/contexts/RequestTypeContextCheckerInterface.php
index 7dc1438e606..5764d861540 100644
--- a/core/domain/services/contexts/RequestTypeContextCheckerInterface.php
+++ b/core/domain/services/contexts/RequestTypeContextCheckerInterface.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\domain\services\contexts;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * RequestTypeContextCheckerInterface
  * Service class that provides useful methods for evaluating the current request type
@@ -10,7 +12,7 @@
  * @author  Brent Christensen
  * @since   4.9.53
  */
-interface RequestTypeContextCheckerInterface
+interface RequestTypeContextCheckerInterface extends InterminableInterface
 {
     /**
      * true if the current request involves some form of activation
diff --git a/core/domain/services/contexts/RequestTypeContextDetector.php b/core/domain/services/contexts/RequestTypeContextDetector.php
index 0d134f3fbf7..f97aeab708e 100644
--- a/core/domain/services/contexts/RequestTypeContextDetector.php
+++ b/core/domain/services/contexts/RequestTypeContextDetector.php
@@ -3,6 +3,7 @@
 namespace EventEspresso\core\domain\services\contexts;
 
 use EventEspresso\core\domain\Domain;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\graphql\GraphQLEndpoint;
 use EventEspresso\core\services\request\RequestInterface;
 use EventEspresso\core\domain\entities\contexts\RequestTypeContext;
@@ -16,7 +17,7 @@
  * @author  Brent Christensen
  * @since   4.9.51
  */
-class RequestTypeContextDetector
+class RequestTypeContextDetector implements InterminableInterface
 {
     /**
      * @var GraphQLEndpoint $gql_endpoint
diff --git a/core/domain/services/contexts/RequestTypeContextFactory.php b/core/domain/services/contexts/RequestTypeContextFactory.php
index 9fbe8d2cf5e..c6fb7f5d825 100644
--- a/core/domain/services/contexts/RequestTypeContextFactory.php
+++ b/core/domain/services/contexts/RequestTypeContextFactory.php
@@ -37,7 +37,7 @@ public function __construct(LoaderInterface $loader)
      * @param string $slug
      * @return RequestTypeContext
      */
-    public function create($slug)
+    public function create($slug): RequestTypeContext
     {
         switch ($slug) {
             case RequestTypeContext::ACTIVATION:
diff --git a/core/domain/services/contexts/RequestTypeContextFactoryInterface.php b/core/domain/services/contexts/RequestTypeContextFactoryInterface.php
index de6b3932f1c..d1cf6eab3d7 100644
--- a/core/domain/services/contexts/RequestTypeContextFactoryInterface.php
+++ b/core/domain/services/contexts/RequestTypeContextFactoryInterface.php
@@ -3,6 +3,7 @@
 namespace EventEspresso\core\domain\services\contexts;
 
 use EventEspresso\core\domain\entities\contexts\RequestTypeContext;
+use EventEspresso\core\interfaces\InterminableInterface;
 
 /**
  * RequestTypeContextFactoryInterface
@@ -12,7 +13,7 @@
  * @author  Brent Christensen
  * @since   4.9.51
  */
-interface RequestTypeContextFactoryInterface
+interface RequestTypeContextFactoryInterface extends InterminableInterface
 {
     /**
      * @param string $slug
diff --git a/core/domain/services/custom_post_types/RewriteRules.php b/core/domain/services/custom_post_types/RewriteRules.php
index e7cc4f1c3a1..388a9fc7b71 100644
--- a/core/domain/services/custom_post_types/RewriteRules.php
+++ b/core/domain/services/custom_post_types/RewriteRules.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\domain\services\custom_post_types;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Class RewriteRules
  * Manages the flushing of rewrite rules
@@ -10,7 +12,7 @@
  * @author  Brent Christensen
  * @since   4.9.62.p
  */
-class RewriteRules
+class RewriteRules implements InterminableInterface
 {
     const OPTION_KEY_FLUSH_REWRITE_RULES = 'ee_flush_rewrite_rules';
 
diff --git a/core/domain/services/factories/CartFactory.php b/core/domain/services/factories/CartFactory.php
index 8e57fd8deea..def51a5adc1 100644
--- a/core/domain/services/factories/CartFactory.php
+++ b/core/domain/services/factories/CartFactory.php
@@ -3,10 +3,7 @@
 namespace EventEspresso\core\domain\services\factories;
 
 use EE_Cart;
-use EventEspresso\core\exceptions\InvalidDataTypeException;
-use EventEspresso\core\exceptions\InvalidInterfaceException;
 use EventEspresso\core\services\loaders\LoaderFactory;
-use InvalidArgumentException;
 
 /**
  * Class CartFactory
@@ -16,16 +13,13 @@
  * @author  Brent Christensen
  * @since   4.9.59.p
  */
-class CartFactory
+class CartFactory extends LoaderFactory
 {
     /**
      * @return EE_Cart
-     * @throws InvalidArgumentException
-     * @throws InvalidInterfaceException
-     * @throws InvalidDataTypeException
      */
-    public static function getCart()
+    public static function getCart(): EE_Cart
     {
-        return LoaderFactory::getLoader()->getShared('EE_Cart');
+        return CartFactory::getShared('EE_Cart');
     }
 }
diff --git a/core/domain/services/factories/EmailAddressFactory.php b/core/domain/services/factories/EmailAddressFactory.php
index 08dea80d1a3..532d5d993b3 100644
--- a/core/domain/services/factories/EmailAddressFactory.php
+++ b/core/domain/services/factories/EmailAddressFactory.php
@@ -3,11 +3,9 @@
 namespace EventEspresso\core\domain\services\factories;
 
 use EventEspresso\core\domain\services\validation\email\EmailValidationException;
+use EventEspresso\core\domain\services\validation\email\EmailValidationService;
 use EventEspresso\core\domain\values\EmailAddress;
-use EventEspresso\core\exceptions\InvalidDataTypeException;
-use EventEspresso\core\exceptions\InvalidInterfaceException;
 use EventEspresso\core\services\loaders\LoaderFactory;
-use InvalidArgumentException;
 
 /**
  * Class EmailAddressFactory
@@ -16,21 +14,49 @@
  * @package EventEspresso\core\domain\services\factories
  * @author  Brent Christensen
  */
-class EmailAddressFactory implements FactoryInterface
+class EmailAddressFactory extends LoaderFactory implements FactoryInterface
 {
+    /**
+     * @var EmailValidationService
+     * @since $VID:$
+     */
+    private static $validator;
+
+
+    /**
+     * @return EmailValidationService
+     */
+    public static function getValidator(): EmailValidationService
+    {
+        if (! EmailAddressFactory::$validator instanceof EmailValidationService) {
+            EmailAddressFactory::setValidator(EmailAddressFactory::getShared(EmailValidationService::class));
+        }
+        return EmailAddressFactory::$validator;
+    }
+
+
+    /**
+     * @param EmailValidationService $validator
+     */
+    public static function setValidator(EmailValidationService $validator): void
+    {
+        EmailAddressFactory::$validator = $validator;
+    }
+
+
     /**
      * @param string $email_address
      * @return EmailAddress
      * @throws EmailValidationException
-     * @throws InvalidDataTypeException
-     * @throws InvalidInterfaceException
-     * @throws InvalidArgumentException
      */
-    public static function create($email_address)
+    public static function create($email_address): EmailAddress
     {
-        return LoaderFactory::getLoader()->getNew(
-            'EventEspresso\core\domain\values\EmailAddress',
-            array($email_address)
+        return EmailAddressFactory::getNew(
+            EmailAddress::class,
+            [
+                $email_address,
+                EmailAddressFactory::getValidator()
+            ]
         );
     }
 }
diff --git a/core/domain/services/factories/ModelFactory.php b/core/domain/services/factories/ModelFactory.php
index 0dbbd4d01a1..ea39ebb9a12 100644
--- a/core/domain/services/factories/ModelFactory.php
+++ b/core/domain/services/factories/ModelFactory.php
@@ -2,13 +2,8 @@
 
 namespace EventEspresso\core\domain\services\factories;
 
-use EE_Error;
-use EE_Registry;
 use EEM_Base;
-use EventEspresso\core\exceptions\InvalidDataTypeException;
-use EventEspresso\core\exceptions\InvalidInterfaceException;
-use InvalidArgumentException;
-use ReflectionException;
+use EventEspresso\core\services\loaders\LoaderFactory;
 
 /**
  * Class ModelFactory
@@ -18,19 +13,14 @@
  * @author  Brent Christensen
  * @since   4.9.59.p
  */
-class ModelFactory
+class ModelFactory extends LoaderFactory
 {
     /**
      * @param string $model_name
      * @return bool|EEM_Base
-     * @throws EE_Error
-     * @throws InvalidDataTypeException
-     * @throws InvalidInterfaceException
-     * @throws InvalidArgumentException
-     * @throws ReflectionException
      */
-    public static function getModel($model_name)
+    public static function getModel(string $model_name)
     {
-        return EE_Registry::instance()->load_model($model_name);
+        return ModelFactory::getShared($model_name);
     }
 }
diff --git a/core/domain/services/validation/email/EmailValidationService.php b/core/domain/services/validation/email/EmailValidationService.php
index a6c532761d7..98ce65355f2 100644
--- a/core/domain/services/validation/email/EmailValidationService.php
+++ b/core/domain/services/validation/email/EmailValidationService.php
@@ -3,6 +3,10 @@
 namespace EventEspresso\core\domain\services\validation\email;
 
 use EE_Registration_Config;
+use EventEspresso\core\domain\services\validation\email\strategies\Basic;
+use EventEspresso\core\domain\services\validation\email\strategies\International;
+use EventEspresso\core\domain\services\validation\email\strategies\InternationalDNS;
+use EventEspresso\core\domain\services\validation\email\strategies\WordPress;
 use EventEspresso\core\services\loaders\Loader;
 
 /**
@@ -15,16 +19,46 @@
  */
 class EmailValidationService implements EmailValidatorInterface
 {
+    public const VALIDATION_LEVEL_BASIC      = 'basic';
+
+    public const VALIDATION_LEVEL_I18N       = 'i18n';
+
+    public const VALIDATION_LEVEL_I18N_DNS   = 'i18n_dns';
+
+    public const VALIDATION_LEVEL_WP_DEFAULT = 'wp_default';
+
+
     /**
-     * @var EE_Registration_Config $registration_config
+     * @var EE_Registration_Config
      */
     protected $registration_config;
 
     /**
-     * @var Loader $loader
+     * @var Loader
      */
     protected $loader;
 
+    /**
+     * @var Basic
+     */
+    private $validator_basic;
+
+    /**
+     * @var International
+     */
+    private $validator_i18n;
+
+    /**
+     * @var InternationalDNS
+     */
+    private $validator_i18n_dns;
+
+    /**
+     * @var WordPress
+     */
+    private $validator_wordpress;
+
+
 
     /**
      * EmailValidationService constructor.
@@ -44,36 +78,78 @@ public function __construct(EE_Registration_Config $config, Loader $loader)
      * Validates the email address. If it's invalid, an EmailValidationException
      * is thrown that describes why its invalid.
      *
-     * @param string $email_address
+     * @param string|null $email_address
      * @return boolean
-     * @throws EmailValidationException
      */
-    public function validate($email_address)
+    public function validate(?string $email_address): bool
     {
         // pick the correct validator according to the config
         switch ($this->registration_config->email_validation_level) {
-            case 'basic':
-                $validator = $this->loader->getShared(
-                    'EventEspresso\core\domain\services\validation\email\strategies\Basic'
-                );
-                break;
-            case 'i18n':
-                $validator = $this->loader->getShared(
-                    'EventEspresso\core\domain\services\validation\email\strategies\International'
-                );
-                break;
-            case 'i18n_dns':
-                $validator = $this->loader->getShared(
-                    'EventEspresso\core\domain\services\validation\email\strategies\InternationalDNS'
-                );
-                break;
-            case 'wp_default':
+            case EmailValidationService::VALIDATION_LEVEL_BASIC:
+                return $this->basicValidator()->validate($email_address);
+            case EmailValidationService::VALIDATION_LEVEL_I18N:
+                return $this->i18nValidator()->validate($email_address);
+            case EmailValidationService::VALIDATION_LEVEL_I18N_DNS:
+                return $this->i18nDnsValidator()->validate($email_address);
+            case EmailValidationService::VALIDATION_LEVEL_WP_DEFAULT:
             default:
-                $validator = $this->loader->getShared(
-                    'EventEspresso\core\domain\services\validation\email\strategies\WordPress'
-                );
-                break;
+                return $this->wordpressValidator()->validate($email_address);
+        }
+    }
+
+
+    /**
+     * @return Basic
+     */
+    public function basicValidator(): Basic
+    {
+        if (! $this->validator_basic instanceof Basic) {
+            $this->validator_basic = $this->loader->getShared(
+                'EventEspresso\core\domain\services\validation\email\strategies\Basic'
+            );
+        }
+        return $this->validator_basic;
+    }
+
+
+    /**
+     * @return International
+     */
+    public function i18nValidator(): International
+    {
+        if (! $this->validator_i18n instanceof Basic) {
+            $this->validator_i18n = $this->loader->getShared(
+                'EventEspresso\core\domain\services\validation\email\strategies\International'
+            );
+        }
+        return $this->validator_i18n;
+    }
+
+
+    /**
+     * @return InternationalDNS
+     */
+    public function i18nDnsValidator(): InternationalDNS
+    {
+        if (! $this->validator_i18n_dns instanceof Basic) {
+            $this->validator_i18n_dns = $this->loader->getShared(
+                'EventEspresso\core\domain\services\validation\email\strategies\InternationalDNS'
+            );
+        }
+        return $this->validator_i18n_dns;
+    }
+
+
+    /**
+     * @return WordPress
+     */
+    public function wordpressValidator(): WordPress
+    {
+        if (! $this->validator_wordpress instanceof Basic) {
+            $this->validator_wordpress = $this->loader->getShared(
+                'EventEspresso\core\domain\services\validation\email\strategies\WordPress'
+            );
         }
-        return $validator->validate($email_address);
+        return $this->validator_wordpress;
     }
 }
diff --git a/core/domain/services/validation/email/EmailValidatorInterface.php b/core/domain/services/validation/email/EmailValidatorInterface.php
index 78220f691ba..ec7d4e11296 100644
--- a/core/domain/services/validation/email/EmailValidatorInterface.php
+++ b/core/domain/services/validation/email/EmailValidatorInterface.php
@@ -16,9 +16,9 @@ interface EmailValidatorInterface
     /**
      * Validates the supplied email address. If it is invalid, throws EmailValidationException
      *
-     * @param string $email_address
+     * @param string|null $email_address
      * @return boolean
      * @throws EmailValidationException
      */
-    public function validate($email_address);
+    public function validate(?string $email_address): bool;
 }
diff --git a/core/domain/services/validation/email/strategies/Basic.php b/core/domain/services/validation/email/strategies/Basic.php
index 52e5a949a0d..3f6a2d16b38 100644
--- a/core/domain/services/validation/email/strategies/Basic.php
+++ b/core/domain/services/validation/email/strategies/Basic.php
@@ -15,11 +15,11 @@
 class Basic implements EmailValidatorInterface
 {
     /**
-     * @param string $email_address
+     * @param string|null $email_address
      * @return bool
      * @throws EmailValidationException
      */
-    public function validate($email_address)
+    public function validate(?string $email_address): bool
     {
         if (! preg_match('/^.+\@\S+$/', (string) $email_address)) {
             // email not in correct {string}@{string} format
diff --git a/core/domain/services/validation/email/strategies/International.php b/core/domain/services/validation/email/strategies/International.php
index 33b0bc80266..eaff1282805 100644
--- a/core/domain/services/validation/email/strategies/International.php
+++ b/core/domain/services/validation/email/strategies/International.php
@@ -15,11 +15,11 @@
 class International extends Basic
 {
     /**
-     * @param string $email_address
+     * @param string|null $email_address
      * @return bool
      * @throws \EventEspresso\core\domain\services\validation\email\EmailValidationException
      */
-    public function validate($email_address)
+    public function validate(?string $email_address): bool
     {
         parent::validate($email_address);
         if (
diff --git a/core/domain/services/validation/email/strategies/InternationalDNS.php b/core/domain/services/validation/email/strategies/InternationalDNS.php
index c30cf15b811..db5bb98fa4a 100644
--- a/core/domain/services/validation/email/strategies/InternationalDNS.php
+++ b/core/domain/services/validation/email/strategies/InternationalDNS.php
@@ -18,11 +18,11 @@ class InternationalDNS extends International
      * Validates the email in teh same way as the parent, but also
      * verifies the domain exists.
      *
-     * @param string $email_address
+     * @param string|null $email_address
      * @return bool
      * @throws EmailValidationException
      */
-    public function validate($email_address)
+    public function validate(?string $email_address): bool
     {
         parent::validate($email_address);
         $domain = $this->getDomainPartOfEmail(
diff --git a/core/domain/services/validation/email/strategies/WordPress.php b/core/domain/services/validation/email/strategies/WordPress.php
index afee5b3a89e..63adf51cfdf 100644
--- a/core/domain/services/validation/email/strategies/WordPress.php
+++ b/core/domain/services/validation/email/strategies/WordPress.php
@@ -15,11 +15,11 @@
 class WordPress extends Basic
 {
     /**
-     * @param string $email_address
+     * @param string|null $email_address
      * @return boolean
      * @throws EmailValidationException
      */
-    public function validate($email_address)
+    public function validate(?string $email_address): bool
     {
         parent::validate($email_address);
         if (! is_email($email_address)) {
diff --git a/core/domain/values/session/SessionLifespan.php b/core/domain/values/session/SessionLifespan.php
index b3d9fad22b0..747740eca7f 100644
--- a/core/domain/values/session/SessionLifespan.php
+++ b/core/domain/values/session/SessionLifespan.php
@@ -34,7 +34,7 @@ class SessionLifespan
      * @param int $lifespan
      * @throws DomainException
      */
-    public function __construct($lifespan = 0)
+    public function __construct(int $lifespan = 0)
     {
         $lifespan = absint($lifespan);
         $lifespan = $lifespan > 0 ? $lifespan : (int) HOUR_IN_SECONDS;
@@ -46,7 +46,7 @@ public function __construct($lifespan = 0)
      * @param int $lifespan
      * @throws DomainException
      */
-    protected function setLifespan($lifespan)
+    protected function setLifespan(int $lifespan)
     {
         if ($lifespan < 60) {
             throw new DomainException(
@@ -70,7 +70,7 @@ protected function setLifespan($lifespan)
     /**
      * @return int
      */
-    public function inSeconds()
+    public function inSeconds(): int
     {
         return $this->lifespan;
     }
@@ -80,7 +80,7 @@ public function inSeconds()
      * @param string $separator
      * @return string
      */
-    public function inHoursMinutesSeconds($separator = ':')
+    public function inHoursMinutesSeconds(string $separator = ':'): string
     {
         return sprintf(
             '%02d%s%02d%s%02d',
@@ -100,7 +100,7 @@ public function inHoursMinutesSeconds($separator = ':')
      *                  If false, displays expiration in local time
      * @return int
      */
-    public function expiration($utc = true)
+    public function expiration(bool $utc = true): int
     {
         return (int) current_time('timestamp', $utc) - $this->lifespan;
     }
@@ -109,7 +109,7 @@ public function expiration($utc = true)
     /**
      * @return string
      */
-    public function __toString()
+    public function __toString(): string
     {
         return (string) $this->inSeconds();
     }
diff --git a/core/helpers/EEH_Activation.helper.php b/core/helpers/EEH_Activation.helper.php
index 4d14ac66e72..72fcdf1b348 100644
--- a/core/helpers/EEH_Activation.helper.php
+++ b/core/helpers/EEH_Activation.helper.php
@@ -587,7 +587,12 @@ public static function get_default_creator_id()
         }
         $capabilities_key = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
         $query            = $wpdb->prepare(
-            "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
+            "SELECT user_id 
+            FROM $wpdb->usermeta 
+            WHERE meta_key = '$capabilities_key' 
+              AND meta_value LIKE %s 
+            ORDER BY user_id ASC 
+            LIMIT 0,1",
             '%' . $role_to_check . '%'
         );
         $user_id          = $wpdb->get_var($query);
@@ -595,9 +600,8 @@ public static function get_default_creator_id()
         if ($user_id && (int) $user_id) {
             self::$_default_creator_id = (int) $user_id;
             return self::$_default_creator_id;
-        } else {
-            return null;
         }
+        return null;
     }
 
 
diff --git a/core/helpers/EEH_DTT_Helper.helper.php b/core/helpers/EEH_DTT_Helper.helper.php
index a477ff8197e..b7b85769bbd 100644
--- a/core/helpers/EEH_DTT_Helper.helper.php
+++ b/core/helpers/EEH_DTT_Helper.helper.php
@@ -3,7 +3,7 @@
 use EventEspresso\core\services\helpers\datetime\HelperInterface;
 use EventEspresso\core\exceptions\InvalidDataTypeException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
-use EventEspresso\core\services\loaders\LoaderFactory;
+use EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper;
 
 /**
  * EEH_DTT_Helper
@@ -1035,10 +1035,11 @@ public static function get_user_locale($user_id = 0)
      */
     private static function getHelperAdapter()
     {
-        $dtt_helper_fqcn = PHP_VERSION_ID < 50600
-            ? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
-            : 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper';
-        return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn);
+        static $dtt_helper_fqcn;
+        if (! $dtt_helper_fqcn instanceof PhpCompatGreaterFiveSixHelper) {
+            $dtt_helper_fqcn = new PhpCompatGreaterFiveSixHelper();
+        }
+        return $dtt_helper_fqcn;
     }
 
 
diff --git a/core/interfaces/EEI_Address_Formatter.interface.php b/core/interfaces/EEI_Address_Formatter.interface.php
index cd5f1bd2ff7..41d7c0cdeca 100644
--- a/core/interfaces/EEI_Address_Formatter.interface.php
+++ b/core/interfaces/EEI_Address_Formatter.interface.php
@@ -14,5 +14,13 @@ interface EEI_Address_Formatter
      * @param string $country
      * @param string $CNT_ISO
      */
-    public function format($address, $address2, $city, $state, $zip, $country, $CNT_ISO);
+    public function format(
+        string $address,
+        string $address2,
+        string $city,
+        string $state,
+        string $zip,
+        string $country,
+        string $CNT_ISO
+    ): ?string;
 }
diff --git a/core/libraries/messages/data_class/EE_Messages_Preview_incoming_data.class.php b/core/libraries/messages/data_class/EE_Messages_Preview_incoming_data.class.php
index 4214e7ba0ed..a92fba958b2 100644
--- a/core/libraries/messages/data_class/EE_Messages_Preview_incoming_data.class.php
+++ b/core/libraries/messages/data_class/EE_Messages_Preview_incoming_data.class.php
@@ -432,13 +432,11 @@ private function _get_some_events(array $event_ids = [])
      */
     protected function _setup_data()
     {
-        // need to figure out the running total for test purposes so... we're going to create a temp cart and add the tickets to it!
-        if (EE_Registry::instance()->SSN instanceof EE_Session) {
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
-            $session = EE_Registry::instance()->SSN;
-        } else {
-            $session = EE_Registry::instance()->load_core('Session');
-        }
+        /** @var EE_Session $session */
+        $session = LoaderFactory::getLoader()->getNew(EE_Session::class);
+        $session->clear_session(__CLASS__, __FUNCTION__);
+        // need to figure out the running total for test purposes so...
+        // we're going to create a temp cart and add the tickets to it!
         $cart = EE_Cart::instance(null, $session);
 
         // add tickets to cart
diff --git a/core/libraries/payment_methods/EE_Payment_Method_Manager.lib.php b/core/libraries/payment_methods/EE_Payment_Method_Manager.lib.php
index da56e059838..afecfe167dd 100644
--- a/core/libraries/payment_methods/EE_Payment_Method_Manager.lib.php
+++ b/core/libraries/payment_methods/EE_Payment_Method_Manager.lib.php
@@ -34,12 +34,12 @@ class EE_Payment_Method_Manager implements ResettableInterface
     /**
      * @var array keys are class names without 'EE_PMT_', values are their filepaths
      */
-    protected $_payment_method_types = array();
+    protected $_payment_method_types = [];
 
     /**
      * @var EE_PMT_Base[]
      */
-    protected $payment_method_objects = array();
+    protected $payment_method_objects = [];
 
 
     /**
@@ -48,7 +48,7 @@ class EE_Payment_Method_Manager implements ResettableInterface
      * @throws EE_Error
      * @throws DomainException
      */
-    public function __construct()
+    protected function __construct()
     {
         // if in admin lets ensure caps are set.
         if (is_admin()) {
@@ -58,7 +58,7 @@ public function __construct()
             // plus any time they get reset
             add_filter(
                 'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
-                array($this, 'addPaymentMethodCapsDuringReset')
+                [$this, 'addPaymentMethodCapsDuringReset']
             );
         }
     }
@@ -69,8 +69,9 @@ public function __construct()
      * @return EE_Payment_Method_Manager instance
      * @throws DomainException
      * @throws EE_Error
+     * @throws ReflectionException
      */
-    public static function instance()
+    public static function instance(): EE_Payment_Method_Manager
     {
         // check if class object is instantiated, and instantiated properly
         if (! self::$_instance instanceof EE_Payment_Method_Manager) {
@@ -87,10 +88,14 @@ public static function instance()
      * @return EE_Payment_Method_Manager
      * @throws DomainException
      * @throws EE_Error
+     * @throws ReflectionException
      */
-    public static function reset()
+    public static function reset(): EE_Payment_Method_Manager
     {
-        self::$_instance = null;
+        self::$_instance->payment_method_caps_initialized = false;
+        self::$_instance->_payment_method_types           = [];
+        self::$_instance->payment_method_objects          = [];
+        self::$_instance                                  = null;
         return self::instance();
     }
 
@@ -98,11 +103,11 @@ public static function reset()
     /**
      * If necessary, re-register payment methods
      *
-     * @param boolean $force_recheck whether to recheck for payment method types,
+     * @param bool $force_recheck    whether to recheck for payment method types,
      *                               or just re-use the PMTs we found last time we checked during this request (if
      *                               we have not yet checked during this request, then we need to check anyways)
      */
-    public function maybe_register_payment_methods($force_recheck = false)
+    public function maybe_register_payment_methods(bool $force_recheck = false)
     {
         if (! $this->_payment_method_types || $force_recheck) {
             $this->_register_payment_methods();
@@ -115,7 +120,7 @@ public function maybe_register_payment_methods($force_recheck = false)
      *
      * @return array
      */
-    protected function _register_payment_methods()
+    protected function _register_payment_methods(): array
     {
         // grab list of installed modules
         $pm_to_register = glob(EE_PAYMENT_METHODS . '*', GLOB_ONLYDIR);
@@ -147,7 +152,7 @@ protected function _register_payment_methods()
      * @param string $payment_method_path - full path up to and including payment method folder
      * @return boolean
      */
-    public function register_payment_method($payment_method_path = '')
+    public function register_payment_method(string $payment_method_path = ''): bool
     {
         do_action('AHEE__EE_Payment_Method_Manager__register_payment_method__begin', $payment_method_path);
         $module_ext = '.pm.php';
@@ -156,7 +161,7 @@ public function register_payment_method($payment_method_path = '')
         // grab and sanitize module name
         $module_dir = basename($payment_method_path);
         // create class name from module directory name
-        $module = str_replace(array('_', ' '), array(' ', '_'), $module_dir);
+        $module = str_replace(['_', ' '], [' ', '_'], $module_dir);
         // add class prefix
         $module_class = 'EE_PMT_' . $module;
         // does the module exist ?
@@ -196,7 +201,7 @@ public function register_payment_method($payment_method_path = '')
      * @param boolean $force_recheck       whether to force re-checking for new payment method types
      * @return boolean
      */
-    public function payment_method_type_exists($payment_method_name, $force_recheck = false)
+    public function payment_method_type_exists(string $payment_method_name, bool $force_recheck = false): bool
     {
         if (
             $force_recheck
@@ -221,12 +226,12 @@ public function payment_method_type_exists($payment_method_name, $force_recheck
      * @param boolean $force_recheck whether to force re-checking for new payment method types
      * @return array
      */
-    public function payment_method_type_names($with_prefixes = false, $force_recheck = false)
+    public function payment_method_type_names(bool $with_prefixes = false, bool $force_recheck = false): array
     {
         $this->maybe_register_payment_methods($force_recheck);
         if ($with_prefixes) {
-            $classnames = array_keys($this->_payment_method_types);
-            $payment_methods = array();
+            $classnames      = array_keys($this->_payment_method_types);
+            $payment_methods = [];
             foreach ($classnames as $classname) {
                 $payment_methods[] = $this->payment_method_class_from_type($classname);
             }
@@ -243,7 +248,7 @@ public function payment_method_type_names($with_prefixes = false, $force_recheck
      * @param boolean $force_recheck whether to force re-checking for new payment method types
      * @return EE_PMT_Base[]
      */
-    public function payment_method_types($force_recheck = false)
+    public function payment_method_types(bool $force_recheck = false): array
     {
         if ($force_recheck || empty($this->payment_method_objects)) {
             $this->maybe_register_payment_methods($force_recheck);
@@ -264,7 +269,7 @@ public function payment_method_types($force_recheck = false)
      * @param string $classname
      * @return string
      */
-    public function payment_method_type_sans_class_prefix($classname)
+    public function payment_method_type_sans_class_prefix(string $classname): string
     {
         return str_replace('EE_PMT_', '', $classname);
     }
@@ -276,7 +281,7 @@ public function payment_method_type_sans_class_prefix($classname)
      * @param string $type
      * @return string
      */
-    public function payment_method_class_from_type($type)
+    public function payment_method_class_from_type(string $type): string
     {
         return 'EE_PMT_' . $type;
     }
@@ -289,8 +294,9 @@ public function payment_method_class_from_type($type)
      * @return EE_Payment_Method
      * @throws InvalidDataTypeException
      * @throws EE_Error
+     * @throws ReflectionException
      */
-    public function activate_a_payment_method_of_type($payment_method_type)
+    public function activate_a_payment_method_of_type(string $payment_method_type): EE_Payment_Method
     {
         $this->maybe_register_payment_methods();
         $payment_method = EEM_Payment_Method::instance()->get_one_of_type($payment_method_type);
@@ -298,7 +304,7 @@ public function activate_a_payment_method_of_type($payment_method_type)
             $pm_type_class = $this->payment_method_class_from_type($payment_method_type);
             if (class_exists($pm_type_class)) {
                 /** @var $pm_type_obj EE_PMT_Base */
-                $pm_type_obj = new $pm_type_class();
+                $pm_type_obj    = new $pm_type_class();
                 $payment_method = EEM_Payment_Method::instance()->get_one_by_slug($pm_type_obj->system_name());
                 if (! $payment_method) {
                     $payment_method = $this->create_payment_method_of_type($pm_type_obj);
@@ -350,27 +356,27 @@ public function activate_a_payment_method_of_type($payment_method_type)
     /**
      * Creates a payment method of the specified type. Does not save it.
      *
-     * @global WP_User    $current_user
      * @param EE_PMT_Base $pm_type_obj
      * @return EE_Payment_Method
-     * @throws EE_Error
+     * @throws EE_Error*@throws ReflectionException
+     * @throws ReflectionException
+     * @global WP_User    $current_user
      */
-    public function create_payment_method_of_type($pm_type_obj)
+    public function create_payment_method_of_type(EE_PMT_Base $pm_type_obj): EE_Payment_Method
     {
         global $current_user;
-        $payment_method = EE_Payment_Method::new_instance(
-            array(
+        return EE_Payment_Method::new_instance(
+            [
                 'PMD_type'       => $pm_type_obj->system_name(),
                 'PMD_name'       => $pm_type_obj->defaultFrontendName(),
                 'PMD_admin_name' => $pm_type_obj->pretty_name(),
                 'PMD_slug'       => $pm_type_obj->system_name(),// automatically converted to slug
                 'PMD_wp_user'    => $current_user->ID,
                 'PMD_order'      => EEM_Payment_Method::instance()->count(
-                    array(array('PMD_type' => array('!=', 'Admin_Only')))
+                    [['PMD_type' => ['!=', 'Admin_Only']]]
                 ) * 10,
-            )
+            ]
         );
-        return $payment_method;
     }
 
 
@@ -380,8 +386,9 @@ public function create_payment_method_of_type($pm_type_obj)
      * @param EE_Payment_Method $payment_method
      * @return EE_Payment_Method
      * @throws EE_Error
+     * @throws ReflectionException
      */
-    public function initialize_payment_method($payment_method)
+    public function initialize_payment_method(EE_Payment_Method $payment_method): EE_Payment_Method
     {
         $pm_type_obj = $payment_method->type_obj();
         $payment_method->set_description($pm_type_obj->default_description());
@@ -406,12 +413,11 @@ public function initialize_payment_method($payment_method)
     /**
      * Makes sure the payment method is related to the specified payment method
      *
-     * @deprecated in 4.9.40 because the currency payment method table is being deprecated
      * @param EE_Payment_Method $payment_method
      * @return EE_Payment_Method
-     * @throws EE_Error
+     * @deprecated in 4.9.40 because the currency payment method table is being deprecated
      */
-    public function set_usable_currencies_on_payment_method($payment_method)
+    public function set_usable_currencies_on_payment_method(EE_Payment_Method $payment_method): EE_Payment_Method
     {
         EE_Error::doing_it_wrong(
             'EE_Payment_Method_Manager::set_usable_currencies_on_payment_method',
@@ -431,8 +437,9 @@ public function set_usable_currencies_on_payment_method($payment_method)
      * @param string $payment_method_slug The slug for the payment method to deactivate.
      * @return int count of rows updated.
      * @throws EE_Error
+     * @throws ReflectionException
      */
-    public function deactivate_payment_method($payment_method_slug)
+    public function deactivate_payment_method(string $payment_method_slug): int
     {
         EE_Log::instance()->log(
             __FILE__,
@@ -447,8 +454,8 @@ public function deactivate_payment_method($payment_method_slug)
             'payment_method_change'
         );
         $count_updated = EEM_Payment_Method::instance()->update(
-            array('PMD_scope' => array()),
-            array(array('PMD_slug' => $payment_method_slug))
+            ['PMD_scope' => []],
+            [['PMD_slug' => $payment_method_slug]]
         );
         do_action(
             'AHEE__EE_Payment_Method_Manager__deactivate_payment_method__after_deactivating_payment_method',
@@ -497,9 +504,9 @@ protected function initializePaymentMethodCaps()
      * @return array
      * @throws DomainException
      */
-    protected function getPaymentMethodCaps()
+    protected function getPaymentMethodCaps(): array
     {
-        $caps = array();
+        $caps = [];
         foreach ($this->payment_method_type_names() as $payment_method_name) {
             $caps = $this->addPaymentMethodCap($payment_method_name, $caps);
         }
@@ -514,8 +521,11 @@ protected function getPaymentMethodCaps()
      * @return array
      * @throws DomainException
      */
-    public function addPaymentMethodCap($payment_method_name, array $payment_method_caps, $role = 'administrator')
-    {
+    public function addPaymentMethodCap(
+        string $payment_method_name,
+        array $payment_method_caps,
+        string $role = 'administrator'
+    ): array {
         if (empty($payment_method_name)) {
             throw new DomainException(
                 esc_html__(
@@ -536,7 +546,7 @@ public function addPaymentMethodCap($payment_method_name, array $payment_method_
             );
         }
         if (! isset($payment_method_caps[ $role ])) {
-            $payment_method_caps[ $role ] = array();
+            $payment_method_caps[ $role ] = [];
         }
         $payment_method_caps[ $role ][] = EE_Payment_Method_Manager::CAPABILITIES_PREFIX
                                           . strtolower($payment_method_name);
@@ -554,20 +564,20 @@ public function addPaymentMethodCap($payment_method_name, array $payment_method_
      * @return array
      * @throws DomainException
      */
-    public function addPaymentMethodCapsDuringReset(array $caps, $reset = false)
+    public function addPaymentMethodCapsDuringReset(array $caps, bool $reset = false): array
     {
         if ($reset || ! $this->payment_method_caps_initialized) {
             $this->payment_method_caps_initialized = true;
-            $caps = array_merge_recursive($caps, $this->getPaymentMethodCaps());
+            $caps                                  = array_merge_recursive($caps, $this->getPaymentMethodCaps());
         }
         return $caps;
     }
 
 
     /**
-     * @deprecated 4.9.42
      * @param $caps
      * @return mixed
+     * @deprecated 4.9.42
      */
     public function add_payment_method_caps($caps)
     {
diff --git a/core/services/address/CountrySubRegionDao.php b/core/services/address/CountrySubRegionDao.php
index c3373766f68..85e3d1ed61a 100644
--- a/core/services/address/CountrySubRegionDao.php
+++ b/core/services/address/CountrySubRegionDao.php
@@ -5,7 +5,6 @@
 use EE_Country;
 use EE_Error;
 use EE_State;
-use EEM_Country;
 use EEM_State;
 use EventEspresso\core\exceptions\InvalidDataTypeException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
@@ -72,11 +71,11 @@ public function __construct(EEM_State $state_model, JsonValidator $json_validato
      * @throws InvalidInterfaceException
      * @throws ReflectionException
      */
-    public function saveCountrySubRegions(EE_Country $country_object)
+    public function saveCountrySubRegions(EE_Country $country_object): bool
     {
         $CNT_ISO = $country_object->ID();
         $has_sub_regions = $this->state_model->count(array(array('Country.CNT_ISO' => $CNT_ISO)));
-        $data = [];
+        $data = new stdClass();
         if (empty($this->countries)) {
             $this->data_version = $this->getCountrySubRegionDataVersion();
             $data = $this->retrieveJsonData(self::REPO_URL . 'countries.json');
@@ -110,7 +109,7 @@ public function saveCountrySubRegions(EE_Country $country_object)
      * @since 4.9.70.p
      * @return string
      */
-    private function getCountrySubRegionDataVersion()
+    private function getCountrySubRegionDataVersion(): string
     {
         return get_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, null);
     }
@@ -119,7 +118,7 @@ private function getCountrySubRegionDataVersion()
     /**
      * @param string $version
      */
-    private function updateCountrySubRegionDataVersion($version = '')
+    private function updateCountrySubRegionDataVersion(string $version = '')
     {
         // add version option if it has never been added before, or update existing
         if ($this->data_version === null) {
@@ -135,16 +134,12 @@ private function updateCountrySubRegionDataVersion($version = '')
      * @param array  $countries
      * @return int
      * @throws EE_Error
-     * @throws InvalidArgumentException
-     * @throws InvalidDataTypeException
-     * @throws InvalidInterfaceException
-     * @throws ReflectionException
      * @since 4.9.70.p
      */
-    private function processCountryData($CNT_ISO, $countries = array())
+    private function processCountryData(string $CNT_ISO, array $countries = array()): int
     {
         if (! empty($countries)) {
-            foreach ($countries as $key => $country) {
+            foreach ($countries as $country) {
                 if (
                     $country instanceof stdClass
                     && $country->code === $CNT_ISO
@@ -166,7 +161,7 @@ private function processCountryData($CNT_ISO, $countries = array())
      * @param string $url
      * @return array
      */
-    private function retrieveJsonData($url)
+    private function retrieveJsonData(string $url): array
     {
         if (empty($url)) {
             EE_Error::add_error(
@@ -204,9 +199,8 @@ private function retrieveJsonData($url)
      * @throws InvalidArgumentException
      * @throws InvalidDataTypeException
      * @throws InvalidInterfaceException
-     * @throws ReflectionException
      */
-    private function saveSubRegionData(stdClass $country, $sub_regions = array())
+    private function saveSubRegionData(stdClass $country, array $sub_regions = array()): int
     {
         $results = 0;
         if (is_array($sub_regions)) {
@@ -244,15 +238,14 @@ private function saveSubRegionData(stdClass $country, $sub_regions = array())
 
     /**
      * @param string $CNT_ISO
-     * @since 4.9.76.p
      * @return array
      * @throws EE_Error
      * @throws InvalidArgumentException
      * @throws InvalidDataTypeException
      * @throws InvalidInterfaceException
-     * @throws ReflectionException
+     *@since 4.9.76.p
      */
-    private function getExistingStateAbbreviations($CNT_ISO)
+    private function getExistingStateAbbreviations(string $CNT_ISO): array
     {
         $existing_sub_region_IDs = [];
         $existing_sub_regions = $this->state_model->get_all(array(
diff --git a/core/services/address/formatters/AddressFormatter.php b/core/services/address/formatters/AddressFormatter.php
index f4d1bfec6d2..0790c7b791a 100644
--- a/core/services/address/formatters/AddressFormatter.php
+++ b/core/services/address/formatters/AddressFormatter.php
@@ -22,18 +22,18 @@ class AddressFormatter
      * @param string $country
      * @param string $formatted_address
      * @param string $sub
-     * @return mixed
+     * @return string
      */
     protected function parse_formatted_address(
-        $address,
-        $address2,
-        $city,
-        $state,
-        $zip,
-        $country,
-        $formatted_address,
-        $sub
-    ) {
+        string $address,
+        string $address2,
+        string $city,
+        string $state,
+        string $zip,
+        string $country,
+        string $formatted_address,
+        string $sub
+    ): string {
         // swap address part placeholders for the real text
         $formatted_address = str_replace(
             // find
diff --git a/core/services/address/formatters/InlineAddressFormatter.php b/core/services/address/formatters/InlineAddressFormatter.php
index 82ce790ee0f..d3c8c0eeba8 100644
--- a/core/services/address/formatters/InlineAddressFormatter.php
+++ b/core/services/address/formatters/InlineAddressFormatter.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\services\address\formatters;
 
+use EEI_Address_Formatter;
+
 /**
  * Class InlineAddressFormatter
  * This class will format an address and add commas in appropriate places
@@ -11,7 +13,7 @@
  * @author        Brent Christensen
  * @since         4.8
  */
-class InlineAddressFormatter extends AddressFormatter implements \EEI_Address_Formatter
+class InlineAddressFormatter extends AddressFormatter implements EEI_Address_Formatter
 {
     /**
      * @param string $address
@@ -23,8 +25,15 @@ class InlineAddressFormatter extends AddressFormatter implements \EEI_Address_Fo
      * @param string $CNT_ISO
      * @return string
      */
-    public function format($address, $address2, $city, $state, $zip, $country, $CNT_ISO)
-    {
+    public function format(
+        string $address,
+        string $address2,
+        string $city,
+        string $state,
+        string $zip,
+        string $country,
+        string $CNT_ISO
+    ): string {
         $address_formats = apply_filters(
             'FHEE__EE_Inline_Address_Formatter__address_formats',
             array(
@@ -35,8 +44,7 @@ public function format($address, $address2, $city, $state, $zip, $country, $CNT_
             )
         );
         // if the incoming country has a set format, use that, else use the default
-        $formatted_address = isset($address_formats[ $CNT_ISO ]) ? $address_formats[ $CNT_ISO ]
-            : $address_formats['ZZZ'];
+        $formatted_address = $address_formats[ $CNT_ISO ] ?? $address_formats['ZZZ'];
         return $this->parse_formatted_address(
             $address,
             $address2,
diff --git a/core/services/address/formatters/MultiLineAddressFormatter.php b/core/services/address/formatters/MultiLineAddressFormatter.php
index 50e8f7f1546..c20ed6f7831 100644
--- a/core/services/address/formatters/MultiLineAddressFormatter.php
+++ b/core/services/address/formatters/MultiLineAddressFormatter.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\services\address\formatters;
 
+use EEI_Address_Formatter;
+
 /**
  * Class MultiLineAddressFormatter
  * This class will format an address and add line breaks in appropriate places
@@ -11,7 +13,7 @@
  * @author        Brent Christensen
  * @since         4.8
  */
-class MultiLineAddressFormatter extends AddressFormatter implements \EEI_Address_Formatter
+class MultiLineAddressFormatter extends AddressFormatter implements EEI_Address_Formatter
 {
     /**
      * @param string $address
@@ -23,8 +25,15 @@ class MultiLineAddressFormatter extends AddressFormatter implements \EEI_Address
      * @param string $CNT_ISO
      * @return string
      */
-    public function format($address, $address2, $city, $state, $zip, $country, $CNT_ISO)
-    {
+    public function format(
+        string $address,
+        string $address2,
+        string $city,
+        string $state,
+        string $zip,
+        string $country,
+        string $CNT_ISO
+    ): string {
         $address_formats = apply_filters(
             'FHEE__EE_MultiLine_Address_Formatter__address_formats',
             array(
@@ -35,8 +44,7 @@ public function format($address, $address2, $city, $state, $zip, $country, $CNT_
             )
         );
         // if the incoming country has a set format, use that, else use the default
-        $formatted_address = isset($address_formats[ $CNT_ISO ]) ? $address_formats[ $CNT_ISO ]
-            : $address_formats['ZZ'];
+        $formatted_address = $address_formats[ $CNT_ISO ] ?? $address_formats['ZZ'];
         return $this->parse_formatted_address(
             $address,
             $address2,
diff --git a/core/services/address/formatters/NullAddressFormatter.php b/core/services/address/formatters/NullAddressFormatter.php
index 15120e94f25..2f0c50d5df1 100644
--- a/core/services/address/formatters/NullAddressFormatter.php
+++ b/core/services/address/formatters/NullAddressFormatter.php
@@ -20,10 +20,17 @@ class NullAddressFormatter implements \EEI_Address_Formatter
      * @param string $zip
      * @param string $country
      * @param string $CNT_ISO
-     * @return string
+     * @return null
      */
-    public function format($address, $address2, $city, $state, $zip, $country, $CNT_ISO)
-    {
+    public function format(
+        string $address,
+        string $address2,
+        string $city,
+        string $state,
+        string $zip,
+        string $country,
+        string $CNT_ISO
+    ): ?string {
         return null;
     }
 }
diff --git a/core/services/bootstrap/BootstrapCore.php b/core/services/bootstrap/BootstrapCore.php
index ba0e7c2fd8e..18d74967c0e 100644
--- a/core/services/bootstrap/BootstrapCore.php
+++ b/core/services/bootstrap/BootstrapCore.php
@@ -10,6 +10,7 @@
 use EventEspresso\core\exceptions\InvalidDataTypeException;
 use EventEspresso\core\exceptions\InvalidFilePathException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\loaders\LoaderInterface;
 use EventEspresso\core\services\request\InvalidRequestStackMiddlewareException;
 use EventEspresso\core\services\request\RequestInterface;
@@ -44,7 +45,7 @@
  * @author  Brent Christensen
  * @since   4.9.59.p
  */
-class BootstrapCore
+class BootstrapCore implements InterminableInterface
 {
     /**
      * @type LoaderInterface $loader
diff --git a/core/services/bootstrap/BootstrapDependencyInjectionContainer.php b/core/services/bootstrap/BootstrapDependencyInjectionContainer.php
index 0a8bdc71a3b..0e6c6d2d373 100644
--- a/core/services/bootstrap/BootstrapDependencyInjectionContainer.php
+++ b/core/services/bootstrap/BootstrapDependencyInjectionContainer.php
@@ -7,6 +7,7 @@
 use EE_Registry;
 use EventEspresso\core\exceptions\InvalidDataTypeException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\container\Mirror;
 use EventEspresso\core\services\loaders\ClassInterfaceCache;
 use EventEspresso\core\services\loaders\LoaderFactory;
@@ -22,7 +23,7 @@
  * @author  Brent Christensen
  * @since   4.9.59.p
  */
-class BootstrapDependencyInjectionContainer
+class BootstrapDependencyInjectionContainer implements InterminableInterface
 {
     /**
      * @var EE_Dependency_Map $dependency_map
diff --git a/core/services/bootstrap/BootstrapRequestResponseObjects.php b/core/services/bootstrap/BootstrapRequestResponseObjects.php
index ac1628dfcfd..fb8ca0e6480 100644
--- a/core/services/bootstrap/BootstrapRequestResponseObjects.php
+++ b/core/services/bootstrap/BootstrapRequestResponseObjects.php
@@ -5,6 +5,7 @@
 use EE_Dependency_Map;
 use EE_Error;
 use EE_Request;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\loaders\LoaderInterface;
 use EventEspresso\core\services\request\LegacyRequestInterface;
 use EventEspresso\core\services\request\Request;
@@ -26,7 +27,7 @@
  * @author  Brent Christensen
  * @since   4.9.53
  */
-class BootstrapRequestResponseObjects
+class BootstrapRequestResponseObjects implements InterminableInterface
 {
     /**
      * @type LegacyRequestInterface $legacy_request
diff --git a/core/services/collections/Collection.php b/core/services/collections/Collection.php
index 5d2c23d4f8a..0746f5d05af 100644
--- a/core/services/collections/Collection.php
+++ b/core/services/collections/Collection.php
@@ -4,6 +4,7 @@
 
 use EventEspresso\core\exceptions\InvalidEntityException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
+use EventEspresso\core\interfaces\InterminableInterface;
 use LimitIterator;
 use SplObjectStorage;
 
@@ -51,7 +52,7 @@ class Collection extends SplObjectStorage implements CollectionInterface
      * @param string $collection_name
      * @throws InvalidInterfaceException
      */
-    public function __construct($collection_interface, $collection_name = '')
+    public function __construct(string $collection_interface, string $collection_name = '')
     {
         $this->setCollectionInterface($collection_interface);
         $this->setCollectionName($collection_name);
@@ -75,7 +76,7 @@ public function collectionInterface(): string
      * @param  string $collection_interface
      * @throws InvalidInterfaceException
      */
-    protected function setCollectionInterface($collection_interface)
+    protected function setCollectionInterface(string $collection_interface)
     {
         if (! (interface_exists($collection_interface) || class_exists($collection_interface))) {
             throw new InvalidInterfaceException($collection_interface);
@@ -87,7 +88,7 @@ protected function setCollectionInterface($collection_interface)
     /**
      * @return string
      */
-    public function collectionName()
+    public function collectionName(): string
     {
         return $this->collection_name;
     }
@@ -96,7 +97,7 @@ public function collectionName()
     /**
      * @param string $collection_name
      */
-    protected function setCollectionName($collection_name)
+    protected function setCollectionName(string $collection_name)
     {
         $this->collection_name = ! empty($collection_name)
             ? sanitize_key($collection_name)
@@ -107,7 +108,7 @@ protected function setCollectionName($collection_name)
     /**
      * @return string
      */
-    public function collectionIdentifier()
+    public function collectionIdentifier(): string
     {
         return $this->collection_identifier;
     }
@@ -138,22 +139,22 @@ protected function setCollectionIdentifier()
      * and sets any supplied data associated with the current iterator entry
      * by calling EE_Object_Collection::set_identifier()
      *
-     * @param        $object
-     * @param  mixed $identifier
+     * @param mixed $object
+     * @param mixed $identifier
      * @return bool
      * @throws InvalidEntityException
      * @throws DuplicateCollectionIdentifierException
      */
-    public function add($object, $identifier = null)
+    public function add($object, $identifier = null): bool
     {
         if (! $object instanceof $this->collection_interface) {
             throw new InvalidEntityException($object, $this->collection_interface);
         }
-        if ($this->contains($object)) {
+        $identifier = $this->getIdentifier($object, $identifier);
+        if ($this->contains($object) || $this->has($identifier)) {
             throw new DuplicateCollectionIdentifierException($identifier);
         }
-        $this->attach($object);
-        $this->setIdentifier($object, $identifier);
+        parent::attach($object, $identifier);
         return $this->contains($object);
     }
 
@@ -164,13 +165,11 @@ public function add($object, $identifier = null)
      *
      * @param        $object
      * @param  mixed $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
-        return ! empty($identifier)
-            ? $identifier
-            : spl_object_hash($object);
+        return ! empty($identifier) ? $identifier : spl_object_hash($object);
     }
 
 
@@ -183,7 +182,7 @@ public function getIdentifier($object, $identifier = null)
      * @param  mixed $identifier
      * @return bool
      */
-    public function setIdentifier($object, $identifier = null)
+    public function setIdentifier($object, $identifier = null): bool
     {
         $identifier = $this->getIdentifier($object, $identifier);
         $this->rewind();
@@ -231,7 +230,7 @@ public function get($identifier)
      * @param  mixed $identifier
      * @return bool
      */
-    public function has($identifier)
+    public function has($identifier): bool
     {
         $this->rewind();
         while ($this->valid()) {
@@ -252,7 +251,7 @@ public function has($identifier)
      * @param $object
      * @return bool
      */
-    public function hasObject($object)
+    public function hasObject($object): bool
     {
         return $this->contains($object);
     }
@@ -264,7 +263,7 @@ public function hasObject($object)
      *
      * @return bool
      */
-    public function hasObjects()
+    public function hasObjects(): bool
     {
         return $this->count() !== 0;
     }
@@ -276,7 +275,7 @@ public function hasObjects()
      *
      * @return bool
      */
-    public function isEmpty()
+    public function isEmpty(): bool
     {
         return $this->count() === 0;
     }
@@ -289,13 +288,35 @@ public function isEmpty()
      * @param $object
      * @return bool
      */
-    public function remove($object)
+    public function remove($object): bool
     {
         $this->detach($object);
         return true;
     }
 
 
+    /**
+     * detaches the object matching the supplied identifier from the Collection
+     *
+     * @param mixed $identifier
+     * @return bool
+     */
+    public function removeByIdentifier($identifier): bool
+    {
+        $this->rewind();
+        while ($this->valid()) {
+            $object = $this->current();
+            $this->next();
+            if ($identifier === $this->getInfo()) {
+                $this->detach($object);
+                unset($object);
+                return true;
+            }
+        }
+        return false;
+    }
+
+
     /**
      * setCurrent
      * advances pointer to the object whose identifier matches that which was provided
@@ -303,7 +324,7 @@ public function remove($object)
      * @param mixed $identifier
      * @return boolean
      */
-    public function setCurrent($identifier)
+    public function setCurrent($identifier): bool
     {
         $this->rewind();
         while ($this->valid()) {
@@ -323,7 +344,7 @@ public function setCurrent($identifier)
      * @param $object
      * @return boolean
      */
-    public function setCurrentUsingObject($object)
+    public function setCurrentUsingObject($object): bool
     {
         $this->rewind();
         while ($this->valid()) {
@@ -358,7 +379,7 @@ public function previous()
      *
      * @see http://stackoverflow.com/a/8736013
      * @param $object
-     * @return boolean|int|string
+     * @return boolean|int
      */
     public function indexOf($object)
     {
@@ -397,7 +418,7 @@ public function objectAtIndex($index)
      * @param int $length
      * @return array
      */
-    public function slice($offset, $length)
+    public function slice($offset, $length): array
     {
         $slice = array();
         $iterator = new LimitIterator($this, $offset, $length);
@@ -419,7 +440,7 @@ public function slice($offset, $length)
      * @throws DuplicateCollectionIdentifierException
      * @throws InvalidEntityException
      */
-    public function insertObjectAt($object, $index, $identifier = null)
+    public function insertObjectAt($object, int $index, $identifier = null): bool
     {
         // check to ensure that objects don't already exist in the collection
         if ($this->has($identifier)) {
@@ -480,11 +501,11 @@ public function insertAt($objects, $index)
         }
         // add the new objects we're splicing in
         foreach ($objects as $object) {
-            $this->attach($object);
+            $this->add($object);
         }
         // attach the objects we previously detached
         foreach ($remaining as $object) {
-            $this->attach($object);
+            $this->add($object);
         }
     }
 
@@ -524,8 +545,10 @@ public function trashAndDetachAll()
         while ($this->valid()) {
             $object = $this->current();
             $this->next();
-            $this->detach($object);
-            unset($object);
+            if (! $object instanceof InterminableInterface) {
+                $this->detach($object);
+                unset($object);
+            }
         }
     }
 }
diff --git a/core/services/collections/CollectionDetails.php b/core/services/collections/CollectionDetails.php
index e77049bc474..75cdde51e95 100644
--- a/core/services/collections/CollectionDetails.php
+++ b/core/services/collections/CollectionDetails.php
@@ -2,7 +2,7 @@
 
 namespace EventEspresso\core\services\collections;
 
-use EventEspresso\core\exceptions\InvalidDataTypeException;
+use EventEspresso\core\exceptions\InvalidClassException;
 use EventEspresso\core\exceptions\InvalidFilePathException;
 use EventEspresso\core\exceptions\InvalidIdentifierException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
@@ -139,7 +139,6 @@ class CollectionDetails implements CollectionDetailsInterface
     /**
      * CollectionDetails constructor.
      *
-     * @access public
      * @param string           $collection_name
      * @param string           $collection_interface
      * @param array            $collection_FQCNs
@@ -147,17 +146,17 @@ class CollectionDetails implements CollectionDetailsInterface
      * @param string           $file_mask
      * @param string           $identifier_type
      * @param string           $identifier_callback
-     * @param LocatorInterface $file_locator
+     * @param LocatorInterface|null $file_locator
      * @throws CollectionDetailsException
      */
     public function __construct(
-        $collection_name,
-        $collection_interface,
+        string $collection_name,
+        string $collection_interface,
         array $collection_FQCNs = array(),
         array $collection_paths = array(),
-        $file_mask = '',
-        $identifier_type = CollectionDetails::ID_OBJECT_HASH,
-        $identifier_callback = '',
+        string $file_mask = '',
+        string $identifier_type = CollectionDetails::ID_OBJECT_HASH,
+        string $identifier_callback = '',
         LocatorInterface $file_locator = null
     ) {
         try {
@@ -176,21 +175,19 @@ public function __construct(
 
 
     /**
-     * @access public
-     * @return mixed
+     * @return string
      */
-    public function getCollectionInterface()
+    public function getCollectionInterface(): string
     {
         return $this->collection_interface;
     }
 
 
     /**
-     * @access protected
      * @param string $collection_interface
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
+     * @throws InvalidInterfaceException
      */
-    protected function setCollectionInterface($collection_interface)
+    protected function setCollectionInterface(string $collection_interface)
     {
         if (! (interface_exists($collection_interface) || class_exists($collection_interface))) {
             throw new InvalidInterfaceException($collection_interface);
@@ -202,10 +199,9 @@ protected function setCollectionInterface($collection_interface)
     /**
      * the collection name will be used for creating dynamic filters
      *
-     * @access public
      * @return string
      */
-    public function collectionName()
+    public function collectionName(): string
     {
         return $this->collection_name;
     }
@@ -214,15 +210,10 @@ public function collectionName()
     /**
      * sanitizes collection name and converts spaces and dashes to underscores
      *
-     * @access protected
      * @param string $collection_name
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
      */
-    protected function setCollectionName($collection_name)
+    protected function setCollectionName(string $collection_name)
     {
-        if (! is_string($collection_name)) {
-            throw new InvalidDataTypeException('$collection_name', $collection_name, 'string');
-        }
         $this->collection_name = str_replace(
             '-',
             '_',
@@ -232,26 +223,25 @@ protected function setCollectionName($collection_name)
 
 
     /**
-     * @access public
      * @return string
      */
-    public function identifierType()
+    public function identifierType(): string
     {
         return $this->identifier_type;
     }
 
 
     /**
-     * @access protected
      * @param string $identifier_type
      * @throws InvalidIdentifierException
      */
-    protected function setIdentifierType($identifier_type)
+    protected function setIdentifierType(string $identifier_type)
     {
         if (
-            ! ($identifier_type === CollectionDetails::ID_CLASS_NAME
-               || $identifier_type === CollectionDetails::ID_OBJECT_HASH
-               || $identifier_type === CollectionDetails::ID_CALLBACK_METHOD
+            ! (
+                $identifier_type === CollectionDetails::ID_CLASS_NAME
+                || $identifier_type === CollectionDetails::ID_OBJECT_HASH
+                || $identifier_type === CollectionDetails::ID_CALLBACK_METHOD
             )
         ) {
             throw new InvalidIdentifierException(
@@ -264,34 +254,27 @@ protected function setIdentifierType($identifier_type)
 
 
     /**
-     * @access public
      * @return string
      */
-    public function identifierCallback()
+    public function identifierCallback(): string
     {
         return $this->identifier_callback;
     }
 
 
     /**
-     * @access protected
      * @param string $identifier_callback
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
      */
-    protected function setIdentifierCallback($identifier_callback = 'identifier')
+    protected function setIdentifierCallback(string $identifier_callback = 'identifier')
     {
-        if (! is_string($identifier_callback)) {
-            throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string');
-        }
         $this->identifier_callback = $identifier_callback;
     }
 
 
     /**
-     * @access public
      * @return string
      */
-    public function getFileMask()
+    public function getFileMask(): string
     {
         return $this->file_mask;
     }
@@ -301,36 +284,26 @@ public function getFileMask()
      * sets the file mask which is then used to filter what files get loaded
      * when searching for classes to add to the collection. Defaults to '*.php'
      *
-     * @access protected
      * @param string $file_mask
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
      */
-    protected function setFileMasks($file_mask)
+    protected function setFileMasks(string $file_mask)
     {
         $this->file_mask = ! empty($file_mask) ? $file_mask : '*.php';
-        // we know our default is a string, so if it's not a string now,
-        // then that means the incoming parameter was something else
-        if (! is_string($this->file_mask)) {
-            throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string');
-        }
     }
 
 
     /**
-     * @access public
      * @return array
      */
-    public function getCollectionFQCNs()
+    public function getCollectionFQCNs(): array
     {
         return $this->collection_FQCNs;
     }
 
 
     /**
-     * @access public
      * @param string|array $collection_FQCNs
-     * @throws \EventEspresso\core\exceptions\InvalidClassException
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
+     * @throws InvalidClassException
      */
     public function setCollectionFQCNs($collection_FQCNs)
     {
@@ -339,7 +312,8 @@ public function setCollectionFQCNs($collection_FQCNs)
                 if (class_exists($collection_FQCN)) {
                     $this->collection_FQCNs[] = $collection_FQCN;
                 } else {
-                    foreach ($this->getFQCNsFromPartialNamespace($collection_FQCN) as $FQCN) {
+                    $FQCNs = $this->getFQCNsFromPartialNamespace($collection_FQCN);
+                    foreach ($FQCNs as $FQCN) {
                         $this->collection_FQCNs[] = $FQCN;
                     }
                 }
@@ -349,13 +323,11 @@ public function setCollectionFQCNs($collection_FQCNs)
 
 
     /**
-     * @access protected
-     * @param  string $partial_FQCN
+     * @param string $partial_FQCN
      * @return array
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
-     * @throws \EventEspresso\core\exceptions\InvalidClassException
+     * @throws InvalidClassException
      */
-    protected function getFQCNsFromPartialNamespace($partial_FQCN)
+    protected function getFQCNsFromPartialNamespace(string $partial_FQCN): array
     {
         if (! $this->file_locator instanceof FqcnLocator) {
             $this->file_locator = new FqcnLocator();
@@ -366,19 +338,17 @@ protected function getFQCNsFromPartialNamespace($partial_FQCN)
 
 
     /**
-     * @access public
      * @return array
      */
-    public function getCollectionPaths()
+    public function getCollectionPaths(): array
     {
         return $this->collection_paths;
     }
 
 
     /**
-     * @access public
      * @param string|array $collection_paths
-     * @throws \EventEspresso\core\exceptions\InvalidFilePathException
+     * @throws InvalidFilePathException
      */
     public function setCollectionPaths($collection_paths)
     {
diff --git a/core/services/collections/CollectionLoader.php b/core/services/collections/CollectionLoader.php
index 0ca1a605376..fe566f86138 100644
--- a/core/services/collections/CollectionLoader.php
+++ b/core/services/collections/CollectionLoader.php
@@ -73,8 +73,8 @@ class CollectionLoader
      * CollectionLoader constructor.
      *
      * @param CollectionDetailsInterface $collection_details
-     * @param CollectionInterface        $collection
-     * @param LocatorInterface           $file_locator
+     * @param CollectionInterface|null   $collection
+     * @param LocatorInterface|null      $file_locator
      * @param FactoryInterface|null      $entity_factory
      * @throws CollectionLoaderException
      */
@@ -141,7 +141,7 @@ protected function loadAllFromFilepaths()
 
 
     /**
-     * @param  string $filepath
+     * @param string|null $filepath
      * @return string
      * @throws InvalidEntityException
      * @throws InvalidDataTypeException
@@ -149,7 +149,7 @@ protected function loadAllFromFilepaths()
      * @throws InvalidClassException
      * @throws DuplicateCollectionIdentifierException
      */
-    protected function loadClassFromFilepath($filepath)
+    protected function loadClassFromFilepath(?string $filepath): string
     {
         if (! is_string($filepath)) {
             throw new InvalidDataTypeException('$filepath', $filepath, 'string');
@@ -179,7 +179,7 @@ protected function loadClassFromFilepath($filepath)
      * @throws InvalidEntityException
      * @throws DuplicateCollectionIdentifierException
      */
-    protected function addEntityToCollection($entity, $identifier)
+    protected function addEntityToCollection($entity, $identifier): string
     {
         do_action(
             'FHEE__CollectionLoader__addEntityToCollection__entity',
@@ -188,7 +188,7 @@ protected function addEntityToCollection($entity, $identifier)
             $this->collection_details
         );
         $identifier = $this->setIdentifier($entity, $identifier);
-        if ($this->collection->has($identifier)) {
+        if ($this->collection->contains($entity) || $this->collection->has($identifier)) {
             do_action(
                 'FHEE__CollectionLoader__addEntityToCollection__entity_already_added',
                 $this,
@@ -222,7 +222,7 @@ protected function addEntityToCollection($entity, $identifier)
      * @return string
      * @throws InvalidEntityException
      */
-    protected function setIdentifier($entity, $identifier)
+    protected function setIdentifier($entity, $identifier): string
     {
         switch ($this->collection_details->identifierType()) {
             // every unique object gets added to the collection, but not duplicates of the exact same object
@@ -289,7 +289,7 @@ protected function loadFromFQCNs()
 
 
     /**
-     * @param  string $FQCN Fully Qualified Class Name
+     * @param string|null $FQCN Fully Qualified Class Name
      * @return string
      * @throws InvalidArgumentException
      * @throws InvalidInterfaceException
@@ -300,7 +300,7 @@ protected function loadFromFQCNs()
      * @throws InvalidClassException
      * @throws DuplicateCollectionIdentifierException
      */
-    protected function loadClassFromFQCN($FQCN)
+    protected function loadClassFromFQCN(?string $FQCN): string
     {
         if (! is_string($FQCN)) {
             throw new InvalidDataTypeException('$FQCN', $FQCN, 'string');
diff --git a/core/services/collections/LooseCollection.php b/core/services/collections/LooseCollection.php
index 605a1f5a5e5..8a1273cce31 100644
--- a/core/services/collections/LooseCollection.php
+++ b/core/services/collections/LooseCollection.php
@@ -20,7 +20,7 @@ class LooseCollection extends Collection
      * @access protected
      * @param  string $collection_interface
      */
-    protected function setCollectionInterface($collection_interface)
+    protected function setCollectionInterface(string $collection_interface)
     {
         $this->collection_interface = '';
     }
@@ -38,13 +38,13 @@ protected function setCollectionInterface($collection_interface)
      * @return bool
      * @throws InvalidEntityException
      */
-    public function add($object, $identifier = null)
+    public function add($object, $identifier = null): bool
     {
         if (! is_object($object)) {
             throw new InvalidEntityException($object, 'object');
         }
-        $this->attach($object);
-        $this->setIdentifier($object, $identifier);
+        $identifier = $this->getIdentifier($object, $identifier);
+        parent::attach($object, $identifier);
         return $this->contains($object);
     }
 }
diff --git a/core/services/commands/CommandBusInterface.php b/core/services/commands/CommandBusInterface.php
index f149eaca3b7..45e8e4002c2 100644
--- a/core/services/commands/CommandBusInterface.php
+++ b/core/services/commands/CommandBusInterface.php
@@ -2,12 +2,14 @@
 
 namespace EventEspresso\core\services\commands;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Interface CommandBusInterface
  *
  * @package EventEspresso\core\services\commands
  */
-interface CommandBusInterface
+interface CommandBusInterface extends InterminableInterface
 {
     /**
      * @return CommandHandlerManagerInterface
diff --git a/core/services/commands/CommandFactoryInterface.php b/core/services/commands/CommandFactoryInterface.php
index 5c37e2372f8..77e0a25d848 100644
--- a/core/services/commands/CommandFactoryInterface.php
+++ b/core/services/commands/CommandFactoryInterface.php
@@ -2,11 +2,12 @@
 
 namespace EventEspresso\core\services\commands;
 
+use EventEspresso\core\interfaces\InterminableInterface;
 use InvalidArgumentException;
 use EventEspresso\core\exceptions\InvalidDataTypeException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
 
-interface CommandFactoryInterface
+interface CommandFactoryInterface extends InterminableInterface
 {
     /**
      * @param string $command_fqcn
diff --git a/core/services/commands/CommandHandlerInterface.php b/core/services/commands/CommandHandlerInterface.php
index e323dd4f16a..436189bafb0 100644
--- a/core/services/commands/CommandHandlerInterface.php
+++ b/core/services/commands/CommandHandlerInterface.php
@@ -2,12 +2,14 @@
 
 namespace EventEspresso\core\services\commands;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Interface CommandHandlerInterface
  *
  * @package EventEspresso\core\services\commands
  */
-interface CommandHandlerInterface
+interface CommandHandlerInterface extends InterminableInterface
 {
     /**
      * verifies that the supplied command is the correct class for the handler.
diff --git a/core/services/commands/CommandHandlerManagerInterface.php b/core/services/commands/CommandHandlerManagerInterface.php
index 4df0013b2b0..cf1e5b20c86 100644
--- a/core/services/commands/CommandHandlerManagerInterface.php
+++ b/core/services/commands/CommandHandlerManagerInterface.php
@@ -2,12 +2,14 @@
 
 namespace EventEspresso\core\services\commands;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Interface CommandHandlerManagerInterface
  *
  * @package EventEspresso\core\services\commands
  */
-interface CommandHandlerManagerInterface
+interface CommandHandlerManagerInterface extends InterminableInterface
 {
     /**
      * !!! IMPORTANT !!!
diff --git a/core/services/commands/middleware/CommandBusMiddlewareInterface.php b/core/services/commands/middleware/CommandBusMiddlewareInterface.php
index 9b76477e141..c868ec934f9 100644
--- a/core/services/commands/middleware/CommandBusMiddlewareInterface.php
+++ b/core/services/commands/middleware/CommandBusMiddlewareInterface.php
@@ -3,6 +3,7 @@
 namespace EventEspresso\core\services\commands\middleware;
 
 use Closure;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\commands\CommandInterface;
 
 /**
@@ -10,7 +11,7 @@
  *
  * @package EventEspresso\core\services\commands
  */
-interface CommandBusMiddlewareInterface
+interface CommandBusMiddlewareInterface extends InterminableInterface
 {
     /**
      * @param CommandInterface $command
diff --git a/core/services/database/TableAnalysis.php b/core/services/database/TableAnalysis.php
index 84485f81cd8..bef86ec94c8 100644
--- a/core/services/database/TableAnalysis.php
+++ b/core/services/database/TableAnalysis.php
@@ -2,6 +2,11 @@
 
 namespace EventEspresso\core\services\database;
 
+use EE_Base;
+use EEH_Activation;
+use EventEspresso\core\interfaces\InterminableInterface;
+use wpdb;
+
 /**
  * Class TableAnalysis
  * For analyzing database tables; should not perform any manipulation, or have
@@ -11,7 +16,7 @@
  * @subpackage
  * @author                Mike Nelson
  */
-class TableAnalysis extends \EE_Base
+class TableAnalysis extends EE_Base implements InterminableInterface
 {
     /**
      * The maximum number of characters that can be indexed on a column using utf8mb4 collation,
@@ -19,16 +24,17 @@ class TableAnalysis extends \EE_Base
      */
     const INDEX_COLUMN_SIZE = 191;
 
+
     /**
      * Returns the table name which will definitely have the wpdb prefix on the front,
      * except if it currently has the wpdb->base_prefix on the front, in which case
      * it will have the wpdb->base_prefix on it
      *
-     * @global \wpdb $wpdb
      * @param string $table_name
      * @return string $tableName, having ensured it has the wpdb prefix on the front
+     * @global wpdb  $wpdb
      */
-    public function ensureTableNameHasPrefix($table_name)
+    public function ensureTableNameHasPrefix(string $table_name): string
     {
         global $wpdb;
         return strpos($table_name, $wpdb->base_prefix) === 0 ? $table_name : $wpdb->prefix . $table_name;
@@ -39,17 +45,17 @@ public function ensureTableNameHasPrefix($table_name)
      * Indicates whether or not the table has any entries. $table_name can
      * optionally start with $wpdb->prefix or not
      *
-     * @global \wpdb $wpdb
      * @param string $table_name
      * @return bool
+     * @global wpdb  $wpdb
      */
-    public function tableIsEmpty($table_name)
+    public function tableIsEmpty(string $table_name): bool
     {
         global $wpdb;
         $table_name = $this->ensureTableNameHasPrefix($table_name);
         if ($this->tableExists($table_name)) {
             $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
-            return absint($count) === 0 ? true : false;
+            return absint($count) === 0;
         }
         return false;
     }
@@ -59,39 +65,37 @@ public function tableIsEmpty($table_name)
      * Indicates whether or not the table exists. $table_name can optionally
      * have the $wpdb->prefix on the beginning, or not.
      *
-     * @global \wpdb $wpdb
-     * @global array EZSQL_Error
-     * @param        $table_name
+     * @param string $table_name
      * @return bool
+     * @global wpdb  $wpdb
      */
-    public function tableExists($table_name)
+    public function tableExists(string $table_name): bool
     {
         global $wpdb, $EZSQL_ERROR;
         $table_name = $this->ensureTableNameHasPrefix($table_name);
         // ignore if this causes an sql error
-        $old_error = $wpdb->last_error;
-        $old_suppress_errors = $wpdb->suppress_errors();
+        $old_error             = $wpdb->last_error;
+        $old_suppress_errors   = $wpdb->suppress_errors();
         $old_show_errors_value = $wpdb->show_errors(false);
-        $ezsql_error_cache = $EZSQL_ERROR;
+        $ezsql_error_cache     = $EZSQL_ERROR;
         $wpdb->get_results("SELECT * from $table_name LIMIT 1");
         $wpdb->show_errors($old_show_errors_value);
         $wpdb->suppress_errors($old_suppress_errors);
-        $new_error = $wpdb->last_error;
+        $new_error        = $wpdb->last_error;
         $wpdb->last_error = $old_error;
-        $EZSQL_ERROR = $ezsql_error_cache;
+        $EZSQL_ERROR      = $ezsql_error_cache;
         // if there was a table doesn't exist error
         if (! empty($new_error)) {
             if (
                 in_array(
-                    \EEH_Activation::last_wpdb_error_code(),
-                    array(
-                    1051, // bad table
-                    1109, // unknown table
-                    117, // no such table
-                    )
+                    EEH_Activation::last_wpdb_error_code(),
+                    [
+                        1051, // bad table
+                        1109, // unknown table
+                        117, // no such table
+                    ]
                 )
-                ||
-                preg_match(
+                || preg_match(
                     '~^Table .* doesn\'t exist~',
                     $new_error
                 ) // in case not using mysql and error codes aren't reliable, just check for this error string
@@ -115,8 +119,8 @@ public function tableExists($table_name)
 
 
     /**
-     * @param $table_name
-     * @param $index_name
+     * @param string $table_name
+     * @param string $index_name
      * @return array of columns used on that index, Each entry is an object with the following properties {
      * @type string Table
      * @type string Non_unique "0" or "1"
@@ -132,12 +136,12 @@ public function tableExists($table_name)
      * @type string Index_type
      * @type string Comment
      * @type string Index_comment
-     * }
+     *       }
      */
-    public function showIndexes($table_name, $index_name)
+    public function showIndexes(string $table_name, string $index_name): array
     {
         global $wpdb;
-        $table_name = $this->ensureTableNameHasPrefix($table_name);
+        $table_name         = $this->ensureTableNameHasPrefix($table_name);
         $index_exists_query = "SHOW INDEX FROM {$table_name} WHERE Key_name = '{$index_name}'";
         return $wpdb->get_results($index_exists_query);
     }
diff --git a/core/services/graphql/connections/ConnectionCollection.php b/core/services/graphql/connections/ConnectionCollection.php
index 01571b8fedc..060d5d3c78e 100644
--- a/core/services/graphql/connections/ConnectionCollection.php
+++ b/core/services/graphql/connections/ConnectionCollection.php
@@ -94,9 +94,9 @@ public function loadConnections()
      *
      * @param        $object
      * @param mixed  $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
diff --git a/core/services/graphql/enums/EnumCollection.php b/core/services/graphql/enums/EnumCollection.php
index a55aad78f88..49bbd807757 100644
--- a/core/services/graphql/enums/EnumCollection.php
+++ b/core/services/graphql/enums/EnumCollection.php
@@ -94,9 +94,9 @@ public function loadEnums()
      *
      * @param        $object
      * @param mixed  $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
diff --git a/core/services/graphql/inputs/InputCollection.php b/core/services/graphql/inputs/InputCollection.php
index 55ad792f1e5..a976cf7a6fb 100644
--- a/core/services/graphql/inputs/InputCollection.php
+++ b/core/services/graphql/inputs/InputCollection.php
@@ -94,9 +94,9 @@ public function loadInputs()
      *
      * @param        $object
      * @param mixed  $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
diff --git a/core/services/graphql/resolvers/ResolverCollection.php b/core/services/graphql/resolvers/ResolverCollection.php
index 82e3f46fffa..8cc59cba6d2 100644
--- a/core/services/graphql/resolvers/ResolverCollection.php
+++ b/core/services/graphql/resolvers/ResolverCollection.php
@@ -94,9 +94,9 @@ public function loadResolvers()
      *
      * @param        $object
      * @param mixed  $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
diff --git a/core/services/graphql/types/TypeCollection.php b/core/services/graphql/types/TypeCollection.php
index e69d3c71a3a..fd1f22c9d47 100644
--- a/core/services/graphql/types/TypeCollection.php
+++ b/core/services/graphql/types/TypeCollection.php
@@ -97,9 +97,9 @@ public function loadTypes()
      *
      * @param        $object
      * @param mixed  $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
diff --git a/core/services/loaders/ClassInterfaceCache.php b/core/services/loaders/ClassInterfaceCache.php
index 0bbabb69cad..7912968856c 100644
--- a/core/services/loaders/ClassInterfaceCache.php
+++ b/core/services/loaders/ClassInterfaceCache.php
@@ -4,6 +4,7 @@
 
 use EventEspresso\core\domain\values\FullyQualifiedName;
 use EventEspresso\core\exceptions\InvalidAliasException;
+use EventEspresso\core\interfaces\InterminableInterface;
 
 /**
  * Class ClassInterfaceCache
@@ -14,7 +15,7 @@
  * @author  Brent Christensen
  * @since   4.9.62.p
  */
-class ClassInterfaceCache
+class ClassInterfaceCache implements InterminableInterface
 {
     /**
      * array of interfaces indexed by FQCNs where values are arrays of interface FQNs
@@ -38,10 +39,10 @@ public function getAliases()
     }
 
     /**
-     * @param string $fqn
+     * @param string|FullyQualifiedName $fqn
      * @return string
      */
-    public function getFqn($fqn)
+    public function getFqn($fqn): string
     {
         $fqn = $fqn instanceof FullyQualifiedName ? $fqn->string() : $fqn;
         return ltrim((string) $fqn, '\\');
@@ -49,10 +50,10 @@ public function getFqn($fqn)
 
 
     /**
-     * @param string $fqn
+     * @param string|FullyQualifiedName $fqn
      * @return array
      */
-    public function getInterfaces($fqn)
+    public function getInterfaces($fqn): array
     {
         $fqn = $this->getFqn($fqn);
         // have we already seen this FQCN ?
@@ -70,11 +71,11 @@ public function getInterfaces($fqn)
 
 
     /**
-     * @param string $fqn
-     * @param string $interface
+     * @param string|FullyQualifiedName $fqn
+     * @param string|FullyQualifiedName $interface
      * @return bool
      */
-    public function hasInterface($fqn, $interface)
+    public function hasInterface($fqn, $interface): bool
     {
         $fqn        = $this->getFqn($fqn);
         $interfaces = $this->getInterfaces($fqn);
@@ -85,12 +86,12 @@ public function hasInterface($fqn, $interface)
     /**
      * adds an alias for a classname
      *
-     * @param string $fqn       the class name that should be used (concrete class to replace interface)
-     * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
-     * @param string $for_class the class that has the dependency (is type hinting for the interface)
+     * @param string|FullyQualifiedName $fqn       the class name that should be used (concrete class to replace interface)
+     * @param string|FullyQualifiedName $alias     the class name that would be type hinted for (abstract parent or interface)
+     * @param string                    $for_class the class that has the dependency (is type hinting for the interface)
      * @throws InvalidAliasException
      */
-    public function addAlias($fqn, $alias, $for_class = '')
+    public function addAlias($fqn, $alias, string $for_class = '')
     {
         $fqn   = $this->getFqn($fqn);
         $alias = $this->getFqn($alias);
@@ -113,11 +114,11 @@ public function addAlias($fqn, $alias, $for_class = '')
     /**
      * returns TRUE if the provided FQN is an alias
      *
-     * @param string $fqn
-     * @param string $for_class
+     * @param string|FullyQualifiedName $fqn
+     * @param string                    $for_class
      * @return bool
      */
-    public function isAlias($fqn = '', $for_class = '')
+    public function isAlias($fqn = '', string $for_class = ''): bool
     {
         $fqn = $this->getFqn($fqn);
         if ($this->isAliasForClass($fqn, $for_class)) {
@@ -136,9 +137,9 @@ public function isAlias($fqn = '', $for_class = '')
      * @param string $fqn
      * @return bool
      */
-    protected function isDirectAlias($fqn = '')
+    protected function isDirectAlias(string $fqn = ''): bool
     {
-        return isset($this->aliases[ (string) $fqn ]) && ! is_array($this->aliases[ (string) $fqn ]);
+        return isset($this->aliases[ $fqn ]) && ! is_array($this->aliases[ $fqn ]);
     }
 
 
@@ -149,12 +150,9 @@ protected function isDirectAlias($fqn = '')
      * @param string $for_class
      * @return bool
      */
-    protected function isAliasForClass($fqn = '', $for_class = '')
+    protected function isAliasForClass(string $fqn = '', string $for_class = ''): bool
     {
-        return (
-            $for_class !== ''
-            && isset($this->aliases[ (string) $for_class ][ (string) $fqn ])
-        );
+        return $for_class !== '' && isset($this->aliases[ $for_class ][ $fqn ]);
     }
 
 
@@ -170,19 +168,19 @@ protected function isAliasForClass($fqn = '', $for_class = '')
      *      then one could use Loader::getNew( 'interface_alias' )
      *      to load an instance of 'some\namespace\classname'
      *
-     * @param string $alias
-     * @param string $for_class
+     * @param string|FullyQualifiedName $alias
+     * @param string                    $for_class
      * @return string
      */
-    public function getFqnForAlias($alias = '', $for_class = '')
+    public function getFqnForAlias($alias = '', string $for_class = ''): string
     {
         $alias = $this->getFqn($alias);
         if ($this->isAliasForClass($alias, $for_class)) {
-            return $this->getFqnForAlias($this->aliases[ (string) $for_class ][ (string) $alias ], $for_class);
+            return $this->getFqnForAlias($this->aliases[ $for_class ][ $alias ], $for_class);
         }
         if ($this->isDirectAlias($alias)) {
             // note: changed '' to $for_class
-            return $this->getFqnForAlias($this->aliases[ (string) $alias ], $for_class);
+            return $this->getFqnForAlias($this->aliases[ $alias ], $for_class);
         }
         return $alias;
     }
diff --git a/core/services/loaders/ObjectIdentifier.php b/core/services/loaders/ObjectIdentifier.php
index 20944e93b3b..4de2d4c00c8 100644
--- a/core/services/loaders/ObjectIdentifier.php
+++ b/core/services/loaders/ObjectIdentifier.php
@@ -44,7 +44,7 @@ public function __construct(ClassInterfaceCache $class_cache)
      * @param string $object_identifier
      * @return bool
      */
-    public function hasArguments($object_identifier)
+    public function hasArguments(string $object_identifier): bool
     {
         // type casting to bool instead of using strpos() !== false
         // because an object identifier should never begin with the delimiter
@@ -65,7 +65,7 @@ public function hasArguments($object_identifier)
      * @param string $object_identifier
      * @return bool
      */
-    public function fqcnMatchesObjectIdentifier($fqcn, $object_identifier)
+    public function fqcnMatchesObjectIdentifier(string $fqcn, string $object_identifier): bool
     {
         $fqcn = str_replace('\\', '_', $fqcn);
         return $fqcn === $object_identifier
@@ -80,7 +80,7 @@ public function fqcnMatchesObjectIdentifier($fqcn, $object_identifier)
      * @param array  $arguments
      * @return string
      */
-    public function getIdentifier($fqcn, array $arguments = array())
+    public function getIdentifier(string $fqcn, array $arguments = array()): string
     {
         // only build identifier from arguments if class is not ReservedInstanceInterface
         $identifier = ! $this->class_cache->hasInterface(
@@ -104,7 +104,7 @@ public function getIdentifier($fqcn, array $arguments = array())
      * @param array $arguments
      * @return string
      */
-    protected function getIdentifierForArguments(array $arguments)
+    protected function getIdentifierForArguments(array $arguments): string
     {
         if (empty($arguments)) {
             return '';
diff --git a/core/services/locators/FqcnLocator.php b/core/services/locators/FqcnLocator.php
index 838af503069..26cb8306259 100644
--- a/core/services/locators/FqcnLocator.php
+++ b/core/services/locators/FqcnLocator.php
@@ -80,6 +80,7 @@ public function locate($namespaces): array
                 $this->FQCNs[ $key ] = $file;
             }
         }
+        $this->FQCNs = array_unique($this->FQCNs, SORT_STRING);
         return $this->FQCNs;
     }
 
@@ -104,22 +105,23 @@ protected function findFQCNsByNamespace(string $partial_namespace): array
         if (iterator_count($iterator) === 0) {
             return [];
         }
+        $FQCNs = [];
         foreach ($iterator as $file) {
             if ($file->isFile() && $file->getExtension() === 'php') {
-                $file = $file->getPath() . '/' . $file->getBasename('.php');
+                $file_name = $file->getPath() . '/' . $file->getBasename('.php');
                 foreach ($this->namespaces as $namespace => $base_dir) {
                     $namespace .= Psr4Autoloader::NS;
-                    if (strpos($file, $base_dir) === 0) {
-                        $this->FQCNs[] = Psr4Autoloader::NS . str_replace(
+                    if (strpos($file_name, $base_dir) === 0) {
+                        $FQCNs[] = Psr4Autoloader::NS . str_replace(
                             [$base_dir, '/'],
                             [$namespace, Psr4Autoloader::NS],
-                            $file
+                            $file_name
                         );
                     }
                 }
             }
         }
-        return $this->FQCNs;
+        return array_unique($FQCNs, SORT_STRING);
     }
 
 
diff --git a/core/services/orm/ModelFieldFactory.php b/core/services/orm/ModelFieldFactory.php
index 0ac9db3e04d..c511cc2f00d 100644
--- a/core/services/orm/ModelFieldFactory.php
+++ b/core/services/orm/ModelFieldFactory.php
@@ -32,6 +32,7 @@
 use EE_WP_Post_Status_Field;
 use EE_WP_Post_Type_Field;
 use EE_WP_User_Field;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\loaders\LoaderInterface;
 
 // phpcs:disable PEAR.Functions.ValidDefaultValue.NotAtEnd
@@ -44,7 +45,7 @@
  * @author  Brent Christensen
  * @since   4.9.45
  */
-class ModelFieldFactory
+class ModelFieldFactory implements InterminableInterface
 {
     /**
      * @var LoaderInterface $loader
@@ -64,10 +65,10 @@ public function __construct(LoaderInterface $loader)
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_All_Caps_Text_Field
      */
     public function createAllCapsTextField(
@@ -84,11 +85,11 @@ public function createAllCapsTextField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
-     * @param string $model_name
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
+     * @param string     $model_name
      * @return EE_Any_Foreign_Model_Name_Field
      */
     public function createAnyForeignModelNameField(
@@ -106,10 +107,10 @@ public function createAnyForeignModelNameField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Boolean_Field
      */
     public function createBooleanField(
@@ -126,27 +127,35 @@ public function createBooleanField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param string $default_value
+     * @param string      $table_column
+     * @param string      $nice_name
+     * @param bool|null   $nullable
+     * @param string|null $default_value
      * @return EE_Datetime_Field
      */
     public function createDatetimeField(
         string $table_column,
         string $nice_name,
-        bool $nullable = false,
-        string $default_value = EE_Datetime_Field::now
+        ?bool $nullable = false,
+        ?string $default_value = EE_Datetime_Field::now
     ): EE_Datetime_Field {
-        return $this->loader->getNew('EE_Datetime_Field', [$table_column, $nice_name, $nullable, $default_value,]);
+        return $this->loader->getNew(
+            'EE_Datetime_Field',
+            [
+                $table_column,
+                $nice_name,
+                $nullable,
+                $default_value,
+            ]
+        );
     }
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_DB_Only_Float_Field
      */
     public function createDbOnlyFloatField(
@@ -163,10 +172,10 @@ public function createDbOnlyFloatField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_DB_Only_Int_Field
      */
     public function createDbOnlyIntField(
@@ -183,10 +192,10 @@ public function createDbOnlyIntField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_DB_Only_Text_Field
      */
     public function createDbOnlyTextField(
@@ -223,12 +232,12 @@ public function createEmailField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
-     * @param array  $allowed_enum_values keys are values to be used in the DB,
-     *                                    values are how they should be displayed
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
+     * @param array      $allowed_enum_values keys are values to be used in the DB,
+     *                                        values are how they should be displayed
      * @return EE_Enum_Integer_Field
      */
     public function createEnumIntegerField(
@@ -246,12 +255,12 @@ public function createEnumIntegerField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
-     * @param array  $allowed_enum_values keys are values to be used in the DB,
-     *                                    values are how they should be displayed
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
+     * @param array      $allowed_enum_values keys are values to be used in the DB,
+     *                                        values are how they should be displayed
      * @return EE_Enum_Text_Field
      */
     public function createEnumTextField(
@@ -269,10 +278,10 @@ public function createEnumTextField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Float_Field
      */
     public function createFloatField(
@@ -289,11 +298,11 @@ public function createFloatField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
-     * @param string $model_name
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
+     * @param string     $model_name
      * @return EE_Foreign_Key_Int_Field
      */
     public function createForeignKeyIntField(
@@ -311,11 +320,11 @@ public function createForeignKeyIntField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
-     * @param string $model_name
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
+     * @param string     $model_name
      * @return EE_Foreign_Key_String_Field
      */
     public function createForeignKeyStringField(
@@ -333,10 +342,10 @@ public function createForeignKeyStringField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Full_HTML_Field
      */
     public function createFullHtmlField(
@@ -353,10 +362,10 @@ public function createFullHtmlField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Infinite_Integer_Field
      */
     public function createInfiniteIntegerField(
@@ -373,10 +382,10 @@ public function createInfiniteIntegerField(
 
 
     /**
-     * @param string  $table_column
-     * @param string  $nice_name
-     * @param bool    $nullable
-     * @param integer $default_value
+     * @param string $table_column
+     * @param string $nice_name
+     * @param bool   $nullable
+     * @param int    $default_value
      * @return EE_Integer_Field
      */
     public function createIntegerField(
@@ -393,10 +402,10 @@ public function createIntegerField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Maybe_Serialized_Simple_HTML_Field
      */
     public function createMaybeSerializedSimpleHtmlField(
@@ -413,10 +422,10 @@ public function createMaybeSerializedSimpleHtmlField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Maybe_Serialized_Text_Field
      */
     public function createMaybeSerializedTextField(
@@ -433,10 +442,10 @@ public function createMaybeSerializedTextField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Money_Field
      */
     public function createMoneyField(
@@ -473,10 +482,10 @@ public function createPlainTextField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Post_Content_Field
      */
     public function createPostContentField(
@@ -515,10 +524,10 @@ public function createPrimaryKeyStringField(string $table_column, string $nice_n
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Serialized_Text_Field
      */
     public function createSerializedTextField(
@@ -535,10 +544,10 @@ public function createSerializedTextField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Simple_HTML_Field
      */
     public function createSimpleHtmlField(
@@ -555,10 +564,10 @@ public function createSimpleHtmlField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Slug_Field
      */
     public function createSlugField(
@@ -575,10 +584,10 @@ public function createSlugField(
 
 
     /**
-     * @param string $table_column
-     * @param string $nice_name
-     * @param bool   $nullable
-     * @param null   $default_value
+     * @param string     $table_column
+     * @param string     $nice_name
+     * @param bool       $nullable
+     * @param mixed|null $default_value
      * @return EE_Trashed_Flag_Field
      */
     public function createTrashedFlagField(
diff --git a/core/services/request/Response.php b/core/services/request/Response.php
index 63b50b9a9fb..25894fd5cd1 100644
--- a/core/services/request/Response.php
+++ b/core/services/request/Response.php
@@ -2,6 +2,7 @@
 
 namespace EventEspresso\core\services\request;
 
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\interfaces\ReservedInstanceInterface;
 
 /**
@@ -12,7 +13,7 @@
  * @subpackage      /core/
  * @author          Brent Christensen
  */
-class Response implements ResponseInterface, ReservedInstanceInterface
+class Response implements InterminableInterface, ResponseInterface, ReservedInstanceInterface
 {
     /**
      * @var array $notice
@@ -63,14 +64,14 @@ public function setNotice($key, $value)
      */
     public function getNotice($key)
     {
-        return isset($this->notice[ $key ]) ? $this->notice[ $key ] : null;
+        return $this->notice[ $key ] ?? null;
     }
 
 
     /**
      * @return array
      */
-    public function getNotices()
+    public function getNotices(): array
     {
         return $this->notice;
     }
@@ -102,16 +103,16 @@ public function getOutput($as_string = true, $separator = PHP_EOL)
 
 
     /**
-     * @return boolean
+     * @return bool
      */
-    public function requestTerminated()
+    public function requestTerminated(): bool
     {
         return $this->request_terminated;
     }
 
 
     /**
-     * @param boolean $request_terminated
+     * @param bool $request_terminated
      */
     public function terminateRequest($request_terminated = true)
     {
@@ -120,9 +121,9 @@ public function terminateRequest($request_terminated = true)
 
 
     /**
-     * @return boolean
+     * @return bool
      */
-    public function pluginDeactivated()
+    public function pluginDeactivated(): bool
     {
         return $this->deactivate_plugin;
     }
diff --git a/core/services/request/middleware/Middleware.php b/core/services/request/middleware/Middleware.php
index dfa1fb0955f..9fb5cb3644c 100644
--- a/core/services/request/middleware/Middleware.php
+++ b/core/services/request/middleware/Middleware.php
@@ -2,6 +2,7 @@
 
 namespace EventEspresso\core\services\request\middleware;
 
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\loaders\LoaderInterface;
 use EventEspresso\core\services\request\RequestDecoratorInterface;
 use EventEspresso\core\services\request\RequestInterface;
@@ -22,7 +23,7 @@
  * @author  Brent Christensen
  * @since   4.9.52
  */
-abstract class Middleware implements RequestDecoratorInterface
+abstract class Middleware implements InterminableInterface, RequestDecoratorInterface
 {
     /**
      * @var RequestDecoratorInterface $request_stack_app
diff --git a/core/services/request/sanitizers/AllowedTags.php b/core/services/request/sanitizers/AllowedTags.php
index c0248eeca03..80085a298c0 100644
--- a/core/services/request/sanitizers/AllowedTags.php
+++ b/core/services/request/sanitizers/AllowedTags.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\services\request\sanitizers;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Class AllowedTags
  * expanded list of tags and attributes for use with wp_kses()
@@ -10,7 +12,7 @@
  * @package EventEspresso\core\services\request\sanitizers
  * @since   4.10.29.p
  */
-class AllowedTags
+class AllowedTags implements InterminableInterface
 {
     /**
      * @var array[]
diff --git a/core/services/request/sanitizers/AttributesSanitizer.php b/core/services/request/sanitizers/AttributesSanitizer.php
index 22c9009c4ca..4299bb1584c 100644
--- a/core/services/request/sanitizers/AttributesSanitizer.php
+++ b/core/services/request/sanitizers/AttributesSanitizer.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\services\request\sanitizers;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Class MultipleAttributes
  *
@@ -9,7 +11,7 @@
  * @package EventEspresso\core\services\request\sanitizers
  * @since   4.10.31.p
  */
-class AttributesSanitizer
+class AttributesSanitizer implements InterminableInterface
 {
     /**
      * @param string $attributes
diff --git a/core/services/request/sanitizers/RequestSanitizer.php b/core/services/request/sanitizers/RequestSanitizer.php
index 0220af1d767..a6e54c24fe9 100644
--- a/core/services/request/sanitizers/RequestSanitizer.php
+++ b/core/services/request/sanitizers/RequestSanitizer.php
@@ -2,9 +2,10 @@
 
 namespace EventEspresso\core\services\request\sanitizers;
 
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\request\DataType;
 
-class RequestSanitizer
+class RequestSanitizer implements InterminableInterface
 {
     /**
      * Will sanitize the supplied request parameter based on the specified data type
diff --git a/core/services/request/sanitizers/ServerSanitizer.php b/core/services/request/sanitizers/ServerSanitizer.php
index 88d035136fe..aab89f88494 100644
--- a/core/services/request/sanitizers/ServerSanitizer.php
+++ b/core/services/request/sanitizers/ServerSanitizer.php
@@ -2,6 +2,8 @@
 
 namespace EventEspresso\core\services\request\sanitizers;
 
+use EventEspresso\core\interfaces\InterminableInterface;
+
 /**
  * Class ServerSanitizer
  *
@@ -9,7 +11,7 @@
  * @package EventEspresso\core\services\request\sanitizers
  * @since   4.10.14.p
  */
-class ServerSanitizer
+class ServerSanitizer implements InterminableInterface
 {
     /**
      * @param string $key
diff --git a/core/services/routing/RouteCollection.php b/core/services/routing/RouteCollection.php
index a30fd54e356..8a5e0c91df2 100644
--- a/core/services/routing/RouteCollection.php
+++ b/core/services/routing/RouteCollection.php
@@ -2,7 +2,6 @@
 
 namespace EventEspresso\core\services\routing;
 
-use EventEspresso\core\services\routing\RouteInterface;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
 use EventEspresso\core\services\collections\Collection;
 
@@ -40,9 +39,9 @@ public function __construct()
      *
      * @param        $object
      * @param mixed  $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
@@ -55,7 +54,7 @@ public function getIdentifier($object, $identifier = null)
      *
      * @return RouteInterface[]
      */
-    public function getRoutesForCurrentRequest()
+    public function getRoutesForCurrentRequest(): array
     {
         $routes = [];
         $this->rewind();
diff --git a/core/services/routing/RouteMatchSpecificationCollection.php b/core/services/routing/RouteMatchSpecificationCollection.php
index 65b4ba8e56c..b555bbf27a7 100644
--- a/core/services/routing/RouteMatchSpecificationCollection.php
+++ b/core/services/routing/RouteMatchSpecificationCollection.php
@@ -39,9 +39,9 @@ public function __construct()
      *
      * @param        $object
      * @param  mixed $identifier
-     * @return bool
+     * @return string
      */
-    public function getIdentifier($object, $identifier = null)
+    public function getIdentifier($object, $identifier = null): string
     {
         return ! empty($identifier)
             ? $identifier
diff --git a/core/services/routing/RouteMatchSpecificationFactory.php b/core/services/routing/RouteMatchSpecificationFactory.php
index ad7875af45e..72102e665fa 100644
--- a/core/services/routing/RouteMatchSpecificationFactory.php
+++ b/core/services/routing/RouteMatchSpecificationFactory.php
@@ -5,6 +5,7 @@
 use EventEspresso\core\domain\entities\routing\specifications\RouteMatchSpecification;
 use EventEspresso\core\exceptions\InvalidDataTypeException;
 use EventEspresso\core\exceptions\InvalidInterfaceException;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\factory\FactoryWithDependencyResolver;
 use EventEspresso\core\services\loaders\LoaderFactory;
 use EventEspresso\core\services\loaders\LoaderInterface;
@@ -20,7 +21,7 @@
  * @author  Brent Christensen
  * @since   4.9.71.p
  */
-class RouteMatchSpecificationFactory extends FactoryWithDependencyResolver
+class RouteMatchSpecificationFactory extends FactoryWithDependencyResolver implements InterminableInterface
 {
     /**
      * RouteMatchSpecificationFactory constructor
@@ -34,12 +35,12 @@ public function __construct(RouteMatchSpecificationDependencyResolver $dependenc
     }
 
     /**
-     * @param $fqcn
+     * @param string $fqcn
      * @return RouteMatchSpecification
      * @throws InvalidDataTypeException
      * @since 4.9.71.p
      */
-    public function createNewRouteMatchSpecification($fqcn)
+    public function createNewRouteMatchSpecification(string $fqcn): RouteMatchSpecification
     {
         $this->dependencyResolver()->resolveDependenciesForClass($fqcn);
         return $this->loader()->getShared($fqcn);
@@ -47,14 +48,14 @@ public function createNewRouteMatchSpecification($fqcn)
 
 
     /**
-     * @param $fqcn
+     * @param string $fqcn
      * @return RouteMatchSpecification
      * @throws InvalidArgumentException
      * @throws InvalidDataTypeException
      * @throws InvalidInterfaceException
      * @since 4.9.71.p
      */
-    public static function create($fqcn)
+    public static function create($fqcn): RouteMatchSpecification
     {
         /** @var RouteMatchSpecificationFactory $specification_factory */
         $specification_factory = LoaderFactory::getLoader()->getShared(
diff --git a/core/services/routing/RouteMatchSpecificationManager.php b/core/services/routing/RouteMatchSpecificationManager.php
index aae2e9384eb..6ec3a6b8590 100644
--- a/core/services/routing/RouteMatchSpecificationManager.php
+++ b/core/services/routing/RouteMatchSpecificationManager.php
@@ -4,6 +4,7 @@
 
 use EventEspresso\core\domain\entities\routing\specifications\RouteMatchSpecificationInterface;
 use EventEspresso\core\exceptions\InvalidClassException;
+use EventEspresso\core\interfaces\InterminableInterface;
 use EventEspresso\core\services\collections\CollectionDetails;
 use EventEspresso\core\services\collections\CollectionDetailsException;
 use EventEspresso\core\services\collections\CollectionInterface;
@@ -16,14 +17,14 @@
  * and compares specifications in it via the currentRequestMatches() method.
  * Folders containing RouteMatchSpecification classes can be added to the collection using the
  * FHEE__EventEspresso_core_services_route_match_RouteMatchSpecificationManager__populateSpecificationCollection__collection_FQCNs
- * filter prior to the AHEE__EE_System__initialize hookpoint
+ * filter prior to the AHEE__EE_System__initialize hook point
  *
  *
  * @package EventEspresso\core\services\routing
  * @author  Brent Christensen
  * @since   4.9.71.p
  */
-class RouteMatchSpecificationManager
+class RouteMatchSpecificationManager implements InterminableInterface
 {
     /**
      * @var CollectionInterface[]|RouteMatchSpecificationInterface[] $specifications
@@ -61,19 +62,23 @@ public function __construct(
      */
     public function initialize()
     {
-        $this->populateSpecificationCollection();
+        // static $initialized = false;
+        // if (! $initialized) {
+            $this->populateSpecificationCollection();
+        //     $initialized = true;
+        // }
     }
 
 
     /**
-     * @return CollectionInterface|RouteMatchSpecificationInterface[]
+     * @return void
      * @throws CollectionLoaderException
      * @throws CollectionDetailsException
      * @since 4.9.71.p
      */
     private function populateSpecificationCollection()
     {
-        $loader = new CollectionLoader(
+        new CollectionLoader(
             new CollectionDetails(
                 // collection name
                 RouteMatchSpecificationCollection::COLLECTION_NAME,
@@ -99,7 +104,6 @@ private function populateSpecificationCollection()
             null,
             $this->specifications_factory
         );
-        return $loader->getCollection();
     }
 
 
@@ -111,7 +115,7 @@ private function populateSpecificationCollection()
      * @throws InvalidClassException
      * @since 4.9.71.p
      */
-    public function routeMatchesCurrentRequest($routeMatchSpecificationFqcn)
+    public function routeMatchesCurrentRequest(string $routeMatchSpecificationFqcn): bool
     {
         /** @var RouteMatchSpecificationInterface $specification */
         $specification = $this->specifications->get($routeMatchSpecificationFqcn);
@@ -132,7 +136,7 @@ public function routeMatchesCurrentRequest($routeMatchSpecificationFqcn)
      * @return array
      * @since 4.9.71.p
      */
-    public function findRouteMatchSpecificationsMatchingCurrentRequest()
+    public function findRouteMatchSpecificationsMatchingCurrentRequest(): array
     {
         $matches = array();
         foreach ($this->specifications as $specification) {
diff --git a/core/services/session/SessionStartHandler.php b/core/services/session/SessionStartHandler.php
index 40dd77e0335..f4e67245880 100644
--- a/core/services/session/SessionStartHandler.php
+++ b/core/services/session/SessionStartHandler.php
@@ -28,16 +28,21 @@
 class SessionStartHandler
 {
     const OPTION_NAME_SESSION_SAVE_HANDLER_STATUS = 'ee_session_save_handler_status';
-    const REQUEST_PARAM_RETRY_SESSION = 'ee_retry_session';
-    const SESSION_SAVE_HANDLER_STATUS_FAILED = 'session_save_handler_failed';
-    const SESSION_SAVE_HANDLER_STATUS_SUCCESS = 'session_save_handler_success';
-    const SESSION_SAVE_HANDLER_STATUS_UNKNOWN = 'session_save_handler_untested';
+
+    const REQUEST_PARAM_RETRY_SESSION             = 'ee_retry_session';
+
+    const SESSION_SAVE_HANDLER_STATUS_FAILED      = 'session_save_handler_failed';
+
+    const SESSION_SAVE_HANDLER_STATUS_SUCCESS     = 'session_save_handler_success';
+
+    const SESSION_SAVE_HANDLER_STATUS_UNKNOWN     = 'session_save_handler_untested';
 
     /**
      * @var RequestInterface $request
      */
     protected $request;
 
+
     /**
      * StartSession constructor.
      *
@@ -48,6 +53,7 @@ public function __construct(RequestInterface $request)
         $this->request = $request;
     }
 
+
     /**
      * Check if a custom session save handler is in play
      * and attempt to start the PHP session
@@ -68,23 +74,19 @@ public function startSession()
         }
     }
 
+
     /**
      * Returns `true` if the 'session.save_handler' ini setting matches a known custom handler
      *
-     * @since 4.9.68.p
      * @return bool
+     * @since 4.9.68.p
      */
-    private function hasKnownCustomSessionSaveHandler()
+    private function hasKnownCustomSessionSaveHandler(): bool
     {
-        return in_array(
-            ini_get('session.save_handler'),
-            array(
-                'user',
-            ),
-            true
-        );
+        return ini_get('session.save_handler') === 'user';
     }
 
+
     /**
      * Attempt to start the PHP session when a custom Session Save Handler is known to be set.
      *
@@ -119,10 +121,10 @@ private function checkCustomSessionSaveHandler()
      * retrieves the value for the 'ee_session_save_handler_status' WP option.
      * default value = 'session_save_handler_untested'
      *
-     * @since 4.9.68.p
      * @return string
+     * @since 4.9.68.p
      */
-    private function getSessionSaveHandlerStatus()
+    private function getSessionSaveHandlerStatus(): string
     {
         return get_option(
             SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS,
@@ -130,83 +132,89 @@ private function getSessionSaveHandlerStatus()
         );
     }
 
+
     /**
      * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_failed'
      * which can then be upgraded is everything works correctly
      *
+     * @return void
      * @since 4.9.68.p
-     * @return bool
      */
-    private function initializeSessionSaveHandlerStatus()
+    private function initializeSessionSaveHandlerStatus(): void
     {
-        return update_option(
+        update_option(
             SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS,
             SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_FAILED
         );
     }
 
+
     /**
      * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_success'
      *
+     * @return void
      * @since 4.9.68.p
-     * @return bool
      */
-    private function setSessionSaveHandlerStatusToValid()
+    private function setSessionSaveHandlerStatusToValid(): void
     {
-        return update_option(
+        update_option(
             SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS,
             SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_SUCCESS
         );
     }
 
+
     /**
      * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_untested'
      *
+     * @return void
      * @since 4.9.68.p
-     * @return bool
      */
-    private function resetSessionSaveHandlerStatus()
+    private function resetSessionSaveHandlerStatus(): void
     {
-        return update_option(
+        update_option(
             SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS,
             SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_UNKNOWN
         );
     }
 
+
     /**
      * Returns `true` if the 'ee_session_save_handler_status' WP option value
      * is equal to 'session_save_handler_success'
      *
-     * @since 4.9.68.p
      * @return bool
+     * @since 4.9.68.p
      */
-    private function sessionSaveHandlerIsValid()
+    private function sessionSaveHandlerIsValid(): bool
     {
         return $this->getSessionSaveHandlerStatus() === SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_SUCCESS;
     }
 
+
     /**
      * Returns `true` if the 'ee_session_save_handler_status' WP option value
      * is equal to 'session_save_handler_failed'
      *
-     * @since 4.9.68.p
      * @return bool
+     * @since 4.9.68.p
      */
-    private function sessionSaveHandlerFailed()
+    private function sessionSaveHandlerFailed(): bool
     {
         return $this->getSessionSaveHandlerStatus() === SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_FAILED;
     }
 
+
     /**
      * Returns `true` if no errors were detected with the session save handler,
      * otherwise attempts to work notify the appropriate authorities
      * with a suggestion for how to fix the issue, and returns `false`.
      *
      *
-     * @since 4.9.68.p
      * @return bool
+     * @since 4.9.68.p
      */
-    private function handleSessionSaveHandlerErrors()
+    private function handleSessionSaveHandlerErrors(): bool
     {
         // Check if we had a fatal error last time while trying to start the session
         if ($this->sessionSaveHandlerFailed()) {
@@ -218,7 +226,7 @@ private function handleSessionSaveHandlerErrors()
                 // Better to remove it and redirect, and try on the next request
                 EEH_URL::safeRedirectAndExit(
                     remove_query_arg(
-                        array(SessionStartHandler::REQUEST_PARAM_RETRY_SESSION),
+                        [SessionStartHandler::REQUEST_PARAM_RETRY_SESSION],
                         EEH_URL::current_url()
                     )
                 );
@@ -231,6 +239,7 @@ private function handleSessionSaveHandlerErrors()
         return true;
     }
 
+
     /**
      * Generates an EE_Error notice regarding the current session woes
      * but only if the current user is an admin with permission to 'install_plugins'.
@@ -241,7 +250,7 @@ private function displaySessionSaveHandlerErrorNotice()
     {
         if (current_user_can('install_plugins')) {
             $retry_session_url = add_query_arg(
-                array(SessionStartHandler::REQUEST_PARAM_RETRY_SESSION => true),
+                [SessionStartHandler::REQUEST_PARAM_RETRY_SESSION => true],
                 EEH_URL::current_url()
             );
             EE_Error::add_error(
diff --git a/tests/mocks/admin/events/Events_Admin_Page_Mock.php b/tests/mocks/admin/events/Events_Admin_Page_Mock.php
index 34310d35696..ba1e171ba48 100644
--- a/tests/mocks/admin/events/Events_Admin_Page_Mock.php
+++ b/tests/mocks/admin/events/Events_Admin_Page_Mock.php
@@ -1,51 +1,61 @@
 _default_tickets_update( $evtobj, $data );
-	}
-
-
-
-
-	/**
-	 * Mock for the _delete_event method that will handle setting up things for testing event deletes via the admin page.
-	 * @param $EVT_ID_to_delete
-	 */
-	public function delete_event( $EVT_ID_to_delete ) {
-		//set request data for event
+class Events_Admin_Page_Mock extends Events_Admin_Page
+{
+    /**
+     * @var EE_Admin_Config
+     */
+    public $admin_config;
+
+
+    public function __construct($routing = true)
+    {
+        //define any constants that might not be defined yet when using this mock.
+        if (! defined('EVENTS_PG_SLUG')) {
+            define('EVENTS_PG_SLUG', 'espresso_events');
+            define('EVENTS_LABEL', esc_html__('Events', 'event_espresso'));
+            define('EVENTS_ADMIN', EE_ADMIN_PAGES . 'events/');
+            define('EVENTS_ADMIN_URL', admin_url('admin.php?page=' . EVENTS_PG_SLUG));
+            define('EVENTS_TEMPLATE_PATH', EVENTS_ADMIN . 'templates/');
+            define('EVENTS_ASSETS_URL', EE_PLUGIN_DIR_URL . 'admin_pages/events/assets/');
+        }
+
+        parent::__construct(false);
+    }
+
+
+    public function default_tickets_update($evtobj, $data)
+    {
+        return $this->_default_tickets_update($evtobj, $data);
+    }
+
+
+    /**
+     * Mock for the _delete_event method that will handle setting up things for testing event deletes via the admin
+     * page.
+     *
+     * @param $EVT_ID_to_delete
+     */
+    public function delete_event($EVT_ID_to_delete)
+    {
+        //set request data for event
         $this->request->setRequestParam('EVT_IDs', $EVT_ID_to_delete);
-		$this->_delete_event( false );
-	}
-
-} //end class Events_Admin_Page_Mock
+        $this->_delete_event(false);
+    }
+}
+//end class Events_Admin_Page_Mock
diff --git a/tests/mocks/core/EE_Session_Mock.core.php b/tests/mocks/core/EE_Session_Mock.core.php
index 84c88882c1f..6a9e611c22a 100644
--- a/tests/mocks/core/EE_Session_Mock.core.php
+++ b/tests/mocks/core/EE_Session_Mock.core.php
@@ -1,72 +1,70 @@
 cache_storage = $cache_storage;
-        $this->request = $request;
-        $this->encryption = $encryption;
+        $this->request       = $request;
+        $this->encryption    = $encryption;
     }
 
 
-	public function lifespan() {
-		return  60 * MINUTE_IN_SECONDS;
-	}
-
+    public function lifespan(): int
+    {
+        return 60 * MINUTE_IN_SECONDS;
+    }
 
 
-	/**
-	 * @return EE_Encryption
-	 */
-	public function encryption() {
-		return $this->encryption;
-	}
+    /**
+     * @return EE_Encryption
+     */
+    public function encryption(): ?EE_Encryption
+    {
+        return $this->encryption;
+    }
 
 
     /**
      * @param null $key
      * @param bool $reset_cache
-     * @return    array
+     * @return mixed
+     * @throws EE_Error
+     * @throws ReflectionException
      */
-    public function get_session_data($key = null, $reset_cache = false)
+    public function get_session_data($key = null, bool $reset_cache = false)
     {
         if ($reset_cache) {
             $this->clear_session();
         }
         if (! empty($key)) {
-            return isset($this->session_data[ $key ]) ? $this->session_data[ $key ] : null;
+            return $this->session_data[ $key ] ?? null;
         }
         return $this->session_data;
     }
@@ -137,11 +135,10 @@ public function get_session_data($key = null, $reset_cache = false)
     /**
      * set session data
      *
-     * @access    public
-     * @param    array $data
+     * @param array|null $data
      * @return    TRUE on success, FALSE on fail
      */
-    public function set_session_data($data)
+    public function set_session_data(?array $data): bool
     {
         foreach ($data as $key => $value) {
             $this->session_data[ $key ] = $value;
@@ -150,17 +147,17 @@ public function set_session_data($data)
     }
 
 
-    public function clear_session($class = '', $function = '')
+    public function clear_session(string $class = '', string $function = '')
     {
-        $this->session_data = array();
+        $this->session_data = [];
     }
 
 
     /**
-     * @param \EE_Cart $cart
+     * @param EE_Cart $cart
      * @return bool
      */
-    public function set_cart(EE_Cart $cart)
+    public function set_cart(EE_Cart $cart): bool
     {
         $this->session_data['cart'] = $cart;
         return true;
@@ -177,9 +174,9 @@ public function reset_cart()
 
 
     /**
-     * @return \EE_Cart
+     * @return EE_Cart
      */
-    public function cart()
+    public function cart(): ?EE_Cart
     {
         return isset($this->session_data['cart']) && $this->session_data['cart'] instanceof EE_Cart
             ? $this->session_data['cart']
@@ -188,10 +185,10 @@ public function cart()
 
 
     /**
-     * @param \EE_Checkout $checkout
+     * @param EE_Checkout $checkout
      * @return bool
      */
-    public function set_checkout(EE_Checkout $checkout)
+    public function set_checkout(EE_Checkout $checkout): bool
     {
         $this->session_data['checkout'] = $checkout;
         return true;
@@ -208,9 +205,9 @@ public function reset_checkout()
 
 
     /**
-     * @return \EE_Checkout
+     * @return EE_Checkout
      */
-    public function checkout()
+    public function checkout(): ?EE_Checkout
     {
         return isset($this->session_data['checkout']) && $this->session_data['checkout'] instanceof EE_Checkout
             ? $this->session_data['checkout']
@@ -219,11 +216,12 @@ public function checkout()
 
 
     /**
-     * @param \EE_Transaction $transaction
+     * @param EE_Transaction $transaction
      * @return bool
      * @throws EE_Error
+     * @throws ReflectionException
      */
-    public function set_transaction(EE_Transaction $transaction)
+    public function set_transaction(EE_Transaction $transaction): bool
     {
         // first remove the session from the transaction before we save the transaction in the session
         $transaction->set_txn_session_data(null);
@@ -242,9 +240,9 @@ public function reset_transaction()
 
 
     /**
-     * @return \EE_Transaction
+     * @return EE_Transaction
      */
-    public function transaction()
+    public function transaction(): ?EE_Transaction
     {
         return isset($this->session_data['transaction'])
                && $this->session_data['transaction'] instanceof EE_Transaction
diff --git a/tests/testcases/admin_pages/events_decaf/Events_Admin_Page_Decaf_Test.php b/tests/testcases/admin_pages/events_decaf/Events_Admin_Page_Decaf_Test.php
index e6cae1a82ef..d4d6283e7e7 100644
--- a/tests/testcases/admin_pages/events_decaf/Events_Admin_Page_Decaf_Test.php
+++ b/tests/testcases/admin_pages/events_decaf/Events_Admin_Page_Decaf_Test.php
@@ -1,244 +1,326 @@
 delayedAdminPageMocks( 'decaf_events' );
-        $this->setupRequest();
-        $this->useAdvancedEditor= EE_Registry::instance()->CFG->admin->useAdvancedEditor();
+class Events_Admin_Page_Decaf_Test extends EE_UnitTestCase
+{
+    /**
+     * This holds the Events_Admin_Page_Mock class
+     *
+     * @var Events_Admin_Page_Mock
+     */
+    protected $_admin_page;
+
+
+    /**
+     * This holds the EE_Event object for testing with.
+     *
+     * @var EE_Event
+     */
+    protected $_event;
+
+
+    /**
+     * @var boolean
+     */
+    protected $useAdvancedEditor;
+
+
+    public function set_up()
+    {
+        parent::set_up();
+        $this->useAdvancedEditor = EE_Registry::instance()->CFG->admin->useAdvancedEditor();
         EE_Registry::instance()->CFG->admin->setUseAdvancedEditor(false);
-	}
-
-	public function tear_down()
-	{
-		parent::tear_down();
-        EE_Registry::instance()->CFG->admin->setUseAdvancedEditor($this->useAdvancedEditor);
-	}
-
-
-	/**
-	 * loader for setting the $_admin_page_property
-	 *
-	 * @param string $timezone Timezone string to initialize the times in.
-	 * @since 4.6
-	 */
-	protected function _load_requirements( $timezone = 'America/Vancouver' )
-	{
-		$this->_admin_page = new Events_Admin_Page_Mock();
-		$this->_event = $this->factory->event->create();
-		$this->_event->set_timezone( $timezone );
-		$this->_event->save();
-		$this->_set_default_dates( $timezone );
-	}
-
-
-
-
-	/**
-	 * tests the decaf datetime and tickets update method for Events Admin Page.
-	 *
-	 *@since 4.6
-	 */
-	public function test_default_tickets_update() {
-		//first test is just with default data
-		$this->_load_requirements();
-		$this->_testing_updates( "Tests with Default Data\n" );
-
-		//next test is with empty TKT_start and TKT_end dates.
-		$replacement['edit_tickets']['1']['TKT_start_date'] = null;
-		$replacement['edit_tickets']['1']['TKT_end_date'] = null;
-
-		//override _default_dates because we expect something different.
-		$this->_default_dates = array();
-		$this->_load_requirements();
-		$this->_default_dates['TKT_start'] = new DateTime( 'now', new DateTimeZone( 'America/Vancouver' ) );
-
-		/**
-		 *  TKT_start is set in the decaf ticket saves without seconds, so we need to set the seconds to zero as well for comparison.
-		 */
-		$this->_default_dates['TKT_start']->setTime( $this->_default_dates['TKT_start']->format( 'H' ), $this->_default_dates['TKT_start']->format( 'i' ), 0 );
-		/**
-		 * tkt end date is the same as start date because here's the code execution in Events_Admin_page::default_tickets_update:
-		 * 1. If no TKT_end_date, then set to DTT_EVT_start.
-		 * 2. However, this means that DTT_EVT_start (because its static) will always be earlier than what the value for TKT_start_date is.
-		 * 3. So later the code changes TKT_end_date to be the SAME as TKT_start_date and then sets it forward by a day.  So that's what our expected value will be.
-		 */
-		$this->_default_dates['TKT_end'] = clone $this->_default_dates['TKT_start'];
-		$this->_default_dates['TKT_end'] = $this->_default_dates['TKT_end']->add( new DateInterval( 'P1D' ) );
-		$this->_testing_updates( "Tests with unset tkt start and end date\n", $replacement );
-
-	}
-
-
-
-
-	/**
-	 * This is a common looped to test saves of ticket and datetime data.
-	 *
-	 * @param string $context_for_error_messages Used this to add context to any failed tests so
-	 *                                           you can easily verify what triggered it.
-	 * @param array  $data_to_replace            An array of replacements for the default data.
-	 *                                           Use null to indicate you want the key unset.
-	 * @since 4.6
-	 */
-	protected function _testing_updates( $context_for_error_messages, $data_to_replace = array() ) {
-		$formats_to_test = $this->date_formats_to_test();
-
-		$saved_dtts_for_tickets = $formats_for_compare = $saved_tkts = array();
-
-		/**
-		 * Note: Keep in mind, decaf does NOT provide the ability to choose the format that the dates are
-		 * displayed in for the event editor.  So when we test comparing formats, it is important to set the
-		 * format on the objects before retrieval.  Also important is that only the 'Y-m-d h:i a' format is used
-		 * on the decaf editor form.  So we make sure the all the dates going in for the data are in the same format.
-		 */
-
-		foreach( $formats_to_test['date'] as $date_format ) {
-			foreach( $formats_to_test['time'] as $time_format ) {
-				$full_format = $date_format . ' ' . $time_format;
-				$decaf_date_format = 'Y-m-d h:i a';
-				$data = $this->_get_save_data( $decaf_date_format );
-
-				//is there any data to unset/replace?
-				if ( ! empty( $data_to_replace ) ) {
-					//any data to unset?
-					foreach( $data_to_replace as $top_level => $second_level ) {
-						if ( is_array( $second_level ) ) {
-							foreach ( $second_level as $third_level => $fourth_level )
-								if ( is_array( $fourth_level ) ) {
-									foreach ( $fourth_level as $fifth_level => $sixth_level ) {
-										if ( is_null( $sixth_level ) ) {
-											unset( $data_to_replace[$top_level][$third_level][$fifth_level] );
-											unset( $data[$top_level][$third_level][$fifth_level] );
-
-										}
-									}
-								} else if ( is_null( $fourth_level ) ) {
-									unset( $data_to_replace[$top_level][$third_level] );
-									unset( $data[$top_level][$third_level] );
-								}
-						} else {
-							if ( is_null( $second_level ) ) {
-								unset( $data_to_replace[$top_level] );
-								unset( $data[$top_level] );
-							}
-						}
-					}
-					//moige
-					$data = array_merge( $data, $data_to_replace );
-				}
-
-
-
-				$saved_data = $this->_admin_page->default_tickets_update( $this->_event, $data );
-				$dtt = $saved_data[0];
-				$tkts = $saved_data[1];
-
-				//verify datetime.
-				$this->assertInstanceof( 'EE_Datetime', $dtt );
-				//verify start and date
-				$this->assertEquals( $dtt->start_date_and_time( $date_format, $time_format ), $this->_default_dates['DTT_start']->format( $full_format ), $context_for_error_messages . sprintf( 'Start Date Format Tested: %s', $full_format ) );
-				$this->assertEquals( $dtt->end_date_and_time( $date_format, $time_format ), $this->_default_dates['DTT_end']->format( $full_format ), $context_for_error_messages . sprintf( 'End Date Format Tested: %s', $full_format ) );
-
-				$saved_dtts_for_tickets[$full_format] = $dtt;
-				$formats_for_compare[$dtt->ID()] = array( $date_format, $time_format );
-
-				//verify tkts
-				foreach ( $tkts as $tkt ) {
-					$this->assertInstanceof( 'EE_Ticket', $tkt, $context_for_error_messages . sprintf( 'Format: %s', $full_format ) );
-
-					//verify start and date
-					//Note: currently this test sometimes fails depending on the timing of when it happens and how fast
-					// the server is. Whenever I've seen this fail its been off by 1 minute and that's because when the
-					// default dates for testing were created, they likely happened at the second turnover.
-					$this->assertDateWithinOneMinute( $tkt->start_date( $date_format, $time_format ), $this->_default_dates['TKT_start']->format( $full_format ), $full_format, $context_for_error_messages . sprintf( 'Start Ticket DateFormat Tested: %s', $full_format ) );
-					$this->assertDateWithinOneMinute( $tkt->end_date( $date_format, $time_format ), $this->_default_dates['TKT_end']->format( $full_format ), $full_format, $context_for_error_messages . sprintf( 'End Ticket Date Format Tested: %s', $full_format ) );
-
-					$saved_tkts[$full_format] = $tkt;
-				}
-			}
-		}
-
-
-		//now let's verify these items were saved corectly in the db.
-		/*$new_tkts = $new_dtts = array();
-		foreach ( $tkt as $format => $tkt ) {
-			$new_tkts[$format] = EEM_Ticket::instance()->refresh_entity_map_from_db( $tkt->ID() );
-		}
-
-		foreach ( $saved_dtts_for_tickets[$full_format] as $format => $dtt ) {
-			$new_dtts[$format] = EEM_Datetime::instance()->refresh_entity_map_from_db( $dtt->ID() );
-		}/**/
-
-		$new_event = EEM_Event::instance()->refresh_entity_map_from_db( $this->_event->ID() );
-		$new_event->set_timezone( 'America/Vancouver' );
-
-		$evt_dtts = $new_event->datetimes_ordered();
-
-		//now let's do comparisons.
-		foreach( $evt_dtts as  $edtt ) {
-			$formats = $formats_for_compare[$edtt->ID()];
-			$format = $formats[0] . ' ' . $formats[1];
-			$this->assertEquals( $edtt->start_date_and_time( $formats[0], $formats[1] ), $this->_default_dates['DTT_start']->format( $format), $context_for_error_messages . sprintf( 'DB DTT/Default DTT Start Date Format Checked: %s', $format ) );
-			$this->assertEquals( $edtt->end_date_and_time( $formats[0], $formats[1] ), $this->_default_dates['DTT_end']->format( $format ), $context_for_error_messages . sprintf( 'DB DTT/Default DTT End Date Format Checked: %s', $format ) );
-			$this->assertEquals( $edtt->start_date_and_time( $formats[0], $formats[1] ), $saved_dtts_for_tickets[$format]->start_date_and_time( $formats[0], $formats[1] ), $context_for_error_messages . sprintf( 'DB DTT/Orig DTT Start Date Format Checked: %s', $format ) );
-			$this->assertEquals( $edtt->end_date_and_time( $formats[0], $formats[1] ), $saved_dtts_for_tickets[$format]->end_date_and_time( $formats[0], $formats[1] ), $context_for_error_messages . sprintf( 'DB DTT/Orig DTT End Date Format Checked: %s', $format ) );
-
-			//get related ticket on this $edtt
-			$evt_tkt = $edtt->get_first_related( 'Ticket' );
-			$this->assertDateWithinOneMinute( $evt_tkt->start_date( $formats[0], $formats[1] ), $this->_default_dates['TKT_start']->format( $format ), $format, $context_for_error_messages . sprintf( 'DB TKT/Default TKT Start Date Format Checked: %s', $format ) );
-			$this->assertDateWithinOneMinute( $evt_tkt->end_date( $formats[0], $formats[1] ), $this->_default_dates['TKT_end']->format( $format ), $format, $context_for_error_messages . sprintf( 'DB TKT/Default TKT End Date Format Checked: %s', $format ) );
-			$this->assertDateWithinOneMinute( $evt_tkt->start_date( $formats[0], $formats[1] ), $saved_tkts[$format]->start_date( $formats[0], $formats[1] ), $format, $context_for_error_messages . sprintf( 'DB TKT/Orig TKT Start Date Format Checked: %s', $format ) );
-			$this->assertDateWithinOneMinute( $evt_tkt->end_date( $formats[0], $formats[1] ), $saved_tkts[$format]->end_date( $formats[0], $formats[1] ), $format, $context_for_error_messages . sprintf( 'DB TKT/Orig TKT End Date Format Checked: %s', $format ) );
-		}
-	}
-
-
-
+        $this->delayedAdminPageMocks('decaf_events');
+        $this->setupRequest();
+    }
 
 
+    public function tear_down()
+    {
+        parent::tear_down();
+        EE_Registry::instance()->CFG->admin->setUseAdvancedEditor($this->useAdvancedEditor);
+    }
+
+
+    /**
+     * loader for setting the $_admin_page_property
+     *
+     * @param string $timezone Timezone string to initialize the times in.
+     * @since 4.6
+     */
+    protected function _load_requirements($timezone = 'America/Vancouver')
+    {
+        $this->_admin_page               = new Events_Admin_Page_Mock();
+        $this->_admin_page->admin_config = EE_Registry::instance()->CFG->admin;
+        $this->_event                    = $this->factory->event->create();
+        $this->_event->set_timezone($timezone);
+        $this->_event->save();
+        $this->_set_default_dates($timezone);
+    }
+
+
+    /**
+     * tests the decaf datetime and tickets update method for Events Admin Page.
+     *
+     * @since 4.6
+     */
+    public function test_default_tickets_update()
+    {
+        //first test is just with default data
+        $this->_load_requirements();
+        $this->_testing_updates("Tests with Default Data\n");
+
+        //next test is with empty TKT_start and TKT_end dates.
+        $replacement['edit_tickets']['1']['TKT_start_date'] = null;
+        $replacement['edit_tickets']['1']['TKT_end_date']   = null;
+
+        //override _default_dates because we expect something different.
+        $this->_default_dates = [];
+        $this->_load_requirements();
+        $this->_default_dates['TKT_start'] = new DateTime('now', new DateTimeZone('America/Vancouver'));
+
+        /**
+         *  TKT_start is set in the decaf ticket saves without seconds, so we need to set the seconds to zero as well for comparison.
+         */
+        $this->_default_dates['TKT_start']->setTime(
+            $this->_default_dates['TKT_start']->format('H'),
+            $this->_default_dates['TKT_start']->format('i'),
+            0
+        );
+        /**
+         * tkt end date is the same as start date because here's the code execution in Events_Admin_page::default_tickets_update:
+         * 1. If no TKT_end_date, then set to DTT_EVT_start.
+         * 2. However, this means that DTT_EVT_start (because its static) will always be earlier than what the value for TKT_start_date is.
+         * 3. So later the code changes TKT_end_date to be the SAME as TKT_start_date and then sets it forward by a day.  So that's what our expected value will be.
+         */
+        $this->_default_dates['TKT_end'] = clone $this->_default_dates['TKT_start'];
+        $this->_default_dates['TKT_end'] = $this->_default_dates['TKT_end']->add(new DateInterval('P1D'));
+        $this->_testing_updates("Tests with unset tkt start and end date\n", $replacement);
+    }
+
+
+    /**
+     * This is a common looped to test saves of ticket and datetime data.
+     *
+     * @param string $context_for_error_messages Used this to add context to any failed tests so
+     *                                           you can easily verify what triggered it.
+     * @param array  $data_to_replace            An array of replacements for the default data.
+     *                                           Use null to indicate you want the key unset.
+     * @since 4.6
+     */
+    protected function _testing_updates($context_for_error_messages, $data_to_replace = [])
+    {
+        $formats_to_test = $this->date_formats_to_test();
+
+        $saved_dtts_for_tickets = $formats_for_compare = $saved_tkts = [];
+
+        /**
+         * Note: Keep in mind, decaf does NOT provide the ability to choose the format that the dates are
+         * displayed in for the event editor.  So when we test comparing formats, it is important to set the
+         * format on the objects before retrieval.  Also important is that only the 'Y-m-d h:i a' format is used
+         * on the decaf editor form.  So we make sure the all the dates going in for the data are in the same format.
+         */
+
+        foreach ($formats_to_test['date'] as $date_format) {
+            foreach ($formats_to_test['time'] as $time_format) {
+                $full_format       = $date_format . ' ' . $time_format;
+                $decaf_date_format = 'Y-m-d h:i a';
+                $data              = $this->_get_save_data($decaf_date_format);
+
+                //is there any data to unset/replace?
+                if (! empty($data_to_replace)) {
+                    //any data to unset?
+                    foreach ($data_to_replace as $top_level => $second_level) {
+                        if (is_array($second_level)) {
+                            foreach ($second_level as $third_level => $fourth_level) {
+                                if (is_array($fourth_level)) {
+                                    foreach ($fourth_level as $fifth_level => $sixth_level) {
+                                        if (is_null($sixth_level)) {
+                                            unset($data_to_replace[ $top_level ][ $third_level ][ $fifth_level ]);
+                                            unset($data[ $top_level ][ $third_level ][ $fifth_level ]);
+                                        }
+                                    }
+                                } elseif (is_null($fourth_level)) {
+                                    unset($data_to_replace[ $top_level ][ $third_level ]);
+                                    unset($data[ $top_level ][ $third_level ]);
+                                }
+                            }
+                        } else {
+                            if (is_null($second_level)) {
+                                unset($data_to_replace[ $top_level ]);
+                                unset($data[ $top_level ]);
+                            }
+                        }
+                    }
+                    //moige
+                    $data = array_merge($data, $data_to_replace);
+                }
+
+                $saved_data = $this->_admin_page->default_tickets_update($this->_event, $data);
+                $dtt        = $saved_data[0];
+                $tkts       = $saved_data[1];
+
+                //verify datetime.
+                $this->assertInstanceof('EE_Datetime', $dtt);
+                //verify start and date
+                $this->assertEquals(
+                    $dtt->start_date_and_time($date_format, $time_format),
+                    $this->_default_dates['DTT_start']->format($full_format),
+                    $context_for_error_messages . sprintf('Start Date Format Tested: %s', $full_format)
+                );
+                $this->assertEquals(
+                    $dtt->end_date_and_time($date_format, $time_format),
+                    $this->_default_dates['DTT_end']->format($full_format),
+                    $context_for_error_messages . sprintf('End Date Format Tested: %s', $full_format)
+                );
+
+                $saved_dtts_for_tickets[ $full_format ] = $dtt;
+                $formats_for_compare[ $dtt->ID() ]      = [$date_format, $time_format];
+
+                //verify tkts
+                foreach ($tkts as $tkt) {
+                    $this->assertInstanceof(
+                        'EE_Ticket',
+                        $tkt,
+                        $context_for_error_messages . sprintf('Format: %s', $full_format)
+                    );
+
+                    //verify start and date
+                    //Note: currently this test sometimes fails depending on the timing of when it happens and how fast
+                    // the server is. Whenever I've seen this fail its been off by 1 minute and that's because when the
+                    // default dates for testing were created, they likely happened at the second turnover.
+                    $this->assertDateWithinOneMinute(
+                        $tkt->start_date($date_format, $time_format),
+                        $this->_default_dates['TKT_start']->format($full_format),
+                        $full_format,
+                        $context_for_error_messages . sprintf(
+                            'Start Ticket DateFormat Tested: %s',
+                            $full_format
+                        )
+                    );
+                    $this->assertDateWithinOneMinute(
+                        $tkt->end_date($date_format, $time_format),
+                        $this->_default_dates['TKT_end']->format($full_format),
+                        $full_format,
+                        $context_for_error_messages . sprintf(
+                            'End Ticket Date Format Tested: %s',
+                            $full_format
+                        )
+                    );
+
+                    $saved_tkts[ $full_format ] = $tkt;
+                }
+            }
+        }
+
+
+        //now let's verify these items were saved corectly in the db.
+        /*$new_tkts = $new_dtts = array();
+        foreach ( $tkt as $format => $tkt ) {
+            $new_tkts[$format] = EEM_Ticket::instance()->refresh_entity_map_from_db( $tkt->ID() );
+        }
+
+        foreach ( $saved_dtts_for_tickets[$full_format] as $format => $dtt ) {
+            $new_dtts[$format] = EEM_Datetime::instance()->refresh_entity_map_from_db( $dtt->ID() );
+        }/**/
+
+        $new_event = EEM_Event::instance()->refresh_entity_map_from_db($this->_event->ID());
+        $new_event->set_timezone('America/Vancouver');
+
+        $evt_dtts = $new_event->datetimes_ordered();
+
+        //now let's do comparisons.
+        foreach ($evt_dtts as $edtt) {
+            $formats = $formats_for_compare[ $edtt->ID() ];
+            $format  = $formats[0] . ' ' . $formats[1];
+            $this->assertEquals(
+                $edtt->start_date_and_time($formats[0], $formats[1]),
+                $this->_default_dates['DTT_start']->format($format),
+                $context_for_error_messages . sprintf(
+                    'DB DTT/Default DTT Start Date Format Checked: %s',
+                    $format
+                )
+            );
+            $this->assertEquals(
+                $edtt->end_date_and_time($formats[0], $formats[1]),
+                $this->_default_dates['DTT_end']->format($format),
+                $context_for_error_messages . sprintf(
+                    'DB DTT/Default DTT End Date Format Checked: %s',
+                    $format
+                )
+            );
+            $this->assertEquals(
+                $edtt->start_date_and_time($formats[0], $formats[1]),
+                $saved_dtts_for_tickets[ $format ]->start_date_and_time($formats[0], $formats[1]),
+                $context_for_error_messages . sprintf(
+                    'DB DTT/Orig DTT Start Date Format Checked: %s',
+                    $format
+                )
+            );
+            $this->assertEquals(
+                $edtt->end_date_and_time($formats[0], $formats[1]),
+                $saved_dtts_for_tickets[ $format ]->end_date_and_time($formats[0], $formats[1]),
+                $context_for_error_messages . sprintf(
+                    'DB DTT/Orig DTT End Date Format Checked: %s',
+                    $format
+                )
+            );
+
+            //get related ticket on this $edtt
+            $evt_tkt = $edtt->get_first_related('Ticket');
+            $this->assertDateWithinOneMinute(
+                $evt_tkt->start_date($formats[0], $formats[1]),
+                $this->_default_dates['TKT_start']->format($format),
+                $format,
+                $context_for_error_messages . sprintf(
+                    'DB TKT/Default TKT Start Date Format Checked: %s',
+                    $format
+                )
+            );
+            $this->assertDateWithinOneMinute(
+                $evt_tkt->end_date($formats[0], $formats[1]),
+                $this->_default_dates['TKT_end']->format($format),
+                $format,
+                $context_for_error_messages . sprintf(
+                    'DB TKT/Default TKT End Date Format Checked: %s',
+                    $format
+                )
+            );
+            $this->assertDateWithinOneMinute(
+                $evt_tkt->start_date($formats[0], $formats[1]),
+                $saved_tkts[ $format ]->start_date($formats[0], $formats[1]),
+                $format,
+                $context_for_error_messages . sprintf(
+                    'DB TKT/Orig TKT Start Date Format Checked: %s',
+                    $format
+                )
+            );
+            $this->assertDateWithinOneMinute(
+                $evt_tkt->end_date($formats[0], $formats[1]),
+                $saved_tkts[ $format ]->end_date($formats[0], $formats[1]),
+                $format,
+                $context_for_error_messages . sprintf(
+                    'DB TKT/Orig TKT End Date Format Checked: %s',
+                    $format
+                )
+            );
+        }
+    }
 }
 // end class Events_Admin_Page_Decaf
 // Location: testcases/admin_pages/events_decaf/Events_Admin_Page_Decaf_Test.php
diff --git a/tests/testcases/core/db_models/EEM_Event_Test.php b/tests/testcases/core/db_models/EEM_Event_Test.php
index 84de2848252..7d55a7bff35 100644
--- a/tests/testcases/core/db_models/EEM_Event_Test.php
+++ b/tests/testcases/core/db_models/EEM_Event_Test.php
@@ -1,11 +1,4 @@
  $this->factory->datetime->create( array( 'DTT_EVT_start' => $past_start_date->format( $full_format ), 'DTT_EVT_end' => $past_start_date->format( $full_format), 'timezone' => 'America/Toronto', 'formats' =>  $formats ) ),
-			'upcoming_datetime' => $this->factory->datetime->create( array( 'DTT_EVT_start' => $upcoming_start_date->format( $full_format ), 'DTT_EVT_end' => $upcoming_start_date->format( $full_format), 'timezone' => 'America/Toronto', 'formats' => $formats ) ),
-			'active_datetime' => $this->factory->datetime->create( array( 'DTT_EVT_start' => $current->sub( new DateInterval( "PT2H") )->format( $full_format ), 'DTT_EVT_end' => $current_end_date->add( new DateInterval( "PT2H" ) )->format( $full_format), 'timezone' => 'America/Toronto', 'formats' =>  $formats ) ),
-			'sold_out_datetime' => $this->factory->datetime->create( array( 'DTT_EVT_start' => $upcoming_start_date->format( $full_format ), 'DTT_EVT_end' => $upcoming_start_date->format( $full_format), 'DTT_reg_limit' => 10, 'DTT_sold' => 10,  'timezone' => 'America/Toronto', 'formats' =>  $formats ) ),
-			'inactive_datetime' => $this->factory->datetime->create( array( 'DTT_EVT_start' => $current->sub( new DateInterval( "PT2H") )->format( $full_format ), 'DTT_EVT_end' => $current_end_date->add( new DateInterval( "PT2H" ) )->format( $full_format), 'timezone' => 'America/Toronto', 'formats' =>  $formats ) )
-			);
-
-		//setup some events
+    /**
+     * This just sets up some events in the db for running certain tests that query getting events back.
+     *
+     * @since 4.6.x
+     */
+    protected function _setup_events()
+    {
+        //setup some dates we'll use for testing with.
+        $timezone            = new DateTimeZone('America/Toronto');
+        $upcoming_start_date = new DateTime("now +2hours", $timezone);
+        $past_start_date     = new DateTime("now -2days", $timezone);
+        $current_end_date    = new DateTime("now +2days", $timezone);
+        $current             = new DateTime("now", $timezone);
+        $formats             = ['Y-d-m', 'h:i a'];
+        $full_format         = implode(' ', $formats);
+
+        //setup some datetimes to attach to events.
+        $datetimes = [
+            'expired_datetime'  => $this->factory->datetime->create(
+                [
+                    'DTT_EVT_start' => $past_start_date->format($full_format),
+                    'DTT_EVT_end'   => $past_start_date->format($full_format),
+                    'timezone'      => 'America/Toronto',
+                    'formats'       => $formats,
+                ]
+            ),
+            'upcoming_datetime' => $this->factory->datetime->create(
+                [
+                    'DTT_EVT_start' => $upcoming_start_date->format($full_format),
+                    'DTT_EVT_end'   => $upcoming_start_date->format($full_format),
+                    'timezone'      => 'America/Toronto',
+                    'formats'       => $formats,
+                ]
+            ),
+            'active_datetime'   => $this->factory->datetime->create(
+                [
+                    'DTT_EVT_start' => $current->sub(new DateInterval("PT2H"))->format($full_format),
+                    'DTT_EVT_end'   => $current_end_date->add(new DateInterval("PT2H"))->format($full_format),
+                    'timezone'      => 'America/Toronto',
+                    'formats'       => $formats,
+                ]
+            ),
+            'sold_out_datetime' => $this->factory->datetime->create(
+                [
+                    'DTT_EVT_start' => $upcoming_start_date->format($full_format),
+                    'DTT_EVT_end'   => $upcoming_start_date->format($full_format),
+                    'DTT_reg_limit' => 10,
+                    'DTT_sold'      => 10,
+                    'timezone'      => 'America/Toronto',
+                    'formats'       => $formats,
+                ]
+            ),
+            'inactive_datetime' => $this->factory->datetime->create(
+                [
+                    'DTT_EVT_start' => $current->sub(new DateInterval("PT2H"))->format($full_format),
+                    'DTT_EVT_end'   => $current_end_date->add(new DateInterval("PT2H"))->format($full_format),
+                    'timezone'      => 'America/Toronto',
+                    'formats'       => $formats,
+                ]
+            ),
+        ];
+
+        //setup some events
         /** @var EE_Event[] $events */
-        $events = $this->factory->event->create_many( '4' );
-
-		//add datetimes to the events.
-		$events[0]->_add_relation_to( $datetimes['expired_datetime'], 'Datetime' );
-		$events[0]->save();
-		$events[1]->_add_relation_to( $datetimes['upcoming_datetime'], 'Datetime' );
-		$events[1]->save();
-		$events[2]->_add_relation_to( $datetimes['active_datetime'], 'Datetime' );
-		$events[2]->save();
-		$events[3]->_add_relation_to( $datetimes['sold_out_datetime'], 'Datetime' );
-		$events[3]->save();
-
-		foreach( $events as $event ) {
-			$event->set('status', 'publish');
-			$event->save();
-		}
-
-		//one more event that is just going to be inactive
+        $events = $this->factory->event->create_many('4');
+
+        //add datetimes to the events.
+        $events[0]->_add_relation_to($datetimes['expired_datetime'], 'Datetime');
+        $events[0]->save();
+        $events[1]->_add_relation_to($datetimes['upcoming_datetime'], 'Datetime');
+        $events[1]->save();
+        $events[2]->_add_relation_to($datetimes['active_datetime'], 'Datetime');
+        $events[2]->save();
+        $events[3]->_add_relation_to($datetimes['sold_out_datetime'], 'Datetime');
+        $events[3]->save();
+
+        foreach ($events as $event) {
+            $event->set('status', 'publish');
+            $event->save();
+        }
+
+        //one more event that is just going to be inactive
         /** @var EE_Event $final_event */
         $final_event = $this->factory->event->create();
-		$final_event->_add_relation_to( $datetimes['inactive_datetime'], 'Datetime' );
-		$final_event->save();
+        $final_event->_add_relation_to($datetimes['inactive_datetime'], 'Datetime');
+        $final_event->save();
+    }
 
-	}
+
+    /**
+     * This tests getting active events.
+     *
+     * @since 4.6.x
+     */
+    public function test_get_active_events()
+    {
+        $this->_setup_events();
+        //now do our tests
+        $this->assertEquals(1, EEM_Event::instance()->get_active_events([], true));
+    }
 
 
+    public function test_get_upcoming_events()
+    {
+        $this->_setup_events();
+        //now do our tests
+        $this->assertEquals(2, EEM_Event::instance()->get_upcoming_events([], true));
+    }
 
-	/**
-	 * This tests getting active events.
-	 * @since 4.6.x
-	 */
-	public function test_get_active_events() {
-		$this->_setup_events();
-		//now do our tests
-		$this->assertEquals( 1, EEM_Event::instance()->get_active_events( array(), true ) );
-	}
 
+    public function test_get_expired_events()
+    {
+        $this->_setup_events();
+        //now do our tests
+        $this->assertEquals(1, EEM_Event::instance()->get_expired_events([], true));
+    }
 
-	public function test_get_upcoming_events() {
-		$this->_setup_events();
-		//now do our tests
-		$this->assertEquals( 2, EEM_Event::instance()->get_upcoming_events( array(), true ) );
-	}
 
+    public function test_get_inactive_events()
+    {
+        $this->_setup_events();
+        //now do our tests
+        $this->assertEquals(1, EEM_Event::instance()->get_inactive_events([], true));
+    }
 
-	public function test_get_expired_events() {
-		$this->_setup_events();
-		//now do our tests
-		$this->assertEquals( 1, EEM_Event::instance()->get_expired_events( array(), true ) );
-	}
 
-	public function test_get_inactive_events() {
-		$this->_setup_events();
-		//now do our tests
-		$this->assertEquals( 1, EEM_Event::instance()->get_inactive_events( array(), true ) );
-	}
+    public function test_get_active_and_upcoming_events()
+    {
+        $this->_setup_events();
+        //now do our tests
+        $this->assertEquals(3, EEM_Event::instance()->get_active_and_upcoming_events([], true));
+    }
 
-	public function test_get_active_and_upcoming_events() {
-		$this->_setup_events();
-		//now do our tests
-		$this->assertEquals( 3, EEM_Event::instance()->get_active_and_upcoming_events( array(), true ) );
-	}
 
+    /**
+     * @see   https://events.codebasehq.com/projects/event-espresso/tickets/8799
+     * @group 8799
+     * @since 4.8.8.rc.019
+     */
+    public function test_default_reg_status()
+    {
+        //first verify the default reg status on config is pending payment
+        $this->assertEquals(
+            EEM_Registration::status_id_pending_payment,
+            EE_Registry::instance()->CFG->registration->default_STS_ID
+        );
 
-	/**
-	 * @see https://events.codebasehq.com/projects/event-espresso/tickets/8799
-	 * @group 8799
-	 * @since 4.8.8.rc.019
-	 */
-	public function test_default_reg_status() {
-		//first verify the default reg status on config is pending payment
-		$this->assertEquals( EEM_Registration::status_id_pending_payment, EE_Registry::instance()->CFG->registration->default_STS_ID );
+        //verify creating default event from the model has that default reg status
+        /** @type EE_Event $event */
+        $event = EEM_Event::instance()->create_default_object();
+        $this->assertEquals(EEM_Registration::status_id_pending_payment, $event->default_registration_status());
 
-		//verify creating default event from the model has that default reg status
-		/** @type EE_Event $event */
-		$event = EEM_Event::instance()->create_default_object();
-		$this->assertEquals( EEM_Registration::status_id_pending_payment, $event->default_registration_status() );
+        //let's update config in the db to have default reg status of approved
+        EE_Registry::instance()->CFG->registration->default_STS_ID = EEM_Registration::status_id_approved;
+        EE_Registry::instance()->CFG->update_espresso_config();
 
-		//let's update config in the db to have default reg status of approved
-		EE_Registry::instance()->CFG->registration->default_STS_ID = EEM_Registration::status_id_approved;
-		EE_Registry::instance()->CFG->update_espresso_config();
+        //let's reset for new test
+        EEM_Event::reset();
+        EE_Registry::reset();
 
-		//let's reset for new test
-		EEM_Event::reset();
-		EE_Registry::reset();
+        //k NOW the default reg status in config should be approved
+        $this->assertEquals(
+            EEM_Registration::status_id_approved,
+            EE_Registry::instance()->CFG->registration->default_STS_ID
+        );
 
-		//k NOW the default reg status in config should be approved
-		$this->assertEquals( EEM_Registration::status_id_approved, EE_Registry::instance()->CFG->registration->default_STS_ID );
+        //new default event should have approved as the default reg status
+        $event = EEM_Event::instance()->create_default_object();
+        $this->assertEquals(EEM_Registration::status_id_approved, $event->default_registration_status());
+    }
 
-		//new default event should have approved as the default reg status
-		$event = EEM_Event::instance()->create_default_object();
-		$this->assertEquals( EEM_Registration::status_id_approved, $event->default_registration_status() );
-	}
 
     /**
-     * @since 4.10.0.p
      * @throws EE_Error
      * @throws InvalidArgumentException
      * @throws ReflectionException
      * @throws InvalidDataTypeException
      * @throws InvalidInterfaceException
+     * @since 4.10.0.p
      */
-	public function testGetQuestionGroupsForEvent()
+    public function testGetQuestionGroupsForEvent()
     {
         $r = $this->new_model_obj_with_dependencies(
             'Registration',
             [
-                'REG_count' => 1
+                'REG_count' => 1,
             ]
         );
         $r->event_obj()->add_question_group(EEM_Question_Group::system_personal, true);
@@ -187,6 +233,5 @@ public function testGetQuestionGroupsForEvent()
             $qgs
         );
     }
-
 }
 // Location: testcases/core/db_models/EEM_Event_Test.php
diff --git a/tests/testcases/core/helpers/EEH_Activation_Test.php b/tests/testcases/core/helpers/EEH_Activation_Test.php
index 39938f17b16..fb1262009ec 100644
--- a/tests/testcases/core/helpers/EEH_Activation_Test.php
+++ b/tests/testcases/core/helpers/EEH_Activation_Test.php
@@ -1,263 +1,295 @@
 load_lib( 'Message_Resource_Manager' );
-		// messengers that have been activated and verified installed
-		$active_messengers = $message_resource_manager->active_messengers();
-		// ALL installed messengers regardless of whether they are active or not
-		$installed_messengers = $message_resource_manager->installed_messengers();
-		$should_be_installed = array();
-		foreach( $active_messengers as $msgr ) {
-			$this->assertInstanceOf( 'EE_messenger', $msgr );
-			if ( $msgr->activate_on_install ) {
-				$should_be_installed[] = $msgr->name;
-			}
-		}
-		//loop through $should_be_installed and verify that those that should be active ARE active.
-		foreach ( $should_be_installed as $msgr_name ) {
-			$this->assertTrue(
-				isset( $installed_messengers[ $msgr_name ] ),
-				sprintf( 'The messenger %s should be active on fresh install, but it is not.', $msgr_name )
-			);
-		}
-
-		//now verify that the code doesn't run new message template generation etc.
-		$this->assertFalse( EEH_Activation::generate_default_message_templates() );
-
-
-		// now we simulate someone who's deactivated a messenger
-		// and we simulate a migration that triggers generating default message templates again.
-		//  The html messenger should STICK and NOT be activated.
-		$message_resource_manager->deactivate_messenger( 'html' );
-
-		//do the same for message type
-		$message_resource_manager->deactivate_message_type_for_messenger( 'not_approved', 'email' );
-
-		//Reset messages to test stickiness
-		EE_Registry::reset();
-
-		$activated_response = EEH_Activation::generate_default_message_templates();
-
-		//verify we got a response (html should not have templates generated)
-		$this->assertFalse( $activated_response );
-
-		// double check we still don't have html in the active messengers array
-		$active_messengers = $message_resource_manager->get_active_messengers_option( true );
-		$this->assertFalse( isset( $active_messengers['html'] ) );
-		$this->assertFalse( $message_resource_manager->is_message_type_active_for_messenger( 'email', 'not_approved' ) );
-	}
-
-
-
-
-
-	/**
-	 * This tests the generate_default_message_templates method with using the
-	 * FHEE__EE_messenger__get_default_message_types__default_types filter to add a
-	 * bogus message_type string.  No errors should be triggered, and the invalid default mt
-	 * should NOT be added to the active array for the messenger.
-	 *
-	 * @since 4.6
-	 * @group 7595
-	 */
-	public function test_filtered_default_message_types_on_activation() {
-		/** @type EE_Message_Resource_Manager $message_resource_manager */
-		$message_resource_manager = EE_Registry::instance()->load_lib( 'Message_Resource_Manager' );
-		//let's clear out all active messengers to get an accurate test of initial generation of message templates.
-		global $wpdb;
-		// delete message_template_group templates
-		$message_template_group_table = $wpdb->prefix . 'esp_message_template_group';
-		$query = "DELETE FROM $message_template_group_table WHERE 'GRP_ID' > 0";
-		$wpdb->query( $query );
-		// delete message_template templates
-		$message_template_table = $wpdb->prefix . 'esp_message_template';
-		$query = "DELETE FROM $message_template_table WHERE 'MTP_ID' > 0";
-		$wpdb->query($query);
-		// delete event_message_template templates
-		$event_message_template_table = $wpdb->prefix . 'esp_event_message_template';
-		$query = "DELETE FROM $event_message_template_table WHERE 'EMT_ID' > 0";
-		$wpdb->query( $query );
-
-		$message_resource_manager->update_active_messengers_option( array() );
-		//set a filter for the invalid message type
-		add_filter(
-			'FHEE__EE_messenger__get_default_message_types__default_types',
-			function( $default_types ) {
-				$default_types[] = 'bogus_message_type';
-				return $default_types;
-			}, 10, 2
-		);
-
-		try {
-			//activate messages... if there's any problems then errors will trigger a fail.
-			EEH_Activation::generate_default_message_templates();
-		} catch( EE_Error $e ){
-			$this->assertInstanceOf( 'EE_Error', $e );
-		}
-
-		//all went well so let's make sure the activated system does NOT have our invalid message type string.
-		$active_messengers = $message_resource_manager->get_active_messengers_option( true );
-		foreach( $active_messengers as $messenger => $settings ) {
-			$this->assertFalse(
-				isset( $settings[ 'settings' ][ $messenger . '-message_types' ][ 'bogus_message_type' ] ),
-				sprintf( 'The %s messenger should not have "bogus_message_type" active on it but it does.', $messenger )
-			);
-		}
-	}
-
-
-
-
-	/**
-	 * Ensure getting default creator works as expected
-	 * @since 4.6.0
-	 */
-	public function test_get_default_creator_id() {
-		//clear out any previous users that may be lurking in teh system
-		foreach( get_users() as $wp_user ){
-			wp_delete_user( $wp_user->ID );
-		}
-		//set some users; and just make it interesting by having the first user NOT be an admin
-		$this->factory->user->create_many( 2 );
-		$users = $this->factory->user->create_many( 2 );
-		//make users administrators.
-		foreach ( $users as $user_id ) {
-			$user = $this->factory->user->get_object_by_id( $user_id );
-			//verify
-			$this->assertInstanceOf( 'WP_User', $user );
-			//add role
-			$user->add_role( 'administrator' );
-		}
-
-		//get all users so we know who is the first one that we should be expecting.
-		$expected_id = reset( $users );
-		$this->assertEquals( EEH_Activation::get_default_creator_id(), $expected_id );
-
-		/**
-		 * ok now let's verify EEH_Activation::reset() properly clears the cache
-		 * on EEH_Activation. This is important for subsequent unit tests (because
-		 * EEH_Activation::reset() is called between unit tests), but also when an admin
-		 * resets their EE database, or when anyone wants to reset that cache)
-		 * clear out any previous users that may be lurking in teh system
-		 */
-		EEH_Activation::reset();
-		foreach( get_users() as $wp_user ){
-			wp_delete_user( $wp_user->ID );
-		}
-		//set some users; and just make it interesting by having the first user NOT be an admin
-		$this->factory->user->create_many( 2 );
-		$users_created_after_reset = $this->factory->user->create_many( 2 );
-		//make users administrators.
-		foreach ( $users_created_after_reset as $user_id ) {
-			$user = $this->factory->user->get_object_by_id( $user_id );
-			//verify
-			$this->assertInstanceOf( 'WP_User', $user );
-			//add role
-			$user->add_role( 'administrator' );
-		}
-
-		//get all users so we know who is the first one that we should be expecting.
-		$new_expected_id = reset( $users_created_after_reset );
-		$this->assertEquals( EEH_Activation::get_default_creator_id(), $new_expected_id );
-
-	}
-
-	function test_get_cron_tasks__old() {
-		add_filter( 'FHEE__EEH_Activation__get_cron_tasks', array( $this, 'change_cron_tasks' ) );
-		$old_cron_tasks = EEH_Activation::get_cron_tasks( 'old' );
-		$this->assertArrayHasKey( self::expired_cron_task_name, $old_cron_tasks );
-		$this->assertArrayNotHasKey( self::current_cron_task_name, $old_cron_tasks );
-	}
-	function test_get_cron_tasks__all() {
-		add_filter( 'FHEE__EEH_Activation__get_cron_tasks', array( $this, 'change_cron_tasks' ) );
-		$old_cron_tasks = EEH_Activation::get_cron_tasks( 'all' );
-		$this->assertArrayHasKey( self::expired_cron_task_name, $old_cron_tasks );
-		$this->assertArrayHasKey( self::current_cron_task_name, $old_cron_tasks );
-	}
-
-
-	/**
-	 * @see   https://events.codebasehq.com/projects/event-espresso/tickets/9501
-	 * @since 4.8.36
-	 */
-	function test_remove_cron_tasks_with_empty_timestamp_values() {
-		//first cache existing cron array
-		$old_cron_option = _get_cron_array();
-		//merge in a bunch of empty timestamps
-		$empty_timestamps = array(
-			time() + 30 => array(),
-			time() + 600 => array(),
-			time() - 400 => array()
-		);
-		_set_cron_array(
-			array_merge( $empty_timestamps, $old_cron_option )
-		);
-
-		//now let's run the EEH_Activation::remove_cron_tasks
-		EEH_Activation::remove_cron_tasks();
-
-		//and verify that there are no empty timestamps
-		$updated_cron_option = _get_cron_array();
-		$this->assertEquals( count( $old_cron_option ), count( $updated_cron_option ) );
-
-		//now restore
-		_set_cron_array( $old_cron_option );
-	}
-
-
-	/**
-	 * Makes it so this function can be independent on what the current cron tasks actually are
-	 * (because they'll likely change, whereas some of these functions just want to check that
-	 * we are retrieving cron tasks correctly)
-	 *
-	 * @param array $old_cron_tasks
-	 * @return array
-	 */
-	function change_cron_tasks( $old_cron_tasks ) {
-		return array(
-			self::current_cron_task_name => 'hourly',
-			self::expired_cron_task_name => EEH_Activation::cron_task_no_longer_in_use
-		);
-	}
-	
-	function test_table_exists__success() {
-		$this->assertTrue( EEH_Activation::table_exists( 'posts' ) );
-		$this->assertTrue( EEH_Activation::table_exists( 'esp_attendee_meta' ) );
-	}
-	
-	function test_table_exists__false() {
-		$this->assertFalse( EEH_Activation::table_exists( 'monkeys' ) );
-	}
-
+class EEH_Activation_Test extends EE_UnitTestCase
+{
+    const current_cron_task_name = 'current_one';
+
+    const expired_cron_task_name = 'expired_one';
+
+
+    public function set_up()
+    {
+        parent::set_up();
+        EEH_Activation::reset();
+    }
+
+
+    /**
+     * Makes it so this function can be independent on what the current cron tasks actually are
+     * (because they'll likely change, whereas some of these functions just want to check that
+     * we are retrieving cron tasks correctly)
+     *
+     * @return array
+     */
+    public function change_cron_tasks(): array
+    {
+        return [
+            self::current_cron_task_name => 'hourly',
+            self::expired_cron_task_name => EEH_Activation::cron_task_no_longer_in_use,
+        ];
+    }
+
+
+    /**
+     * The purpose of this test is to ensure that generation of default templates works as expected.
+     *
+     * @throws EE_Error
+     * @throws ReflectionException
+     * @since 4.5.0
+     */
+    public function test_generate_default_message_templates()
+    {
+        /**
+         * Testing default messengers setup on activation (or introduction on migration)
+         */
+        //first let's make sure all message templates got setup on new install as they should be.
+        /** @type EE_Message_Resource_Manager $message_resource_manager */
+        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
+        // messengers that have been activated and verified installed
+        $active_messengers = $message_resource_manager->active_messengers();
+        // ALL installed messengers regardless of whether they are active or not
+        $installed_messengers = $message_resource_manager->installed_messengers();
+        $should_be_installed  = [];
+        foreach ($active_messengers as $msgr) {
+            $this->assertInstanceOf('EE_messenger', $msgr);
+            if ($msgr->activate_on_install) {
+                $should_be_installed[] = $msgr->name;
+            }
+        }
+        //loop through $should_be_installed and verify that those that should be active ARE active.
+        foreach ($should_be_installed as $msgr_name) {
+            $this->assertTrue(
+                isset($installed_messengers[ $msgr_name ]),
+                sprintf('The messenger %s should be active on fresh install, but it is not.', $msgr_name)
+            );
+        }
+
+        //now verify that the code doesn't run new message template generation etc.
+        $this->assertFalse(EEH_Activation::generate_default_message_templates());
+
+
+        // now we simulate someone who's deactivated a messenger
+        // and we simulate a migration that triggers generating default message templates again.
+        //  The html messenger should STICK and NOT be activated.
+        $message_resource_manager->deactivate_messenger('html');
+
+        //do the same for message type
+        $message_resource_manager->deactivate_message_type_for_messenger('not_approved', 'email');
+
+        //Reset messages to test stickiness
+        EE_Registry::reset();
+
+        $activated_response = EEH_Activation::generate_default_message_templates();
+
+        //verify we got a response (html should not have templates generated)
+        $this->assertFalse($activated_response);
+
+        // double check we still don't have html in the active messengers array
+        $active_messengers = $message_resource_manager->get_active_messengers_option(true);
+        $this->assertFalse(isset($active_messengers['html']));
+        $this->assertFalse($message_resource_manager->is_message_type_active_for_messenger('email', 'not_approved'));
+    }
+
+
+    /**
+     * This tests the generate_default_message_templates method with using the
+     * FHEE__EE_messenger__get_default_message_types__default_types filter to add a
+     * bogus message_type string.  No errors should be triggered, and the invalid default mt
+     * should NOT be added to the active array for the messenger.
+     *
+     * @throws EE_Error
+     * @throws ReflectionException
+     * @since 4.6
+     * @group 7595
+     */
+    public function test_filtered_default_message_types_on_activation()
+    {
+        /** @type EE_Message_Resource_Manager $message_resource_manager */
+        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
+        //let's clear out all active messengers to get an accurate test of initial generation of message templates.
+        global $wpdb;
+        // delete message_template_group templates
+        $message_template_group_table = $wpdb->prefix . 'esp_message_template_group';
+        $query                        = "DELETE FROM $message_template_group_table WHERE 'GRP_ID' > 0";
+        $wpdb->query($query);
+        // delete message_template templates
+        $message_template_table = $wpdb->prefix . 'esp_message_template';
+        $query                  = "DELETE FROM $message_template_table WHERE 'MTP_ID' > 0";
+        $wpdb->query($query);
+        // delete event_message_template templates
+        $event_message_template_table = $wpdb->prefix . 'esp_event_message_template';
+        $query                        = "DELETE FROM $event_message_template_table WHERE 'EMT_ID' > 0";
+        $wpdb->query($query);
+
+        $message_resource_manager->update_active_messengers_option([]);
+        //set a filter for the invalid message type
+        add_filter(
+            'FHEE__EE_messenger__get_default_message_types__default_types',
+            function ($default_types) {
+                $default_types[] = 'bogus_message_type';
+                return $default_types;
+            },
+            10,
+            2
+        );
+
+        try {
+            //activate messages... if there's any problems then errors will trigger a fail.
+            EEH_Activation::generate_default_message_templates();
+        } catch (EE_Error $e) {
+            $this->assertInstanceOf('EE_Error', $e);
+        }
+
+        //all went well so let's make sure the activated system does NOT have our invalid message type string.
+        $active_messengers = $message_resource_manager->get_active_messengers_option(true);
+        foreach ($active_messengers as $messenger => $settings) {
+            $this->assertFalse(
+                isset($settings['settings'][ $messenger . '-message_types' ]['bogus_message_type']),
+                sprintf('The %s messenger should not have "bogus_message_type" active on it but it does.', $messenger)
+            );
+        }
+    }
+
+
+    /**
+     * Ensure getting default creator works as expected
+     *
+     * @throws EE_Error
+     * @throws ReflectionException
+     * @since 4.6.0
+     */
+    public function test_get_default_creator_id()
+    {
+        //clear out any previous users that may be lurking in teh system
+        foreach (get_users() as $wp_user) {
+            wp_delete_user($wp_user->ID);
+        }
+        //set some users; and just make it interesting by having the first user NOT be an admin
+        $this->factory->user->create_many(2);
+        $users = $this->factory->user->create_many(2);
+        //make users administrators.
+        foreach ($users as $user_id) {
+            $user = $this->factory->user->get_object_by_id($user_id);
+            //verify
+            $this->assertInstanceOf('WP_User', $user);
+            //add role
+            $user->add_role('administrator');
+        }
+
+        //get all users so we know who is the first one that we should be expecting.
+        $expected_id = reset($users);
+        $this->assertEquals($expected_id, EEH_Activation::get_default_creator_id());
+
+        /**
+         * ok now let's verify EEH_Activation::reset() properly clears the cache
+         * on EEH_Activation. This is important for subsequent unit tests (because
+         * EEH_Activation::reset() is called between unit tests), but also when an admin
+         * resets their EE database, or when anyone wants to reset that cache)
+         * clear out any previous users that may be lurking in teh system
+         */
+        EEH_Activation::reset();
+        foreach (get_users() as $wp_user) {
+            wp_delete_user($wp_user->ID);
+        }
+        //set some users; and just make it interesting by having the first user NOT be an admin
+        $this->factory->user->create_many(2);
+        $users_created_after_reset = $this->factory->user->create_many(2);
+        //make users administrators.
+        foreach ($users_created_after_reset as $user_id) {
+            $user = $this->factory->user->get_object_by_id($user_id);
+            //verify
+            $this->assertInstanceOf('WP_User', $user);
+            //add role
+            $user->add_role('administrator');
+        }
+
+        //get all users so we know who is the first one that we should be expecting.
+        $new_expected_id = reset($users_created_after_reset);
+        $this->assertEquals(EEH_Activation::get_default_creator_id(), $new_expected_id);
+    }
+
+
+    /**
+     * @throws EE_Error
+     */
+    public function test_get_cron_tasks__old()
+    {
+        add_filter('FHEE__EEH_Activation__get_cron_tasks', [$this, 'change_cron_tasks']);
+        $old_cron_tasks = EEH_Activation::get_cron_tasks('old');
+        $this->assertArrayHasKey(self::expired_cron_task_name, $old_cron_tasks);
+        $this->assertArrayNotHasKey(self::current_cron_task_name, $old_cron_tasks);
+    }
+
+
+    /**
+     * @throws EE_Error
+     */
+    public function test_get_cron_tasks__all()
+    {
+        add_filter('FHEE__EEH_Activation__get_cron_tasks', [$this, 'change_cron_tasks']);
+        $old_cron_tasks = EEH_Activation::get_cron_tasks('all');
+        $this->assertArrayHasKey(self::expired_cron_task_name, $old_cron_tasks);
+        $this->assertArrayHasKey(self::current_cron_task_name, $old_cron_tasks);
+    }
+
+
+    /**
+     * @throws EE_Error
+     * @see   https://events.codebasehq.com/projects/event-espresso/tickets/9501
+     * @since 4.8.36
+     */
+    public function test_remove_cron_tasks_with_empty_timestamp_values()
+    {
+        //first cache existing cron array
+        $old_cron_option = _get_cron_array();
+        //merge in a bunch of empty timestamps
+        $empty_timestamps = [
+            time() + 30  => [],
+            time() + 600 => [],
+            time() - 400 => [],
+        ];
+        _set_cron_array(
+            array_merge($empty_timestamps, $old_cron_option)
+        );
+
+        //now let's run the EEH_Activation::remove_cron_tasks
+        EEH_Activation::remove_cron_tasks();
+
+        //and verify that there are no empty timestamps
+        $updated_cron_option = _get_cron_array();
+        $this->assertEquals(count($old_cron_option), count($updated_cron_option));
+
+        //now restore
+        _set_cron_array($old_cron_option);
+    }
+
+
+    /**
+     * @throws EE_Error
+     * @throws ReflectionException
+     */
+    public function test_table_exists__success()
+    {
+        $this->assertTrue(EEH_Activation::table_exists('posts'));
+        $this->assertTrue(EEH_Activation::table_exists('esp_attendee_meta'));
+    }
+
+
+    /**
+     * @throws EE_Error
+     * @throws ReflectionException
+     */
+    public function test_table_exists__false()
+    {
+        $this->assertFalse(EEH_Activation::table_exists('monkeys'));
+    }
 
 
 } //end class EEH_Activation_Test
diff --git a/tests/testcases/core/helpers/EEH_Parse_Shortcodes_Test.php b/tests/testcases/core/helpers/EEH_Parse_Shortcodes_Test.php
index 6acfd4554ad..e84ac67e169 100644
--- a/tests/testcases/core/helpers/EEH_Parse_Shortcodes_Test.php
+++ b/tests/testcases/core/helpers/EEH_Parse_Shortcodes_Test.php
@@ -278,6 +278,7 @@ protected function _get_parsed_content($messenger, $message_type, $field, $conte
      */
     public function test_parsing_email_payment_received()
     {
+        tests_add_filter('FHEE_load_EE_Session', '__return_true');
         $parsed = $this->_get_parsed_content('email', 'payment', 'content', 'primary_attendee');
 
         //now that we have parsed let's test the results, note for the purpose of this test we are verifying transaction shortcodes and ticket shortcodes.
@@ -319,7 +320,7 @@ public function test_parsing_email_payment_received()
             $parsed,
             '[TKT_QTY_PURCHASED] shortcode was not parsed correctly to the expected value which is 3'
         );
-
+        tests_add_filter('FHEE_load_EE_Session', '__return_true');
     }
 
 
diff --git a/tests/testcases/core/libraries/plugin_api/EE_Register_Payment_Method_Test.php b/tests/testcases/core/libraries/plugin_api/EE_Register_Payment_Method_Test.php
index 4ed8a73aa9e..44a9349db61 100644
--- a/tests/testcases/core/libraries/plugin_api/EE_Register_Payment_Method_Test.php
+++ b/tests/testcases/core/libraries/plugin_api/EE_Register_Payment_Method_Test.php
@@ -30,7 +30,7 @@ public function set_up()
                 ],
         ];
         $this->_pmt_name              = 'Mock_Onsite';
-        $this->payment_method_manager = LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
+        $this->payment_method_manager = EE_Payment_Method_Manager::reset();
     }
 
 
@@ -51,7 +51,7 @@ public function test_register__fail()
         $this->_stop_pretending_addon_hook_time();
         remove_all_filters('FHEE__EE_Payment_Method_Manager__register_payment_methods__payment_methods_to_register');
 
-        //first verify it doesn't already exists
+        // first verify it doesn't already exists
         $pmt_exists = $this->payment_method_manager->payment_method_type_exists($this->_pmt_name);
         $this->assertFalse($pmt_exists);
 
diff --git a/tests/testcases/core/services/loaders/CachingLoaderTest.php b/tests/testcases/core/services/loaders/CachingLoaderTest.php
index 15c3c63a46f..a7ce54c07b5 100644
--- a/tests/testcases/core/services/loaders/CachingLoaderTest.php
+++ b/tests/testcases/core/services/loaders/CachingLoaderTest.php
@@ -43,7 +43,7 @@ public function set_up()
         //different persistence tests
         if (! CachingLoaderTest::$caching_loader instanceof LoaderDecorator) {
             CachingLoaderTest::$caching_loader = new CachingLoaderMock(
-                new CoreLoader(EE_Registry::instance()),
+                new CoreLoader(EE_Registry::reset()),
                 new LooseCollection(''),
                 new ObjectIdentifier(new ClassInterfaceCache())
             );
diff --git a/tests/testcases/core/services/request/RequestStackBuilderTest.php b/tests/testcases/core/services/request/RequestStackBuilderTest.php
index 47bc96480d9..1661daa99da 100644
--- a/tests/testcases/core/services/request/RequestStackBuilderTest.php
+++ b/tests/testcases/core/services/request/RequestStackBuilderTest.php
@@ -91,6 +91,11 @@ public function setMiddlewareFQCNs()
      */
     public function addMiddleware(bool $legacy = false)
     {
+        // but first, clear out any existing middleware
+        while ($this->request_stack_builder->count() > 0) {
+            $this->request_stack_builder->pop();
+        }
+        $this->assertCount(0, $this->request_stack_builder);
         $this->setMiddlewareFQCNs();
         if ($legacy) {
             $this->request_stack_builder->push([0, $this->general_grievous]);
@@ -215,14 +220,14 @@ public function TheBattleOfUtapau()
         $this->assertEquals(0, EE_Error::has_notices());
         $request_stack->handleRequest($this->request, $this->getResponse());
         $notices = $this->getNotices();
-        $this->assertCount(1, $notices['success']);
+        $this->assertCount(1, $notices['success'], var_export($notices['success'], true));
         $this->assertEquals('Hello There!', reset($notices['success']));
-        $this->assertCount(1, $notices['attention']);
+        $this->assertCount(1, $notices['attention'], var_export($notices['attention'], true));
         $this->assertEquals('General Kenobi!', reset($notices['attention']));
         $this->assertCount(1, $notices['errors']);
         $this->assertEquals(
             'Back away! I will deal with this Jedi slime myself!',
-            $notices['errors'][0],
+            reset($notices['errors']),
             'notices array: ' . var_export($notices, true)
         );
         $request_stack->handleResponse();