Completed
Branch master (44537d)
by
unknown
14:30 queued 10:03
created
4_5_0_stages/EE_DMS_4_5_0_update_wp_user_for_question_groups.dmsstage.php 2 patches
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -10,44 +10,44 @@
 block discarded – undo
10 10
  */
11 11
 class EE_DMS_4_5_0_update_wp_user_for_question_groups extends EE_Data_Migration_Script_Stage_Table
12 12
 {
13
-    public function __construct()
14
-    {
15
-        global $wpdb;
16
-        $this->_pretty_name = esc_html__("Question Groups", "event_espresso");
17
-        $this->_old_table   = $wpdb->prefix . "esp_question_group";
18
-        parent::__construct();
19
-    }
13
+	public function __construct()
14
+	{
15
+		global $wpdb;
16
+		$this->_pretty_name = esc_html__("Question Groups", "event_espresso");
17
+		$this->_old_table   = $wpdb->prefix . "esp_question_group";
18
+		parent::__construct();
19
+	}
20 20
 
21 21
 
22
-    protected function _migrate_old_row($old_row)
23
-    {
24
-        // foreach ticket row we add the id for the current logged in user.
25
-        global $wpdb;
26
-        $user_id = EEH_Activation::get_default_creator_id();
27
-        $user_id = $user_id ?: 0;
28
-        $updated = $wpdb->update(
29
-            $this->_old_table,
30
-            ['QSG_wp_user' => $user_id],
31
-            ['QSG_ID' => $old_row['QSG_ID']],
32
-            [
33
-                '%d',// QSG_wp_user
34
-            ],
35
-            [
36
-                '%d',// QSG_ID
37
-            ]
38
-        );
39
-        if (false === $updated) {
40
-            $this->add_error(
41
-                sprintf(
42
-                    esc_html__(
43
-                        "Error in updating table %s setting QSG_wp_user = %d where QSG_ID = %d",
44
-                        'event_espresso'
45
-                    ),
46
-                    $this->_old_table,
47
-                    $user_id,
48
-                    $old_row['QSG_ID']
49
-                )
50
-            );
51
-        }
52
-    }
22
+	protected function _migrate_old_row($old_row)
23
+	{
24
+		// foreach ticket row we add the id for the current logged in user.
25
+		global $wpdb;
26
+		$user_id = EEH_Activation::get_default_creator_id();
27
+		$user_id = $user_id ?: 0;
28
+		$updated = $wpdb->update(
29
+			$this->_old_table,
30
+			['QSG_wp_user' => $user_id],
31
+			['QSG_ID' => $old_row['QSG_ID']],
32
+			[
33
+				'%d',// QSG_wp_user
34
+			],
35
+			[
36
+				'%d',// QSG_ID
37
+			]
38
+		);
39
+		if (false === $updated) {
40
+			$this->add_error(
41
+				sprintf(
42
+					esc_html__(
43
+						"Error in updating table %s setting QSG_wp_user = %d where QSG_ID = %d",
44
+						'event_espresso'
45
+					),
46
+					$this->_old_table,
47
+					$user_id,
48
+					$old_row['QSG_ID']
49
+				)
50
+			);
51
+		}
52
+	}
53 53
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -14,7 +14,7 @@  discard block
 block discarded – undo
14 14
     {
15 15
         global $wpdb;
16 16
         $this->_pretty_name = esc_html__("Question Groups", "event_espresso");
17
-        $this->_old_table   = $wpdb->prefix . "esp_question_group";
17
+        $this->_old_table   = $wpdb->prefix."esp_question_group";
18 18
         parent::__construct();
19 19
     }
20 20
 
@@ -30,10 +30,10 @@  discard block
 block discarded – undo
30 30
             ['QSG_wp_user' => $user_id],
31 31
             ['QSG_ID' => $old_row['QSG_ID']],
32 32
             [
33
-                '%d',// QSG_wp_user
33
+                '%d', // QSG_wp_user
34 34
             ],
35 35
             [
36
-                '%d',// QSG_ID
36
+                '%d', // QSG_ID
37 37
             ]
38 38
         );
39 39
         if (false === $updated) {
Please login to merge, or discard this patch.
4_5_0_stages/EE_DMS_4_5_0_update_wp_user_for_price_types.dmsstage.php 2 patches
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -10,44 +10,44 @@
 block discarded – undo
10 10
  */
11 11
 class EE_DMS_4_5_0_update_wp_user_for_price_types extends EE_Data_Migration_Script_Stage_Table
12 12
 {
13
-    public function __construct()
14
-    {
15
-        global $wpdb;
16
-        $this->_pretty_name = esc_html__("Price Types", "event_espresso");
17
-        $this->_old_table   = $wpdb->prefix . "esp_price_type";
18
-        parent::__construct();
19
-    }
13
+	public function __construct()
14
+	{
15
+		global $wpdb;
16
+		$this->_pretty_name = esc_html__("Price Types", "event_espresso");
17
+		$this->_old_table   = $wpdb->prefix . "esp_price_type";
18
+		parent::__construct();
19
+	}
20 20
 
21 21
 
22
-    protected function _migrate_old_row($old_row)
23
-    {
24
-        // foreach ticket row we add the id for the current logged in user.
25
-        global $wpdb;
26
-        $user_id = EEH_Activation::get_default_creator_id();
27
-        $user_id = $user_id ?: 0;
28
-        $updated = $wpdb->update(
29
-            $this->_old_table,
30
-            ['PRT_wp_user' => $user_id],
31
-            ['PRT_ID' => $old_row['PRT_ID']],
32
-            [
33
-                '%d',// PRT_wp_user
34
-            ],
35
-            [
36
-                '%d',// PRT_ID
37
-            ]
38
-        );
39
-        if (false === $updated) {
40
-            $this->add_error(
41
-                sprintf(
42
-                    esc_html__(
43
-                        "Error in updating table %s setting PRT_wp_user = %d where PRT_ID = %d",
44
-                        'event_espresso'
45
-                    ),
46
-                    $this->_old_table,
47
-                    $user_id,
48
-                    $old_row['PRT_ID']
49
-                )
50
-            );
51
-        }
52
-    }
22
+	protected function _migrate_old_row($old_row)
23
+	{
24
+		// foreach ticket row we add the id for the current logged in user.
25
+		global $wpdb;
26
+		$user_id = EEH_Activation::get_default_creator_id();
27
+		$user_id = $user_id ?: 0;
28
+		$updated = $wpdb->update(
29
+			$this->_old_table,
30
+			['PRT_wp_user' => $user_id],
31
+			['PRT_ID' => $old_row['PRT_ID']],
32
+			[
33
+				'%d',// PRT_wp_user
34
+			],
35
+			[
36
+				'%d',// PRT_ID
37
+			]
38
+		);
39
+		if (false === $updated) {
40
+			$this->add_error(
41
+				sprintf(
42
+					esc_html__(
43
+						"Error in updating table %s setting PRT_wp_user = %d where PRT_ID = %d",
44
+						'event_espresso'
45
+					),
46
+					$this->_old_table,
47
+					$user_id,
48
+					$old_row['PRT_ID']
49
+				)
50
+			);
51
+		}
52
+	}
53 53
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -14,7 +14,7 @@  discard block
 block discarded – undo
14 14
     {
15 15
         global $wpdb;
16 16
         $this->_pretty_name = esc_html__("Price Types", "event_espresso");
17
-        $this->_old_table   = $wpdb->prefix . "esp_price_type";
17
+        $this->_old_table   = $wpdb->prefix."esp_price_type";
18 18
         parent::__construct();
19 19
     }
20 20
 
@@ -30,10 +30,10 @@  discard block
 block discarded – undo
30 30
             ['PRT_wp_user' => $user_id],
31 31
             ['PRT_ID' => $old_row['PRT_ID']],
32 32
             [
33
-                '%d',// PRT_wp_user
33
+                '%d', // PRT_wp_user
34 34
             ],
35 35
             [
36
-                '%d',// PRT_ID
36
+                '%d', // PRT_ID
37 37
             ]
38 38
         );
39 39
         if (false === $updated) {
Please login to merge, or discard this patch.
core/Psr4Autoloader.php 2 patches
Indentation   +131 added lines, -131 removed lines patch added patch discarded remove patch
@@ -44,148 +44,148 @@
 block discarded – undo
44 44
  */
45 45
 class Psr4Autoloader
46 46
 {
47
-    /**
48
-     * namespace separator
49
-     */
50
-    public const NS = '\\';
47
+	/**
48
+	 * namespace separator
49
+	 */
50
+	public const NS = '\\';
51 51
 
52
-    /**
53
-     * An associative array where the key is a namespace prefix and the value
54
-     * is an array of base directories for classes in that namespace.
55
-     *
56
-     * @var array
57
-     */
58
-    protected array $prefixes = [];
52
+	/**
53
+	 * An associative array where the key is a namespace prefix and the value
54
+	 * is an array of base directories for classes in that namespace.
55
+	 *
56
+	 * @var array
57
+	 */
58
+	protected array $prefixes = [];
59 59
 
60 60
 
61
-    /**
62
-     * returns an array of registered namespace prefixes
63
-     *
64
-     * @param string $prefix
65
-     * @return array
66
-     */
67
-    public function prefixes(string $prefix = ''): array
68
-    {
69
-        if (! empty($prefix)) {
70
-            // are there any base directories for this namespace prefix?
71
-            return $this->prefixes[ $prefix ] ?? [];
72
-        }
73
-        return $this->prefixes;
74
-    }
61
+	/**
62
+	 * returns an array of registered namespace prefixes
63
+	 *
64
+	 * @param string $prefix
65
+	 * @return array
66
+	 */
67
+	public function prefixes(string $prefix = ''): array
68
+	{
69
+		if (! empty($prefix)) {
70
+			// are there any base directories for this namespace prefix?
71
+			return $this->prefixes[ $prefix ] ?? [];
72
+		}
73
+		return $this->prefixes;
74
+	}
75 75
 
76 76
 
77
-    /**
78
-     * Register loader with SPL autoloader stack.
79
-     *
80
-     * @return void
81
-     */
82
-    public function register()
83
-    {
84
-        spl_autoload_register([$this, 'loadClass']);
85
-    }
77
+	/**
78
+	 * Register loader with SPL autoloader stack.
79
+	 *
80
+	 * @return void
81
+	 */
82
+	public function register()
83
+	{
84
+		spl_autoload_register([$this, 'loadClass']);
85
+	}
86 86
 
87 87
 
88
-    /**
89
-     * Adds a base directory for a namespace prefix.
90
-     *
91
-     * @param string $prefix    The namespace prefix.
92
-     * @param string $base_dir  A base directory for class files in the namespace.
93
-     * @param bool   $prepend   If true, prepend the base directory to the stack instead of appending it;
94
-     *                          this causes it to be searched first rather than last.
95
-     * @return bool             returns TRUE if the namespace was successfully added
96
-     */
97
-    public function addNamespace(string $prefix, string $base_dir, bool $prepend = false): bool
98
-    {
99
-        // normalize namespace prefix
100
-        $prefix = trim($prefix, Psr4Autoloader::NS) . Psr4Autoloader::NS;
101
-        // normalize the base directory with a trailing separator
102
-        $base_dir = str_replace(['\\', '/'], '/', $base_dir);
103
-        $base_dir = rtrim($base_dir, '/\\') . '/';
104
-        // initialize the namespace prefix array
105
-        if (! isset($this->prefixes[ $prefix ])) {
106
-            $this->prefixes[ $prefix ] = [];
107
-        }
108
-        // retain the base directory for the namespace prefix
109
-        if ($prepend) {
110
-            array_unshift($this->prefixes[ $prefix ], $base_dir);
111
-        } else {
112
-            $this->prefixes[ $prefix ][] = $base_dir;
113
-        }
114
-        return isset($this->prefixes[ $prefix ]);
115
-    }
88
+	/**
89
+	 * Adds a base directory for a namespace prefix.
90
+	 *
91
+	 * @param string $prefix    The namespace prefix.
92
+	 * @param string $base_dir  A base directory for class files in the namespace.
93
+	 * @param bool   $prepend   If true, prepend the base directory to the stack instead of appending it;
94
+	 *                          this causes it to be searched first rather than last.
95
+	 * @return bool             returns TRUE if the namespace was successfully added
96
+	 */
97
+	public function addNamespace(string $prefix, string $base_dir, bool $prepend = false): bool
98
+	{
99
+		// normalize namespace prefix
100
+		$prefix = trim($prefix, Psr4Autoloader::NS) . Psr4Autoloader::NS;
101
+		// normalize the base directory with a trailing separator
102
+		$base_dir = str_replace(['\\', '/'], '/', $base_dir);
103
+		$base_dir = rtrim($base_dir, '/\\') . '/';
104
+		// initialize the namespace prefix array
105
+		if (! isset($this->prefixes[ $prefix ])) {
106
+			$this->prefixes[ $prefix ] = [];
107
+		}
108
+		// retain the base directory for the namespace prefix
109
+		if ($prepend) {
110
+			array_unshift($this->prefixes[ $prefix ], $base_dir);
111
+		} else {
112
+			$this->prefixes[ $prefix ][] = $base_dir;
113
+		}
114
+		return isset($this->prefixes[ $prefix ]);
115
+	}
116 116
 
117 117
 
118
-    /**
119
-     * Loads the class file for a given class name.
120
-     *
121
-     * @param string $class The fully-qualified class name.
122
-     * @return string The mapped file name on success or boolean false on failure.
123
-     */
124
-    public function loadClass(string $class): string
125
-    {
126
-        // the current namespace prefix
127
-        $prefix = $class;
128
-        // work backwards through the namespace names of the fully-qualified
129
-        // class name to find a mapped file name
130
-        while (false !== $pos = strrpos($prefix, Psr4Autoloader::NS)) {
131
-            // retain the trailing namespace separator in the prefix
132
-            $prefix = substr($class, 0, $pos + 1);
133
-            // the rest is the relative class name
134
-            $relative_class = substr($class, $pos + 1);
135
-            // try to load a mapped file for the prefix and relative class
136
-            $mapped_file = $this->loadMappedFile($prefix, $relative_class);
137
-            if ($mapped_file) {
138
-                return $mapped_file;
139
-            }
140
-            // remove the trailing namespace separator for the next iteration of strrpos()
141
-            $prefix = rtrim($prefix, Psr4Autoloader::NS);
142
-        }
143
-        // never found a mapped file
144
-        return '';
145
-    }
118
+	/**
119
+	 * Loads the class file for a given class name.
120
+	 *
121
+	 * @param string $class The fully-qualified class name.
122
+	 * @return string The mapped file name on success or boolean false on failure.
123
+	 */
124
+	public function loadClass(string $class): string
125
+	{
126
+		// the current namespace prefix
127
+		$prefix = $class;
128
+		// work backwards through the namespace names of the fully-qualified
129
+		// class name to find a mapped file name
130
+		while (false !== $pos = strrpos($prefix, Psr4Autoloader::NS)) {
131
+			// retain the trailing namespace separator in the prefix
132
+			$prefix = substr($class, 0, $pos + 1);
133
+			// the rest is the relative class name
134
+			$relative_class = substr($class, $pos + 1);
135
+			// try to load a mapped file for the prefix and relative class
136
+			$mapped_file = $this->loadMappedFile($prefix, $relative_class);
137
+			if ($mapped_file) {
138
+				return $mapped_file;
139
+			}
140
+			// remove the trailing namespace separator for the next iteration of strrpos()
141
+			$prefix = rtrim($prefix, Psr4Autoloader::NS);
142
+		}
143
+		// never found a mapped file
144
+		return '';
145
+	}
146 146
 
147 147
 
148
-    /**
149
-     * Load the mapped file for a namespace prefix and relative class.
150
-     *
151
-     * @param string $prefix         The namespace prefix.
152
-     * @param string $relative_class The relative class name.
153
-     * @return string                empty string if no mapped file can be loaded,
154
-     *                               or the name of the mapped file that was loaded.
155
-     */
156
-    protected function loadMappedFile(string $prefix, string $relative_class): string
157
-    {
158
-        // look through base directories for this namespace prefix
159
-        foreach ($this->prefixes($prefix) as $base_dir) {
160
-            // replace the namespace prefix with the base directory,
161
-            // replace namespace separators with directory separators
162
-            // in the relative class name, append with .php
163
-            $file = $base_dir
164
-                    . str_replace(Psr4Autoloader::NS, '/', $relative_class)
165
-                    . '.php';
166
-            // if the mapped file exists, require it
167
-            if ($this->requireFile($file)) {
168
-                // yes, we're done
169
-                return $file;
170
-            }
171
-        }
172
-        // never found it
173
-        return '';
174
-    }
148
+	/**
149
+	 * Load the mapped file for a namespace prefix and relative class.
150
+	 *
151
+	 * @param string $prefix         The namespace prefix.
152
+	 * @param string $relative_class The relative class name.
153
+	 * @return string                empty string if no mapped file can be loaded,
154
+	 *                               or the name of the mapped file that was loaded.
155
+	 */
156
+	protected function loadMappedFile(string $prefix, string $relative_class): string
157
+	{
158
+		// look through base directories for this namespace prefix
159
+		foreach ($this->prefixes($prefix) as $base_dir) {
160
+			// replace the namespace prefix with the base directory,
161
+			// replace namespace separators with directory separators
162
+			// in the relative class name, append with .php
163
+			$file = $base_dir
164
+					. str_replace(Psr4Autoloader::NS, '/', $relative_class)
165
+					. '.php';
166
+			// if the mapped file exists, require it
167
+			if ($this->requireFile($file)) {
168
+				// yes, we're done
169
+				return $file;
170
+			}
171
+		}
172
+		// never found it
173
+		return '';
174
+	}
175 175
 
176 176
 
177
-    /**
178
-     * If a file exists, require it from the file system.
179
-     *
180
-     * @param string $file The file to require.
181
-     * @return bool         True if the file exists, false if not.
182
-     */
183
-    protected function requireFile(string $file): bool
184
-    {
185
-        if (file_exists($file)) {
186
-            require $file;
187
-            return true;
188
-        }
189
-        return false;
190
-    }
177
+	/**
178
+	 * If a file exists, require it from the file system.
179
+	 *
180
+	 * @param string $file The file to require.
181
+	 * @return bool         True if the file exists, false if not.
182
+	 */
183
+	protected function requireFile(string $file): bool
184
+	{
185
+		if (file_exists($file)) {
186
+			require $file;
187
+			return true;
188
+		}
189
+		return false;
190
+	}
191 191
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -66,9 +66,9 @@  discard block
 block discarded – undo
66 66
      */
67 67
     public function prefixes(string $prefix = ''): array
68 68
     {
69
-        if (! empty($prefix)) {
69
+        if ( ! empty($prefix)) {
70 70
             // are there any base directories for this namespace prefix?
71
-            return $this->prefixes[ $prefix ] ?? [];
71
+            return $this->prefixes[$prefix] ?? [];
72 72
         }
73 73
         return $this->prefixes;
74 74
     }
@@ -97,21 +97,21 @@  discard block
 block discarded – undo
97 97
     public function addNamespace(string $prefix, string $base_dir, bool $prepend = false): bool
98 98
     {
99 99
         // normalize namespace prefix
100
-        $prefix = trim($prefix, Psr4Autoloader::NS) . Psr4Autoloader::NS;
100
+        $prefix = trim($prefix, Psr4Autoloader::NS).Psr4Autoloader::NS;
101 101
         // normalize the base directory with a trailing separator
102 102
         $base_dir = str_replace(['\\', '/'], '/', $base_dir);
103
-        $base_dir = rtrim($base_dir, '/\\') . '/';
103
+        $base_dir = rtrim($base_dir, '/\\').'/';
104 104
         // initialize the namespace prefix array
105
-        if (! isset($this->prefixes[ $prefix ])) {
106
-            $this->prefixes[ $prefix ] = [];
105
+        if ( ! isset($this->prefixes[$prefix])) {
106
+            $this->prefixes[$prefix] = [];
107 107
         }
108 108
         // retain the base directory for the namespace prefix
109 109
         if ($prepend) {
110
-            array_unshift($this->prefixes[ $prefix ], $base_dir);
110
+            array_unshift($this->prefixes[$prefix], $base_dir);
111 111
         } else {
112
-            $this->prefixes[ $prefix ][] = $base_dir;
112
+            $this->prefixes[$prefix][] = $base_dir;
113 113
         }
114
-        return isset($this->prefixes[ $prefix ]);
114
+        return isset($this->prefixes[$prefix]);
115 115
     }
116 116
 
117 117
 
Please login to merge, or discard this patch.
core/EE_Session.core.php 2 patches
Indentation   +1308 added lines, -1308 removed lines patch added patch discarded remove patch
@@ -23,1306 +23,1306 @@  discard block
 block discarded – undo
23 23
  */
24 24
 class EE_Session implements SessionIdentifierInterface
25 25
 {
26
-    const session_id_prefix    = 'ee_ssn_';
27
-
28
-    const hash_check_prefix    = 'ee_shc_';
29
-
30
-    const OPTION_NAME_SETTINGS = 'ee_session_settings';
31
-
32
-    const STATUS_CLOSED        = 0;
33
-
34
-    const STATUS_OPEN          = 1;
35
-
36
-    const SAVE_STATE_CLEAN     = 'clean';
37
-
38
-    const SAVE_STATE_DIRTY     = 'dirty';
39
-
40
-
41
-    /**
42
-     * instance of the EE_Session object
43
-     *
44
-     * @var EE_Session
45
-     */
46
-    private static $_instance;
47
-
48
-    /**
49
-     * @var CacheStorageInterface $cache_storage
50
-     */
51
-    protected $cache_storage;
52
-
53
-    /**
54
-     * @var Base64Encoder
55
-     */
56
-    protected $encryption;
57
-
58
-    /**
59
-     * @var SessionStartHandler $session_start_handler
60
-     */
61
-    protected $session_start_handler;
62
-
63
-    /**
64
-     * the session id
65
-     *
66
-     * @var string
67
-     */
68
-    private $_sid;
69
-
70
-    /**
71
-     * session id salt
72
-     *
73
-     * @var string
74
-     */
75
-    private $_sid_salt;
76
-
77
-    /**
78
-     * session data
79
-     *
80
-     * @var array
81
-     */
82
-    private $_session_data = [];
83
-
84
-    /**
85
-     * how long an EE session lasts
86
-     * default session lifespan of 1 hour (for not so instant IPNs)
87
-     *
88
-     * @var SessionLifespan $session_lifespan
89
-     */
90
-    private $session_lifespan;
91
-
92
-    /**
93
-     * session expiration time as Unix timestamp in GMT
94
-     *
95
-     * @var int
96
-     */
97
-    private $_expiration;
98
-
99
-    /**
100
-     * whether session has expired at some point
101
-     *
102
-     * @var boolean
103
-     */
104
-    private $_expired = false;
105
-
106
-    /**
107
-     * current time as Unix timestamp in GMT
108
-     *
109
-     * @var int
110
-     */
111
-    private $_time;
112
-
113
-    /**
114
-     * whether to encrypt session data
115
-     *
116
-     * @var bool
117
-     */
118
-    private $_use_encryption;
119
-
120
-    /**
121
-     * well... according to the server...
122
-     *
123
-     * @var null
124
-     */
125
-    private $_user_agent;
126
-
127
-
128
-    /**
129
-     * array for defining default session vars
130
-     *
131
-     * @var array
132
-     */
133
-    private $_default_session_vars = [
134
-        'id'            => null,
135
-        'user_id'       => null,
136
-        'ip_address'    => null,
137
-        'user_agent'    => null,
138
-        'init_access'   => null,
139
-        'last_access'   => null,
140
-        'expiration'    => null,
141
-        'pages_visited' => [],
142
-    ];
143
-
144
-    /**
145
-     * timestamp for when last garbage collection cycle was performed
146
-     *
147
-     * @var int $_last_gc
148
-     */
149
-    private $_last_gc;
150
-
151
-    /**
152
-     * @var RequestInterface $request
153
-     */
154
-    protected $request;
155
-
156
-    /**
157
-     * whether session is active or not
158
-     *
159
-     * @var int $status
160
-     */
161
-    private $status = EE_Session::STATUS_CLOSED;
162
-
163
-    /**
164
-     * whether session data has changed therefore requiring a session save
165
-     *
166
-     * @var string $save_state
167
-     */
168
-    private $save_state = EE_Session::SAVE_STATE_CLEAN;
169
-
170
-
171
-    /**
172
-     * @singleton method used to instantiate class object
173
-     * @param CacheStorageInterface|null $cache_storage
174
-     * @param SessionLifespan|null       $lifespan
175
-     * @param RequestInterface|null      $request
176
-     * @param SessionStartHandler|null   $session_start_handler
177
-     * @param Base64Encoder|null         $encryption
178
-     * @return EE_Session
179
-     * @throws InvalidArgumentException
180
-     * @throws InvalidDataTypeException
181
-     * @throws InvalidInterfaceException
182
-     */
183
-    public static function instance(
184
-        CacheStorageInterface $cache_storage = null,
185
-        SessionLifespan $lifespan = null,
186
-        RequestInterface $request = null,
187
-        SessionStartHandler $session_start_handler = null,
188
-        Base64Encoder $encryption = null
189
-    ) {
190
-        // check if class object is instantiated
191
-        // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
192
-        // add_filter( 'FHEE_load_EE_Session', '__return_false' );
193
-        if (
194
-            ! self::$_instance instanceof EE_Session
195
-            && $cache_storage instanceof CacheStorageInterface
196
-            && $lifespan instanceof SessionLifespan
197
-            && $request instanceof RequestInterface
198
-            && $session_start_handler instanceof SessionStartHandler
199
-            && apply_filters('FHEE_load_EE_Session', true)
200
-        ) {
201
-            self::$_instance = new self(
202
-                $cache_storage,
203
-                $lifespan,
204
-                $request,
205
-                $session_start_handler,
206
-                $encryption
207
-            );
208
-        }
209
-        return self::$_instance;
210
-    }
211
-
212
-
213
-    /**
214
-     * protected constructor to prevent direct creation
215
-     *
216
-     * @param CacheStorageInterface $cache_storage
217
-     * @param SessionLifespan       $lifespan
218
-     * @param RequestInterface      $request
219
-     * @param SessionStartHandler   $session_start_handler
220
-     * @param Base64Encoder|null    $encryption
221
-     * @throws InvalidArgumentException
222
-     * @throws InvalidDataTypeException
223
-     * @throws InvalidInterfaceException
224
-     */
225
-    protected function __construct(
226
-        CacheStorageInterface $cache_storage,
227
-        SessionLifespan $lifespan,
228
-        RequestInterface $request,
229
-        SessionStartHandler $session_start_handler,
230
-        Base64Encoder $encryption = null
231
-    ) {
232
-        // session loading is turned ON by default,
233
-        // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
234
-        // (which currently fires on the init hook at priority 9),
235
-        // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
236
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
237
-            return;
238
-        }
239
-        $this->session_start_handler = $session_start_handler;
240
-        $this->session_lifespan      = $lifespan;
241
-        $this->request               = $request;
242
-        if (! defined('ESPRESSO_SESSION')) {
243
-            define('ESPRESSO_SESSION', true);
244
-        }
245
-        // retrieve session options from db
246
-        $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, []);
247
-        if (! empty($session_settings)) {
248
-            // cycle though existing session options
249
-            foreach ($session_settings as $var_name => $session_setting) {
250
-                // set values for class properties
251
-                $var_name          = '_' . $var_name;
252
-                $this->{$var_name} = $session_setting;
253
-            }
254
-        }
255
-        $this->cache_storage = $cache_storage;
256
-        // are we using encryption?
257
-        $this->_use_encryption = $encryption instanceof Base64Encoder
258
-                                 && EE_Registry::instance()->CFG->admin->encode_session_data();
259
-        // encrypt data via: $this->encryption->encodeString();
260
-        $this->encryption = $encryption;
261
-        // filter hook allows outside functions/classes/plugins to change default empty cart
262
-        $extra_default_session_vars  = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', []);
263
-        $this->_default_session_vars = array_merge($this->_default_session_vars, $extra_default_session_vars);
264
-        // apply default session vars
265
-        $this->_set_defaults();
266
-        add_action('AHEE__EE_System__initialize', [$this, 'open_session']);
267
-        // check request for 'clear_session' param
268
-        add_action('AHEE__EE_Request_Handler__construct__complete', [$this, 'wp_loaded']);
269
-        // once everything is all said and done,
270
-        add_action('shutdown', [$this, 'update'], 100);
271
-        add_action('shutdown', [$this, 'garbageCollection'], 1000);
272
-        $this->configure_garbage_collection_filters();
273
-    }
274
-
275
-
276
-    /**
277
-     * @return bool
278
-     * @throws InvalidArgumentException
279
-     * @throws InvalidDataTypeException
280
-     * @throws InvalidInterfaceException
281
-     */
282
-    public static function isLoadedAndActive(): bool
283
-    {
284
-        return did_action('AHEE__EE_System__core_loaded_and_ready')
285
-               && EE_Session::instance() instanceof EE_Session
286
-               && EE_Session::instance()->isActive();
287
-    }
288
-
289
-
290
-    /**
291
-     * @return bool
292
-     */
293
-    public function isActive(): bool
294
-    {
295
-        return $this->status === EE_Session::STATUS_OPEN;
296
-    }
297
-
298
-
299
-    /**
300
-     * @return void
301
-     * @throws EE_Error
302
-     * @throws InvalidArgumentException
303
-     * @throws InvalidDataTypeException
304
-     * @throws InvalidInterfaceException
305
-     * @throws InvalidSessionDataException
306
-     * @throws RuntimeException
307
-     * @throws ReflectionException
308
-     */
309
-    public function open_session()
310
-    {
311
-        // Check for an existing session and retrieve it from the database, unless the system is in maintenance level 2.
312
-        if (EE_Maintenance_Mode::instance()->models_can_query() && ! $this->_espresso_session()) {
313
-            // or just start a new one
314
-            $this->_create_espresso_session();
315
-        }
316
-    }
317
-
318
-
319
-    /**
320
-     * @return bool
321
-     */
322
-    public function expired(): bool
323
-    {
324
-        return $this->_expired;
325
-    }
326
-
327
-
328
-    /**
329
-     * @return void
330
-     */
331
-    public function reset_expired()
332
-    {
333
-        $this->_expired = false;
334
-    }
335
-
336
-
337
-    /**
338
-     * @return int
339
-     */
340
-    public function expiration(): int
341
-    {
342
-        return $this->_expiration;
343
-    }
344
-
345
-
346
-    /**
347
-     * @return int
348
-     */
349
-    public function extension(): int
350
-    {
351
-        return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
352
-    }
353
-
354
-
355
-    /**
356
-     * @param int $time number of seconds to add to session expiration
357
-     */
358
-    public function extend_expiration(int $time = 0)
359
-    {
360
-        $time              = $time
361
-            ?: $this->extension();
362
-        $this->_expiration += absint($time);
363
-    }
364
-
365
-
366
-    /**
367
-     * @return int
368
-     */
369
-    public function lifespan(): int
370
-    {
371
-        return $this->session_lifespan->inSeconds();
372
-    }
373
-
374
-
375
-    /**
376
-     * Marks whether the session data has been updated or not.
377
-     * Valid options are:
378
-     *      EE_Session::SAVE_STATE_CLEAN - session data remains unchanged and updating is not necessary
379
-     *      EE_Session::SAVE_STATE_DIRTY - session data has changed since last save and needs to be updated
380
-     * default value is EE_Session::SAVE_STATE_DIRTY
381
-     *
382
-     * @param string $save_state
383
-     */
384
-    public function setSaveState(string $save_state = EE_Session::SAVE_STATE_DIRTY)
385
-    {
386
-        $valid_save_states = [
387
-            EE_Session::SAVE_STATE_CLEAN,
388
-            EE_Session::SAVE_STATE_DIRTY,
389
-        ];
390
-        if (! in_array($save_state, $valid_save_states, true)) {
391
-            $save_state = EE_Session::SAVE_STATE_DIRTY;
392
-        }
393
-        $this->save_state = $save_state;
394
-    }
395
-
396
-
397
-    /**
398
-     * This just sets some defaults for the _session data property
399
-     *
400
-     * @return void
401
-     */
402
-    private function _set_defaults()
403
-    {
404
-        // set some defaults
405
-        foreach ($this->_default_session_vars as $key => $default_var) {
406
-            if (is_array($default_var)) {
407
-                $this->_session_data[ $key ] = [];
408
-            } else {
409
-                $this->_session_data[ $key ] = '';
410
-            }
411
-        }
412
-    }
413
-
414
-
415
-    /**
416
-     * @retrieve  session data
417
-     * @return    string
418
-     */
419
-    public function id(): string
420
-    {
421
-        return $this->_sid;
422
-    }
423
-
424
-
425
-    /**
426
-     * @param EE_Cart $cart
427
-     * @return bool
428
-     */
429
-    public function set_cart(EE_Cart $cart): bool
430
-    {
431
-        $this->_session_data['cart'] = $cart;
432
-        $this->setSaveState();
433
-        return true;
434
-    }
435
-
436
-
437
-    /**
438
-     * reset_cart
439
-     */
440
-    public function reset_cart()
441
-    {
442
-        do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
443
-        $this->_session_data['cart'] = null;
444
-        $this->setSaveState();
445
-    }
446
-
447
-
448
-    /**
449
-     * @return EE_Cart
450
-     */
451
-    public function cart(): ?EE_Cart
452
-    {
453
-        return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
454
-            ? $this->_session_data['cart']
455
-            : null;
456
-    }
457
-
458
-
459
-    /**
460
-     * @param EE_Checkout $checkout
461
-     * @return bool
462
-     */
463
-    public function set_checkout(EE_Checkout $checkout): bool
464
-    {
465
-        $this->_session_data['checkout'] = $checkout;
466
-        $this->setSaveState();
467
-        return true;
468
-    }
469
-
470
-
471
-    /**
472
-     * reset_checkout
473
-     */
474
-    public function reset_checkout()
475
-    {
476
-        do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
477
-        $this->_session_data['checkout'] = null;
478
-        $this->setSaveState();
479
-    }
480
-
481
-
482
-    /**
483
-     * @return EE_Checkout
484
-     */
485
-    public function checkout(): ?EE_Checkout
486
-    {
487
-        return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
488
-            ? $this->_session_data['checkout']
489
-            : null;
490
-    }
491
-
492
-
493
-    /**
494
-     * @param EE_Transaction $transaction
495
-     * @return bool
496
-     * @throws EE_Error
497
-     * @throws ReflectionException
498
-     */
499
-    public function set_transaction(EE_Transaction $transaction): bool
500
-    {
501
-        // first remove the session from the transaction before we save the transaction in the session
502
-        $transaction->set_txn_session_data(null);
503
-        $this->_session_data['transaction'] = $transaction;
504
-        $this->setSaveState();
505
-        return true;
506
-    }
507
-
508
-
509
-    /**
510
-     * reset_transaction
511
-     */
512
-    public function reset_transaction()
513
-    {
514
-        do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
515
-        $this->_session_data['transaction'] = null;
516
-        $this->setSaveState();
517
-    }
518
-
519
-
520
-    /**
521
-     * @return EE_Transaction
522
-     */
523
-    public function transaction(): ?EE_Transaction
524
-    {
525
-        return isset($this->_session_data['transaction'])
526
-               && $this->_session_data['transaction'] instanceof EE_Transaction
527
-            ? $this->_session_data['transaction']
528
-            : null;
529
-    }
530
-
531
-
532
-    /**
533
-     * retrieve session data
534
-     *
535
-     * @param string|null $key
536
-     * @param bool        $reset_cache
537
-     * @return array|EE_Cart|EE_Checkout|EE_Transaction
538
-     */
539
-    public function get_session_data(?string $key = null, bool $reset_cache = false)
540
-    {
541
-        if ($reset_cache) {
542
-            $this->reset_cart();
543
-            $this->reset_checkout();
544
-            $this->reset_transaction();
545
-        }
546
-        if (! empty($key)) {
547
-            return $this->_session_data[ $key ] ?? null;
548
-        }
549
-        return $this->_session_data;
550
-    }
551
-
552
-
553
-    /**
554
-     * Returns TRUE on success, FALSE on fail
555
-     *
556
-     * @param array $data
557
-     * @return bool
558
-     */
559
-    public function set_session_data(array $data): bool
560
-    {
561
-        // nothing ??? bad data ??? go home!
562
-        if (empty($data)) {
563
-            EE_Error::add_error(
564
-                esc_html__(
565
-                    'No session data or invalid session data was provided.',
566
-                    'event_espresso'
567
-                ),
568
-                __FILE__,
569
-                __FUNCTION__,
570
-                __LINE__
571
-            );
572
-            return false;
573
-        }
574
-        foreach ($data as $key => $value) {
575
-            if (isset($this->_default_session_vars[ $key ])) {
576
-                EE_Error::add_error(
577
-                    sprintf(
578
-                        esc_html__(
579
-                            'Sorry! %s is a default session datum and can not be reset.',
580
-                            'event_espresso'
581
-                        ),
582
-                        $key
583
-                    ),
584
-                    __FILE__,
585
-                    __FUNCTION__,
586
-                    __LINE__
587
-                );
588
-                return false;
589
-            }
590
-            $this->_session_data[ $key ] = $value;
591
-            $this->setSaveState();
592
-        }
593
-        return true;
594
-    }
595
-
596
-
597
-    /**
598
-     * @initiate session
599
-     * @return bool TRUE on success, FALSE on fail
600
-     * @throws EE_Error
601
-     * @throws InvalidArgumentException
602
-     * @throws InvalidDataTypeException
603
-     * @throws InvalidInterfaceException
604
-     * @throws InvalidSessionDataException
605
-     * @throws RuntimeException
606
-     * @throws ReflectionException
607
-     */
608
-    private function _espresso_session(): bool
609
-    {
610
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
611
-        $this->session_start_handler->startSession();
612
-        $this->status = EE_Session::STATUS_OPEN;
613
-        // get our modified session ID
614
-        $this->_sid = $this->_generate_session_id();
615
-        // set the "user agent"
616
-        $this->_user_agent = $this->request->userAgent();
617
-        // now let's retrieve what's in the db
618
-        $session_data = $this->_retrieve_session_data();
619
-        if (empty($session_data)) {
620
-            // set initial site access time and the session expiration
621
-            $this->_set_init_access_and_expiration();
622
-            // set referer
623
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
624
-                $this->request->getServerParam('HTTP_REFERER')
625
-            );
626
-            // no previous session = go back and create one (on top of the data above)
627
-            return false;
628
-        }
629
-        // get the current time in UTC
630
-        $this->_time = $this->_time !== null
631
-            ? $this->_time
632
-            : time();
633
-        // and reset the session expiration
634
-        $this->_expiration = $session_data['expiration'] ?? $this->_time + $this->session_lifespan->inSeconds();
635
-        // now the user agent
636
-        if ($session_data['user_agent'] !== $this->_user_agent) {
637
-            return false;
638
-        }
639
-        // wait a minute... how old are you?
640
-        if ($this->_time > $this->_expiration) {
641
-            // yer too old fer me!
642
-            $this->_expired = true;
643
-            // wipe out everything that isn't a default session datum
644
-            $this->clear_session(__CLASS__, __FUNCTION__);
645
-        }
646
-        // make event espresso session data available to plugin
647
-        $this->_session_data = array_merge($this->_session_data, $session_data);
648
-        return true;
649
-    }
650
-
651
-
652
-    /**
653
-     * _get_session_data
654
-     * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
655
-     * databases
656
-     *
657
-     * @return array
658
-     * @throws EE_Error
659
-     * @throws InvalidArgumentException
660
-     * @throws InvalidSessionDataException
661
-     * @throws InvalidDataTypeException
662
-     * @throws InvalidInterfaceException
663
-     * @throws RuntimeException
664
-     * @throws ReflectionException
665
-     */
666
-    protected function _retrieve_session_data(): array
667
-    {
668
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
669
-        try {
670
-            // we're using WP's Transient API to store session data using the PHP session ID as the option name
671
-            $session_data = $this->cache_storage->get($ssn_key, false);
672
-            if (empty($session_data)) {
673
-                return [];
674
-            }
675
-            if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
676
-                $hash_check = $this->cache_storage->get(
677
-                    EE_Session::hash_check_prefix . $this->_sid,
678
-                    false
679
-                );
680
-                if ($hash_check && $hash_check !== md5($session_data)) {
681
-                    EE_Error::add_error(
682
-                        sprintf(
683
-                            esc_html__(
684
-                                'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
685
-                                'event_espresso'
686
-                            ),
687
-                            EE_Session::session_id_prefix . $this->_sid
688
-                        ),
689
-                        __FILE__,
690
-                        __FUNCTION__,
691
-                        __LINE__
692
-                    );
693
-                }
694
-            }
695
-        } catch (Exception $e) {
696
-            // let's just eat that error for now and attempt to correct any corrupted data
697
-            global $wpdb;
698
-            $row          = $wpdb->get_row(
699
-                $wpdb->prepare(
700
-                    "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
701
-                    '_transient_' . $ssn_key
702
-                )
703
-            );
704
-            $session_data = is_object($row)
705
-                ? $row->option_value
706
-                : null;
707
-            if ($session_data) {
708
-                $session_data = preg_replace_callback(
709
-                    '!s:(d+):"(.*?)";!',
710
-                    function ($match) {
711
-                        return $match[1] === strlen($match[2])
712
-                            ? $match[0]
713
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
714
-                    },
715
-                    $session_data
716
-                );
717
-            }
718
-            $session_data = maybe_unserialize($session_data);
719
-        }
720
-        // in case the data is encoded... try to decode it
721
-        $session_data = $this->_use_encryption
722
-            ? $this->encryption->encodeString($session_data)
723
-            : $session_data;
724
-        if (! is_array($session_data)) {
725
-            try {
726
-                $session_data = maybe_unserialize($session_data);
727
-            } catch (Exception $e) {
728
-                $msg = esc_html__(
729
-                    'An error occurred while attempting to unserialize the session data.',
730
-                    'event_espresso'
731
-                );
732
-                $msg .= WP_DEBUG
733
-                    ? '<br><pre>'
734
-                      . print_r($session_data, true)
735
-                      . '</pre><br>'
736
-                      . $this->find_serialize_error($session_data)
737
-                    : '';
738
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
739
-                throw new InvalidSessionDataException($msg, 0, $e);
740
-            }
741
-        }
742
-        // just a check to make sure the session array is indeed an array
743
-        if (! is_array($session_data)) {
744
-            // no?!?! then something is wrong
745
-            $msg = esc_html__(
746
-                'The session data is missing, invalid, or corrupted.',
747
-                'event_espresso'
748
-            );
749
-            $msg .= WP_DEBUG
750
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
751
-                : '';
752
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
753
-            throw new InvalidSessionDataException($msg);
754
-        }
755
-        if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
756
-            $session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
757
-                $session_data['transaction']
758
-            );
759
-        }
760
-        return $session_data;
761
-    }
762
-
763
-
764
-    /**
765
-     * _generate_session_id
766
-     * Retrieves the PHP session id either directly from the PHP session,
767
-     * or from the request array if it was passed in from an AJAX request.
768
-     * The session id is then salted and hashed (mmm sounds tasty)
769
-     * so that it can be safely used as a request param
770
-     *
771
-     * @return string
772
-     */
773
-    protected function _generate_session_id(): string
774
-    {
775
-        // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
776
-        $session_id = $this->request->requestParamIsSet('EESID')
777
-            ? $this->request->getRequestParam('EESID')
778
-            : md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
779
-        return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
780
-    }
781
-
782
-
783
-    /**
784
-     * _get_sid_salt
785
-     *
786
-     * @return string
787
-     */
788
-    protected function _get_sid_salt(): string
789
-    {
790
-        // was session id salt already saved to db ?
791
-        if (empty($this->_sid_salt)) {
792
-            // no?  then maybe use WP defined constant
793
-            if (defined('AUTH_SALT')) {
794
-                $this->_sid_salt = AUTH_SALT;
795
-            }
796
-            // if salt doesn't exist or is too short
797
-            if (strlen($this->_sid_salt) < 32) {
798
-                // create a new one
799
-                $this->_sid_salt = wp_generate_password(64);
800
-            }
801
-            // and save it as a permanent session setting
802
-            $this->updateSessionSettings(['sid_salt' => $this->_sid_salt]);
803
-        }
804
-        return $this->_sid_salt;
805
-    }
806
-
807
-
808
-    /**
809
-     * _set_init_access_and_expiration
810
-     *
811
-     * @return void
812
-     */
813
-    protected function _set_init_access_and_expiration()
814
-    {
815
-        $this->_time       = time();
816
-        $this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
817
-        // set initial site access time
818
-        $this->_session_data['init_access'] = $this->_time;
819
-        // and the session expiration
820
-        $this->_session_data['expiration'] = $this->_expiration;
821
-    }
822
-
823
-
824
-    /**
825
-     * @update session data  prior to saving to the db
826
-     * @param bool $new_session
827
-     * @return bool TRUE on success, FALSE on fail
828
-     * @throws EE_Error
829
-     * @throws InvalidArgumentException
830
-     * @throws InvalidDataTypeException
831
-     * @throws InvalidInterfaceException
832
-     * @throws ReflectionException
833
-     */
834
-    public function update(bool $new_session = false): bool
835
-    {
836
-        $this->_session_data = is_array($this->_session_data) && isset($this->_session_data['id'])
837
-            ? $this->_session_data
838
-            : [];
839
-        if (empty($this->_session_data)) {
840
-            $this->_set_defaults();
841
-        }
842
-        $session_data = [];
843
-        foreach ($this->_session_data as $key => $value) {
844
-            switch ($key) {
845
-                case 'id':
846
-                    // session ID
847
-                    $session_data['id'] = $this->_sid;
848
-                    break;
849
-                case 'ip_address':
850
-                    // visitor ip address
851
-                    $session_data['ip_address'] = $this->request->ipAddress();
852
-                    break;
853
-                case 'user_agent':
854
-                    // visitor user_agent
855
-                    $session_data['user_agent'] = $this->_user_agent;
856
-                    break;
857
-                case 'init_access':
858
-                    $session_data['init_access'] = absint($value);
859
-                    break;
860
-                case 'last_access':
861
-                    // current access time
862
-                    $session_data['last_access'] = $this->_time;
863
-                    break;
864
-                case 'expiration':
865
-                    // when the session expires
866
-                    $session_data['expiration'] = ! empty($this->_expiration)
867
-                        ? $this->_expiration
868
-                        : $session_data['init_access'] + $this->session_lifespan->inSeconds();
869
-                    break;
870
-                case 'user_id':
871
-                    // current user if logged in
872
-                    $session_data['user_id'] = $this->_wp_user_id();
873
-                    break;
874
-                case 'pages_visited':
875
-                    $page_visit = $this->_get_page_visit();
876
-                    if ($page_visit) {
877
-                        // set pages visited where the first will be the http referrer
878
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
879
-                        // we'll only save the last 10 page visits.
880
-                        $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
881
-                    }
882
-                    break;
883
-                default:
884
-                    // carry any other data over
885
-                    $session_data[ $key ] = $this->_session_data[ $key ];
886
-            }
887
-        }
888
-        $this->_session_data = $session_data;
889
-        // creating a new session does not require saving to the db just yet
890
-        if (! $new_session) {
891
-            // ready? let's save
892
-            if ($this->_save_session_to_db()) {
893
-                return true;
894
-            }
895
-            return false;
896
-        }
897
-        // meh, why not?
898
-        return true;
899
-    }
900
-
901
-
902
-    /**
903
-     * @create session data array
904
-     * @throws EE_Error
905
-     * @throws InvalidArgumentException
906
-     * @throws InvalidDataTypeException
907
-     * @throws InvalidInterfaceException
908
-     * @throws ReflectionException
909
-     */
910
-    private function _create_espresso_session()
911
-    {
912
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
913
-        // use the update function for now with $new_session arg set to TRUE
914
-        $this->update(true);
915
-    }
916
-
917
-
918
-    /**
919
-     * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good
920
-     * too). This is used when determining if we want to save the session or not.
921
-     *
922
-     * @return bool
923
-     * @since 4.9.67.p
924
-     */
925
-    private function sessionHasStuffWorthSaving(): bool
926
-    {
927
-        return $this->save_state === EE_Session::SAVE_STATE_DIRTY
928
-               // we may want to eventually remove the following
929
-               // on the assumption that the above check is enough
930
-               || $this->cart() instanceof EE_Cart
931
-               || (
932
-                   isset($this->_session_data['ee_notices'])
933
-                   && (
934
-                       ! empty($this->_session_data['ee_notices']['attention'])
935
-                       || ! empty($this->_session_data['ee_notices']['errors'])
936
-                       || ! empty($this->_session_data['ee_notices']['success'])
937
-                   )
938
-               );
939
-    }
940
-
941
-
942
-    /**
943
-     * _save_session_to_db
944
-     *
945
-     * @param bool $clear_session
946
-     * @return bool
947
-     * @throws EE_Error
948
-     * @throws InvalidArgumentException
949
-     * @throws InvalidDataTypeException
950
-     * @throws InvalidInterfaceException
951
-     * @throws ReflectionException
952
-     */
953
-    private function _save_session_to_db(bool $clear_session = false): bool
954
-    {
955
-        // don't save sessions for crawlers
956
-        // and unless we're deleting the session data, don't save anything if there isn't a cart
957
-        if (
958
-            $this->request->isBot()
959
-            || (
960
-                ! $clear_session
961
-                && ! $this->sessionHasStuffWorthSaving()
962
-                && apply_filters('FHEE__EE_Session___save_session_to_db__abort_session_save', true)
963
-            )
964
-        ) {
965
-            return false;
966
-        }
967
-        $transaction = $this->transaction();
968
-        if ($transaction instanceof EE_Transaction) {
969
-            if (! $transaction->ID()) {
970
-                $transaction->save();
971
-            }
972
-            $this->_session_data['transaction'] = $transaction->ID();
973
-        }
974
-        // then serialize all of our session data
975
-        $session_data = serialize($this->_session_data);
976
-        // do we need to also encode it to avoid corrupted data when saved to the db?
977
-        $session_data = $this->_use_encryption
978
-            ? $this->encryption->decodeString($session_data)
979
-            : $session_data;
980
-        // maybe save hash check
981
-        if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
982
-            $this->cache_storage->add(
983
-                EE_Session::hash_check_prefix . $this->_sid,
984
-                md5($session_data),
985
-                $this->session_lifespan->inSeconds()
986
-            );
987
-        }
988
-        // we're using the Transient API for storing session data,
989
-        $saved = $this->cache_storage->add(
990
-            EE_Session::session_id_prefix . $this->_sid,
991
-            $session_data,
992
-            $this->session_lifespan->inSeconds()
993
-        );
994
-        $this->setSaveState(EE_Session::SAVE_STATE_CLEAN);
995
-        return $saved;
996
-    }
997
-
998
-
999
-    /**
1000
-     * @get    the full page request the visitor is accessing
1001
-     * @return string
1002
-     */
1003
-    public function _get_page_visit(): string
1004
-    {
1005
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1006
-        // check for request url
1007
-        if ($this->request->serverParamIsSet('REQUEST_URI')) {
1008
-            $page_id     = '?';
1009
-            $e_reg       = '';
1010
-            $request_uri = $this->request->getServerParam('REQUEST_URI');
1011
-            $ru_bits     = explode('?', $request_uri);
1012
-            $request_uri = $ru_bits[0];
1013
-            $http_host   = $this->request->getServerParam('HTTP_HOST');
1014
-            // check for page_id in SERVER REQUEST
1015
-            if ($this->request->requestParamIsSet('page_id')) {
1016
-                // rebuild $e_reg without any of the extra parameters
1017
-                $page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1018
-            }
1019
-            // check for $e_reg in SERVER REQUEST
1020
-            if ($this->request->requestParamIsSet('ee')) {
1021
-                // rebuild $e_reg without any of the extra parameters
1022
-                $e_reg = 'ee=' . $this->request->getRequestParam('ee');
1023
-            }
1024
-            $page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1025
-        }
1026
-        return $page_visit !== home_url('/wp-admin/admin-ajax.php')
1027
-            ? $page_visit
1028
-            : '';
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * @the    current wp user id
1034
-     * @return int
1035
-     */
1036
-    public function _wp_user_id(): int
1037
-    {
1038
-        // if I need to explain the following lines of code, then you shouldn't be looking at this!
1039
-        return get_current_user_id();
1040
-    }
1041
-
1042
-
1043
-    /**
1044
-     * Clear EE_Session data
1045
-     *
1046
-     * @param string $class
1047
-     * @param string $function
1048
-     * @return void
1049
-     * @throws EE_Error
1050
-     * @throws InvalidArgumentException
1051
-     * @throws InvalidDataTypeException
1052
-     * @throws InvalidInterfaceException
1053
-     * @throws ReflectionException
1054
-     */
1055
-    public function clear_session(string $class = '', string $function = '')
1056
-    {
26
+	const session_id_prefix    = 'ee_ssn_';
27
+
28
+	const hash_check_prefix    = 'ee_shc_';
29
+
30
+	const OPTION_NAME_SETTINGS = 'ee_session_settings';
31
+
32
+	const STATUS_CLOSED        = 0;
33
+
34
+	const STATUS_OPEN          = 1;
35
+
36
+	const SAVE_STATE_CLEAN     = 'clean';
37
+
38
+	const SAVE_STATE_DIRTY     = 'dirty';
39
+
40
+
41
+	/**
42
+	 * instance of the EE_Session object
43
+	 *
44
+	 * @var EE_Session
45
+	 */
46
+	private static $_instance;
47
+
48
+	/**
49
+	 * @var CacheStorageInterface $cache_storage
50
+	 */
51
+	protected $cache_storage;
52
+
53
+	/**
54
+	 * @var Base64Encoder
55
+	 */
56
+	protected $encryption;
57
+
58
+	/**
59
+	 * @var SessionStartHandler $session_start_handler
60
+	 */
61
+	protected $session_start_handler;
62
+
63
+	/**
64
+	 * the session id
65
+	 *
66
+	 * @var string
67
+	 */
68
+	private $_sid;
69
+
70
+	/**
71
+	 * session id salt
72
+	 *
73
+	 * @var string
74
+	 */
75
+	private $_sid_salt;
76
+
77
+	/**
78
+	 * session data
79
+	 *
80
+	 * @var array
81
+	 */
82
+	private $_session_data = [];
83
+
84
+	/**
85
+	 * how long an EE session lasts
86
+	 * default session lifespan of 1 hour (for not so instant IPNs)
87
+	 *
88
+	 * @var SessionLifespan $session_lifespan
89
+	 */
90
+	private $session_lifespan;
91
+
92
+	/**
93
+	 * session expiration time as Unix timestamp in GMT
94
+	 *
95
+	 * @var int
96
+	 */
97
+	private $_expiration;
98
+
99
+	/**
100
+	 * whether session has expired at some point
101
+	 *
102
+	 * @var boolean
103
+	 */
104
+	private $_expired = false;
105
+
106
+	/**
107
+	 * current time as Unix timestamp in GMT
108
+	 *
109
+	 * @var int
110
+	 */
111
+	private $_time;
112
+
113
+	/**
114
+	 * whether to encrypt session data
115
+	 *
116
+	 * @var bool
117
+	 */
118
+	private $_use_encryption;
119
+
120
+	/**
121
+	 * well... according to the server...
122
+	 *
123
+	 * @var null
124
+	 */
125
+	private $_user_agent;
126
+
127
+
128
+	/**
129
+	 * array for defining default session vars
130
+	 *
131
+	 * @var array
132
+	 */
133
+	private $_default_session_vars = [
134
+		'id'            => null,
135
+		'user_id'       => null,
136
+		'ip_address'    => null,
137
+		'user_agent'    => null,
138
+		'init_access'   => null,
139
+		'last_access'   => null,
140
+		'expiration'    => null,
141
+		'pages_visited' => [],
142
+	];
143
+
144
+	/**
145
+	 * timestamp for when last garbage collection cycle was performed
146
+	 *
147
+	 * @var int $_last_gc
148
+	 */
149
+	private $_last_gc;
150
+
151
+	/**
152
+	 * @var RequestInterface $request
153
+	 */
154
+	protected $request;
155
+
156
+	/**
157
+	 * whether session is active or not
158
+	 *
159
+	 * @var int $status
160
+	 */
161
+	private $status = EE_Session::STATUS_CLOSED;
162
+
163
+	/**
164
+	 * whether session data has changed therefore requiring a session save
165
+	 *
166
+	 * @var string $save_state
167
+	 */
168
+	private $save_state = EE_Session::SAVE_STATE_CLEAN;
169
+
170
+
171
+	/**
172
+	 * @singleton method used to instantiate class object
173
+	 * @param CacheStorageInterface|null $cache_storage
174
+	 * @param SessionLifespan|null       $lifespan
175
+	 * @param RequestInterface|null      $request
176
+	 * @param SessionStartHandler|null   $session_start_handler
177
+	 * @param Base64Encoder|null         $encryption
178
+	 * @return EE_Session
179
+	 * @throws InvalidArgumentException
180
+	 * @throws InvalidDataTypeException
181
+	 * @throws InvalidInterfaceException
182
+	 */
183
+	public static function instance(
184
+		CacheStorageInterface $cache_storage = null,
185
+		SessionLifespan $lifespan = null,
186
+		RequestInterface $request = null,
187
+		SessionStartHandler $session_start_handler = null,
188
+		Base64Encoder $encryption = null
189
+	) {
190
+		// check if class object is instantiated
191
+		// session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
192
+		// add_filter( 'FHEE_load_EE_Session', '__return_false' );
193
+		if (
194
+			! self::$_instance instanceof EE_Session
195
+			&& $cache_storage instanceof CacheStorageInterface
196
+			&& $lifespan instanceof SessionLifespan
197
+			&& $request instanceof RequestInterface
198
+			&& $session_start_handler instanceof SessionStartHandler
199
+			&& apply_filters('FHEE_load_EE_Session', true)
200
+		) {
201
+			self::$_instance = new self(
202
+				$cache_storage,
203
+				$lifespan,
204
+				$request,
205
+				$session_start_handler,
206
+				$encryption
207
+			);
208
+		}
209
+		return self::$_instance;
210
+	}
211
+
212
+
213
+	/**
214
+	 * protected constructor to prevent direct creation
215
+	 *
216
+	 * @param CacheStorageInterface $cache_storage
217
+	 * @param SessionLifespan       $lifespan
218
+	 * @param RequestInterface      $request
219
+	 * @param SessionStartHandler   $session_start_handler
220
+	 * @param Base64Encoder|null    $encryption
221
+	 * @throws InvalidArgumentException
222
+	 * @throws InvalidDataTypeException
223
+	 * @throws InvalidInterfaceException
224
+	 */
225
+	protected function __construct(
226
+		CacheStorageInterface $cache_storage,
227
+		SessionLifespan $lifespan,
228
+		RequestInterface $request,
229
+		SessionStartHandler $session_start_handler,
230
+		Base64Encoder $encryption = null
231
+	) {
232
+		// session loading is turned ON by default,
233
+		// but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
234
+		// (which currently fires on the init hook at priority 9),
235
+		// can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
236
+		if (! apply_filters('FHEE_load_EE_Session', true)) {
237
+			return;
238
+		}
239
+		$this->session_start_handler = $session_start_handler;
240
+		$this->session_lifespan      = $lifespan;
241
+		$this->request               = $request;
242
+		if (! defined('ESPRESSO_SESSION')) {
243
+			define('ESPRESSO_SESSION', true);
244
+		}
245
+		// retrieve session options from db
246
+		$session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, []);
247
+		if (! empty($session_settings)) {
248
+			// cycle though existing session options
249
+			foreach ($session_settings as $var_name => $session_setting) {
250
+				// set values for class properties
251
+				$var_name          = '_' . $var_name;
252
+				$this->{$var_name} = $session_setting;
253
+			}
254
+		}
255
+		$this->cache_storage = $cache_storage;
256
+		// are we using encryption?
257
+		$this->_use_encryption = $encryption instanceof Base64Encoder
258
+								 && EE_Registry::instance()->CFG->admin->encode_session_data();
259
+		// encrypt data via: $this->encryption->encodeString();
260
+		$this->encryption = $encryption;
261
+		// filter hook allows outside functions/classes/plugins to change default empty cart
262
+		$extra_default_session_vars  = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', []);
263
+		$this->_default_session_vars = array_merge($this->_default_session_vars, $extra_default_session_vars);
264
+		// apply default session vars
265
+		$this->_set_defaults();
266
+		add_action('AHEE__EE_System__initialize', [$this, 'open_session']);
267
+		// check request for 'clear_session' param
268
+		add_action('AHEE__EE_Request_Handler__construct__complete', [$this, 'wp_loaded']);
269
+		// once everything is all said and done,
270
+		add_action('shutdown', [$this, 'update'], 100);
271
+		add_action('shutdown', [$this, 'garbageCollection'], 1000);
272
+		$this->configure_garbage_collection_filters();
273
+	}
274
+
275
+
276
+	/**
277
+	 * @return bool
278
+	 * @throws InvalidArgumentException
279
+	 * @throws InvalidDataTypeException
280
+	 * @throws InvalidInterfaceException
281
+	 */
282
+	public static function isLoadedAndActive(): bool
283
+	{
284
+		return did_action('AHEE__EE_System__core_loaded_and_ready')
285
+			   && EE_Session::instance() instanceof EE_Session
286
+			   && EE_Session::instance()->isActive();
287
+	}
288
+
289
+
290
+	/**
291
+	 * @return bool
292
+	 */
293
+	public function isActive(): bool
294
+	{
295
+		return $this->status === EE_Session::STATUS_OPEN;
296
+	}
297
+
298
+
299
+	/**
300
+	 * @return void
301
+	 * @throws EE_Error
302
+	 * @throws InvalidArgumentException
303
+	 * @throws InvalidDataTypeException
304
+	 * @throws InvalidInterfaceException
305
+	 * @throws InvalidSessionDataException
306
+	 * @throws RuntimeException
307
+	 * @throws ReflectionException
308
+	 */
309
+	public function open_session()
310
+	{
311
+		// Check for an existing session and retrieve it from the database, unless the system is in maintenance level 2.
312
+		if (EE_Maintenance_Mode::instance()->models_can_query() && ! $this->_espresso_session()) {
313
+			// or just start a new one
314
+			$this->_create_espresso_session();
315
+		}
316
+	}
317
+
318
+
319
+	/**
320
+	 * @return bool
321
+	 */
322
+	public function expired(): bool
323
+	{
324
+		return $this->_expired;
325
+	}
326
+
327
+
328
+	/**
329
+	 * @return void
330
+	 */
331
+	public function reset_expired()
332
+	{
333
+		$this->_expired = false;
334
+	}
335
+
336
+
337
+	/**
338
+	 * @return int
339
+	 */
340
+	public function expiration(): int
341
+	{
342
+		return $this->_expiration;
343
+	}
344
+
345
+
346
+	/**
347
+	 * @return int
348
+	 */
349
+	public function extension(): int
350
+	{
351
+		return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
352
+	}
353
+
354
+
355
+	/**
356
+	 * @param int $time number of seconds to add to session expiration
357
+	 */
358
+	public function extend_expiration(int $time = 0)
359
+	{
360
+		$time              = $time
361
+			?: $this->extension();
362
+		$this->_expiration += absint($time);
363
+	}
364
+
365
+
366
+	/**
367
+	 * @return int
368
+	 */
369
+	public function lifespan(): int
370
+	{
371
+		return $this->session_lifespan->inSeconds();
372
+	}
373
+
374
+
375
+	/**
376
+	 * Marks whether the session data has been updated or not.
377
+	 * Valid options are:
378
+	 *      EE_Session::SAVE_STATE_CLEAN - session data remains unchanged and updating is not necessary
379
+	 *      EE_Session::SAVE_STATE_DIRTY - session data has changed since last save and needs to be updated
380
+	 * default value is EE_Session::SAVE_STATE_DIRTY
381
+	 *
382
+	 * @param string $save_state
383
+	 */
384
+	public function setSaveState(string $save_state = EE_Session::SAVE_STATE_DIRTY)
385
+	{
386
+		$valid_save_states = [
387
+			EE_Session::SAVE_STATE_CLEAN,
388
+			EE_Session::SAVE_STATE_DIRTY,
389
+		];
390
+		if (! in_array($save_state, $valid_save_states, true)) {
391
+			$save_state = EE_Session::SAVE_STATE_DIRTY;
392
+		}
393
+		$this->save_state = $save_state;
394
+	}
395
+
396
+
397
+	/**
398
+	 * This just sets some defaults for the _session data property
399
+	 *
400
+	 * @return void
401
+	 */
402
+	private function _set_defaults()
403
+	{
404
+		// set some defaults
405
+		foreach ($this->_default_session_vars as $key => $default_var) {
406
+			if (is_array($default_var)) {
407
+				$this->_session_data[ $key ] = [];
408
+			} else {
409
+				$this->_session_data[ $key ] = '';
410
+			}
411
+		}
412
+	}
413
+
414
+
415
+	/**
416
+	 * @retrieve  session data
417
+	 * @return    string
418
+	 */
419
+	public function id(): string
420
+	{
421
+		return $this->_sid;
422
+	}
423
+
424
+
425
+	/**
426
+	 * @param EE_Cart $cart
427
+	 * @return bool
428
+	 */
429
+	public function set_cart(EE_Cart $cart): bool
430
+	{
431
+		$this->_session_data['cart'] = $cart;
432
+		$this->setSaveState();
433
+		return true;
434
+	}
435
+
436
+
437
+	/**
438
+	 * reset_cart
439
+	 */
440
+	public function reset_cart()
441
+	{
442
+		do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
443
+		$this->_session_data['cart'] = null;
444
+		$this->setSaveState();
445
+	}
446
+
447
+
448
+	/**
449
+	 * @return EE_Cart
450
+	 */
451
+	public function cart(): ?EE_Cart
452
+	{
453
+		return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
454
+			? $this->_session_data['cart']
455
+			: null;
456
+	}
457
+
458
+
459
+	/**
460
+	 * @param EE_Checkout $checkout
461
+	 * @return bool
462
+	 */
463
+	public function set_checkout(EE_Checkout $checkout): bool
464
+	{
465
+		$this->_session_data['checkout'] = $checkout;
466
+		$this->setSaveState();
467
+		return true;
468
+	}
469
+
470
+
471
+	/**
472
+	 * reset_checkout
473
+	 */
474
+	public function reset_checkout()
475
+	{
476
+		do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
477
+		$this->_session_data['checkout'] = null;
478
+		$this->setSaveState();
479
+	}
480
+
481
+
482
+	/**
483
+	 * @return EE_Checkout
484
+	 */
485
+	public function checkout(): ?EE_Checkout
486
+	{
487
+		return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
488
+			? $this->_session_data['checkout']
489
+			: null;
490
+	}
491
+
492
+
493
+	/**
494
+	 * @param EE_Transaction $transaction
495
+	 * @return bool
496
+	 * @throws EE_Error
497
+	 * @throws ReflectionException
498
+	 */
499
+	public function set_transaction(EE_Transaction $transaction): bool
500
+	{
501
+		// first remove the session from the transaction before we save the transaction in the session
502
+		$transaction->set_txn_session_data(null);
503
+		$this->_session_data['transaction'] = $transaction;
504
+		$this->setSaveState();
505
+		return true;
506
+	}
507
+
508
+
509
+	/**
510
+	 * reset_transaction
511
+	 */
512
+	public function reset_transaction()
513
+	{
514
+		do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
515
+		$this->_session_data['transaction'] = null;
516
+		$this->setSaveState();
517
+	}
518
+
519
+
520
+	/**
521
+	 * @return EE_Transaction
522
+	 */
523
+	public function transaction(): ?EE_Transaction
524
+	{
525
+		return isset($this->_session_data['transaction'])
526
+			   && $this->_session_data['transaction'] instanceof EE_Transaction
527
+			? $this->_session_data['transaction']
528
+			: null;
529
+	}
530
+
531
+
532
+	/**
533
+	 * retrieve session data
534
+	 *
535
+	 * @param string|null $key
536
+	 * @param bool        $reset_cache
537
+	 * @return array|EE_Cart|EE_Checkout|EE_Transaction
538
+	 */
539
+	public function get_session_data(?string $key = null, bool $reset_cache = false)
540
+	{
541
+		if ($reset_cache) {
542
+			$this->reset_cart();
543
+			$this->reset_checkout();
544
+			$this->reset_transaction();
545
+		}
546
+		if (! empty($key)) {
547
+			return $this->_session_data[ $key ] ?? null;
548
+		}
549
+		return $this->_session_data;
550
+	}
551
+
552
+
553
+	/**
554
+	 * Returns TRUE on success, FALSE on fail
555
+	 *
556
+	 * @param array $data
557
+	 * @return bool
558
+	 */
559
+	public function set_session_data(array $data): bool
560
+	{
561
+		// nothing ??? bad data ??? go home!
562
+		if (empty($data)) {
563
+			EE_Error::add_error(
564
+				esc_html__(
565
+					'No session data or invalid session data was provided.',
566
+					'event_espresso'
567
+				),
568
+				__FILE__,
569
+				__FUNCTION__,
570
+				__LINE__
571
+			);
572
+			return false;
573
+		}
574
+		foreach ($data as $key => $value) {
575
+			if (isset($this->_default_session_vars[ $key ])) {
576
+				EE_Error::add_error(
577
+					sprintf(
578
+						esc_html__(
579
+							'Sorry! %s is a default session datum and can not be reset.',
580
+							'event_espresso'
581
+						),
582
+						$key
583
+					),
584
+					__FILE__,
585
+					__FUNCTION__,
586
+					__LINE__
587
+				);
588
+				return false;
589
+			}
590
+			$this->_session_data[ $key ] = $value;
591
+			$this->setSaveState();
592
+		}
593
+		return true;
594
+	}
595
+
596
+
597
+	/**
598
+	 * @initiate session
599
+	 * @return bool TRUE on success, FALSE on fail
600
+	 * @throws EE_Error
601
+	 * @throws InvalidArgumentException
602
+	 * @throws InvalidDataTypeException
603
+	 * @throws InvalidInterfaceException
604
+	 * @throws InvalidSessionDataException
605
+	 * @throws RuntimeException
606
+	 * @throws ReflectionException
607
+	 */
608
+	private function _espresso_session(): bool
609
+	{
610
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
611
+		$this->session_start_handler->startSession();
612
+		$this->status = EE_Session::STATUS_OPEN;
613
+		// get our modified session ID
614
+		$this->_sid = $this->_generate_session_id();
615
+		// set the "user agent"
616
+		$this->_user_agent = $this->request->userAgent();
617
+		// now let's retrieve what's in the db
618
+		$session_data = $this->_retrieve_session_data();
619
+		if (empty($session_data)) {
620
+			// set initial site access time and the session expiration
621
+			$this->_set_init_access_and_expiration();
622
+			// set referer
623
+			$this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
624
+				$this->request->getServerParam('HTTP_REFERER')
625
+			);
626
+			// no previous session = go back and create one (on top of the data above)
627
+			return false;
628
+		}
629
+		// get the current time in UTC
630
+		$this->_time = $this->_time !== null
631
+			? $this->_time
632
+			: time();
633
+		// and reset the session expiration
634
+		$this->_expiration = $session_data['expiration'] ?? $this->_time + $this->session_lifespan->inSeconds();
635
+		// now the user agent
636
+		if ($session_data['user_agent'] !== $this->_user_agent) {
637
+			return false;
638
+		}
639
+		// wait a minute... how old are you?
640
+		if ($this->_time > $this->_expiration) {
641
+			// yer too old fer me!
642
+			$this->_expired = true;
643
+			// wipe out everything that isn't a default session datum
644
+			$this->clear_session(__CLASS__, __FUNCTION__);
645
+		}
646
+		// make event espresso session data available to plugin
647
+		$this->_session_data = array_merge($this->_session_data, $session_data);
648
+		return true;
649
+	}
650
+
651
+
652
+	/**
653
+	 * _get_session_data
654
+	 * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
655
+	 * databases
656
+	 *
657
+	 * @return array
658
+	 * @throws EE_Error
659
+	 * @throws InvalidArgumentException
660
+	 * @throws InvalidSessionDataException
661
+	 * @throws InvalidDataTypeException
662
+	 * @throws InvalidInterfaceException
663
+	 * @throws RuntimeException
664
+	 * @throws ReflectionException
665
+	 */
666
+	protected function _retrieve_session_data(): array
667
+	{
668
+		$ssn_key = EE_Session::session_id_prefix . $this->_sid;
669
+		try {
670
+			// we're using WP's Transient API to store session data using the PHP session ID as the option name
671
+			$session_data = $this->cache_storage->get($ssn_key, false);
672
+			if (empty($session_data)) {
673
+				return [];
674
+			}
675
+			if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
676
+				$hash_check = $this->cache_storage->get(
677
+					EE_Session::hash_check_prefix . $this->_sid,
678
+					false
679
+				);
680
+				if ($hash_check && $hash_check !== md5($session_data)) {
681
+					EE_Error::add_error(
682
+						sprintf(
683
+							esc_html__(
684
+								'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
685
+								'event_espresso'
686
+							),
687
+							EE_Session::session_id_prefix . $this->_sid
688
+						),
689
+						__FILE__,
690
+						__FUNCTION__,
691
+						__LINE__
692
+					);
693
+				}
694
+			}
695
+		} catch (Exception $e) {
696
+			// let's just eat that error for now and attempt to correct any corrupted data
697
+			global $wpdb;
698
+			$row          = $wpdb->get_row(
699
+				$wpdb->prepare(
700
+					"SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
701
+					'_transient_' . $ssn_key
702
+				)
703
+			);
704
+			$session_data = is_object($row)
705
+				? $row->option_value
706
+				: null;
707
+			if ($session_data) {
708
+				$session_data = preg_replace_callback(
709
+					'!s:(d+):"(.*?)";!',
710
+					function ($match) {
711
+						return $match[1] === strlen($match[2])
712
+							? $match[0]
713
+							: 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
714
+					},
715
+					$session_data
716
+				);
717
+			}
718
+			$session_data = maybe_unserialize($session_data);
719
+		}
720
+		// in case the data is encoded... try to decode it
721
+		$session_data = $this->_use_encryption
722
+			? $this->encryption->encodeString($session_data)
723
+			: $session_data;
724
+		if (! is_array($session_data)) {
725
+			try {
726
+				$session_data = maybe_unserialize($session_data);
727
+			} catch (Exception $e) {
728
+				$msg = esc_html__(
729
+					'An error occurred while attempting to unserialize the session data.',
730
+					'event_espresso'
731
+				);
732
+				$msg .= WP_DEBUG
733
+					? '<br><pre>'
734
+					  . print_r($session_data, true)
735
+					  . '</pre><br>'
736
+					  . $this->find_serialize_error($session_data)
737
+					: '';
738
+				$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
739
+				throw new InvalidSessionDataException($msg, 0, $e);
740
+			}
741
+		}
742
+		// just a check to make sure the session array is indeed an array
743
+		if (! is_array($session_data)) {
744
+			// no?!?! then something is wrong
745
+			$msg = esc_html__(
746
+				'The session data is missing, invalid, or corrupted.',
747
+				'event_espresso'
748
+			);
749
+			$msg .= WP_DEBUG
750
+				? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
751
+				: '';
752
+			$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
753
+			throw new InvalidSessionDataException($msg);
754
+		}
755
+		if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
756
+			$session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
757
+				$session_data['transaction']
758
+			);
759
+		}
760
+		return $session_data;
761
+	}
762
+
763
+
764
+	/**
765
+	 * _generate_session_id
766
+	 * Retrieves the PHP session id either directly from the PHP session,
767
+	 * or from the request array if it was passed in from an AJAX request.
768
+	 * The session id is then salted and hashed (mmm sounds tasty)
769
+	 * so that it can be safely used as a request param
770
+	 *
771
+	 * @return string
772
+	 */
773
+	protected function _generate_session_id(): string
774
+	{
775
+		// check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
776
+		$session_id = $this->request->requestParamIsSet('EESID')
777
+			? $this->request->getRequestParam('EESID')
778
+			: md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
779
+		return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
780
+	}
781
+
782
+
783
+	/**
784
+	 * _get_sid_salt
785
+	 *
786
+	 * @return string
787
+	 */
788
+	protected function _get_sid_salt(): string
789
+	{
790
+		// was session id salt already saved to db ?
791
+		if (empty($this->_sid_salt)) {
792
+			// no?  then maybe use WP defined constant
793
+			if (defined('AUTH_SALT')) {
794
+				$this->_sid_salt = AUTH_SALT;
795
+			}
796
+			// if salt doesn't exist or is too short
797
+			if (strlen($this->_sid_salt) < 32) {
798
+				// create a new one
799
+				$this->_sid_salt = wp_generate_password(64);
800
+			}
801
+			// and save it as a permanent session setting
802
+			$this->updateSessionSettings(['sid_salt' => $this->_sid_salt]);
803
+		}
804
+		return $this->_sid_salt;
805
+	}
806
+
807
+
808
+	/**
809
+	 * _set_init_access_and_expiration
810
+	 *
811
+	 * @return void
812
+	 */
813
+	protected function _set_init_access_and_expiration()
814
+	{
815
+		$this->_time       = time();
816
+		$this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
817
+		// set initial site access time
818
+		$this->_session_data['init_access'] = $this->_time;
819
+		// and the session expiration
820
+		$this->_session_data['expiration'] = $this->_expiration;
821
+	}
822
+
823
+
824
+	/**
825
+	 * @update session data  prior to saving to the db
826
+	 * @param bool $new_session
827
+	 * @return bool TRUE on success, FALSE on fail
828
+	 * @throws EE_Error
829
+	 * @throws InvalidArgumentException
830
+	 * @throws InvalidDataTypeException
831
+	 * @throws InvalidInterfaceException
832
+	 * @throws ReflectionException
833
+	 */
834
+	public function update(bool $new_session = false): bool
835
+	{
836
+		$this->_session_data = is_array($this->_session_data) && isset($this->_session_data['id'])
837
+			? $this->_session_data
838
+			: [];
839
+		if (empty($this->_session_data)) {
840
+			$this->_set_defaults();
841
+		}
842
+		$session_data = [];
843
+		foreach ($this->_session_data as $key => $value) {
844
+			switch ($key) {
845
+				case 'id':
846
+					// session ID
847
+					$session_data['id'] = $this->_sid;
848
+					break;
849
+				case 'ip_address':
850
+					// visitor ip address
851
+					$session_data['ip_address'] = $this->request->ipAddress();
852
+					break;
853
+				case 'user_agent':
854
+					// visitor user_agent
855
+					$session_data['user_agent'] = $this->_user_agent;
856
+					break;
857
+				case 'init_access':
858
+					$session_data['init_access'] = absint($value);
859
+					break;
860
+				case 'last_access':
861
+					// current access time
862
+					$session_data['last_access'] = $this->_time;
863
+					break;
864
+				case 'expiration':
865
+					// when the session expires
866
+					$session_data['expiration'] = ! empty($this->_expiration)
867
+						? $this->_expiration
868
+						: $session_data['init_access'] + $this->session_lifespan->inSeconds();
869
+					break;
870
+				case 'user_id':
871
+					// current user if logged in
872
+					$session_data['user_id'] = $this->_wp_user_id();
873
+					break;
874
+				case 'pages_visited':
875
+					$page_visit = $this->_get_page_visit();
876
+					if ($page_visit) {
877
+						// set pages visited where the first will be the http referrer
878
+						$this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
879
+						// we'll only save the last 10 page visits.
880
+						$session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
881
+					}
882
+					break;
883
+				default:
884
+					// carry any other data over
885
+					$session_data[ $key ] = $this->_session_data[ $key ];
886
+			}
887
+		}
888
+		$this->_session_data = $session_data;
889
+		// creating a new session does not require saving to the db just yet
890
+		if (! $new_session) {
891
+			// ready? let's save
892
+			if ($this->_save_session_to_db()) {
893
+				return true;
894
+			}
895
+			return false;
896
+		}
897
+		// meh, why not?
898
+		return true;
899
+	}
900
+
901
+
902
+	/**
903
+	 * @create session data array
904
+	 * @throws EE_Error
905
+	 * @throws InvalidArgumentException
906
+	 * @throws InvalidDataTypeException
907
+	 * @throws InvalidInterfaceException
908
+	 * @throws ReflectionException
909
+	 */
910
+	private function _create_espresso_session()
911
+	{
912
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
913
+		// use the update function for now with $new_session arg set to TRUE
914
+		$this->update(true);
915
+	}
916
+
917
+
918
+	/**
919
+	 * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good
920
+	 * too). This is used when determining if we want to save the session or not.
921
+	 *
922
+	 * @return bool
923
+	 * @since 4.9.67.p
924
+	 */
925
+	private function sessionHasStuffWorthSaving(): bool
926
+	{
927
+		return $this->save_state === EE_Session::SAVE_STATE_DIRTY
928
+			   // we may want to eventually remove the following
929
+			   // on the assumption that the above check is enough
930
+			   || $this->cart() instanceof EE_Cart
931
+			   || (
932
+				   isset($this->_session_data['ee_notices'])
933
+				   && (
934
+					   ! empty($this->_session_data['ee_notices']['attention'])
935
+					   || ! empty($this->_session_data['ee_notices']['errors'])
936
+					   || ! empty($this->_session_data['ee_notices']['success'])
937
+				   )
938
+			   );
939
+	}
940
+
941
+
942
+	/**
943
+	 * _save_session_to_db
944
+	 *
945
+	 * @param bool $clear_session
946
+	 * @return bool
947
+	 * @throws EE_Error
948
+	 * @throws InvalidArgumentException
949
+	 * @throws InvalidDataTypeException
950
+	 * @throws InvalidInterfaceException
951
+	 * @throws ReflectionException
952
+	 */
953
+	private function _save_session_to_db(bool $clear_session = false): bool
954
+	{
955
+		// don't save sessions for crawlers
956
+		// and unless we're deleting the session data, don't save anything if there isn't a cart
957
+		if (
958
+			$this->request->isBot()
959
+			|| (
960
+				! $clear_session
961
+				&& ! $this->sessionHasStuffWorthSaving()
962
+				&& apply_filters('FHEE__EE_Session___save_session_to_db__abort_session_save', true)
963
+			)
964
+		) {
965
+			return false;
966
+		}
967
+		$transaction = $this->transaction();
968
+		if ($transaction instanceof EE_Transaction) {
969
+			if (! $transaction->ID()) {
970
+				$transaction->save();
971
+			}
972
+			$this->_session_data['transaction'] = $transaction->ID();
973
+		}
974
+		// then serialize all of our session data
975
+		$session_data = serialize($this->_session_data);
976
+		// do we need to also encode it to avoid corrupted data when saved to the db?
977
+		$session_data = $this->_use_encryption
978
+			? $this->encryption->decodeString($session_data)
979
+			: $session_data;
980
+		// maybe save hash check
981
+		if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
982
+			$this->cache_storage->add(
983
+				EE_Session::hash_check_prefix . $this->_sid,
984
+				md5($session_data),
985
+				$this->session_lifespan->inSeconds()
986
+			);
987
+		}
988
+		// we're using the Transient API for storing session data,
989
+		$saved = $this->cache_storage->add(
990
+			EE_Session::session_id_prefix . $this->_sid,
991
+			$session_data,
992
+			$this->session_lifespan->inSeconds()
993
+		);
994
+		$this->setSaveState(EE_Session::SAVE_STATE_CLEAN);
995
+		return $saved;
996
+	}
997
+
998
+
999
+	/**
1000
+	 * @get    the full page request the visitor is accessing
1001
+	 * @return string
1002
+	 */
1003
+	public function _get_page_visit(): string
1004
+	{
1005
+		$page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1006
+		// check for request url
1007
+		if ($this->request->serverParamIsSet('REQUEST_URI')) {
1008
+			$page_id     = '?';
1009
+			$e_reg       = '';
1010
+			$request_uri = $this->request->getServerParam('REQUEST_URI');
1011
+			$ru_bits     = explode('?', $request_uri);
1012
+			$request_uri = $ru_bits[0];
1013
+			$http_host   = $this->request->getServerParam('HTTP_HOST');
1014
+			// check for page_id in SERVER REQUEST
1015
+			if ($this->request->requestParamIsSet('page_id')) {
1016
+				// rebuild $e_reg without any of the extra parameters
1017
+				$page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1018
+			}
1019
+			// check for $e_reg in SERVER REQUEST
1020
+			if ($this->request->requestParamIsSet('ee')) {
1021
+				// rebuild $e_reg without any of the extra parameters
1022
+				$e_reg = 'ee=' . $this->request->getRequestParam('ee');
1023
+			}
1024
+			$page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1025
+		}
1026
+		return $page_visit !== home_url('/wp-admin/admin-ajax.php')
1027
+			? $page_visit
1028
+			: '';
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * @the    current wp user id
1034
+	 * @return int
1035
+	 */
1036
+	public function _wp_user_id(): int
1037
+	{
1038
+		// if I need to explain the following lines of code, then you shouldn't be looking at this!
1039
+		return get_current_user_id();
1040
+	}
1041
+
1042
+
1043
+	/**
1044
+	 * Clear EE_Session data
1045
+	 *
1046
+	 * @param string $class
1047
+	 * @param string $function
1048
+	 * @return void
1049
+	 * @throws EE_Error
1050
+	 * @throws InvalidArgumentException
1051
+	 * @throws InvalidDataTypeException
1052
+	 * @throws InvalidInterfaceException
1053
+	 * @throws ReflectionException
1054
+	 */
1055
+	public function clear_session(string $class = '', string $function = '')
1056
+	{
1057 1057
 //         echo '
1058 1058
 // <h3 style="color:#999;line-height:.9em;">
1059 1059
 // <span style="color:#2EA2CC">' . __CLASS__ . '</span>::<span style="color:#E76700">' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )</span><br/>
1060 1060
 // <span style="font-size:9px;font-weight:normal;">' . __FILE__ . '</span>    <b style="font-size:10px;">  ' . __LINE__ . ' </b>
1061 1061
 // </h3>';
1062
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1063
-        $this->reset_cart();
1064
-        $this->reset_checkout();
1065
-        $this->reset_transaction();
1066
-        // wipe out everything that isn't a default session datum
1067
-        $this->reset_data(array_keys($this->_session_data));
1068
-        // reset initial site access time and the session expiration
1069
-        $this->_set_init_access_and_expiration();
1070
-        $this->setSaveState();
1071
-        $this->_save_session_to_db(true);
1072
-    }
1073
-
1074
-
1075
-    /**
1076
-     * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1077
-     *
1078
-     * @param array|mixed $data_to_reset
1079
-     * @param bool        $show_all_notices
1080
-     * @return bool
1081
-     */
1082
-    public function reset_data($data_to_reset = [], bool $show_all_notices = false): bool
1083
-    {
1084
-        // if $data_to_reset is not in an array, then put it in one
1085
-        if (! is_array($data_to_reset)) {
1086
-            $data_to_reset = [$data_to_reset];
1087
-        }
1088
-        // nothing ??? go home!
1089
-        if (empty($data_to_reset)) {
1090
-            EE_Error::add_error(
1091
-                esc_html__(
1092
-                    'No session data could be reset, because no session var name was provided.',
1093
-                    'event_espresso'
1094
-                ),
1095
-                __FILE__,
1096
-                __FUNCTION__,
1097
-                __LINE__
1098
-            );
1099
-            return false;
1100
-        }
1101
-        $return_value = true;
1102
-        // since $data_to_reset is an array, cycle through the values
1103
-        foreach ($data_to_reset as $reset) {
1104
-            // first check to make sure it is a valid session var
1105
-            if (isset($this->_session_data[ $reset ])) {
1106
-                // then check to make sure it is not a default var
1107
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1108
-                    // remove session var
1109
-                    unset($this->_session_data[ $reset ]);
1110
-                    $this->setSaveState();
1111
-                    if ($show_all_notices) {
1112
-                        EE_Error::add_success(
1113
-                            sprintf(
1114
-                                esc_html__('The session variable %s was removed.', 'event_espresso'),
1115
-                                $reset
1116
-                            ),
1117
-                            __FILE__,
1118
-                            __FUNCTION__,
1119
-                            __LINE__
1120
-                        );
1121
-                    }
1122
-                } else {
1123
-                    // yeeeeeeeeerrrrrrrrrrr OUT !!!!
1124
-                    if ($show_all_notices) {
1125
-                        EE_Error::add_error(
1126
-                            sprintf(
1127
-                                esc_html__(
1128
-                                    'Sorry! %s is a default session datum and can not be reset.',
1129
-                                    'event_espresso'
1130
-                                ),
1131
-                                $reset
1132
-                            ),
1133
-                            __FILE__,
1134
-                            __FUNCTION__,
1135
-                            __LINE__
1136
-                        );
1137
-                    }
1138
-                    $return_value = false;
1139
-                }
1140
-            } elseif ($show_all_notices) {
1141
-                // oops! that session var does not exist!
1142
-                EE_Error::add_error(
1143
-                    sprintf(
1144
-                        esc_html__(
1145
-                            'The session item provided, %s, is invalid or does not exist.',
1146
-                            'event_espresso'
1147
-                        ),
1148
-                        $reset
1149
-                    ),
1150
-                    __FILE__,
1151
-                    __FUNCTION__,
1152
-                    __LINE__
1153
-                );
1154
-                $return_value = false;
1155
-            }
1156
-        } // end of foreach
1157
-        return $return_value;
1158
-    }
1159
-
1160
-
1161
-    /**
1162
-     *   wp_loaded
1163
-     *
1164
-     * @throws EE_Error
1165
-     * @throws InvalidDataTypeException
1166
-     * @throws InvalidInterfaceException
1167
-     * @throws InvalidArgumentException
1168
-     * @throws ReflectionException
1169
-     */
1170
-    public function wp_loaded()
1171
-    {
1172
-        if ($this->request->requestParamIsSet('clear_session')) {
1173
-            $this->clear_session(__CLASS__, __FUNCTION__);
1174
-        }
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * Used to reset the entire object (for tests).
1180
-     *
1181
-     * @throws EE_Error
1182
-     * @throws InvalidDataTypeException
1183
-     * @throws InvalidInterfaceException
1184
-     * @throws InvalidArgumentException
1185
-     * @throws ReflectionException
1186
-     * @since 4.3.0
1187
-     */
1188
-    public function reset_instance()
1189
-    {
1190
-        $this->clear_session();
1191
-        self::$_instance = null;
1192
-    }
1193
-
1194
-
1195
-    public function configure_garbage_collection_filters()
1196
-    {
1197
-        // run old filter we had for controlling session cleanup
1198
-        $expired_session_transient_delete_query_limit = absint(
1199
-            apply_filters(
1200
-                'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1201
-                50
1202
-            )
1203
-        );
1204
-        // is there a value? or one that is different than the default 50 records?
1205
-        if ($expired_session_transient_delete_query_limit === 0) {
1206
-            // hook into TransientCacheStorage in case Session cleanup was turned off
1207
-            add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1208
-        } elseif ($expired_session_transient_delete_query_limit !== 50) {
1209
-            // or use that for the new transient cleanup query limit
1210
-            add_filter(
1211
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1212
-                function () use ($expired_session_transient_delete_query_limit) {
1213
-                    return $expired_session_transient_delete_query_limit;
1214
-                }
1215
-            );
1216
-        }
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1222
-     * @param string $data1
1223
-     * @return string
1224
-     */
1225
-    private function find_serialize_error(string $data1): string
1226
-    {
1227
-        $error = '<pre>';
1228
-        $data2 = preg_replace_callback(
1229
-            '!s:(\d+):"(.*?)";!',
1230
-            function ($match) {
1231
-                return ($match[1] === strlen($match[2]))
1232
-                    ? $match[0]
1233
-                    : 's:'
1234
-                      . strlen($match[2])
1235
-                      . ':"'
1236
-                      . $match[2]
1237
-                      . '";';
1238
-            },
1239
-            $data1
1240
-        );
1241
-        $max   = (strlen($data1) > strlen($data2))
1242
-            ? strlen($data1)
1243
-            : strlen($data2);
1244
-        $error .= $data1 . PHP_EOL;
1245
-        $error .= $data2 . PHP_EOL;
1246
-        for ($i = 0; $i < $max; $i++) {
1247
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1248
-                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1249
-                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1250
-                $error  .= "\t-> Line Number = $i" . PHP_EOL;
1251
-                $start  = ($i - 20);
1252
-                $start  = ($start < 0)
1253
-                    ? 0
1254
-                    : $start;
1255
-                $length = 40;
1256
-                $point  = $max - $i;
1257
-                if ($point < 20) {
1258
-                    $rlength = 1;
1259
-                    $rpoint  = -$point;
1260
-                } else {
1261
-                    $rpoint  = $length - 20;
1262
-                    $rlength = 1;
1263
-                }
1264
-                $error .= "\t-> Section Data1  = ";
1265
-                $error .= substr_replace(
1266
-                    substr($data1, $start, $length),
1267
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1268
-                    $rpoint,
1269
-                    $rlength
1270
-                );
1271
-                $error .= PHP_EOL;
1272
-                $error .= "\t-> Section Data2  = ";
1273
-                $error .= substr_replace(
1274
-                    substr($data2, $start, $length),
1275
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1276
-                    $rpoint,
1277
-                    $rlength
1278
-                );
1279
-                $error .= PHP_EOL;
1280
-            }
1281
-        }
1282
-        $error .= '</pre>';
1283
-        return $error;
1284
-    }
1285
-
1286
-
1287
-    /**
1288
-     * Saves an  array of settings used for configuring aspects of session behaviour
1289
-     *
1290
-     * @param array $updated_settings
1291
-     */
1292
-    private function updateSessionSettings(array $updated_settings = [])
1293
-    {
1294
-        // add existing settings, but only if not included in incoming $updated_settings array
1295
-        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, []);
1296
-        update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1297
-    }
1298
-
1299
-
1300
-    /**
1301
-     * garbage_collection
1302
-     */
1303
-    public function garbageCollection()
1304
-    {
1305
-        // only perform during regular requests if last garbage collection was over an hour ago
1306
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1307
-            $this->_last_gc = time();
1308
-            $this->updateSessionSettings(['last_gc' => $this->_last_gc]);
1309
-            /** @type WPDB $wpdb */
1310
-            global $wpdb;
1311
-            // filter the query limit. Set to 0 to turn off garbage collection
1312
-            $expired_session_transient_delete_query_limit = absint(
1313
-                apply_filters(
1314
-                    'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1315
-                    50
1316
-                )
1317
-            );
1318
-            // non-zero LIMIT means take out the trash
1319
-            if ($expired_session_transient_delete_query_limit) {
1320
-                $session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
1321
-                $hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1322
-                // since transient expiration timestamps are set in the future, we can compare against NOW,
1323
-                // but we only want to pick up any trash that's been around for more than a day
1324
-                $expiration = time() - DAY_IN_SECONDS;
1325
-                $SQL        = "
1062
+		do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1063
+		$this->reset_cart();
1064
+		$this->reset_checkout();
1065
+		$this->reset_transaction();
1066
+		// wipe out everything that isn't a default session datum
1067
+		$this->reset_data(array_keys($this->_session_data));
1068
+		// reset initial site access time and the session expiration
1069
+		$this->_set_init_access_and_expiration();
1070
+		$this->setSaveState();
1071
+		$this->_save_session_to_db(true);
1072
+	}
1073
+
1074
+
1075
+	/**
1076
+	 * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1077
+	 *
1078
+	 * @param array|mixed $data_to_reset
1079
+	 * @param bool        $show_all_notices
1080
+	 * @return bool
1081
+	 */
1082
+	public function reset_data($data_to_reset = [], bool $show_all_notices = false): bool
1083
+	{
1084
+		// if $data_to_reset is not in an array, then put it in one
1085
+		if (! is_array($data_to_reset)) {
1086
+			$data_to_reset = [$data_to_reset];
1087
+		}
1088
+		// nothing ??? go home!
1089
+		if (empty($data_to_reset)) {
1090
+			EE_Error::add_error(
1091
+				esc_html__(
1092
+					'No session data could be reset, because no session var name was provided.',
1093
+					'event_espresso'
1094
+				),
1095
+				__FILE__,
1096
+				__FUNCTION__,
1097
+				__LINE__
1098
+			);
1099
+			return false;
1100
+		}
1101
+		$return_value = true;
1102
+		// since $data_to_reset is an array, cycle through the values
1103
+		foreach ($data_to_reset as $reset) {
1104
+			// first check to make sure it is a valid session var
1105
+			if (isset($this->_session_data[ $reset ])) {
1106
+				// then check to make sure it is not a default var
1107
+				if (! array_key_exists($reset, $this->_default_session_vars)) {
1108
+					// remove session var
1109
+					unset($this->_session_data[ $reset ]);
1110
+					$this->setSaveState();
1111
+					if ($show_all_notices) {
1112
+						EE_Error::add_success(
1113
+							sprintf(
1114
+								esc_html__('The session variable %s was removed.', 'event_espresso'),
1115
+								$reset
1116
+							),
1117
+							__FILE__,
1118
+							__FUNCTION__,
1119
+							__LINE__
1120
+						);
1121
+					}
1122
+				} else {
1123
+					// yeeeeeeeeerrrrrrrrrrr OUT !!!!
1124
+					if ($show_all_notices) {
1125
+						EE_Error::add_error(
1126
+							sprintf(
1127
+								esc_html__(
1128
+									'Sorry! %s is a default session datum and can not be reset.',
1129
+									'event_espresso'
1130
+								),
1131
+								$reset
1132
+							),
1133
+							__FILE__,
1134
+							__FUNCTION__,
1135
+							__LINE__
1136
+						);
1137
+					}
1138
+					$return_value = false;
1139
+				}
1140
+			} elseif ($show_all_notices) {
1141
+				// oops! that session var does not exist!
1142
+				EE_Error::add_error(
1143
+					sprintf(
1144
+						esc_html__(
1145
+							'The session item provided, %s, is invalid or does not exist.',
1146
+							'event_espresso'
1147
+						),
1148
+						$reset
1149
+					),
1150
+					__FILE__,
1151
+					__FUNCTION__,
1152
+					__LINE__
1153
+				);
1154
+				$return_value = false;
1155
+			}
1156
+		} // end of foreach
1157
+		return $return_value;
1158
+	}
1159
+
1160
+
1161
+	/**
1162
+	 *   wp_loaded
1163
+	 *
1164
+	 * @throws EE_Error
1165
+	 * @throws InvalidDataTypeException
1166
+	 * @throws InvalidInterfaceException
1167
+	 * @throws InvalidArgumentException
1168
+	 * @throws ReflectionException
1169
+	 */
1170
+	public function wp_loaded()
1171
+	{
1172
+		if ($this->request->requestParamIsSet('clear_session')) {
1173
+			$this->clear_session(__CLASS__, __FUNCTION__);
1174
+		}
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * Used to reset the entire object (for tests).
1180
+	 *
1181
+	 * @throws EE_Error
1182
+	 * @throws InvalidDataTypeException
1183
+	 * @throws InvalidInterfaceException
1184
+	 * @throws InvalidArgumentException
1185
+	 * @throws ReflectionException
1186
+	 * @since 4.3.0
1187
+	 */
1188
+	public function reset_instance()
1189
+	{
1190
+		$this->clear_session();
1191
+		self::$_instance = null;
1192
+	}
1193
+
1194
+
1195
+	public function configure_garbage_collection_filters()
1196
+	{
1197
+		// run old filter we had for controlling session cleanup
1198
+		$expired_session_transient_delete_query_limit = absint(
1199
+			apply_filters(
1200
+				'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1201
+				50
1202
+			)
1203
+		);
1204
+		// is there a value? or one that is different than the default 50 records?
1205
+		if ($expired_session_transient_delete_query_limit === 0) {
1206
+			// hook into TransientCacheStorage in case Session cleanup was turned off
1207
+			add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1208
+		} elseif ($expired_session_transient_delete_query_limit !== 50) {
1209
+			// or use that for the new transient cleanup query limit
1210
+			add_filter(
1211
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1212
+				function () use ($expired_session_transient_delete_query_limit) {
1213
+					return $expired_session_transient_delete_query_limit;
1214
+				}
1215
+			);
1216
+		}
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1222
+	 * @param string $data1
1223
+	 * @return string
1224
+	 */
1225
+	private function find_serialize_error(string $data1): string
1226
+	{
1227
+		$error = '<pre>';
1228
+		$data2 = preg_replace_callback(
1229
+			'!s:(\d+):"(.*?)";!',
1230
+			function ($match) {
1231
+				return ($match[1] === strlen($match[2]))
1232
+					? $match[0]
1233
+					: 's:'
1234
+					  . strlen($match[2])
1235
+					  . ':"'
1236
+					  . $match[2]
1237
+					  . '";';
1238
+			},
1239
+			$data1
1240
+		);
1241
+		$max   = (strlen($data1) > strlen($data2))
1242
+			? strlen($data1)
1243
+			: strlen($data2);
1244
+		$error .= $data1 . PHP_EOL;
1245
+		$error .= $data2 . PHP_EOL;
1246
+		for ($i = 0; $i < $max; $i++) {
1247
+			if (@$data1[ $i ] !== @$data2[ $i ]) {
1248
+				$error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1249
+				$error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1250
+				$error  .= "\t-> Line Number = $i" . PHP_EOL;
1251
+				$start  = ($i - 20);
1252
+				$start  = ($start < 0)
1253
+					? 0
1254
+					: $start;
1255
+				$length = 40;
1256
+				$point  = $max - $i;
1257
+				if ($point < 20) {
1258
+					$rlength = 1;
1259
+					$rpoint  = -$point;
1260
+				} else {
1261
+					$rpoint  = $length - 20;
1262
+					$rlength = 1;
1263
+				}
1264
+				$error .= "\t-> Section Data1  = ";
1265
+				$error .= substr_replace(
1266
+					substr($data1, $start, $length),
1267
+					"<b style=\"color:green\">{$data1[ $i ]}</b>",
1268
+					$rpoint,
1269
+					$rlength
1270
+				);
1271
+				$error .= PHP_EOL;
1272
+				$error .= "\t-> Section Data2  = ";
1273
+				$error .= substr_replace(
1274
+					substr($data2, $start, $length),
1275
+					"<b style=\"color:red\">{$data2[ $i ]}</b>",
1276
+					$rpoint,
1277
+					$rlength
1278
+				);
1279
+				$error .= PHP_EOL;
1280
+			}
1281
+		}
1282
+		$error .= '</pre>';
1283
+		return $error;
1284
+	}
1285
+
1286
+
1287
+	/**
1288
+	 * Saves an  array of settings used for configuring aspects of session behaviour
1289
+	 *
1290
+	 * @param array $updated_settings
1291
+	 */
1292
+	private function updateSessionSettings(array $updated_settings = [])
1293
+	{
1294
+		// add existing settings, but only if not included in incoming $updated_settings array
1295
+		$updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, []);
1296
+		update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1297
+	}
1298
+
1299
+
1300
+	/**
1301
+	 * garbage_collection
1302
+	 */
1303
+	public function garbageCollection()
1304
+	{
1305
+		// only perform during regular requests if last garbage collection was over an hour ago
1306
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1307
+			$this->_last_gc = time();
1308
+			$this->updateSessionSettings(['last_gc' => $this->_last_gc]);
1309
+			/** @type WPDB $wpdb */
1310
+			global $wpdb;
1311
+			// filter the query limit. Set to 0 to turn off garbage collection
1312
+			$expired_session_transient_delete_query_limit = absint(
1313
+				apply_filters(
1314
+					'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1315
+					50
1316
+				)
1317
+			);
1318
+			// non-zero LIMIT means take out the trash
1319
+			if ($expired_session_transient_delete_query_limit) {
1320
+				$session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
1321
+				$hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1322
+				// since transient expiration timestamps are set in the future, we can compare against NOW,
1323
+				// but we only want to pick up any trash that's been around for more than a day
1324
+				$expiration = time() - DAY_IN_SECONDS;
1325
+				$SQL        = "
1326 1326
                     SELECT option_name
1327 1327
                     FROM $wpdb->options
1328 1328
                     WHERE
@@ -1331,17 +1331,17 @@  discard block
 block discarded – undo
1331 1331
                     AND option_value < $expiration
1332 1332
                     LIMIT $expired_session_transient_delete_query_limit
1333 1333
                 ";
1334
-                // produces something like:
1335
-                // SELECT option_name FROM wp_options
1336
-                // WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1337
-                // OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1338
-                // AND option_value < 1508368198 LIMIT 50
1339
-                $expired_sessions = $wpdb->get_col($SQL);
1340
-                // valid results?
1341
-                if (! empty($expired_sessions)) {
1342
-                    $this->cache_storage->deleteMany($expired_sessions, true);
1343
-                }
1344
-            }
1345
-        }
1346
-    }
1334
+				// produces something like:
1335
+				// SELECT option_name FROM wp_options
1336
+				// WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1337
+				// OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1338
+				// AND option_value < 1508368198 LIMIT 50
1339
+				$expired_sessions = $wpdb->get_col($SQL);
1340
+				// valid results?
1341
+				if (! empty($expired_sessions)) {
1342
+					$this->cache_storage->deleteMany($expired_sessions, true);
1343
+				}
1344
+			}
1345
+		}
1346
+	}
1347 1347
 }
Please login to merge, or discard this patch.
Spacing   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -233,22 +233,22 @@  discard block
 block discarded – undo
233 233
         // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
234 234
         // (which currently fires on the init hook at priority 9),
235 235
         // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
236
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
236
+        if ( ! apply_filters('FHEE_load_EE_Session', true)) {
237 237
             return;
238 238
         }
239 239
         $this->session_start_handler = $session_start_handler;
240 240
         $this->session_lifespan      = $lifespan;
241 241
         $this->request               = $request;
242
-        if (! defined('ESPRESSO_SESSION')) {
242
+        if ( ! defined('ESPRESSO_SESSION')) {
243 243
             define('ESPRESSO_SESSION', true);
244 244
         }
245 245
         // retrieve session options from db
246 246
         $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, []);
247
-        if (! empty($session_settings)) {
247
+        if ( ! empty($session_settings)) {
248 248
             // cycle though existing session options
249 249
             foreach ($session_settings as $var_name => $session_setting) {
250 250
                 // set values for class properties
251
-                $var_name          = '_' . $var_name;
251
+                $var_name          = '_'.$var_name;
252 252
                 $this->{$var_name} = $session_setting;
253 253
             }
254 254
         }
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
      */
358 358
     public function extend_expiration(int $time = 0)
359 359
     {
360
-        $time              = $time
360
+        $time = $time
361 361
             ?: $this->extension();
362 362
         $this->_expiration += absint($time);
363 363
     }
@@ -387,7 +387,7 @@  discard block
 block discarded – undo
387 387
             EE_Session::SAVE_STATE_CLEAN,
388 388
             EE_Session::SAVE_STATE_DIRTY,
389 389
         ];
390
-        if (! in_array($save_state, $valid_save_states, true)) {
390
+        if ( ! in_array($save_state, $valid_save_states, true)) {
391 391
             $save_state = EE_Session::SAVE_STATE_DIRTY;
392 392
         }
393 393
         $this->save_state = $save_state;
@@ -404,9 +404,9 @@  discard block
 block discarded – undo
404 404
         // set some defaults
405 405
         foreach ($this->_default_session_vars as $key => $default_var) {
406 406
             if (is_array($default_var)) {
407
-                $this->_session_data[ $key ] = [];
407
+                $this->_session_data[$key] = [];
408 408
             } else {
409
-                $this->_session_data[ $key ] = '';
409
+                $this->_session_data[$key] = '';
410 410
             }
411 411
         }
412 412
     }
@@ -543,8 +543,8 @@  discard block
 block discarded – undo
543 543
             $this->reset_checkout();
544 544
             $this->reset_transaction();
545 545
         }
546
-        if (! empty($key)) {
547
-            return $this->_session_data[ $key ] ?? null;
546
+        if ( ! empty($key)) {
547
+            return $this->_session_data[$key] ?? null;
548 548
         }
549 549
         return $this->_session_data;
550 550
     }
@@ -572,7 +572,7 @@  discard block
 block discarded – undo
572 572
             return false;
573 573
         }
574 574
         foreach ($data as $key => $value) {
575
-            if (isset($this->_default_session_vars[ $key ])) {
575
+            if (isset($this->_default_session_vars[$key])) {
576 576
                 EE_Error::add_error(
577 577
                     sprintf(
578 578
                         esc_html__(
@@ -587,7 +587,7 @@  discard block
 block discarded – undo
587 587
                 );
588 588
                 return false;
589 589
             }
590
-            $this->_session_data[ $key ] = $value;
590
+            $this->_session_data[$key] = $value;
591 591
             $this->setSaveState();
592 592
         }
593 593
         return true;
@@ -620,7 +620,7 @@  discard block
 block discarded – undo
620 620
             // set initial site access time and the session expiration
621 621
             $this->_set_init_access_and_expiration();
622 622
             // set referer
623
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
623
+            $this->_session_data['pages_visited'][$this->_session_data['init_access']] = esc_attr(
624 624
                 $this->request->getServerParam('HTTP_REFERER')
625 625
             );
626 626
             // no previous session = go back and create one (on top of the data above)
@@ -665,7 +665,7 @@  discard block
 block discarded – undo
665 665
      */
666 666
     protected function _retrieve_session_data(): array
667 667
     {
668
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
668
+        $ssn_key = EE_Session::session_id_prefix.$this->_sid;
669 669
         try {
670 670
             // we're using WP's Transient API to store session data using the PHP session ID as the option name
671 671
             $session_data = $this->cache_storage->get($ssn_key, false);
@@ -674,7 +674,7 @@  discard block
 block discarded – undo
674 674
             }
675 675
             if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
676 676
                 $hash_check = $this->cache_storage->get(
677
-                    EE_Session::hash_check_prefix . $this->_sid,
677
+                    EE_Session::hash_check_prefix.$this->_sid,
678 678
                     false
679 679
                 );
680 680
                 if ($hash_check && $hash_check !== md5($session_data)) {
@@ -684,7 +684,7 @@  discard block
 block discarded – undo
684 684
                                 'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
685 685
                                 'event_espresso'
686 686
                             ),
687
-                            EE_Session::session_id_prefix . $this->_sid
687
+                            EE_Session::session_id_prefix.$this->_sid
688 688
                         ),
689 689
                         __FILE__,
690 690
                         __FUNCTION__,
@@ -695,10 +695,10 @@  discard block
 block discarded – undo
695 695
         } catch (Exception $e) {
696 696
             // let's just eat that error for now and attempt to correct any corrupted data
697 697
             global $wpdb;
698
-            $row          = $wpdb->get_row(
698
+            $row = $wpdb->get_row(
699 699
                 $wpdb->prepare(
700 700
                     "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1",
701
-                    '_transient_' . $ssn_key
701
+                    '_transient_'.$ssn_key
702 702
                 )
703 703
             );
704 704
             $session_data = is_object($row)
@@ -707,10 +707,10 @@  discard block
 block discarded – undo
707 707
             if ($session_data) {
708 708
                 $session_data = preg_replace_callback(
709 709
                     '!s:(d+):"(.*?)";!',
710
-                    function ($match) {
710
+                    function($match) {
711 711
                         return $match[1] === strlen($match[2])
712 712
                             ? $match[0]
713
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
713
+                            : 's:'.strlen($match[2]).':"'.$match[2].'";';
714 714
                     },
715 715
                     $session_data
716 716
                 );
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
         $session_data = $this->_use_encryption
722 722
             ? $this->encryption->encodeString($session_data)
723 723
             : $session_data;
724
-        if (! is_array($session_data)) {
724
+        if ( ! is_array($session_data)) {
725 725
             try {
726 726
                 $session_data = maybe_unserialize($session_data);
727 727
             } catch (Exception $e) {
@@ -735,21 +735,21 @@  discard block
 block discarded – undo
735 735
                       . '</pre><br>'
736 736
                       . $this->find_serialize_error($session_data)
737 737
                     : '';
738
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
738
+                $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
739 739
                 throw new InvalidSessionDataException($msg, 0, $e);
740 740
             }
741 741
         }
742 742
         // just a check to make sure the session array is indeed an array
743
-        if (! is_array($session_data)) {
743
+        if ( ! is_array($session_data)) {
744 744
             // no?!?! then something is wrong
745 745
             $msg = esc_html__(
746 746
                 'The session data is missing, invalid, or corrupted.',
747 747
                 'event_espresso'
748 748
             );
749 749
             $msg .= WP_DEBUG
750
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
750
+                ? '<br><pre>'.print_r($session_data, true).'</pre><br>'.$this->find_serialize_error($session_data)
751 751
                 : '';
752
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
752
+            $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
753 753
             throw new InvalidSessionDataException($msg);
754 754
         }
755 755
         if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
@@ -775,7 +775,7 @@  discard block
 block discarded – undo
775 775
         // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
776 776
         $session_id = $this->request->requestParamIsSet('EESID')
777 777
             ? $this->request->getRequestParam('EESID')
778
-            : md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
778
+            : md5(session_id().get_current_blog_id().$this->_get_sid_salt());
779 779
         return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
780 780
     }
781 781
 
@@ -875,19 +875,19 @@  discard block
 block discarded – undo
875 875
                     $page_visit = $this->_get_page_visit();
876 876
                     if ($page_visit) {
877 877
                         // set pages visited where the first will be the http referrer
878
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
878
+                        $this->_session_data['pages_visited'][$this->_time] = $page_visit;
879 879
                         // we'll only save the last 10 page visits.
880 880
                         $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
881 881
                     }
882 882
                     break;
883 883
                 default:
884 884
                     // carry any other data over
885
-                    $session_data[ $key ] = $this->_session_data[ $key ];
885
+                    $session_data[$key] = $this->_session_data[$key];
886 886
             }
887 887
         }
888 888
         $this->_session_data = $session_data;
889 889
         // creating a new session does not require saving to the db just yet
890
-        if (! $new_session) {
890
+        if ( ! $new_session) {
891 891
             // ready? let's save
892 892
             if ($this->_save_session_to_db()) {
893 893
                 return true;
@@ -966,7 +966,7 @@  discard block
 block discarded – undo
966 966
         }
967 967
         $transaction = $this->transaction();
968 968
         if ($transaction instanceof EE_Transaction) {
969
-            if (! $transaction->ID()) {
969
+            if ( ! $transaction->ID()) {
970 970
                 $transaction->save();
971 971
             }
972 972
             $this->_session_data['transaction'] = $transaction->ID();
@@ -980,14 +980,14 @@  discard block
 block discarded – undo
980 980
         // maybe save hash check
981 981
         if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
982 982
             $this->cache_storage->add(
983
-                EE_Session::hash_check_prefix . $this->_sid,
983
+                EE_Session::hash_check_prefix.$this->_sid,
984 984
                 md5($session_data),
985 985
                 $this->session_lifespan->inSeconds()
986 986
             );
987 987
         }
988 988
         // we're using the Transient API for storing session data,
989 989
         $saved = $this->cache_storage->add(
990
-            EE_Session::session_id_prefix . $this->_sid,
990
+            EE_Session::session_id_prefix.$this->_sid,
991 991
             $session_data,
992 992
             $this->session_lifespan->inSeconds()
993 993
         );
@@ -1002,7 +1002,7 @@  discard block
 block discarded – undo
1002 1002
      */
1003 1003
     public function _get_page_visit(): string
1004 1004
     {
1005
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1005
+        $page_visit = home_url('/').'wp-admin/admin-ajax.php';
1006 1006
         // check for request url
1007 1007
         if ($this->request->serverParamIsSet('REQUEST_URI')) {
1008 1008
             $page_id     = '?';
@@ -1014,14 +1014,14 @@  discard block
 block discarded – undo
1014 1014
             // check for page_id in SERVER REQUEST
1015 1015
             if ($this->request->requestParamIsSet('page_id')) {
1016 1016
                 // rebuild $e_reg without any of the extra parameters
1017
-                $page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1017
+                $page_id .= 'page_id='.$this->request->getRequestParam('page_id', 0, 'int').'&amp;';
1018 1018
             }
1019 1019
             // check for $e_reg in SERVER REQUEST
1020 1020
             if ($this->request->requestParamIsSet('ee')) {
1021 1021
                 // rebuild $e_reg without any of the extra parameters
1022
-                $e_reg = 'ee=' . $this->request->getRequestParam('ee');
1022
+                $e_reg = 'ee='.$this->request->getRequestParam('ee');
1023 1023
             }
1024
-            $page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1024
+            $page_visit = esc_url(rtrim($http_host.$request_uri.$page_id.$e_reg, '?'));
1025 1025
         }
1026 1026
         return $page_visit !== home_url('/wp-admin/admin-ajax.php')
1027 1027
             ? $page_visit
@@ -1059,7 +1059,7 @@  discard block
 block discarded – undo
1059 1059
 // <span style="color:#2EA2CC">' . __CLASS__ . '</span>::<span style="color:#E76700">' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )</span><br/>
1060 1060
 // <span style="font-size:9px;font-weight:normal;">' . __FILE__ . '</span>    <b style="font-size:10px;">  ' . __LINE__ . ' </b>
1061 1061
 // </h3>';
1062
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1062
+        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : '.$class.'::'.$function.'()');
1063 1063
         $this->reset_cart();
1064 1064
         $this->reset_checkout();
1065 1065
         $this->reset_transaction();
@@ -1082,7 +1082,7 @@  discard block
 block discarded – undo
1082 1082
     public function reset_data($data_to_reset = [], bool $show_all_notices = false): bool
1083 1083
     {
1084 1084
         // if $data_to_reset is not in an array, then put it in one
1085
-        if (! is_array($data_to_reset)) {
1085
+        if ( ! is_array($data_to_reset)) {
1086 1086
             $data_to_reset = [$data_to_reset];
1087 1087
         }
1088 1088
         // nothing ??? go home!
@@ -1102,11 +1102,11 @@  discard block
 block discarded – undo
1102 1102
         // since $data_to_reset is an array, cycle through the values
1103 1103
         foreach ($data_to_reset as $reset) {
1104 1104
             // first check to make sure it is a valid session var
1105
-            if (isset($this->_session_data[ $reset ])) {
1105
+            if (isset($this->_session_data[$reset])) {
1106 1106
                 // then check to make sure it is not a default var
1107
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1107
+                if ( ! array_key_exists($reset, $this->_default_session_vars)) {
1108 1108
                     // remove session var
1109
-                    unset($this->_session_data[ $reset ]);
1109
+                    unset($this->_session_data[$reset]);
1110 1110
                     $this->setSaveState();
1111 1111
                     if ($show_all_notices) {
1112 1112
                         EE_Error::add_success(
@@ -1209,7 +1209,7 @@  discard block
 block discarded – undo
1209 1209
             // or use that for the new transient cleanup query limit
1210 1210
             add_filter(
1211 1211
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1212
-                function () use ($expired_session_transient_delete_query_limit) {
1212
+                function() use ($expired_session_transient_delete_query_limit) {
1213 1213
                     return $expired_session_transient_delete_query_limit;
1214 1214
                 }
1215 1215
             );
@@ -1227,7 +1227,7 @@  discard block
 block discarded – undo
1227 1227
         $error = '<pre>';
1228 1228
         $data2 = preg_replace_callback(
1229 1229
             '!s:(\d+):"(.*?)";!',
1230
-            function ($match) {
1230
+            function($match) {
1231 1231
                 return ($match[1] === strlen($match[2]))
1232 1232
                     ? $match[0]
1233 1233
                     : 's:'
@@ -1238,16 +1238,16 @@  discard block
 block discarded – undo
1238 1238
             },
1239 1239
             $data1
1240 1240
         );
1241
-        $max   = (strlen($data1) > strlen($data2))
1241
+        $max = (strlen($data1) > strlen($data2))
1242 1242
             ? strlen($data1)
1243 1243
             : strlen($data2);
1244
-        $error .= $data1 . PHP_EOL;
1245
-        $error .= $data2 . PHP_EOL;
1244
+        $error .= $data1.PHP_EOL;
1245
+        $error .= $data2.PHP_EOL;
1246 1246
         for ($i = 0; $i < $max; $i++) {
1247
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1248
-                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1249
-                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1250
-                $error  .= "\t-> Line Number = $i" . PHP_EOL;
1247
+            if (@$data1[$i] !== @$data2[$i]) {
1248
+                $error  .= 'Difference '.@$data1[$i].' != '.@$data2[$i].PHP_EOL;
1249
+                $error  .= "\t-> ORD number ".ord(@$data1[$i]).' != '.ord(@$data2[$i]).PHP_EOL;
1250
+                $error  .= "\t-> Line Number = $i".PHP_EOL;
1251 1251
                 $start  = ($i - 20);
1252 1252
                 $start  = ($start < 0)
1253 1253
                     ? 0
@@ -1264,7 +1264,7 @@  discard block
 block discarded – undo
1264 1264
                 $error .= "\t-> Section Data1  = ";
1265 1265
                 $error .= substr_replace(
1266 1266
                     substr($data1, $start, $length),
1267
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1267
+                    "<b style=\"color:green\">{$data1[$i]}</b>",
1268 1268
                     $rpoint,
1269 1269
                     $rlength
1270 1270
                 );
@@ -1272,7 +1272,7 @@  discard block
 block discarded – undo
1272 1272
                 $error .= "\t-> Section Data2  = ";
1273 1273
                 $error .= substr_replace(
1274 1274
                     substr($data2, $start, $length),
1275
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1275
+                    "<b style=\"color:red\">{$data2[$i]}</b>",
1276 1276
                     $rpoint,
1277 1277
                     $rlength
1278 1278
                 );
@@ -1303,7 +1303,7 @@  discard block
 block discarded – undo
1303 1303
     public function garbageCollection()
1304 1304
     {
1305 1305
         // only perform during regular requests if last garbage collection was over an hour ago
1306
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1306
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1307 1307
             $this->_last_gc = time();
1308 1308
             $this->updateSessionSettings(['last_gc' => $this->_last_gc]);
1309 1309
             /** @type WPDB $wpdb */
@@ -1338,7 +1338,7 @@  discard block
 block discarded – undo
1338 1338
                 // AND option_value < 1508368198 LIMIT 50
1339 1339
                 $expired_sessions = $wpdb->get_col($SQL);
1340 1340
                 // valid results?
1341
-                if (! empty($expired_sessions)) {
1341
+                if ( ! empty($expired_sessions)) {
1342 1342
                     $this->cache_storage->deleteMany($expired_sessions, true);
1343 1343
                 }
1344 1344
             }
Please login to merge, or discard this patch.
core/EE_Dependency_Map.core.php 2 patches
Indentation   +1159 added lines, -1159 removed lines patch added patch discarded remove patch
@@ -21,1163 +21,1163 @@
 block discarded – undo
21 21
  */
22 22
 class EE_Dependency_Map
23 23
 {
24
-    /**
25
-     * This means that the requested class dependency is not present in the dependency map
26
-     */
27
-    const not_registered = 0;
28
-
29
-    /**
30
-     * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
31
-     */
32
-    const load_new_object = 1;
33
-
34
-    /**
35
-     * This instructs class loaders to return a previously instantiated and cached object for the requested class.
36
-     * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
37
-     */
38
-    const load_from_cache = 2;
39
-
40
-    /**
41
-     * When registering a dependency,
42
-     * this indicates to keep any existing dependencies that already exist,
43
-     * and simply discard any new dependencies declared in the incoming data
44
-     */
45
-    const KEEP_EXISTING_DEPENDENCIES = 0;
46
-
47
-    /**
48
-     * When registering a dependency,
49
-     * this indicates to overwrite any existing dependencies that already exist using the incoming data
50
-     */
51
-    const OVERWRITE_DEPENDENCIES = 1;
52
-
53
-    /**
54
-     * @type EE_Dependency_Map $_instance
55
-     */
56
-    protected static $_instance;
57
-
58
-    /**
59
-     * @var ClassInterfaceCache $class_cache
60
-     */
61
-    private $class_cache;
62
-
63
-    /**
64
-     * @type RequestInterface $request
65
-     */
66
-    protected $request;
67
-
68
-    /**
69
-     * @type LegacyRequestInterface $legacy_request
70
-     */
71
-    protected $legacy_request;
72
-
73
-    /**
74
-     * @type ResponseInterface $response
75
-     */
76
-    protected $response;
77
-
78
-    /**
79
-     * @type LoaderInterface $loader
80
-     */
81
-    protected $loader;
82
-
83
-    /**
84
-     * @type array $_dependency_map
85
-     */
86
-    protected $_dependency_map = [];
87
-
88
-    /**
89
-     * @type array $_class_loaders
90
-     */
91
-    protected $_class_loaders = [];
92
-
93
-
94
-    /**
95
-     * EE_Dependency_Map constructor.
96
-     *
97
-     * @param ClassInterfaceCache $class_cache
98
-     */
99
-    protected function __construct(ClassInterfaceCache $class_cache)
100
-    {
101
-        $this->class_cache = $class_cache;
102
-        do_action('EE_Dependency_Map____construct', $this);
103
-    }
104
-
105
-
106
-    /**
107
-     * @return void
108
-     * @throws InvalidAliasException
109
-     */
110
-    public function initialize()
111
-    {
112
-        $this->_register_core_dependencies();
113
-        $this->_register_core_class_loaders();
114
-        $this->_register_core_aliases();
115
-    }
116
-
117
-
118
-    /**
119
-     * @singleton method used to instantiate class object
120
-     * @param ClassInterfaceCache|null $class_cache
121
-     * @return EE_Dependency_Map
122
-     */
123
-    public static function instance(ClassInterfaceCache $class_cache = null): EE_Dependency_Map
124
-    {
125
-        // check if class object is instantiated, and instantiated properly
126
-        if (
127
-            ! EE_Dependency_Map::$_instance instanceof EE_Dependency_Map
128
-            && $class_cache instanceof ClassInterfaceCache
129
-        ) {
130
-            EE_Dependency_Map::$_instance = new EE_Dependency_Map($class_cache);
131
-        }
132
-        return EE_Dependency_Map::$_instance;
133
-    }
134
-
135
-
136
-    /**
137
-     * @param RequestInterface $request
138
-     */
139
-    public function setRequest(RequestInterface $request)
140
-    {
141
-        $this->request = $request;
142
-    }
143
-
144
-
145
-    /**
146
-     * @param LegacyRequestInterface $legacy_request
147
-     */
148
-    public function setLegacyRequest(LegacyRequestInterface $legacy_request)
149
-    {
150
-        $this->legacy_request = $legacy_request;
151
-    }
152
-
153
-
154
-    /**
155
-     * @param ResponseInterface $response
156
-     */
157
-    public function setResponse(ResponseInterface $response)
158
-    {
159
-        $this->response = $response;
160
-    }
161
-
162
-
163
-    /**
164
-     * @param LoaderInterface $loader
165
-     */
166
-    public function setLoader(LoaderInterface $loader)
167
-    {
168
-        $this->loader = $loader;
169
-    }
170
-
171
-
172
-    /**
173
-     * @param string $class
174
-     * @param array  $dependencies
175
-     * @param int    $overwrite
176
-     * @return bool
177
-     */
178
-    public static function register_dependencies(
179
-        string $class,
180
-        array $dependencies,
181
-        int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
182
-    ): bool {
183
-        return EE_Dependency_Map::$_instance->registerDependencies($class, $dependencies, $overwrite);
184
-    }
185
-
186
-
187
-    /**
188
-     * Assigns an array of class names and corresponding load sources (new or cached)
189
-     * to the class specified by the first parameter.
190
-     * IMPORTANT !!!
191
-     * The order of elements in the incoming $dependencies array MUST match
192
-     * the order of the constructor parameters for the class in question.
193
-     * This is especially important when overriding any existing dependencies that are registered.
194
-     * the third parameter controls whether any duplicate dependencies are overwritten or not.
195
-     *
196
-     * @param string $class
197
-     * @param array  $dependencies
198
-     * @param int    $overwrite
199
-     * @return bool
200
-     */
201
-    public function registerDependencies(
202
-        string $class,
203
-        array $dependencies,
204
-        int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
205
-    ): bool {
206
-        if (empty($dependencies)) {
207
-            return false;
208
-        }
209
-        $class      = trim($class, '\\');
210
-        $registered = false;
211
-        if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) {
212
-            EE_Dependency_Map::$_instance->_dependency_map[ $class ] = [];
213
-        }
214
-        // we need to make sure that any aliases used when registering a dependency
215
-        // get resolved to the correct class name
216
-        foreach ($dependencies as $dependency => $load_source) {
217
-            $alias = EE_Dependency_Map::$_instance->getFqnForAlias($dependency);
218
-            if (
219
-                $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
220
-                || ! isset(
221
-                    EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $dependency ],
222
-                    EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]
223
-                )
224
-            ) {
225
-                unset($dependencies[ $dependency ]);
226
-                $dependencies[ $alias ] = $load_source;
227
-                $registered             = true;
228
-            }
229
-        }
230
-        // now add our two lists of dependencies together.
231
-        // using Union (+=) favours the arrays in precedence from left to right,
232
-        // so $dependencies is NOT overwritten because it is listed first
233
-        // ie: with A = B + C, entries in B take precedence over duplicate entries in C
234
-        // Union is way faster than array_merge() but should be used with caution...
235
-        // especially with numerically indexed arrays
236
-        $dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ];
237
-        // now we need to ensure that the resulting dependencies
238
-        // array only has the entries that are required for the class
239
-        // so first count how many dependencies were originally registered for the class
240
-        $dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]);
241
-        // if that count is non-zero (meaning dependencies were already registered)
242
-        EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count
243
-            // then truncate the  final array to match that count
244
-            ? array_slice($dependencies, 0, $dependency_count)
245
-            // otherwise just take the incoming array because nothing previously existed
246
-            : $dependencies;
247
-        return $registered
248
-               || count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]) === count($dependencies);
249
-    }
250
-
251
-
252
-    /**
253
-     * @param string          $class_name
254
-     * @param callable|string $loader
255
-     * @param bool            $overwrite
256
-     * @return bool
257
-     * @throws DomainException
258
-     */
259
-    public static function register_class_loader(
260
-        string $class_name,
261
-        $loader = 'load_core',
262
-        bool $overwrite = false
263
-    ): bool {
264
-        return EE_Dependency_Map::$_instance->registerClassLoader($class_name, $loader, $overwrite);
265
-    }
266
-
267
-
268
-    /**
269
-     * @param string         $class_name
270
-     * @param Closure|string $loader
271
-     * @param bool           $overwrite
272
-     * @return bool
273
-     * @throws DomainException
274
-     */
275
-    public function registerClassLoader(string $class_name, $loader = 'load_core', bool $overwrite = false): bool
276
-    {
277
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
278
-            throw new DomainException(
279
-                esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
280
-            );
281
-        }
282
-        // check that loader is callable or method starts with "load_" and exists in EE_Registry
283
-        if (
284
-            ! is_callable($loader)
285
-            && (
286
-                strpos($loader, 'load_') !== 0
287
-                || ! method_exists('EE_Registry', $loader)
288
-            )
289
-        ) {
290
-            throw new DomainException(
291
-                sprintf(
292
-                    esc_html__(
293
-                        '"%1$s" is not a valid loader method on EE_Registry.',
294
-                        'event_espresso'
295
-                    ),
296
-                    $loader
297
-                )
298
-            );
299
-        }
300
-        $class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name);
301
-        if ($overwrite || ! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) {
302
-            EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader;
303
-            return true;
304
-        }
305
-        return false;
306
-    }
307
-
308
-
309
-    /**
310
-     * @return array
311
-     */
312
-    public function dependency_map(): array
313
-    {
314
-        return $this->_dependency_map;
315
-    }
316
-
317
-
318
-    /**
319
-     * returns TRUE if dependency map contains a listing for the provided class name
320
-     *
321
-     * @param string $class_name
322
-     * @return boolean
323
-     */
324
-    public function has(string $class_name = ''): bool
325
-    {
326
-        // all legacy models have the same dependencies
327
-        if (strpos($class_name, 'EEM_') === 0) {
328
-            $class_name = 'LEGACY_MODELS';
329
-        }
330
-        return isset($this->_dependency_map[ $class_name ]);
331
-    }
332
-
333
-
334
-    /**
335
-     * returns TRUE if dependency map contains a listing for the provided class name AND dependency
336
-     *
337
-     * @param string $class_name
338
-     * @param string $dependency
339
-     * @return bool
340
-     */
341
-    public function has_dependency_for_class(string $class_name = '', string $dependency = ''): bool
342
-    {
343
-        // all legacy models have the same dependencies
344
-        if (strpos($class_name, 'EEM_') === 0) {
345
-            $class_name = 'LEGACY_MODELS';
346
-        }
347
-        $dependency = $this->getFqnForAlias($dependency, $class_name);
348
-        return isset($this->_dependency_map[ $class_name ][ $dependency ]);
349
-    }
350
-
351
-
352
-    /**
353
-     * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
354
-     *
355
-     * @param string $class_name
356
-     * @param string $dependency
357
-     * @return int
358
-     */
359
-    public function loading_strategy_for_class_dependency(string $class_name = '', string $dependency = ''): int
360
-    {
361
-        // all legacy models have the same dependencies
362
-        if (strpos($class_name, 'EEM_') === 0) {
363
-            $class_name = 'LEGACY_MODELS';
364
-        }
365
-        $dependency = $this->getFqnForAlias($dependency);
366
-        return $this->has_dependency_for_class($class_name, $dependency)
367
-            ? $this->_dependency_map[ $class_name ][ $dependency ]
368
-            : EE_Dependency_Map::not_registered;
369
-    }
370
-
371
-
372
-    /**
373
-     * @param string $class_name
374
-     * @return string | Closure
375
-     */
376
-    public function class_loader(string $class_name)
377
-    {
378
-        // all legacy models use load_model()
379
-        if (strpos($class_name, 'EEM_') === 0) {
380
-            return 'load_model';
381
-        }
382
-        // EE_CPT_*_Strategy classes like EE_CPT_Event_Strategy, EE_CPT_Venue_Strategy, etc
383
-        // perform strpos() first to avoid loading regex every time we load a class
384
-        if (
385
-            strpos($class_name, 'EE_CPT_') === 0
386
-            && preg_match('/^EE_CPT_([a-zA-Z]+)_Strategy$/', $class_name)
387
-        ) {
388
-            return 'load_core';
389
-        }
390
-        $class_name = $this->getFqnForAlias($class_name);
391
-        return $this->_class_loaders[ $class_name ] ?? '';
392
-    }
393
-
394
-
395
-    /**
396
-     * @return array
397
-     */
398
-    public function class_loaders(): array
399
-    {
400
-        return $this->_class_loaders;
401
-    }
402
-
403
-
404
-    /**
405
-     * adds an alias for a classname
406
-     *
407
-     * @param string $fqcn      the class name that should be used (concrete class to replace interface)
408
-     * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
409
-     * @param string $for_class the class that has the dependency (is type hinting for the interface)
410
-     * @throws InvalidAliasException
411
-     */
412
-    public function add_alias(string $fqcn, string $alias, string $for_class = '')
413
-    {
414
-        $this->class_cache->addAlias($fqcn, $alias, $for_class);
415
-    }
416
-
417
-
418
-    /**
419
-     * Returns TRUE if the provided fully qualified name IS an alias
420
-     * WHY?
421
-     * Because if a class is type hinting for a concretion,
422
-     * then why would we need to find another class to supply it?
423
-     * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
424
-     * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
425
-     * Don't go looking for some substitute.
426
-     * Whereas if a class is type hinting for an interface...
427
-     * then we need to find an actual class to use.
428
-     * So the interface IS the alias for some other FQN,
429
-     * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
430
-     * represents some other class.
431
-     *
432
-     * @param string $fqn
433
-     * @param string $for_class
434
-     * @return bool
435
-     */
436
-    public function isAlias(string $fqn = '', string $for_class = ''): bool
437
-    {
438
-        return $this->class_cache->isAlias($fqn, $for_class);
439
-    }
440
-
441
-
442
-    /**
443
-     * Returns a FQN for provided alias if one exists, otherwise returns the original $alias
444
-     * functions recursively, so that multiple aliases can be used to drill down to a FQN
445
-     *  for example:
446
-     *      if the following two entries were added to the _aliases array:
447
-     *          array(
448
-     *              'interface_alias'           => 'some\namespace\interface'
449
-     *              'some\namespace\interface'  => 'some\namespace\classname'
450
-     *          )
451
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
452
-     *      to load an instance of 'some\namespace\classname'
453
-     *
454
-     * @param string $alias
455
-     * @param string $for_class
456
-     * @return string
457
-     */
458
-    public function getFqnForAlias(string $alias = '', string $for_class = ''): string
459
-    {
460
-        return $this->class_cache->getFqnForAlias($alias, $for_class);
461
-    }
462
-
463
-
464
-    /**
465
-     * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
466
-     * if one exists, or whether a new object should be generated every time the requested class is loaded.
467
-     * This is done by using the following class constants:
468
-     *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
469
-     *        EE_Dependency_Map::load_new_object - generates a new object every time
470
-     */
471
-    protected function _register_core_dependencies()
472
-    {
473
-        $this->_dependency_map = [
474
-            'EE_Admin'                                                                                                           => [
475
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
476
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
477
-            ],
478
-            'EE_Request_Handler'                                                                                                 => [
479
-                'EventEspresso\core\services\request\Request'  => EE_Dependency_Map::load_from_cache,
480
-                'EventEspresso\core\services\request\Response' => EE_Dependency_Map::load_from_cache,
481
-            ],
482
-            'EE_System'                                                                                                          => [
483
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
484
-                'EE_Maintenance_Mode'                         => EE_Dependency_Map::load_from_cache,
485
-                'EE_Registry'                                 => EE_Dependency_Map::load_from_cache,
486
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
487
-                'EventEspresso\core\services\routing\Router'  => EE_Dependency_Map::load_from_cache,
488
-            ],
489
-            'EE_Session'                                                                                                         => [
490
-                'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
491
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
492
-                'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
493
-                'EventEspresso\core\services\session\SessionStartHandler'  => EE_Dependency_Map::load_from_cache,
494
-                'EventEspresso\core\services\encryption\Base64Encoder'     => EE_Dependency_Map::load_from_cache,
495
-            ],
496
-            'EE_Cart'                                                                                                            => [
497
-                'EE_Session' => EE_Dependency_Map::load_from_cache,
498
-            ],
499
-            'EE_Messenger_Collection_Loader'                                                                                     => [
500
-                'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
501
-            ],
502
-            'EE_Message_Type_Collection_Loader'                                                                                  => [
503
-                'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
504
-            ],
505
-            'EE_Message_Resource_Manager'                                                                                        => [
506
-                'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
507
-                'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
508
-                'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
509
-            ],
510
-            'EE_Message_Factory'                                                                                                 => [
511
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
512
-            ],
513
-            'EE_messages'                                                                                                        => [
514
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
515
-            ],
516
-            'EE_Messages_Generator'                                                                                              => [
517
-                'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
518
-                'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
519
-                'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
520
-                'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
521
-            ],
522
-            'EE_Messages_Processor'                                                                                              => [
523
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
524
-            ],
525
-            'EE_Messages_Queue'                                                                                                  => [
526
-                'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
527
-            ],
528
-            'EE_Messages_Template_Defaults'                                                                                      => [
529
-                'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
530
-                'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
531
-            ],
532
-            'EE_Message_To_Generate_From_Request'                                                                                => [
533
-                'EE_Message_Resource_Manager'                 => EE_Dependency_Map::load_from_cache,
534
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
535
-            ],
536
-            'EventEspresso\core\services\commands\CommandBus'                                                                    => [
537
-                'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
538
-            ],
539
-            'EventEspresso\services\commands\CommandHandler'                                                                     => [
540
-                'EE_Registry'         => EE_Dependency_Map::load_from_cache,
541
-                'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
542
-            ],
543
-            'EventEspresso\core\services\commands\CommandHandlerManager'                                                         => [
544
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
545
-            ],
546
-            'EventEspresso\core\services\commands\CompositeCommandHandler'                                                       => [
547
-                'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
548
-                'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
549
-            ],
550
-            'EventEspresso\core\services\commands\CommandFactory'                                                                => [
551
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
552
-            ],
553
-            'EventEspresso\core\services\commands\middleware\CapChecker'                                                         => [
554
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
555
-            ],
556
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                                => [
557
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
558
-            ],
559
-            'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                            => [
560
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
561
-            ],
562
-            'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommandHandler'                          => [
563
-                'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
564
-            ],
565
-            'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => [
566
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
567
-            ],
568
-            'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => [
569
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
570
-            ],
571
-            'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => [
572
-                'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
573
-            ],
574
-            'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => [
575
-                'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
576
-            ],
577
-            'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => [
578
-                'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
579
-            ],
580
-            'EventEspresso\core\domain\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => [
581
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
582
-            ],
583
-            'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                          => [
584
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
585
-            ],
586
-            'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler'                                  => [
587
-                'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
588
-            ],
589
-            'EventEspresso\core\domain\values\session\SessionLifespan'                                                           => [
590
-                'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
591
-            ],
592
-            'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanForm'                                 => [
593
-                'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
594
-            ],
595
-            'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanFormHandler'                          => [
596
-                'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
597
-            ],
598
-            'EventEspresso\core\services\database\TableManager'                                                                  => [
599
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
600
-            ],
601
-            'EE_Data_Migration_Class_Base'                                                                                       => [
602
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
603
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
604
-            ],
605
-            'EE_DMS_Core_4_1_0'                                                                                                  => [
606
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
607
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
608
-            ],
609
-            'EE_DMS_Core_4_2_0'                                                                                                  => [
610
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
611
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
612
-            ],
613
-            'EE_DMS_Core_4_3_0'                                                                                                  => [
614
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
615
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
616
-            ],
617
-            'EE_DMS_Core_4_4_0'                                                                                                  => [
618
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
619
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
620
-            ],
621
-            'EE_DMS_Core_4_5_0'                                                                                                  => [
622
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
623
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
624
-            ],
625
-            'EE_DMS_Core_4_6_0'                                                                                                  => [
626
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
627
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
628
-            ],
629
-            'EE_DMS_Core_4_7_0'                                                                                                  => [
630
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
631
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
632
-            ],
633
-            'EE_DMS_Core_4_8_0'                                                                                                  => [
634
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
635
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
636
-            ],
637
-            'EE_DMS_Core_4_9_0'                                                                                                  => [
638
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
639
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
640
-            ],
641
-            'EE_DMS_Core_4_10_0'                                                                                                 => [
642
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
643
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
644
-                'EE_DMS_Core_4_9_0'                                  => EE_Dependency_Map::load_from_cache,
645
-            ],
646
-            'EE_DMS_Core_5_0_0'                                                                                                  => [
647
-                'EE_DMS_Core_4_10_0'                                 => EE_Dependency_Map::load_from_cache,
648
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
649
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
650
-            ],
651
-            'EventEspresso\core\services\assets\I18nRegistry'                                                                    => [
652
-                'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
653
-            ],
654
-            'EventEspresso\core\services\assets\Registry'                                                                        => [
655
-                'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_from_cache,
656
-                'EventEspresso\core\services\assets\AssetManifest'   => EE_Dependency_Map::load_from_cache,
657
-            ],
658
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                                    => [
659
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
660
-            ],
661
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                                     => [
662
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
663
-            ],
664
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                               => [
665
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
666
-            ],
667
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                       => [
668
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
669
-            ],
670
-            'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                                     => [
671
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
672
-            ],
673
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                               => [
674
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
675
-            ],
676
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                                      => [
677
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
678
-            ],
679
-            'EventEspresso\core\services\cache\BasicCacheManager'                                                                => [
680
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
681
-            ],
682
-            'EventEspresso\core\services\cache\PostRelatedCacheManager'                                                          => [
683
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
684
-            ],
685
-            'EventEspresso\core\domain\services\validation\email\EmailValidationService'                                         => [
686
-                'EE_Registration_Config'                     => EE_Dependency_Map::load_from_cache,
687
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
688
-            ],
689
-            'EventEspresso\core\domain\values\EmailAddress'                                                                      => [
690
-                null,
691
-                'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
692
-            ],
693
-            'EventEspresso\core\services\orm\ModelFieldFactory'                                                                  => [
694
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
695
-            ],
696
-            'LEGACY_MODELS'                                                                                                      => [
697
-                null,
698
-                'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
699
-            ],
700
-            'EE_Module_Request_Router'                                                                                           => [
701
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
702
-            ],
703
-            'EE_Registration_Processor'                                                                                          => [
704
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
705
-            ],
706
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'                                             => [
707
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
708
-                'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
709
-            ],
710
-            'EventEspresso\caffeinated\modules\recaptcha_invisible\InvisibleRecaptcha'                                           => [
711
-                'EE_Registration_Config' => EE_Dependency_Map::load_from_cache,
712
-                'EE_Session'             => EE_Dependency_Map::load_from_cache,
713
-            ],
714
-            'EventEspresso\modules\ticket_selector\DisplayTicketSelector'                                                        => [
715
-                'EventEspresso\core\domain\entities\users\CurrentUser' => EE_Dependency_Map::load_from_cache,
716
-                'EventEspresso\core\services\request\Request'          => EE_Dependency_Map::load_from_cache,
717
-                'EE_Ticket_Selector_Config'                            => EE_Dependency_Map::load_from_cache,
718
-            ],
719
-            'EventEspresso\modules\ticket_selector\ProcessTicketSelector'                                                        => [
720
-                'EE_Core_Config'                                                          => EE_Dependency_Map::load_from_cache,
721
-                'EventEspresso\core\services\request\Request'                             => EE_Dependency_Map::load_from_cache,
722
-                'EE_Session'                                                              => EE_Dependency_Map::load_from_cache,
723
-                'EEM_Ticket'                                                              => EE_Dependency_Map::load_from_cache,
724
-                'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => EE_Dependency_Map::load_from_cache,
725
-            ],
726
-            'EventEspresso\modules\ticket_selector\ProcessTicketSelectorPostData'                                                => [
727
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
728
-                'EEM_Event'                                   => EE_Dependency_Map::load_from_cache,
729
-            ],
730
-            'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker'                                            => [
731
-                'EEM_Datetime' => EE_Dependency_Map::load_from_cache,
732
-            ],
733
-            'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'                                     => [
734
-                'EE_Core_Config'                             => EE_Dependency_Map::load_from_cache,
735
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
736
-            ],
737
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'                                       => [
738
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
739
-            ],
740
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'                                      => [
741
-                'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
742
-            ],
743
-            'EE_CPT_Strategy'                                                                                                    => [
744
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
745
-                'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
746
-            ],
747
-            'EventEspresso\core\services\loaders\ObjectIdentifier'                                                               => [
748
-                'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
749
-            ],
750
-            'EventEspresso\core\CPTs\CptQueryModifier'                                                                           => [
751
-                null,
752
-                null,
753
-                null,
754
-                'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
755
-                'EventEspresso\core\services\request\Request'     => EE_Dependency_Map::load_from_cache,
756
-                'EventEspresso\core\services\loaders\Loader'      => EE_Dependency_Map::load_from_cache,
757
-            ],
758
-            'EventEspresso\core\services\dependencies\DependencyResolver'                                                        => [
759
-                'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
760
-                'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
761
-                'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
762
-            ],
763
-            'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver'                                      => [
764
-                'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
765
-                'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
766
-                'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
767
-            ],
768
-            'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'                                                 => [
769
-                'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => EE_Dependency_Map::load_from_cache,
770
-                'EventEspresso\core\services\loaders\Loader'                                    => EE_Dependency_Map::load_from_cache,
771
-            ],
772
-            'EventEspresso\core\services\routing\RouteMatchSpecificationManager'                                                 => [
773
-                'EventEspresso\core\services\routing\RouteMatchSpecificationCollection' => EE_Dependency_Map::load_from_cache,
774
-                'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'    => EE_Dependency_Map::load_from_cache,
775
-            ],
776
-            'EventEspresso\core\services\request\files\FilesDataHandler'                                                         => [
777
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
778
-            ],
779
-            'EventEspressoBatchRequest\BatchRequestProcessor'                                                                    => [
780
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
781
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
782
-            ],
783
-            'EventEspresso\core\domain\services\converters\RestApiSpoofer'                                                       => [
784
-                'WP_REST_Server'                                               => EE_Dependency_Map::load_from_cache,
785
-                'EED_Core_Rest_Api'                                            => EE_Dependency_Map::load_from_cache,
786
-                'EventEspresso\core\libraries\rest_api\controllers\model\Read' => EE_Dependency_Map::load_from_cache,
787
-                null,
788
-            ],
789
-            'EventEspresso\core\services\routing\RouteHandler'                                                                   => [
790
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
791
-                'EventEspresso\core\services\json\JsonDataNodeHandler'                => EE_Dependency_Map::load_from_cache,
792
-                'EventEspresso\core\services\loaders\Loader'                          => EE_Dependency_Map::load_from_cache,
793
-                'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
794
-                'EventEspresso\core\services\routing\RouteCollection'                 => EE_Dependency_Map::load_from_cache,
795
-            ],
796
-            'EventEspresso\core\services\json\JsonDataNodeHandler'                                                               => [
797
-                'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
798
-            ],
799
-            'EventEspresso\core\services\routing\Router'                                                                         => [
800
-                'EE_Dependency_Map'                                => EE_Dependency_Map::load_from_cache,
801
-                'EventEspresso\core\services\loaders\Loader'       => EE_Dependency_Map::load_from_cache,
802
-                'EventEspresso\core\services\routing\RouteHandler' => EE_Dependency_Map::load_from_cache,
803
-            ],
804
-            'EventEspresso\core\services\assets\AssetManifest'                                                                   => [
805
-                'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
806
-            ],
807
-            'EventEspresso\core\services\assets\AssetManifestFactory'                                                            => [
808
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
809
-            ],
810
-            'EventEspresso\core\services\assets\BaristaFactory'                                                                  => [
811
-                'EventEspresso\core\services\assets\AssetManifestFactory' => EE_Dependency_Map::load_from_cache,
812
-                'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
813
-            ],
814
-            'EventEspresso\core\domain\services\capabilities\FeatureFlags'                                                       => [
815
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
816
-                'EventEspresso\core\domain\Domain'                                    => EE_Dependency_Map::load_from_cache,
817
-            ],
818
-            'EventEspresso\core\services\addon\AddonManager'                                                                     => [
819
-                'EventEspresso\core\services\addon\AddonCollection'              => EE_Dependency_Map::load_from_cache,
820
-                'EventEspresso\core\Psr4Autoloader'                              => EE_Dependency_Map::load_from_cache,
821
-                'EventEspresso\core\services\addon\api\v1\RegisterAddon'         => EE_Dependency_Map::load_from_cache,
822
-                'EventEspresso\core\services\addon\api\IncompatibleAddonHandler' => EE_Dependency_Map::load_from_cache,
823
-                'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'  => EE_Dependency_Map::load_from_cache,
824
-            ],
825
-            'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'                                                      => [
826
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
827
-            ],
828
-            'EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion'                                                         => [
829
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
830
-            ],
831
-            'EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'                                                         => [
832
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
833
-            ],
834
-            'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'                                               => [
835
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
836
-                'EEM_Event'                                                   => EE_Dependency_Map::load_from_cache,
837
-                'EEM_Datetime'                                                => EE_Dependency_Map::load_from_cache,
838
-                'EEM_Registration'                                            => EE_Dependency_Map::load_from_cache,
839
-            ],
840
-            'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'                                               => [
841
-                'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
842
-            ],
843
-            'EventEspresso\core\services\request\CurrentPage'                                                                    => [
844
-                'EE_CPT_Strategy'                             => EE_Dependency_Map::load_from_cache,
845
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
846
-            ],
847
-            'EventEspresso\core\services\shortcodes\LegacyShortcodesManager'                                                     => [
848
-                'EE_Registry'                                     => EE_Dependency_Map::load_from_cache,
849
-                'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
850
-            ],
851
-            'EventEspresso\core\services\shortcodes\ShortcodesManager'                                                           => [
852
-                'EventEspresso\core\services\shortcodes\LegacyShortcodesManager' => EE_Dependency_Map::load_from_cache,
853
-                'EventEspresso\core\services\request\CurrentPage'                => EE_Dependency_Map::load_from_cache,
854
-            ],
855
-            'EventEspresso\core\domain\entities\users\CurrentUser'                                                               => [
856
-                'EventEspresso\core\domain\entities\users\EventManagers' => EE_Dependency_Map::load_from_cache,
857
-            ],
858
-            'EventEspresso\core\services\form\meta\InputTypes'                                                                   => [
859
-                'EventEspresso\core\services\form\meta\inputs\Block'    => EE_Dependency_Map::load_from_cache,
860
-                'EventEspresso\core\services\form\meta\inputs\Button'   => EE_Dependency_Map::load_from_cache,
861
-                'EventEspresso\core\services\form\meta\inputs\DateTime' => EE_Dependency_Map::load_from_cache,
862
-                'EventEspresso\core\services\form\meta\inputs\Input'    => EE_Dependency_Map::load_from_cache,
863
-                'EventEspresso\core\services\form\meta\inputs\Number'   => EE_Dependency_Map::load_from_cache,
864
-                'EventEspresso\core\services\form\meta\inputs\Phone'    => EE_Dependency_Map::load_from_cache,
865
-                'EventEspresso\core\services\form\meta\inputs\Select'   => EE_Dependency_Map::load_from_cache,
866
-                'EventEspresso\core\services\form\meta\inputs\Text'     => EE_Dependency_Map::load_from_cache,
867
-            ],
868
-            'EventEspresso\core\domain\services\registration\form\v1\RegFormDependencyHandler'                                   => [
869
-                'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache,
870
-            ],
871
-            'EventEspresso\core\services\calculators\LineItemCalculator'                                                         => [
872
-                'EventEspresso\core\services\helpers\DecimalValues' => EE_Dependency_Map::load_from_cache,
873
-            ],
874
-            'EventEspresso\core\services\helpers\DecimalValues'                                                                  => [
875
-                'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
876
-            ],
877
-            'EE_Brewing_Regular'                                                                                                 => [
878
-                'EE_Dependency_Map'                                  => EE_Dependency_Map::load_from_cache,
879
-                'EventEspresso\core\services\loaders\Loader'         => EE_Dependency_Map::load_from_cache,
880
-                'EventEspresso\core\services\routing\RouteHandler'   => EE_Dependency_Map::load_from_cache,
881
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
882
-            ],
883
-            'EventEspresso\core\domain\services\messages\MessageTemplateRequestData'                                             => [
884
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
885
-            ],
886
-            'EventEspresso\core\domain\services\messages\MessageTemplateValidator'                                               => [
887
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
888
-            ],
889
-            'EventEspresso\core\domain\services\messages\MessageTemplateManager'                                                 => [
890
-                'EEM_Message_Template'                                                   => EE_Dependency_Map::load_from_cache,
891
-                'EEM_Message_Template_Group'                                             => EE_Dependency_Map::load_from_cache,
892
-                'EventEspresso\core\domain\services\messages\MessageTemplateRequestData' => EE_Dependency_Map::load_from_cache,
893
-                'EventEspresso\core\domain\services\messages\MessageTemplateValidator'   => EE_Dependency_Map::load_from_cache,
894
-                'EventEspresso\core\services\request\Request'                            => EE_Dependency_Map::load_from_cache,
895
-            ],
896
-            'EventEspresso\core\services\request\sanitizers\RequestSanitizer'                                                    => [
897
-                'EventEspresso\core\domain\services\validation\email\strategies\Basic' => EE_Dependency_Map::load_from_cache,
898
-            ],
899
-        ];
900
-    }
901
-
902
-
903
-    /**
904
-     * Registers how core classes are loaded.
905
-     * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
906
-     *        'EE_Request_Handler' => 'load_core'
907
-     *        'EE_Messages_Queue'  => 'load_lib'
908
-     *        'EEH_Debug_Tools'    => 'load_helper'
909
-     * or, if greater control is required, by providing a custom closure. For example:
910
-     *        'Some_Class' => function () {
911
-     *            return new Some_Class();
912
-     *        },
913
-     * This is required for instantiating dependencies
914
-     * where an interface has been type hinted in a class constructor. For example:
915
-     *        'Required_Interface' => function () {
916
-     *            return new A_Class_That_Implements_Required_Interface();
917
-     *        },
918
-     */
919
-    protected function _register_core_class_loaders()
920
-    {
921
-        $this->_class_loaders = [
922
-            // load_core
923
-            'EE_Dependency_Map'                            => function () {
924
-                return $this;
925
-            },
926
-            'EE_Capabilities'                              => 'load_core',
927
-            'EE_Encryption'                                => 'load_core',
928
-            'EE_Front_Controller'                          => 'load_core',
929
-            'EE_Module_Request_Router'                     => 'load_core',
930
-            'EE_Registry'                                  => 'load_core',
931
-            'EE_Request'                                   => function () {
932
-                return $this->legacy_request;
933
-            },
934
-            'EventEspresso\core\services\request\Request'  => function () {
935
-                return $this->request;
936
-            },
937
-            'EventEspresso\core\services\request\Response' => function () {
938
-                return $this->response;
939
-            },
940
-            'EE_Base'                                      => 'load_core',
941
-            'EE_Request_Handler'                           => 'load_core',
942
-            'EE_Session'                                   => 'load_core',
943
-            'EE_Cron_Tasks'                                => 'load_core',
944
-            'EE_System'                                    => 'load_core',
945
-            'EE_Maintenance_Mode'                          => 'load_core',
946
-            'EE_Register_CPTs'                             => 'load_core',
947
-            'EE_Admin'                                     => 'load_core',
948
-            'EE_CPT_Strategy'                              => 'load_core',
949
-            // load_class
950
-            'EE_Registration_Processor'                    => 'load_class',
951
-            // load_lib
952
-            'EE_Message_Resource_Manager'                  => 'load_lib',
953
-            'EE_Message_Type_Collection'                   => 'load_lib',
954
-            'EE_Message_Type_Collection_Loader'            => 'load_lib',
955
-            'EE_Messenger_Collection'                      => 'load_lib',
956
-            'EE_Messenger_Collection_Loader'               => 'load_lib',
957
-            'EE_Messages_Processor'                        => 'load_lib',
958
-            'EE_Message_Repository'                        => 'load_lib',
959
-            'EE_Messages_Queue'                            => 'load_lib',
960
-            'EE_Messages_Data_Handler_Collection'          => 'load_lib',
961
-            'EE_Message_Template_Group_Collection'         => 'load_lib',
962
-            'EE_Payment_Method_Manager'                    => 'load_lib',
963
-            'EE_Payment_Processor'                         => 'load_core',
964
-            'EE_DMS_Core_4_1_0'                            => 'load_dms',
965
-            'EE_DMS_Core_4_2_0'                            => 'load_dms',
966
-            'EE_DMS_Core_4_3_0'                            => 'load_dms',
967
-            'EE_DMS_Core_4_5_0'                            => 'load_dms',
968
-            'EE_DMS_Core_4_6_0'                            => 'load_dms',
969
-            'EE_DMS_Core_4_7_0'                            => 'load_dms',
970
-            'EE_DMS_Core_4_8_0'                            => 'load_dms',
971
-            'EE_DMS_Core_4_9_0'                            => 'load_dms',
972
-            'EE_DMS_Core_4_10_0'                           => 'load_dms',
973
-            'EE_DMS_Core_5_0_0'                            => 'load_dms',
974
-            'EE_Messages_Generator'                        => static function () {
975
-                return EE_Registry::instance()->load_lib(
976
-                    'Messages_Generator',
977
-                    [],
978
-                    false,
979
-                    false
980
-                );
981
-            },
982
-            'EE_Messages_Template_Defaults'                => static function ($arguments = []) {
983
-                return EE_Registry::instance()->load_lib(
984
-                    'Messages_Template_Defaults',
985
-                    $arguments,
986
-                    false,
987
-                    false
988
-                );
989
-            },
990
-            // load_helper
991
-            'EEH_Parse_Shortcodes'                         => static function () {
992
-                if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
993
-                    return new EEH_Parse_Shortcodes();
994
-                }
995
-                return null;
996
-            },
997
-            'EE_Template_Config'                           => static function () {
998
-                return EE_Config::instance()->template_settings;
999
-            },
1000
-            'EE_Currency_Config'                           => static function () {
1001
-                return EE_Currency_Config::getCurrencyConfig();
1002
-            },
1003
-            'EE_Registration_Config'                       => static function () {
1004
-                return EE_Config::instance()->registration;
1005
-            },
1006
-            'EE_Core_Config'                               => static function () {
1007
-                return EE_Config::instance()->core;
1008
-            },
1009
-            'EventEspresso\core\services\loaders\Loader'   => static function () {
1010
-                return LoaderFactory::getLoader();
1011
-            },
1012
-            'EE_Network_Config'                            => static function () {
1013
-                return EE_Network_Config::instance();
1014
-            },
1015
-            'EE_Config'                                    => static function () {
1016
-                return EE_Config::instance();
1017
-            },
1018
-            'EventEspresso\core\domain\Domain'             => static function () {
1019
-                return DomainFactory::getEventEspressoCoreDomain();
1020
-            },
1021
-            'EE_Admin_Config'                              => static function () {
1022
-                return EE_Config::instance()->admin;
1023
-            },
1024
-            'EE_Organization_Config'                       => static function () {
1025
-                return EE_Config::instance()->organization;
1026
-            },
1027
-            'EE_Network_Core_Config'                       => static function () {
1028
-                return EE_Network_Config::instance()->core;
1029
-            },
1030
-            'EE_Environment_Config'                        => static function () {
1031
-                return EE_Config::instance()->environment;
1032
-            },
1033
-            'EED_Core_Rest_Api'                            => static function () {
1034
-                return EED_Core_Rest_Api::instance();
1035
-            },
1036
-            'WP_REST_Server'                               => static function () {
1037
-                return rest_get_server();
1038
-            },
1039
-            'EventEspresso\core\Psr4Autoloader'            => static function () {
1040
-                return EE_Psr4AutoloaderInit::psr4_loader();
1041
-            },
1042
-            'EE_Ticket_Selector_Config'                    => function () {
1043
-                return EE_Config::instance()->template_settings->EED_Ticket_Selector;
1044
-            },
1045
-        ];
1046
-    }
1047
-
1048
-
1049
-    /**
1050
-     * can be used for supplying alternate names for classes,
1051
-     * or for connecting interface names to instantiable classes
1052
-     *
1053
-     * @throws InvalidAliasException
1054
-     */
1055
-    protected function _register_core_aliases()
1056
-    {
1057
-        $aliases = [
1058
-            'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
1059
-            'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
1060
-            'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
1061
-            'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
1062
-            'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
1063
-            'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
1064
-            'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1065
-            'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
1066
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1067
-            'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
1068
-            'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommand',
1069
-            'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommand',
1070
-            'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommand',
1071
-            'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
1072
-            'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
1073
-            'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommand',
1074
-            'CreateTransactionCommandHandler'                                              => 'EventEspresso\core\domain\services\commands\transaction\CreateTransactionCommandHandler',
1075
-            'CreateAttendeeCommandHandler'                                                 => 'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler',
1076
-            'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
1077
-            'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
1078
-            'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1079
-            'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
1080
-            'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1081
-            'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
1082
-            'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
1083
-            'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
1084
-            'CommandFactoryInterface'                                                      => 'EventEspresso\core\services\commands\CommandFactoryInterface',
1085
-            'EventEspresso\core\services\commands\CommandFactoryInterface'                 => 'EventEspresso\core\services\commands\CommandFactory',
1086
-            'EmailValidatorInterface'                                                      => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
1087
-            'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface'  => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
1088
-            'NoticeConverterInterface'                                                     => 'EventEspresso\core\services\notices\NoticeConverterInterface',
1089
-            'EventEspresso\core\services\notices\NoticeConverterInterface'                 => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
1090
-            'NoticesContainerInterface'                                                    => 'EventEspresso\core\services\notices\NoticesContainerInterface',
1091
-            'EventEspresso\core\services\notices\NoticesContainerInterface'                => 'EventEspresso\core\services\notices\NoticesContainer',
1092
-            'EventEspresso\core\services\request\RequestInterface'                         => 'EventEspresso\core\services\request\Request',
1093
-            'EventEspresso\core\services\request\ResponseInterface'                        => 'EventEspresso\core\services\request\Response',
1094
-            'EventEspresso\core\domain\DomainInterface'                                    => 'EventEspresso\core\domain\Domain',
1095
-            'Registration_Processor'                                                       => 'EE_Registration_Processor',
1096
-            'EventEspresso\core\services\assets\AssetManifestInterface'                    => 'EventEspresso\core\services\assets\AssetManifest',
1097
-        ];
1098
-        foreach ($aliases as $alias => $fqn) {
1099
-            if (is_array($fqn)) {
1100
-                foreach ($fqn as $class => $for_class) {
1101
-                    $this->class_cache->addAlias($class, $alias, $for_class);
1102
-                }
1103
-                continue;
1104
-            }
1105
-            $this->class_cache->addAlias($fqn, $alias);
1106
-        }
1107
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1108
-            $this->class_cache->addAlias(
1109
-                'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
1110
-                'EventEspresso\core\services\notices\NoticeConverterInterface'
1111
-            );
1112
-        }
1113
-    }
1114
-
1115
-
1116
-    public function debug($for_class = '')
1117
-    {
1118
-        if (method_exists($this->class_cache, 'debug')) {
1119
-            $this->class_cache->debug($for_class);
1120
-        }
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
1126
-     * request Primarily used by unit tests.
1127
-     */
1128
-    public function reset()
1129
-    {
1130
-        $this->_register_core_class_loaders();
1131
-        $this->_register_core_dependencies();
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * PLZ NOTE: a better name for this method would be is_alias()
1137
-     * because it returns TRUE if the provided fully qualified name IS an alias
1138
-     * WHY?
1139
-     * Because if a class is type hinting for a concretion,
1140
-     * then why would we need to find another class to supply it?
1141
-     * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
1142
-     * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
1143
-     * Don't go looking for some substitute.
1144
-     * Whereas if a class is type hinting for an interface...
1145
-     * then we need to find an actual class to use.
1146
-     * So the interface IS the alias for some other FQN,
1147
-     * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
1148
-     * represents some other class.
1149
-     *
1150
-     * @param string $fqn
1151
-     * @param string $for_class
1152
-     * @return bool
1153
-     * @deprecated 4.9.62.p
1154
-     */
1155
-    public function has_alias(string $fqn = '', string $for_class = ''): bool
1156
-    {
1157
-        return $this->isAlias($fqn, $for_class);
1158
-    }
1159
-
1160
-
1161
-    /**
1162
-     * PLZ NOTE: a better name for this method would be get_fqn_for_alias()
1163
-     * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias
1164
-     * functions recursively, so that multiple aliases can be used to drill down to a FQN
1165
-     *  for example:
1166
-     *      if the following two entries were added to the _aliases array:
1167
-     *          array(
1168
-     *              'interface_alias'           => 'some\namespace\interface'
1169
-     *              'some\namespace\interface'  => 'some\namespace\classname'
1170
-     *          )
1171
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
1172
-     *      to load an instance of 'some\namespace\classname'
1173
-     *
1174
-     * @param string $alias
1175
-     * @param string $for_class
1176
-     * @return string
1177
-     * @deprecated 4.9.62.p
1178
-     */
1179
-    public function get_alias(string $alias = '', string $for_class = ''): string
1180
-    {
1181
-        return $this->getFqnForAlias($alias, $for_class);
1182
-    }
24
+	/**
25
+	 * This means that the requested class dependency is not present in the dependency map
26
+	 */
27
+	const not_registered = 0;
28
+
29
+	/**
30
+	 * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
31
+	 */
32
+	const load_new_object = 1;
33
+
34
+	/**
35
+	 * This instructs class loaders to return a previously instantiated and cached object for the requested class.
36
+	 * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
37
+	 */
38
+	const load_from_cache = 2;
39
+
40
+	/**
41
+	 * When registering a dependency,
42
+	 * this indicates to keep any existing dependencies that already exist,
43
+	 * and simply discard any new dependencies declared in the incoming data
44
+	 */
45
+	const KEEP_EXISTING_DEPENDENCIES = 0;
46
+
47
+	/**
48
+	 * When registering a dependency,
49
+	 * this indicates to overwrite any existing dependencies that already exist using the incoming data
50
+	 */
51
+	const OVERWRITE_DEPENDENCIES = 1;
52
+
53
+	/**
54
+	 * @type EE_Dependency_Map $_instance
55
+	 */
56
+	protected static $_instance;
57
+
58
+	/**
59
+	 * @var ClassInterfaceCache $class_cache
60
+	 */
61
+	private $class_cache;
62
+
63
+	/**
64
+	 * @type RequestInterface $request
65
+	 */
66
+	protected $request;
67
+
68
+	/**
69
+	 * @type LegacyRequestInterface $legacy_request
70
+	 */
71
+	protected $legacy_request;
72
+
73
+	/**
74
+	 * @type ResponseInterface $response
75
+	 */
76
+	protected $response;
77
+
78
+	/**
79
+	 * @type LoaderInterface $loader
80
+	 */
81
+	protected $loader;
82
+
83
+	/**
84
+	 * @type array $_dependency_map
85
+	 */
86
+	protected $_dependency_map = [];
87
+
88
+	/**
89
+	 * @type array $_class_loaders
90
+	 */
91
+	protected $_class_loaders = [];
92
+
93
+
94
+	/**
95
+	 * EE_Dependency_Map constructor.
96
+	 *
97
+	 * @param ClassInterfaceCache $class_cache
98
+	 */
99
+	protected function __construct(ClassInterfaceCache $class_cache)
100
+	{
101
+		$this->class_cache = $class_cache;
102
+		do_action('EE_Dependency_Map____construct', $this);
103
+	}
104
+
105
+
106
+	/**
107
+	 * @return void
108
+	 * @throws InvalidAliasException
109
+	 */
110
+	public function initialize()
111
+	{
112
+		$this->_register_core_dependencies();
113
+		$this->_register_core_class_loaders();
114
+		$this->_register_core_aliases();
115
+	}
116
+
117
+
118
+	/**
119
+	 * @singleton method used to instantiate class object
120
+	 * @param ClassInterfaceCache|null $class_cache
121
+	 * @return EE_Dependency_Map
122
+	 */
123
+	public static function instance(ClassInterfaceCache $class_cache = null): EE_Dependency_Map
124
+	{
125
+		// check if class object is instantiated, and instantiated properly
126
+		if (
127
+			! EE_Dependency_Map::$_instance instanceof EE_Dependency_Map
128
+			&& $class_cache instanceof ClassInterfaceCache
129
+		) {
130
+			EE_Dependency_Map::$_instance = new EE_Dependency_Map($class_cache);
131
+		}
132
+		return EE_Dependency_Map::$_instance;
133
+	}
134
+
135
+
136
+	/**
137
+	 * @param RequestInterface $request
138
+	 */
139
+	public function setRequest(RequestInterface $request)
140
+	{
141
+		$this->request = $request;
142
+	}
143
+
144
+
145
+	/**
146
+	 * @param LegacyRequestInterface $legacy_request
147
+	 */
148
+	public function setLegacyRequest(LegacyRequestInterface $legacy_request)
149
+	{
150
+		$this->legacy_request = $legacy_request;
151
+	}
152
+
153
+
154
+	/**
155
+	 * @param ResponseInterface $response
156
+	 */
157
+	public function setResponse(ResponseInterface $response)
158
+	{
159
+		$this->response = $response;
160
+	}
161
+
162
+
163
+	/**
164
+	 * @param LoaderInterface $loader
165
+	 */
166
+	public function setLoader(LoaderInterface $loader)
167
+	{
168
+		$this->loader = $loader;
169
+	}
170
+
171
+
172
+	/**
173
+	 * @param string $class
174
+	 * @param array  $dependencies
175
+	 * @param int    $overwrite
176
+	 * @return bool
177
+	 */
178
+	public static function register_dependencies(
179
+		string $class,
180
+		array $dependencies,
181
+		int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
182
+	): bool {
183
+		return EE_Dependency_Map::$_instance->registerDependencies($class, $dependencies, $overwrite);
184
+	}
185
+
186
+
187
+	/**
188
+	 * Assigns an array of class names and corresponding load sources (new or cached)
189
+	 * to the class specified by the first parameter.
190
+	 * IMPORTANT !!!
191
+	 * The order of elements in the incoming $dependencies array MUST match
192
+	 * the order of the constructor parameters for the class in question.
193
+	 * This is especially important when overriding any existing dependencies that are registered.
194
+	 * the third parameter controls whether any duplicate dependencies are overwritten or not.
195
+	 *
196
+	 * @param string $class
197
+	 * @param array  $dependencies
198
+	 * @param int    $overwrite
199
+	 * @return bool
200
+	 */
201
+	public function registerDependencies(
202
+		string $class,
203
+		array $dependencies,
204
+		int $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
205
+	): bool {
206
+		if (empty($dependencies)) {
207
+			return false;
208
+		}
209
+		$class      = trim($class, '\\');
210
+		$registered = false;
211
+		if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) {
212
+			EE_Dependency_Map::$_instance->_dependency_map[ $class ] = [];
213
+		}
214
+		// we need to make sure that any aliases used when registering a dependency
215
+		// get resolved to the correct class name
216
+		foreach ($dependencies as $dependency => $load_source) {
217
+			$alias = EE_Dependency_Map::$_instance->getFqnForAlias($dependency);
218
+			if (
219
+				$overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
220
+				|| ! isset(
221
+					EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $dependency ],
222
+					EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]
223
+				)
224
+			) {
225
+				unset($dependencies[ $dependency ]);
226
+				$dependencies[ $alias ] = $load_source;
227
+				$registered             = true;
228
+			}
229
+		}
230
+		// now add our two lists of dependencies together.
231
+		// using Union (+=) favours the arrays in precedence from left to right,
232
+		// so $dependencies is NOT overwritten because it is listed first
233
+		// ie: with A = B + C, entries in B take precedence over duplicate entries in C
234
+		// Union is way faster than array_merge() but should be used with caution...
235
+		// especially with numerically indexed arrays
236
+		$dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ];
237
+		// now we need to ensure that the resulting dependencies
238
+		// array only has the entries that are required for the class
239
+		// so first count how many dependencies were originally registered for the class
240
+		$dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]);
241
+		// if that count is non-zero (meaning dependencies were already registered)
242
+		EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count
243
+			// then truncate the  final array to match that count
244
+			? array_slice($dependencies, 0, $dependency_count)
245
+			// otherwise just take the incoming array because nothing previously existed
246
+			: $dependencies;
247
+		return $registered
248
+			   || count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]) === count($dependencies);
249
+	}
250
+
251
+
252
+	/**
253
+	 * @param string          $class_name
254
+	 * @param callable|string $loader
255
+	 * @param bool            $overwrite
256
+	 * @return bool
257
+	 * @throws DomainException
258
+	 */
259
+	public static function register_class_loader(
260
+		string $class_name,
261
+		$loader = 'load_core',
262
+		bool $overwrite = false
263
+	): bool {
264
+		return EE_Dependency_Map::$_instance->registerClassLoader($class_name, $loader, $overwrite);
265
+	}
266
+
267
+
268
+	/**
269
+	 * @param string         $class_name
270
+	 * @param Closure|string $loader
271
+	 * @param bool           $overwrite
272
+	 * @return bool
273
+	 * @throws DomainException
274
+	 */
275
+	public function registerClassLoader(string $class_name, $loader = 'load_core', bool $overwrite = false): bool
276
+	{
277
+		if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
278
+			throw new DomainException(
279
+				esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
280
+			);
281
+		}
282
+		// check that loader is callable or method starts with "load_" and exists in EE_Registry
283
+		if (
284
+			! is_callable($loader)
285
+			&& (
286
+				strpos($loader, 'load_') !== 0
287
+				|| ! method_exists('EE_Registry', $loader)
288
+			)
289
+		) {
290
+			throw new DomainException(
291
+				sprintf(
292
+					esc_html__(
293
+						'"%1$s" is not a valid loader method on EE_Registry.',
294
+						'event_espresso'
295
+					),
296
+					$loader
297
+				)
298
+			);
299
+		}
300
+		$class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name);
301
+		if ($overwrite || ! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) {
302
+			EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader;
303
+			return true;
304
+		}
305
+		return false;
306
+	}
307
+
308
+
309
+	/**
310
+	 * @return array
311
+	 */
312
+	public function dependency_map(): array
313
+	{
314
+		return $this->_dependency_map;
315
+	}
316
+
317
+
318
+	/**
319
+	 * returns TRUE if dependency map contains a listing for the provided class name
320
+	 *
321
+	 * @param string $class_name
322
+	 * @return boolean
323
+	 */
324
+	public function has(string $class_name = ''): bool
325
+	{
326
+		// all legacy models have the same dependencies
327
+		if (strpos($class_name, 'EEM_') === 0) {
328
+			$class_name = 'LEGACY_MODELS';
329
+		}
330
+		return isset($this->_dependency_map[ $class_name ]);
331
+	}
332
+
333
+
334
+	/**
335
+	 * returns TRUE if dependency map contains a listing for the provided class name AND dependency
336
+	 *
337
+	 * @param string $class_name
338
+	 * @param string $dependency
339
+	 * @return bool
340
+	 */
341
+	public function has_dependency_for_class(string $class_name = '', string $dependency = ''): bool
342
+	{
343
+		// all legacy models have the same dependencies
344
+		if (strpos($class_name, 'EEM_') === 0) {
345
+			$class_name = 'LEGACY_MODELS';
346
+		}
347
+		$dependency = $this->getFqnForAlias($dependency, $class_name);
348
+		return isset($this->_dependency_map[ $class_name ][ $dependency ]);
349
+	}
350
+
351
+
352
+	/**
353
+	 * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
354
+	 *
355
+	 * @param string $class_name
356
+	 * @param string $dependency
357
+	 * @return int
358
+	 */
359
+	public function loading_strategy_for_class_dependency(string $class_name = '', string $dependency = ''): int
360
+	{
361
+		// all legacy models have the same dependencies
362
+		if (strpos($class_name, 'EEM_') === 0) {
363
+			$class_name = 'LEGACY_MODELS';
364
+		}
365
+		$dependency = $this->getFqnForAlias($dependency);
366
+		return $this->has_dependency_for_class($class_name, $dependency)
367
+			? $this->_dependency_map[ $class_name ][ $dependency ]
368
+			: EE_Dependency_Map::not_registered;
369
+	}
370
+
371
+
372
+	/**
373
+	 * @param string $class_name
374
+	 * @return string | Closure
375
+	 */
376
+	public function class_loader(string $class_name)
377
+	{
378
+		// all legacy models use load_model()
379
+		if (strpos($class_name, 'EEM_') === 0) {
380
+			return 'load_model';
381
+		}
382
+		// EE_CPT_*_Strategy classes like EE_CPT_Event_Strategy, EE_CPT_Venue_Strategy, etc
383
+		// perform strpos() first to avoid loading regex every time we load a class
384
+		if (
385
+			strpos($class_name, 'EE_CPT_') === 0
386
+			&& preg_match('/^EE_CPT_([a-zA-Z]+)_Strategy$/', $class_name)
387
+		) {
388
+			return 'load_core';
389
+		}
390
+		$class_name = $this->getFqnForAlias($class_name);
391
+		return $this->_class_loaders[ $class_name ] ?? '';
392
+	}
393
+
394
+
395
+	/**
396
+	 * @return array
397
+	 */
398
+	public function class_loaders(): array
399
+	{
400
+		return $this->_class_loaders;
401
+	}
402
+
403
+
404
+	/**
405
+	 * adds an alias for a classname
406
+	 *
407
+	 * @param string $fqcn      the class name that should be used (concrete class to replace interface)
408
+	 * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
409
+	 * @param string $for_class the class that has the dependency (is type hinting for the interface)
410
+	 * @throws InvalidAliasException
411
+	 */
412
+	public function add_alias(string $fqcn, string $alias, string $for_class = '')
413
+	{
414
+		$this->class_cache->addAlias($fqcn, $alias, $for_class);
415
+	}
416
+
417
+
418
+	/**
419
+	 * Returns TRUE if the provided fully qualified name IS an alias
420
+	 * WHY?
421
+	 * Because if a class is type hinting for a concretion,
422
+	 * then why would we need to find another class to supply it?
423
+	 * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
424
+	 * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
425
+	 * Don't go looking for some substitute.
426
+	 * Whereas if a class is type hinting for an interface...
427
+	 * then we need to find an actual class to use.
428
+	 * So the interface IS the alias for some other FQN,
429
+	 * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
430
+	 * represents some other class.
431
+	 *
432
+	 * @param string $fqn
433
+	 * @param string $for_class
434
+	 * @return bool
435
+	 */
436
+	public function isAlias(string $fqn = '', string $for_class = ''): bool
437
+	{
438
+		return $this->class_cache->isAlias($fqn, $for_class);
439
+	}
440
+
441
+
442
+	/**
443
+	 * Returns a FQN for provided alias if one exists, otherwise returns the original $alias
444
+	 * functions recursively, so that multiple aliases can be used to drill down to a FQN
445
+	 *  for example:
446
+	 *      if the following two entries were added to the _aliases array:
447
+	 *          array(
448
+	 *              'interface_alias'           => 'some\namespace\interface'
449
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
450
+	 *          )
451
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
452
+	 *      to load an instance of 'some\namespace\classname'
453
+	 *
454
+	 * @param string $alias
455
+	 * @param string $for_class
456
+	 * @return string
457
+	 */
458
+	public function getFqnForAlias(string $alias = '', string $for_class = ''): string
459
+	{
460
+		return $this->class_cache->getFqnForAlias($alias, $for_class);
461
+	}
462
+
463
+
464
+	/**
465
+	 * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
466
+	 * if one exists, or whether a new object should be generated every time the requested class is loaded.
467
+	 * This is done by using the following class constants:
468
+	 *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
469
+	 *        EE_Dependency_Map::load_new_object - generates a new object every time
470
+	 */
471
+	protected function _register_core_dependencies()
472
+	{
473
+		$this->_dependency_map = [
474
+			'EE_Admin'                                                                                                           => [
475
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
476
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
477
+			],
478
+			'EE_Request_Handler'                                                                                                 => [
479
+				'EventEspresso\core\services\request\Request'  => EE_Dependency_Map::load_from_cache,
480
+				'EventEspresso\core\services\request\Response' => EE_Dependency_Map::load_from_cache,
481
+			],
482
+			'EE_System'                                                                                                          => [
483
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
484
+				'EE_Maintenance_Mode'                         => EE_Dependency_Map::load_from_cache,
485
+				'EE_Registry'                                 => EE_Dependency_Map::load_from_cache,
486
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
487
+				'EventEspresso\core\services\routing\Router'  => EE_Dependency_Map::load_from_cache,
488
+			],
489
+			'EE_Session'                                                                                                         => [
490
+				'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
491
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
492
+				'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
493
+				'EventEspresso\core\services\session\SessionStartHandler'  => EE_Dependency_Map::load_from_cache,
494
+				'EventEspresso\core\services\encryption\Base64Encoder'     => EE_Dependency_Map::load_from_cache,
495
+			],
496
+			'EE_Cart'                                                                                                            => [
497
+				'EE_Session' => EE_Dependency_Map::load_from_cache,
498
+			],
499
+			'EE_Messenger_Collection_Loader'                                                                                     => [
500
+				'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
501
+			],
502
+			'EE_Message_Type_Collection_Loader'                                                                                  => [
503
+				'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
504
+			],
505
+			'EE_Message_Resource_Manager'                                                                                        => [
506
+				'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
507
+				'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
508
+				'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
509
+			],
510
+			'EE_Message_Factory'                                                                                                 => [
511
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
512
+			],
513
+			'EE_messages'                                                                                                        => [
514
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
515
+			],
516
+			'EE_Messages_Generator'                                                                                              => [
517
+				'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
518
+				'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
519
+				'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
520
+				'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
521
+			],
522
+			'EE_Messages_Processor'                                                                                              => [
523
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
524
+			],
525
+			'EE_Messages_Queue'                                                                                                  => [
526
+				'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
527
+			],
528
+			'EE_Messages_Template_Defaults'                                                                                      => [
529
+				'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
530
+				'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
531
+			],
532
+			'EE_Message_To_Generate_From_Request'                                                                                => [
533
+				'EE_Message_Resource_Manager'                 => EE_Dependency_Map::load_from_cache,
534
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
535
+			],
536
+			'EventEspresso\core\services\commands\CommandBus'                                                                    => [
537
+				'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
538
+			],
539
+			'EventEspresso\services\commands\CommandHandler'                                                                     => [
540
+				'EE_Registry'         => EE_Dependency_Map::load_from_cache,
541
+				'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
542
+			],
543
+			'EventEspresso\core\services\commands\CommandHandlerManager'                                                         => [
544
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
545
+			],
546
+			'EventEspresso\core\services\commands\CompositeCommandHandler'                                                       => [
547
+				'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
548
+				'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
549
+			],
550
+			'EventEspresso\core\services\commands\CommandFactory'                                                                => [
551
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
552
+			],
553
+			'EventEspresso\core\services\commands\middleware\CapChecker'                                                         => [
554
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
555
+			],
556
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                                => [
557
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
558
+			],
559
+			'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                            => [
560
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
561
+			],
562
+			'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommandHandler'                          => [
563
+				'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
564
+			],
565
+			'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => [
566
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
567
+			],
568
+			'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => [
569
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
570
+			],
571
+			'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => [
572
+				'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
573
+			],
574
+			'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => [
575
+				'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
576
+			],
577
+			'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => [
578
+				'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
579
+			],
580
+			'EventEspresso\core\domain\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => [
581
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
582
+			],
583
+			'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                          => [
584
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
585
+			],
586
+			'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler'                                  => [
587
+				'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
588
+			],
589
+			'EventEspresso\core\domain\values\session\SessionLifespan'                                                           => [
590
+				'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
591
+			],
592
+			'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanForm'                                 => [
593
+				'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
594
+			],
595
+			'EventEspresso\caffeinated\admin\extend\registration_form\forms\SessionLifespanFormHandler'                          => [
596
+				'EventEspresso\core\domain\values\session\SessionLifespanOption' => EE_Dependency_Map::load_from_cache,
597
+			],
598
+			'EventEspresso\core\services\database\TableManager'                                                                  => [
599
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
600
+			],
601
+			'EE_Data_Migration_Class_Base'                                                                                       => [
602
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
603
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
604
+			],
605
+			'EE_DMS_Core_4_1_0'                                                                                                  => [
606
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
607
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
608
+			],
609
+			'EE_DMS_Core_4_2_0'                                                                                                  => [
610
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
611
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
612
+			],
613
+			'EE_DMS_Core_4_3_0'                                                                                                  => [
614
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
615
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
616
+			],
617
+			'EE_DMS_Core_4_4_0'                                                                                                  => [
618
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
619
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
620
+			],
621
+			'EE_DMS_Core_4_5_0'                                                                                                  => [
622
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
623
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
624
+			],
625
+			'EE_DMS_Core_4_6_0'                                                                                                  => [
626
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
627
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
628
+			],
629
+			'EE_DMS_Core_4_7_0'                                                                                                  => [
630
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
631
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
632
+			],
633
+			'EE_DMS_Core_4_8_0'                                                                                                  => [
634
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
635
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
636
+			],
637
+			'EE_DMS_Core_4_9_0'                                                                                                  => [
638
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
639
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
640
+			],
641
+			'EE_DMS_Core_4_10_0'                                                                                                 => [
642
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
643
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
644
+				'EE_DMS_Core_4_9_0'                                  => EE_Dependency_Map::load_from_cache,
645
+			],
646
+			'EE_DMS_Core_5_0_0'                                                                                                  => [
647
+				'EE_DMS_Core_4_10_0'                                 => EE_Dependency_Map::load_from_cache,
648
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
649
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
650
+			],
651
+			'EventEspresso\core\services\assets\I18nRegistry'                                                                    => [
652
+				'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
653
+			],
654
+			'EventEspresso\core\services\assets\Registry'                                                                        => [
655
+				'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_from_cache,
656
+				'EventEspresso\core\services\assets\AssetManifest'   => EE_Dependency_Map::load_from_cache,
657
+			],
658
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                                    => [
659
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
660
+			],
661
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                                     => [
662
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
663
+			],
664
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                               => [
665
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
666
+			],
667
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                       => [
668
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
669
+			],
670
+			'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                                     => [
671
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
672
+			],
673
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                               => [
674
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
675
+			],
676
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                                      => [
677
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
678
+			],
679
+			'EventEspresso\core\services\cache\BasicCacheManager'                                                                => [
680
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
681
+			],
682
+			'EventEspresso\core\services\cache\PostRelatedCacheManager'                                                          => [
683
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
684
+			],
685
+			'EventEspresso\core\domain\services\validation\email\EmailValidationService'                                         => [
686
+				'EE_Registration_Config'                     => EE_Dependency_Map::load_from_cache,
687
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
688
+			],
689
+			'EventEspresso\core\domain\values\EmailAddress'                                                                      => [
690
+				null,
691
+				'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
692
+			],
693
+			'EventEspresso\core\services\orm\ModelFieldFactory'                                                                  => [
694
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
695
+			],
696
+			'LEGACY_MODELS'                                                                                                      => [
697
+				null,
698
+				'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
699
+			],
700
+			'EE_Module_Request_Router'                                                                                           => [
701
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
702
+			],
703
+			'EE_Registration_Processor'                                                                                          => [
704
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
705
+			],
706
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'                                             => [
707
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
708
+				'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
709
+			],
710
+			'EventEspresso\caffeinated\modules\recaptcha_invisible\InvisibleRecaptcha'                                           => [
711
+				'EE_Registration_Config' => EE_Dependency_Map::load_from_cache,
712
+				'EE_Session'             => EE_Dependency_Map::load_from_cache,
713
+			],
714
+			'EventEspresso\modules\ticket_selector\DisplayTicketSelector'                                                        => [
715
+				'EventEspresso\core\domain\entities\users\CurrentUser' => EE_Dependency_Map::load_from_cache,
716
+				'EventEspresso\core\services\request\Request'          => EE_Dependency_Map::load_from_cache,
717
+				'EE_Ticket_Selector_Config'                            => EE_Dependency_Map::load_from_cache,
718
+			],
719
+			'EventEspresso\modules\ticket_selector\ProcessTicketSelector'                                                        => [
720
+				'EE_Core_Config'                                                          => EE_Dependency_Map::load_from_cache,
721
+				'EventEspresso\core\services\request\Request'                             => EE_Dependency_Map::load_from_cache,
722
+				'EE_Session'                                                              => EE_Dependency_Map::load_from_cache,
723
+				'EEM_Ticket'                                                              => EE_Dependency_Map::load_from_cache,
724
+				'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker' => EE_Dependency_Map::load_from_cache,
725
+			],
726
+			'EventEspresso\modules\ticket_selector\ProcessTicketSelectorPostData'                                                => [
727
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
728
+				'EEM_Event'                                   => EE_Dependency_Map::load_from_cache,
729
+			],
730
+			'EventEspresso\modules\ticket_selector\TicketDatetimeAvailabilityTracker'                                            => [
731
+				'EEM_Datetime' => EE_Dependency_Map::load_from_cache,
732
+			],
733
+			'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'                                     => [
734
+				'EE_Core_Config'                             => EE_Dependency_Map::load_from_cache,
735
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
736
+			],
737
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'                                       => [
738
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
739
+			],
740
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'                                      => [
741
+				'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
742
+			],
743
+			'EE_CPT_Strategy'                                                                                                    => [
744
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' => EE_Dependency_Map::load_from_cache,
745
+				'EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions' => EE_Dependency_Map::load_from_cache,
746
+			],
747
+			'EventEspresso\core\services\loaders\ObjectIdentifier'                                                               => [
748
+				'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
749
+			],
750
+			'EventEspresso\core\CPTs\CptQueryModifier'                                                                           => [
751
+				null,
752
+				null,
753
+				null,
754
+				'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
755
+				'EventEspresso\core\services\request\Request'     => EE_Dependency_Map::load_from_cache,
756
+				'EventEspresso\core\services\loaders\Loader'      => EE_Dependency_Map::load_from_cache,
757
+			],
758
+			'EventEspresso\core\services\dependencies\DependencyResolver'                                                        => [
759
+				'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
760
+				'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
761
+				'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
762
+			],
763
+			'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver'                                      => [
764
+				'EventEspresso\core\services\container\Mirror'            => EE_Dependency_Map::load_from_cache,
765
+				'EventEspresso\core\services\loaders\ClassInterfaceCache' => EE_Dependency_Map::load_from_cache,
766
+				'EE_Dependency_Map'                                       => EE_Dependency_Map::load_from_cache,
767
+			],
768
+			'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'                                                 => [
769
+				'EventEspresso\core\services\routing\RouteMatchSpecificationDependencyResolver' => EE_Dependency_Map::load_from_cache,
770
+				'EventEspresso\core\services\loaders\Loader'                                    => EE_Dependency_Map::load_from_cache,
771
+			],
772
+			'EventEspresso\core\services\routing\RouteMatchSpecificationManager'                                                 => [
773
+				'EventEspresso\core\services\routing\RouteMatchSpecificationCollection' => EE_Dependency_Map::load_from_cache,
774
+				'EventEspresso\core\services\routing\RouteMatchSpecificationFactory'    => EE_Dependency_Map::load_from_cache,
775
+			],
776
+			'EventEspresso\core\services\request\files\FilesDataHandler'                                                         => [
777
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
778
+			],
779
+			'EventEspressoBatchRequest\BatchRequestProcessor'                                                                    => [
780
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
781
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
782
+			],
783
+			'EventEspresso\core\domain\services\converters\RestApiSpoofer'                                                       => [
784
+				'WP_REST_Server'                                               => EE_Dependency_Map::load_from_cache,
785
+				'EED_Core_Rest_Api'                                            => EE_Dependency_Map::load_from_cache,
786
+				'EventEspresso\core\libraries\rest_api\controllers\model\Read' => EE_Dependency_Map::load_from_cache,
787
+				null,
788
+			],
789
+			'EventEspresso\core\services\routing\RouteHandler'                                                                   => [
790
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
791
+				'EventEspresso\core\services\json\JsonDataNodeHandler'                => EE_Dependency_Map::load_from_cache,
792
+				'EventEspresso\core\services\loaders\Loader'                          => EE_Dependency_Map::load_from_cache,
793
+				'EventEspresso\core\services\request\Request'                         => EE_Dependency_Map::load_from_cache,
794
+				'EventEspresso\core\services\routing\RouteCollection'                 => EE_Dependency_Map::load_from_cache,
795
+			],
796
+			'EventEspresso\core\services\json\JsonDataNodeHandler'                                                               => [
797
+				'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
798
+			],
799
+			'EventEspresso\core\services\routing\Router'                                                                         => [
800
+				'EE_Dependency_Map'                                => EE_Dependency_Map::load_from_cache,
801
+				'EventEspresso\core\services\loaders\Loader'       => EE_Dependency_Map::load_from_cache,
802
+				'EventEspresso\core\services\routing\RouteHandler' => EE_Dependency_Map::load_from_cache,
803
+			],
804
+			'EventEspresso\core\services\assets\AssetManifest'                                                                   => [
805
+				'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache,
806
+			],
807
+			'EventEspresso\core\services\assets\AssetManifestFactory'                                                            => [
808
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
809
+			],
810
+			'EventEspresso\core\services\assets\BaristaFactory'                                                                  => [
811
+				'EventEspresso\core\services\assets\AssetManifestFactory' => EE_Dependency_Map::load_from_cache,
812
+				'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
813
+			],
814
+			'EventEspresso\core\domain\services\capabilities\FeatureFlags'                                                       => [
815
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
816
+				'EventEspresso\core\domain\Domain'                                    => EE_Dependency_Map::load_from_cache,
817
+			],
818
+			'EventEspresso\core\services\addon\AddonManager'                                                                     => [
819
+				'EventEspresso\core\services\addon\AddonCollection'              => EE_Dependency_Map::load_from_cache,
820
+				'EventEspresso\core\Psr4Autoloader'                              => EE_Dependency_Map::load_from_cache,
821
+				'EventEspresso\core\services\addon\api\v1\RegisterAddon'         => EE_Dependency_Map::load_from_cache,
822
+				'EventEspresso\core\services\addon\api\IncompatibleAddonHandler' => EE_Dependency_Map::load_from_cache,
823
+				'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'  => EE_Dependency_Map::load_from_cache,
824
+			],
825
+			'EventEspresso\core\services\addon\api\ThirdPartyPluginHandler'                                                      => [
826
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
827
+			],
828
+			'EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion'                                                         => [
829
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
830
+			],
831
+			'EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'                                                         => [
832
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
833
+			],
834
+			'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'                                               => [
835
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
836
+				'EEM_Event'                                                   => EE_Dependency_Map::load_from_cache,
837
+				'EEM_Datetime'                                                => EE_Dependency_Map::load_from_cache,
838
+				'EEM_Registration'                                            => EE_Dependency_Map::load_from_cache,
839
+			],
840
+			'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'                                               => [
841
+				'EventEspresso\core\services\orm\tree_traversal\NodeGroupDao' => EE_Dependency_Map::load_from_cache,
842
+			],
843
+			'EventEspresso\core\services\request\CurrentPage'                                                                    => [
844
+				'EE_CPT_Strategy'                             => EE_Dependency_Map::load_from_cache,
845
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
846
+			],
847
+			'EventEspresso\core\services\shortcodes\LegacyShortcodesManager'                                                     => [
848
+				'EE_Registry'                                     => EE_Dependency_Map::load_from_cache,
849
+				'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
850
+			],
851
+			'EventEspresso\core\services\shortcodes\ShortcodesManager'                                                           => [
852
+				'EventEspresso\core\services\shortcodes\LegacyShortcodesManager' => EE_Dependency_Map::load_from_cache,
853
+				'EventEspresso\core\services\request\CurrentPage'                => EE_Dependency_Map::load_from_cache,
854
+			],
855
+			'EventEspresso\core\domain\entities\users\CurrentUser'                                                               => [
856
+				'EventEspresso\core\domain\entities\users\EventManagers' => EE_Dependency_Map::load_from_cache,
857
+			],
858
+			'EventEspresso\core\services\form\meta\InputTypes'                                                                   => [
859
+				'EventEspresso\core\services\form\meta\inputs\Block'    => EE_Dependency_Map::load_from_cache,
860
+				'EventEspresso\core\services\form\meta\inputs\Button'   => EE_Dependency_Map::load_from_cache,
861
+				'EventEspresso\core\services\form\meta\inputs\DateTime' => EE_Dependency_Map::load_from_cache,
862
+				'EventEspresso\core\services\form\meta\inputs\Input'    => EE_Dependency_Map::load_from_cache,
863
+				'EventEspresso\core\services\form\meta\inputs\Number'   => EE_Dependency_Map::load_from_cache,
864
+				'EventEspresso\core\services\form\meta\inputs\Phone'    => EE_Dependency_Map::load_from_cache,
865
+				'EventEspresso\core\services\form\meta\inputs\Select'   => EE_Dependency_Map::load_from_cache,
866
+				'EventEspresso\core\services\form\meta\inputs\Text'     => EE_Dependency_Map::load_from_cache,
867
+			],
868
+			'EventEspresso\core\domain\services\registration\form\v1\RegFormDependencyHandler'                                   => [
869
+				'EE_Dependency_Map' => EE_Dependency_Map::load_from_cache,
870
+			],
871
+			'EventEspresso\core\services\calculators\LineItemCalculator'                                                         => [
872
+				'EventEspresso\core\services\helpers\DecimalValues' => EE_Dependency_Map::load_from_cache,
873
+			],
874
+			'EventEspresso\core\services\helpers\DecimalValues'                                                                  => [
875
+				'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
876
+			],
877
+			'EE_Brewing_Regular'                                                                                                 => [
878
+				'EE_Dependency_Map'                                  => EE_Dependency_Map::load_from_cache,
879
+				'EventEspresso\core\services\loaders\Loader'         => EE_Dependency_Map::load_from_cache,
880
+				'EventEspresso\core\services\routing\RouteHandler'   => EE_Dependency_Map::load_from_cache,
881
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
882
+			],
883
+			'EventEspresso\core\domain\services\messages\MessageTemplateRequestData'                                             => [
884
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
885
+			],
886
+			'EventEspresso\core\domain\services\messages\MessageTemplateValidator'                                               => [
887
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
888
+			],
889
+			'EventEspresso\core\domain\services\messages\MessageTemplateManager'                                                 => [
890
+				'EEM_Message_Template'                                                   => EE_Dependency_Map::load_from_cache,
891
+				'EEM_Message_Template_Group'                                             => EE_Dependency_Map::load_from_cache,
892
+				'EventEspresso\core\domain\services\messages\MessageTemplateRequestData' => EE_Dependency_Map::load_from_cache,
893
+				'EventEspresso\core\domain\services\messages\MessageTemplateValidator'   => EE_Dependency_Map::load_from_cache,
894
+				'EventEspresso\core\services\request\Request'                            => EE_Dependency_Map::load_from_cache,
895
+			],
896
+			'EventEspresso\core\services\request\sanitizers\RequestSanitizer'                                                    => [
897
+				'EventEspresso\core\domain\services\validation\email\strategies\Basic' => EE_Dependency_Map::load_from_cache,
898
+			],
899
+		];
900
+	}
901
+
902
+
903
+	/**
904
+	 * Registers how core classes are loaded.
905
+	 * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
906
+	 *        'EE_Request_Handler' => 'load_core'
907
+	 *        'EE_Messages_Queue'  => 'load_lib'
908
+	 *        'EEH_Debug_Tools'    => 'load_helper'
909
+	 * or, if greater control is required, by providing a custom closure. For example:
910
+	 *        'Some_Class' => function () {
911
+	 *            return new Some_Class();
912
+	 *        },
913
+	 * This is required for instantiating dependencies
914
+	 * where an interface has been type hinted in a class constructor. For example:
915
+	 *        'Required_Interface' => function () {
916
+	 *            return new A_Class_That_Implements_Required_Interface();
917
+	 *        },
918
+	 */
919
+	protected function _register_core_class_loaders()
920
+	{
921
+		$this->_class_loaders = [
922
+			// load_core
923
+			'EE_Dependency_Map'                            => function () {
924
+				return $this;
925
+			},
926
+			'EE_Capabilities'                              => 'load_core',
927
+			'EE_Encryption'                                => 'load_core',
928
+			'EE_Front_Controller'                          => 'load_core',
929
+			'EE_Module_Request_Router'                     => 'load_core',
930
+			'EE_Registry'                                  => 'load_core',
931
+			'EE_Request'                                   => function () {
932
+				return $this->legacy_request;
933
+			},
934
+			'EventEspresso\core\services\request\Request'  => function () {
935
+				return $this->request;
936
+			},
937
+			'EventEspresso\core\services\request\Response' => function () {
938
+				return $this->response;
939
+			},
940
+			'EE_Base'                                      => 'load_core',
941
+			'EE_Request_Handler'                           => 'load_core',
942
+			'EE_Session'                                   => 'load_core',
943
+			'EE_Cron_Tasks'                                => 'load_core',
944
+			'EE_System'                                    => 'load_core',
945
+			'EE_Maintenance_Mode'                          => 'load_core',
946
+			'EE_Register_CPTs'                             => 'load_core',
947
+			'EE_Admin'                                     => 'load_core',
948
+			'EE_CPT_Strategy'                              => 'load_core',
949
+			// load_class
950
+			'EE_Registration_Processor'                    => 'load_class',
951
+			// load_lib
952
+			'EE_Message_Resource_Manager'                  => 'load_lib',
953
+			'EE_Message_Type_Collection'                   => 'load_lib',
954
+			'EE_Message_Type_Collection_Loader'            => 'load_lib',
955
+			'EE_Messenger_Collection'                      => 'load_lib',
956
+			'EE_Messenger_Collection_Loader'               => 'load_lib',
957
+			'EE_Messages_Processor'                        => 'load_lib',
958
+			'EE_Message_Repository'                        => 'load_lib',
959
+			'EE_Messages_Queue'                            => 'load_lib',
960
+			'EE_Messages_Data_Handler_Collection'          => 'load_lib',
961
+			'EE_Message_Template_Group_Collection'         => 'load_lib',
962
+			'EE_Payment_Method_Manager'                    => 'load_lib',
963
+			'EE_Payment_Processor'                         => 'load_core',
964
+			'EE_DMS_Core_4_1_0'                            => 'load_dms',
965
+			'EE_DMS_Core_4_2_0'                            => 'load_dms',
966
+			'EE_DMS_Core_4_3_0'                            => 'load_dms',
967
+			'EE_DMS_Core_4_5_0'                            => 'load_dms',
968
+			'EE_DMS_Core_4_6_0'                            => 'load_dms',
969
+			'EE_DMS_Core_4_7_0'                            => 'load_dms',
970
+			'EE_DMS_Core_4_8_0'                            => 'load_dms',
971
+			'EE_DMS_Core_4_9_0'                            => 'load_dms',
972
+			'EE_DMS_Core_4_10_0'                           => 'load_dms',
973
+			'EE_DMS_Core_5_0_0'                            => 'load_dms',
974
+			'EE_Messages_Generator'                        => static function () {
975
+				return EE_Registry::instance()->load_lib(
976
+					'Messages_Generator',
977
+					[],
978
+					false,
979
+					false
980
+				);
981
+			},
982
+			'EE_Messages_Template_Defaults'                => static function ($arguments = []) {
983
+				return EE_Registry::instance()->load_lib(
984
+					'Messages_Template_Defaults',
985
+					$arguments,
986
+					false,
987
+					false
988
+				);
989
+			},
990
+			// load_helper
991
+			'EEH_Parse_Shortcodes'                         => static function () {
992
+				if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
993
+					return new EEH_Parse_Shortcodes();
994
+				}
995
+				return null;
996
+			},
997
+			'EE_Template_Config'                           => static function () {
998
+				return EE_Config::instance()->template_settings;
999
+			},
1000
+			'EE_Currency_Config'                           => static function () {
1001
+				return EE_Currency_Config::getCurrencyConfig();
1002
+			},
1003
+			'EE_Registration_Config'                       => static function () {
1004
+				return EE_Config::instance()->registration;
1005
+			},
1006
+			'EE_Core_Config'                               => static function () {
1007
+				return EE_Config::instance()->core;
1008
+			},
1009
+			'EventEspresso\core\services\loaders\Loader'   => static function () {
1010
+				return LoaderFactory::getLoader();
1011
+			},
1012
+			'EE_Network_Config'                            => static function () {
1013
+				return EE_Network_Config::instance();
1014
+			},
1015
+			'EE_Config'                                    => static function () {
1016
+				return EE_Config::instance();
1017
+			},
1018
+			'EventEspresso\core\domain\Domain'             => static function () {
1019
+				return DomainFactory::getEventEspressoCoreDomain();
1020
+			},
1021
+			'EE_Admin_Config'                              => static function () {
1022
+				return EE_Config::instance()->admin;
1023
+			},
1024
+			'EE_Organization_Config'                       => static function () {
1025
+				return EE_Config::instance()->organization;
1026
+			},
1027
+			'EE_Network_Core_Config'                       => static function () {
1028
+				return EE_Network_Config::instance()->core;
1029
+			},
1030
+			'EE_Environment_Config'                        => static function () {
1031
+				return EE_Config::instance()->environment;
1032
+			},
1033
+			'EED_Core_Rest_Api'                            => static function () {
1034
+				return EED_Core_Rest_Api::instance();
1035
+			},
1036
+			'WP_REST_Server'                               => static function () {
1037
+				return rest_get_server();
1038
+			},
1039
+			'EventEspresso\core\Psr4Autoloader'            => static function () {
1040
+				return EE_Psr4AutoloaderInit::psr4_loader();
1041
+			},
1042
+			'EE_Ticket_Selector_Config'                    => function () {
1043
+				return EE_Config::instance()->template_settings->EED_Ticket_Selector;
1044
+			},
1045
+		];
1046
+	}
1047
+
1048
+
1049
+	/**
1050
+	 * can be used for supplying alternate names for classes,
1051
+	 * or for connecting interface names to instantiable classes
1052
+	 *
1053
+	 * @throws InvalidAliasException
1054
+	 */
1055
+	protected function _register_core_aliases()
1056
+	{
1057
+		$aliases = [
1058
+			'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
1059
+			'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
1060
+			'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
1061
+			'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
1062
+			'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
1063
+			'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
1064
+			'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1065
+			'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
1066
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
1067
+			'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
1068
+			'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\domain\services\commands\registration\CreateRegistrationCommand',
1069
+			'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationDetailsCommand',
1070
+			'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\domain\services\commands\registration\CopyRegistrationPaymentsCommand',
1071
+			'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\domain\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
1072
+			'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\domain\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
1073
+			'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\domain\services\commands\ticket\CreateTicketLineItemCommand',
1074
+			'CreateTransactionCommandHandler'                                              => 'EventEspresso\core\domain\services\commands\transaction\CreateTransactionCommandHandler',
1075
+			'CreateAttendeeCommandHandler'                                                 => 'EventEspresso\core\domain\services\commands\attendee\CreateAttendeeCommandHandler',
1076
+			'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
1077
+			'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
1078
+			'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1079
+			'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
1080
+			'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
1081
+			'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
1082
+			'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
1083
+			'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
1084
+			'CommandFactoryInterface'                                                      => 'EventEspresso\core\services\commands\CommandFactoryInterface',
1085
+			'EventEspresso\core\services\commands\CommandFactoryInterface'                 => 'EventEspresso\core\services\commands\CommandFactory',
1086
+			'EmailValidatorInterface'                                                      => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
1087
+			'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface'  => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
1088
+			'NoticeConverterInterface'                                                     => 'EventEspresso\core\services\notices\NoticeConverterInterface',
1089
+			'EventEspresso\core\services\notices\NoticeConverterInterface'                 => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
1090
+			'NoticesContainerInterface'                                                    => 'EventEspresso\core\services\notices\NoticesContainerInterface',
1091
+			'EventEspresso\core\services\notices\NoticesContainerInterface'                => 'EventEspresso\core\services\notices\NoticesContainer',
1092
+			'EventEspresso\core\services\request\RequestInterface'                         => 'EventEspresso\core\services\request\Request',
1093
+			'EventEspresso\core\services\request\ResponseInterface'                        => 'EventEspresso\core\services\request\Response',
1094
+			'EventEspresso\core\domain\DomainInterface'                                    => 'EventEspresso\core\domain\Domain',
1095
+			'Registration_Processor'                                                       => 'EE_Registration_Processor',
1096
+			'EventEspresso\core\services\assets\AssetManifestInterface'                    => 'EventEspresso\core\services\assets\AssetManifest',
1097
+		];
1098
+		foreach ($aliases as $alias => $fqn) {
1099
+			if (is_array($fqn)) {
1100
+				foreach ($fqn as $class => $for_class) {
1101
+					$this->class_cache->addAlias($class, $alias, $for_class);
1102
+				}
1103
+				continue;
1104
+			}
1105
+			$this->class_cache->addAlias($fqn, $alias);
1106
+		}
1107
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1108
+			$this->class_cache->addAlias(
1109
+				'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
1110
+				'EventEspresso\core\services\notices\NoticeConverterInterface'
1111
+			);
1112
+		}
1113
+	}
1114
+
1115
+
1116
+	public function debug($for_class = '')
1117
+	{
1118
+		if (method_exists($this->class_cache, 'debug')) {
1119
+			$this->class_cache->debug($for_class);
1120
+		}
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
1126
+	 * request Primarily used by unit tests.
1127
+	 */
1128
+	public function reset()
1129
+	{
1130
+		$this->_register_core_class_loaders();
1131
+		$this->_register_core_dependencies();
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * PLZ NOTE: a better name for this method would be is_alias()
1137
+	 * because it returns TRUE if the provided fully qualified name IS an alias
1138
+	 * WHY?
1139
+	 * Because if a class is type hinting for a concretion,
1140
+	 * then why would we need to find another class to supply it?
1141
+	 * ie: if a class asks for `Fully/Qualified/Namespace/SpecificClassName`,
1142
+	 * then give it an instance of `Fully/Qualified/Namespace/SpecificClassName`.
1143
+	 * Don't go looking for some substitute.
1144
+	 * Whereas if a class is type hinting for an interface...
1145
+	 * then we need to find an actual class to use.
1146
+	 * So the interface IS the alias for some other FQN,
1147
+	 * and we need to find out if `Fully/Qualified/Namespace/SomeInterface`
1148
+	 * represents some other class.
1149
+	 *
1150
+	 * @param string $fqn
1151
+	 * @param string $for_class
1152
+	 * @return bool
1153
+	 * @deprecated 4.9.62.p
1154
+	 */
1155
+	public function has_alias(string $fqn = '', string $for_class = ''): bool
1156
+	{
1157
+		return $this->isAlias($fqn, $for_class);
1158
+	}
1159
+
1160
+
1161
+	/**
1162
+	 * PLZ NOTE: a better name for this method would be get_fqn_for_alias()
1163
+	 * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias
1164
+	 * functions recursively, so that multiple aliases can be used to drill down to a FQN
1165
+	 *  for example:
1166
+	 *      if the following two entries were added to the _aliases array:
1167
+	 *          array(
1168
+	 *              'interface_alias'           => 'some\namespace\interface'
1169
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
1170
+	 *          )
1171
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
1172
+	 *      to load an instance of 'some\namespace\classname'
1173
+	 *
1174
+	 * @param string $alias
1175
+	 * @param string $for_class
1176
+	 * @return string
1177
+	 * @deprecated 4.9.62.p
1178
+	 */
1179
+	public function get_alias(string $alias = '', string $for_class = ''): string
1180
+	{
1181
+		return $this->getFqnForAlias($alias, $for_class);
1182
+	}
1183 1183
 }
Please login to merge, or discard this patch.
Spacing   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -208,8 +208,8 @@  discard block
 block discarded – undo
208 208
         }
209 209
         $class      = trim($class, '\\');
210 210
         $registered = false;
211
-        if (empty(EE_Dependency_Map::$_instance->_dependency_map[ $class ])) {
212
-            EE_Dependency_Map::$_instance->_dependency_map[ $class ] = [];
211
+        if (empty(EE_Dependency_Map::$_instance->_dependency_map[$class])) {
212
+            EE_Dependency_Map::$_instance->_dependency_map[$class] = [];
213 213
         }
214 214
         // we need to make sure that any aliases used when registering a dependency
215 215
         // get resolved to the correct class name
@@ -218,12 +218,12 @@  discard block
 block discarded – undo
218 218
             if (
219 219
                 $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
220 220
                 || ! isset(
221
-                    EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $dependency ],
222
-                    EE_Dependency_Map::$_instance->_dependency_map[ $class ][ $alias ]
221
+                    EE_Dependency_Map::$_instance->_dependency_map[$class][$dependency],
222
+                    EE_Dependency_Map::$_instance->_dependency_map[$class][$alias]
223 223
                 )
224 224
             ) {
225
-                unset($dependencies[ $dependency ]);
226
-                $dependencies[ $alias ] = $load_source;
225
+                unset($dependencies[$dependency]);
226
+                $dependencies[$alias] = $load_source;
227 227
                 $registered             = true;
228 228
             }
229 229
         }
@@ -233,19 +233,19 @@  discard block
 block discarded – undo
233 233
         // ie: with A = B + C, entries in B take precedence over duplicate entries in C
234 234
         // Union is way faster than array_merge() but should be used with caution...
235 235
         // especially with numerically indexed arrays
236
-        $dependencies += EE_Dependency_Map::$_instance->_dependency_map[ $class ];
236
+        $dependencies += EE_Dependency_Map::$_instance->_dependency_map[$class];
237 237
         // now we need to ensure that the resulting dependencies
238 238
         // array only has the entries that are required for the class
239 239
         // so first count how many dependencies were originally registered for the class
240
-        $dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]);
240
+        $dependency_count = count(EE_Dependency_Map::$_instance->_dependency_map[$class]);
241 241
         // if that count is non-zero (meaning dependencies were already registered)
242
-        EE_Dependency_Map::$_instance->_dependency_map[ $class ] = $dependency_count
242
+        EE_Dependency_Map::$_instance->_dependency_map[$class] = $dependency_count
243 243
             // then truncate the  final array to match that count
244 244
             ? array_slice($dependencies, 0, $dependency_count)
245 245
             // otherwise just take the incoming array because nothing previously existed
246 246
             : $dependencies;
247 247
         return $registered
248
-               || count(EE_Dependency_Map::$_instance->_dependency_map[ $class ]) === count($dependencies);
248
+               || count(EE_Dependency_Map::$_instance->_dependency_map[$class]) === count($dependencies);
249 249
     }
250 250
 
251 251
 
@@ -274,7 +274,7 @@  discard block
 block discarded – undo
274 274
      */
275 275
     public function registerClassLoader(string $class_name, $loader = 'load_core', bool $overwrite = false): bool
276 276
     {
277
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
277
+        if ( ! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
278 278
             throw new DomainException(
279 279
                 esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
280 280
             );
@@ -298,8 +298,8 @@  discard block
 block discarded – undo
298 298
             );
299 299
         }
300 300
         $class_name = EE_Dependency_Map::$_instance->getFqnForAlias($class_name);
301
-        if ($overwrite || ! isset(EE_Dependency_Map::$_instance->_class_loaders[ $class_name ])) {
302
-            EE_Dependency_Map::$_instance->_class_loaders[ $class_name ] = $loader;
301
+        if ($overwrite || ! isset(EE_Dependency_Map::$_instance->_class_loaders[$class_name])) {
302
+            EE_Dependency_Map::$_instance->_class_loaders[$class_name] = $loader;
303 303
             return true;
304 304
         }
305 305
         return false;
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
         if (strpos($class_name, 'EEM_') === 0) {
328 328
             $class_name = 'LEGACY_MODELS';
329 329
         }
330
-        return isset($this->_dependency_map[ $class_name ]);
330
+        return isset($this->_dependency_map[$class_name]);
331 331
     }
332 332
 
333 333
 
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
             $class_name = 'LEGACY_MODELS';
346 346
         }
347 347
         $dependency = $this->getFqnForAlias($dependency, $class_name);
348
-        return isset($this->_dependency_map[ $class_name ][ $dependency ]);
348
+        return isset($this->_dependency_map[$class_name][$dependency]);
349 349
     }
350 350
 
351 351
 
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
         }
365 365
         $dependency = $this->getFqnForAlias($dependency);
366 366
         return $this->has_dependency_for_class($class_name, $dependency)
367
-            ? $this->_dependency_map[ $class_name ][ $dependency ]
367
+            ? $this->_dependency_map[$class_name][$dependency]
368 368
             : EE_Dependency_Map::not_registered;
369 369
     }
370 370
 
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
             return 'load_core';
389 389
         }
390 390
         $class_name = $this->getFqnForAlias($class_name);
391
-        return $this->_class_loaders[ $class_name ] ?? '';
391
+        return $this->_class_loaders[$class_name] ?? '';
392 392
     }
393 393
 
394 394
 
@@ -920,7 +920,7 @@  discard block
 block discarded – undo
920 920
     {
921 921
         $this->_class_loaders = [
922 922
             // load_core
923
-            'EE_Dependency_Map'                            => function () {
923
+            'EE_Dependency_Map'                            => function() {
924 924
                 return $this;
925 925
             },
926 926
             'EE_Capabilities'                              => 'load_core',
@@ -928,13 +928,13 @@  discard block
 block discarded – undo
928 928
             'EE_Front_Controller'                          => 'load_core',
929 929
             'EE_Module_Request_Router'                     => 'load_core',
930 930
             'EE_Registry'                                  => 'load_core',
931
-            'EE_Request'                                   => function () {
931
+            'EE_Request'                                   => function() {
932 932
                 return $this->legacy_request;
933 933
             },
934
-            'EventEspresso\core\services\request\Request'  => function () {
934
+            'EventEspresso\core\services\request\Request'  => function() {
935 935
                 return $this->request;
936 936
             },
937
-            'EventEspresso\core\services\request\Response' => function () {
937
+            'EventEspresso\core\services\request\Response' => function() {
938 938
                 return $this->response;
939 939
             },
940 940
             'EE_Base'                                      => 'load_core',
@@ -971,7 +971,7 @@  discard block
 block discarded – undo
971 971
             'EE_DMS_Core_4_9_0'                            => 'load_dms',
972 972
             'EE_DMS_Core_4_10_0'                           => 'load_dms',
973 973
             'EE_DMS_Core_5_0_0'                            => 'load_dms',
974
-            'EE_Messages_Generator'                        => static function () {
974
+            'EE_Messages_Generator'                        => static function() {
975 975
                 return EE_Registry::instance()->load_lib(
976 976
                     'Messages_Generator',
977 977
                     [],
@@ -979,7 +979,7 @@  discard block
 block discarded – undo
979 979
                     false
980 980
                 );
981 981
             },
982
-            'EE_Messages_Template_Defaults'                => static function ($arguments = []) {
982
+            'EE_Messages_Template_Defaults'                => static function($arguments = []) {
983 983
                 return EE_Registry::instance()->load_lib(
984 984
                     'Messages_Template_Defaults',
985 985
                     $arguments,
@@ -988,58 +988,58 @@  discard block
 block discarded – undo
988 988
                 );
989 989
             },
990 990
             // load_helper
991
-            'EEH_Parse_Shortcodes'                         => static function () {
991
+            'EEH_Parse_Shortcodes'                         => static function() {
992 992
                 if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
993 993
                     return new EEH_Parse_Shortcodes();
994 994
                 }
995 995
                 return null;
996 996
             },
997
-            'EE_Template_Config'                           => static function () {
997
+            'EE_Template_Config'                           => static function() {
998 998
                 return EE_Config::instance()->template_settings;
999 999
             },
1000
-            'EE_Currency_Config'                           => static function () {
1000
+            'EE_Currency_Config'                           => static function() {
1001 1001
                 return EE_Currency_Config::getCurrencyConfig();
1002 1002
             },
1003
-            'EE_Registration_Config'                       => static function () {
1003
+            'EE_Registration_Config'                       => static function() {
1004 1004
                 return EE_Config::instance()->registration;
1005 1005
             },
1006
-            'EE_Core_Config'                               => static function () {
1006
+            'EE_Core_Config'                               => static function() {
1007 1007
                 return EE_Config::instance()->core;
1008 1008
             },
1009
-            'EventEspresso\core\services\loaders\Loader'   => static function () {
1009
+            'EventEspresso\core\services\loaders\Loader'   => static function() {
1010 1010
                 return LoaderFactory::getLoader();
1011 1011
             },
1012
-            'EE_Network_Config'                            => static function () {
1012
+            'EE_Network_Config'                            => static function() {
1013 1013
                 return EE_Network_Config::instance();
1014 1014
             },
1015
-            'EE_Config'                                    => static function () {
1015
+            'EE_Config'                                    => static function() {
1016 1016
                 return EE_Config::instance();
1017 1017
             },
1018
-            'EventEspresso\core\domain\Domain'             => static function () {
1018
+            'EventEspresso\core\domain\Domain'             => static function() {
1019 1019
                 return DomainFactory::getEventEspressoCoreDomain();
1020 1020
             },
1021
-            'EE_Admin_Config'                              => static function () {
1021
+            'EE_Admin_Config'                              => static function() {
1022 1022
                 return EE_Config::instance()->admin;
1023 1023
             },
1024
-            'EE_Organization_Config'                       => static function () {
1024
+            'EE_Organization_Config'                       => static function() {
1025 1025
                 return EE_Config::instance()->organization;
1026 1026
             },
1027
-            'EE_Network_Core_Config'                       => static function () {
1027
+            'EE_Network_Core_Config'                       => static function() {
1028 1028
                 return EE_Network_Config::instance()->core;
1029 1029
             },
1030
-            'EE_Environment_Config'                        => static function () {
1030
+            'EE_Environment_Config'                        => static function() {
1031 1031
                 return EE_Config::instance()->environment;
1032 1032
             },
1033
-            'EED_Core_Rest_Api'                            => static function () {
1033
+            'EED_Core_Rest_Api'                            => static function() {
1034 1034
                 return EED_Core_Rest_Api::instance();
1035 1035
             },
1036
-            'WP_REST_Server'                               => static function () {
1036
+            'WP_REST_Server'                               => static function() {
1037 1037
                 return rest_get_server();
1038 1038
             },
1039
-            'EventEspresso\core\Psr4Autoloader'            => static function () {
1039
+            'EventEspresso\core\Psr4Autoloader'            => static function() {
1040 1040
                 return EE_Psr4AutoloaderInit::psr4_loader();
1041 1041
             },
1042
-            'EE_Ticket_Selector_Config'                    => function () {
1042
+            'EE_Ticket_Selector_Config'                    => function() {
1043 1043
                 return EE_Config::instance()->template_settings->EED_Ticket_Selector;
1044 1044
             },
1045 1045
         ];
@@ -1104,7 +1104,7 @@  discard block
 block discarded – undo
1104 1104
             }
1105 1105
             $this->class_cache->addAlias($fqn, $alias);
1106 1106
         }
1107
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1107
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1108 1108
             $this->class_cache->addAlias(
1109 1109
                 'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
1110 1110
                 'EventEspresso\core\services\notices\NoticeConverterInterface'
Please login to merge, or discard this patch.
core/helpers/EEH_Class_Tools.helper.php 2 patches
Indentation   +122 added lines, -122 removed lines patch added patch discarded remove patch
@@ -13,137 +13,137 @@
 block discarded – undo
13 13
  */
14 14
 class EEH_Class_Tools
15 15
 {
16
-    public static $i         = 0;
16
+	public static $i         = 0;
17 17
 
18
-    public static $file_line = null;
18
+	public static $file_line = null;
19 19
 
20 20
 
21
-    /**
22
-     *  get_called_class - for PHP versions < 5.3
23
-     *
24
-     * @access     public
25
-     * @author     origins:  http://stackoverflow.com/a/1542045
26
-     *  return string
27
-     */
28
-    public static function get_called_class()
29
-    {
30
-        $backtrace = debug_backtrace();
31
-        if (
32
-            isset($backtrace[2])
33
-            && is_array($backtrace[2])
34
-            && isset($backtrace[2]['class'])
35
-            && ! isset($backtrace[2]['file'])
36
-        ) {
37
-            return $backtrace[2]['class'];
38
-        } elseif (
39
-            isset($backtrace[3])
40
-            && is_array($backtrace[3])
41
-            && isset($backtrace[3]['class'])
42
-            && ! isset($backtrace[3]['file'])
43
-        ) {
44
-            return $backtrace[3]['class'];
45
-        } elseif (
46
-            isset($backtrace[2])
47
-            && is_array($backtrace[2])
48
-            && isset($backtrace[2]['file'])
49
-            && isset($backtrace[2]['line'])
50
-        ) {
51
-            if (self::$file_line == $backtrace[2]['file'] . $backtrace[2]['line']) {
52
-                self::$i++;
53
-            } else {
54
-                self::$i         = 0;
55
-                self::$file_line = $backtrace[2]['file'] . $backtrace[2]['line'];
56
-            }
57
-            // was  class method called via call_user_func ?
58
-            if (
59
-                $backtrace[2]['function'] == 'call_user_func' && isset($backtrace[2]['args'])
60
-                && is_array(
61
-                    $backtrace[2]['args']
62
-                )
63
-            ) {
64
-                if (isset($backtrace[2]['args'][0]) && isset($backtrace[2]['args'][0][0])) {
65
-                    $called_class = $backtrace[2]['args'][0][0];
66
-                    // is it an EE function ?
67
-                    if (strpos($called_class, 'EE') === 0) {
68
-                        $prefix_chars = strpos($called_class, '_') + 1;
69
-                        $prefix       = substr($called_class, 0, $prefix_chars);
70
-                        $classname    = substr($called_class, $prefix_chars, strlen($called_class));
71
-                        $classname    =
72
-                            $prefix . str_replace(' ', '_', ucwords(strtolower(str_replace('_', ' ', $classname))));
73
-                        return $classname;
74
-                    }
75
-                }
76
-            } else {
77
-                $lines = file($backtrace[2]['file']);
78
-                preg_match_all(
79
-                    '/([a-zA-Z0-9_]+)::' . $backtrace[2]['function'] . '/',
80
-                    $lines[ $backtrace[2]['line'] - 1 ],
81
-                    $matches
82
-                );
83
-                if (isset($matches[1]) && isset($matches[1][ self::$i ])) {
84
-                    return $matches[1][ self::$i ];
85
-                }
86
-            }
87
-        }
88
-        return false;
89
-    }
21
+	/**
22
+	 *  get_called_class - for PHP versions < 5.3
23
+	 *
24
+	 * @access     public
25
+	 * @author     origins:  http://stackoverflow.com/a/1542045
26
+	 *  return string
27
+	 */
28
+	public static function get_called_class()
29
+	{
30
+		$backtrace = debug_backtrace();
31
+		if (
32
+			isset($backtrace[2])
33
+			&& is_array($backtrace[2])
34
+			&& isset($backtrace[2]['class'])
35
+			&& ! isset($backtrace[2]['file'])
36
+		) {
37
+			return $backtrace[2]['class'];
38
+		} elseif (
39
+			isset($backtrace[3])
40
+			&& is_array($backtrace[3])
41
+			&& isset($backtrace[3]['class'])
42
+			&& ! isset($backtrace[3]['file'])
43
+		) {
44
+			return $backtrace[3]['class'];
45
+		} elseif (
46
+			isset($backtrace[2])
47
+			&& is_array($backtrace[2])
48
+			&& isset($backtrace[2]['file'])
49
+			&& isset($backtrace[2]['line'])
50
+		) {
51
+			if (self::$file_line == $backtrace[2]['file'] . $backtrace[2]['line']) {
52
+				self::$i++;
53
+			} else {
54
+				self::$i         = 0;
55
+				self::$file_line = $backtrace[2]['file'] . $backtrace[2]['line'];
56
+			}
57
+			// was  class method called via call_user_func ?
58
+			if (
59
+				$backtrace[2]['function'] == 'call_user_func' && isset($backtrace[2]['args'])
60
+				&& is_array(
61
+					$backtrace[2]['args']
62
+				)
63
+			) {
64
+				if (isset($backtrace[2]['args'][0]) && isset($backtrace[2]['args'][0][0])) {
65
+					$called_class = $backtrace[2]['args'][0][0];
66
+					// is it an EE function ?
67
+					if (strpos($called_class, 'EE') === 0) {
68
+						$prefix_chars = strpos($called_class, '_') + 1;
69
+						$prefix       = substr($called_class, 0, $prefix_chars);
70
+						$classname    = substr($called_class, $prefix_chars, strlen($called_class));
71
+						$classname    =
72
+							$prefix . str_replace(' ', '_', ucwords(strtolower(str_replace('_', ' ', $classname))));
73
+						return $classname;
74
+					}
75
+				}
76
+			} else {
77
+				$lines = file($backtrace[2]['file']);
78
+				preg_match_all(
79
+					'/([a-zA-Z0-9_]+)::' . $backtrace[2]['function'] . '/',
80
+					$lines[ $backtrace[2]['line'] - 1 ],
81
+					$matches
82
+				);
83
+				if (isset($matches[1]) && isset($matches[1][ self::$i ])) {
84
+					return $matches[1][ self::$i ];
85
+				}
86
+			}
87
+		}
88
+		return false;
89
+	}
90 90
 
91 91
 
92
-    /**
93
-     *  get_class_names_for_all_callbacks_on_hook
94
-     * returns an array of names for all classes that have methods registered as callbacks for the given action or
95
-     * filter hook
96
-     *
97
-     * @access     public
98
-     * @param string $hook
99
-     * @return     array
100
-     */
101
-    public static function get_class_names_for_all_callbacks_on_hook($hook = null)
102
-    {
103
-        // moved this function into new class since this class is now deprecated
104
-        return WordPressHooks::getClassNamesForAllCallbacksOnHook($hook);
105
-    }
92
+	/**
93
+	 *  get_class_names_for_all_callbacks_on_hook
94
+	 * returns an array of names for all classes that have methods registered as callbacks for the given action or
95
+	 * filter hook
96
+	 *
97
+	 * @access     public
98
+	 * @param string $hook
99
+	 * @return     array
100
+	 */
101
+	public static function get_class_names_for_all_callbacks_on_hook($hook = null)
102
+	{
103
+		// moved this function into new class since this class is now deprecated
104
+		return WordPressHooks::getClassNamesForAllCallbacksOnHook($hook);
105
+	}
106 106
 
107 107
 
108
-    /**
109
-     *  property_exists() with fallback for PHP versions < 5.3
110
-     *
111
-     * @access     public
112
-     * @param mixed object | string   $class
113
-     * @param string $property
114
-     * @return         boolean
115
-     * @throws ReflectionException
116
-     */
117
-    public static function has_property($class = null, $property = null)
118
-    {
119
-        // if $class or $property don't exist, then get out, cuz that would be like... fatal dude
120
-        if (empty($class) || empty($property)) {
121
-            return false;
122
-        }
123
-        // if your hosting company doesn't cut the mustard
124
-        if (version_compare(PHP_VERSION, '5.3.0') < 0) {
125
-            // just in case $class is an actual instantiated object
126
-            if (is_object($class)) {
127
-                return isset($class->{$property}) ? true : false;
128
-            } else {
129
-                // use reflection for < PHP 5.3 to get details using just the class name
130
-                $reflector = new ReflectionClass($class);
131
-                return $reflector->hasProperty($property);
132
-            }
133
-        } else {
134
-            // or try regular property exists method which works as expected in PHP 5.3+
135
-            return property_exists($class, $property);
136
-        }
137
-    }
108
+	/**
109
+	 *  property_exists() with fallback for PHP versions < 5.3
110
+	 *
111
+	 * @access     public
112
+	 * @param mixed object | string   $class
113
+	 * @param string $property
114
+	 * @return         boolean
115
+	 * @throws ReflectionException
116
+	 */
117
+	public static function has_property($class = null, $property = null)
118
+	{
119
+		// if $class or $property don't exist, then get out, cuz that would be like... fatal dude
120
+		if (empty($class) || empty($property)) {
121
+			return false;
122
+		}
123
+		// if your hosting company doesn't cut the mustard
124
+		if (version_compare(PHP_VERSION, '5.3.0') < 0) {
125
+			// just in case $class is an actual instantiated object
126
+			if (is_object($class)) {
127
+				return isset($class->{$property}) ? true : false;
128
+			} else {
129
+				// use reflection for < PHP 5.3 to get details using just the class name
130
+				$reflector = new ReflectionClass($class);
131
+				return $reflector->hasProperty($property);
132
+			}
133
+		} else {
134
+			// or try regular property exists method which works as expected in PHP 5.3+
135
+			return property_exists($class, $property);
136
+		}
137
+	}
138 138
 }
139 139
 
140 140
 // if PHP version < 5.3
141 141
 if (! function_exists('get_called_class')) {
142
-    /**
143
-     * @return string
144
-     */
145
-    function get_called_class()
146
-    {
147
-        return EEH_Class_Tools::get_called_class();
148
-    }
142
+	/**
143
+	 * @return string
144
+	 */
145
+	function get_called_class()
146
+	{
147
+		return EEH_Class_Tools::get_called_class();
148
+	}
149 149
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -48,11 +48,11 @@  discard block
 block discarded – undo
48 48
             && isset($backtrace[2]['file'])
49 49
             && isset($backtrace[2]['line'])
50 50
         ) {
51
-            if (self::$file_line == $backtrace[2]['file'] . $backtrace[2]['line']) {
51
+            if (self::$file_line == $backtrace[2]['file'].$backtrace[2]['line']) {
52 52
                 self::$i++;
53 53
             } else {
54 54
                 self::$i         = 0;
55
-                self::$file_line = $backtrace[2]['file'] . $backtrace[2]['line'];
55
+                self::$file_line = $backtrace[2]['file'].$backtrace[2]['line'];
56 56
             }
57 57
             // was  class method called via call_user_func ?
58 58
             if (
@@ -69,19 +69,19 @@  discard block
 block discarded – undo
69 69
                         $prefix       = substr($called_class, 0, $prefix_chars);
70 70
                         $classname    = substr($called_class, $prefix_chars, strlen($called_class));
71 71
                         $classname    =
72
-                            $prefix . str_replace(' ', '_', ucwords(strtolower(str_replace('_', ' ', $classname))));
72
+                            $prefix.str_replace(' ', '_', ucwords(strtolower(str_replace('_', ' ', $classname))));
73 73
                         return $classname;
74 74
                     }
75 75
                 }
76 76
             } else {
77 77
                 $lines = file($backtrace[2]['file']);
78 78
                 preg_match_all(
79
-                    '/([a-zA-Z0-9_]+)::' . $backtrace[2]['function'] . '/',
80
-                    $lines[ $backtrace[2]['line'] - 1 ],
79
+                    '/([a-zA-Z0-9_]+)::'.$backtrace[2]['function'].'/',
80
+                    $lines[$backtrace[2]['line'] - 1],
81 81
                     $matches
82 82
                 );
83
-                if (isset($matches[1]) && isset($matches[1][ self::$i ])) {
84
-                    return $matches[1][ self::$i ];
83
+                if (isset($matches[1]) && isset($matches[1][self::$i])) {
84
+                    return $matches[1][self::$i];
85 85
                 }
86 86
             }
87 87
         }
@@ -138,7 +138,7 @@  discard block
 block discarded – undo
138 138
 }
139 139
 
140 140
 // if PHP version < 5.3
141
-if (! function_exists('get_called_class')) {
141
+if ( ! function_exists('get_called_class')) {
142 142
     /**
143 143
      * @return string
144 144
      */
Please login to merge, or discard this patch.
core/helpers/EEH_Line_Item.helper.php 2 patches
Indentation   +2201 added lines, -2201 removed lines patch added patch discarded remove patch
@@ -21,2205 +21,2205 @@
 block discarded – undo
21 21
  */
22 22
 class EEH_Line_Item
23 23
 {
24
-    /**
25
-     * @var EE_Line_Item[]|null
26
-     */
27
-    private static ?array $global_taxes = null;
28
-
29
-
30
-    /**
31
-     * Adds a simple item (unrelated to any other model object) to the provided PARENT line item.
32
-     * Does NOT automatically re-calculate the line item totals or update the related transaction.
33
-     * You should call recalculate_total_including_taxes() on the grant total line item after this
34
-     * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
35
-     * to keep the registration final prices in-sync with the transaction's total.
36
-     *
37
-     * @param EE_Line_Item $parent_line_item
38
-     * @param string       $name
39
-     * @param float        $unit_price
40
-     * @param string       $description
41
-     * @param int          $quantity
42
-     * @param boolean      $taxable
43
-     * @param string|null  $code if set to a value, ensures there is only one line item with that code
44
-     * @param bool         $return_item
45
-     * @param bool         $recalculate_totals
46
-     * @return boolean|EE_Line_Item success
47
-     * @throws EE_Error
48
-     * @throws ReflectionException
49
-     */
50
-    public static function add_unrelated_item(
51
-        EE_Line_Item $parent_line_item,
52
-        string $name,
53
-        float $unit_price,
54
-        string $description = '',
55
-        int $quantity = 1,
56
-        bool $taxable = false,
57
-        ?string $code = null,
58
-        bool $return_item = false,
59
-        bool $recalculate_totals = true
60
-    ) {
61
-        $items_subtotal = self::get_pre_tax_subtotal($parent_line_item);
62
-        $line_item      = EE_Line_Item::new_instance(
63
-            [
64
-                'LIN_name'       => $name,
65
-                'LIN_desc'       => $description,
66
-                'LIN_unit_price' => $unit_price,
67
-                'LIN_quantity'   => $quantity,
68
-                'LIN_percent'    => null,
69
-                'LIN_is_taxable' => $taxable,
70
-                'LIN_order'      => count($items_subtotal->children()),
71
-                'LIN_total'      => $unit_price * $quantity,
72
-                'LIN_type'       => EEM_Line_Item::type_line_item,
73
-                'LIN_code'       => $code,
74
-            ]
75
-        );
76
-        $line_item      = apply_filters(
77
-            'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
78
-            $line_item,
79
-            $parent_line_item
80
-        );
81
-        $added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
82
-        return $return_item ? $line_item : $added;
83
-    }
84
-
85
-
86
-    /**
87
-     * Adds a simple item ( unrelated to any other model object) to the total line item,
88
-     * in the correct spot in the line item tree. Does not automatically
89
-     * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's
90
-     * registrations' final prices (which should probably change because of this).
91
-     * You should call recalculate_total_including_taxes() on the grand total line item, then
92
-     * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices()
93
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
94
-     *
95
-     * @param EE_Line_Item $parent_line_item
96
-     * @param string       $name
97
-     * @param float        $percentage_amount
98
-     * @param string       $description
99
-     * @param boolean      $taxable
100
-     * @param string|null  $code
101
-     * @param bool         $return_item
102
-     * @return boolean|EE_Line_Item success
103
-     * @throws EE_Error
104
-     * @throws ReflectionException
105
-     */
106
-    public static function add_percentage_based_item(
107
-        EE_Line_Item $parent_line_item,
108
-        string $name,
109
-        float $percentage_amount,
110
-        string $description = '',
111
-        bool $taxable = false,
112
-        ?string $code = null,
113
-        bool $return_item = false
114
-    ) {
115
-        $total     = $percentage_amount * $parent_line_item->total() / 100;
116
-        $line_item = EE_Line_Item::new_instance(
117
-            [
118
-                'LIN_name'       => $name,
119
-                'LIN_desc'       => $description,
120
-                'LIN_unit_price' => 0,
121
-                'LIN_percent'    => $percentage_amount,
122
-                'LIN_quantity'   => 1,
123
-                'LIN_is_taxable' => $taxable,
124
-                'LIN_total'      => $total,
125
-                'LIN_type'       => EEM_Line_Item::type_line_item,
126
-                'LIN_parent'     => $parent_line_item->ID(),
127
-                'LIN_code'       => $code,
128
-            ]
129
-        );
130
-        $line_item = apply_filters(
131
-            'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
132
-            $line_item
133
-        );
134
-        $added     = $parent_line_item->add_child_line_item($line_item, false);
135
-        return $return_item ? $line_item : $added;
136
-    }
137
-
138
-
139
-    /**
140
-     * Returns the new line item created by adding a purchase of the ticket
141
-     * ensures that ticket line item is saved, and that cart total has been recalculated.
142
-     * If this ticket has already been purchased, just increments its count.
143
-     * Automatically re-calculates the line item totals and updates the related transaction. But
144
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
145
-     * should probably change because of this).
146
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
147
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
148
-     *
149
-     * @param EE_Line_Item|null $total_line_item grand total line item of type EEM_Line_Item::type_total
150
-     * @param EE_Ticket         $ticket
151
-     * @param int               $qty
152
-     * @return EE_Line_Item
153
-     * @throws EE_Error
154
-     * @throws ReflectionException
155
-     */
156
-    public static function add_ticket_purchase(
157
-        ?EE_Line_Item $total_line_item,
158
-        EE_Ticket $ticket,
159
-        int $qty = 1
160
-    ): ?EE_Line_Item {
161
-        if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
162
-            throw new EE_Error(
163
-                sprintf(
164
-                    esc_html__(
165
-                        'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.',
166
-                        'event_espresso'
167
-                    ),
168
-                    $ticket->ID(),
169
-                    $total_line_item->ID()
170
-                )
171
-            );
172
-        }
173
-        // either increment the qty for an existing ticket
174
-        $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty);
175
-        // or add a new one
176
-        if (! $line_item instanceof EE_Line_Item) {
177
-            $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty);
178
-        }
179
-        $total_line_item->recalculate_total_including_taxes();
180
-        return $line_item;
181
-    }
182
-
183
-
184
-    /**
185
-     * Returns the new line item created by adding a purchase of the ticket
186
-     *
187
-     * @param EE_Line_Item|null $total_line_item
188
-     * @param EE_Ticket         $ticket
189
-     * @param int               $qty
190
-     * @return EE_Line_Item
191
-     * @throws EE_Error
192
-     * @throws InvalidArgumentException
193
-     * @throws InvalidDataTypeException
194
-     * @throws InvalidInterfaceException
195
-     * @throws ReflectionException
196
-     */
197
-    public static function increment_ticket_qty_if_already_in_cart(
198
-        ?EE_Line_Item $total_line_item,
199
-        EE_Ticket $ticket,
200
-        int $qty = 1
201
-    ): ?EE_Line_Item {
202
-        $line_item = null;
203
-        if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) {
204
-            $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
205
-            foreach ($ticket_line_items as $ticket_line_item) {
206
-                if (
207
-                    $ticket_line_item instanceof EE_Line_Item
208
-                    && $ticket_line_item->OBJ_ID() === $ticket->ID()
209
-                ) {
210
-                    $line_item = $ticket_line_item;
211
-                    break;
212
-                }
213
-            }
214
-        }
215
-        if ($line_item instanceof EE_Line_Item) {
216
-            EEH_Line_Item::increment_quantity($line_item, $qty);
217
-            return $line_item;
218
-        }
219
-        return null;
220
-    }
221
-
222
-
223
-    /**
224
-     * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected).
225
-     * Does NOT save or recalculate other line items totals
226
-     *
227
-     * @param EE_Line_Item $line_item
228
-     * @param int          $qty
229
-     * @return void
230
-     * @throws EE_Error
231
-     * @throws InvalidArgumentException
232
-     * @throws InvalidDataTypeException
233
-     * @throws InvalidInterfaceException
234
-     * @throws ReflectionException
235
-     */
236
-    public static function increment_quantity(EE_Line_Item $line_item, int $qty = 1)
237
-    {
238
-        if (! $line_item->is_percent()) {
239
-            $qty += $line_item->quantity();
240
-            $line_item->set_quantity($qty);
241
-            $line_item->set_total($line_item->unit_price() * $qty);
242
-            $line_item->save();
243
-        }
244
-        foreach ($line_item->children() as $child) {
245
-            if ($child->is_sub_line_item()) {
246
-                EEH_Line_Item::update_quantity($child, $qty);
247
-            }
248
-        }
249
-    }
250
-
251
-
252
-    /**
253
-     * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected).
254
-     * Does NOT save or recalculate other line items totals
255
-     *
256
-     * @param EE_Line_Item $line_item
257
-     * @param int          $qty
258
-     * @return void
259
-     * @throws EE_Error
260
-     * @throws InvalidArgumentException
261
-     * @throws InvalidDataTypeException
262
-     * @throws InvalidInterfaceException
263
-     * @throws ReflectionException
264
-     */
265
-    public static function decrement_quantity(EE_Line_Item $line_item, int $qty = 1)
266
-    {
267
-        if (! $line_item->is_percent()) {
268
-            $qty = $line_item->quantity() - $qty;
269
-            $qty = max($qty, 0);
270
-            $line_item->set_quantity($qty);
271
-            $line_item->set_total($line_item->unit_price() * $qty);
272
-            $line_item->save();
273
-        }
274
-        foreach ($line_item->children() as $child) {
275
-            if ($child->is_sub_line_item()) {
276
-                EEH_Line_Item::update_quantity($child, $qty);
277
-            }
278
-        }
279
-    }
280
-
281
-
282
-    /**
283
-     * Updates the line item and its children's quantities to the specified number.
284
-     * Does NOT save them or recalculate totals.
285
-     *
286
-     * @param EE_Line_Item $line_item
287
-     * @param int          $new_quantity
288
-     * @throws EE_Error
289
-     * @throws InvalidArgumentException
290
-     * @throws InvalidDataTypeException
291
-     * @throws InvalidInterfaceException
292
-     * @throws ReflectionException
293
-     */
294
-    public static function update_quantity(EE_Line_Item $line_item, int $new_quantity)
295
-    {
296
-        if (! $line_item->is_percent()) {
297
-            $line_item->set_quantity($new_quantity);
298
-            $line_item->set_total($line_item->unit_price() * $new_quantity);
299
-            $line_item->save();
300
-        }
301
-        foreach ($line_item->children() as $child) {
302
-            if ($child->is_sub_line_item()) {
303
-                EEH_Line_Item::update_quantity($child, $new_quantity);
304
-            }
305
-        }
306
-    }
307
-
308
-
309
-    /**
310
-     * Returns the new line item created by adding a purchase of the ticket
311
-     *
312
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
313
-     * @param EE_Ticket    $ticket
314
-     * @param int          $qty
315
-     * @return EE_Line_Item
316
-     * @throws EE_Error
317
-     * @throws InvalidArgumentException
318
-     * @throws InvalidDataTypeException
319
-     * @throws InvalidInterfaceException
320
-     * @throws ReflectionException
321
-     */
322
-    public static function create_ticket_line_item(
323
-        EE_Line_Item $total_line_item,
324
-        EE_Ticket $ticket,
325
-        int $qty = 1
326
-    ): EE_Line_Item {
327
-        $datetimes           = $ticket->datetimes();
328
-        $first_datetime      = reset($datetimes);
329
-        $first_datetime_name = esc_html__('Event', 'event_espresso');
330
-        if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) {
331
-            $first_datetime_name = $first_datetime->event()->name();
332
-        }
333
-        $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name);
334
-        // get event subtotal line
335
-        $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket);
336
-        $taxes            = $ticket->tax_price_modifiers();
337
-        // add $ticket to cart
338
-        $line_item = EE_Line_Item::new_instance(
339
-            [
340
-                'LIN_name'       => $ticket->name(),
341
-                'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
342
-                'LIN_unit_price' => $ticket->price(),
343
-                'LIN_quantity'   => $qty,
344
-                'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
345
-                'LIN_order'      => count($events_sub_total->children()),
346
-                'LIN_total'      => $ticket->price() * $qty,
347
-                'LIN_type'       => EEM_Line_Item::type_line_item,
348
-                'OBJ_ID'         => $ticket->ID(),
349
-                'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_TICKET,
350
-            ]
351
-        );
352
-        $line_item = apply_filters(
353
-            'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
354
-            $line_item
355
-        );
356
-        if (! $line_item instanceof EE_Line_Item) {
357
-            throw new DomainException(
358
-                esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
359
-            );
360
-        }
361
-        $events_sub_total->add_child_line_item($line_item);
362
-        // now add the sub-line items
363
-        $running_pre_tax_total = 0;
364
-        $prices                = $ticket->prices();
365
-        if (empty($prices)) {
366
-            // WUT?!?! NO PRICES??? Well, just create a default price then.
367
-            $default_price = EEM_Price::instance()->get_new_price();
368
-            if ($default_price->amount() !== $ticket->price()) {
369
-                $default_price->set_amount($ticket->price());
370
-            }
371
-            $default_price->save();
372
-            $ticket->_add_relation_to($default_price, 'Price');
373
-            $ticket->save();
374
-            $prices = [$default_price];
375
-        }
376
-        foreach ($prices as $price) {
377
-            $sign        = $price->is_discount() ? -1 : 1;
378
-            $price_total = $price->is_percent()
379
-                ? $running_pre_tax_total * $price->amount() / 100
380
-                : $price->amount() * $qty;
381
-            if ($price->is_percent()) {
382
-                $percent    = $sign * $price->amount();
383
-                $unit_price = 0;
384
-            } else {
385
-                $percent    = 0;
386
-                $unit_price = $sign * $price->amount();
387
-            }
388
-            $sub_line_item         = EE_Line_Item::new_instance(
389
-                [
390
-                    'LIN_name'       => $price->name(),
391
-                    'LIN_desc'       => $price->desc(),
392
-                    'LIN_quantity'   => $price->is_percent() ? null : $qty,
393
-                    'LIN_is_taxable' => false,
394
-                    'LIN_order'      => $price->order(),
395
-                    'LIN_total'      => $price_total,
396
-                    'LIN_pretax'     => 0,
397
-                    'LIN_unit_price' => $unit_price,
398
-                    'LIN_percent'    => $percent,
399
-                    'LIN_type'       => $price->is_tax() ? EEM_Line_Item::type_sub_tax
400
-                        : EEM_Line_Item::type_sub_line_item,
401
-                    'OBJ_ID'         => $price->ID(),
402
-                    'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
403
-                ]
404
-            );
405
-            $sub_line_item         = apply_filters(
406
-                'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
407
-                $sub_line_item
408
-            );
409
-            $running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0;
410
-            $line_item->add_child_line_item($sub_line_item);
411
-        }
412
-        $line_item->setPretaxTotal($running_pre_tax_total);
413
-        return $line_item;
414
-    }
415
-
416
-
417
-    /**
418
-     * Adds the specified item under the pre-tax-sub-total line item. Automatically
419
-     * re-calculates the line item totals and updates the related transaction. But
420
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
421
-     * should probably change because of this).
422
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
423
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
424
-     *
425
-     * @param EE_Line_Item $total_line_item
426
-     * @param EE_Line_Item $item to be added
427
-     * @param bool         $recalculate_totals
428
-     * @return boolean
429
-     * @throws EE_Error
430
-     * @throws InvalidArgumentException
431
-     * @throws InvalidDataTypeException
432
-     * @throws InvalidInterfaceException
433
-     * @throws ReflectionException
434
-     */
435
-    public static function add_item(
436
-        EE_Line_Item $total_line_item,
437
-        EE_Line_Item $item,
438
-        bool $recalculate_totals = true
439
-    ): bool {
440
-        $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item);
441
-        $success          = $pre_tax_subtotal->add_child_line_item($item);
442
-        if ($recalculate_totals) {
443
-            $total_line_item->recalculate_total_including_taxes();
444
-        }
445
-        return $success;
446
-    }
447
-
448
-
449
-    /**
450
-     * cancels an existing ticket line item,
451
-     * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item.
452
-     * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
453
-     *
454
-     * @param EE_Line_Item $ticket_line_item
455
-     * @param int          $qty
456
-     * @return bool success
457
-     * @throws EE_Error
458
-     * @throws InvalidArgumentException
459
-     * @throws InvalidDataTypeException
460
-     * @throws InvalidInterfaceException
461
-     * @throws ReflectionException
462
-     */
463
-    public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
464
-    {
465
-        // validate incoming line_item
466
-        if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
467
-            throw new EE_Error(
468
-                sprintf(
469
-                    esc_html__(
470
-                        'The supplied line item must have an Object Type of "Ticket", not %1$s.',
471
-                        'event_espresso'
472
-                    ),
473
-                    $ticket_line_item->type()
474
-                )
475
-            );
476
-        }
477
-        if ($ticket_line_item->quantity() < $qty) {
478
-            throw new EE_Error(
479
-                sprintf(
480
-                    esc_html__(
481
-                        'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.',
482
-                        'event_espresso'
483
-                    ),
484
-                    $qty,
485
-                    $ticket_line_item->quantity()
486
-                )
487
-            );
488
-        }
489
-        // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this
490
-        $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty);
491
-        foreach ($ticket_line_item->children() as $child_line_item) {
492
-            if (
493
-                $child_line_item->is_sub_line_item()
494
-                && ! $child_line_item->is_percent()
495
-                && ! $child_line_item->is_cancellation()
496
-            ) {
497
-                $child_line_item->set_quantity($child_line_item->quantity() - $qty);
498
-            }
499
-        }
500
-        // get cancellation sub line item
501
-        $cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
502
-            $ticket_line_item,
503
-            EEM_Line_Item::type_cancellation
504
-        );
505
-        $cancellation_line_item = reset($cancellation_line_item);
506
-        // verify that this ticket was indeed previously cancelled
507
-        if ($cancellation_line_item instanceof EE_Line_Item) {
508
-            // increment cancelled quantity
509
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty);
510
-        } else {
511
-            // create cancellation sub line item
512
-            $cancellation_line_item = EE_Line_Item::new_instance(
513
-                [
514
-                    'LIN_name'       => esc_html__('Cancellation', 'event_espresso'),
515
-                    'LIN_desc'       => sprintf(
516
-                        esc_html_x(
517
-                            'Cancelled %1$s : %2$s',
518
-                            'Cancelled Ticket Name : 2015-01-01 11:11',
519
-                            'event_espresso'
520
-                        ),
521
-                        $ticket_line_item->name(),
522
-                        current_time(get_option('date_format') . ' ' . get_option('time_format'))
523
-                    ),
524
-                    'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
525
-                    'LIN_quantity'   => $qty,
526
-                    'LIN_is_taxable' => $ticket_line_item->is_taxable(),
527
-                    'LIN_order'      => count($ticket_line_item->children()),
528
-                    'LIN_total'      => 0, // $ticket_line_item->unit_price()
529
-                    'LIN_type'       => EEM_Line_Item::type_cancellation,
530
-                ]
531
-            );
532
-            $ticket_line_item->add_child_line_item($cancellation_line_item);
533
-        }
534
-        if ($ticket_line_item->save_this_and_descendants() > 0) {
535
-            // decrement parent line item quantity
536
-            $event_line_item = $ticket_line_item->parent();
537
-            if (
538
-                $event_line_item instanceof EE_Line_Item
539
-                && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
540
-            ) {
541
-                $event_line_item->set_quantity($event_line_item->quantity() - $qty);
542
-                $event_line_item->save();
543
-            }
544
-            EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
545
-            return true;
546
-        }
547
-        return false;
548
-    }
549
-
550
-
551
-    /**
552
-     * reinstates (un-cancels?) a previously canceled ticket line item,
553
-     * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item.
554
-     * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
555
-     *
556
-     * @param EE_Line_Item $ticket_line_item
557
-     * @param int          $qty
558
-     * @return bool success
559
-     * @throws EE_Error
560
-     * @throws InvalidArgumentException
561
-     * @throws InvalidDataTypeException
562
-     * @throws InvalidInterfaceException
563
-     * @throws ReflectionException
564
-     */
565
-    public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
566
-    {
567
-        // validate incoming line_item
568
-        if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
569
-            throw new EE_Error(
570
-                sprintf(
571
-                    esc_html__(
572
-                        'The supplied line item must have an Object Type of "Ticket", not %1$s.',
573
-                        'event_espresso'
574
-                    ),
575
-                    $ticket_line_item->type()
576
-                )
577
-            );
578
-        }
579
-        // get cancellation sub line item
580
-        $cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
581
-            $ticket_line_item,
582
-            EEM_Line_Item::type_cancellation
583
-        );
584
-        $cancellation_line_item = reset($cancellation_line_item);
585
-        // verify that this ticket was indeed previously cancelled
586
-        if (! $cancellation_line_item instanceof EE_Line_Item) {
587
-            return false;
588
-        }
589
-        if ($cancellation_line_item->quantity() > $qty) {
590
-            // decrement cancelled quantity
591
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
592
-        } elseif ($cancellation_line_item->quantity() === $qty) {
593
-            // decrement cancelled quantity in case anyone still has the object kicking around
594
-            $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
595
-            // delete because quantity will end up as 0
596
-            $cancellation_line_item->delete();
597
-            // and attempt to destroy the object,
598
-            // even though PHP won't actually destroy it until it needs the memory
599
-            unset($cancellation_line_item);
600
-        } else {
601
-            // what ?!?! negative quantity ?!?!
602
-            throw new EE_Error(
603
-                sprintf(
604
-                    esc_html__(
605
-                        'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.',
606
-                        'event_espresso'
607
-                    ),
608
-                    $qty,
609
-                    $cancellation_line_item->quantity()
610
-                )
611
-            );
612
-        }
613
-        // increment ticket quantity
614
-        $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty);
615
-        if ($ticket_line_item->save_this_and_descendants() > 0) {
616
-            // increment parent line item quantity
617
-            $event_line_item = $ticket_line_item->parent();
618
-            if (
619
-                $event_line_item instanceof EE_Line_Item
620
-                && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
621
-            ) {
622
-                $event_line_item->set_quantity($event_line_item->quantity() + $qty);
623
-            }
624
-            EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
625
-            return true;
626
-        }
627
-        return false;
628
-    }
629
-
630
-
631
-    /**
632
-     * calls EEH_Line_Item::find_transaction_grand_total_for_line_item()
633
-     * then EE_Line_Item::recalculate_total_including_taxes() on the result
634
-     *
635
-     * @param EE_Line_Item $line_item
636
-     * @return float
637
-     * @throws EE_Error
638
-     * @throws InvalidArgumentException
639
-     * @throws InvalidDataTypeException
640
-     * @throws InvalidInterfaceException
641
-     * @throws ReflectionException
642
-     */
643
-    public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item): float
644
-    {
645
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item);
646
-        return $grand_total_line_item->recalculate_total_including_taxes();
647
-    }
648
-
649
-
650
-    /**
651
-     * Gets the line item which contains the subtotal of all the items
652
-     *
653
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
654
-     * @return EE_Line_Item
655
-     * @throws EE_Error
656
-     * @throws InvalidArgumentException
657
-     * @throws InvalidDataTypeException
658
-     * @throws InvalidInterfaceException
659
-     * @throws ReflectionException
660
-     */
661
-    public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
662
-    {
663
-        $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal');
664
-        return $pre_tax_subtotal instanceof EE_Line_Item
665
-            ? $pre_tax_subtotal
666
-            : self::create_pre_tax_subtotal($total_line_item);
667
-    }
668
-
669
-
670
-    /**
671
-     * Gets the line item for the taxes subtotal
672
-     *
673
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
674
-     * @return EE_Line_Item
675
-     * @throws EE_Error
676
-     * @throws InvalidArgumentException
677
-     * @throws InvalidDataTypeException
678
-     * @throws InvalidInterfaceException
679
-     * @throws ReflectionException
680
-     */
681
-    public static function get_taxes_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
682
-    {
683
-        $taxes = $total_line_item->get_child_line_item('taxes');
684
-        return $taxes ?: self::create_taxes_subtotal($total_line_item);
685
-    }
686
-
687
-
688
-    /**
689
-     * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object
690
-     *
691
-     * @param EE_Line_Item        $line_item
692
-     * @param EE_Transaction|null $transaction
693
-     * @return void
694
-     * @throws EE_Error
695
-     * @throws InvalidArgumentException
696
-     * @throws InvalidDataTypeException
697
-     * @throws InvalidInterfaceException
698
-     * @throws ReflectionException
699
-     */
700
-    public static function set_TXN_ID(EE_Line_Item $line_item, ?EE_Transaction $transaction = null)
701
-    {
702
-        if ($transaction) {
703
-            /** @type EEM_Transaction $EEM_Transaction */
704
-            $EEM_Transaction = EE_Registry::instance()->load_model('Transaction');
705
-            $TXN_ID          = $EEM_Transaction->ensure_is_ID($transaction);
706
-            $line_item->set_TXN_ID($TXN_ID);
707
-        }
708
-    }
709
-
710
-
711
-    /**
712
-     * Creates a new default total line item for the transaction,
713
-     * and its tickets subtotal and taxes subtotal line items (and adds the
714
-     * existing taxes as children of the taxes subtotal line item)
715
-     *
716
-     * @param EE_Transaction|null $transaction
717
-     * @return EE_Line_Item of type total
718
-     * @throws EE_Error
719
-     * @throws InvalidArgumentException
720
-     * @throws InvalidDataTypeException
721
-     * @throws InvalidInterfaceException
722
-     * @throws ReflectionException
723
-     */
724
-    public static function create_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
725
-    {
726
-        $total_line_item = EE_Line_Item::new_instance(
727
-            [
728
-                'LIN_code' => 'total',
729
-                'LIN_name' => esc_html__('Grand Total', 'event_espresso'),
730
-                'LIN_type' => EEM_Line_Item::type_total,
731
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION,
732
-            ]
733
-        );
734
-        $total_line_item = apply_filters(
735
-            'FHEE__EEH_Line_Item__create_total_line_item__total_line_item',
736
-            $total_line_item
737
-        );
738
-        self::set_TXN_ID($total_line_item, $transaction);
739
-        self::create_pre_tax_subtotal($total_line_item, $transaction);
740
-        self::create_taxes_subtotal($total_line_item, $transaction);
741
-        return $total_line_item;
742
-    }
743
-
744
-
745
-    /**
746
-     * Creates a default items subtotal line item
747
-     *
748
-     * @param EE_Line_Item        $total_line_item
749
-     * @param EE_Transaction|null $transaction
750
-     * @return EE_Line_Item
751
-     * @throws EE_Error
752
-     * @throws InvalidArgumentException
753
-     * @throws InvalidDataTypeException
754
-     * @throws InvalidInterfaceException
755
-     * @throws ReflectionException
756
-     */
757
-    protected static function create_pre_tax_subtotal(
758
-        EE_Line_Item $total_line_item,
759
-        ?EE_Transaction $transaction = null
760
-    ): EE_Line_Item {
761
-        $pre_tax_line_item = EE_Line_Item::new_instance(
762
-            [
763
-                'LIN_code' => 'pre-tax-subtotal',
764
-                'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'),
765
-                'LIN_type' => EEM_Line_Item::type_sub_total,
766
-            ]
767
-        );
768
-        $pre_tax_line_item = apply_filters(
769
-            'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item',
770
-            $pre_tax_line_item
771
-        );
772
-        self::set_TXN_ID($pre_tax_line_item, $transaction);
773
-        $total_line_item->add_child_line_item($pre_tax_line_item);
774
-        self::create_event_subtotal($pre_tax_line_item, $transaction);
775
-        return $pre_tax_line_item;
776
-    }
777
-
778
-
779
-    /**
780
-     * Creates a line item for the taxes subtotal and finds all the tax prices
781
-     * and applies taxes to it
782
-     *
783
-     * @param EE_Line_Item        $total_line_item of type EEM_Line_Item::type_total
784
-     * @param EE_Transaction|null $transaction
785
-     * @return EE_Line_Item
786
-     * @throws EE_Error
787
-     * @throws InvalidArgumentException
788
-     * @throws InvalidDataTypeException
789
-     * @throws InvalidInterfaceException
790
-     * @throws ReflectionException
791
-     */
792
-    protected static function create_taxes_subtotal(
793
-        EE_Line_Item $total_line_item,
794
-        ?EE_Transaction $transaction = null
795
-    ): EE_Line_Item {
796
-        $tax_line_item = EE_Line_Item::new_instance(
797
-            [
798
-                'LIN_code'  => 'taxes',
799
-                'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
800
-                'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
801
-                'LIN_order' => 1000,// this should always come last
802
-            ]
803
-        );
804
-        $tax_line_item = apply_filters(
805
-            'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item',
806
-            $tax_line_item
807
-        );
808
-        self::set_TXN_ID($tax_line_item, $transaction);
809
-        $total_line_item->add_child_line_item($tax_line_item);
810
-        // and lastly, add the actual taxes
811
-        self::apply_taxes($total_line_item);
812
-        return $tax_line_item;
813
-    }
814
-
815
-
816
-    /**
817
-     * Creates a default items subtotal line item
818
-     *
819
-     * @param EE_Line_Item        $pre_tax_line_item
820
-     * @param EE_Transaction|null $transaction
821
-     * @param EE_Event|null       $event
822
-     * @return EE_Line_Item
823
-     * @throws EE_Error
824
-     * @throws InvalidArgumentException
825
-     * @throws InvalidDataTypeException
826
-     * @throws InvalidInterfaceException
827
-     * @throws ReflectionException
828
-     */
829
-    public static function create_event_subtotal(
830
-        EE_Line_Item $pre_tax_line_item,
831
-        ?EE_Transaction $transaction = null,
832
-        ?EE_Event $event = null
833
-    ): EE_Line_Item {
834
-        $event_line_item = EE_Line_Item::new_instance(
835
-            [
836
-                'LIN_code' => self::get_event_code($event),
837
-                'LIN_name' => self::get_event_name($event),
838
-                'LIN_desc' => self::get_event_desc($event),
839
-                'LIN_type' => EEM_Line_Item::type_sub_total,
840
-                'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT,
841
-                'OBJ_ID'   => $event instanceof EE_Event ? $event->ID() : 0,
842
-            ]
843
-        );
844
-        $event_line_item = apply_filters(
845
-            'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item',
846
-            $event_line_item
847
-        );
848
-        self::set_TXN_ID($event_line_item, $transaction);
849
-        $pre_tax_line_item->add_child_line_item($event_line_item);
850
-        return $event_line_item;
851
-    }
852
-
853
-
854
-    /**
855
-     * Gets what the event ticket's code SHOULD be
856
-     *
857
-     * @param EE_Event|null $event
858
-     * @return string
859
-     * @throws EE_Error
860
-     * @throws ReflectionException
861
-     */
862
-    public static function get_event_code(?EE_Event $event = null): string
863
-    {
864
-        return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
865
-    }
866
-
867
-
868
-    /**
869
-     * Gets the event name
870
-     *
871
-     * @param EE_Event|null $event
872
-     * @return string
873
-     * @throws EE_Error
874
-     * @throws ReflectionException
875
-     */
876
-    public static function get_event_name(?EE_Event $event = null): string
877
-    {
878
-        return $event instanceof EE_Event
879
-            ? mb_substr($event->name(), 0, 245)
880
-            : esc_html__('Event', 'event_espresso');
881
-    }
882
-
883
-
884
-    /**
885
-     * Gets the event excerpt
886
-     *
887
-     * @param EE_Event|null $event
888
-     * @return string
889
-     * @throws EE_Error
890
-     * @throws ReflectionException
891
-     */
892
-    public static function get_event_desc(?EE_Event $event = null): string
893
-    {
894
-        return $event instanceof EE_Event ? $event->short_description() : '';
895
-    }
896
-
897
-
898
-    /**
899
-     * Given the grand total line item and a ticket, finds the event sub-total
900
-     * line item the ticket's purchase should be added onto
901
-     *
902
-     * @access public
903
-     * @param EE_Line_Item $grand_total the grand total line item
904
-     * @param EE_Ticket    $ticket
905
-     * @return EE_Line_Item
906
-     * @throws EE_Error
907
-     * @throws InvalidArgumentException
908
-     * @throws InvalidDataTypeException
909
-     * @throws InvalidInterfaceException
910
-     * @throws ReflectionException
911
-     */
912
-    public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket): EE_Line_Item
913
-    {
914
-        $first_datetime = $ticket->first_datetime();
915
-        if (! $first_datetime instanceof EE_Datetime) {
916
-            throw new EE_Error(
917
-                sprintf(
918
-                    esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
919
-                    $ticket->ID()
920
-                )
921
-            );
922
-        }
923
-        $event = $first_datetime->event();
924
-        if (! $event instanceof EE_Event) {
925
-            throw new EE_Error(
926
-                sprintf(
927
-                    esc_html__(
928
-                        'The supplied ticket (ID %d) has no event data associated with it.',
929
-                        'event_espresso'
930
-                    ),
931
-                    $ticket->ID()
932
-                )
933
-            );
934
-        }
935
-        $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
936
-        if (! $events_sub_total instanceof EE_Line_Item) {
937
-            throw new EE_Error(
938
-                sprintf(
939
-                    esc_html__(
940
-                        'There is no events sub-total for ticket %s on total line item %d',
941
-                        'event_espresso'
942
-                    ),
943
-                    $ticket->ID(),
944
-                    $grand_total->ID()
945
-                )
946
-            );
947
-        }
948
-        return $events_sub_total;
949
-    }
950
-
951
-
952
-    /**
953
-     * Gets the event line item
954
-     *
955
-     * @param EE_Line_Item  $grand_total
956
-     * @param EE_Event|null $event
957
-     * @return EE_Line_Item for the event subtotal which is a child of $grand_total
958
-     * @throws EE_Error
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidDataTypeException
961
-     * @throws InvalidInterfaceException
962
-     * @throws ReflectionException
963
-     */
964
-    public static function get_event_line_item(EE_Line_Item $grand_total, ?EE_Event $event = null): ?EE_Line_Item
965
-    {
966
-        /** @type EE_Event $event */
967
-        $event           = EEM_Event::instance()->ensure_is_obj($event, true);
968
-        $event_line_item = null;
969
-        $found           = false;
970
-        foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
971
-            // default event subtotal, we should only ever find this the first time this method is called
972
-            if (! $event_line_item->OBJ_ID()) {
973
-                // let's use this! but first... set the event details
974
-                EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
975
-                $found = true;
976
-                break;
977
-            }
978
-            if ($event_line_item->OBJ_ID() === $event->ID()) {
979
-                // found existing line item for this event in the cart, so break out of loop and use this one
980
-                $found = true;
981
-                break;
982
-            }
983
-        }
984
-        if (! $found) {
985
-            // there is no event sub-total yet, so add it
986
-            $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
987
-            // create a new "event" subtotal below that
988
-            $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event);
989
-            // and set the event details
990
-            EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
991
-        }
992
-        return $event_line_item;
993
-    }
994
-
995
-
996
-    /**
997
-     * Creates a default items subtotal line item
998
-     *
999
-     * @param EE_Line_Item        $event_line_item
1000
-     * @param EE_Event|null       $event
1001
-     * @param EE_Transaction|null $transaction
1002
-     * @return void
1003
-     * @throws EE_Error
1004
-     * @throws InvalidArgumentException
1005
-     * @throws InvalidDataTypeException
1006
-     * @throws InvalidInterfaceException
1007
-     * @throws ReflectionException
1008
-     */
1009
-    public static function set_event_subtotal_details(
1010
-        EE_Line_Item $event_line_item,
1011
-        EE_Event $event = null,
1012
-        ?EE_Transaction $transaction = null
1013
-    ) {
1014
-        if ($event instanceof EE_Event) {
1015
-            $event_line_item->set_code(self::get_event_code($event));
1016
-            $event_line_item->set_name(self::get_event_name($event));
1017
-            $event_line_item->set_desc(self::get_event_desc($event));
1018
-            $event_line_item->set_OBJ_ID($event->ID());
1019
-        }
1020
-        self::set_TXN_ID($event_line_item, $transaction);
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * Finds what taxes should apply, adds them as tax line items under the taxes sub-total,
1026
-     * and recalculates the taxes sub-total and the grand total. Resets the taxes, so
1027
-     * any old taxes are removed
1028
-     *
1029
-     * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
1030
-     * @param bool         $update_txn_status
1031
-     * @return bool
1032
-     * @throws EE_Error
1033
-     * @throws InvalidArgumentException
1034
-     * @throws InvalidDataTypeException
1035
-     * @throws InvalidInterfaceException
1036
-     * @throws ReflectionException
1037
-     * @throws RuntimeException
1038
-     */
1039
-    public static function apply_taxes(EE_Line_Item $total_line_item, bool $update_txn_status = false): bool
1040
-    {
1041
-        $total_line_item       = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item);
1042
-        $taxes_line_item       = self::get_taxes_subtotal($total_line_item);
1043
-        $existing_global_taxes = $taxes_line_item->tax_descendants();
1044
-        $updates               = false;
1045
-        // loop thru taxes
1046
-        $global_taxes = EEH_Line_Item::getGlobalTaxes();
1047
-        foreach ($global_taxes as $order => $taxes) {
1048
-            foreach ($taxes as $tax) {
1049
-                if ($tax instanceof EE_Price) {
1050
-                    $found = false;
1051
-                    // check if this is already an existing tax
1052
-                    foreach ($existing_global_taxes as $existing_global_tax) {
1053
-                        if ($tax->ID() === $existing_global_tax->OBJ_ID()) {
1054
-                            // maybe update the tax rate in case it has changed
1055
-                            if ($existing_global_tax->percent() !== $tax->amount()) {
1056
-                                $existing_global_tax->set_percent($tax->amount());
1057
-                                $existing_global_tax->save();
1058
-                                $updates = true;
1059
-                            }
1060
-                            $found = true;
1061
-                            break;
1062
-                        }
1063
-                    }
1064
-                    if (! $found) {
1065
-                        // add a new line item for this global tax
1066
-                        $tax_line_item = apply_filters(
1067
-                            'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
1068
-                            EE_Line_Item::new_instance(
1069
-                                [
1070
-                                    'LIN_name'       => $tax->name(),
1071
-                                    'LIN_desc'       => $tax->desc(),
1072
-                                    'LIN_percent'    => $tax->amount(),
1073
-                                    'LIN_is_taxable' => false,
1074
-                                    'LIN_order'      => $order,
1075
-                                    'LIN_total'      => 0,
1076
-                                    'LIN_type'       => EEM_Line_Item::type_tax,
1077
-                                    'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
1078
-                                    'OBJ_ID'         => $tax->ID(),
1079
-                                ]
1080
-                            )
1081
-                        );
1082
-                        $updates       = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1083
-                    }
1084
-                }
1085
-            }
1086
-        }
1087
-        // only recalculate totals if something changed
1088
-        if ($updates || $update_txn_status) {
1089
-            $total_line_item->recalculate_total_including_taxes($update_txn_status);
1090
-            return true;
1091
-        }
1092
-        return false;
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     * Ensures that taxes have been applied to the order, if not applies them.
1098
-     * Returns the total amount of tax
1099
-     *
1100
-     * @param EE_Line_Item|null $total_line_item of type EEM_Line_Item::type_total
1101
-     * @return float
1102
-     * @throws EE_Error
1103
-     * @throws InvalidArgumentException
1104
-     * @throws InvalidDataTypeException
1105
-     * @throws InvalidInterfaceException
1106
-     * @throws ReflectionException
1107
-     */
1108
-    public static function ensure_taxes_applied(?EE_Line_Item $total_line_item): float
1109
-    {
1110
-        $taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1111
-        if (! $taxes_subtotal->children()) {
1112
-            self::apply_taxes($total_line_item);
1113
-        }
1114
-        return $taxes_subtotal->total();
1115
-    }
1116
-
1117
-
1118
-    /**
1119
-     * Deletes ALL children of the passed line item
1120
-     *
1121
-     * @param EE_Line_Item $parent_line_item
1122
-     * @return bool
1123
-     * @throws EE_Error
1124
-     * @throws InvalidArgumentException
1125
-     * @throws InvalidDataTypeException
1126
-     * @throws InvalidInterfaceException
1127
-     * @throws ReflectionException
1128
-     */
1129
-    public static function delete_all_child_items(EE_Line_Item $parent_line_item)
1130
-    {
1131
-        $deleted = 0;
1132
-        foreach ($parent_line_item->children() as $child_line_item) {
1133
-            if ($child_line_item instanceof EE_Line_Item) {
1134
-                $deleted += EEH_Line_Item::delete_all_child_items($child_line_item);
1135
-                if ($child_line_item->ID()) {
1136
-                    $child_line_item->delete();
1137
-                    unset($child_line_item);
1138
-                } else {
1139
-                    $parent_line_item->delete_child_line_item($child_line_item->code());
1140
-                }
1141
-                $deleted++;
1142
-            }
1143
-        }
1144
-        return $deleted;
1145
-    }
1146
-
1147
-
1148
-    /**
1149
-     * Deletes the line items as indicated by the line item code(s) provided,
1150
-     * regardless of where they're found in the line item tree. Automatically
1151
-     * re-calculates the line item totals and updates the related transaction. But
1152
-     * DOES NOT automatically upgrade the transaction's registrations' final prices (which
1153
-     * should probably change because of this).
1154
-     * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
1155
-     * after using this, to keep the registration final prices in-sync with the transaction's total.
1156
-     *
1157
-     * @param EE_Line_Item      $total_line_item of type EEM_Line_Item::type_total
1158
-     * @param array|bool|string $line_item_codes
1159
-     * @return int number of items successfully removed
1160
-     * @throws EE_Error
1161
-     * @throws ReflectionException
1162
-     */
1163
-    public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false)
1164
-    {
1165
-        if ($total_line_item->type() !== EEM_Line_Item::type_total) {
1166
-            EE_Error::doing_it_wrong(
1167
-                'EEH_Line_Item::delete_items',
1168
-                esc_html__(
1169
-                    'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly',
1170
-                    'event_espresso'
1171
-                ),
1172
-                '4.6.18'
1173
-            );
1174
-        }
1175
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1176
-
1177
-        // check if only a single line_item_id was passed
1178
-        if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1179
-            // place single line_item_id in an array to appear as multiple line_item_ids
1180
-            $line_item_codes = [$line_item_codes];
1181
-        }
1182
-        $removals = 0;
1183
-        // cycle thru line_item_ids
1184
-        foreach ($line_item_codes as $line_item_id) {
1185
-            $removals += $total_line_item->delete_child_line_item($line_item_id);
1186
-        }
1187
-
1188
-        if ($removals > 0) {
1189
-            $total_line_item->recalculate_taxes_and_tax_total();
1190
-            return $removals;
1191
-        } else {
1192
-            return false;
1193
-        }
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * Overwrites the previous tax by clearing out the old taxes, and creates a new
1199
-     * tax and updates the total line item accordingly
1200
-     *
1201
-     * @param EE_Line_Item $total_line_item
1202
-     * @param float        $amount
1203
-     * @param string       $name
1204
-     * @param string       $description
1205
-     * @param string       $code
1206
-     * @param boolean      $add_to_existing_line_item
1207
-     *                          if true, and a duplicate line item with the same code is found,
1208
-     *                          $amount will be added onto it; otherwise will simply set the taxes to match $amount
1209
-     * @return EE_Line_Item the new tax line item created
1210
-     * @throws EE_Error
1211
-     * @throws InvalidArgumentException
1212
-     * @throws InvalidDataTypeException
1213
-     * @throws InvalidInterfaceException
1214
-     * @throws ReflectionException
1215
-     */
1216
-    public static function set_total_tax_to(
1217
-        EE_Line_Item $total_line_item,
1218
-        float $amount,
1219
-        string $name = '',
1220
-        string $description = '',
1221
-        string $code = '',
1222
-        bool $add_to_existing_line_item = false
1223
-    ): EE_Line_Item {
1224
-        $tax_subtotal  = self::get_taxes_subtotal($total_line_item);
1225
-        $taxable_total = $total_line_item->taxable_total();
1226
-
1227
-        if ($add_to_existing_line_item) {
1228
-            $new_tax = $tax_subtotal->get_child_line_item($code);
1229
-            EEM_Line_Item::instance()->delete(
1230
-                [['LIN_code' => ['!=', $code], 'LIN_parent' => $tax_subtotal->ID()]]
1231
-            );
1232
-        } else {
1233
-            $new_tax = null;
1234
-            $tax_subtotal->delete_children_line_items();
1235
-        }
1236
-        if ($new_tax) {
1237
-            $new_tax->set_total($new_tax->total() + $amount);
1238
-            $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
1239
-        } else {
1240
-            // no existing tax item. Create it
1241
-            $new_tax = EE_Line_Item::new_instance(
1242
-                [
1243
-                    'TXN_ID'      => $total_line_item->TXN_ID(),
1244
-                    'LIN_name'    => $name ?: esc_html__('Tax', 'event_espresso'),
1245
-                    'LIN_desc'    => $description ?: '',
1246
-                    'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0,
1247
-                    'LIN_total'   => $amount,
1248
-                    'LIN_parent'  => $tax_subtotal->ID(),
1249
-                    'LIN_type'    => EEM_Line_Item::type_tax,
1250
-                    'LIN_code'    => $code,
1251
-                ]
1252
-            );
1253
-        }
1254
-
1255
-        $new_tax = apply_filters(
1256
-            'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal',
1257
-            $new_tax,
1258
-            $total_line_item
1259
-        );
1260
-        $new_tax->save();
1261
-        $tax_subtotal->set_total($new_tax->total());
1262
-        $tax_subtotal->save();
1263
-        $total_line_item->recalculate_total_including_taxes();
1264
-        return $new_tax;
1265
-    }
1266
-
1267
-
1268
-    /**
1269
-     * Makes all the line items which are children of $line_item taxable (or not).
1270
-     * Does NOT save the line items
1271
-     *
1272
-     * @param EE_Line_Item $line_item
1273
-     * @param boolean      $taxable
1274
-     * @param string|null  $code_substring_for_whitelist if this string is part of the line item's code
1275
-     *                                                   it will be whitelisted (ie, except from becoming taxable)
1276
-     * @throws EE_Error
1277
-     * @throws ReflectionException
1278
-     */
1279
-    public static function set_line_items_taxable(
1280
-        EE_Line_Item $line_item,
1281
-        bool $taxable = true,
1282
-        ?string $code_substring_for_whitelist = null
1283
-    ) {
1284
-        $whitelisted = false;
1285
-        if ($code_substring_for_whitelist !== null) {
1286
-            $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1287
-        }
1288
-        if (! $whitelisted && $line_item->is_line_item()) {
1289
-            $line_item->set_is_taxable($taxable);
1290
-        }
1291
-        foreach ($line_item->children() as $child_line_item) {
1292
-            EEH_Line_Item::set_line_items_taxable(
1293
-                $child_line_item,
1294
-                $taxable,
1295
-                $code_substring_for_whitelist
1296
-            );
1297
-        }
1298
-    }
1299
-
1300
-
1301
-    /**
1302
-     * Gets all descendants that are event subtotals
1303
-     *
1304
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1305
-     * @return EE_Line_Item[]
1306
-     * @throws EE_Error
1307
-     * @throws ReflectionException
1308
-     * @uses  EEH_Line_Item::get_subtotals_of_object_type()
1309
-     */
1310
-    public static function get_event_subtotals(EE_Line_Item $parent_line_item): array
1311
-    {
1312
-        return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT);
1313
-    }
1314
-
1315
-
1316
-    /**
1317
-     * Gets all descendants subtotals that match the supplied object type
1318
-     *
1319
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1320
-     * @param string       $obj_type
1321
-     * @return EE_Line_Item[]
1322
-     * @throws EE_Error
1323
-     * @throws ReflectionException
1324
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1325
-     */
1326
-    public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1327
-    {
1328
-        return self::_get_descendants_by_type_and_object_type(
1329
-            $parent_line_item,
1330
-            EEM_Line_Item::type_sub_total,
1331
-            $obj_type
1332
-        );
1333
-    }
1334
-
1335
-
1336
-    /**
1337
-     * Gets all descendants that are tickets
1338
-     *
1339
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1340
-     * @return EE_Line_Item[]
1341
-     * @throws EE_Error
1342
-     * @throws ReflectionException
1343
-     * @uses  EEH_Line_Item::get_line_items_of_object_type()
1344
-     */
1345
-    public static function get_ticket_line_items(EE_Line_Item $parent_line_item): array
1346
-    {
1347
-        return self::get_line_items_of_object_type(
1348
-            $parent_line_item,
1349
-            EEM_Line_Item::OBJ_TYPE_TICKET
1350
-        );
1351
-    }
1352
-
1353
-
1354
-    /**
1355
-     * Gets all descendants subtotals that match the supplied object type
1356
-     *
1357
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1358
-     * @param string       $obj_type
1359
-     * @return EE_Line_Item[]
1360
-     * @throws EE_Error
1361
-     * @throws ReflectionException
1362
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1363
-     */
1364
-    public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1365
-    {
1366
-        return self::_get_descendants_by_type_and_object_type(
1367
-            $parent_line_item,
1368
-            EEM_Line_Item::type_line_item,
1369
-            $obj_type
1370
-        );
1371
-    }
1372
-
1373
-
1374
-    /**
1375
-     * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax'
1376
-     *
1377
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1378
-     * @return EE_Line_Item[]
1379
-     * @throws EE_Error
1380
-     * @throws ReflectionException
1381
-     * @uses  EEH_Line_Item::get_descendants_of_type()
1382
-     */
1383
-    public static function get_tax_descendants(EE_Line_Item $parent_line_item): array
1384
-    {
1385
-        return EEH_Line_Item::get_descendants_of_type(
1386
-            $parent_line_item,
1387
-            EEM_Line_Item::type_tax
1388
-        );
1389
-    }
1390
-
1391
-
1392
-    /**
1393
-     * Gets all the real items purchased which are children of this item
1394
-     *
1395
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1396
-     * @return EE_Line_Item[]
1397
-     * @throws EE_Error
1398
-     * @throws ReflectionException
1399
-     * @uses  EEH_Line_Item::get_descendants_of_type()
1400
-     */
1401
-    public static function get_line_item_descendants(EE_Line_Item $parent_line_item): array
1402
-    {
1403
-        return EEH_Line_Item::get_descendants_of_type(
1404
-            $parent_line_item,
1405
-            EEM_Line_Item::type_line_item
1406
-        );
1407
-    }
1408
-
1409
-
1410
-    /**
1411
-     * Gets all descendants of supplied line item that match the supplied line item type
1412
-     *
1413
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1414
-     * @param string       $line_item_type   one of the EEM_Line_Item constants
1415
-     * @return EE_Line_Item[]
1416
-     * @throws EE_Error
1417
-     * @throws ReflectionException
1418
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1419
-     */
1420
-    public static function get_descendants_of_type(EE_Line_Item $parent_line_item, string $line_item_type): array
1421
-    {
1422
-        return self::_get_descendants_by_type_and_object_type(
1423
-            $parent_line_item,
1424
-            $line_item_type
1425
-        );
1426
-    }
1427
-
1428
-
1429
-    /**
1430
-     * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1431
-     * as well
1432
-     *
1433
-     * @param EE_Line_Item $parent_line_item  - the line item to find descendants of
1434
-     * @param string       $line_item_type    one of the EEM_Line_Item constants
1435
-     * @param string|null  $obj_type          object model class name (minus prefix) or NULL to ignore object type when
1436
-     *                                        searching
1437
-     * @return EE_Line_Item[]
1438
-     * @throws EE_Error
1439
-     * @throws ReflectionException
1440
-     */
1441
-    protected static function _get_descendants_by_type_and_object_type(
1442
-        EE_Line_Item $parent_line_item,
1443
-        string $line_item_type,
1444
-        ?string $obj_type = null
1445
-    ): array {
1446
-        $objects = [];
1447
-        foreach ($parent_line_item->children() as $child_line_item) {
1448
-            if ($child_line_item instanceof EE_Line_Item) {
1449
-                if (
1450
-                    $child_line_item->type() === $line_item_type
1451
-                    && (
1452
-                        $child_line_item->OBJ_type() === $obj_type || $obj_type === null
1453
-                    )
1454
-                ) {
1455
-                    $objects[] = $child_line_item;
1456
-                } else {
1457
-                    // go-through-all-its children looking for more matches
1458
-                    $objects = array_merge(
1459
-                        $objects,
1460
-                        self::_get_descendants_by_type_and_object_type(
1461
-                            $child_line_item,
1462
-                            $line_item_type,
1463
-                            $obj_type
1464
-                        )
1465
-                    );
1466
-                }
1467
-            }
1468
-        }
1469
-        return $objects;
1470
-    }
1471
-
1472
-
1473
-    /**
1474
-     * Gets all descendants subtotals that match the supplied object type
1475
-     *
1476
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1477
-     * @param string       $OBJ_type         object type (like Event)
1478
-     * @param array        $OBJ_IDs          array of OBJ_IDs
1479
-     * @return EE_Line_Item[]
1480
-     * @throws EE_Error
1481
-     * @throws ReflectionException
1482
-     * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1483
-     */
1484
-    public static function get_line_items_by_object_type_and_IDs(
1485
-        EE_Line_Item $parent_line_item,
1486
-        string $OBJ_type = '',
1487
-        array $OBJ_IDs = []
1488
-    ): array {
1489
-        return self::_get_descendants_by_object_type_and_object_ID(
1490
-            $parent_line_item,
1491
-            $OBJ_type,
1492
-            $OBJ_IDs
1493
-        );
1494
-    }
1495
-
1496
-
1497
-    /**
1498
-     * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1499
-     * as well
1500
-     *
1501
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1502
-     * @param string       $OBJ_type         object type (like Event)
1503
-     * @param array        $OBJ_IDs          array of OBJ_IDs
1504
-     * @return EE_Line_Item[]
1505
-     * @throws EE_Error
1506
-     * @throws ReflectionException
1507
-     */
1508
-    protected static function _get_descendants_by_object_type_and_object_ID(
1509
-        EE_Line_Item $parent_line_item,
1510
-        string $OBJ_type,
1511
-        array $OBJ_IDs
1512
-    ): array {
1513
-        $objects = [];
1514
-        foreach ($parent_line_item->children() as $child_line_item) {
1515
-            if ($child_line_item instanceof EE_Line_Item) {
1516
-                if (
1517
-                    $child_line_item->OBJ_type() === $OBJ_type
1518
-                    && in_array($child_line_item->OBJ_ID(), $OBJ_IDs)
1519
-                ) {
1520
-                    $objects[] = $child_line_item;
1521
-                } else {
1522
-                    // go-through-all-its children looking for more matches
1523
-                    $objects = array_merge(
1524
-                        $objects,
1525
-                        self::_get_descendants_by_object_type_and_object_ID(
1526
-                            $child_line_item,
1527
-                            $OBJ_type,
1528
-                            $OBJ_IDs
1529
-                        )
1530
-                    );
1531
-                }
1532
-            }
1533
-        }
1534
-        return $objects;
1535
-    }
1536
-
1537
-
1538
-    /**
1539
-     * Uses a breadth-first-search in order to find the nearest descendant of
1540
-     * the specified type and returns it, else NULL
1541
-     *
1542
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1543
-     * @param string       $type             like one of the EEM_Line_Item::type_*
1544
-     * @return EE_Line_Item
1545
-     * @throws EE_Error
1546
-     * @throws InvalidArgumentException
1547
-     * @throws InvalidDataTypeException
1548
-     * @throws InvalidInterfaceException
1549
-     * @throws ReflectionException
1550
-     * @uses  EEH_Line_Item::_get_nearest_descendant()
1551
-     */
1552
-    public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, string $type): ?EE_Line_Item
1553
-    {
1554
-        return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type);
1555
-    }
1556
-
1557
-
1558
-    /**
1559
-     * Uses a breadth-first-search in order to find the nearest descendant
1560
-     * having the specified LIN_code and returns it, else NULL
1561
-     *
1562
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1563
-     * @param string       $code             any value used for LIN_code
1564
-     * @return EE_Line_Item
1565
-     * @throws EE_Error
1566
-     * @throws InvalidArgumentException
1567
-     * @throws InvalidDataTypeException
1568
-     * @throws InvalidInterfaceException
1569
-     * @throws ReflectionException
1570
-     * @uses  EEH_Line_Item::_get_nearest_descendant()
1571
-     */
1572
-    public static function get_nearest_descendant_having_code(
1573
-        EE_Line_Item $parent_line_item,
1574
-        string $code
1575
-    ): ?EE_Line_Item {
1576
-        return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code);
1577
-    }
1578
-
1579
-
1580
-    /**
1581
-     * Uses a breadth-first-search in order to find the nearest descendant
1582
-     * having the specified LIN_code and returns it, else NULL
1583
-     *
1584
-     * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1585
-     * @param string       $search_field     name of EE_Line_Item property
1586
-     * @param mixed        $value            any value stored in $search_field
1587
-     * @return EE_Line_Item
1588
-     * @throws EE_Error
1589
-     * @throws InvalidArgumentException
1590
-     * @throws InvalidDataTypeException
1591
-     * @throws InvalidInterfaceException
1592
-     * @throws ReflectionException
1593
-     */
1594
-    protected static function _get_nearest_descendant(
1595
-        EE_Line_Item $parent_line_item,
1596
-        string $search_field,
1597
-        $value
1598
-    ): ?EE_Line_Item {
1599
-        foreach ($parent_line_item->children() as $child) {
1600
-            if ($child->get($search_field) == $value) {
1601
-                return $child;
1602
-            }
1603
-        }
1604
-        foreach ($parent_line_item->children() as $child) {
1605
-            $descendant_found = self::_get_nearest_descendant(
1606
-                $child,
1607
-                $search_field,
1608
-                $value
1609
-            );
1610
-            if ($descendant_found) {
1611
-                return $descendant_found;
1612
-            }
1613
-        }
1614
-        return null;
1615
-    }
1616
-
1617
-
1618
-    /**
1619
-     * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction,
1620
-     * else recursively walks up the line item tree until a parent of type total is found,
1621
-     *
1622
-     * @param EE_Line_Item $line_item
1623
-     * @return EE_Line_Item
1624
-     * @throws EE_Error
1625
-     * @throws ReflectionException
1626
-     */
1627
-    public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item
1628
-    {
1629
-        if ($line_item->is_total()) {
1630
-            return $line_item;
1631
-        }
1632
-        if ($line_item->TXN_ID()) {
1633
-            $total_line_item = $line_item->transaction()->total_line_item(false);
1634
-            if ($total_line_item instanceof EE_Line_Item) {
1635
-                return $total_line_item;
1636
-            }
1637
-        } else {
1638
-            $line_item_parent = $line_item->parent();
1639
-            if ($line_item_parent instanceof EE_Line_Item) {
1640
-                if ($line_item_parent->is_total()) {
1641
-                    return $line_item_parent;
1642
-                }
1643
-                return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent);
1644
-            }
1645
-        }
1646
-        throw new EE_Error(
1647
-            sprintf(
1648
-                esc_html__(
1649
-                    'A valid grand total for line item %1$d was not found.',
1650
-                    'event_espresso'
1651
-                ),
1652
-                $line_item->ID()
1653
-            )
1654
-        );
1655
-    }
1656
-
1657
-
1658
-    /**
1659
-     * Prints out a representation of the line item tree
1660
-     *
1661
-     * @param EE_Line_Item $line_item
1662
-     * @param int          $indentation
1663
-     * @param bool         $top_level
1664
-     * @return void
1665
-     * @throws EE_Error
1666
-     * @throws ReflectionException
1667
-     */
1668
-    public static function visualize(EE_Line_Item $line_item, int $indentation = 0, bool $top_level = true)
1669
-    {
1670
-        $testing  = defined('EE_TESTS_DIR');
1671
-        $new_line = $testing ? "\n" : '<br />';
1672
-        if ($top_level && ! $testing) {
1673
-            echo '<div style="position: relative; z-index: 9999; margin: 2rem;">';
1674
-            echo '<pre style="padding: 2rem 3rem; color: #00CCFF; background: #363636;">';
1675
-        }
1676
-        if ($indentation) {
1677
-            echo $new_line;
1678
-        }
1679
-        echo str_repeat('. ', $indentation);
1680
-        $breakdown = '';
1681
-        if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) {
1682
-            if ($line_item->is_percent()) {
1683
-                $breakdown = "{$line_item->percent()}%";
1684
-            } else {
1685
-                $breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}";
1686
-            }
1687
-        }
1688
-        echo wp_kses($line_item->name(), AllowedTags::getAllowedTags());
1689
-        echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : ";
1690
-        echo "\${$line_item->total()}";
1691
-        if ($breakdown) {
1692
-            echo " ( $breakdown )";
1693
-        }
1694
-        if ($line_item->is_taxable()) {
1695
-            echo '  * taxable';
1696
-        }
1697
-        if ($line_item->children()) {
1698
-            foreach ($line_item->children() as $child) {
1699
-                self::visualize($child, $indentation + 1, false);
1700
-            }
1701
-        }
1702
-        if ($top_level && ! $testing) {
1703
-            echo $new_line;
1704
-            echo '</pre></div>';
1705
-        }
1706
-    }
1707
-
1708
-
1709
-    /**
1710
-     * Calculates the registration's final price, taking into account that they
1711
-     * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes,
1712
-     * and receive a portion of any transaction-wide discounts.
1713
-     * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount
1714
-     * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get
1715
-     * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50
1716
-     * and brent's final price should be $5.50.
1717
-     * In order to do this, we basically need to traverse the line item tree calculating
1718
-     * the running totals (just as if we were recalculating the total), but when we identify
1719
-     * regular line items, we need to keep track of their share of the grand total.
1720
-     * Also, we need to keep track of the TAXABLE total for each ticket purchase, so
1721
-     * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total"
1722
-     * when there are non-taxable items; otherwise they would be the same)
1723
-     *
1724
-     * @param EE_Line_Item $line_item
1725
-     * @param array        $billable_ticket_quantities          array of EE_Ticket IDs and their corresponding quantity
1726
-     *                                                          that can be included in price calculations at this
1727
-     *                                                          moment
1728
-     * @return array        keys are line items for tickets IDs and values are their share of the running total,
1729
-     *                                                          plus the key 'total', and 'taxable' which also has keys
1730
-     *                                                          of all the ticket IDs. Eg array(
1731
-     *                                                          12 => 4.3
1732
-     *                                                          23 => 8.0
1733
-     *                                                          'total' => 16.6,
1734
-     *                                                          'taxable' => array(
1735
-     *                                                          12 => 10,
1736
-     *                                                          23 => 4
1737
-     *                                                          ).
1738
-     *                                                          So to find which registrations have which final price,
1739
-     *                                                          we need to find which line item is theirs, which can be
1740
-     *                                                          done with
1741
-     *                                                          `EEM_Line_Item::instance()->get_line_item_for_registration(
1742
-     *                                                          $registration );`
1743
-     * @throws EE_Error
1744
-     * @throws InvalidArgumentException
1745
-     * @throws InvalidDataTypeException
1746
-     * @throws InvalidInterfaceException
1747
-     * @throws ReflectionException
1748
-     */
1749
-    public static function calculate_reg_final_prices_per_line_item(
1750
-        EE_Line_Item $line_item,
1751
-        array $billable_ticket_quantities = []
1752
-    ): array {
1753
-        $running_totals = [
1754
-            'total'   => 0,
1755
-            'taxable' => ['total' => 0],
1756
-        ];
1757
-        foreach ($line_item->children() as $child_line_item) {
1758
-            switch ($child_line_item->type()) {
1759
-                case EEM_Line_Item::type_sub_total:
1760
-                    $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1761
-                        $child_line_item,
1762
-                        $billable_ticket_quantities
1763
-                    );
1764
-                    // combine arrays but preserve numeric keys
1765
-                    $running_totals                     = array_replace_recursive(
1766
-                        $running_totals_from_subtotal,
1767
-                        $running_totals
1768
-                    );
1769
-                    $running_totals['total']            += $running_totals_from_subtotal['total'];
1770
-                    $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total'];
1771
-                    break;
1772
-
1773
-                case EEM_Line_Item::type_tax_sub_total:
1774
-                    // find how much the taxes percentage is
1775
-                    if ($child_line_item->percent() !== 0.0) {
1776
-                        $tax_percent_decimal = $child_line_item->percent() / 100;
1777
-                    } else {
1778
-                        $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100;
1779
-                    }
1780
-                    // and apply to all the taxable totals, and add to the pretax totals
1781
-                    foreach ($running_totals as $line_item_id => $this_running_total) {
1782
-                        // "total" and "taxable" array key is an exception
1783
-                        if ($line_item_id === 'taxable') {
1784
-                            continue;
1785
-                        }
1786
-                        $taxable_total                   = $running_totals['taxable'][ $line_item_id ];
1787
-                        $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1788
-                    }
1789
-                    break;
1790
-
1791
-                case EEM_Line_Item::type_line_item:
1792
-                    // ticket line items or ????
1793
-                    if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1794
-                        // kk it's a ticket
1795
-                        if (isset($running_totals[ $child_line_item->ID() ])) {
1796
-                            // huh? that shouldn't happen.
1797
-                            $running_totals['total'] += $child_line_item->total();
1798
-                        } else {
1799
-                            // its not in our running totals yet. great.
1800
-                            if ($child_line_item->is_taxable()) {
1801
-                                $taxable_amount = $child_line_item->unit_price();
1802
-                            } else {
1803
-                                $taxable_amount = 0;
1804
-                            }
1805
-                            // are we only calculating totals for some tickets?
1806
-                            if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1807
-                                $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1808
-
1809
-                                $running_totals[ $child_line_item->ID() ]            = $quantity
1810
-                                    ? $child_line_item->unit_price()
1811
-                                    : 0;
1812
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1813
-                                    ? $taxable_amount
1814
-                                    : 0;
1815
-                            } else {
1816
-                                $quantity                                            = $child_line_item->quantity();
1817
-                                $running_totals[ $child_line_item->ID() ]            = $child_line_item->unit_price();
1818
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1819
-                            }
1820
-                            $running_totals['taxable']['total'] += $taxable_amount * $quantity;
1821
-                            $running_totals['total']            += $child_line_item->unit_price() * $quantity;
1822
-                        }
1823
-                    } else {
1824
-                        // it's some other type of item added to the cart
1825
-                        // it should affect the running totals
1826
-                        // basically we want to convert it into a PERCENT modifier. Because
1827
-                        // more clearly affect all registration's final price equally
1828
-                        $line_items_percent_of_running_total = $running_totals['total'] > 0
1829
-                            ? ($child_line_item->total() / $running_totals['total']) + 1
1830
-                            : 1;
1831
-                        foreach ($running_totals as $line_item_id => $this_running_total) {
1832
-                            // the "taxable" array key is an exception
1833
-                            if ($line_item_id === 'taxable') {
1834
-                                continue;
1835
-                            }
1836
-                            // update the running totals
1837
-                            // yes this actually even works for the running grand total!
1838
-                            $running_totals[ $line_item_id ] =
1839
-                                $line_items_percent_of_running_total * $this_running_total;
1840
-
1841
-                            if ($child_line_item->is_taxable()) {
1842
-                                $running_totals['taxable'][ $line_item_id ] =
1843
-                                    $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1844
-                            }
1845
-                        }
1846
-                    }
1847
-                    break;
1848
-            }
1849
-        }
1850
-        return $running_totals;
1851
-    }
1852
-
1853
-
1854
-    /**
1855
-     * @param EE_Line_Item $total_line_item
1856
-     * @param EE_Line_Item $ticket_line_item
1857
-     * @return float | null
1858
-     * @throws EE_Error
1859
-     * @throws InvalidArgumentException
1860
-     * @throws InvalidDataTypeException
1861
-     * @throws InvalidInterfaceException
1862
-     * @throws OutOfRangeException
1863
-     * @throws ReflectionException
1864
-     */
1865
-    public static function calculate_final_price_for_ticket_line_item(
1866
-        EE_Line_Item $total_line_item,
1867
-        EE_Line_Item $ticket_line_item
1868
-    ): ?float {
1869
-        static $final_prices_per_ticket_line_item = [];
1870
-        if (
1871
-            empty($final_prices_per_ticket_line_item)
1872
-            || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])
1873
-        ) {
1874
-            $final_prices_per_ticket_line_item[ $total_line_item->ID() ] =
1875
-                EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1876
-                    $total_line_item
1877
-                );
1878
-        }
1879
-        // ok now find this new registration's final price
1880
-        if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1881
-            return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1882
-        }
1883
-        $message = sprintf(
1884
-            esc_html__(
1885
-                'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.',
1886
-                'event_espresso'
1887
-            ),
1888
-            $ticket_line_item->ID(),
1889
-            $total_line_item->ID()
1890
-        );
1891
-        if (WP_DEBUG) {
1892
-            $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1893
-            throw new OutOfRangeException($message);
1894
-        }
1895
-        EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
1896
-        return null;
1897
-    }
1898
-
1899
-
1900
-    /**
1901
-     * Creates a duplicate of the line item tree, except only includes billable items
1902
-     * and the portion of line items attributed to billable things
1903
-     *
1904
-     * @param EE_Line_Item      $line_item
1905
-     * @param EE_Registration[] $registrations
1906
-     * @return EE_Line_Item
1907
-     * @throws EE_Error
1908
-     * @throws InvalidArgumentException
1909
-     * @throws InvalidDataTypeException
1910
-     * @throws InvalidInterfaceException
1911
-     * @throws ReflectionException
1912
-     */
1913
-    public static function billable_line_item_tree(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1914
-    {
1915
-        $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations);
1916
-        foreach ($line_item->children() as $child_li) {
1917
-            $copy_li->add_child_line_item(
1918
-                EEH_Line_Item::billable_line_item_tree($child_li, $registrations)
1919
-            );
1920
-        }
1921
-        // if this is the grand total line item, make sure the totals all add up
1922
-        // (we could have duplicated this logic AS we copied the line items, but
1923
-        // it seems DRYer this way)
1924
-        if ($copy_li->type() === EEM_Line_Item::type_total) {
1925
-            $copy_li->recalculate_total_including_taxes();
1926
-        }
1927
-        return $copy_li;
1928
-    }
1929
-
1930
-
1931
-    /**
1932
-     * Creates a new, unsaved line item from $line_item that factors in the
1933
-     * number of billable registrations on $registrations.
1934
-     *
1935
-     * @param EE_Line_Item      $line_item
1936
-     * @param EE_Registration[] $registrations
1937
-     * @return EE_Line_Item
1938
-     * @throws EE_Error
1939
-     * @throws InvalidArgumentException
1940
-     * @throws InvalidDataTypeException
1941
-     * @throws InvalidInterfaceException
1942
-     * @throws ReflectionException
1943
-     */
1944
-    public static function billable_line_item(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1945
-    {
1946
-        $new_li_fields = $line_item->model_field_array();
1947
-        if (
1948
-            $line_item->type() === EEM_Line_Item::type_line_item &&
1949
-            $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1950
-        ) {
1951
-            $count = 0;
1952
-            foreach ($registrations as $registration) {
1953
-                if (
1954
-                    $line_item->OBJ_ID() === $registration->ticket_ID() &&
1955
-                    in_array(
1956
-                        $registration->status_ID(),
1957
-                        EEM_Registration::reg_statuses_that_allow_payment(),
1958
-                        true
1959
-                    )
1960
-                ) {
1961
-                    $count++;
1962
-                }
1963
-            }
1964
-            $new_li_fields['LIN_quantity'] = $count;
1965
-        }
1966
-        // don't set the total. We'll leave that up to the code that calculates it
1967
-        unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']);
1968
-        return EE_Line_Item::new_instance($new_li_fields);
1969
-    }
1970
-
1971
-
1972
-    /**
1973
-     * Returns a modified line item tree where all the subtotals which have a total of 0
1974
-     * are removed, and line items with a quantity of 0
1975
-     *
1976
-     * @param EE_Line_Item $line_item |null
1977
-     * @return EE_Line_Item|null
1978
-     * @throws EE_Error
1979
-     * @throws InvalidArgumentException
1980
-     * @throws InvalidDataTypeException
1981
-     * @throws InvalidInterfaceException
1982
-     * @throws ReflectionException
1983
-     */
1984
-    public static function non_empty_line_items(EE_Line_Item $line_item): ?EE_Line_Item
1985
-    {
1986
-        $copied_li = EEH_Line_Item::non_empty_line_item($line_item);
1987
-        if ($copied_li === null) {
1988
-            return null;
1989
-        }
1990
-        // if this is an event subtotal, we want to only include it if it
1991
-        // has a non-zero total and at least one ticket line item child
1992
-        $ticket_children = 0;
1993
-        foreach ($line_item->children() as $child_li) {
1994
-            $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li);
1995
-            if ($child_li_copy !== null) {
1996
-                $copied_li->add_child_line_item($child_li_copy);
1997
-                if (
1998
-                    $child_li_copy->type() === EEM_Line_Item::type_line_item &&
1999
-                    $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2000
-                ) {
2001
-                    $ticket_children++;
2002
-                }
2003
-            }
2004
-        }
2005
-        // if this is an event subtotal with NO ticket children
2006
-        // we basically want to ignore it
2007
-        if (
2008
-            $ticket_children === 0
2009
-            && $line_item->type() === EEM_Line_Item::type_sub_total
2010
-            && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
2011
-            && $line_item->total() === 0.0
2012
-        ) {
2013
-            return null;
2014
-        }
2015
-        return $copied_li;
2016
-    }
2017
-
2018
-
2019
-    /**
2020
-     * Creates a new, unsaved line item, but if it's a ticket line item
2021
-     * with a total of 0, or a subtotal of 0, returns null instead
2022
-     *
2023
-     * @param EE_Line_Item $line_item
2024
-     * @return EE_Line_Item
2025
-     * @throws EE_Error
2026
-     * @throws InvalidArgumentException
2027
-     * @throws InvalidDataTypeException
2028
-     * @throws InvalidInterfaceException
2029
-     * @throws ReflectionException
2030
-     */
2031
-    public static function non_empty_line_item(EE_Line_Item $line_item): ?EE_Line_Item
2032
-    {
2033
-        if (
2034
-            $line_item->type() === EEM_Line_Item::type_line_item
2035
-            && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2036
-            && $line_item->quantity() === 0
2037
-        ) {
2038
-            return null;
2039
-        }
2040
-        $new_li_fields = $line_item->model_field_array();
2041
-        // don't set the total. We'll leave that up to the code that calculates it
2042
-        unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']);
2043
-        return EE_Line_Item::new_instance($new_li_fields);
2044
-    }
2045
-
2046
-
2047
-    /**
2048
-     * Cycles through all of the ticket line items for the supplied total line item
2049
-     * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket
2050
-     *
2051
-     * @param EE_Line_Item $total_line_item
2052
-     * @throws EE_Error
2053
-     * @throws InvalidArgumentException
2054
-     * @throws InvalidDataTypeException
2055
-     * @throws InvalidInterfaceException
2056
-     * @throws ReflectionException
2057
-     * @since 4.9.79.p
2058
-     */
2059
-    public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item)
2060
-    {
2061
-        $ticket_line_items = self::get_ticket_line_items($total_line_item);
2062
-        foreach ($ticket_line_items as $ticket_line_item) {
2063
-            if (
2064
-                $ticket_line_item instanceof EE_Line_Item
2065
-                && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2066
-            ) {
2067
-                $ticket = $ticket_line_item->ticket();
2068
-                if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) {
2069
-                    $ticket_line_item->set_is_taxable($ticket->taxable());
2070
-                    $ticket_line_item->save();
2071
-                }
2072
-            }
2073
-        }
2074
-    }
2075
-
2076
-
2077
-    /**
2078
-     * @return EE_Line_Item[]
2079
-     * @throws EE_Error
2080
-     * @throws ReflectionException
2081
-     * @since   5.0.0.p
2082
-     */
2083
-    private static function getGlobalTaxes(): array
2084
-    {
2085
-        if (EEH_Line_Item::$global_taxes === null) {
2086
-            /** @type EEM_Price $EEM_Price */
2087
-            $EEM_Price = EE_Registry::instance()->load_model('Price');
2088
-            // get array of taxes via Price Model
2089
-            EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes();
2090
-            ksort(EEH_Line_Item::$global_taxes);
2091
-        }
2092
-        return EEH_Line_Item::$global_taxes;
2093
-    }
2094
-
2095
-
2096
-
2097
-    /**************************************** @DEPRECATED METHODS *************************************** */
2098
-    /**
2099
-     * @param EE_Line_Item $total_line_item
2100
-     * @return EE_Line_Item
2101
-     * @throws EE_Error
2102
-     * @throws InvalidArgumentException
2103
-     * @throws InvalidDataTypeException
2104
-     * @throws InvalidInterfaceException
2105
-     * @throws ReflectionException
2106
-     * @deprecated
2107
-     */
2108
-    public static function get_items_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
2109
-    {
2110
-        EE_Error::doing_it_wrong(
2111
-            'EEH_Line_Item::get_items_subtotal()',
2112
-            sprintf(
2113
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2114
-                'EEH_Line_Item::get_pre_tax_subtotal()'
2115
-            ),
2116
-            '4.6.0'
2117
-        );
2118
-        return self::get_pre_tax_subtotal($total_line_item);
2119
-    }
2120
-
2121
-
2122
-    /**
2123
-     * @param EE_Transaction|null $transaction
2124
-     * @return EE_Line_Item
2125
-     * @throws EE_Error
2126
-     * @throws InvalidArgumentException
2127
-     * @throws InvalidDataTypeException
2128
-     * @throws InvalidInterfaceException
2129
-     * @throws ReflectionException
2130
-     * @deprecated
2131
-     */
2132
-    public static function create_default_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
2133
-    {
2134
-        EE_Error::doing_it_wrong(
2135
-            'EEH_Line_Item::create_default_total_line_item()',
2136
-            sprintf(
2137
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2138
-                'EEH_Line_Item::create_total_line_item()'
2139
-            ),
2140
-            '4.6.0'
2141
-        );
2142
-        return self::create_total_line_item($transaction);
2143
-    }
2144
-
2145
-
2146
-    /**
2147
-     * @param EE_Line_Item        $total_line_item
2148
-     * @param EE_Transaction|null $transaction
2149
-     * @return EE_Line_Item
2150
-     * @throws EE_Error
2151
-     * @throws InvalidArgumentException
2152
-     * @throws InvalidDataTypeException
2153
-     * @throws InvalidInterfaceException
2154
-     * @throws ReflectionException
2155
-     * @deprecated
2156
-     */
2157
-    public static function create_default_tickets_subtotal(
2158
-        EE_Line_Item $total_line_item,
2159
-        ?EE_Transaction $transaction = null
2160
-    ): EE_Line_Item {
2161
-        EE_Error::doing_it_wrong(
2162
-            'EEH_Line_Item::create_default_tickets_subtotal()',
2163
-            sprintf(
2164
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2165
-                'EEH_Line_Item::create_pre_tax_subtotal()'
2166
-            ),
2167
-            '4.6.0'
2168
-        );
2169
-        return self::create_pre_tax_subtotal($total_line_item, $transaction);
2170
-    }
2171
-
2172
-
2173
-    /**
2174
-     * @param EE_Line_Item        $total_line_item
2175
-     * @param EE_Transaction|null $transaction
2176
-     * @return EE_Line_Item
2177
-     * @throws EE_Error
2178
-     * @throws InvalidArgumentException
2179
-     * @throws InvalidDataTypeException
2180
-     * @throws InvalidInterfaceException
2181
-     * @throws ReflectionException
2182
-     * @deprecated
2183
-     */
2184
-    public static function create_default_taxes_subtotal(
2185
-        EE_Line_Item $total_line_item,
2186
-        ?EE_Transaction $transaction = null
2187
-    ): EE_Line_Item {
2188
-        EE_Error::doing_it_wrong(
2189
-            'EEH_Line_Item::create_default_taxes_subtotal()',
2190
-            sprintf(
2191
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2192
-                'EEH_Line_Item::create_taxes_subtotal()'
2193
-            ),
2194
-            '4.6.0'
2195
-        );
2196
-        return self::create_taxes_subtotal($total_line_item, $transaction);
2197
-    }
2198
-
2199
-
2200
-    /**
2201
-     * @param EE_Line_Item        $total_line_item
2202
-     * @param EE_Transaction|null $transaction
2203
-     * @return EE_Line_Item
2204
-     * @throws EE_Error
2205
-     * @throws InvalidArgumentException
2206
-     * @throws InvalidDataTypeException
2207
-     * @throws InvalidInterfaceException
2208
-     * @throws ReflectionException
2209
-     * @deprecated
2210
-     */
2211
-    public static function create_default_event_subtotal(
2212
-        EE_Line_Item $total_line_item,
2213
-        ?EE_Transaction $transaction = null
2214
-    ): EE_Line_Item {
2215
-        EE_Error::doing_it_wrong(
2216
-            'EEH_Line_Item::create_default_event_subtotal()',
2217
-            sprintf(
2218
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
2219
-                'EEH_Line_Item::create_event_subtotal()'
2220
-            ),
2221
-            '4.6.0'
2222
-        );
2223
-        return self::create_event_subtotal($total_line_item, $transaction);
2224
-    }
24
+	/**
25
+	 * @var EE_Line_Item[]|null
26
+	 */
27
+	private static ?array $global_taxes = null;
28
+
29
+
30
+	/**
31
+	 * Adds a simple item (unrelated to any other model object) to the provided PARENT line item.
32
+	 * Does NOT automatically re-calculate the line item totals or update the related transaction.
33
+	 * You should call recalculate_total_including_taxes() on the grant total line item after this
34
+	 * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
35
+	 * to keep the registration final prices in-sync with the transaction's total.
36
+	 *
37
+	 * @param EE_Line_Item $parent_line_item
38
+	 * @param string       $name
39
+	 * @param float        $unit_price
40
+	 * @param string       $description
41
+	 * @param int          $quantity
42
+	 * @param boolean      $taxable
43
+	 * @param string|null  $code if set to a value, ensures there is only one line item with that code
44
+	 * @param bool         $return_item
45
+	 * @param bool         $recalculate_totals
46
+	 * @return boolean|EE_Line_Item success
47
+	 * @throws EE_Error
48
+	 * @throws ReflectionException
49
+	 */
50
+	public static function add_unrelated_item(
51
+		EE_Line_Item $parent_line_item,
52
+		string $name,
53
+		float $unit_price,
54
+		string $description = '',
55
+		int $quantity = 1,
56
+		bool $taxable = false,
57
+		?string $code = null,
58
+		bool $return_item = false,
59
+		bool $recalculate_totals = true
60
+	) {
61
+		$items_subtotal = self::get_pre_tax_subtotal($parent_line_item);
62
+		$line_item      = EE_Line_Item::new_instance(
63
+			[
64
+				'LIN_name'       => $name,
65
+				'LIN_desc'       => $description,
66
+				'LIN_unit_price' => $unit_price,
67
+				'LIN_quantity'   => $quantity,
68
+				'LIN_percent'    => null,
69
+				'LIN_is_taxable' => $taxable,
70
+				'LIN_order'      => count($items_subtotal->children()),
71
+				'LIN_total'      => $unit_price * $quantity,
72
+				'LIN_type'       => EEM_Line_Item::type_line_item,
73
+				'LIN_code'       => $code,
74
+			]
75
+		);
76
+		$line_item      = apply_filters(
77
+			'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
78
+			$line_item,
79
+			$parent_line_item
80
+		);
81
+		$added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
82
+		return $return_item ? $line_item : $added;
83
+	}
84
+
85
+
86
+	/**
87
+	 * Adds a simple item ( unrelated to any other model object) to the total line item,
88
+	 * in the correct spot in the line item tree. Does not automatically
89
+	 * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's
90
+	 * registrations' final prices (which should probably change because of this).
91
+	 * You should call recalculate_total_including_taxes() on the grand total line item, then
92
+	 * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices()
93
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
94
+	 *
95
+	 * @param EE_Line_Item $parent_line_item
96
+	 * @param string       $name
97
+	 * @param float        $percentage_amount
98
+	 * @param string       $description
99
+	 * @param boolean      $taxable
100
+	 * @param string|null  $code
101
+	 * @param bool         $return_item
102
+	 * @return boolean|EE_Line_Item success
103
+	 * @throws EE_Error
104
+	 * @throws ReflectionException
105
+	 */
106
+	public static function add_percentage_based_item(
107
+		EE_Line_Item $parent_line_item,
108
+		string $name,
109
+		float $percentage_amount,
110
+		string $description = '',
111
+		bool $taxable = false,
112
+		?string $code = null,
113
+		bool $return_item = false
114
+	) {
115
+		$total     = $percentage_amount * $parent_line_item->total() / 100;
116
+		$line_item = EE_Line_Item::new_instance(
117
+			[
118
+				'LIN_name'       => $name,
119
+				'LIN_desc'       => $description,
120
+				'LIN_unit_price' => 0,
121
+				'LIN_percent'    => $percentage_amount,
122
+				'LIN_quantity'   => 1,
123
+				'LIN_is_taxable' => $taxable,
124
+				'LIN_total'      => $total,
125
+				'LIN_type'       => EEM_Line_Item::type_line_item,
126
+				'LIN_parent'     => $parent_line_item->ID(),
127
+				'LIN_code'       => $code,
128
+			]
129
+		);
130
+		$line_item = apply_filters(
131
+			'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
132
+			$line_item
133
+		);
134
+		$added     = $parent_line_item->add_child_line_item($line_item, false);
135
+		return $return_item ? $line_item : $added;
136
+	}
137
+
138
+
139
+	/**
140
+	 * Returns the new line item created by adding a purchase of the ticket
141
+	 * ensures that ticket line item is saved, and that cart total has been recalculated.
142
+	 * If this ticket has already been purchased, just increments its count.
143
+	 * Automatically re-calculates the line item totals and updates the related transaction. But
144
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
145
+	 * should probably change because of this).
146
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
147
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
148
+	 *
149
+	 * @param EE_Line_Item|null $total_line_item grand total line item of type EEM_Line_Item::type_total
150
+	 * @param EE_Ticket         $ticket
151
+	 * @param int               $qty
152
+	 * @return EE_Line_Item
153
+	 * @throws EE_Error
154
+	 * @throws ReflectionException
155
+	 */
156
+	public static function add_ticket_purchase(
157
+		?EE_Line_Item $total_line_item,
158
+		EE_Ticket $ticket,
159
+		int $qty = 1
160
+	): ?EE_Line_Item {
161
+		if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
162
+			throw new EE_Error(
163
+				sprintf(
164
+					esc_html__(
165
+						'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.',
166
+						'event_espresso'
167
+					),
168
+					$ticket->ID(),
169
+					$total_line_item->ID()
170
+				)
171
+			);
172
+		}
173
+		// either increment the qty for an existing ticket
174
+		$line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty);
175
+		// or add a new one
176
+		if (! $line_item instanceof EE_Line_Item) {
177
+			$line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty);
178
+		}
179
+		$total_line_item->recalculate_total_including_taxes();
180
+		return $line_item;
181
+	}
182
+
183
+
184
+	/**
185
+	 * Returns the new line item created by adding a purchase of the ticket
186
+	 *
187
+	 * @param EE_Line_Item|null $total_line_item
188
+	 * @param EE_Ticket         $ticket
189
+	 * @param int               $qty
190
+	 * @return EE_Line_Item
191
+	 * @throws EE_Error
192
+	 * @throws InvalidArgumentException
193
+	 * @throws InvalidDataTypeException
194
+	 * @throws InvalidInterfaceException
195
+	 * @throws ReflectionException
196
+	 */
197
+	public static function increment_ticket_qty_if_already_in_cart(
198
+		?EE_Line_Item $total_line_item,
199
+		EE_Ticket $ticket,
200
+		int $qty = 1
201
+	): ?EE_Line_Item {
202
+		$line_item = null;
203
+		if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) {
204
+			$ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
205
+			foreach ($ticket_line_items as $ticket_line_item) {
206
+				if (
207
+					$ticket_line_item instanceof EE_Line_Item
208
+					&& $ticket_line_item->OBJ_ID() === $ticket->ID()
209
+				) {
210
+					$line_item = $ticket_line_item;
211
+					break;
212
+				}
213
+			}
214
+		}
215
+		if ($line_item instanceof EE_Line_Item) {
216
+			EEH_Line_Item::increment_quantity($line_item, $qty);
217
+			return $line_item;
218
+		}
219
+		return null;
220
+	}
221
+
222
+
223
+	/**
224
+	 * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected).
225
+	 * Does NOT save or recalculate other line items totals
226
+	 *
227
+	 * @param EE_Line_Item $line_item
228
+	 * @param int          $qty
229
+	 * @return void
230
+	 * @throws EE_Error
231
+	 * @throws InvalidArgumentException
232
+	 * @throws InvalidDataTypeException
233
+	 * @throws InvalidInterfaceException
234
+	 * @throws ReflectionException
235
+	 */
236
+	public static function increment_quantity(EE_Line_Item $line_item, int $qty = 1)
237
+	{
238
+		if (! $line_item->is_percent()) {
239
+			$qty += $line_item->quantity();
240
+			$line_item->set_quantity($qty);
241
+			$line_item->set_total($line_item->unit_price() * $qty);
242
+			$line_item->save();
243
+		}
244
+		foreach ($line_item->children() as $child) {
245
+			if ($child->is_sub_line_item()) {
246
+				EEH_Line_Item::update_quantity($child, $qty);
247
+			}
248
+		}
249
+	}
250
+
251
+
252
+	/**
253
+	 * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected).
254
+	 * Does NOT save or recalculate other line items totals
255
+	 *
256
+	 * @param EE_Line_Item $line_item
257
+	 * @param int          $qty
258
+	 * @return void
259
+	 * @throws EE_Error
260
+	 * @throws InvalidArgumentException
261
+	 * @throws InvalidDataTypeException
262
+	 * @throws InvalidInterfaceException
263
+	 * @throws ReflectionException
264
+	 */
265
+	public static function decrement_quantity(EE_Line_Item $line_item, int $qty = 1)
266
+	{
267
+		if (! $line_item->is_percent()) {
268
+			$qty = $line_item->quantity() - $qty;
269
+			$qty = max($qty, 0);
270
+			$line_item->set_quantity($qty);
271
+			$line_item->set_total($line_item->unit_price() * $qty);
272
+			$line_item->save();
273
+		}
274
+		foreach ($line_item->children() as $child) {
275
+			if ($child->is_sub_line_item()) {
276
+				EEH_Line_Item::update_quantity($child, $qty);
277
+			}
278
+		}
279
+	}
280
+
281
+
282
+	/**
283
+	 * Updates the line item and its children's quantities to the specified number.
284
+	 * Does NOT save them or recalculate totals.
285
+	 *
286
+	 * @param EE_Line_Item $line_item
287
+	 * @param int          $new_quantity
288
+	 * @throws EE_Error
289
+	 * @throws InvalidArgumentException
290
+	 * @throws InvalidDataTypeException
291
+	 * @throws InvalidInterfaceException
292
+	 * @throws ReflectionException
293
+	 */
294
+	public static function update_quantity(EE_Line_Item $line_item, int $new_quantity)
295
+	{
296
+		if (! $line_item->is_percent()) {
297
+			$line_item->set_quantity($new_quantity);
298
+			$line_item->set_total($line_item->unit_price() * $new_quantity);
299
+			$line_item->save();
300
+		}
301
+		foreach ($line_item->children() as $child) {
302
+			if ($child->is_sub_line_item()) {
303
+				EEH_Line_Item::update_quantity($child, $new_quantity);
304
+			}
305
+		}
306
+	}
307
+
308
+
309
+	/**
310
+	 * Returns the new line item created by adding a purchase of the ticket
311
+	 *
312
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
313
+	 * @param EE_Ticket    $ticket
314
+	 * @param int          $qty
315
+	 * @return EE_Line_Item
316
+	 * @throws EE_Error
317
+	 * @throws InvalidArgumentException
318
+	 * @throws InvalidDataTypeException
319
+	 * @throws InvalidInterfaceException
320
+	 * @throws ReflectionException
321
+	 */
322
+	public static function create_ticket_line_item(
323
+		EE_Line_Item $total_line_item,
324
+		EE_Ticket $ticket,
325
+		int $qty = 1
326
+	): EE_Line_Item {
327
+		$datetimes           = $ticket->datetimes();
328
+		$first_datetime      = reset($datetimes);
329
+		$first_datetime_name = esc_html__('Event', 'event_espresso');
330
+		if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) {
331
+			$first_datetime_name = $first_datetime->event()->name();
332
+		}
333
+		$event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name);
334
+		// get event subtotal line
335
+		$events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket);
336
+		$taxes            = $ticket->tax_price_modifiers();
337
+		// add $ticket to cart
338
+		$line_item = EE_Line_Item::new_instance(
339
+			[
340
+				'LIN_name'       => $ticket->name(),
341
+				'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
342
+				'LIN_unit_price' => $ticket->price(),
343
+				'LIN_quantity'   => $qty,
344
+				'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
345
+				'LIN_order'      => count($events_sub_total->children()),
346
+				'LIN_total'      => $ticket->price() * $qty,
347
+				'LIN_type'       => EEM_Line_Item::type_line_item,
348
+				'OBJ_ID'         => $ticket->ID(),
349
+				'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_TICKET,
350
+			]
351
+		);
352
+		$line_item = apply_filters(
353
+			'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
354
+			$line_item
355
+		);
356
+		if (! $line_item instanceof EE_Line_Item) {
357
+			throw new DomainException(
358
+				esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
359
+			);
360
+		}
361
+		$events_sub_total->add_child_line_item($line_item);
362
+		// now add the sub-line items
363
+		$running_pre_tax_total = 0;
364
+		$prices                = $ticket->prices();
365
+		if (empty($prices)) {
366
+			// WUT?!?! NO PRICES??? Well, just create a default price then.
367
+			$default_price = EEM_Price::instance()->get_new_price();
368
+			if ($default_price->amount() !== $ticket->price()) {
369
+				$default_price->set_amount($ticket->price());
370
+			}
371
+			$default_price->save();
372
+			$ticket->_add_relation_to($default_price, 'Price');
373
+			$ticket->save();
374
+			$prices = [$default_price];
375
+		}
376
+		foreach ($prices as $price) {
377
+			$sign        = $price->is_discount() ? -1 : 1;
378
+			$price_total = $price->is_percent()
379
+				? $running_pre_tax_total * $price->amount() / 100
380
+				: $price->amount() * $qty;
381
+			if ($price->is_percent()) {
382
+				$percent    = $sign * $price->amount();
383
+				$unit_price = 0;
384
+			} else {
385
+				$percent    = 0;
386
+				$unit_price = $sign * $price->amount();
387
+			}
388
+			$sub_line_item         = EE_Line_Item::new_instance(
389
+				[
390
+					'LIN_name'       => $price->name(),
391
+					'LIN_desc'       => $price->desc(),
392
+					'LIN_quantity'   => $price->is_percent() ? null : $qty,
393
+					'LIN_is_taxable' => false,
394
+					'LIN_order'      => $price->order(),
395
+					'LIN_total'      => $price_total,
396
+					'LIN_pretax'     => 0,
397
+					'LIN_unit_price' => $unit_price,
398
+					'LIN_percent'    => $percent,
399
+					'LIN_type'       => $price->is_tax() ? EEM_Line_Item::type_sub_tax
400
+						: EEM_Line_Item::type_sub_line_item,
401
+					'OBJ_ID'         => $price->ID(),
402
+					'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
403
+				]
404
+			);
405
+			$sub_line_item         = apply_filters(
406
+				'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
407
+				$sub_line_item
408
+			);
409
+			$running_pre_tax_total += ! $price->is_tax() ? $sign * $price_total : 0;
410
+			$line_item->add_child_line_item($sub_line_item);
411
+		}
412
+		$line_item->setPretaxTotal($running_pre_tax_total);
413
+		return $line_item;
414
+	}
415
+
416
+
417
+	/**
418
+	 * Adds the specified item under the pre-tax-sub-total line item. Automatically
419
+	 * re-calculates the line item totals and updates the related transaction. But
420
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
421
+	 * should probably change because of this).
422
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
423
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
424
+	 *
425
+	 * @param EE_Line_Item $total_line_item
426
+	 * @param EE_Line_Item $item to be added
427
+	 * @param bool         $recalculate_totals
428
+	 * @return boolean
429
+	 * @throws EE_Error
430
+	 * @throws InvalidArgumentException
431
+	 * @throws InvalidDataTypeException
432
+	 * @throws InvalidInterfaceException
433
+	 * @throws ReflectionException
434
+	 */
435
+	public static function add_item(
436
+		EE_Line_Item $total_line_item,
437
+		EE_Line_Item $item,
438
+		bool $recalculate_totals = true
439
+	): bool {
440
+		$pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item);
441
+		$success          = $pre_tax_subtotal->add_child_line_item($item);
442
+		if ($recalculate_totals) {
443
+			$total_line_item->recalculate_total_including_taxes();
444
+		}
445
+		return $success;
446
+	}
447
+
448
+
449
+	/**
450
+	 * cancels an existing ticket line item,
451
+	 * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item.
452
+	 * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
453
+	 *
454
+	 * @param EE_Line_Item $ticket_line_item
455
+	 * @param int          $qty
456
+	 * @return bool success
457
+	 * @throws EE_Error
458
+	 * @throws InvalidArgumentException
459
+	 * @throws InvalidDataTypeException
460
+	 * @throws InvalidInterfaceException
461
+	 * @throws ReflectionException
462
+	 */
463
+	public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
464
+	{
465
+		// validate incoming line_item
466
+		if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
467
+			throw new EE_Error(
468
+				sprintf(
469
+					esc_html__(
470
+						'The supplied line item must have an Object Type of "Ticket", not %1$s.',
471
+						'event_espresso'
472
+					),
473
+					$ticket_line_item->type()
474
+				)
475
+			);
476
+		}
477
+		if ($ticket_line_item->quantity() < $qty) {
478
+			throw new EE_Error(
479
+				sprintf(
480
+					esc_html__(
481
+						'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.',
482
+						'event_espresso'
483
+					),
484
+					$qty,
485
+					$ticket_line_item->quantity()
486
+				)
487
+			);
488
+		}
489
+		// decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this
490
+		$ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty);
491
+		foreach ($ticket_line_item->children() as $child_line_item) {
492
+			if (
493
+				$child_line_item->is_sub_line_item()
494
+				&& ! $child_line_item->is_percent()
495
+				&& ! $child_line_item->is_cancellation()
496
+			) {
497
+				$child_line_item->set_quantity($child_line_item->quantity() - $qty);
498
+			}
499
+		}
500
+		// get cancellation sub line item
501
+		$cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
502
+			$ticket_line_item,
503
+			EEM_Line_Item::type_cancellation
504
+		);
505
+		$cancellation_line_item = reset($cancellation_line_item);
506
+		// verify that this ticket was indeed previously cancelled
507
+		if ($cancellation_line_item instanceof EE_Line_Item) {
508
+			// increment cancelled quantity
509
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty);
510
+		} else {
511
+			// create cancellation sub line item
512
+			$cancellation_line_item = EE_Line_Item::new_instance(
513
+				[
514
+					'LIN_name'       => esc_html__('Cancellation', 'event_espresso'),
515
+					'LIN_desc'       => sprintf(
516
+						esc_html_x(
517
+							'Cancelled %1$s : %2$s',
518
+							'Cancelled Ticket Name : 2015-01-01 11:11',
519
+							'event_espresso'
520
+						),
521
+						$ticket_line_item->name(),
522
+						current_time(get_option('date_format') . ' ' . get_option('time_format'))
523
+					),
524
+					'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
525
+					'LIN_quantity'   => $qty,
526
+					'LIN_is_taxable' => $ticket_line_item->is_taxable(),
527
+					'LIN_order'      => count($ticket_line_item->children()),
528
+					'LIN_total'      => 0, // $ticket_line_item->unit_price()
529
+					'LIN_type'       => EEM_Line_Item::type_cancellation,
530
+				]
531
+			);
532
+			$ticket_line_item->add_child_line_item($cancellation_line_item);
533
+		}
534
+		if ($ticket_line_item->save_this_and_descendants() > 0) {
535
+			// decrement parent line item quantity
536
+			$event_line_item = $ticket_line_item->parent();
537
+			if (
538
+				$event_line_item instanceof EE_Line_Item
539
+				&& $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
540
+			) {
541
+				$event_line_item->set_quantity($event_line_item->quantity() - $qty);
542
+				$event_line_item->save();
543
+			}
544
+			EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
545
+			return true;
546
+		}
547
+		return false;
548
+	}
549
+
550
+
551
+	/**
552
+	 * reinstates (un-cancels?) a previously canceled ticket line item,
553
+	 * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item.
554
+	 * ALL totals and subtotals will NEED TO BE UPDATED after performing this action
555
+	 *
556
+	 * @param EE_Line_Item $ticket_line_item
557
+	 * @param int          $qty
558
+	 * @return bool success
559
+	 * @throws EE_Error
560
+	 * @throws InvalidArgumentException
561
+	 * @throws InvalidDataTypeException
562
+	 * @throws InvalidInterfaceException
563
+	 * @throws ReflectionException
564
+	 */
565
+	public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, int $qty = 1): bool
566
+	{
567
+		// validate incoming line_item
568
+		if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
569
+			throw new EE_Error(
570
+				sprintf(
571
+					esc_html__(
572
+						'The supplied line item must have an Object Type of "Ticket", not %1$s.',
573
+						'event_espresso'
574
+					),
575
+					$ticket_line_item->type()
576
+				)
577
+			);
578
+		}
579
+		// get cancellation sub line item
580
+		$cancellation_line_item = EEH_Line_Item::get_descendants_of_type(
581
+			$ticket_line_item,
582
+			EEM_Line_Item::type_cancellation
583
+		);
584
+		$cancellation_line_item = reset($cancellation_line_item);
585
+		// verify that this ticket was indeed previously cancelled
586
+		if (! $cancellation_line_item instanceof EE_Line_Item) {
587
+			return false;
588
+		}
589
+		if ($cancellation_line_item->quantity() > $qty) {
590
+			// decrement cancelled quantity
591
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
592
+		} elseif ($cancellation_line_item->quantity() === $qty) {
593
+			// decrement cancelled quantity in case anyone still has the object kicking around
594
+			$cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty);
595
+			// delete because quantity will end up as 0
596
+			$cancellation_line_item->delete();
597
+			// and attempt to destroy the object,
598
+			// even though PHP won't actually destroy it until it needs the memory
599
+			unset($cancellation_line_item);
600
+		} else {
601
+			// what ?!?! negative quantity ?!?!
602
+			throw new EE_Error(
603
+				sprintf(
604
+					esc_html__(
605
+						'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.',
606
+						'event_espresso'
607
+					),
608
+					$qty,
609
+					$cancellation_line_item->quantity()
610
+				)
611
+			);
612
+		}
613
+		// increment ticket quantity
614
+		$ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty);
615
+		if ($ticket_line_item->save_this_and_descendants() > 0) {
616
+			// increment parent line item quantity
617
+			$event_line_item = $ticket_line_item->parent();
618
+			if (
619
+				$event_line_item instanceof EE_Line_Item
620
+				&& $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
621
+			) {
622
+				$event_line_item->set_quantity($event_line_item->quantity() + $qty);
623
+			}
624
+			EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item);
625
+			return true;
626
+		}
627
+		return false;
628
+	}
629
+
630
+
631
+	/**
632
+	 * calls EEH_Line_Item::find_transaction_grand_total_for_line_item()
633
+	 * then EE_Line_Item::recalculate_total_including_taxes() on the result
634
+	 *
635
+	 * @param EE_Line_Item $line_item
636
+	 * @return float
637
+	 * @throws EE_Error
638
+	 * @throws InvalidArgumentException
639
+	 * @throws InvalidDataTypeException
640
+	 * @throws InvalidInterfaceException
641
+	 * @throws ReflectionException
642
+	 */
643
+	public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item): float
644
+	{
645
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item);
646
+		return $grand_total_line_item->recalculate_total_including_taxes();
647
+	}
648
+
649
+
650
+	/**
651
+	 * Gets the line item which contains the subtotal of all the items
652
+	 *
653
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
654
+	 * @return EE_Line_Item
655
+	 * @throws EE_Error
656
+	 * @throws InvalidArgumentException
657
+	 * @throws InvalidDataTypeException
658
+	 * @throws InvalidInterfaceException
659
+	 * @throws ReflectionException
660
+	 */
661
+	public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
662
+	{
663
+		$pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal');
664
+		return $pre_tax_subtotal instanceof EE_Line_Item
665
+			? $pre_tax_subtotal
666
+			: self::create_pre_tax_subtotal($total_line_item);
667
+	}
668
+
669
+
670
+	/**
671
+	 * Gets the line item for the taxes subtotal
672
+	 *
673
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
674
+	 * @return EE_Line_Item
675
+	 * @throws EE_Error
676
+	 * @throws InvalidArgumentException
677
+	 * @throws InvalidDataTypeException
678
+	 * @throws InvalidInterfaceException
679
+	 * @throws ReflectionException
680
+	 */
681
+	public static function get_taxes_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
682
+	{
683
+		$taxes = $total_line_item->get_child_line_item('taxes');
684
+		return $taxes ?: self::create_taxes_subtotal($total_line_item);
685
+	}
686
+
687
+
688
+	/**
689
+	 * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object
690
+	 *
691
+	 * @param EE_Line_Item        $line_item
692
+	 * @param EE_Transaction|null $transaction
693
+	 * @return void
694
+	 * @throws EE_Error
695
+	 * @throws InvalidArgumentException
696
+	 * @throws InvalidDataTypeException
697
+	 * @throws InvalidInterfaceException
698
+	 * @throws ReflectionException
699
+	 */
700
+	public static function set_TXN_ID(EE_Line_Item $line_item, ?EE_Transaction $transaction = null)
701
+	{
702
+		if ($transaction) {
703
+			/** @type EEM_Transaction $EEM_Transaction */
704
+			$EEM_Transaction = EE_Registry::instance()->load_model('Transaction');
705
+			$TXN_ID          = $EEM_Transaction->ensure_is_ID($transaction);
706
+			$line_item->set_TXN_ID($TXN_ID);
707
+		}
708
+	}
709
+
710
+
711
+	/**
712
+	 * Creates a new default total line item for the transaction,
713
+	 * and its tickets subtotal and taxes subtotal line items (and adds the
714
+	 * existing taxes as children of the taxes subtotal line item)
715
+	 *
716
+	 * @param EE_Transaction|null $transaction
717
+	 * @return EE_Line_Item of type total
718
+	 * @throws EE_Error
719
+	 * @throws InvalidArgumentException
720
+	 * @throws InvalidDataTypeException
721
+	 * @throws InvalidInterfaceException
722
+	 * @throws ReflectionException
723
+	 */
724
+	public static function create_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
725
+	{
726
+		$total_line_item = EE_Line_Item::new_instance(
727
+			[
728
+				'LIN_code' => 'total',
729
+				'LIN_name' => esc_html__('Grand Total', 'event_espresso'),
730
+				'LIN_type' => EEM_Line_Item::type_total,
731
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION,
732
+			]
733
+		);
734
+		$total_line_item = apply_filters(
735
+			'FHEE__EEH_Line_Item__create_total_line_item__total_line_item',
736
+			$total_line_item
737
+		);
738
+		self::set_TXN_ID($total_line_item, $transaction);
739
+		self::create_pre_tax_subtotal($total_line_item, $transaction);
740
+		self::create_taxes_subtotal($total_line_item, $transaction);
741
+		return $total_line_item;
742
+	}
743
+
744
+
745
+	/**
746
+	 * Creates a default items subtotal line item
747
+	 *
748
+	 * @param EE_Line_Item        $total_line_item
749
+	 * @param EE_Transaction|null $transaction
750
+	 * @return EE_Line_Item
751
+	 * @throws EE_Error
752
+	 * @throws InvalidArgumentException
753
+	 * @throws InvalidDataTypeException
754
+	 * @throws InvalidInterfaceException
755
+	 * @throws ReflectionException
756
+	 */
757
+	protected static function create_pre_tax_subtotal(
758
+		EE_Line_Item $total_line_item,
759
+		?EE_Transaction $transaction = null
760
+	): EE_Line_Item {
761
+		$pre_tax_line_item = EE_Line_Item::new_instance(
762
+			[
763
+				'LIN_code' => 'pre-tax-subtotal',
764
+				'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'),
765
+				'LIN_type' => EEM_Line_Item::type_sub_total,
766
+			]
767
+		);
768
+		$pre_tax_line_item = apply_filters(
769
+			'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item',
770
+			$pre_tax_line_item
771
+		);
772
+		self::set_TXN_ID($pre_tax_line_item, $transaction);
773
+		$total_line_item->add_child_line_item($pre_tax_line_item);
774
+		self::create_event_subtotal($pre_tax_line_item, $transaction);
775
+		return $pre_tax_line_item;
776
+	}
777
+
778
+
779
+	/**
780
+	 * Creates a line item for the taxes subtotal and finds all the tax prices
781
+	 * and applies taxes to it
782
+	 *
783
+	 * @param EE_Line_Item        $total_line_item of type EEM_Line_Item::type_total
784
+	 * @param EE_Transaction|null $transaction
785
+	 * @return EE_Line_Item
786
+	 * @throws EE_Error
787
+	 * @throws InvalidArgumentException
788
+	 * @throws InvalidDataTypeException
789
+	 * @throws InvalidInterfaceException
790
+	 * @throws ReflectionException
791
+	 */
792
+	protected static function create_taxes_subtotal(
793
+		EE_Line_Item $total_line_item,
794
+		?EE_Transaction $transaction = null
795
+	): EE_Line_Item {
796
+		$tax_line_item = EE_Line_Item::new_instance(
797
+			[
798
+				'LIN_code'  => 'taxes',
799
+				'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
800
+				'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
801
+				'LIN_order' => 1000,// this should always come last
802
+			]
803
+		);
804
+		$tax_line_item = apply_filters(
805
+			'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item',
806
+			$tax_line_item
807
+		);
808
+		self::set_TXN_ID($tax_line_item, $transaction);
809
+		$total_line_item->add_child_line_item($tax_line_item);
810
+		// and lastly, add the actual taxes
811
+		self::apply_taxes($total_line_item);
812
+		return $tax_line_item;
813
+	}
814
+
815
+
816
+	/**
817
+	 * Creates a default items subtotal line item
818
+	 *
819
+	 * @param EE_Line_Item        $pre_tax_line_item
820
+	 * @param EE_Transaction|null $transaction
821
+	 * @param EE_Event|null       $event
822
+	 * @return EE_Line_Item
823
+	 * @throws EE_Error
824
+	 * @throws InvalidArgumentException
825
+	 * @throws InvalidDataTypeException
826
+	 * @throws InvalidInterfaceException
827
+	 * @throws ReflectionException
828
+	 */
829
+	public static function create_event_subtotal(
830
+		EE_Line_Item $pre_tax_line_item,
831
+		?EE_Transaction $transaction = null,
832
+		?EE_Event $event = null
833
+	): EE_Line_Item {
834
+		$event_line_item = EE_Line_Item::new_instance(
835
+			[
836
+				'LIN_code' => self::get_event_code($event),
837
+				'LIN_name' => self::get_event_name($event),
838
+				'LIN_desc' => self::get_event_desc($event),
839
+				'LIN_type' => EEM_Line_Item::type_sub_total,
840
+				'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT,
841
+				'OBJ_ID'   => $event instanceof EE_Event ? $event->ID() : 0,
842
+			]
843
+		);
844
+		$event_line_item = apply_filters(
845
+			'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item',
846
+			$event_line_item
847
+		);
848
+		self::set_TXN_ID($event_line_item, $transaction);
849
+		$pre_tax_line_item->add_child_line_item($event_line_item);
850
+		return $event_line_item;
851
+	}
852
+
853
+
854
+	/**
855
+	 * Gets what the event ticket's code SHOULD be
856
+	 *
857
+	 * @param EE_Event|null $event
858
+	 * @return string
859
+	 * @throws EE_Error
860
+	 * @throws ReflectionException
861
+	 */
862
+	public static function get_event_code(?EE_Event $event = null): string
863
+	{
864
+		return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
865
+	}
866
+
867
+
868
+	/**
869
+	 * Gets the event name
870
+	 *
871
+	 * @param EE_Event|null $event
872
+	 * @return string
873
+	 * @throws EE_Error
874
+	 * @throws ReflectionException
875
+	 */
876
+	public static function get_event_name(?EE_Event $event = null): string
877
+	{
878
+		return $event instanceof EE_Event
879
+			? mb_substr($event->name(), 0, 245)
880
+			: esc_html__('Event', 'event_espresso');
881
+	}
882
+
883
+
884
+	/**
885
+	 * Gets the event excerpt
886
+	 *
887
+	 * @param EE_Event|null $event
888
+	 * @return string
889
+	 * @throws EE_Error
890
+	 * @throws ReflectionException
891
+	 */
892
+	public static function get_event_desc(?EE_Event $event = null): string
893
+	{
894
+		return $event instanceof EE_Event ? $event->short_description() : '';
895
+	}
896
+
897
+
898
+	/**
899
+	 * Given the grand total line item and a ticket, finds the event sub-total
900
+	 * line item the ticket's purchase should be added onto
901
+	 *
902
+	 * @access public
903
+	 * @param EE_Line_Item $grand_total the grand total line item
904
+	 * @param EE_Ticket    $ticket
905
+	 * @return EE_Line_Item
906
+	 * @throws EE_Error
907
+	 * @throws InvalidArgumentException
908
+	 * @throws InvalidDataTypeException
909
+	 * @throws InvalidInterfaceException
910
+	 * @throws ReflectionException
911
+	 */
912
+	public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket): EE_Line_Item
913
+	{
914
+		$first_datetime = $ticket->first_datetime();
915
+		if (! $first_datetime instanceof EE_Datetime) {
916
+			throw new EE_Error(
917
+				sprintf(
918
+					esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
919
+					$ticket->ID()
920
+				)
921
+			);
922
+		}
923
+		$event = $first_datetime->event();
924
+		if (! $event instanceof EE_Event) {
925
+			throw new EE_Error(
926
+				sprintf(
927
+					esc_html__(
928
+						'The supplied ticket (ID %d) has no event data associated with it.',
929
+						'event_espresso'
930
+					),
931
+					$ticket->ID()
932
+				)
933
+			);
934
+		}
935
+		$events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
936
+		if (! $events_sub_total instanceof EE_Line_Item) {
937
+			throw new EE_Error(
938
+				sprintf(
939
+					esc_html__(
940
+						'There is no events sub-total for ticket %s on total line item %d',
941
+						'event_espresso'
942
+					),
943
+					$ticket->ID(),
944
+					$grand_total->ID()
945
+				)
946
+			);
947
+		}
948
+		return $events_sub_total;
949
+	}
950
+
951
+
952
+	/**
953
+	 * Gets the event line item
954
+	 *
955
+	 * @param EE_Line_Item  $grand_total
956
+	 * @param EE_Event|null $event
957
+	 * @return EE_Line_Item for the event subtotal which is a child of $grand_total
958
+	 * @throws EE_Error
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidDataTypeException
961
+	 * @throws InvalidInterfaceException
962
+	 * @throws ReflectionException
963
+	 */
964
+	public static function get_event_line_item(EE_Line_Item $grand_total, ?EE_Event $event = null): ?EE_Line_Item
965
+	{
966
+		/** @type EE_Event $event */
967
+		$event           = EEM_Event::instance()->ensure_is_obj($event, true);
968
+		$event_line_item = null;
969
+		$found           = false;
970
+		foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
971
+			// default event subtotal, we should only ever find this the first time this method is called
972
+			if (! $event_line_item->OBJ_ID()) {
973
+				// let's use this! but first... set the event details
974
+				EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
975
+				$found = true;
976
+				break;
977
+			}
978
+			if ($event_line_item->OBJ_ID() === $event->ID()) {
979
+				// found existing line item for this event in the cart, so break out of loop and use this one
980
+				$found = true;
981
+				break;
982
+			}
983
+		}
984
+		if (! $found) {
985
+			// there is no event sub-total yet, so add it
986
+			$pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
987
+			// create a new "event" subtotal below that
988
+			$event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event);
989
+			// and set the event details
990
+			EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
991
+		}
992
+		return $event_line_item;
993
+	}
994
+
995
+
996
+	/**
997
+	 * Creates a default items subtotal line item
998
+	 *
999
+	 * @param EE_Line_Item        $event_line_item
1000
+	 * @param EE_Event|null       $event
1001
+	 * @param EE_Transaction|null $transaction
1002
+	 * @return void
1003
+	 * @throws EE_Error
1004
+	 * @throws InvalidArgumentException
1005
+	 * @throws InvalidDataTypeException
1006
+	 * @throws InvalidInterfaceException
1007
+	 * @throws ReflectionException
1008
+	 */
1009
+	public static function set_event_subtotal_details(
1010
+		EE_Line_Item $event_line_item,
1011
+		EE_Event $event = null,
1012
+		?EE_Transaction $transaction = null
1013
+	) {
1014
+		if ($event instanceof EE_Event) {
1015
+			$event_line_item->set_code(self::get_event_code($event));
1016
+			$event_line_item->set_name(self::get_event_name($event));
1017
+			$event_line_item->set_desc(self::get_event_desc($event));
1018
+			$event_line_item->set_OBJ_ID($event->ID());
1019
+		}
1020
+		self::set_TXN_ID($event_line_item, $transaction);
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * Finds what taxes should apply, adds them as tax line items under the taxes sub-total,
1026
+	 * and recalculates the taxes sub-total and the grand total. Resets the taxes, so
1027
+	 * any old taxes are removed
1028
+	 *
1029
+	 * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
1030
+	 * @param bool         $update_txn_status
1031
+	 * @return bool
1032
+	 * @throws EE_Error
1033
+	 * @throws InvalidArgumentException
1034
+	 * @throws InvalidDataTypeException
1035
+	 * @throws InvalidInterfaceException
1036
+	 * @throws ReflectionException
1037
+	 * @throws RuntimeException
1038
+	 */
1039
+	public static function apply_taxes(EE_Line_Item $total_line_item, bool $update_txn_status = false): bool
1040
+	{
1041
+		$total_line_item       = EEH_Line_Item::find_transaction_grand_total_for_line_item($total_line_item);
1042
+		$taxes_line_item       = self::get_taxes_subtotal($total_line_item);
1043
+		$existing_global_taxes = $taxes_line_item->tax_descendants();
1044
+		$updates               = false;
1045
+		// loop thru taxes
1046
+		$global_taxes = EEH_Line_Item::getGlobalTaxes();
1047
+		foreach ($global_taxes as $order => $taxes) {
1048
+			foreach ($taxes as $tax) {
1049
+				if ($tax instanceof EE_Price) {
1050
+					$found = false;
1051
+					// check if this is already an existing tax
1052
+					foreach ($existing_global_taxes as $existing_global_tax) {
1053
+						if ($tax->ID() === $existing_global_tax->OBJ_ID()) {
1054
+							// maybe update the tax rate in case it has changed
1055
+							if ($existing_global_tax->percent() !== $tax->amount()) {
1056
+								$existing_global_tax->set_percent($tax->amount());
1057
+								$existing_global_tax->save();
1058
+								$updates = true;
1059
+							}
1060
+							$found = true;
1061
+							break;
1062
+						}
1063
+					}
1064
+					if (! $found) {
1065
+						// add a new line item for this global tax
1066
+						$tax_line_item = apply_filters(
1067
+							'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
1068
+							EE_Line_Item::new_instance(
1069
+								[
1070
+									'LIN_name'       => $tax->name(),
1071
+									'LIN_desc'       => $tax->desc(),
1072
+									'LIN_percent'    => $tax->amount(),
1073
+									'LIN_is_taxable' => false,
1074
+									'LIN_order'      => $order,
1075
+									'LIN_total'      => 0,
1076
+									'LIN_type'       => EEM_Line_Item::type_tax,
1077
+									'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
1078
+									'OBJ_ID'         => $tax->ID(),
1079
+								]
1080
+							)
1081
+						);
1082
+						$updates       = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1083
+					}
1084
+				}
1085
+			}
1086
+		}
1087
+		// only recalculate totals if something changed
1088
+		if ($updates || $update_txn_status) {
1089
+			$total_line_item->recalculate_total_including_taxes($update_txn_status);
1090
+			return true;
1091
+		}
1092
+		return false;
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 * Ensures that taxes have been applied to the order, if not applies them.
1098
+	 * Returns the total amount of tax
1099
+	 *
1100
+	 * @param EE_Line_Item|null $total_line_item of type EEM_Line_Item::type_total
1101
+	 * @return float
1102
+	 * @throws EE_Error
1103
+	 * @throws InvalidArgumentException
1104
+	 * @throws InvalidDataTypeException
1105
+	 * @throws InvalidInterfaceException
1106
+	 * @throws ReflectionException
1107
+	 */
1108
+	public static function ensure_taxes_applied(?EE_Line_Item $total_line_item): float
1109
+	{
1110
+		$taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1111
+		if (! $taxes_subtotal->children()) {
1112
+			self::apply_taxes($total_line_item);
1113
+		}
1114
+		return $taxes_subtotal->total();
1115
+	}
1116
+
1117
+
1118
+	/**
1119
+	 * Deletes ALL children of the passed line item
1120
+	 *
1121
+	 * @param EE_Line_Item $parent_line_item
1122
+	 * @return bool
1123
+	 * @throws EE_Error
1124
+	 * @throws InvalidArgumentException
1125
+	 * @throws InvalidDataTypeException
1126
+	 * @throws InvalidInterfaceException
1127
+	 * @throws ReflectionException
1128
+	 */
1129
+	public static function delete_all_child_items(EE_Line_Item $parent_line_item)
1130
+	{
1131
+		$deleted = 0;
1132
+		foreach ($parent_line_item->children() as $child_line_item) {
1133
+			if ($child_line_item instanceof EE_Line_Item) {
1134
+				$deleted += EEH_Line_Item::delete_all_child_items($child_line_item);
1135
+				if ($child_line_item->ID()) {
1136
+					$child_line_item->delete();
1137
+					unset($child_line_item);
1138
+				} else {
1139
+					$parent_line_item->delete_child_line_item($child_line_item->code());
1140
+				}
1141
+				$deleted++;
1142
+			}
1143
+		}
1144
+		return $deleted;
1145
+	}
1146
+
1147
+
1148
+	/**
1149
+	 * Deletes the line items as indicated by the line item code(s) provided,
1150
+	 * regardless of where they're found in the line item tree. Automatically
1151
+	 * re-calculates the line item totals and updates the related transaction. But
1152
+	 * DOES NOT automatically upgrade the transaction's registrations' final prices (which
1153
+	 * should probably change because of this).
1154
+	 * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item()
1155
+	 * after using this, to keep the registration final prices in-sync with the transaction's total.
1156
+	 *
1157
+	 * @param EE_Line_Item      $total_line_item of type EEM_Line_Item::type_total
1158
+	 * @param array|bool|string $line_item_codes
1159
+	 * @return int number of items successfully removed
1160
+	 * @throws EE_Error
1161
+	 * @throws ReflectionException
1162
+	 */
1163
+	public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false)
1164
+	{
1165
+		if ($total_line_item->type() !== EEM_Line_Item::type_total) {
1166
+			EE_Error::doing_it_wrong(
1167
+				'EEH_Line_Item::delete_items',
1168
+				esc_html__(
1169
+					'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly',
1170
+					'event_espresso'
1171
+				),
1172
+				'4.6.18'
1173
+			);
1174
+		}
1175
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1176
+
1177
+		// check if only a single line_item_id was passed
1178
+		if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1179
+			// place single line_item_id in an array to appear as multiple line_item_ids
1180
+			$line_item_codes = [$line_item_codes];
1181
+		}
1182
+		$removals = 0;
1183
+		// cycle thru line_item_ids
1184
+		foreach ($line_item_codes as $line_item_id) {
1185
+			$removals += $total_line_item->delete_child_line_item($line_item_id);
1186
+		}
1187
+
1188
+		if ($removals > 0) {
1189
+			$total_line_item->recalculate_taxes_and_tax_total();
1190
+			return $removals;
1191
+		} else {
1192
+			return false;
1193
+		}
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * Overwrites the previous tax by clearing out the old taxes, and creates a new
1199
+	 * tax and updates the total line item accordingly
1200
+	 *
1201
+	 * @param EE_Line_Item $total_line_item
1202
+	 * @param float        $amount
1203
+	 * @param string       $name
1204
+	 * @param string       $description
1205
+	 * @param string       $code
1206
+	 * @param boolean      $add_to_existing_line_item
1207
+	 *                          if true, and a duplicate line item with the same code is found,
1208
+	 *                          $amount will be added onto it; otherwise will simply set the taxes to match $amount
1209
+	 * @return EE_Line_Item the new tax line item created
1210
+	 * @throws EE_Error
1211
+	 * @throws InvalidArgumentException
1212
+	 * @throws InvalidDataTypeException
1213
+	 * @throws InvalidInterfaceException
1214
+	 * @throws ReflectionException
1215
+	 */
1216
+	public static function set_total_tax_to(
1217
+		EE_Line_Item $total_line_item,
1218
+		float $amount,
1219
+		string $name = '',
1220
+		string $description = '',
1221
+		string $code = '',
1222
+		bool $add_to_existing_line_item = false
1223
+	): EE_Line_Item {
1224
+		$tax_subtotal  = self::get_taxes_subtotal($total_line_item);
1225
+		$taxable_total = $total_line_item->taxable_total();
1226
+
1227
+		if ($add_to_existing_line_item) {
1228
+			$new_tax = $tax_subtotal->get_child_line_item($code);
1229
+			EEM_Line_Item::instance()->delete(
1230
+				[['LIN_code' => ['!=', $code], 'LIN_parent' => $tax_subtotal->ID()]]
1231
+			);
1232
+		} else {
1233
+			$new_tax = null;
1234
+			$tax_subtotal->delete_children_line_items();
1235
+		}
1236
+		if ($new_tax) {
1237
+			$new_tax->set_total($new_tax->total() + $amount);
1238
+			$new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
1239
+		} else {
1240
+			// no existing tax item. Create it
1241
+			$new_tax = EE_Line_Item::new_instance(
1242
+				[
1243
+					'TXN_ID'      => $total_line_item->TXN_ID(),
1244
+					'LIN_name'    => $name ?: esc_html__('Tax', 'event_espresso'),
1245
+					'LIN_desc'    => $description ?: '',
1246
+					'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0,
1247
+					'LIN_total'   => $amount,
1248
+					'LIN_parent'  => $tax_subtotal->ID(),
1249
+					'LIN_type'    => EEM_Line_Item::type_tax,
1250
+					'LIN_code'    => $code,
1251
+				]
1252
+			);
1253
+		}
1254
+
1255
+		$new_tax = apply_filters(
1256
+			'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal',
1257
+			$new_tax,
1258
+			$total_line_item
1259
+		);
1260
+		$new_tax->save();
1261
+		$tax_subtotal->set_total($new_tax->total());
1262
+		$tax_subtotal->save();
1263
+		$total_line_item->recalculate_total_including_taxes();
1264
+		return $new_tax;
1265
+	}
1266
+
1267
+
1268
+	/**
1269
+	 * Makes all the line items which are children of $line_item taxable (or not).
1270
+	 * Does NOT save the line items
1271
+	 *
1272
+	 * @param EE_Line_Item $line_item
1273
+	 * @param boolean      $taxable
1274
+	 * @param string|null  $code_substring_for_whitelist if this string is part of the line item's code
1275
+	 *                                                   it will be whitelisted (ie, except from becoming taxable)
1276
+	 * @throws EE_Error
1277
+	 * @throws ReflectionException
1278
+	 */
1279
+	public static function set_line_items_taxable(
1280
+		EE_Line_Item $line_item,
1281
+		bool $taxable = true,
1282
+		?string $code_substring_for_whitelist = null
1283
+	) {
1284
+		$whitelisted = false;
1285
+		if ($code_substring_for_whitelist !== null) {
1286
+			$whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1287
+		}
1288
+		if (! $whitelisted && $line_item->is_line_item()) {
1289
+			$line_item->set_is_taxable($taxable);
1290
+		}
1291
+		foreach ($line_item->children() as $child_line_item) {
1292
+			EEH_Line_Item::set_line_items_taxable(
1293
+				$child_line_item,
1294
+				$taxable,
1295
+				$code_substring_for_whitelist
1296
+			);
1297
+		}
1298
+	}
1299
+
1300
+
1301
+	/**
1302
+	 * Gets all descendants that are event subtotals
1303
+	 *
1304
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1305
+	 * @return EE_Line_Item[]
1306
+	 * @throws EE_Error
1307
+	 * @throws ReflectionException
1308
+	 * @uses  EEH_Line_Item::get_subtotals_of_object_type()
1309
+	 */
1310
+	public static function get_event_subtotals(EE_Line_Item $parent_line_item): array
1311
+	{
1312
+		return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT);
1313
+	}
1314
+
1315
+
1316
+	/**
1317
+	 * Gets all descendants subtotals that match the supplied object type
1318
+	 *
1319
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1320
+	 * @param string       $obj_type
1321
+	 * @return EE_Line_Item[]
1322
+	 * @throws EE_Error
1323
+	 * @throws ReflectionException
1324
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1325
+	 */
1326
+	public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1327
+	{
1328
+		return self::_get_descendants_by_type_and_object_type(
1329
+			$parent_line_item,
1330
+			EEM_Line_Item::type_sub_total,
1331
+			$obj_type
1332
+		);
1333
+	}
1334
+
1335
+
1336
+	/**
1337
+	 * Gets all descendants that are tickets
1338
+	 *
1339
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1340
+	 * @return EE_Line_Item[]
1341
+	 * @throws EE_Error
1342
+	 * @throws ReflectionException
1343
+	 * @uses  EEH_Line_Item::get_line_items_of_object_type()
1344
+	 */
1345
+	public static function get_ticket_line_items(EE_Line_Item $parent_line_item): array
1346
+	{
1347
+		return self::get_line_items_of_object_type(
1348
+			$parent_line_item,
1349
+			EEM_Line_Item::OBJ_TYPE_TICKET
1350
+		);
1351
+	}
1352
+
1353
+
1354
+	/**
1355
+	 * Gets all descendants subtotals that match the supplied object type
1356
+	 *
1357
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1358
+	 * @param string       $obj_type
1359
+	 * @return EE_Line_Item[]
1360
+	 * @throws EE_Error
1361
+	 * @throws ReflectionException
1362
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1363
+	 */
1364
+	public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, string $obj_type = ''): array
1365
+	{
1366
+		return self::_get_descendants_by_type_and_object_type(
1367
+			$parent_line_item,
1368
+			EEM_Line_Item::type_line_item,
1369
+			$obj_type
1370
+		);
1371
+	}
1372
+
1373
+
1374
+	/**
1375
+	 * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax'
1376
+	 *
1377
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1378
+	 * @return EE_Line_Item[]
1379
+	 * @throws EE_Error
1380
+	 * @throws ReflectionException
1381
+	 * @uses  EEH_Line_Item::get_descendants_of_type()
1382
+	 */
1383
+	public static function get_tax_descendants(EE_Line_Item $parent_line_item): array
1384
+	{
1385
+		return EEH_Line_Item::get_descendants_of_type(
1386
+			$parent_line_item,
1387
+			EEM_Line_Item::type_tax
1388
+		);
1389
+	}
1390
+
1391
+
1392
+	/**
1393
+	 * Gets all the real items purchased which are children of this item
1394
+	 *
1395
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1396
+	 * @return EE_Line_Item[]
1397
+	 * @throws EE_Error
1398
+	 * @throws ReflectionException
1399
+	 * @uses  EEH_Line_Item::get_descendants_of_type()
1400
+	 */
1401
+	public static function get_line_item_descendants(EE_Line_Item $parent_line_item): array
1402
+	{
1403
+		return EEH_Line_Item::get_descendants_of_type(
1404
+			$parent_line_item,
1405
+			EEM_Line_Item::type_line_item
1406
+		);
1407
+	}
1408
+
1409
+
1410
+	/**
1411
+	 * Gets all descendants of supplied line item that match the supplied line item type
1412
+	 *
1413
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1414
+	 * @param string       $line_item_type   one of the EEM_Line_Item constants
1415
+	 * @return EE_Line_Item[]
1416
+	 * @throws EE_Error
1417
+	 * @throws ReflectionException
1418
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1419
+	 */
1420
+	public static function get_descendants_of_type(EE_Line_Item $parent_line_item, string $line_item_type): array
1421
+	{
1422
+		return self::_get_descendants_by_type_and_object_type(
1423
+			$parent_line_item,
1424
+			$line_item_type
1425
+		);
1426
+	}
1427
+
1428
+
1429
+	/**
1430
+	 * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1431
+	 * as well
1432
+	 *
1433
+	 * @param EE_Line_Item $parent_line_item  - the line item to find descendants of
1434
+	 * @param string       $line_item_type    one of the EEM_Line_Item constants
1435
+	 * @param string|null  $obj_type          object model class name (minus prefix) or NULL to ignore object type when
1436
+	 *                                        searching
1437
+	 * @return EE_Line_Item[]
1438
+	 * @throws EE_Error
1439
+	 * @throws ReflectionException
1440
+	 */
1441
+	protected static function _get_descendants_by_type_and_object_type(
1442
+		EE_Line_Item $parent_line_item,
1443
+		string $line_item_type,
1444
+		?string $obj_type = null
1445
+	): array {
1446
+		$objects = [];
1447
+		foreach ($parent_line_item->children() as $child_line_item) {
1448
+			if ($child_line_item instanceof EE_Line_Item) {
1449
+				if (
1450
+					$child_line_item->type() === $line_item_type
1451
+					&& (
1452
+						$child_line_item->OBJ_type() === $obj_type || $obj_type === null
1453
+					)
1454
+				) {
1455
+					$objects[] = $child_line_item;
1456
+				} else {
1457
+					// go-through-all-its children looking for more matches
1458
+					$objects = array_merge(
1459
+						$objects,
1460
+						self::_get_descendants_by_type_and_object_type(
1461
+							$child_line_item,
1462
+							$line_item_type,
1463
+							$obj_type
1464
+						)
1465
+					);
1466
+				}
1467
+			}
1468
+		}
1469
+		return $objects;
1470
+	}
1471
+
1472
+
1473
+	/**
1474
+	 * Gets all descendants subtotals that match the supplied object type
1475
+	 *
1476
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1477
+	 * @param string       $OBJ_type         object type (like Event)
1478
+	 * @param array        $OBJ_IDs          array of OBJ_IDs
1479
+	 * @return EE_Line_Item[]
1480
+	 * @throws EE_Error
1481
+	 * @throws ReflectionException
1482
+	 * @uses  EEH_Line_Item::_get_descendants_by_type_and_object_type()
1483
+	 */
1484
+	public static function get_line_items_by_object_type_and_IDs(
1485
+		EE_Line_Item $parent_line_item,
1486
+		string $OBJ_type = '',
1487
+		array $OBJ_IDs = []
1488
+	): array {
1489
+		return self::_get_descendants_by_object_type_and_object_ID(
1490
+			$parent_line_item,
1491
+			$OBJ_type,
1492
+			$OBJ_IDs
1493
+		);
1494
+	}
1495
+
1496
+
1497
+	/**
1498
+	 * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type
1499
+	 * as well
1500
+	 *
1501
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1502
+	 * @param string       $OBJ_type         object type (like Event)
1503
+	 * @param array        $OBJ_IDs          array of OBJ_IDs
1504
+	 * @return EE_Line_Item[]
1505
+	 * @throws EE_Error
1506
+	 * @throws ReflectionException
1507
+	 */
1508
+	protected static function _get_descendants_by_object_type_and_object_ID(
1509
+		EE_Line_Item $parent_line_item,
1510
+		string $OBJ_type,
1511
+		array $OBJ_IDs
1512
+	): array {
1513
+		$objects = [];
1514
+		foreach ($parent_line_item->children() as $child_line_item) {
1515
+			if ($child_line_item instanceof EE_Line_Item) {
1516
+				if (
1517
+					$child_line_item->OBJ_type() === $OBJ_type
1518
+					&& in_array($child_line_item->OBJ_ID(), $OBJ_IDs)
1519
+				) {
1520
+					$objects[] = $child_line_item;
1521
+				} else {
1522
+					// go-through-all-its children looking for more matches
1523
+					$objects = array_merge(
1524
+						$objects,
1525
+						self::_get_descendants_by_object_type_and_object_ID(
1526
+							$child_line_item,
1527
+							$OBJ_type,
1528
+							$OBJ_IDs
1529
+						)
1530
+					);
1531
+				}
1532
+			}
1533
+		}
1534
+		return $objects;
1535
+	}
1536
+
1537
+
1538
+	/**
1539
+	 * Uses a breadth-first-search in order to find the nearest descendant of
1540
+	 * the specified type and returns it, else NULL
1541
+	 *
1542
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1543
+	 * @param string       $type             like one of the EEM_Line_Item::type_*
1544
+	 * @return EE_Line_Item
1545
+	 * @throws EE_Error
1546
+	 * @throws InvalidArgumentException
1547
+	 * @throws InvalidDataTypeException
1548
+	 * @throws InvalidInterfaceException
1549
+	 * @throws ReflectionException
1550
+	 * @uses  EEH_Line_Item::_get_nearest_descendant()
1551
+	 */
1552
+	public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, string $type): ?EE_Line_Item
1553
+	{
1554
+		return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type);
1555
+	}
1556
+
1557
+
1558
+	/**
1559
+	 * Uses a breadth-first-search in order to find the nearest descendant
1560
+	 * having the specified LIN_code and returns it, else NULL
1561
+	 *
1562
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1563
+	 * @param string       $code             any value used for LIN_code
1564
+	 * @return EE_Line_Item
1565
+	 * @throws EE_Error
1566
+	 * @throws InvalidArgumentException
1567
+	 * @throws InvalidDataTypeException
1568
+	 * @throws InvalidInterfaceException
1569
+	 * @throws ReflectionException
1570
+	 * @uses  EEH_Line_Item::_get_nearest_descendant()
1571
+	 */
1572
+	public static function get_nearest_descendant_having_code(
1573
+		EE_Line_Item $parent_line_item,
1574
+		string $code
1575
+	): ?EE_Line_Item {
1576
+		return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code);
1577
+	}
1578
+
1579
+
1580
+	/**
1581
+	 * Uses a breadth-first-search in order to find the nearest descendant
1582
+	 * having the specified LIN_code and returns it, else NULL
1583
+	 *
1584
+	 * @param EE_Line_Item $parent_line_item - the line item to find descendants of
1585
+	 * @param string       $search_field     name of EE_Line_Item property
1586
+	 * @param mixed        $value            any value stored in $search_field
1587
+	 * @return EE_Line_Item
1588
+	 * @throws EE_Error
1589
+	 * @throws InvalidArgumentException
1590
+	 * @throws InvalidDataTypeException
1591
+	 * @throws InvalidInterfaceException
1592
+	 * @throws ReflectionException
1593
+	 */
1594
+	protected static function _get_nearest_descendant(
1595
+		EE_Line_Item $parent_line_item,
1596
+		string $search_field,
1597
+		$value
1598
+	): ?EE_Line_Item {
1599
+		foreach ($parent_line_item->children() as $child) {
1600
+			if ($child->get($search_field) == $value) {
1601
+				return $child;
1602
+			}
1603
+		}
1604
+		foreach ($parent_line_item->children() as $child) {
1605
+			$descendant_found = self::_get_nearest_descendant(
1606
+				$child,
1607
+				$search_field,
1608
+				$value
1609
+			);
1610
+			if ($descendant_found) {
1611
+				return $descendant_found;
1612
+			}
1613
+		}
1614
+		return null;
1615
+	}
1616
+
1617
+
1618
+	/**
1619
+	 * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction,
1620
+	 * else recursively walks up the line item tree until a parent of type total is found,
1621
+	 *
1622
+	 * @param EE_Line_Item $line_item
1623
+	 * @return EE_Line_Item
1624
+	 * @throws EE_Error
1625
+	 * @throws ReflectionException
1626
+	 */
1627
+	public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item): EE_Line_Item
1628
+	{
1629
+		if ($line_item->is_total()) {
1630
+			return $line_item;
1631
+		}
1632
+		if ($line_item->TXN_ID()) {
1633
+			$total_line_item = $line_item->transaction()->total_line_item(false);
1634
+			if ($total_line_item instanceof EE_Line_Item) {
1635
+				return $total_line_item;
1636
+			}
1637
+		} else {
1638
+			$line_item_parent = $line_item->parent();
1639
+			if ($line_item_parent instanceof EE_Line_Item) {
1640
+				if ($line_item_parent->is_total()) {
1641
+					return $line_item_parent;
1642
+				}
1643
+				return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent);
1644
+			}
1645
+		}
1646
+		throw new EE_Error(
1647
+			sprintf(
1648
+				esc_html__(
1649
+					'A valid grand total for line item %1$d was not found.',
1650
+					'event_espresso'
1651
+				),
1652
+				$line_item->ID()
1653
+			)
1654
+		);
1655
+	}
1656
+
1657
+
1658
+	/**
1659
+	 * Prints out a representation of the line item tree
1660
+	 *
1661
+	 * @param EE_Line_Item $line_item
1662
+	 * @param int          $indentation
1663
+	 * @param bool         $top_level
1664
+	 * @return void
1665
+	 * @throws EE_Error
1666
+	 * @throws ReflectionException
1667
+	 */
1668
+	public static function visualize(EE_Line_Item $line_item, int $indentation = 0, bool $top_level = true)
1669
+	{
1670
+		$testing  = defined('EE_TESTS_DIR');
1671
+		$new_line = $testing ? "\n" : '<br />';
1672
+		if ($top_level && ! $testing) {
1673
+			echo '<div style="position: relative; z-index: 9999; margin: 2rem;">';
1674
+			echo '<pre style="padding: 2rem 3rem; color: #00CCFF; background: #363636;">';
1675
+		}
1676
+		if ($indentation) {
1677
+			echo $new_line;
1678
+		}
1679
+		echo str_repeat('. ', $indentation);
1680
+		$breakdown = '';
1681
+		if ($line_item->is_line_item() || $line_item->is_sub_line_item() || $line_item->isSubTax()) {
1682
+			if ($line_item->is_percent()) {
1683
+				$breakdown = "{$line_item->percent()}%";
1684
+			} else {
1685
+				$breakdown = "\${$line_item->unit_price()} x {$line_item->quantity()}";
1686
+			}
1687
+		}
1688
+		echo wp_kses($line_item->name(), AllowedTags::getAllowedTags());
1689
+		echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : ";
1690
+		echo "\${$line_item->total()}";
1691
+		if ($breakdown) {
1692
+			echo " ( $breakdown )";
1693
+		}
1694
+		if ($line_item->is_taxable()) {
1695
+			echo '  * taxable';
1696
+		}
1697
+		if ($line_item->children()) {
1698
+			foreach ($line_item->children() as $child) {
1699
+				self::visualize($child, $indentation + 1, false);
1700
+			}
1701
+		}
1702
+		if ($top_level && ! $testing) {
1703
+			echo $new_line;
1704
+			echo '</pre></div>';
1705
+		}
1706
+	}
1707
+
1708
+
1709
+	/**
1710
+	 * Calculates the registration's final price, taking into account that they
1711
+	 * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes,
1712
+	 * and receive a portion of any transaction-wide discounts.
1713
+	 * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount
1714
+	 * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get
1715
+	 * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50
1716
+	 * and brent's final price should be $5.50.
1717
+	 * In order to do this, we basically need to traverse the line item tree calculating
1718
+	 * the running totals (just as if we were recalculating the total), but when we identify
1719
+	 * regular line items, we need to keep track of their share of the grand total.
1720
+	 * Also, we need to keep track of the TAXABLE total for each ticket purchase, so
1721
+	 * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total"
1722
+	 * when there are non-taxable items; otherwise they would be the same)
1723
+	 *
1724
+	 * @param EE_Line_Item $line_item
1725
+	 * @param array        $billable_ticket_quantities          array of EE_Ticket IDs and their corresponding quantity
1726
+	 *                                                          that can be included in price calculations at this
1727
+	 *                                                          moment
1728
+	 * @return array        keys are line items for tickets IDs and values are their share of the running total,
1729
+	 *                                                          plus the key 'total', and 'taxable' which also has keys
1730
+	 *                                                          of all the ticket IDs. Eg array(
1731
+	 *                                                          12 => 4.3
1732
+	 *                                                          23 => 8.0
1733
+	 *                                                          'total' => 16.6,
1734
+	 *                                                          'taxable' => array(
1735
+	 *                                                          12 => 10,
1736
+	 *                                                          23 => 4
1737
+	 *                                                          ).
1738
+	 *                                                          So to find which registrations have which final price,
1739
+	 *                                                          we need to find which line item is theirs, which can be
1740
+	 *                                                          done with
1741
+	 *                                                          `EEM_Line_Item::instance()->get_line_item_for_registration(
1742
+	 *                                                          $registration );`
1743
+	 * @throws EE_Error
1744
+	 * @throws InvalidArgumentException
1745
+	 * @throws InvalidDataTypeException
1746
+	 * @throws InvalidInterfaceException
1747
+	 * @throws ReflectionException
1748
+	 */
1749
+	public static function calculate_reg_final_prices_per_line_item(
1750
+		EE_Line_Item $line_item,
1751
+		array $billable_ticket_quantities = []
1752
+	): array {
1753
+		$running_totals = [
1754
+			'total'   => 0,
1755
+			'taxable' => ['total' => 0],
1756
+		];
1757
+		foreach ($line_item->children() as $child_line_item) {
1758
+			switch ($child_line_item->type()) {
1759
+				case EEM_Line_Item::type_sub_total:
1760
+					$running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1761
+						$child_line_item,
1762
+						$billable_ticket_quantities
1763
+					);
1764
+					// combine arrays but preserve numeric keys
1765
+					$running_totals                     = array_replace_recursive(
1766
+						$running_totals_from_subtotal,
1767
+						$running_totals
1768
+					);
1769
+					$running_totals['total']            += $running_totals_from_subtotal['total'];
1770
+					$running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total'];
1771
+					break;
1772
+
1773
+				case EEM_Line_Item::type_tax_sub_total:
1774
+					// find how much the taxes percentage is
1775
+					if ($child_line_item->percent() !== 0.0) {
1776
+						$tax_percent_decimal = $child_line_item->percent() / 100;
1777
+					} else {
1778
+						$tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100;
1779
+					}
1780
+					// and apply to all the taxable totals, and add to the pretax totals
1781
+					foreach ($running_totals as $line_item_id => $this_running_total) {
1782
+						// "total" and "taxable" array key is an exception
1783
+						if ($line_item_id === 'taxable') {
1784
+							continue;
1785
+						}
1786
+						$taxable_total                   = $running_totals['taxable'][ $line_item_id ];
1787
+						$running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1788
+					}
1789
+					break;
1790
+
1791
+				case EEM_Line_Item::type_line_item:
1792
+					// ticket line items or ????
1793
+					if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1794
+						// kk it's a ticket
1795
+						if (isset($running_totals[ $child_line_item->ID() ])) {
1796
+							// huh? that shouldn't happen.
1797
+							$running_totals['total'] += $child_line_item->total();
1798
+						} else {
1799
+							// its not in our running totals yet. great.
1800
+							if ($child_line_item->is_taxable()) {
1801
+								$taxable_amount = $child_line_item->unit_price();
1802
+							} else {
1803
+								$taxable_amount = 0;
1804
+							}
1805
+							// are we only calculating totals for some tickets?
1806
+							if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1807
+								$quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1808
+
1809
+								$running_totals[ $child_line_item->ID() ]            = $quantity
1810
+									? $child_line_item->unit_price()
1811
+									: 0;
1812
+								$running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1813
+									? $taxable_amount
1814
+									: 0;
1815
+							} else {
1816
+								$quantity                                            = $child_line_item->quantity();
1817
+								$running_totals[ $child_line_item->ID() ]            = $child_line_item->unit_price();
1818
+								$running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1819
+							}
1820
+							$running_totals['taxable']['total'] += $taxable_amount * $quantity;
1821
+							$running_totals['total']            += $child_line_item->unit_price() * $quantity;
1822
+						}
1823
+					} else {
1824
+						// it's some other type of item added to the cart
1825
+						// it should affect the running totals
1826
+						// basically we want to convert it into a PERCENT modifier. Because
1827
+						// more clearly affect all registration's final price equally
1828
+						$line_items_percent_of_running_total = $running_totals['total'] > 0
1829
+							? ($child_line_item->total() / $running_totals['total']) + 1
1830
+							: 1;
1831
+						foreach ($running_totals as $line_item_id => $this_running_total) {
1832
+							// the "taxable" array key is an exception
1833
+							if ($line_item_id === 'taxable') {
1834
+								continue;
1835
+							}
1836
+							// update the running totals
1837
+							// yes this actually even works for the running grand total!
1838
+							$running_totals[ $line_item_id ] =
1839
+								$line_items_percent_of_running_total * $this_running_total;
1840
+
1841
+							if ($child_line_item->is_taxable()) {
1842
+								$running_totals['taxable'][ $line_item_id ] =
1843
+									$line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1844
+							}
1845
+						}
1846
+					}
1847
+					break;
1848
+			}
1849
+		}
1850
+		return $running_totals;
1851
+	}
1852
+
1853
+
1854
+	/**
1855
+	 * @param EE_Line_Item $total_line_item
1856
+	 * @param EE_Line_Item $ticket_line_item
1857
+	 * @return float | null
1858
+	 * @throws EE_Error
1859
+	 * @throws InvalidArgumentException
1860
+	 * @throws InvalidDataTypeException
1861
+	 * @throws InvalidInterfaceException
1862
+	 * @throws OutOfRangeException
1863
+	 * @throws ReflectionException
1864
+	 */
1865
+	public static function calculate_final_price_for_ticket_line_item(
1866
+		EE_Line_Item $total_line_item,
1867
+		EE_Line_Item $ticket_line_item
1868
+	): ?float {
1869
+		static $final_prices_per_ticket_line_item = [];
1870
+		if (
1871
+			empty($final_prices_per_ticket_line_item)
1872
+			|| empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])
1873
+		) {
1874
+			$final_prices_per_ticket_line_item[ $total_line_item->ID() ] =
1875
+				EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1876
+					$total_line_item
1877
+				);
1878
+		}
1879
+		// ok now find this new registration's final price
1880
+		if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1881
+			return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1882
+		}
1883
+		$message = sprintf(
1884
+			esc_html__(
1885
+				'The final price for the ticket line item (ID:%1$d) on the total line item (ID:%2$d) could not be calculated.',
1886
+				'event_espresso'
1887
+			),
1888
+			$ticket_line_item->ID(),
1889
+			$total_line_item->ID()
1890
+		);
1891
+		if (WP_DEBUG) {
1892
+			$message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1893
+			throw new OutOfRangeException($message);
1894
+		}
1895
+		EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
1896
+		return null;
1897
+	}
1898
+
1899
+
1900
+	/**
1901
+	 * Creates a duplicate of the line item tree, except only includes billable items
1902
+	 * and the portion of line items attributed to billable things
1903
+	 *
1904
+	 * @param EE_Line_Item      $line_item
1905
+	 * @param EE_Registration[] $registrations
1906
+	 * @return EE_Line_Item
1907
+	 * @throws EE_Error
1908
+	 * @throws InvalidArgumentException
1909
+	 * @throws InvalidDataTypeException
1910
+	 * @throws InvalidInterfaceException
1911
+	 * @throws ReflectionException
1912
+	 */
1913
+	public static function billable_line_item_tree(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1914
+	{
1915
+		$copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations);
1916
+		foreach ($line_item->children() as $child_li) {
1917
+			$copy_li->add_child_line_item(
1918
+				EEH_Line_Item::billable_line_item_tree($child_li, $registrations)
1919
+			);
1920
+		}
1921
+		// if this is the grand total line item, make sure the totals all add up
1922
+		// (we could have duplicated this logic AS we copied the line items, but
1923
+		// it seems DRYer this way)
1924
+		if ($copy_li->type() === EEM_Line_Item::type_total) {
1925
+			$copy_li->recalculate_total_including_taxes();
1926
+		}
1927
+		return $copy_li;
1928
+	}
1929
+
1930
+
1931
+	/**
1932
+	 * Creates a new, unsaved line item from $line_item that factors in the
1933
+	 * number of billable registrations on $registrations.
1934
+	 *
1935
+	 * @param EE_Line_Item      $line_item
1936
+	 * @param EE_Registration[] $registrations
1937
+	 * @return EE_Line_Item
1938
+	 * @throws EE_Error
1939
+	 * @throws InvalidArgumentException
1940
+	 * @throws InvalidDataTypeException
1941
+	 * @throws InvalidInterfaceException
1942
+	 * @throws ReflectionException
1943
+	 */
1944
+	public static function billable_line_item(EE_Line_Item $line_item, array $registrations): EE_Line_Item
1945
+	{
1946
+		$new_li_fields = $line_item->model_field_array();
1947
+		if (
1948
+			$line_item->type() === EEM_Line_Item::type_line_item &&
1949
+			$line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
1950
+		) {
1951
+			$count = 0;
1952
+			foreach ($registrations as $registration) {
1953
+				if (
1954
+					$line_item->OBJ_ID() === $registration->ticket_ID() &&
1955
+					in_array(
1956
+						$registration->status_ID(),
1957
+						EEM_Registration::reg_statuses_that_allow_payment(),
1958
+						true
1959
+					)
1960
+				) {
1961
+					$count++;
1962
+				}
1963
+			}
1964
+			$new_li_fields['LIN_quantity'] = $count;
1965
+		}
1966
+		// don't set the total. We'll leave that up to the code that calculates it
1967
+		unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']);
1968
+		return EE_Line_Item::new_instance($new_li_fields);
1969
+	}
1970
+
1971
+
1972
+	/**
1973
+	 * Returns a modified line item tree where all the subtotals which have a total of 0
1974
+	 * are removed, and line items with a quantity of 0
1975
+	 *
1976
+	 * @param EE_Line_Item $line_item |null
1977
+	 * @return EE_Line_Item|null
1978
+	 * @throws EE_Error
1979
+	 * @throws InvalidArgumentException
1980
+	 * @throws InvalidDataTypeException
1981
+	 * @throws InvalidInterfaceException
1982
+	 * @throws ReflectionException
1983
+	 */
1984
+	public static function non_empty_line_items(EE_Line_Item $line_item): ?EE_Line_Item
1985
+	{
1986
+		$copied_li = EEH_Line_Item::non_empty_line_item($line_item);
1987
+		if ($copied_li === null) {
1988
+			return null;
1989
+		}
1990
+		// if this is an event subtotal, we want to only include it if it
1991
+		// has a non-zero total and at least one ticket line item child
1992
+		$ticket_children = 0;
1993
+		foreach ($line_item->children() as $child_li) {
1994
+			$child_li_copy = EEH_Line_Item::non_empty_line_items($child_li);
1995
+			if ($child_li_copy !== null) {
1996
+				$copied_li->add_child_line_item($child_li_copy);
1997
+				if (
1998
+					$child_li_copy->type() === EEM_Line_Item::type_line_item &&
1999
+					$child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2000
+				) {
2001
+					$ticket_children++;
2002
+				}
2003
+			}
2004
+		}
2005
+		// if this is an event subtotal with NO ticket children
2006
+		// we basically want to ignore it
2007
+		if (
2008
+			$ticket_children === 0
2009
+			&& $line_item->type() === EEM_Line_Item::type_sub_total
2010
+			&& $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT
2011
+			&& $line_item->total() === 0.0
2012
+		) {
2013
+			return null;
2014
+		}
2015
+		return $copied_li;
2016
+	}
2017
+
2018
+
2019
+	/**
2020
+	 * Creates a new, unsaved line item, but if it's a ticket line item
2021
+	 * with a total of 0, or a subtotal of 0, returns null instead
2022
+	 *
2023
+	 * @param EE_Line_Item $line_item
2024
+	 * @return EE_Line_Item
2025
+	 * @throws EE_Error
2026
+	 * @throws InvalidArgumentException
2027
+	 * @throws InvalidDataTypeException
2028
+	 * @throws InvalidInterfaceException
2029
+	 * @throws ReflectionException
2030
+	 */
2031
+	public static function non_empty_line_item(EE_Line_Item $line_item): ?EE_Line_Item
2032
+	{
2033
+		if (
2034
+			$line_item->type() === EEM_Line_Item::type_line_item
2035
+			&& $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2036
+			&& $line_item->quantity() === 0
2037
+		) {
2038
+			return null;
2039
+		}
2040
+		$new_li_fields = $line_item->model_field_array();
2041
+		// don't set the total. We'll leave that up to the code that calculates it
2042
+		unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']);
2043
+		return EE_Line_Item::new_instance($new_li_fields);
2044
+	}
2045
+
2046
+
2047
+	/**
2048
+	 * Cycles through all of the ticket line items for the supplied total line item
2049
+	 * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket
2050
+	 *
2051
+	 * @param EE_Line_Item $total_line_item
2052
+	 * @throws EE_Error
2053
+	 * @throws InvalidArgumentException
2054
+	 * @throws InvalidDataTypeException
2055
+	 * @throws InvalidInterfaceException
2056
+	 * @throws ReflectionException
2057
+	 * @since 4.9.79.p
2058
+	 */
2059
+	public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item)
2060
+	{
2061
+		$ticket_line_items = self::get_ticket_line_items($total_line_item);
2062
+		foreach ($ticket_line_items as $ticket_line_item) {
2063
+			if (
2064
+				$ticket_line_item instanceof EE_Line_Item
2065
+				&& $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET
2066
+			) {
2067
+				$ticket = $ticket_line_item->ticket();
2068
+				if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) {
2069
+					$ticket_line_item->set_is_taxable($ticket->taxable());
2070
+					$ticket_line_item->save();
2071
+				}
2072
+			}
2073
+		}
2074
+	}
2075
+
2076
+
2077
+	/**
2078
+	 * @return EE_Line_Item[]
2079
+	 * @throws EE_Error
2080
+	 * @throws ReflectionException
2081
+	 * @since   5.0.0.p
2082
+	 */
2083
+	private static function getGlobalTaxes(): array
2084
+	{
2085
+		if (EEH_Line_Item::$global_taxes === null) {
2086
+			/** @type EEM_Price $EEM_Price */
2087
+			$EEM_Price = EE_Registry::instance()->load_model('Price');
2088
+			// get array of taxes via Price Model
2089
+			EEH_Line_Item::$global_taxes = $EEM_Price->get_all_prices_that_are_taxes();
2090
+			ksort(EEH_Line_Item::$global_taxes);
2091
+		}
2092
+		return EEH_Line_Item::$global_taxes;
2093
+	}
2094
+
2095
+
2096
+
2097
+	/**************************************** @DEPRECATED METHODS *************************************** */
2098
+	/**
2099
+	 * @param EE_Line_Item $total_line_item
2100
+	 * @return EE_Line_Item
2101
+	 * @throws EE_Error
2102
+	 * @throws InvalidArgumentException
2103
+	 * @throws InvalidDataTypeException
2104
+	 * @throws InvalidInterfaceException
2105
+	 * @throws ReflectionException
2106
+	 * @deprecated
2107
+	 */
2108
+	public static function get_items_subtotal(EE_Line_Item $total_line_item): EE_Line_Item
2109
+	{
2110
+		EE_Error::doing_it_wrong(
2111
+			'EEH_Line_Item::get_items_subtotal()',
2112
+			sprintf(
2113
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2114
+				'EEH_Line_Item::get_pre_tax_subtotal()'
2115
+			),
2116
+			'4.6.0'
2117
+		);
2118
+		return self::get_pre_tax_subtotal($total_line_item);
2119
+	}
2120
+
2121
+
2122
+	/**
2123
+	 * @param EE_Transaction|null $transaction
2124
+	 * @return EE_Line_Item
2125
+	 * @throws EE_Error
2126
+	 * @throws InvalidArgumentException
2127
+	 * @throws InvalidDataTypeException
2128
+	 * @throws InvalidInterfaceException
2129
+	 * @throws ReflectionException
2130
+	 * @deprecated
2131
+	 */
2132
+	public static function create_default_total_line_item(?EE_Transaction $transaction = null): EE_Line_Item
2133
+	{
2134
+		EE_Error::doing_it_wrong(
2135
+			'EEH_Line_Item::create_default_total_line_item()',
2136
+			sprintf(
2137
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2138
+				'EEH_Line_Item::create_total_line_item()'
2139
+			),
2140
+			'4.6.0'
2141
+		);
2142
+		return self::create_total_line_item($transaction);
2143
+	}
2144
+
2145
+
2146
+	/**
2147
+	 * @param EE_Line_Item        $total_line_item
2148
+	 * @param EE_Transaction|null $transaction
2149
+	 * @return EE_Line_Item
2150
+	 * @throws EE_Error
2151
+	 * @throws InvalidArgumentException
2152
+	 * @throws InvalidDataTypeException
2153
+	 * @throws InvalidInterfaceException
2154
+	 * @throws ReflectionException
2155
+	 * @deprecated
2156
+	 */
2157
+	public static function create_default_tickets_subtotal(
2158
+		EE_Line_Item $total_line_item,
2159
+		?EE_Transaction $transaction = null
2160
+	): EE_Line_Item {
2161
+		EE_Error::doing_it_wrong(
2162
+			'EEH_Line_Item::create_default_tickets_subtotal()',
2163
+			sprintf(
2164
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2165
+				'EEH_Line_Item::create_pre_tax_subtotal()'
2166
+			),
2167
+			'4.6.0'
2168
+		);
2169
+		return self::create_pre_tax_subtotal($total_line_item, $transaction);
2170
+	}
2171
+
2172
+
2173
+	/**
2174
+	 * @param EE_Line_Item        $total_line_item
2175
+	 * @param EE_Transaction|null $transaction
2176
+	 * @return EE_Line_Item
2177
+	 * @throws EE_Error
2178
+	 * @throws InvalidArgumentException
2179
+	 * @throws InvalidDataTypeException
2180
+	 * @throws InvalidInterfaceException
2181
+	 * @throws ReflectionException
2182
+	 * @deprecated
2183
+	 */
2184
+	public static function create_default_taxes_subtotal(
2185
+		EE_Line_Item $total_line_item,
2186
+		?EE_Transaction $transaction = null
2187
+	): EE_Line_Item {
2188
+		EE_Error::doing_it_wrong(
2189
+			'EEH_Line_Item::create_default_taxes_subtotal()',
2190
+			sprintf(
2191
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2192
+				'EEH_Line_Item::create_taxes_subtotal()'
2193
+			),
2194
+			'4.6.0'
2195
+		);
2196
+		return self::create_taxes_subtotal($total_line_item, $transaction);
2197
+	}
2198
+
2199
+
2200
+	/**
2201
+	 * @param EE_Line_Item        $total_line_item
2202
+	 * @param EE_Transaction|null $transaction
2203
+	 * @return EE_Line_Item
2204
+	 * @throws EE_Error
2205
+	 * @throws InvalidArgumentException
2206
+	 * @throws InvalidDataTypeException
2207
+	 * @throws InvalidInterfaceException
2208
+	 * @throws ReflectionException
2209
+	 * @deprecated
2210
+	 */
2211
+	public static function create_default_event_subtotal(
2212
+		EE_Line_Item $total_line_item,
2213
+		?EE_Transaction $transaction = null
2214
+	): EE_Line_Item {
2215
+		EE_Error::doing_it_wrong(
2216
+			'EEH_Line_Item::create_default_event_subtotal()',
2217
+			sprintf(
2218
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
2219
+				'EEH_Line_Item::create_event_subtotal()'
2220
+			),
2221
+			'4.6.0'
2222
+		);
2223
+		return self::create_event_subtotal($total_line_item, $transaction);
2224
+	}
2225 2225
 }
Please login to merge, or discard this patch.
Spacing   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
     /**
25 25
      * @var EE_Line_Item[]|null
26 26
      */
27
-    private static ?array $global_taxes = null;
27
+    private static ? array $global_taxes = null;
28 28
 
29 29
 
30 30
     /**
@@ -73,12 +73,12 @@  discard block
 block discarded – undo
73 73
                 'LIN_code'       => $code,
74 74
             ]
75 75
         );
76
-        $line_item      = apply_filters(
76
+        $line_item = apply_filters(
77 77
             'FHEE__EEH_Line_Item__add_unrelated_item__line_item',
78 78
             $line_item,
79 79
             $parent_line_item
80 80
         );
81
-        $added          = self::add_item($parent_line_item, $line_item, $recalculate_totals);
81
+        $added = self::add_item($parent_line_item, $line_item, $recalculate_totals);
82 82
         return $return_item ? $line_item : $added;
83 83
     }
84 84
 
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
             'FHEE__EEH_Line_Item__add_percentage_based_item__line_item',
132 132
             $line_item
133 133
         );
134
-        $added     = $parent_line_item->add_child_line_item($line_item, false);
134
+        $added = $parent_line_item->add_child_line_item($line_item, false);
135 135
         return $return_item ? $line_item : $added;
136 136
     }
137 137
 
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
         EE_Ticket $ticket,
159 159
         int $qty = 1
160 160
     ): ?EE_Line_Item {
161
-        if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
161
+        if ( ! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) {
162 162
             throw new EE_Error(
163 163
                 sprintf(
164 164
                     esc_html__(
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
         // either increment the qty for an existing ticket
174 174
         $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty);
175 175
         // or add a new one
176
-        if (! $line_item instanceof EE_Line_Item) {
176
+        if ( ! $line_item instanceof EE_Line_Item) {
177 177
             $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty);
178 178
         }
179 179
         $total_line_item->recalculate_total_including_taxes();
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
      */
236 236
     public static function increment_quantity(EE_Line_Item $line_item, int $qty = 1)
237 237
     {
238
-        if (! $line_item->is_percent()) {
238
+        if ( ! $line_item->is_percent()) {
239 239
             $qty += $line_item->quantity();
240 240
             $line_item->set_quantity($qty);
241 241
             $line_item->set_total($line_item->unit_price() * $qty);
@@ -264,7 +264,7 @@  discard block
 block discarded – undo
264 264
      */
265 265
     public static function decrement_quantity(EE_Line_Item $line_item, int $qty = 1)
266 266
     {
267
-        if (! $line_item->is_percent()) {
267
+        if ( ! $line_item->is_percent()) {
268 268
             $qty = $line_item->quantity() - $qty;
269 269
             $qty = max($qty, 0);
270 270
             $line_item->set_quantity($qty);
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
      */
294 294
     public static function update_quantity(EE_Line_Item $line_item, int $new_quantity)
295 295
     {
296
-        if (! $line_item->is_percent()) {
296
+        if ( ! $line_item->is_percent()) {
297 297
             $line_item->set_quantity($new_quantity);
298 298
             $line_item->set_total($line_item->unit_price() * $new_quantity);
299 299
             $line_item->save();
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
         $line_item = EE_Line_Item::new_instance(
339 339
             [
340 340
                 'LIN_name'       => $ticket->name(),
341
-                'LIN_desc'       => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event,
341
+                'LIN_desc'       => $ticket->description() !== '' ? $ticket->description().' '.$event : $event,
342 342
                 'LIN_unit_price' => $ticket->price(),
343 343
                 'LIN_quantity'   => $qty,
344 344
                 'LIN_is_taxable' => empty($taxes) && $ticket->taxable(),
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
             'FHEE__EEH_Line_Item__create_ticket_line_item__line_item',
354 354
             $line_item
355 355
         );
356
-        if (! $line_item instanceof EE_Line_Item) {
356
+        if ( ! $line_item instanceof EE_Line_Item) {
357 357
             throw new DomainException(
358 358
                 esc_html__('Invalid EE_Line_Item received.', 'event_espresso')
359 359
             );
@@ -385,7 +385,7 @@  discard block
 block discarded – undo
385 385
                 $percent    = 0;
386 386
                 $unit_price = $sign * $price->amount();
387 387
             }
388
-            $sub_line_item         = EE_Line_Item::new_instance(
388
+            $sub_line_item = EE_Line_Item::new_instance(
389 389
                 [
390 390
                     'LIN_name'       => $price->name(),
391 391
                     'LIN_desc'       => $price->desc(),
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
                     'OBJ_type'       => EEM_Line_Item::OBJ_TYPE_PRICE,
403 403
                 ]
404 404
             );
405
-            $sub_line_item         = apply_filters(
405
+            $sub_line_item = apply_filters(
406 406
                 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item',
407 407
                 $sub_line_item
408 408
             );
@@ -519,7 +519,7 @@  discard block
 block discarded – undo
519 519
                             'event_espresso'
520 520
                         ),
521 521
                         $ticket_line_item->name(),
522
-                        current_time(get_option('date_format') . ' ' . get_option('time_format'))
522
+                        current_time(get_option('date_format').' '.get_option('time_format'))
523 523
                     ),
524 524
                     'LIN_unit_price' => 0, // $ticket_line_item->unit_price()
525 525
                     'LIN_quantity'   => $qty,
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
         );
584 584
         $cancellation_line_item = reset($cancellation_line_item);
585 585
         // verify that this ticket was indeed previously cancelled
586
-        if (! $cancellation_line_item instanceof EE_Line_Item) {
586
+        if ( ! $cancellation_line_item instanceof EE_Line_Item) {
587 587
             return false;
588 588
         }
589 589
         if ($cancellation_line_item->quantity() > $qty) {
@@ -798,7 +798,7 @@  discard block
 block discarded – undo
798 798
                 'LIN_code'  => 'taxes',
799 799
                 'LIN_name'  => esc_html__('Taxes', 'event_espresso'),
800 800
                 'LIN_type'  => EEM_Line_Item::type_tax_sub_total,
801
-                'LIN_order' => 1000,// this should always come last
801
+                'LIN_order' => 1000, // this should always come last
802 802
             ]
803 803
         );
804 804
         $tax_line_item = apply_filters(
@@ -861,7 +861,7 @@  discard block
 block discarded – undo
861 861
      */
862 862
     public static function get_event_code(?EE_Event $event = null): string
863 863
     {
864
-        return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0');
864
+        return 'event-'.($event instanceof EE_Event ? $event->ID() : '0');
865 865
     }
866 866
 
867 867
 
@@ -912,7 +912,7 @@  discard block
 block discarded – undo
912 912
     public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket): EE_Line_Item
913 913
     {
914 914
         $first_datetime = $ticket->first_datetime();
915
-        if (! $first_datetime instanceof EE_Datetime) {
915
+        if ( ! $first_datetime instanceof EE_Datetime) {
916 916
             throw new EE_Error(
917 917
                 sprintf(
918 918
                     esc_html__('The supplied ticket (ID %d) has no datetimes', 'event_espresso'),
@@ -921,7 +921,7 @@  discard block
 block discarded – undo
921 921
             );
922 922
         }
923 923
         $event = $first_datetime->event();
924
-        if (! $event instanceof EE_Event) {
924
+        if ( ! $event instanceof EE_Event) {
925 925
             throw new EE_Error(
926 926
                 sprintf(
927 927
                     esc_html__(
@@ -933,7 +933,7 @@  discard block
 block discarded – undo
933 933
             );
934 934
         }
935 935
         $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event);
936
-        if (! $events_sub_total instanceof EE_Line_Item) {
936
+        if ( ! $events_sub_total instanceof EE_Line_Item) {
937 937
             throw new EE_Error(
938 938
                 sprintf(
939 939
                     esc_html__(
@@ -969,7 +969,7 @@  discard block
 block discarded – undo
969 969
         $found           = false;
970 970
         foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) {
971 971
             // default event subtotal, we should only ever find this the first time this method is called
972
-            if (! $event_line_item->OBJ_ID()) {
972
+            if ( ! $event_line_item->OBJ_ID()) {
973 973
                 // let's use this! but first... set the event details
974 974
                 EEH_Line_Item::set_event_subtotal_details($event_line_item, $event);
975 975
                 $found = true;
@@ -981,7 +981,7 @@  discard block
 block discarded – undo
981 981
                 break;
982 982
             }
983 983
         }
984
-        if (! $found) {
984
+        if ( ! $found) {
985 985
             // there is no event sub-total yet, so add it
986 986
             $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total);
987 987
             // create a new "event" subtotal below that
@@ -1061,7 +1061,7 @@  discard block
 block discarded – undo
1061 1061
                             break;
1062 1062
                         }
1063 1063
                     }
1064
-                    if (! $found) {
1064
+                    if ( ! $found) {
1065 1065
                         // add a new line item for this global tax
1066 1066
                         $tax_line_item = apply_filters(
1067 1067
                             'FHEE__EEH_Line_Item__apply_taxes__tax_line_item',
@@ -1079,7 +1079,7 @@  discard block
 block discarded – undo
1079 1079
                                 ]
1080 1080
                             )
1081 1081
                         );
1082
-                        $updates       = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1082
+                        $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? true : $updates;
1083 1083
                     }
1084 1084
                 }
1085 1085
             }
@@ -1108,7 +1108,7 @@  discard block
 block discarded – undo
1108 1108
     public static function ensure_taxes_applied(?EE_Line_Item $total_line_item): float
1109 1109
     {
1110 1110
         $taxes_subtotal = self::get_taxes_subtotal($total_line_item);
1111
-        if (! $taxes_subtotal->children()) {
1111
+        if ( ! $taxes_subtotal->children()) {
1112 1112
             self::apply_taxes($total_line_item);
1113 1113
         }
1114 1114
         return $taxes_subtotal->total();
@@ -1175,7 +1175,7 @@  discard block
 block discarded – undo
1175 1175
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1176 1176
 
1177 1177
         // check if only a single line_item_id was passed
1178
-        if (! empty($line_item_codes) && ! is_array($line_item_codes)) {
1178
+        if ( ! empty($line_item_codes) && ! is_array($line_item_codes)) {
1179 1179
             // place single line_item_id in an array to appear as multiple line_item_ids
1180 1180
             $line_item_codes = [$line_item_codes];
1181 1181
         }
@@ -1285,7 +1285,7 @@  discard block
 block discarded – undo
1285 1285
         if ($code_substring_for_whitelist !== null) {
1286 1286
             $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false;
1287 1287
         }
1288
-        if (! $whitelisted && $line_item->is_line_item()) {
1288
+        if ( ! $whitelisted && $line_item->is_line_item()) {
1289 1289
             $line_item->set_is_taxable($taxable);
1290 1290
         }
1291 1291
         foreach ($line_item->children() as $child_line_item) {
@@ -1762,7 +1762,7 @@  discard block
 block discarded – undo
1762 1762
                         $billable_ticket_quantities
1763 1763
                     );
1764 1764
                     // combine arrays but preserve numeric keys
1765
-                    $running_totals                     = array_replace_recursive(
1765
+                    $running_totals = array_replace_recursive(
1766 1766
                         $running_totals_from_subtotal,
1767 1767
                         $running_totals
1768 1768
                     );
@@ -1783,8 +1783,8 @@  discard block
 block discarded – undo
1783 1783
                         if ($line_item_id === 'taxable') {
1784 1784
                             continue;
1785 1785
                         }
1786
-                        $taxable_total                   = $running_totals['taxable'][ $line_item_id ];
1787
-                        $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal);
1786
+                        $taxable_total = $running_totals['taxable'][$line_item_id];
1787
+                        $running_totals[$line_item_id] += ($taxable_total * $tax_percent_decimal);
1788 1788
                     }
1789 1789
                     break;
1790 1790
 
@@ -1792,7 +1792,7 @@  discard block
 block discarded – undo
1792 1792
                     // ticket line items or ????
1793 1793
                     if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
1794 1794
                         // kk it's a ticket
1795
-                        if (isset($running_totals[ $child_line_item->ID() ])) {
1795
+                        if (isset($running_totals[$child_line_item->ID()])) {
1796 1796
                             // huh? that shouldn't happen.
1797 1797
                             $running_totals['total'] += $child_line_item->total();
1798 1798
                         } else {
@@ -1803,19 +1803,19 @@  discard block
 block discarded – undo
1803 1803
                                 $taxable_amount = 0;
1804 1804
                             }
1805 1805
                             // are we only calculating totals for some tickets?
1806
-                            if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) {
1807
-                                $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ];
1806
+                            if (isset($billable_ticket_quantities[$child_line_item->OBJ_ID()])) {
1807
+                                $quantity = $billable_ticket_quantities[$child_line_item->OBJ_ID()];
1808 1808
 
1809
-                                $running_totals[ $child_line_item->ID() ]            = $quantity
1809
+                                $running_totals[$child_line_item->ID()]            = $quantity
1810 1810
                                     ? $child_line_item->unit_price()
1811 1811
                                     : 0;
1812
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $quantity
1812
+                                $running_totals['taxable'][$child_line_item->ID()] = $quantity
1813 1813
                                     ? $taxable_amount
1814 1814
                                     : 0;
1815 1815
                             } else {
1816 1816
                                 $quantity                                            = $child_line_item->quantity();
1817
-                                $running_totals[ $child_line_item->ID() ]            = $child_line_item->unit_price();
1818
-                                $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount;
1817
+                                $running_totals[$child_line_item->ID()]            = $child_line_item->unit_price();
1818
+                                $running_totals['taxable'][$child_line_item->ID()] = $taxable_amount;
1819 1819
                             }
1820 1820
                             $running_totals['taxable']['total'] += $taxable_amount * $quantity;
1821 1821
                             $running_totals['total']            += $child_line_item->unit_price() * $quantity;
@@ -1835,12 +1835,12 @@  discard block
 block discarded – undo
1835 1835
                             }
1836 1836
                             // update the running totals
1837 1837
                             // yes this actually even works for the running grand total!
1838
-                            $running_totals[ $line_item_id ] =
1838
+                            $running_totals[$line_item_id] =
1839 1839
                                 $line_items_percent_of_running_total * $this_running_total;
1840 1840
 
1841 1841
                             if ($child_line_item->is_taxable()) {
1842
-                                $running_totals['taxable'][ $line_item_id ] =
1843
-                                    $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ];
1842
+                                $running_totals['taxable'][$line_item_id] =
1843
+                                    $line_items_percent_of_running_total * $running_totals['taxable'][$line_item_id];
1844 1844
                             }
1845 1845
                         }
1846 1846
                     }
@@ -1869,16 +1869,16 @@  discard block
 block discarded – undo
1869 1869
         static $final_prices_per_ticket_line_item = [];
1870 1870
         if (
1871 1871
             empty($final_prices_per_ticket_line_item)
1872
-            || empty($final_prices_per_ticket_line_item[ $total_line_item->ID() ])
1872
+            || empty($final_prices_per_ticket_line_item[$total_line_item->ID()])
1873 1873
         ) {
1874
-            $final_prices_per_ticket_line_item[ $total_line_item->ID() ] =
1874
+            $final_prices_per_ticket_line_item[$total_line_item->ID()] =
1875 1875
                 EEH_Line_Item::calculate_reg_final_prices_per_line_item(
1876 1876
                     $total_line_item
1877 1877
                 );
1878 1878
         }
1879 1879
         // ok now find this new registration's final price
1880
-        if (isset($final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ])) {
1881
-            return $final_prices_per_ticket_line_item[ $total_line_item->ID() ][ $ticket_line_item->ID() ];
1880
+        if (isset($final_prices_per_ticket_line_item[$total_line_item->ID()][$ticket_line_item->ID()])) {
1881
+            return $final_prices_per_ticket_line_item[$total_line_item->ID()][$ticket_line_item->ID()];
1882 1882
         }
1883 1883
         $message = sprintf(
1884 1884
             esc_html__(
@@ -1889,7 +1889,7 @@  discard block
 block discarded – undo
1889 1889
             $total_line_item->ID()
1890 1890
         );
1891 1891
         if (WP_DEBUG) {
1892
-            $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true);
1892
+            $message .= '<br>'.print_r($final_prices_per_ticket_line_item, true);
1893 1893
             throw new OutOfRangeException($message);
1894 1894
         }
1895 1895
         EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
Please login to merge, or discard this patch.
core/helpers/EEH_Activation.helper.php 2 patches
Indentation   +1577 added lines, -1577 removed lines patch added patch discarded remove patch
@@ -17,232 +17,232 @@  discard block
 block discarded – undo
17 17
  */
18 18
 class EEH_Activation implements ResettableInterface
19 19
 {
20
-    /**
21
-     * constant used to indicate a cron task is no longer in use
22
-     */
23
-    const cron_task_no_longer_in_use = 'no_longer_in_use';
24
-
25
-    /**
26
-     * WP_User->ID
27
-     *
28
-     * @var int|null
29
-     */
30
-    private static ?int $_default_creator_id = null;
31
-
32
-    /**
33
-     * indicates whether or not we've already verified core's default data during this request,
34
-     * because after migrations are done, any addons activated while in maintenance mode
35
-     * will want to setup their own default data, and they might hook into core's default data
36
-     * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
37
-     * This prevents doing that for EVERY single addon.
38
-     *
39
-     * @var bool
40
-     */
41
-    protected static bool         $_initialized_db_content_already_in_this_request = false;
42
-
43
-    private static ?TableAnalysis $table_analysis                                  = null;
44
-
45
-    private static ?TableManager  $table_manager                                   = null;
46
-
47
-
48
-    /**
49
-     * @return TableAnalysis
50
-     * @throws EE_Error
51
-     * @throws ReflectionException
52
-     */
53
-    public static function getTableAnalysis(): ?TableAnalysis
54
-    {
55
-        if (! self::$table_analysis instanceof TableAnalysis) {
56
-            self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', [], true);
57
-        }
58
-        return self::$table_analysis;
59
-    }
60
-
61
-
62
-    /**
63
-     * @return TableManager
64
-     * @throws EE_Error
65
-     * @throws ReflectionException
66
-     */
67
-    public static function getTableManager(): ?TableManager
68
-    {
69
-        if (! self::$table_manager instanceof TableManager) {
70
-            self::$table_manager = EE_Registry::instance()->create('TableManager', [], true);
71
-        }
72
-        return self::$table_manager;
73
-    }
74
-
75
-
76
-    /**
77
-     * @param $table_name
78
-     * @return string
79
-     * @throws EE_Error
80
-     * @throws ReflectionException
81
-     * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
82
-     */
83
-    public static function ensure_table_name_has_prefix($table_name): string
84
-    {
85
-        return EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
86
-    }
87
-
88
-
89
-    /**
90
-     * ensures the EE configuration settings are loaded with at least default options set
91
-     * and that all critical EE pages have been generated with the appropriate shortcodes in place
92
-     *
93
-     * @return void
94
-     */
95
-    public static function system_initialization()
96
-    {
97
-        EEH_Activation::reset_and_update_config();
98
-        // which is fired BEFORE activation of plugin anyways
99
-        EEH_Activation::verify_default_pages_exist();
100
-    }
101
-
102
-
103
-    /**
104
-     * Sets the database schema and creates folders. This should
105
-     * be called on plugin activation and reactivation
106
-     *
107
-     * @return boolean success, whether the database and folders are setup properly
108
-     * @throws EE_Error
109
-     * @throws ReflectionException
110
-     */
111
-    public static function initialize_db_and_folders(): bool
112
-    {
113
-        EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR);
114
-        EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR . 'logs');
115
-        return EEH_Activation::create_database_tables();
116
-    }
117
-
118
-
119
-    /**
120
-     * assuming we have an up-to-date database schema, this will populate it
121
-     * with default and initial data. This should be called
122
-     * upon activation of a new plugin, reactivation, and at the end
123
-     * of running migration scripts
124
-     *
125
-     * @throws EE_Error
126
-     * @throws ReflectionException
127
-     */
128
-    public static function initialize_db_content()
129
-    {
130
-        // let's avoid doing all this logic repeatedly, especially when addons are requesting it
131
-        if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
132
-            return;
133
-        }
134
-        EEH_Activation::$_initialized_db_content_already_in_this_request = true;
135
-
136
-        EEH_Activation::initialize_system_questions();
137
-        EEH_Activation::insert_default_status_codes();
138
-        EEH_Activation::generate_default_message_templates();
139
-        EEH_Activation::removeEmailConfirmFromAddressGroup();
140
-
141
-        EEH_Activation::validate_messages_system();
142
-        EEH_Activation::insert_default_payment_methods();
143
-        SuppressAdminNotices::suppressWpGraphQlTracking();
144
-        // in case we've
145
-        EEH_Activation::remove_cron_tasks();
146
-        EEH_Activation::create_cron_tasks();
147
-        // remove all TXN locks since that is being done via extra meta now
148
-        delete_option('ee_locked_transactions');
149
-        // also, check for CAF default db content
150
-        do_action('AHEE__EEH_Activation__initialize_db_content');
151
-        // also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
152
-        // which users really won't care about on initial activation
153
-        EE_Error::overwrite_success();
154
-    }
155
-
156
-
157
-    /**
158
-     * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
159
-     * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
160
-     * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
161
-     * (null)
162
-     *
163
-     * @param string $which_to_include can be 'current' (ones that are currently in use),
164
-     *                                 'old' (only returns ones that should no longer be used),or 'all',
165
-     * @return array
166
-     * @throws EE_Error
167
-     */
168
-    public static function get_cron_tasks(string $which_to_include): array
169
-    {
170
-        $cron_tasks = apply_filters(
171
-            'FHEE__EEH_Activation__get_cron_tasks',
172
-            [
173
-                'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
174
-                // 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions' =>
175
-                // EEH_Activation::cron_task_no_longer_in_use, actually this is still in use
176
-                'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
177
-                // there may have been a bug which prevented from these cron tasks from getting unscheduled,
178
-                // so we might want to remove these for a few updates
179
-                'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
180
-            ]
181
-        );
182
-        if ($which_to_include === 'old') {
183
-            $cron_tasks = array_filter(
184
-                $cron_tasks,
185
-                function ($value) {
186
-                    return $value === EEH_Activation::cron_task_no_longer_in_use;
187
-                }
188
-            );
189
-        } elseif ($which_to_include === 'current') {
190
-            $cron_tasks = array_filter($cron_tasks);
191
-        } elseif (WP_DEBUG && $which_to_include !== 'all') {
192
-            throw new EE_Error(
193
-                sprintf(
194
-                    esc_html__(
195
-                        'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
196
-                        'event_espresso'
197
-                    ),
198
-                    $which_to_include
199
-                )
200
-            );
201
-        }
202
-        return (array) $cron_tasks;
203
-    }
204
-
205
-
206
-    /**
207
-     * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
208
-     *
209
-     * @throws EE_Error
210
-     */
211
-    public static function create_cron_tasks()
212
-    {
213
-        foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
214
-            if (! wp_next_scheduled($hook_name)) {
215
-                /**
216
-                 * This allows client code to define the initial start timestamp for this schedule.
217
-                 */
218
-                if (
219
-                    is_array($frequency)
220
-                    && count($frequency) === 2
221
-                    && isset($frequency[0], $frequency[1])
222
-                ) {
223
-                    $start_timestamp = $frequency[0];
224
-                    $frequency       = $frequency[1];
225
-                } else {
226
-                    $start_timestamp = time();
227
-                }
228
-                wp_schedule_event($start_timestamp, $frequency, $hook_name);
229
-            }
230
-        }
231
-    }
232
-
233
-
234
-    /**
235
-     * Remove the currently-existing and now-removed cron tasks.
236
-     *
237
-     * @param bool $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
238
-     * @throws EE_Error
239
-     */
240
-    public static function remove_cron_tasks(bool $remove_all = true)
241
-    {
242
-        $cron_tasks_to_remove = $remove_all ? 'all' : 'old';
243
-        $crons                = _get_cron_array();
244
-        $crons                = is_array($crons) ? $crons : [];
245
-        /* reminder of what $crons look like:
20
+	/**
21
+	 * constant used to indicate a cron task is no longer in use
22
+	 */
23
+	const cron_task_no_longer_in_use = 'no_longer_in_use';
24
+
25
+	/**
26
+	 * WP_User->ID
27
+	 *
28
+	 * @var int|null
29
+	 */
30
+	private static ?int $_default_creator_id = null;
31
+
32
+	/**
33
+	 * indicates whether or not we've already verified core's default data during this request,
34
+	 * because after migrations are done, any addons activated while in maintenance mode
35
+	 * will want to setup their own default data, and they might hook into core's default data
36
+	 * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
37
+	 * This prevents doing that for EVERY single addon.
38
+	 *
39
+	 * @var bool
40
+	 */
41
+	protected static bool         $_initialized_db_content_already_in_this_request = false;
42
+
43
+	private static ?TableAnalysis $table_analysis                                  = null;
44
+
45
+	private static ?TableManager  $table_manager                                   = null;
46
+
47
+
48
+	/**
49
+	 * @return TableAnalysis
50
+	 * @throws EE_Error
51
+	 * @throws ReflectionException
52
+	 */
53
+	public static function getTableAnalysis(): ?TableAnalysis
54
+	{
55
+		if (! self::$table_analysis instanceof TableAnalysis) {
56
+			self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', [], true);
57
+		}
58
+		return self::$table_analysis;
59
+	}
60
+
61
+
62
+	/**
63
+	 * @return TableManager
64
+	 * @throws EE_Error
65
+	 * @throws ReflectionException
66
+	 */
67
+	public static function getTableManager(): ?TableManager
68
+	{
69
+		if (! self::$table_manager instanceof TableManager) {
70
+			self::$table_manager = EE_Registry::instance()->create('TableManager', [], true);
71
+		}
72
+		return self::$table_manager;
73
+	}
74
+
75
+
76
+	/**
77
+	 * @param $table_name
78
+	 * @return string
79
+	 * @throws EE_Error
80
+	 * @throws ReflectionException
81
+	 * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
82
+	 */
83
+	public static function ensure_table_name_has_prefix($table_name): string
84
+	{
85
+		return EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
86
+	}
87
+
88
+
89
+	/**
90
+	 * ensures the EE configuration settings are loaded with at least default options set
91
+	 * and that all critical EE pages have been generated with the appropriate shortcodes in place
92
+	 *
93
+	 * @return void
94
+	 */
95
+	public static function system_initialization()
96
+	{
97
+		EEH_Activation::reset_and_update_config();
98
+		// which is fired BEFORE activation of plugin anyways
99
+		EEH_Activation::verify_default_pages_exist();
100
+	}
101
+
102
+
103
+	/**
104
+	 * Sets the database schema and creates folders. This should
105
+	 * be called on plugin activation and reactivation
106
+	 *
107
+	 * @return boolean success, whether the database and folders are setup properly
108
+	 * @throws EE_Error
109
+	 * @throws ReflectionException
110
+	 */
111
+	public static function initialize_db_and_folders(): bool
112
+	{
113
+		EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR);
114
+		EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR . 'logs');
115
+		return EEH_Activation::create_database_tables();
116
+	}
117
+
118
+
119
+	/**
120
+	 * assuming we have an up-to-date database schema, this will populate it
121
+	 * with default and initial data. This should be called
122
+	 * upon activation of a new plugin, reactivation, and at the end
123
+	 * of running migration scripts
124
+	 *
125
+	 * @throws EE_Error
126
+	 * @throws ReflectionException
127
+	 */
128
+	public static function initialize_db_content()
129
+	{
130
+		// let's avoid doing all this logic repeatedly, especially when addons are requesting it
131
+		if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
132
+			return;
133
+		}
134
+		EEH_Activation::$_initialized_db_content_already_in_this_request = true;
135
+
136
+		EEH_Activation::initialize_system_questions();
137
+		EEH_Activation::insert_default_status_codes();
138
+		EEH_Activation::generate_default_message_templates();
139
+		EEH_Activation::removeEmailConfirmFromAddressGroup();
140
+
141
+		EEH_Activation::validate_messages_system();
142
+		EEH_Activation::insert_default_payment_methods();
143
+		SuppressAdminNotices::suppressWpGraphQlTracking();
144
+		// in case we've
145
+		EEH_Activation::remove_cron_tasks();
146
+		EEH_Activation::create_cron_tasks();
147
+		// remove all TXN locks since that is being done via extra meta now
148
+		delete_option('ee_locked_transactions');
149
+		// also, check for CAF default db content
150
+		do_action('AHEE__EEH_Activation__initialize_db_content');
151
+		// also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
152
+		// which users really won't care about on initial activation
153
+		EE_Error::overwrite_success();
154
+	}
155
+
156
+
157
+	/**
158
+	 * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
159
+	 * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
160
+	 * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
161
+	 * (null)
162
+	 *
163
+	 * @param string $which_to_include can be 'current' (ones that are currently in use),
164
+	 *                                 'old' (only returns ones that should no longer be used),or 'all',
165
+	 * @return array
166
+	 * @throws EE_Error
167
+	 */
168
+	public static function get_cron_tasks(string $which_to_include): array
169
+	{
170
+		$cron_tasks = apply_filters(
171
+			'FHEE__EEH_Activation__get_cron_tasks',
172
+			[
173
+				'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
174
+				// 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions' =>
175
+				// EEH_Activation::cron_task_no_longer_in_use, actually this is still in use
176
+				'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
177
+				// there may have been a bug which prevented from these cron tasks from getting unscheduled,
178
+				// so we might want to remove these for a few updates
179
+				'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
180
+			]
181
+		);
182
+		if ($which_to_include === 'old') {
183
+			$cron_tasks = array_filter(
184
+				$cron_tasks,
185
+				function ($value) {
186
+					return $value === EEH_Activation::cron_task_no_longer_in_use;
187
+				}
188
+			);
189
+		} elseif ($which_to_include === 'current') {
190
+			$cron_tasks = array_filter($cron_tasks);
191
+		} elseif (WP_DEBUG && $which_to_include !== 'all') {
192
+			throw new EE_Error(
193
+				sprintf(
194
+					esc_html__(
195
+						'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
196
+						'event_espresso'
197
+					),
198
+					$which_to_include
199
+				)
200
+			);
201
+		}
202
+		return (array) $cron_tasks;
203
+	}
204
+
205
+
206
+	/**
207
+	 * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
208
+	 *
209
+	 * @throws EE_Error
210
+	 */
211
+	public static function create_cron_tasks()
212
+	{
213
+		foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
214
+			if (! wp_next_scheduled($hook_name)) {
215
+				/**
216
+				 * This allows client code to define the initial start timestamp for this schedule.
217
+				 */
218
+				if (
219
+					is_array($frequency)
220
+					&& count($frequency) === 2
221
+					&& isset($frequency[0], $frequency[1])
222
+				) {
223
+					$start_timestamp = $frequency[0];
224
+					$frequency       = $frequency[1];
225
+				} else {
226
+					$start_timestamp = time();
227
+				}
228
+				wp_schedule_event($start_timestamp, $frequency, $hook_name);
229
+			}
230
+		}
231
+	}
232
+
233
+
234
+	/**
235
+	 * Remove the currently-existing and now-removed cron tasks.
236
+	 *
237
+	 * @param bool $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
238
+	 * @throws EE_Error
239
+	 */
240
+	public static function remove_cron_tasks(bool $remove_all = true)
241
+	{
242
+		$cron_tasks_to_remove = $remove_all ? 'all' : 'old';
243
+		$crons                = _get_cron_array();
244
+		$crons                = is_array($crons) ? $crons : [];
245
+		/* reminder of what $crons look like:
246 246
          * Top-level keys are timestamps, and their values are arrays.
247 247
          * The 2nd level arrays have keys with each of the cron task hook names to run at that time
248 248
          * and their values are arrays.
@@ -259,907 +259,907 @@  discard block
 block discarded – undo
259 259
          *                  ...
260 260
          *      ...
261 261
          */
262
-        $ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
263
-        foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
264
-            if (is_array($hooks_to_fire_at_time)) {
265
-                foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
266
-                    if (
267
-                        isset($ee_cron_tasks_to_remove[ $hook_name ])
268
-                        && is_array($ee_cron_tasks_to_remove[ $hook_name ])
269
-                    ) {
270
-                        unset($crons[ $timestamp ][ $hook_name ]);
271
-                    }
272
-                }
273
-                // also take care of any empty cron timestamps.
274
-                if (empty($hooks_to_fire_at_time)) {
275
-                    unset($crons[ $timestamp ]);
276
-                }
277
-            }
278
-        }
279
-        _set_cron_array($crons);
280
-    }
281
-
282
-
283
-    /**
284
-     * registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
285
-     *
286
-     * @return void
287
-     * @throws EE_Error
288
-     * @throws ReflectionException
289
-     */
290
-    public static function CPT_initialization()
291
-    {
292
-        // register Custom Post Types
293
-        EE_Registry::instance()->load_core('Register_CPTs');
294
-        flush_rewrite_rules();
295
-    }
296
-
297
-
298
-    /**
299
-     * The following code was moved over from EE_Config so that it will no longer run on every request.
300
-     * If there is old calendar config data saved, then it will get converted on activation.
301
-     * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
302
-     *
303
-     * @return void
304
-     */
305
-    public static function reset_and_update_config()
306
-    {
307
-        do_action('AHEE__EE_Config___load_core_config__start', ['EEH_Activation', 'load_calendar_config']);
308
-        add_filter(
309
-            'FHEE__EE_Config___load_core_config__config_settings',
310
-            ['EEH_Activation', 'migrate_old_config_data'],
311
-            10,
312
-            3
313
-        );
314
-        if (! EE_Config::logging_enabled()) {
315
-            delete_option(EE_Config::LOG_NAME);
316
-        }
317
-    }
318
-
319
-
320
-    /**
321
-     * @return    void
322
-     */
323
-    public static function load_calendar_config()
324
-    {
325
-        // grab array of all plugin folders and loop thru it
326
-        $plugins = glob(WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR);
327
-        if (empty($plugins)) {
328
-            return;
329
-        }
330
-        foreach ($plugins as $plugin_path) {
331
-            // grab plugin folder name from path
332
-            $plugin = basename($plugin_path);
333
-            // drill down to Espresso plugins
334
-            // then to calendar related plugins
335
-            if (
336
-                strpos($plugin, 'espresso') !== false
337
-                || strpos($plugin, 'Espresso') !== false
338
-                || strpos($plugin, 'ee4') !== false
339
-                || strpos($plugin, 'EE4') !== false
340
-                || strpos($plugin, 'calendar') !== false
341
-            ) {
342
-                // this is what we are looking for
343
-                $calendar_config = $plugin_path . '/EE_Calendar_Config.php';
344
-                // does it exist in this folder ?
345
-                if (is_readable($calendar_config)) {
346
-                    // YEAH! let's load it
347
-                    require_once($calendar_config);
348
-                }
349
-            }
350
-        }
351
-    }
352
-
353
-
354
-    /**
355
-     * @param array|stdClass $settings
356
-     * @param int|string     $config
357
-     * @param EE_Config      $EE_Config
358
-     * @return stdClass
359
-     */
360
-    public static function migrate_old_config_data($settings, $config, EE_Config $EE_Config)
361
-    {
362
-        $convert_from_array = ['addons'];
363
-        // in case old settings were saved as an array
364
-        if (is_array($settings) && in_array($config, $convert_from_array)) {
365
-            // convert existing settings to an object
366
-            $config_array = $settings;
367
-            $settings     = new stdClass();
368
-            foreach ($config_array as $key => $value) {
369
-                if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
370
-                    $EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
371
-                } else {
372
-                    $settings->{$key} = $value;
373
-                }
374
-            }
375
-            add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
376
-        }
377
-        return $settings;
378
-    }
379
-
380
-
381
-    /**
382
-     * @return void
383
-     */
384
-    public static function deactivate_event_espresso()
385
-    {
386
-        // check permissions
387
-        if (current_user_can('activate_plugins')) {
388
-            deactivate_plugins(EE_PLUGIN_BASENAME, true);
389
-        }
390
-    }
391
-
392
-
393
-    /**
394
-     * @return void
395
-     * @throws InvalidDataTypeException
396
-     */
397
-    public static function verify_default_pages_exist()
398
-    {
399
-        $critical_page_problem = false;
400
-        $critical_pages        = [
401
-            [
402
-                'id'   => 'reg_page_id',
403
-                'name' => esc_html__('Registration Checkout', 'event_espresso'),
404
-                'post' => null,
405
-                'code' => 'ESPRESSO_CHECKOUT',
406
-            ],
407
-            [
408
-                'id'   => 'txn_page_id',
409
-                'name' => esc_html__('Transactions', 'event_espresso'),
410
-                'post' => null,
411
-                'code' => 'ESPRESSO_TXN_PAGE',
412
-            ],
413
-            [
414
-                'id'   => 'thank_you_page_id',
415
-                'name' => esc_html__('Thank You', 'event_espresso'),
416
-                'post' => null,
417
-                'code' => 'ESPRESSO_THANK_YOU',
418
-            ],
419
-            [
420
-                'id'   => 'cancel_page_id',
421
-                'name' => esc_html__('Registration Cancelled', 'event_espresso'),
422
-                'post' => null,
423
-                'code' => 'ESPRESSO_CANCELLED',
424
-            ],
425
-        ];
426
-        $EE_Core_Config        = EE_Registry::instance()->CFG->core;
427
-        foreach ($critical_pages as $critical_page) {
428
-            // is critical page ID set in config ?
429
-            if ($EE_Core_Config->{$critical_page['id']} !== false) {
430
-                // attempt to find post by ID
431
-                $critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
432
-            }
433
-            // no dice?
434
-            if ($critical_page['post'] === null) {
435
-                // attempt to find post by title
436
-                $critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
437
-                // still nothing?
438
-                if ($critical_page['post'] === null) {
439
-                    $critical_page = EEH_Activation::create_critical_page($critical_page);
440
-                    // REALLY? Still nothing ??!?!?
441
-                    if ($critical_page['post'] === null) {
442
-                        $msg = esc_html__(
443
-                            'The Event Espresso critical page configuration settings could not be updated.',
444
-                            'event_espresso'
445
-                        );
446
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
447
-                        break;
448
-                    }
449
-                }
450
-            }
451
-            // check that Post ID matches critical page ID in config
452
-            if (
453
-                isset($critical_page['post']->ID)
454
-                && $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
455
-            ) {
456
-                // update Config with post ID
457
-                $EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
458
-                if (! EE_Config::instance()->update_espresso_config(false, false)) {
459
-                    $msg = esc_html__(
460
-                        'The Event Espresso critical page configuration settings could not be updated.',
461
-                        'event_espresso'
462
-                    );
463
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
464
-                }
465
-            }
466
-            $critical_page_problem =
467
-                ! isset($critical_page['post']->post_status)
468
-                || $critical_page['post']->post_status !== 'publish'
469
-                || strpos($critical_page['post']->post_content, $critical_page['code']) === false
470
-                    ? true
471
-                    : $critical_page_problem;
472
-        }
473
-        if ($critical_page_problem) {
474
-            new PersistentAdminNotice(
475
-                'critical_page_problem',
476
-                sprintf(
477
-                    esc_html__(
478
-                        'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
479
-                        'event_espresso'
480
-                    ),
481
-                    '<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
482
-                    . esc_html__('Event Espresso Critical Pages Settings', 'event_espresso')
483
-                    . '</a>'
484
-                )
485
-            );
486
-        }
487
-        if (EE_Error::has_notices()) {
488
-            EE_Error::get_notices(false, true);
489
-        }
490
-    }
491
-
492
-
493
-    /**
494
-     * Returns the first post which uses the specified shortcode
495
-     *
496
-     * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
497
-     *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
498
-     *                             "[ESPRESSO_THANK_YOU"
499
-     *                             (we don't search for the closing shortcode bracket because they might have added
500
-     *                             parameter to the shortcode
501
-     * @return WP_Post|array|null
502
-     */
503
-    public static function get_page_by_ee_shortcode(string $ee_shortcode)
504
-    {
505
-        global $wpdb;
506
-        $shortcode_and_opening_bracket = '[' . $ee_shortcode;
507
-        $post_id                       =
508
-            $wpdb->get_var(
509
-                "SELECT ID FROM $wpdb->posts WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1"
510
-            );
511
-        if ($post_id) {
512
-            return get_post($post_id);
513
-        }
514
-        return null;
515
-    }
516
-
517
-
518
-    /**
519
-     * This function generates a post for critical espresso pages
520
-     *
521
-     * @param array $critical_page
522
-     * @return array
523
-     */
524
-    public static function create_critical_page(array $critical_page): array
525
-    {
526
-        $post_args = [
527
-            'post_title'     => $critical_page['name'],
528
-            'post_status'    => 'publish',
529
-            'post_type'      => 'page',
530
-            'comment_status' => 'closed',
531
-            'post_content'   => '[' . $critical_page['code'] . ']',
532
-        ];
533
-
534
-        $post_id = wp_insert_post($post_args);
535
-        if (! $post_id) {
536
-            $msg = sprintf(
537
-                esc_html__('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
538
-                $critical_page['name']
539
-            );
540
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
541
-            return $critical_page;
542
-        }
543
-        // get newly created post's details
544
-        if (! $critical_page['post'] = get_post($post_id)) {
545
-            $msg = sprintf(
546
-                esc_html__('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
547
-                $critical_page['name']
548
-            );
549
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
550
-        }
551
-
552
-        return $critical_page;
553
-    }
554
-
555
-
556
-    /**
557
-     * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
558
-     * The role being used to check is filterable.
559
-     *
560
-     * @return int|null WP_user ID or NULL
561
-     * @throws EE_Error
562
-     * @throws ReflectionException
563
-     * @since  4.6.0
564
-     * @global WPDB $wpdb
565
-     */
566
-    public static function get_default_creator_id(): ?int
567
-    {
568
-        global $wpdb;
569
-        if (self::$_default_creator_id) {
570
-            return self::$_default_creator_id;
571
-        }/**/
572
-        $role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
573
-        // let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
574
-        $pre_filtered_id = apply_filters(
575
-            'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
576
-            false,
577
-            $role_to_check
578
-        );
579
-        if ($pre_filtered_id !== false) {
580
-            return (int) $pre_filtered_id;
581
-        }
582
-        $capabilities_key = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
583
-        $query            = $wpdb->prepare(
584
-            "
262
+		$ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
263
+		foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
264
+			if (is_array($hooks_to_fire_at_time)) {
265
+				foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
266
+					if (
267
+						isset($ee_cron_tasks_to_remove[ $hook_name ])
268
+						&& is_array($ee_cron_tasks_to_remove[ $hook_name ])
269
+					) {
270
+						unset($crons[ $timestamp ][ $hook_name ]);
271
+					}
272
+				}
273
+				// also take care of any empty cron timestamps.
274
+				if (empty($hooks_to_fire_at_time)) {
275
+					unset($crons[ $timestamp ]);
276
+				}
277
+			}
278
+		}
279
+		_set_cron_array($crons);
280
+	}
281
+
282
+
283
+	/**
284
+	 * registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
285
+	 *
286
+	 * @return void
287
+	 * @throws EE_Error
288
+	 * @throws ReflectionException
289
+	 */
290
+	public static function CPT_initialization()
291
+	{
292
+		// register Custom Post Types
293
+		EE_Registry::instance()->load_core('Register_CPTs');
294
+		flush_rewrite_rules();
295
+	}
296
+
297
+
298
+	/**
299
+	 * The following code was moved over from EE_Config so that it will no longer run on every request.
300
+	 * If there is old calendar config data saved, then it will get converted on activation.
301
+	 * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
302
+	 *
303
+	 * @return void
304
+	 */
305
+	public static function reset_and_update_config()
306
+	{
307
+		do_action('AHEE__EE_Config___load_core_config__start', ['EEH_Activation', 'load_calendar_config']);
308
+		add_filter(
309
+			'FHEE__EE_Config___load_core_config__config_settings',
310
+			['EEH_Activation', 'migrate_old_config_data'],
311
+			10,
312
+			3
313
+		);
314
+		if (! EE_Config::logging_enabled()) {
315
+			delete_option(EE_Config::LOG_NAME);
316
+		}
317
+	}
318
+
319
+
320
+	/**
321
+	 * @return    void
322
+	 */
323
+	public static function load_calendar_config()
324
+	{
325
+		// grab array of all plugin folders and loop thru it
326
+		$plugins = glob(WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR);
327
+		if (empty($plugins)) {
328
+			return;
329
+		}
330
+		foreach ($plugins as $plugin_path) {
331
+			// grab plugin folder name from path
332
+			$plugin = basename($plugin_path);
333
+			// drill down to Espresso plugins
334
+			// then to calendar related plugins
335
+			if (
336
+				strpos($plugin, 'espresso') !== false
337
+				|| strpos($plugin, 'Espresso') !== false
338
+				|| strpos($plugin, 'ee4') !== false
339
+				|| strpos($plugin, 'EE4') !== false
340
+				|| strpos($plugin, 'calendar') !== false
341
+			) {
342
+				// this is what we are looking for
343
+				$calendar_config = $plugin_path . '/EE_Calendar_Config.php';
344
+				// does it exist in this folder ?
345
+				if (is_readable($calendar_config)) {
346
+					// YEAH! let's load it
347
+					require_once($calendar_config);
348
+				}
349
+			}
350
+		}
351
+	}
352
+
353
+
354
+	/**
355
+	 * @param array|stdClass $settings
356
+	 * @param int|string     $config
357
+	 * @param EE_Config      $EE_Config
358
+	 * @return stdClass
359
+	 */
360
+	public static function migrate_old_config_data($settings, $config, EE_Config $EE_Config)
361
+	{
362
+		$convert_from_array = ['addons'];
363
+		// in case old settings were saved as an array
364
+		if (is_array($settings) && in_array($config, $convert_from_array)) {
365
+			// convert existing settings to an object
366
+			$config_array = $settings;
367
+			$settings     = new stdClass();
368
+			foreach ($config_array as $key => $value) {
369
+				if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
370
+					$EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
371
+				} else {
372
+					$settings->{$key} = $value;
373
+				}
374
+			}
375
+			add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
376
+		}
377
+		return $settings;
378
+	}
379
+
380
+
381
+	/**
382
+	 * @return void
383
+	 */
384
+	public static function deactivate_event_espresso()
385
+	{
386
+		// check permissions
387
+		if (current_user_can('activate_plugins')) {
388
+			deactivate_plugins(EE_PLUGIN_BASENAME, true);
389
+		}
390
+	}
391
+
392
+
393
+	/**
394
+	 * @return void
395
+	 * @throws InvalidDataTypeException
396
+	 */
397
+	public static function verify_default_pages_exist()
398
+	{
399
+		$critical_page_problem = false;
400
+		$critical_pages        = [
401
+			[
402
+				'id'   => 'reg_page_id',
403
+				'name' => esc_html__('Registration Checkout', 'event_espresso'),
404
+				'post' => null,
405
+				'code' => 'ESPRESSO_CHECKOUT',
406
+			],
407
+			[
408
+				'id'   => 'txn_page_id',
409
+				'name' => esc_html__('Transactions', 'event_espresso'),
410
+				'post' => null,
411
+				'code' => 'ESPRESSO_TXN_PAGE',
412
+			],
413
+			[
414
+				'id'   => 'thank_you_page_id',
415
+				'name' => esc_html__('Thank You', 'event_espresso'),
416
+				'post' => null,
417
+				'code' => 'ESPRESSO_THANK_YOU',
418
+			],
419
+			[
420
+				'id'   => 'cancel_page_id',
421
+				'name' => esc_html__('Registration Cancelled', 'event_espresso'),
422
+				'post' => null,
423
+				'code' => 'ESPRESSO_CANCELLED',
424
+			],
425
+		];
426
+		$EE_Core_Config        = EE_Registry::instance()->CFG->core;
427
+		foreach ($critical_pages as $critical_page) {
428
+			// is critical page ID set in config ?
429
+			if ($EE_Core_Config->{$critical_page['id']} !== false) {
430
+				// attempt to find post by ID
431
+				$critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
432
+			}
433
+			// no dice?
434
+			if ($critical_page['post'] === null) {
435
+				// attempt to find post by title
436
+				$critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
437
+				// still nothing?
438
+				if ($critical_page['post'] === null) {
439
+					$critical_page = EEH_Activation::create_critical_page($critical_page);
440
+					// REALLY? Still nothing ??!?!?
441
+					if ($critical_page['post'] === null) {
442
+						$msg = esc_html__(
443
+							'The Event Espresso critical page configuration settings could not be updated.',
444
+							'event_espresso'
445
+						);
446
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
447
+						break;
448
+					}
449
+				}
450
+			}
451
+			// check that Post ID matches critical page ID in config
452
+			if (
453
+				isset($critical_page['post']->ID)
454
+				&& $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
455
+			) {
456
+				// update Config with post ID
457
+				$EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
458
+				if (! EE_Config::instance()->update_espresso_config(false, false)) {
459
+					$msg = esc_html__(
460
+						'The Event Espresso critical page configuration settings could not be updated.',
461
+						'event_espresso'
462
+					);
463
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
464
+				}
465
+			}
466
+			$critical_page_problem =
467
+				! isset($critical_page['post']->post_status)
468
+				|| $critical_page['post']->post_status !== 'publish'
469
+				|| strpos($critical_page['post']->post_content, $critical_page['code']) === false
470
+					? true
471
+					: $critical_page_problem;
472
+		}
473
+		if ($critical_page_problem) {
474
+			new PersistentAdminNotice(
475
+				'critical_page_problem',
476
+				sprintf(
477
+					esc_html__(
478
+						'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
479
+						'event_espresso'
480
+					),
481
+					'<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
482
+					. esc_html__('Event Espresso Critical Pages Settings', 'event_espresso')
483
+					. '</a>'
484
+				)
485
+			);
486
+		}
487
+		if (EE_Error::has_notices()) {
488
+			EE_Error::get_notices(false, true);
489
+		}
490
+	}
491
+
492
+
493
+	/**
494
+	 * Returns the first post which uses the specified shortcode
495
+	 *
496
+	 * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
497
+	 *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
498
+	 *                             "[ESPRESSO_THANK_YOU"
499
+	 *                             (we don't search for the closing shortcode bracket because they might have added
500
+	 *                             parameter to the shortcode
501
+	 * @return WP_Post|array|null
502
+	 */
503
+	public static function get_page_by_ee_shortcode(string $ee_shortcode)
504
+	{
505
+		global $wpdb;
506
+		$shortcode_and_opening_bracket = '[' . $ee_shortcode;
507
+		$post_id                       =
508
+			$wpdb->get_var(
509
+				"SELECT ID FROM $wpdb->posts WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1"
510
+			);
511
+		if ($post_id) {
512
+			return get_post($post_id);
513
+		}
514
+		return null;
515
+	}
516
+
517
+
518
+	/**
519
+	 * This function generates a post for critical espresso pages
520
+	 *
521
+	 * @param array $critical_page
522
+	 * @return array
523
+	 */
524
+	public static function create_critical_page(array $critical_page): array
525
+	{
526
+		$post_args = [
527
+			'post_title'     => $critical_page['name'],
528
+			'post_status'    => 'publish',
529
+			'post_type'      => 'page',
530
+			'comment_status' => 'closed',
531
+			'post_content'   => '[' . $critical_page['code'] . ']',
532
+		];
533
+
534
+		$post_id = wp_insert_post($post_args);
535
+		if (! $post_id) {
536
+			$msg = sprintf(
537
+				esc_html__('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
538
+				$critical_page['name']
539
+			);
540
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
541
+			return $critical_page;
542
+		}
543
+		// get newly created post's details
544
+		if (! $critical_page['post'] = get_post($post_id)) {
545
+			$msg = sprintf(
546
+				esc_html__('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
547
+				$critical_page['name']
548
+			);
549
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
550
+		}
551
+
552
+		return $critical_page;
553
+	}
554
+
555
+
556
+	/**
557
+	 * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
558
+	 * The role being used to check is filterable.
559
+	 *
560
+	 * @return int|null WP_user ID or NULL
561
+	 * @throws EE_Error
562
+	 * @throws ReflectionException
563
+	 * @since  4.6.0
564
+	 * @global WPDB $wpdb
565
+	 */
566
+	public static function get_default_creator_id(): ?int
567
+	{
568
+		global $wpdb;
569
+		if (self::$_default_creator_id) {
570
+			return self::$_default_creator_id;
571
+		}/**/
572
+		$role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
573
+		// let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
574
+		$pre_filtered_id = apply_filters(
575
+			'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
576
+			false,
577
+			$role_to_check
578
+		);
579
+		if ($pre_filtered_id !== false) {
580
+			return (int) $pre_filtered_id;
581
+		}
582
+		$capabilities_key = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
583
+		$query            = $wpdb->prepare(
584
+			"
585 585
 SELECT user_id 
586 586
 FROM $wpdb->usermeta 
587 587
 WHERE meta_key = '$capabilities_key' 
588 588
   AND meta_value LIKE %s 
589 589
 ORDER BY user_id
590 590
 LIMIT 0,1",
591
-            '%' . $role_to_check . '%'
592
-        );
593
-        $user_id          = $wpdb->get_var($query);
594
-        $user_id          = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
595
-        if ($user_id && (int) $user_id) {
596
-            self::$_default_creator_id = (int) $user_id;
597
-            return self::$_default_creator_id;
598
-        }
599
-        return null;
600
-    }
601
-
602
-
603
-    /**
604
-     * used by EE and EE addons during plugin activation to create tables.
605
-     * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
606
-     * but includes extra logic regarding activations.
607
-     *
608
-     * @param string $table_name               without the $wpdb->prefix
609
-     * @param string $sql                      SQL for creating the table (contents between brackets in an SQL create
610
-     *                                         table query)
611
-     * @param string $engine                   like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
612
-     * @param bool   $drop_pre_existing_table  set to TRUE when you want to make SURE the table is completely empty
613
-     *                                         and new once this function is done (ie, you really do want to CREATE a
614
-     *                                         table, and expect it to be empty once you're done) leave as FALSE when
615
-     *                                         you just want to verify the table exists and matches this definition
616
-     *                                         (and if it HAS data in it you want to leave it be)
617
-     * @return void
618
-     * @throws EE_Error if there are database errors
619
-     * @throws ReflectionException
620
-     */
621
-    public static function create_table(
622
-        string $table_name,
623
-        string $sql,
624
-        string $engine = 'ENGINE=InnoDB ',
625
-        bool $drop_pre_existing_table = false
626
-    ) {
627
-        if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
628
-            return;
629
-        }
630
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
631
-        if (! function_exists('dbDelta')) {
632
-            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
633
-        }
634
-        $tableAnalysis = EEH_Activation::getTableAnalysis();
635
-        $wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
636
-        // do we need to first delete an existing version of this table ?
637
-        if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
638
-            // ok, delete the table... but ONLY if it's empty
639
-            $deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
640
-            // table is NOT empty, are you SURE you want to delete this table ???
641
-            if (! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
642
-                EEH_Activation::getTableManager()->dropTable($wp_table_name);
643
-            } elseif (! $deleted_safely) {
644
-                // so we should be more cautious rather than just dropping tables so easily
645
-                error_log(
646
-                    sprintf(
647
-                        esc_html__(
648
-                            'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
649
-                            'event_espresso'
650
-                        ),
651
-                        $wp_table_name,
652
-                        '<br/>',
653
-                        'espresso_db_update'
654
-                    )
655
-                );
656
-            }
657
-        }
658
-        $engine = str_replace('ENGINE=', '', $engine);
659
-        EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
660
-    }
661
-
662
-
663
-    /**
664
-     * Checks if this column already exists on the specified table. Handy for addons which want to add a column
665
-     *
666
-     * @param string $table_name  (without "wp_", eg "esp_attendee"
667
-     * @param string $column_name
668
-     * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
669
-     *                            'VARCHAR(10)'
670
-     * @return bool|int
671
-     * @throws EE_Error
672
-     * @throws ReflectionException
673
-     * @deprecated instead use TableManager::addColumn()
674
-     */
675
-    public static function add_column_if_it_doesnt_exist(
676
-        string $table_name,
677
-        string $column_name,
678
-        string $column_info = 'INT UNSIGNED NOT NULL'
679
-    ) {
680
-        return EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
681
-    }
682
-
683
-
684
-    /**
685
-     * Gets all the fields on the database table.
686
-     *
687
-     * @param string $table_name , without prefixed $wpdb->prefix
688
-     * @return array of database column names
689
-     * @throws EE_Error
690
-     * @throws ReflectionException
691
-     * @deprecated instead use TableManager::getTableColumns()
692
-     */
693
-    public static function get_fields_on_table(string $table_name = ''): array
694
-    {
695
-        return EEH_Activation::getTableManager()->getTableColumns($table_name);
696
-    }
697
-
698
-
699
-    /**
700
-     * @param string $table_name
701
-     * @return bool
702
-     * @throws EE_Error
703
-     * @throws ReflectionException
704
-     * @deprecated instead use TableAnalysis::tableIsEmpty()
705
-     */
706
-    public static function db_table_is_empty(string $table_name): bool
707
-    {
708
-        return EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
709
-    }
710
-
711
-
712
-    /**
713
-     * @param string $table_name
714
-     * @return bool | int
715
-     * @throws EE_Error
716
-     * @throws ReflectionException
717
-     */
718
-    public static function delete_db_table_if_empty(string $table_name)
719
-    {
720
-        if (EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
721
-            return EEH_Activation::getTableManager()->dropTable($table_name);
722
-        }
723
-        return false;
724
-    }
725
-
726
-
727
-    /**
728
-     * @param string $table_name
729
-     * @return bool|int
730
-     * @throws EE_Error
731
-     * @throws ReflectionException
732
-     * @deprecated instead use TableManager::dropTable()
733
-     */
734
-    public static function delete_unused_db_table(string $table_name)
735
-    {
736
-        return EEH_Activation::getTableManager()->dropTable($table_name);
737
-    }
738
-
739
-
740
-    /**
741
-     * @param string $table_name
742
-     * @param string $index_name
743
-     * @return bool|int
744
-     * @throws EE_Error
745
-     * @throws ReflectionException
746
-     * @deprecated instead use TableManager::dropIndex()
747
-     */
748
-    public static function drop_index(string $table_name, string $index_name)
749
-    {
750
-        return EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
751
-    }
752
-
753
-
754
-    /**
755
-     * @return boolean success (whether database is setup properly or not)
756
-     * @throws EE_Error
757
-     * @throws ReflectionException
758
-     */
759
-    public static function create_database_tables(): bool
760
-    {
761
-        EE_Registry::instance()->load_core('Data_Migration_Manager');
762
-        // find the migration script that sets the database to be compatible with the code
763
-        $dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
764
-        if (! $dms_name) {
765
-            EE_Error::add_error(
766
-                esc_html__(
767
-                    'Could not determine most up-to-date data migration script from which to pull database schema
591
+			'%' . $role_to_check . '%'
592
+		);
593
+		$user_id          = $wpdb->get_var($query);
594
+		$user_id          = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
595
+		if ($user_id && (int) $user_id) {
596
+			self::$_default_creator_id = (int) $user_id;
597
+			return self::$_default_creator_id;
598
+		}
599
+		return null;
600
+	}
601
+
602
+
603
+	/**
604
+	 * used by EE and EE addons during plugin activation to create tables.
605
+	 * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
606
+	 * but includes extra logic regarding activations.
607
+	 *
608
+	 * @param string $table_name               without the $wpdb->prefix
609
+	 * @param string $sql                      SQL for creating the table (contents between brackets in an SQL create
610
+	 *                                         table query)
611
+	 * @param string $engine                   like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
612
+	 * @param bool   $drop_pre_existing_table  set to TRUE when you want to make SURE the table is completely empty
613
+	 *                                         and new once this function is done (ie, you really do want to CREATE a
614
+	 *                                         table, and expect it to be empty once you're done) leave as FALSE when
615
+	 *                                         you just want to verify the table exists and matches this definition
616
+	 *                                         (and if it HAS data in it you want to leave it be)
617
+	 * @return void
618
+	 * @throws EE_Error if there are database errors
619
+	 * @throws ReflectionException
620
+	 */
621
+	public static function create_table(
622
+		string $table_name,
623
+		string $sql,
624
+		string $engine = 'ENGINE=InnoDB ',
625
+		bool $drop_pre_existing_table = false
626
+	) {
627
+		if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
628
+			return;
629
+		}
630
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
631
+		if (! function_exists('dbDelta')) {
632
+			require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
633
+		}
634
+		$tableAnalysis = EEH_Activation::getTableAnalysis();
635
+		$wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
636
+		// do we need to first delete an existing version of this table ?
637
+		if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
638
+			// ok, delete the table... but ONLY if it's empty
639
+			$deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
640
+			// table is NOT empty, are you SURE you want to delete this table ???
641
+			if (! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
642
+				EEH_Activation::getTableManager()->dropTable($wp_table_name);
643
+			} elseif (! $deleted_safely) {
644
+				// so we should be more cautious rather than just dropping tables so easily
645
+				error_log(
646
+					sprintf(
647
+						esc_html__(
648
+							'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
649
+							'event_espresso'
650
+						),
651
+						$wp_table_name,
652
+						'<br/>',
653
+						'espresso_db_update'
654
+					)
655
+				);
656
+			}
657
+		}
658
+		$engine = str_replace('ENGINE=', '', $engine);
659
+		EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
660
+	}
661
+
662
+
663
+	/**
664
+	 * Checks if this column already exists on the specified table. Handy for addons which want to add a column
665
+	 *
666
+	 * @param string $table_name  (without "wp_", eg "esp_attendee"
667
+	 * @param string $column_name
668
+	 * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
669
+	 *                            'VARCHAR(10)'
670
+	 * @return bool|int
671
+	 * @throws EE_Error
672
+	 * @throws ReflectionException
673
+	 * @deprecated instead use TableManager::addColumn()
674
+	 */
675
+	public static function add_column_if_it_doesnt_exist(
676
+		string $table_name,
677
+		string $column_name,
678
+		string $column_info = 'INT UNSIGNED NOT NULL'
679
+	) {
680
+		return EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
681
+	}
682
+
683
+
684
+	/**
685
+	 * Gets all the fields on the database table.
686
+	 *
687
+	 * @param string $table_name , without prefixed $wpdb->prefix
688
+	 * @return array of database column names
689
+	 * @throws EE_Error
690
+	 * @throws ReflectionException
691
+	 * @deprecated instead use TableManager::getTableColumns()
692
+	 */
693
+	public static function get_fields_on_table(string $table_name = ''): array
694
+	{
695
+		return EEH_Activation::getTableManager()->getTableColumns($table_name);
696
+	}
697
+
698
+
699
+	/**
700
+	 * @param string $table_name
701
+	 * @return bool
702
+	 * @throws EE_Error
703
+	 * @throws ReflectionException
704
+	 * @deprecated instead use TableAnalysis::tableIsEmpty()
705
+	 */
706
+	public static function db_table_is_empty(string $table_name): bool
707
+	{
708
+		return EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
709
+	}
710
+
711
+
712
+	/**
713
+	 * @param string $table_name
714
+	 * @return bool | int
715
+	 * @throws EE_Error
716
+	 * @throws ReflectionException
717
+	 */
718
+	public static function delete_db_table_if_empty(string $table_name)
719
+	{
720
+		if (EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
721
+			return EEH_Activation::getTableManager()->dropTable($table_name);
722
+		}
723
+		return false;
724
+	}
725
+
726
+
727
+	/**
728
+	 * @param string $table_name
729
+	 * @return bool|int
730
+	 * @throws EE_Error
731
+	 * @throws ReflectionException
732
+	 * @deprecated instead use TableManager::dropTable()
733
+	 */
734
+	public static function delete_unused_db_table(string $table_name)
735
+	{
736
+		return EEH_Activation::getTableManager()->dropTable($table_name);
737
+	}
738
+
739
+
740
+	/**
741
+	 * @param string $table_name
742
+	 * @param string $index_name
743
+	 * @return bool|int
744
+	 * @throws EE_Error
745
+	 * @throws ReflectionException
746
+	 * @deprecated instead use TableManager::dropIndex()
747
+	 */
748
+	public static function drop_index(string $table_name, string $index_name)
749
+	{
750
+		return EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
751
+	}
752
+
753
+
754
+	/**
755
+	 * @return boolean success (whether database is setup properly or not)
756
+	 * @throws EE_Error
757
+	 * @throws ReflectionException
758
+	 */
759
+	public static function create_database_tables(): bool
760
+	{
761
+		EE_Registry::instance()->load_core('Data_Migration_Manager');
762
+		// find the migration script that sets the database to be compatible with the code
763
+		$dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
764
+		if (! $dms_name) {
765
+			EE_Error::add_error(
766
+				esc_html__(
767
+					'Could not determine most up-to-date data migration script from which to pull database schema
768 768
                      structure. So database is probably not setup properly',
769
-                    'event_espresso'
770
-                ),
771
-                __FILE__,
772
-                __FUNCTION__,
773
-                __LINE__
774
-            );
775
-            return false;
776
-        }
777
-        $current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
778
-        $current_data_migration_script->set_migrating(false);
779
-        $current_data_migration_script->schema_changes_before_migration();
780
-        $current_data_migration_script->schema_changes_after_migration();
781
-        if ($current_data_migration_script->get_errors()) {
782
-            if (WP_DEBUG) {
783
-                foreach ($current_data_migration_script->get_errors() as $error) {
784
-                    EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
785
-                }
786
-            } else {
787
-                EE_Error::add_error(
788
-                    esc_html__(
789
-                        'There were errors creating the Event Espresso database tables and Event Espresso has been
769
+					'event_espresso'
770
+				),
771
+				__FILE__,
772
+				__FUNCTION__,
773
+				__LINE__
774
+			);
775
+			return false;
776
+		}
777
+		$current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
778
+		$current_data_migration_script->set_migrating(false);
779
+		$current_data_migration_script->schema_changes_before_migration();
780
+		$current_data_migration_script->schema_changes_after_migration();
781
+		if ($current_data_migration_script->get_errors()) {
782
+			if (WP_DEBUG) {
783
+				foreach ($current_data_migration_script->get_errors() as $error) {
784
+					EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
785
+				}
786
+			} else {
787
+				EE_Error::add_error(
788
+					esc_html__(
789
+						'There were errors creating the Event Espresso database tables and Event Espresso has been
790 790
                             deactivated. To view the errors, please enable WP_DEBUG in your wp-config.php file.',
791
-                        'event_espresso'
792
-                    ),
793
-                    __FILE__,
794
-                    __FUNCTION__,
795
-                    __LINE__
796
-                );
797
-            }
798
-            return false;
799
-        }
800
-        EE_Data_Migration_Manager::instance()->update_current_database_state_to();
801
-        return true;
802
-    }
803
-
804
-
805
-    /**
806
-     * @return void
807
-     * @throws EE_Error
808
-     * @throws ReflectionException
809
-     */
810
-    public static function initialize_system_questions()
811
-    {
812
-        // QUESTION GROUPS
813
-        global $wpdb;
814
-        $table_name = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
815
-        $SQL        = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
816
-        // what we have
817
-        $question_groups = $wpdb->get_col($SQL);
818
-        // check the response
819
-        $question_groups = is_array($question_groups) ? $question_groups : [];
820
-        // what we should have
821
-        $QSG_systems = [1, 2];
822
-        // loop thru what we should have and compare to what we have
823
-        foreach ($QSG_systems as $QSG_system) {
824
-            // reset values array
825
-            $QSG_values = [];
826
-            // if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
827
-            if (! in_array("$QSG_system", $question_groups)) {
828
-                // add it
829
-                switch ($QSG_system) {
830
-                    case 1:
831
-                        $QSG_values = [
832
-                            'QSG_name'            => esc_html__('Personal Information', 'event_espresso'),
833
-                            'QSG_identifier'      => 'personal-information-' . time(),
834
-                            'QSG_desc'            => '',
835
-                            'QSG_order'           => 1,
836
-                            'QSG_show_group_name' => 1,
837
-                            'QSG_show_group_desc' => 1,
838
-                            'QSG_system'          => EEM_Question_Group::system_personal,
839
-                            'QSG_deleted'         => 0,
840
-                        ];
841
-                        break;
842
-                    case 2:
843
-                        $QSG_values = [
844
-                            'QSG_name'            => esc_html__('Address Information', 'event_espresso'),
845
-                            'QSG_identifier'      => 'address-information-' . time(),
846
-                            'QSG_desc'            => '',
847
-                            'QSG_order'           => 2,
848
-                            'QSG_show_group_name' => 1,
849
-                            'QSG_show_group_desc' => 1,
850
-                            'QSG_system'          => EEM_Question_Group::system_address,
851
-                            'QSG_deleted'         => 0,
852
-                        ];
853
-                        break;
854
-                }
855
-                // make sure we have some values before inserting them
856
-                if (! empty($QSG_values)) {
857
-                    // insert system question
858
-                    $wpdb->insert(
859
-                        $table_name,
860
-                        $QSG_values,
861
-                        ['%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d']
862
-                    );
863
-                    $QSG_IDs[ $QSG_system ] = $wpdb->insert_id;
864
-                }
865
-            }
866
-        }
867
-        // QUESTIONS
868
-        global $wpdb;
869
-        $table_name = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
870
-        $SQL        = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
871
-        // what we have
872
-        $questions = $wpdb->get_col($SQL);
873
-        // all system questions
874
-        $personal_system_group_questions = ['fname', 'lname', 'email'];
875
-        $address_system_group_questions  = ['address', 'address2', 'city', 'country', 'state', 'zip', 'phone'];
876
-        $system_questions_not_in_group   = ['email_confirm'];
877
-        // merge all of the system questions we should have
878
-        $QST_systems       = array_merge(
879
-            $personal_system_group_questions,
880
-            $address_system_group_questions,
881
-            $system_questions_not_in_group
882
-        );
883
-        $order_for_group_1 = 1;
884
-        $order_for_group_2 = 1;
885
-        // loop thru what we should have and compare to what we have
886
-        foreach ($QST_systems as $QST_system) {
887
-            // reset values array
888
-            $QST_values = [];
889
-            // if we don't have what we should have
890
-            if (! in_array($QST_system, $questions)) {
891
-                // add it
892
-                switch ($QST_system) {
893
-                    case 'fname':
894
-                        $QST_values = [
895
-                            'QST_display_text'  => esc_html__('First Name', 'event_espresso'),
896
-                            'QST_admin_label'   => esc_html__('First Name - System Question', 'event_espresso'),
897
-                            'QST_system'        => 'fname',
898
-                            'QST_type'          => 'TEXT',
899
-                            'QST_required'      => 1,
900
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
901
-                            'QST_order'         => 1,
902
-                            'QST_admin_only'    => 0,
903
-                            'QST_max'           => EEM_Question::instance()
904
-                                                               ->absolute_max_for_system_question($QST_system),
905
-                            'QST_wp_user'       => self::get_default_creator_id(),
906
-                            'QST_deleted'       => 0,
907
-                        ];
908
-                        break;
909
-                    case 'lname':
910
-                        $QST_values = [
911
-                            'QST_display_text'  => esc_html__('Last Name', 'event_espresso'),
912
-                            'QST_admin_label'   => esc_html__('Last Name - System Question', 'event_espresso'),
913
-                            'QST_system'        => 'lname',
914
-                            'QST_type'          => 'TEXT',
915
-                            'QST_required'      => 1,
916
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
917
-                            'QST_order'         => 2,
918
-                            'QST_admin_only'    => 0,
919
-                            'QST_max'           => EEM_Question::instance()
920
-                                                               ->absolute_max_for_system_question($QST_system),
921
-                            'QST_wp_user'       => self::get_default_creator_id(),
922
-                            'QST_deleted'       => 0,
923
-                        ];
924
-                        break;
925
-                    case 'email':
926
-                        $QST_values = [
927
-                            'QST_display_text'  => esc_html__('Email Address', 'event_espresso'),
928
-                            'QST_admin_label'   => esc_html__('Email Address - System Question', 'event_espresso'),
929
-                            'QST_system'        => 'email',
930
-                            'QST_type'          => 'EMAIL',
931
-                            'QST_required'      => 1,
932
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
933
-                            'QST_order'         => 3,
934
-                            'QST_admin_only'    => 0,
935
-                            'QST_max'           => EEM_Question::instance()
936
-                                                               ->absolute_max_for_system_question($QST_system),
937
-                            'QST_wp_user'       => self::get_default_creator_id(),
938
-                            'QST_deleted'       => 0,
939
-                        ];
940
-                        break;
941
-                    case 'email_confirm':
942
-                        $QST_values = [
943
-                            'QST_display_text'  => esc_html__('Confirm Email Address', 'event_espresso'),
944
-                            'QST_admin_label'   => esc_html__(
945
-                                'Confirm Email Address - System Question',
946
-                                'event_espresso'
947
-                            ),
948
-                            'QST_system'        => 'email_confirm',
949
-                            'QST_type'          => 'EMAIL_CONFIRM',
950
-                            'QST_required'      => 1,
951
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
952
-                            'QST_order'         => 4,
953
-                            'QST_admin_only'    => 0,
954
-                            'QST_max'           => EEM_Question::instance()
955
-                                                               ->absolute_max_for_system_question($QST_system),
956
-                            'QST_wp_user'       => self::get_default_creator_id(),
957
-                            'QST_deleted'       => 0,
958
-                        ];
959
-                        break;
960
-                    case 'address':
961
-                        $QST_values = [
962
-                            'QST_display_text'  => esc_html__('Address', 'event_espresso'),
963
-                            'QST_admin_label'   => esc_html__('Address - System Question', 'event_espresso'),
964
-                            'QST_system'        => 'address',
965
-                            'QST_type'          => 'TEXT',
966
-                            'QST_required'      => 0,
967
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
968
-                            'QST_order'         => 5,
969
-                            'QST_admin_only'    => 0,
970
-                            'QST_max'           => EEM_Question::instance()
971
-                                                               ->absolute_max_for_system_question($QST_system),
972
-                            'QST_wp_user'       => self::get_default_creator_id(),
973
-                            'QST_deleted'       => 0,
974
-                        ];
975
-                        break;
976
-                    case 'address2':
977
-                        $QST_values = [
978
-                            'QST_display_text'  => esc_html__('Address2', 'event_espresso'),
979
-                            'QST_admin_label'   => esc_html__('Address2 - System Question', 'event_espresso'),
980
-                            'QST_system'        => 'address2',
981
-                            'QST_type'          => 'TEXT',
982
-                            'QST_required'      => 0,
983
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
984
-                            'QST_order'         => 6,
985
-                            'QST_admin_only'    => 0,
986
-                            'QST_max'           => EEM_Question::instance()
987
-                                                               ->absolute_max_for_system_question($QST_system),
988
-                            'QST_wp_user'       => self::get_default_creator_id(),
989
-                            'QST_deleted'       => 0,
990
-                        ];
991
-                        break;
992
-                    case 'city':
993
-                        $QST_values = [
994
-                            'QST_display_text'  => esc_html__('City', 'event_espresso'),
995
-                            'QST_admin_label'   => esc_html__('City - System Question', 'event_espresso'),
996
-                            'QST_system'        => 'city',
997
-                            'QST_type'          => 'TEXT',
998
-                            'QST_required'      => 0,
999
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1000
-                            'QST_order'         => 7,
1001
-                            'QST_admin_only'    => 0,
1002
-                            'QST_max'           => EEM_Question::instance()
1003
-                                                               ->absolute_max_for_system_question($QST_system),
1004
-                            'QST_wp_user'       => self::get_default_creator_id(),
1005
-                            'QST_deleted'       => 0,
1006
-                        ];
1007
-                        break;
1008
-                    case 'country':
1009
-                        $QST_values = [
1010
-                            'QST_display_text'  => esc_html__('Country', 'event_espresso'),
1011
-                            'QST_admin_label'   => esc_html__('Country - System Question', 'event_espresso'),
1012
-                            'QST_system'        => 'country',
1013
-                            'QST_type'          => 'COUNTRY',
1014
-                            'QST_required'      => 0,
1015
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1016
-                            'QST_order'         => 8,
1017
-                            'QST_admin_only'    => 0,
1018
-                            'QST_wp_user'       => self::get_default_creator_id(),
1019
-                            'QST_deleted'       => 0,
1020
-                        ];
1021
-                        break;
1022
-                    case 'state':
1023
-                        $QST_values = [
1024
-                            'QST_display_text'  => esc_html__('State/Province', 'event_espresso'),
1025
-                            'QST_admin_label'   => esc_html__('State/Province - System Question', 'event_espresso'),
1026
-                            'QST_system'        => 'state',
1027
-                            'QST_type'          => 'STATE',
1028
-                            'QST_required'      => 0,
1029
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1030
-                            'QST_order'         => 9,
1031
-                            'QST_admin_only'    => 0,
1032
-                            'QST_wp_user'       => self::get_default_creator_id(),
1033
-                            'QST_deleted'       => 0,
1034
-                        ];
1035
-                        break;
1036
-                    case 'zip':
1037
-                        $QST_values = [
1038
-                            'QST_display_text'  => esc_html__('Zip/Postal Code', 'event_espresso'),
1039
-                            'QST_admin_label'   => esc_html__('Zip/Postal Code - System Question', 'event_espresso'),
1040
-                            'QST_system'        => 'zip',
1041
-                            'QST_type'          => 'TEXT',
1042
-                            'QST_required'      => 0,
1043
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1044
-                            'QST_order'         => 10,
1045
-                            'QST_admin_only'    => 0,
1046
-                            'QST_max'           => EEM_Question::instance()
1047
-                                                               ->absolute_max_for_system_question($QST_system),
1048
-                            'QST_wp_user'       => self::get_default_creator_id(),
1049
-                            'QST_deleted'       => 0,
1050
-                        ];
1051
-                        break;
1052
-                    case 'phone':
1053
-                        $QST_values = [
1054
-                            'QST_display_text'  => esc_html__('Phone Number', 'event_espresso'),
1055
-                            'QST_admin_label'   => esc_html__('Phone Number - System Question', 'event_espresso'),
1056
-                            'QST_system'        => 'phone',
1057
-                            'QST_type'          => 'TEXT',
1058
-                            'QST_required'      => 0,
1059
-                            'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1060
-                            'QST_order'         => 11,
1061
-                            'QST_admin_only'    => 0,
1062
-                            'QST_max'           => EEM_Question::instance()
1063
-                                                               ->absolute_max_for_system_question($QST_system),
1064
-                            'QST_wp_user'       => self::get_default_creator_id(),
1065
-                            'QST_deleted'       => 0,
1066
-                        ];
1067
-                        break;
1068
-                }
1069
-                if (! empty($QST_values)) {
1070
-                    // insert system question
1071
-                    $wpdb->insert(
1072
-                        $table_name,
1073
-                        $QST_values,
1074
-                        ['%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d']
1075
-                    );
1076
-                    $QST_ID = $wpdb->insert_id;
1077
-
1078
-                    // QUESTION GROUP QUESTIONS
1079
-                    if (in_array($QST_system, $personal_system_group_questions)) {
1080
-                        $system_question_we_want = EEM_Question_Group::system_personal;
1081
-                    } elseif (in_array($QST_system, $address_system_group_questions)) {
1082
-                        $system_question_we_want = EEM_Question_Group::system_address;
1083
-                    } else {
1084
-                        // QST_system should not be assigned to any group
1085
-                        continue;
1086
-                    }
1087
-                    if (isset($QSG_IDs[ $system_question_we_want ])) {
1088
-                        $QSG_ID = $QSG_IDs[ $system_question_we_want ];
1089
-                    } else {
1090
-                        $id_col = EEM_Question_Group::instance()
1091
-                                                    ->get_col([['QSG_system' => $system_question_we_want]]);
1092
-                        if (is_array($id_col)) {
1093
-                            $QSG_ID = reset($id_col);
1094
-                        } else {
1095
-                            // ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1096
-                            EE_Log::instance()->log(
1097
-                                __FILE__,
1098
-                                __FUNCTION__,
1099
-                                sprintf(
1100
-                                    esc_html__(
1101
-                                        'Could not associate question %1$s to a question group because no system question
791
+						'event_espresso'
792
+					),
793
+					__FILE__,
794
+					__FUNCTION__,
795
+					__LINE__
796
+				);
797
+			}
798
+			return false;
799
+		}
800
+		EE_Data_Migration_Manager::instance()->update_current_database_state_to();
801
+		return true;
802
+	}
803
+
804
+
805
+	/**
806
+	 * @return void
807
+	 * @throws EE_Error
808
+	 * @throws ReflectionException
809
+	 */
810
+	public static function initialize_system_questions()
811
+	{
812
+		// QUESTION GROUPS
813
+		global $wpdb;
814
+		$table_name = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
815
+		$SQL        = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
816
+		// what we have
817
+		$question_groups = $wpdb->get_col($SQL);
818
+		// check the response
819
+		$question_groups = is_array($question_groups) ? $question_groups : [];
820
+		// what we should have
821
+		$QSG_systems = [1, 2];
822
+		// loop thru what we should have and compare to what we have
823
+		foreach ($QSG_systems as $QSG_system) {
824
+			// reset values array
825
+			$QSG_values = [];
826
+			// if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
827
+			if (! in_array("$QSG_system", $question_groups)) {
828
+				// add it
829
+				switch ($QSG_system) {
830
+					case 1:
831
+						$QSG_values = [
832
+							'QSG_name'            => esc_html__('Personal Information', 'event_espresso'),
833
+							'QSG_identifier'      => 'personal-information-' . time(),
834
+							'QSG_desc'            => '',
835
+							'QSG_order'           => 1,
836
+							'QSG_show_group_name' => 1,
837
+							'QSG_show_group_desc' => 1,
838
+							'QSG_system'          => EEM_Question_Group::system_personal,
839
+							'QSG_deleted'         => 0,
840
+						];
841
+						break;
842
+					case 2:
843
+						$QSG_values = [
844
+							'QSG_name'            => esc_html__('Address Information', 'event_espresso'),
845
+							'QSG_identifier'      => 'address-information-' . time(),
846
+							'QSG_desc'            => '',
847
+							'QSG_order'           => 2,
848
+							'QSG_show_group_name' => 1,
849
+							'QSG_show_group_desc' => 1,
850
+							'QSG_system'          => EEM_Question_Group::system_address,
851
+							'QSG_deleted'         => 0,
852
+						];
853
+						break;
854
+				}
855
+				// make sure we have some values before inserting them
856
+				if (! empty($QSG_values)) {
857
+					// insert system question
858
+					$wpdb->insert(
859
+						$table_name,
860
+						$QSG_values,
861
+						['%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d']
862
+					);
863
+					$QSG_IDs[ $QSG_system ] = $wpdb->insert_id;
864
+				}
865
+			}
866
+		}
867
+		// QUESTIONS
868
+		global $wpdb;
869
+		$table_name = EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
870
+		$SQL        = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
871
+		// what we have
872
+		$questions = $wpdb->get_col($SQL);
873
+		// all system questions
874
+		$personal_system_group_questions = ['fname', 'lname', 'email'];
875
+		$address_system_group_questions  = ['address', 'address2', 'city', 'country', 'state', 'zip', 'phone'];
876
+		$system_questions_not_in_group   = ['email_confirm'];
877
+		// merge all of the system questions we should have
878
+		$QST_systems       = array_merge(
879
+			$personal_system_group_questions,
880
+			$address_system_group_questions,
881
+			$system_questions_not_in_group
882
+		);
883
+		$order_for_group_1 = 1;
884
+		$order_for_group_2 = 1;
885
+		// loop thru what we should have and compare to what we have
886
+		foreach ($QST_systems as $QST_system) {
887
+			// reset values array
888
+			$QST_values = [];
889
+			// if we don't have what we should have
890
+			if (! in_array($QST_system, $questions)) {
891
+				// add it
892
+				switch ($QST_system) {
893
+					case 'fname':
894
+						$QST_values = [
895
+							'QST_display_text'  => esc_html__('First Name', 'event_espresso'),
896
+							'QST_admin_label'   => esc_html__('First Name - System Question', 'event_espresso'),
897
+							'QST_system'        => 'fname',
898
+							'QST_type'          => 'TEXT',
899
+							'QST_required'      => 1,
900
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
901
+							'QST_order'         => 1,
902
+							'QST_admin_only'    => 0,
903
+							'QST_max'           => EEM_Question::instance()
904
+															   ->absolute_max_for_system_question($QST_system),
905
+							'QST_wp_user'       => self::get_default_creator_id(),
906
+							'QST_deleted'       => 0,
907
+						];
908
+						break;
909
+					case 'lname':
910
+						$QST_values = [
911
+							'QST_display_text'  => esc_html__('Last Name', 'event_espresso'),
912
+							'QST_admin_label'   => esc_html__('Last Name - System Question', 'event_espresso'),
913
+							'QST_system'        => 'lname',
914
+							'QST_type'          => 'TEXT',
915
+							'QST_required'      => 1,
916
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
917
+							'QST_order'         => 2,
918
+							'QST_admin_only'    => 0,
919
+							'QST_max'           => EEM_Question::instance()
920
+															   ->absolute_max_for_system_question($QST_system),
921
+							'QST_wp_user'       => self::get_default_creator_id(),
922
+							'QST_deleted'       => 0,
923
+						];
924
+						break;
925
+					case 'email':
926
+						$QST_values = [
927
+							'QST_display_text'  => esc_html__('Email Address', 'event_espresso'),
928
+							'QST_admin_label'   => esc_html__('Email Address - System Question', 'event_espresso'),
929
+							'QST_system'        => 'email',
930
+							'QST_type'          => 'EMAIL',
931
+							'QST_required'      => 1,
932
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
933
+							'QST_order'         => 3,
934
+							'QST_admin_only'    => 0,
935
+							'QST_max'           => EEM_Question::instance()
936
+															   ->absolute_max_for_system_question($QST_system),
937
+							'QST_wp_user'       => self::get_default_creator_id(),
938
+							'QST_deleted'       => 0,
939
+						];
940
+						break;
941
+					case 'email_confirm':
942
+						$QST_values = [
943
+							'QST_display_text'  => esc_html__('Confirm Email Address', 'event_espresso'),
944
+							'QST_admin_label'   => esc_html__(
945
+								'Confirm Email Address - System Question',
946
+								'event_espresso'
947
+							),
948
+							'QST_system'        => 'email_confirm',
949
+							'QST_type'          => 'EMAIL_CONFIRM',
950
+							'QST_required'      => 1,
951
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
952
+							'QST_order'         => 4,
953
+							'QST_admin_only'    => 0,
954
+							'QST_max'           => EEM_Question::instance()
955
+															   ->absolute_max_for_system_question($QST_system),
956
+							'QST_wp_user'       => self::get_default_creator_id(),
957
+							'QST_deleted'       => 0,
958
+						];
959
+						break;
960
+					case 'address':
961
+						$QST_values = [
962
+							'QST_display_text'  => esc_html__('Address', 'event_espresso'),
963
+							'QST_admin_label'   => esc_html__('Address - System Question', 'event_espresso'),
964
+							'QST_system'        => 'address',
965
+							'QST_type'          => 'TEXT',
966
+							'QST_required'      => 0,
967
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
968
+							'QST_order'         => 5,
969
+							'QST_admin_only'    => 0,
970
+							'QST_max'           => EEM_Question::instance()
971
+															   ->absolute_max_for_system_question($QST_system),
972
+							'QST_wp_user'       => self::get_default_creator_id(),
973
+							'QST_deleted'       => 0,
974
+						];
975
+						break;
976
+					case 'address2':
977
+						$QST_values = [
978
+							'QST_display_text'  => esc_html__('Address2', 'event_espresso'),
979
+							'QST_admin_label'   => esc_html__('Address2 - System Question', 'event_espresso'),
980
+							'QST_system'        => 'address2',
981
+							'QST_type'          => 'TEXT',
982
+							'QST_required'      => 0,
983
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
984
+							'QST_order'         => 6,
985
+							'QST_admin_only'    => 0,
986
+							'QST_max'           => EEM_Question::instance()
987
+															   ->absolute_max_for_system_question($QST_system),
988
+							'QST_wp_user'       => self::get_default_creator_id(),
989
+							'QST_deleted'       => 0,
990
+						];
991
+						break;
992
+					case 'city':
993
+						$QST_values = [
994
+							'QST_display_text'  => esc_html__('City', 'event_espresso'),
995
+							'QST_admin_label'   => esc_html__('City - System Question', 'event_espresso'),
996
+							'QST_system'        => 'city',
997
+							'QST_type'          => 'TEXT',
998
+							'QST_required'      => 0,
999
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1000
+							'QST_order'         => 7,
1001
+							'QST_admin_only'    => 0,
1002
+							'QST_max'           => EEM_Question::instance()
1003
+															   ->absolute_max_for_system_question($QST_system),
1004
+							'QST_wp_user'       => self::get_default_creator_id(),
1005
+							'QST_deleted'       => 0,
1006
+						];
1007
+						break;
1008
+					case 'country':
1009
+						$QST_values = [
1010
+							'QST_display_text'  => esc_html__('Country', 'event_espresso'),
1011
+							'QST_admin_label'   => esc_html__('Country - System Question', 'event_espresso'),
1012
+							'QST_system'        => 'country',
1013
+							'QST_type'          => 'COUNTRY',
1014
+							'QST_required'      => 0,
1015
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1016
+							'QST_order'         => 8,
1017
+							'QST_admin_only'    => 0,
1018
+							'QST_wp_user'       => self::get_default_creator_id(),
1019
+							'QST_deleted'       => 0,
1020
+						];
1021
+						break;
1022
+					case 'state':
1023
+						$QST_values = [
1024
+							'QST_display_text'  => esc_html__('State/Province', 'event_espresso'),
1025
+							'QST_admin_label'   => esc_html__('State/Province - System Question', 'event_espresso'),
1026
+							'QST_system'        => 'state',
1027
+							'QST_type'          => 'STATE',
1028
+							'QST_required'      => 0,
1029
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1030
+							'QST_order'         => 9,
1031
+							'QST_admin_only'    => 0,
1032
+							'QST_wp_user'       => self::get_default_creator_id(),
1033
+							'QST_deleted'       => 0,
1034
+						];
1035
+						break;
1036
+					case 'zip':
1037
+						$QST_values = [
1038
+							'QST_display_text'  => esc_html__('Zip/Postal Code', 'event_espresso'),
1039
+							'QST_admin_label'   => esc_html__('Zip/Postal Code - System Question', 'event_espresso'),
1040
+							'QST_system'        => 'zip',
1041
+							'QST_type'          => 'TEXT',
1042
+							'QST_required'      => 0,
1043
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1044
+							'QST_order'         => 10,
1045
+							'QST_admin_only'    => 0,
1046
+							'QST_max'           => EEM_Question::instance()
1047
+															   ->absolute_max_for_system_question($QST_system),
1048
+							'QST_wp_user'       => self::get_default_creator_id(),
1049
+							'QST_deleted'       => 0,
1050
+						];
1051
+						break;
1052
+					case 'phone':
1053
+						$QST_values = [
1054
+							'QST_display_text'  => esc_html__('Phone Number', 'event_espresso'),
1055
+							'QST_admin_label'   => esc_html__('Phone Number - System Question', 'event_espresso'),
1056
+							'QST_system'        => 'phone',
1057
+							'QST_type'          => 'TEXT',
1058
+							'QST_required'      => 0,
1059
+							'QST_required_text' => esc_html__('This field is required', 'event_espresso'),
1060
+							'QST_order'         => 11,
1061
+							'QST_admin_only'    => 0,
1062
+							'QST_max'           => EEM_Question::instance()
1063
+															   ->absolute_max_for_system_question($QST_system),
1064
+							'QST_wp_user'       => self::get_default_creator_id(),
1065
+							'QST_deleted'       => 0,
1066
+						];
1067
+						break;
1068
+				}
1069
+				if (! empty($QST_values)) {
1070
+					// insert system question
1071
+					$wpdb->insert(
1072
+						$table_name,
1073
+						$QST_values,
1074
+						['%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d']
1075
+					);
1076
+					$QST_ID = $wpdb->insert_id;
1077
+
1078
+					// QUESTION GROUP QUESTIONS
1079
+					if (in_array($QST_system, $personal_system_group_questions)) {
1080
+						$system_question_we_want = EEM_Question_Group::system_personal;
1081
+					} elseif (in_array($QST_system, $address_system_group_questions)) {
1082
+						$system_question_we_want = EEM_Question_Group::system_address;
1083
+					} else {
1084
+						// QST_system should not be assigned to any group
1085
+						continue;
1086
+					}
1087
+					if (isset($QSG_IDs[ $system_question_we_want ])) {
1088
+						$QSG_ID = $QSG_IDs[ $system_question_we_want ];
1089
+					} else {
1090
+						$id_col = EEM_Question_Group::instance()
1091
+													->get_col([['QSG_system' => $system_question_we_want]]);
1092
+						if (is_array($id_col)) {
1093
+							$QSG_ID = reset($id_col);
1094
+						} else {
1095
+							// ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1096
+							EE_Log::instance()->log(
1097
+								__FILE__,
1098
+								__FUNCTION__,
1099
+								sprintf(
1100
+									esc_html__(
1101
+										'Could not associate question %1$s to a question group because no system question
1102 1102
                                          group existed',
1103
-                                        'event_espresso'
1104
-                                    ),
1105
-                                    $QST_ID
1106
-                                ),
1107
-                                'error'
1108
-                            );
1109
-                            continue;
1110
-                        }
1111
-                    }
1112
-                    // add system questions to groups
1113
-                    $wpdb->insert(
1114
-                        EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1115
-                        [
1116
-                            'QSG_ID'    => $QSG_ID,
1117
-                            'QST_ID'    => $QST_ID,
1118
-                            'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1119
-                        ],
1120
-                        ['%d', '%d', '%d']
1121
-                    );
1122
-                }
1123
-            }
1124
-        }
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * Makes sure the default payment method (Invoice) is active.
1130
-     * This used to be done automatically as part of constructing the old gateways config
1131
-     *
1132
-     * @throws EE_Error
1133
-     * @throws ReflectionException
1134
-     */
1135
-    public static function insert_default_payment_methods()
1136
-    {
1137
-        if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1138
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
1139
-            EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1140
-        } else {
1141
-            EEM_Payment_Method::instance()->verify_button_urls();
1142
-        }
1143
-    }
1144
-
1145
-
1146
-    /**
1147
-     * @return void
1148
-     * @throws EE_Error
1149
-     * @throws ReflectionException
1150
-     */
1151
-    public static function insert_default_status_codes()
1152
-    {
1153
-        global $wpdb;
1154
-
1155
-        if (EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1156
-            $table_name = EEM_Status::instance()->table();
1157
-
1158
-            $SQL =
1159
-                "DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1160
-            $wpdb->query($SQL);
1161
-
1162
-            $SQL = "INSERT INTO $table_name
1103
+										'event_espresso'
1104
+									),
1105
+									$QST_ID
1106
+								),
1107
+								'error'
1108
+							);
1109
+							continue;
1110
+						}
1111
+					}
1112
+					// add system questions to groups
1113
+					$wpdb->insert(
1114
+						EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1115
+						[
1116
+							'QSG_ID'    => $QSG_ID,
1117
+							'QST_ID'    => $QST_ID,
1118
+							'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1119
+						],
1120
+						['%d', '%d', '%d']
1121
+					);
1122
+				}
1123
+			}
1124
+		}
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * Makes sure the default payment method (Invoice) is active.
1130
+	 * This used to be done automatically as part of constructing the old gateways config
1131
+	 *
1132
+	 * @throws EE_Error
1133
+	 * @throws ReflectionException
1134
+	 */
1135
+	public static function insert_default_payment_methods()
1136
+	{
1137
+		if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1138
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
1139
+			EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1140
+		} else {
1141
+			EEM_Payment_Method::instance()->verify_button_urls();
1142
+		}
1143
+	}
1144
+
1145
+
1146
+	/**
1147
+	 * @return void
1148
+	 * @throws EE_Error
1149
+	 * @throws ReflectionException
1150
+	 */
1151
+	public static function insert_default_status_codes()
1152
+	{
1153
+		global $wpdb;
1154
+
1155
+		if (EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1156
+			$table_name = EEM_Status::instance()->table();
1157
+
1158
+			$SQL =
1159
+				"DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1160
+			$wpdb->query($SQL);
1161
+
1162
+			$SQL = "INSERT INTO $table_name
1163 1163
 					(STS_ID, STS_code, STS_type, STS_can_edit, STS_desc, STS_open) VALUES
1164 1164
 					('ACT', 'ACTIVE', 'event', 0, NULL, 1),
1165 1165
 					('NAC', 'NOT_ACTIVE', 'event', 0, NULL, 0),
@@ -1199,466 +1199,466 @@  discard block
 block discarded – undo
1199 1199
 					('MID', 'IDLE', 'message', 0, NULL, 1),
1200 1200
 					('MRS', 'RESEND', 'message', 0, NULL, 1),
1201 1201
 					('MIC', 'INCOMPLETE', 'message', 0, NULL, 0);";
1202
-            $wpdb->query($SQL);
1203
-        }
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * @return bool     true means new templates were created.
1209
-     *                  false means no templates were created.
1210
-     *                  This is NOT an error flag. To check for errors you will want
1211
-     *                  to use either EE_Error or a try catch for an EE_Error exception.
1212
-     * @throws EE_Error
1213
-     * @throws ReflectionException
1214
-     */
1215
-    public static function generate_default_message_templates(): bool
1216
-    {
1217
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
1218
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1219
-        /*
1202
+			$wpdb->query($SQL);
1203
+		}
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * @return bool     true means new templates were created.
1209
+	 *                  false means no templates were created.
1210
+	 *                  This is NOT an error flag. To check for errors you will want
1211
+	 *                  to use either EE_Error or a try catch for an EE_Error exception.
1212
+	 * @throws EE_Error
1213
+	 * @throws ReflectionException
1214
+	 */
1215
+	public static function generate_default_message_templates(): bool
1216
+	{
1217
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
1218
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1219
+		/*
1220 1220
          * This first method is taking care of ensuring any default messengers
1221 1221
          * that should be made active and have templates generated are done.
1222 1222
          */
1223
-        $new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1224
-            $message_resource_manager
1225
-        );
1226
-        /**
1227
-         * This method is verifying there are no NEW default message types
1228
-         * for ACTIVE messengers that need activated (and corresponding templates setup).
1229
-         */
1230
-        $new_templates_created_for_message_type =
1231
-            self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1232
-                $message_resource_manager
1233
-            );
1234
-        // after all is done, let's persist these changes to the db.
1235
-        $message_resource_manager->update_has_activated_messengers_option();
1236
-        $message_resource_manager->update_active_messengers_option();
1237
-        // will return true if either of these are true.  Otherwise will return false.
1238
-        return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * @param EE_Message_Resource_Manager $message_resource_manager
1244
-     * @return array|bool
1245
-     * @throws EE_Error
1246
-     * @throws ReflectionException
1247
-     */
1248
-    protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1249
-        EE_Message_Resource_Manager $message_resource_manager
1250
-    ) {
1251
-        $active_messengers       = $message_resource_manager->active_messengers();
1252
-        $installed_message_types = $message_resource_manager->installed_message_types();
1253
-        $templates_created       = false;
1254
-        foreach ($active_messengers as $active_messenger) {
1255
-            $default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1256
-            $default_message_type_names_to_activate   = [];
1257
-            // looping through each default message type reported by the messenger
1258
-            // and setup the actual message types to activate.
1259
-            foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1260
-                // if already active or has already been activated before we skip
1261
-                // (otherwise we might reactivate something user's intentionally deactivated.)
1262
-                // we also skip if the message type is not installed.
1263
-                if (
1264
-                    $message_resource_manager->has_message_type_been_activated_for_messenger(
1265
-                        $default_message_type_name_for_messenger,
1266
-                        $active_messenger->name
1267
-                    )
1268
-                    || $message_resource_manager->is_message_type_active_for_messenger(
1269
-                        $active_messenger->name,
1270
-                        $default_message_type_name_for_messenger
1271
-                    )
1272
-                    || ! isset($installed_message_types[ $default_message_type_name_for_messenger ])
1273
-                ) {
1274
-                    continue;
1275
-                }
1276
-                $default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1277
-            }
1278
-            // let's activate!
1279
-            $message_resource_manager->ensure_message_types_are_active(
1280
-                $default_message_type_names_to_activate,
1281
-                $active_messenger->name,
1282
-                false
1283
-            );
1284
-            // activate the templates for these message types
1285
-            if (! empty($default_message_type_names_to_activate)) {
1286
-                $templates_created = EEH_MSG_Template::generate_new_templates(
1287
-                    $active_messenger->name,
1288
-                    $default_message_type_names_for_messenger,
1289
-                    '',
1290
-                    true
1291
-                );
1292
-            }
1293
-        }
1294
-        return $templates_created;
1295
-    }
1296
-
1297
-
1298
-    /**
1299
-     * This will activate and generate default messengers and default message types for those messengers.
1300
-     *
1301
-     * @param EE_message_Resource_Manager $message_resource_manager
1302
-     * @return array|bool  True means there were default messengers and message type templates generated.
1303
-     *                     False means that there were no templates generated
1304
-     *                     (which could simply mean there are no default message types for a messenger).
1305
-     * @throws EE_Error
1306
-     * @throws ReflectionException
1307
-     */
1308
-    protected static function _activate_and_generate_default_messengers_and_message_templates(
1309
-        EE_Message_Resource_Manager $message_resource_manager
1310
-    ) {
1311
-        $messengers_to_generate  = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1312
-        $installed_message_types = $message_resource_manager->installed_message_types();
1313
-        $templates_generated     = false;
1314
-        foreach ($messengers_to_generate as $messenger_to_generate) {
1315
-            $default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1316
-            // verify the default message types match an installed message type.
1317
-            foreach ($default_message_type_names_for_messenger as $key => $name) {
1318
-                if (
1319
-                    ! isset($installed_message_types[ $name ])
1320
-                    || $message_resource_manager->has_message_type_been_activated_for_messenger(
1321
-                        $name,
1322
-                        $messenger_to_generate->name
1323
-                    )
1324
-                ) {
1325
-                    unset($default_message_type_names_for_messenger[ $key ]);
1326
-                }
1327
-            }
1328
-            // in previous iterations, the active_messengers option in the db
1329
-            // needed updated before calling create templates. however with the changes this may not be necessary.
1330
-            // This comment is left here just in case we discover that we _do_ need to update before
1331
-            // passing off to create templates (after the refactor is done).
1332
-            // @todo remove this comment when determined not necessary.
1333
-            $message_resource_manager->activate_messenger(
1334
-                $messenger_to_generate,
1335
-                $default_message_type_names_for_messenger,
1336
-                false
1337
-            );
1338
-            // create any templates needing created (or will reactivate templates already generated as necessary).
1339
-            if (! empty($default_message_type_names_for_messenger)) {
1340
-                $templates_generated = EEH_MSG_Template::generate_new_templates(
1341
-                    $messenger_to_generate->name,
1342
-                    $default_message_type_names_for_messenger,
1343
-                    '',
1344
-                    true
1345
-                );
1346
-            }
1347
-        }
1348
-        return $templates_generated;
1349
-    }
1350
-
1351
-
1352
-    /**
1353
-     * This returns the default messengers to generate templates for on activation of EE.
1354
-     * It considers:
1355
-     * - whether a messenger is already active in the db.
1356
-     * - whether a messenger has been made active at any time in the past.
1357
-     *
1358
-     * @param EE_Message_Resource_Manager $message_resource_manager
1359
-     * @return EE_messenger[]
1360
-     */
1361
-    protected static function _get_default_messengers_to_generate_on_activation(
1362
-        EE_Message_Resource_Manager $message_resource_manager
1363
-    ): array {
1364
-        $active_messengers    = $message_resource_manager->active_messengers();
1365
-        $installed_messengers = $message_resource_manager->installed_messengers();
1366
-        $has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1367
-
1368
-        $messengers_to_generate = [];
1369
-        foreach ($installed_messengers as $installed_messenger) {
1370
-            // if installed messenger is a messenger that should be activated on install
1371
-            // and is not already active
1372
-            // and has never been activated
1373
-            if (
1374
-                ! $installed_messenger->activate_on_install
1375
-                || isset($active_messengers[ $installed_messenger->name ])
1376
-                || isset($has_activated[ $installed_messenger->name ])
1377
-            ) {
1378
-                continue;
1379
-            }
1380
-            $messengers_to_generate[ $installed_messenger->name ] = $installed_messenger;
1381
-        }
1382
-        return $messengers_to_generate;
1383
-    }
1384
-
1385
-
1386
-    /**
1387
-     * This simply validates active message types to ensure they actually match installed
1388
-     * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1389
-     * rows are set inactive.
1390
-     * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1391
-     * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1392
-     * are still handled in here.
1393
-     *
1394
-     * @return void
1395
-     * @throws EE_Error
1396
-     * @throws ReflectionException
1397
-     * @since 4.3.1
1398
-     */
1399
-    public static function validate_messages_system()
1400
-    {
1401
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
1402
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1403
-        $message_resource_manager->validate_active_message_types_are_installed();
1404
-        do_action('AHEE__EEH_Activation__validate_messages_system');
1405
-    }
1406
-
1407
-
1408
-    /**
1409
-     * @return void
1410
-     */
1411
-    public static function plugin_deactivation()
1412
-    {
1413
-    }
1414
-
1415
-
1416
-    /**
1417
-     * Finds all our EE4 custom post types, and deletes them and their associated data
1418
-     * (like post meta or term relations)
1419
-     *
1420
-     * @throws EE_Error
1421
-     * @global wpdb $wpdb
1422
-     */
1423
-    public static function delete_all_espresso_cpt_data()
1424
-    {
1425
-        global $wpdb;
1426
-        // get all the CPT post_types
1427
-        $ee_post_types = [];
1428
-        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1429
-            if (method_exists($model_name, 'instance')) {
1430
-                $model_obj = call_user_func([$model_name, 'instance']);
1431
-                if ($model_obj instanceof EEM_CPT_Base) {
1432
-                    $ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1433
-                }
1434
-            }
1435
-        }
1436
-        // get all our CPTs
1437
-        $query   = "SELECT ID FROM $wpdb->posts WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1438
-        $cpt_ids = $wpdb->get_col($query);
1439
-        // delete each post meta and term relations too
1440
-        foreach ($cpt_ids as $post_id) {
1441
-            wp_delete_post($post_id, true);
1442
-        }
1443
-    }
1444
-
1445
-
1446
-    /**
1447
-     * Deletes all EE custom tables
1448
-     *
1449
-     * @return array
1450
-     * @throws EE_Error
1451
-     * @throws ReflectionException
1452
-     */
1453
-    public static function drop_espresso_tables(): array
1454
-    {
1455
-        $tables = [];
1456
-        // load registry
1457
-        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1458
-            if (method_exists($model_name, 'instance')) {
1459
-                $model_obj = call_user_func([$model_name, 'instance']);
1460
-                if ($model_obj instanceof EEM_Base) {
1461
-                    foreach ($model_obj->get_tables() as $table) {
1462
-                        if (
1463
-                            strpos($table->get_table_name(), 'esp_')
1464
-                            && (
1465
-                                is_main_site()// main site? nuke them all
1466
-                                || ! $table->is_global()// not main site,but not global either. nuke it
1467
-                            )
1468
-                        ) {
1469
-                            $tables[ $table->get_table_name() ] = $table->get_table_name();
1470
-                        }
1471
-                    }
1472
-                }
1473
-            }
1474
-        }
1475
-
1476
-        // there are some tables whose models were removed.
1477
-        // they should be removed when removing all EE core's data
1478
-        $tables_without_models = [
1479
-            'esp_promotion',
1480
-            'esp_promotion_applied',
1481
-            'esp_promotion_object',
1482
-            'esp_promotion_rule',
1483
-            'esp_rule',
1484
-        ];
1485
-        foreach ($tables_without_models as $table) {
1486
-            $tables[ $table ] = $table;
1487
-        }
1488
-        return EEH_Activation::getTableManager()->dropTables($tables);
1489
-    }
1490
-
1491
-
1492
-    /**
1493
-     * Drops all the tables mentioned in a single MYSQL query. Double-checks
1494
-     * each table name provided has a wpdb prefix attached, and that it exists.
1495
-     * Returns the list actually deleted
1496
-     *
1497
-     * @param array $table_names
1498
-     * @return array of table names which we deleted
1499
-     * @throws EE_Error
1500
-     * @throws ReflectionException
1501
-     * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1502
-     * @global WPDB $wpdb
1503
-     */
1504
-    public static function drop_tables(array $table_names): array
1505
-    {
1506
-        return EEH_Activation::getTableManager()->dropTables($table_names);
1507
-    }
1508
-
1509
-
1510
-    /**
1511
-     * plugin_uninstall
1512
-     *
1513
-     * @param bool $remove_all
1514
-     * @return void
1515
-     * @throws EE_Error
1516
-     * @throws ReflectionException
1517
-     */
1518
-    public static function delete_all_espresso_tables_and_data(bool $remove_all = true)
1519
-    {
1520
-        global $wpdb;
1521
-        self::drop_espresso_tables();
1522
-        $wp_options_to_delete = [
1523
-            'ee_no_ticket_prices'                        => true,
1524
-            'ee_active_messengers'                       => true,
1525
-            'ee_has_activated_messenger'                 => true,
1526
-            RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES => true,
1527
-            'ee_config'                                  => false,
1528
-            'ee_data_migration_current_db_state'         => true,
1529
-            'ee_data_migration_mapping_'                 => false,
1530
-            'ee_data_migration_script_'                  => false,
1531
-            'ee_data_migrations'                         => true,
1532
-            'ee_dms_map'                                 => false,
1533
-            'ee_notices'                                 => true,
1534
-            'lang_file_check_'                           => false,
1535
-            'ee_maintenance_mode'                        => true,
1536
-            'ee_ueip_optin'                              => true,
1537
-            'ee_ueip_has_notified'                       => true,
1538
-            'ee_plugin_activation_errors'                => true,
1539
-            'ee_id_mapping_from'                         => false,
1540
-            'espresso_persistent_admin_notices'          => true,
1541
-            'ee_encryption_key'                          => true,
1542
-            'pue_force_upgrade_'                         => false,
1543
-            'pue_json_error_'                            => false,
1544
-            'pue_install_key_'                           => false,
1545
-            'pue_verification_error_'                    => false,
1546
-            'pu_dismissed_upgrade_'                      => false,
1547
-            'external_updates-'                          => false,
1548
-            'ee_extra_data'                              => true,
1549
-            'ee_ssn_'                                    => false,
1550
-            'ee_rss_'                                    => false,
1551
-            'ee_rte_n_tx_'                               => false,
1552
-            'ee_pers_admin_notices'                      => true,
1553
-            'ee_job_parameters_'                         => false,
1554
-            'ee_upload_directories_incomplete'           => true,
1555
-            'ee_verified_db_collations'                  => true,
1556
-        ];
1557
-        if (is_main_site()) {
1558
-            $wp_options_to_delete['ee_network_config'] = true;
1559
-        }
1560
-        $undeleted_options = [];
1561
-        foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1562
-            if ($no_wildcard) {
1563
-                if (! delete_option($option_name)) {
1564
-                    $undeleted_options[] = $option_name;
1565
-                }
1566
-            } else {
1567
-                $option_names_to_delete_from_wildcard =
1568
-                    $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1569
-                foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1570
-                    if (! delete_option($option_name_from_wildcard)) {
1571
-                        $undeleted_options[] = $option_name_from_wildcard;
1572
-                    }
1573
-                }
1574
-            }
1575
-        }
1576
-        // also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1577
-        remove_action('shutdown', [EE_Config::instance(), 'shutdown']);
1578
-        if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1579
-            $db_update_sans_ee4 = [];
1580
-            foreach ($espresso_db_update as $version => $times_activated) {
1581
-                if ((string) $version[0] === '3') {// if its NON EE4
1582
-                    $db_update_sans_ee4[ $version ] = $times_activated;
1583
-                }
1584
-            }
1585
-            update_option('espresso_db_update', $db_update_sans_ee4);
1586
-        }
1587
-        $errors = '';
1588
-        if (! empty($undeleted_options)) {
1589
-            $errors .= sprintf(
1590
-                esc_html__('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1591
-                '<br/>',
1592
-                implode(',<br/>', $undeleted_options)
1593
-            );
1594
-        }
1595
-        if (! empty($errors)) {
1596
-            EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1597
-        }
1598
-    }
1599
-
1600
-
1601
-    /**
1602
-     * Gets the mysql error code from the last used query by wpdb
1603
-     *
1604
-     * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1605
-     */
1606
-    public static function last_wpdb_error_code(): int
1607
-    {
1608
-        // phpcs:disable PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
1609
-        global $wpdb;
1610
-        return $wpdb->use_mysqli ? mysqli_errno($wpdb->dbh) : 0;
1611
-        // phpcs:enable
1612
-    }
1613
-
1614
-
1615
-    /**
1616
-     * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1617
-     *
1618
-     * @param string $table_name with or without $wpdb->prefix
1619
-     * @return boolean
1620
-     * @throws EE_Error
1621
-     * @throws ReflectionException
1622
-     * @global wpdb  $wpdb
1623
-     * @deprecated instead use TableAnalysis::tableExists()
1624
-     */
1625
-    public static function table_exists(string $table_name): bool
1626
-    {
1627
-        return EEH_Activation::getTableAnalysis()->tableExists($table_name);
1628
-    }
1629
-
1630
-
1631
-    /**
1632
-     * Resets the cache on EEH_Activation
1633
-     */
1634
-    public static function reset()
1635
-    {
1636
-        self::$_default_creator_id                             = null;
1637
-        self::$_initialized_db_content_already_in_this_request = false;
1638
-    }
1639
-
1640
-
1641
-    /**
1642
-     * Removes 'email_confirm' from the Address info question group on activation
1643
-     *
1644
-     * @return void
1645
-     * @throws EE_Error
1646
-     * @throws ReflectionException
1647
-     */
1648
-    public static function removeEmailConfirmFromAddressGroup()
1649
-    {
1650
-        // Pull the email_confirm question ID.
1651
-        $email_confirm_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(
1652
-            EEM_Attendee::system_question_email_confirm
1653
-        );
1654
-        // Remove the email_confirm question group from the address group questions.
1655
-        EEM_Question_Group_Question::instance()->delete(
1656
-            [
1657
-                [
1658
-                    'QST_ID'                    => $email_confirm_question_id,
1659
-                    'Question_Group.QSG_system' => EEM_Question_Group::system_address,
1660
-                ],
1661
-            ]
1662
-        );
1663
-    }
1223
+		$new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1224
+			$message_resource_manager
1225
+		);
1226
+		/**
1227
+		 * This method is verifying there are no NEW default message types
1228
+		 * for ACTIVE messengers that need activated (and corresponding templates setup).
1229
+		 */
1230
+		$new_templates_created_for_message_type =
1231
+			self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1232
+				$message_resource_manager
1233
+			);
1234
+		// after all is done, let's persist these changes to the db.
1235
+		$message_resource_manager->update_has_activated_messengers_option();
1236
+		$message_resource_manager->update_active_messengers_option();
1237
+		// will return true if either of these are true.  Otherwise will return false.
1238
+		return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * @param EE_Message_Resource_Manager $message_resource_manager
1244
+	 * @return array|bool
1245
+	 * @throws EE_Error
1246
+	 * @throws ReflectionException
1247
+	 */
1248
+	protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1249
+		EE_Message_Resource_Manager $message_resource_manager
1250
+	) {
1251
+		$active_messengers       = $message_resource_manager->active_messengers();
1252
+		$installed_message_types = $message_resource_manager->installed_message_types();
1253
+		$templates_created       = false;
1254
+		foreach ($active_messengers as $active_messenger) {
1255
+			$default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1256
+			$default_message_type_names_to_activate   = [];
1257
+			// looping through each default message type reported by the messenger
1258
+			// and setup the actual message types to activate.
1259
+			foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1260
+				// if already active or has already been activated before we skip
1261
+				// (otherwise we might reactivate something user's intentionally deactivated.)
1262
+				// we also skip if the message type is not installed.
1263
+				if (
1264
+					$message_resource_manager->has_message_type_been_activated_for_messenger(
1265
+						$default_message_type_name_for_messenger,
1266
+						$active_messenger->name
1267
+					)
1268
+					|| $message_resource_manager->is_message_type_active_for_messenger(
1269
+						$active_messenger->name,
1270
+						$default_message_type_name_for_messenger
1271
+					)
1272
+					|| ! isset($installed_message_types[ $default_message_type_name_for_messenger ])
1273
+				) {
1274
+					continue;
1275
+				}
1276
+				$default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1277
+			}
1278
+			// let's activate!
1279
+			$message_resource_manager->ensure_message_types_are_active(
1280
+				$default_message_type_names_to_activate,
1281
+				$active_messenger->name,
1282
+				false
1283
+			);
1284
+			// activate the templates for these message types
1285
+			if (! empty($default_message_type_names_to_activate)) {
1286
+				$templates_created = EEH_MSG_Template::generate_new_templates(
1287
+					$active_messenger->name,
1288
+					$default_message_type_names_for_messenger,
1289
+					'',
1290
+					true
1291
+				);
1292
+			}
1293
+		}
1294
+		return $templates_created;
1295
+	}
1296
+
1297
+
1298
+	/**
1299
+	 * This will activate and generate default messengers and default message types for those messengers.
1300
+	 *
1301
+	 * @param EE_message_Resource_Manager $message_resource_manager
1302
+	 * @return array|bool  True means there were default messengers and message type templates generated.
1303
+	 *                     False means that there were no templates generated
1304
+	 *                     (which could simply mean there are no default message types for a messenger).
1305
+	 * @throws EE_Error
1306
+	 * @throws ReflectionException
1307
+	 */
1308
+	protected static function _activate_and_generate_default_messengers_and_message_templates(
1309
+		EE_Message_Resource_Manager $message_resource_manager
1310
+	) {
1311
+		$messengers_to_generate  = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1312
+		$installed_message_types = $message_resource_manager->installed_message_types();
1313
+		$templates_generated     = false;
1314
+		foreach ($messengers_to_generate as $messenger_to_generate) {
1315
+			$default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1316
+			// verify the default message types match an installed message type.
1317
+			foreach ($default_message_type_names_for_messenger as $key => $name) {
1318
+				if (
1319
+					! isset($installed_message_types[ $name ])
1320
+					|| $message_resource_manager->has_message_type_been_activated_for_messenger(
1321
+						$name,
1322
+						$messenger_to_generate->name
1323
+					)
1324
+				) {
1325
+					unset($default_message_type_names_for_messenger[ $key ]);
1326
+				}
1327
+			}
1328
+			// in previous iterations, the active_messengers option in the db
1329
+			// needed updated before calling create templates. however with the changes this may not be necessary.
1330
+			// This comment is left here just in case we discover that we _do_ need to update before
1331
+			// passing off to create templates (after the refactor is done).
1332
+			// @todo remove this comment when determined not necessary.
1333
+			$message_resource_manager->activate_messenger(
1334
+				$messenger_to_generate,
1335
+				$default_message_type_names_for_messenger,
1336
+				false
1337
+			);
1338
+			// create any templates needing created (or will reactivate templates already generated as necessary).
1339
+			if (! empty($default_message_type_names_for_messenger)) {
1340
+				$templates_generated = EEH_MSG_Template::generate_new_templates(
1341
+					$messenger_to_generate->name,
1342
+					$default_message_type_names_for_messenger,
1343
+					'',
1344
+					true
1345
+				);
1346
+			}
1347
+		}
1348
+		return $templates_generated;
1349
+	}
1350
+
1351
+
1352
+	/**
1353
+	 * This returns the default messengers to generate templates for on activation of EE.
1354
+	 * It considers:
1355
+	 * - whether a messenger is already active in the db.
1356
+	 * - whether a messenger has been made active at any time in the past.
1357
+	 *
1358
+	 * @param EE_Message_Resource_Manager $message_resource_manager
1359
+	 * @return EE_messenger[]
1360
+	 */
1361
+	protected static function _get_default_messengers_to_generate_on_activation(
1362
+		EE_Message_Resource_Manager $message_resource_manager
1363
+	): array {
1364
+		$active_messengers    = $message_resource_manager->active_messengers();
1365
+		$installed_messengers = $message_resource_manager->installed_messengers();
1366
+		$has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1367
+
1368
+		$messengers_to_generate = [];
1369
+		foreach ($installed_messengers as $installed_messenger) {
1370
+			// if installed messenger is a messenger that should be activated on install
1371
+			// and is not already active
1372
+			// and has never been activated
1373
+			if (
1374
+				! $installed_messenger->activate_on_install
1375
+				|| isset($active_messengers[ $installed_messenger->name ])
1376
+				|| isset($has_activated[ $installed_messenger->name ])
1377
+			) {
1378
+				continue;
1379
+			}
1380
+			$messengers_to_generate[ $installed_messenger->name ] = $installed_messenger;
1381
+		}
1382
+		return $messengers_to_generate;
1383
+	}
1384
+
1385
+
1386
+	/**
1387
+	 * This simply validates active message types to ensure they actually match installed
1388
+	 * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1389
+	 * rows are set inactive.
1390
+	 * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1391
+	 * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1392
+	 * are still handled in here.
1393
+	 *
1394
+	 * @return void
1395
+	 * @throws EE_Error
1396
+	 * @throws ReflectionException
1397
+	 * @since 4.3.1
1398
+	 */
1399
+	public static function validate_messages_system()
1400
+	{
1401
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
1402
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1403
+		$message_resource_manager->validate_active_message_types_are_installed();
1404
+		do_action('AHEE__EEH_Activation__validate_messages_system');
1405
+	}
1406
+
1407
+
1408
+	/**
1409
+	 * @return void
1410
+	 */
1411
+	public static function plugin_deactivation()
1412
+	{
1413
+	}
1414
+
1415
+
1416
+	/**
1417
+	 * Finds all our EE4 custom post types, and deletes them and their associated data
1418
+	 * (like post meta or term relations)
1419
+	 *
1420
+	 * @throws EE_Error
1421
+	 * @global wpdb $wpdb
1422
+	 */
1423
+	public static function delete_all_espresso_cpt_data()
1424
+	{
1425
+		global $wpdb;
1426
+		// get all the CPT post_types
1427
+		$ee_post_types = [];
1428
+		foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1429
+			if (method_exists($model_name, 'instance')) {
1430
+				$model_obj = call_user_func([$model_name, 'instance']);
1431
+				if ($model_obj instanceof EEM_CPT_Base) {
1432
+					$ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1433
+				}
1434
+			}
1435
+		}
1436
+		// get all our CPTs
1437
+		$query   = "SELECT ID FROM $wpdb->posts WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1438
+		$cpt_ids = $wpdb->get_col($query);
1439
+		// delete each post meta and term relations too
1440
+		foreach ($cpt_ids as $post_id) {
1441
+			wp_delete_post($post_id, true);
1442
+		}
1443
+	}
1444
+
1445
+
1446
+	/**
1447
+	 * Deletes all EE custom tables
1448
+	 *
1449
+	 * @return array
1450
+	 * @throws EE_Error
1451
+	 * @throws ReflectionException
1452
+	 */
1453
+	public static function drop_espresso_tables(): array
1454
+	{
1455
+		$tables = [];
1456
+		// load registry
1457
+		foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1458
+			if (method_exists($model_name, 'instance')) {
1459
+				$model_obj = call_user_func([$model_name, 'instance']);
1460
+				if ($model_obj instanceof EEM_Base) {
1461
+					foreach ($model_obj->get_tables() as $table) {
1462
+						if (
1463
+							strpos($table->get_table_name(), 'esp_')
1464
+							&& (
1465
+								is_main_site()// main site? nuke them all
1466
+								|| ! $table->is_global()// not main site,but not global either. nuke it
1467
+							)
1468
+						) {
1469
+							$tables[ $table->get_table_name() ] = $table->get_table_name();
1470
+						}
1471
+					}
1472
+				}
1473
+			}
1474
+		}
1475
+
1476
+		// there are some tables whose models were removed.
1477
+		// they should be removed when removing all EE core's data
1478
+		$tables_without_models = [
1479
+			'esp_promotion',
1480
+			'esp_promotion_applied',
1481
+			'esp_promotion_object',
1482
+			'esp_promotion_rule',
1483
+			'esp_rule',
1484
+		];
1485
+		foreach ($tables_without_models as $table) {
1486
+			$tables[ $table ] = $table;
1487
+		}
1488
+		return EEH_Activation::getTableManager()->dropTables($tables);
1489
+	}
1490
+
1491
+
1492
+	/**
1493
+	 * Drops all the tables mentioned in a single MYSQL query. Double-checks
1494
+	 * each table name provided has a wpdb prefix attached, and that it exists.
1495
+	 * Returns the list actually deleted
1496
+	 *
1497
+	 * @param array $table_names
1498
+	 * @return array of table names which we deleted
1499
+	 * @throws EE_Error
1500
+	 * @throws ReflectionException
1501
+	 * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1502
+	 * @global WPDB $wpdb
1503
+	 */
1504
+	public static function drop_tables(array $table_names): array
1505
+	{
1506
+		return EEH_Activation::getTableManager()->dropTables($table_names);
1507
+	}
1508
+
1509
+
1510
+	/**
1511
+	 * plugin_uninstall
1512
+	 *
1513
+	 * @param bool $remove_all
1514
+	 * @return void
1515
+	 * @throws EE_Error
1516
+	 * @throws ReflectionException
1517
+	 */
1518
+	public static function delete_all_espresso_tables_and_data(bool $remove_all = true)
1519
+	{
1520
+		global $wpdb;
1521
+		self::drop_espresso_tables();
1522
+		$wp_options_to_delete = [
1523
+			'ee_no_ticket_prices'                        => true,
1524
+			'ee_active_messengers'                       => true,
1525
+			'ee_has_activated_messenger'                 => true,
1526
+			RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES => true,
1527
+			'ee_config'                                  => false,
1528
+			'ee_data_migration_current_db_state'         => true,
1529
+			'ee_data_migration_mapping_'                 => false,
1530
+			'ee_data_migration_script_'                  => false,
1531
+			'ee_data_migrations'                         => true,
1532
+			'ee_dms_map'                                 => false,
1533
+			'ee_notices'                                 => true,
1534
+			'lang_file_check_'                           => false,
1535
+			'ee_maintenance_mode'                        => true,
1536
+			'ee_ueip_optin'                              => true,
1537
+			'ee_ueip_has_notified'                       => true,
1538
+			'ee_plugin_activation_errors'                => true,
1539
+			'ee_id_mapping_from'                         => false,
1540
+			'espresso_persistent_admin_notices'          => true,
1541
+			'ee_encryption_key'                          => true,
1542
+			'pue_force_upgrade_'                         => false,
1543
+			'pue_json_error_'                            => false,
1544
+			'pue_install_key_'                           => false,
1545
+			'pue_verification_error_'                    => false,
1546
+			'pu_dismissed_upgrade_'                      => false,
1547
+			'external_updates-'                          => false,
1548
+			'ee_extra_data'                              => true,
1549
+			'ee_ssn_'                                    => false,
1550
+			'ee_rss_'                                    => false,
1551
+			'ee_rte_n_tx_'                               => false,
1552
+			'ee_pers_admin_notices'                      => true,
1553
+			'ee_job_parameters_'                         => false,
1554
+			'ee_upload_directories_incomplete'           => true,
1555
+			'ee_verified_db_collations'                  => true,
1556
+		];
1557
+		if (is_main_site()) {
1558
+			$wp_options_to_delete['ee_network_config'] = true;
1559
+		}
1560
+		$undeleted_options = [];
1561
+		foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1562
+			if ($no_wildcard) {
1563
+				if (! delete_option($option_name)) {
1564
+					$undeleted_options[] = $option_name;
1565
+				}
1566
+			} else {
1567
+				$option_names_to_delete_from_wildcard =
1568
+					$wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1569
+				foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1570
+					if (! delete_option($option_name_from_wildcard)) {
1571
+						$undeleted_options[] = $option_name_from_wildcard;
1572
+					}
1573
+				}
1574
+			}
1575
+		}
1576
+		// also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1577
+		remove_action('shutdown', [EE_Config::instance(), 'shutdown']);
1578
+		if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1579
+			$db_update_sans_ee4 = [];
1580
+			foreach ($espresso_db_update as $version => $times_activated) {
1581
+				if ((string) $version[0] === '3') {// if its NON EE4
1582
+					$db_update_sans_ee4[ $version ] = $times_activated;
1583
+				}
1584
+			}
1585
+			update_option('espresso_db_update', $db_update_sans_ee4);
1586
+		}
1587
+		$errors = '';
1588
+		if (! empty($undeleted_options)) {
1589
+			$errors .= sprintf(
1590
+				esc_html__('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1591
+				'<br/>',
1592
+				implode(',<br/>', $undeleted_options)
1593
+			);
1594
+		}
1595
+		if (! empty($errors)) {
1596
+			EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1597
+		}
1598
+	}
1599
+
1600
+
1601
+	/**
1602
+	 * Gets the mysql error code from the last used query by wpdb
1603
+	 *
1604
+	 * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1605
+	 */
1606
+	public static function last_wpdb_error_code(): int
1607
+	{
1608
+		// phpcs:disable PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
1609
+		global $wpdb;
1610
+		return $wpdb->use_mysqli ? mysqli_errno($wpdb->dbh) : 0;
1611
+		// phpcs:enable
1612
+	}
1613
+
1614
+
1615
+	/**
1616
+	 * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1617
+	 *
1618
+	 * @param string $table_name with or without $wpdb->prefix
1619
+	 * @return boolean
1620
+	 * @throws EE_Error
1621
+	 * @throws ReflectionException
1622
+	 * @global wpdb  $wpdb
1623
+	 * @deprecated instead use TableAnalysis::tableExists()
1624
+	 */
1625
+	public static function table_exists(string $table_name): bool
1626
+	{
1627
+		return EEH_Activation::getTableAnalysis()->tableExists($table_name);
1628
+	}
1629
+
1630
+
1631
+	/**
1632
+	 * Resets the cache on EEH_Activation
1633
+	 */
1634
+	public static function reset()
1635
+	{
1636
+		self::$_default_creator_id                             = null;
1637
+		self::$_initialized_db_content_already_in_this_request = false;
1638
+	}
1639
+
1640
+
1641
+	/**
1642
+	 * Removes 'email_confirm' from the Address info question group on activation
1643
+	 *
1644
+	 * @return void
1645
+	 * @throws EE_Error
1646
+	 * @throws ReflectionException
1647
+	 */
1648
+	public static function removeEmailConfirmFromAddressGroup()
1649
+	{
1650
+		// Pull the email_confirm question ID.
1651
+		$email_confirm_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(
1652
+			EEM_Attendee::system_question_email_confirm
1653
+		);
1654
+		// Remove the email_confirm question group from the address group questions.
1655
+		EEM_Question_Group_Question::instance()->delete(
1656
+			[
1657
+				[
1658
+					'QST_ID'                    => $email_confirm_question_id,
1659
+					'Question_Group.QSG_system' => EEM_Question_Group::system_address,
1660
+				],
1661
+			]
1662
+		);
1663
+	}
1664 1664
 }
Please login to merge, or discard this patch.
Spacing   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@  discard block
 block discarded – undo
52 52
      */
53 53
     public static function getTableAnalysis(): ?TableAnalysis
54 54
     {
55
-        if (! self::$table_analysis instanceof TableAnalysis) {
55
+        if ( ! self::$table_analysis instanceof TableAnalysis) {
56 56
             self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', [], true);
57 57
         }
58 58
         return self::$table_analysis;
@@ -66,7 +66,7 @@  discard block
 block discarded – undo
66 66
      */
67 67
     public static function getTableManager(): ?TableManager
68 68
     {
69
-        if (! self::$table_manager instanceof TableManager) {
69
+        if ( ! self::$table_manager instanceof TableManager) {
70 70
             self::$table_manager = EE_Registry::instance()->create('TableManager', [], true);
71 71
         }
72 72
         return self::$table_manager;
@@ -111,7 +111,7 @@  discard block
 block discarded – undo
111 111
     public static function initialize_db_and_folders(): bool
112 112
     {
113 113
         EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR);
114
-        EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR . 'logs');
114
+        EEH_File::ensure_folder_exists_and_is_writable(EVENT_ESPRESSO_UPLOAD_DIR.'logs');
115 115
         return EEH_Activation::create_database_tables();
116 116
     }
117 117
 
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
         if ($which_to_include === 'old') {
183 183
             $cron_tasks = array_filter(
184 184
                 $cron_tasks,
185
-                function ($value) {
185
+                function($value) {
186 186
                     return $value === EEH_Activation::cron_task_no_longer_in_use;
187 187
                 }
188 188
             );
@@ -211,7 +211,7 @@  discard block
 block discarded – undo
211 211
     public static function create_cron_tasks()
212 212
     {
213 213
         foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
214
-            if (! wp_next_scheduled($hook_name)) {
214
+            if ( ! wp_next_scheduled($hook_name)) {
215 215
                 /**
216 216
                  * This allows client code to define the initial start timestamp for this schedule.
217 217
                  */
@@ -264,15 +264,15 @@  discard block
 block discarded – undo
264 264
             if (is_array($hooks_to_fire_at_time)) {
265 265
                 foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
266 266
                     if (
267
-                        isset($ee_cron_tasks_to_remove[ $hook_name ])
268
-                        && is_array($ee_cron_tasks_to_remove[ $hook_name ])
267
+                        isset($ee_cron_tasks_to_remove[$hook_name])
268
+                        && is_array($ee_cron_tasks_to_remove[$hook_name])
269 269
                     ) {
270
-                        unset($crons[ $timestamp ][ $hook_name ]);
270
+                        unset($crons[$timestamp][$hook_name]);
271 271
                     }
272 272
                 }
273 273
                 // also take care of any empty cron timestamps.
274 274
                 if (empty($hooks_to_fire_at_time)) {
275
-                    unset($crons[ $timestamp ]);
275
+                    unset($crons[$timestamp]);
276 276
                 }
277 277
             }
278 278
         }
@@ -311,7 +311,7 @@  discard block
 block discarded – undo
311 311
             10,
312 312
             3
313 313
         );
314
-        if (! EE_Config::logging_enabled()) {
314
+        if ( ! EE_Config::logging_enabled()) {
315 315
             delete_option(EE_Config::LOG_NAME);
316 316
         }
317 317
     }
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
     public static function load_calendar_config()
324 324
     {
325 325
         // grab array of all plugin folders and loop thru it
326
-        $plugins = glob(WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR);
326
+        $plugins = glob(WP_PLUGIN_DIR.'/*', GLOB_ONLYDIR);
327 327
         if (empty($plugins)) {
328 328
             return;
329 329
         }
@@ -340,7 +340,7 @@  discard block
 block discarded – undo
340 340
                 || strpos($plugin, 'calendar') !== false
341 341
             ) {
342 342
                 // this is what we are looking for
343
-                $calendar_config = $plugin_path . '/EE_Calendar_Config.php';
343
+                $calendar_config = $plugin_path.'/EE_Calendar_Config.php';
344 344
                 // does it exist in this folder ?
345 345
                 if (is_readable($calendar_config)) {
346 346
                     // YEAH! let's load it
@@ -423,7 +423,7 @@  discard block
 block discarded – undo
423 423
                 'code' => 'ESPRESSO_CANCELLED',
424 424
             ],
425 425
         ];
426
-        $EE_Core_Config        = EE_Registry::instance()->CFG->core;
426
+        $EE_Core_Config = EE_Registry::instance()->CFG->core;
427 427
         foreach ($critical_pages as $critical_page) {
428 428
             // is critical page ID set in config ?
429 429
             if ($EE_Core_Config->{$critical_page['id']} !== false) {
@@ -455,7 +455,7 @@  discard block
 block discarded – undo
455 455
             ) {
456 456
                 // update Config with post ID
457 457
                 $EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
458
-                if (! EE_Config::instance()->update_espresso_config(false, false)) {
458
+                if ( ! EE_Config::instance()->update_espresso_config(false, false)) {
459 459
                     $msg = esc_html__(
460 460
                         'The Event Espresso critical page configuration settings could not be updated.',
461 461
                         'event_espresso'
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
                         'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
479 479
                         'event_espresso'
480 480
                     ),
481
-                    '<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
481
+                    '<a href="'.admin_url('admin.php?page=espresso_general_settings&action=critical_pages').'">'
482 482
                     . esc_html__('Event Espresso Critical Pages Settings', 'event_espresso')
483 483
                     . '</a>'
484 484
                 )
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
     public static function get_page_by_ee_shortcode(string $ee_shortcode)
504 504
     {
505 505
         global $wpdb;
506
-        $shortcode_and_opening_bracket = '[' . $ee_shortcode;
506
+        $shortcode_and_opening_bracket = '['.$ee_shortcode;
507 507
         $post_id                       =
508 508
             $wpdb->get_var(
509 509
                 "SELECT ID FROM $wpdb->posts WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1"
@@ -528,11 +528,11 @@  discard block
 block discarded – undo
528 528
             'post_status'    => 'publish',
529 529
             'post_type'      => 'page',
530 530
             'comment_status' => 'closed',
531
-            'post_content'   => '[' . $critical_page['code'] . ']',
531
+            'post_content'   => '['.$critical_page['code'].']',
532 532
         ];
533 533
 
534 534
         $post_id = wp_insert_post($post_args);
535
-        if (! $post_id) {
535
+        if ( ! $post_id) {
536 536
             $msg = sprintf(
537 537
                 esc_html__('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
538 538
                 $critical_page['name']
@@ -541,7 +541,7 @@  discard block
 block discarded – undo
541 541
             return $critical_page;
542 542
         }
543 543
         // get newly created post's details
544
-        if (! $critical_page['post'] = get_post($post_id)) {
544
+        if ( ! $critical_page['post'] = get_post($post_id)) {
545 545
             $msg = sprintf(
546 546
                 esc_html__('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
547 547
                 $critical_page['name']
@@ -588,7 +588,7 @@  discard block
 block discarded – undo
588 588
   AND meta_value LIKE %s 
589 589
 ORDER BY user_id
590 590
 LIMIT 0,1",
591
-            '%' . $role_to_check . '%'
591
+            '%'.$role_to_check.'%'
592 592
         );
593 593
         $user_id          = $wpdb->get_var($query);
594 594
         $user_id          = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
@@ -628,8 +628,8 @@  discard block
 block discarded – undo
628 628
             return;
629 629
         }
630 630
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
631
-        if (! function_exists('dbDelta')) {
632
-            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
631
+        if ( ! function_exists('dbDelta')) {
632
+            require_once(ABSPATH.'wp-admin/includes/upgrade.php');
633 633
         }
634 634
         $tableAnalysis = EEH_Activation::getTableAnalysis();
635 635
         $wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
@@ -638,9 +638,9 @@  discard block
 block discarded – undo
638 638
             // ok, delete the table... but ONLY if it's empty
639 639
             $deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
640 640
             // table is NOT empty, are you SURE you want to delete this table ???
641
-            if (! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
641
+            if ( ! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
642 642
                 EEH_Activation::getTableManager()->dropTable($wp_table_name);
643
-            } elseif (! $deleted_safely) {
643
+            } elseif ( ! $deleted_safely) {
644 644
                 // so we should be more cautious rather than just dropping tables so easily
645 645
                 error_log(
646 646
                     sprintf(
@@ -761,7 +761,7 @@  discard block
 block discarded – undo
761 761
         EE_Registry::instance()->load_core('Data_Migration_Manager');
762 762
         // find the migration script that sets the database to be compatible with the code
763 763
         $dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
764
-        if (! $dms_name) {
764
+        if ( ! $dms_name) {
765 765
             EE_Error::add_error(
766 766
                 esc_html__(
767 767
                     'Could not determine most up-to-date data migration script from which to pull database schema
@@ -824,13 +824,13 @@  discard block
 block discarded – undo
824 824
             // reset values array
825 825
             $QSG_values = [];
826 826
             // if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
827
-            if (! in_array("$QSG_system", $question_groups)) {
827
+            if ( ! in_array("$QSG_system", $question_groups)) {
828 828
                 // add it
829 829
                 switch ($QSG_system) {
830 830
                     case 1:
831 831
                         $QSG_values = [
832 832
                             'QSG_name'            => esc_html__('Personal Information', 'event_espresso'),
833
-                            'QSG_identifier'      => 'personal-information-' . time(),
833
+                            'QSG_identifier'      => 'personal-information-'.time(),
834 834
                             'QSG_desc'            => '',
835 835
                             'QSG_order'           => 1,
836 836
                             'QSG_show_group_name' => 1,
@@ -842,7 +842,7 @@  discard block
 block discarded – undo
842 842
                     case 2:
843 843
                         $QSG_values = [
844 844
                             'QSG_name'            => esc_html__('Address Information', 'event_espresso'),
845
-                            'QSG_identifier'      => 'address-information-' . time(),
845
+                            'QSG_identifier'      => 'address-information-'.time(),
846 846
                             'QSG_desc'            => '',
847 847
                             'QSG_order'           => 2,
848 848
                             'QSG_show_group_name' => 1,
@@ -853,14 +853,14 @@  discard block
 block discarded – undo
853 853
                         break;
854 854
                 }
855 855
                 // make sure we have some values before inserting them
856
-                if (! empty($QSG_values)) {
856
+                if ( ! empty($QSG_values)) {
857 857
                     // insert system question
858 858
                     $wpdb->insert(
859 859
                         $table_name,
860 860
                         $QSG_values,
861 861
                         ['%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d']
862 862
                     );
863
-                    $QSG_IDs[ $QSG_system ] = $wpdb->insert_id;
863
+                    $QSG_IDs[$QSG_system] = $wpdb->insert_id;
864 864
                 }
865 865
             }
866 866
         }
@@ -875,7 +875,7 @@  discard block
 block discarded – undo
875 875
         $address_system_group_questions  = ['address', 'address2', 'city', 'country', 'state', 'zip', 'phone'];
876 876
         $system_questions_not_in_group   = ['email_confirm'];
877 877
         // merge all of the system questions we should have
878
-        $QST_systems       = array_merge(
878
+        $QST_systems = array_merge(
879 879
             $personal_system_group_questions,
880 880
             $address_system_group_questions,
881 881
             $system_questions_not_in_group
@@ -887,7 +887,7 @@  discard block
 block discarded – undo
887 887
             // reset values array
888 888
             $QST_values = [];
889 889
             // if we don't have what we should have
890
-            if (! in_array($QST_system, $questions)) {
890
+            if ( ! in_array($QST_system, $questions)) {
891 891
                 // add it
892 892
                 switch ($QST_system) {
893 893
                     case 'fname':
@@ -1066,7 +1066,7 @@  discard block
 block discarded – undo
1066 1066
                         ];
1067 1067
                         break;
1068 1068
                 }
1069
-                if (! empty($QST_values)) {
1069
+                if ( ! empty($QST_values)) {
1070 1070
                     // insert system question
1071 1071
                     $wpdb->insert(
1072 1072
                         $table_name,
@@ -1084,8 +1084,8 @@  discard block
 block discarded – undo
1084 1084
                         // QST_system should not be assigned to any group
1085 1085
                         continue;
1086 1086
                     }
1087
-                    if (isset($QSG_IDs[ $system_question_we_want ])) {
1088
-                        $QSG_ID = $QSG_IDs[ $system_question_we_want ];
1087
+                    if (isset($QSG_IDs[$system_question_we_want])) {
1088
+                        $QSG_ID = $QSG_IDs[$system_question_we_want];
1089 1089
                     } else {
1090 1090
                         $id_col = EEM_Question_Group::instance()
1091 1091
                                                     ->get_col([['QSG_system' => $system_question_we_want]]);
@@ -1134,7 +1134,7 @@  discard block
 block discarded – undo
1134 1134
      */
1135 1135
     public static function insert_default_payment_methods()
1136 1136
     {
1137
-        if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1137
+        if ( ! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1138 1138
             EE_Registry::instance()->load_lib('Payment_Method_Manager');
1139 1139
             EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1140 1140
         } else {
@@ -1269,7 +1269,7 @@  discard block
 block discarded – undo
1269 1269
                         $active_messenger->name,
1270 1270
                         $default_message_type_name_for_messenger
1271 1271
                     )
1272
-                    || ! isset($installed_message_types[ $default_message_type_name_for_messenger ])
1272
+                    || ! isset($installed_message_types[$default_message_type_name_for_messenger])
1273 1273
                 ) {
1274 1274
                     continue;
1275 1275
                 }
@@ -1282,7 +1282,7 @@  discard block
 block discarded – undo
1282 1282
                 false
1283 1283
             );
1284 1284
             // activate the templates for these message types
1285
-            if (! empty($default_message_type_names_to_activate)) {
1285
+            if ( ! empty($default_message_type_names_to_activate)) {
1286 1286
                 $templates_created = EEH_MSG_Template::generate_new_templates(
1287 1287
                     $active_messenger->name,
1288 1288
                     $default_message_type_names_for_messenger,
@@ -1316,13 +1316,13 @@  discard block
 block discarded – undo
1316 1316
             // verify the default message types match an installed message type.
1317 1317
             foreach ($default_message_type_names_for_messenger as $key => $name) {
1318 1318
                 if (
1319
-                    ! isset($installed_message_types[ $name ])
1319
+                    ! isset($installed_message_types[$name])
1320 1320
                     || $message_resource_manager->has_message_type_been_activated_for_messenger(
1321 1321
                         $name,
1322 1322
                         $messenger_to_generate->name
1323 1323
                     )
1324 1324
                 ) {
1325
-                    unset($default_message_type_names_for_messenger[ $key ]);
1325
+                    unset($default_message_type_names_for_messenger[$key]);
1326 1326
                 }
1327 1327
             }
1328 1328
             // in previous iterations, the active_messengers option in the db
@@ -1336,7 +1336,7 @@  discard block
 block discarded – undo
1336 1336
                 false
1337 1337
             );
1338 1338
             // create any templates needing created (or will reactivate templates already generated as necessary).
1339
-            if (! empty($default_message_type_names_for_messenger)) {
1339
+            if ( ! empty($default_message_type_names_for_messenger)) {
1340 1340
                 $templates_generated = EEH_MSG_Template::generate_new_templates(
1341 1341
                     $messenger_to_generate->name,
1342 1342
                     $default_message_type_names_for_messenger,
@@ -1372,12 +1372,12 @@  discard block
 block discarded – undo
1372 1372
             // and has never been activated
1373 1373
             if (
1374 1374
                 ! $installed_messenger->activate_on_install
1375
-                || isset($active_messengers[ $installed_messenger->name ])
1376
-                || isset($has_activated[ $installed_messenger->name ])
1375
+                || isset($active_messengers[$installed_messenger->name])
1376
+                || isset($has_activated[$installed_messenger->name])
1377 1377
             ) {
1378 1378
                 continue;
1379 1379
             }
1380
-            $messengers_to_generate[ $installed_messenger->name ] = $installed_messenger;
1380
+            $messengers_to_generate[$installed_messenger->name] = $installed_messenger;
1381 1381
         }
1382 1382
         return $messengers_to_generate;
1383 1383
     }
@@ -1434,7 +1434,7 @@  discard block
 block discarded – undo
1434 1434
             }
1435 1435
         }
1436 1436
         // get all our CPTs
1437
-        $query   = "SELECT ID FROM $wpdb->posts WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1437
+        $query   = "SELECT ID FROM $wpdb->posts WHERE post_type IN (".implode(",", $ee_post_types).")";
1438 1438
         $cpt_ids = $wpdb->get_col($query);
1439 1439
         // delete each post meta and term relations too
1440 1440
         foreach ($cpt_ids as $post_id) {
@@ -1466,7 +1466,7 @@  discard block
 block discarded – undo
1466 1466
                                 || ! $table->is_global()// not main site,but not global either. nuke it
1467 1467
                             )
1468 1468
                         ) {
1469
-                            $tables[ $table->get_table_name() ] = $table->get_table_name();
1469
+                            $tables[$table->get_table_name()] = $table->get_table_name();
1470 1470
                         }
1471 1471
                     }
1472 1472
                 }
@@ -1483,7 +1483,7 @@  discard block
 block discarded – undo
1483 1483
             'esp_rule',
1484 1484
         ];
1485 1485
         foreach ($tables_without_models as $table) {
1486
-            $tables[ $table ] = $table;
1486
+            $tables[$table] = $table;
1487 1487
         }
1488 1488
         return EEH_Activation::getTableManager()->dropTables($tables);
1489 1489
     }
@@ -1560,14 +1560,14 @@  discard block
 block discarded – undo
1560 1560
         $undeleted_options = [];
1561 1561
         foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1562 1562
             if ($no_wildcard) {
1563
-                if (! delete_option($option_name)) {
1563
+                if ( ! delete_option($option_name)) {
1564 1564
                     $undeleted_options[] = $option_name;
1565 1565
                 }
1566 1566
             } else {
1567 1567
                 $option_names_to_delete_from_wildcard =
1568 1568
                     $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1569 1569
                 foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1570
-                    if (! delete_option($option_name_from_wildcard)) {
1570
+                    if ( ! delete_option($option_name_from_wildcard)) {
1571 1571
                         $undeleted_options[] = $option_name_from_wildcard;
1572 1572
                     }
1573 1573
                 }
@@ -1579,20 +1579,20 @@  discard block
 block discarded – undo
1579 1579
             $db_update_sans_ee4 = [];
1580 1580
             foreach ($espresso_db_update as $version => $times_activated) {
1581 1581
                 if ((string) $version[0] === '3') {// if its NON EE4
1582
-                    $db_update_sans_ee4[ $version ] = $times_activated;
1582
+                    $db_update_sans_ee4[$version] = $times_activated;
1583 1583
                 }
1584 1584
             }
1585 1585
             update_option('espresso_db_update', $db_update_sans_ee4);
1586 1586
         }
1587 1587
         $errors = '';
1588
-        if (! empty($undeleted_options)) {
1588
+        if ( ! empty($undeleted_options)) {
1589 1589
             $errors .= sprintf(
1590 1590
                 esc_html__('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1591 1591
                 '<br/>',
1592 1592
                 implode(',<br/>', $undeleted_options)
1593 1593
             );
1594 1594
         }
1595
-        if (! empty($errors)) {
1595
+        if ( ! empty($errors)) {
1596 1596
             EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1597 1597
         }
1598 1598
     }
Please login to merge, or discard this patch.
core/helpers/EEH_URL.helper.php 2 patches
Indentation   +268 added lines, -268 removed lines patch added patch discarded remove patch
@@ -13,300 +13,300 @@
 block discarded – undo
13 13
  */
14 14
 class EEH_URL
15 15
 {
16
-    const CONTEXT_NONE   = 0;
16
+	const CONTEXT_NONE   = 0;
17 17
 
18
-    const CONTEXT_OUTPUT = 1;
18
+	const CONTEXT_OUTPUT = 1;
19 19
 
20
-    const CONTEXT_RAW    = 2;
20
+	const CONTEXT_RAW    = 2;
21 21
 
22 22
 
23
-    /**
24
-     * _add_query_arg
25
-     * adds nonce to array of arguments then calls WP add_query_arg function
26
-     *
27
-     * @param array  $args
28
-     * @param string $url
29
-     * @param bool   $exclude_nonce If true then the nonce will be excluded from the generated url.
30
-     * @param int    $context
31
-     * @return string
32
-     */
33
-    public static function add_query_args_and_nonce(
34
-        array $args = [],
35
-        string $url = '',
36
-        bool $exclude_nonce = false,
37
-        int $context = EEH_URL::CONTEXT_NONE
38
-    ): string {
39
-        // check that an action exists and add nonce
40
-        if (! $exclude_nonce) {
41
-            if (! empty($args['action'])) {
42
-                $args = array_merge(
43
-                    $args,
44
-                    [
45
-                        $args['action'] . '_nonce' => wp_create_nonce($args['action'] . '_nonce'),
46
-                    ]
47
-                );
48
-            } else {
49
-                $args = array_merge(
50
-                    $args,
51
-                    [
52
-                        'action'        => 'default',
53
-                        'default_nonce' => wp_create_nonce('default_nonce'),
54
-                    ]
55
-                );
56
-            }
57
-        }
23
+	/**
24
+	 * _add_query_arg
25
+	 * adds nonce to array of arguments then calls WP add_query_arg function
26
+	 *
27
+	 * @param array  $args
28
+	 * @param string $url
29
+	 * @param bool   $exclude_nonce If true then the nonce will be excluded from the generated url.
30
+	 * @param int    $context
31
+	 * @return string
32
+	 */
33
+	public static function add_query_args_and_nonce(
34
+		array $args = [],
35
+		string $url = '',
36
+		bool $exclude_nonce = false,
37
+		int $context = EEH_URL::CONTEXT_NONE
38
+	): string {
39
+		// check that an action exists and add nonce
40
+		if (! $exclude_nonce) {
41
+			if (! empty($args['action'])) {
42
+				$args = array_merge(
43
+					$args,
44
+					[
45
+						$args['action'] . '_nonce' => wp_create_nonce($args['action'] . '_nonce'),
46
+					]
47
+				);
48
+			} else {
49
+				$args = array_merge(
50
+					$args,
51
+					[
52
+						'action'        => 'default',
53
+						'default_nonce' => wp_create_nonce('default_nonce'),
54
+					]
55
+				);
56
+			}
57
+		}
58 58
 
59
-        $action = EEH_URL::getRequest()->getRequestParam('action', '');
60
-        // finally, let's always add a return address (if present) :)
61
-        if ($action !== '') {
62
-            $args['return'] = $action;
63
-        }
59
+		$action = EEH_URL::getRequest()->getRequestParam('action', '');
60
+		// finally, let's always add a return address (if present) :)
61
+		if ($action !== '') {
62
+			$args['return'] = $action;
63
+		}
64 64
 
65
-        $url = add_query_arg($args, $url);
66
-        if ($context === EEH_URL::CONTEXT_OUTPUT) {
67
-            return esc_url($url);
68
-        }
69
-        if ($context === EEH_URL::CONTEXT_RAW) {
70
-            return esc_url_raw($url);
71
-        }
72
-        return $url;
73
-    }
65
+		$url = add_query_arg($args, $url);
66
+		if ($context === EEH_URL::CONTEXT_OUTPUT) {
67
+			return esc_url($url);
68
+		}
69
+		if ($context === EEH_URL::CONTEXT_RAW) {
70
+			return esc_url_raw($url);
71
+		}
72
+		return $url;
73
+	}
74 74
 
75 75
 
76
-    /**
77
-     * Returns whether not the remote file exists.
78
-     * Checking via GET because HEAD requests are blocked on some server configurations.
79
-     *
80
-     * @param string $url
81
-     * @param array  $args the arguments that should be passed through to the wp_remote_request call.
82
-     * @return boolean
83
-     */
84
-    public static function remote_file_exists(string $url, array $args = []): bool
85
-    {
86
-        $results = wp_remote_request(
87
-            $url,
88
-            array_merge(
89
-                [
90
-                    'method'      => 'GET',
91
-                    'redirection' => 1,
92
-                ],
93
-                $args
94
-            )
95
-        );
96
-        return ! $results instanceof WP_Error
97
-               && isset($results['response']['code'])
98
-               && $results['response']['code'] == '200';
99
-    }
76
+	/**
77
+	 * Returns whether not the remote file exists.
78
+	 * Checking via GET because HEAD requests are blocked on some server configurations.
79
+	 *
80
+	 * @param string $url
81
+	 * @param array  $args the arguments that should be passed through to the wp_remote_request call.
82
+	 * @return boolean
83
+	 */
84
+	public static function remote_file_exists(string $url, array $args = []): bool
85
+	{
86
+		$results = wp_remote_request(
87
+			$url,
88
+			array_merge(
89
+				[
90
+					'method'      => 'GET',
91
+					'redirection' => 1,
92
+				],
93
+				$args
94
+			)
95
+		);
96
+		return ! $results instanceof WP_Error
97
+			   && isset($results['response']['code'])
98
+			   && $results['response']['code'] == '200';
99
+	}
100 100
 
101 101
 
102
-    /**
103
-     * refactor_url
104
-     * primarily used for removing the query string from a URL
105
-     *
106
-     * @param string $url
107
-     * @param bool   $remove_query  - TRUE (default) will strip off any URL params, ie: ?this=1&that=2
108
-     * @param bool   $base_url_only - TRUE will only return the scheme and host with no other parameters
109
-     * @return string
110
-     */
111
-    public static function refactor_url(
112
-        string $url = '',
113
-        bool $remove_query = true,
114
-        bool $base_url_only = false
115
-    ): string {
116
-        // break apart incoming URL
117
-        $url_bits = parse_url($url);
118
-        // HTTP or HTTPS ?
119
-        $scheme = isset($url_bits['scheme']) ? $url_bits['scheme'] . '://' : 'https://';
120
-        // domain
121
-        $host = isset($url_bits['host']) ? $url_bits['host'] : '';
122
-        // if only the base URL is requested, then return that now
123
-        if ($base_url_only) {
124
-            return $scheme . $host;
125
-        }
126
-        $port = isset($url_bits['port']) ? ':' . $url_bits['port'] : '';
127
-        $user = isset($url_bits['user']) ? $url_bits['user'] : '';
128
-        $pass = isset($url_bits['pass']) ? ':' . $url_bits['pass'] : '';
129
-        $pass = ($user || $pass) ? $pass . '@' : '';
130
-        $path = isset($url_bits['path']) ? $url_bits['path'] : '';
131
-        // if the query string is not required, then return what we have so far
132
-        if ($remove_query) {
133
-            return $scheme . $user . $pass . $host . $port . $path;
134
-        }
135
-        $query    = isset($url_bits['query']) ? '?' . $url_bits['query'] : '';
136
-        $fragment = isset($url_bits['fragment']) ? '#' . $url_bits['fragment'] : '';
137
-        return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
138
-    }
102
+	/**
103
+	 * refactor_url
104
+	 * primarily used for removing the query string from a URL
105
+	 *
106
+	 * @param string $url
107
+	 * @param bool   $remove_query  - TRUE (default) will strip off any URL params, ie: ?this=1&that=2
108
+	 * @param bool   $base_url_only - TRUE will only return the scheme and host with no other parameters
109
+	 * @return string
110
+	 */
111
+	public static function refactor_url(
112
+		string $url = '',
113
+		bool $remove_query = true,
114
+		bool $base_url_only = false
115
+	): string {
116
+		// break apart incoming URL
117
+		$url_bits = parse_url($url);
118
+		// HTTP or HTTPS ?
119
+		$scheme = isset($url_bits['scheme']) ? $url_bits['scheme'] . '://' : 'https://';
120
+		// domain
121
+		$host = isset($url_bits['host']) ? $url_bits['host'] : '';
122
+		// if only the base URL is requested, then return that now
123
+		if ($base_url_only) {
124
+			return $scheme . $host;
125
+		}
126
+		$port = isset($url_bits['port']) ? ':' . $url_bits['port'] : '';
127
+		$user = isset($url_bits['user']) ? $url_bits['user'] : '';
128
+		$pass = isset($url_bits['pass']) ? ':' . $url_bits['pass'] : '';
129
+		$pass = ($user || $pass) ? $pass . '@' : '';
130
+		$path = isset($url_bits['path']) ? $url_bits['path'] : '';
131
+		// if the query string is not required, then return what we have so far
132
+		if ($remove_query) {
133
+			return $scheme . $user . $pass . $host . $port . $path;
134
+		}
135
+		$query    = isset($url_bits['query']) ? '?' . $url_bits['query'] : '';
136
+		$fragment = isset($url_bits['fragment']) ? '#' . $url_bits['fragment'] : '';
137
+		return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
138
+	}
139 139
 
140 140
 
141
-    /**
142
-     * get_query_string
143
-     * returns just the query string from a URL, formatted by default into an array of key value pairs
144
-     *
145
-     * @param string $url
146
-     * @param bool   $as_array TRUE (default) will return query params as an array of key value pairs, FALSE will
147
-     *                         simply return the query string
148
-     * @return string|array
149
-     */
150
-    public static function get_query_string(string $url = '', bool $as_array = true)
151
-    {
152
-        // decode, then break apart incoming URL
153
-        $url_bits = parse_url(html_entity_decode($url));
154
-        // grab query string from URL
155
-        $query = isset($url_bits['query']) ? $url_bits['query'] : '';
156
-        // if we don't want the query string formatted into an array of key => value pairs, then just return it as is
157
-        if (! $as_array) {
158
-            return $query;
159
-        }
160
-        // if no query string exists then just return an empty array now
161
-        if (empty($query)) {
162
-            return [];
163
-        }
164
-        // empty array to hold results
165
-        $query_params = [];
166
-        // now break apart the query string into separate params
167
-        $query = explode('&', $query);
168
-        // loop thru our query params
169
-        foreach ($query as $query_args) {
170
-            // break apart the key value pairs
171
-            $query_args = explode('=', $query_args);
172
-            // and add to our results array
173
-            $query_params[ $query_args[0] ] = $query_args[1];
174
-        }
175
-        return $query_params;
176
-    }
141
+	/**
142
+	 * get_query_string
143
+	 * returns just the query string from a URL, formatted by default into an array of key value pairs
144
+	 *
145
+	 * @param string $url
146
+	 * @param bool   $as_array TRUE (default) will return query params as an array of key value pairs, FALSE will
147
+	 *                         simply return the query string
148
+	 * @return string|array
149
+	 */
150
+	public static function get_query_string(string $url = '', bool $as_array = true)
151
+	{
152
+		// decode, then break apart incoming URL
153
+		$url_bits = parse_url(html_entity_decode($url));
154
+		// grab query string from URL
155
+		$query = isset($url_bits['query']) ? $url_bits['query'] : '';
156
+		// if we don't want the query string formatted into an array of key => value pairs, then just return it as is
157
+		if (! $as_array) {
158
+			return $query;
159
+		}
160
+		// if no query string exists then just return an empty array now
161
+		if (empty($query)) {
162
+			return [];
163
+		}
164
+		// empty array to hold results
165
+		$query_params = [];
166
+		// now break apart the query string into separate params
167
+		$query = explode('&', $query);
168
+		// loop thru our query params
169
+		foreach ($query as $query_args) {
170
+			// break apart the key value pairs
171
+			$query_args = explode('=', $query_args);
172
+			// and add to our results array
173
+			$query_params[ $query_args[0] ] = $query_args[1];
174
+		}
175
+		return $query_params;
176
+	}
177 177
 
178 178
 
179
-    /**
180
-     * prevent_prefetching
181
-     *
182
-     * @return void
183
-     */
184
-    public static function prevent_prefetching()
185
-    {
186
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes
187
-        // with the registration process
188
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
189
-    }
179
+	/**
180
+	 * prevent_prefetching
181
+	 *
182
+	 * @return void
183
+	 */
184
+	public static function prevent_prefetching()
185
+	{
186
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes
187
+		// with the registration process
188
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
189
+	}
190 190
 
191 191
 
192
-    /**
193
-     * This generates a unique site-specific string.
194
-     * An example usage for this string would be to save as a unique identifier for a record in the db for usage in
195
-     * urls.
196
-     *
197
-     * @param string $prefix Use this to prefix the string with something.
198
-     * @return string
199
-     */
200
-    public static function generate_unique_token(string $prefix = ''): string
201
-    {
202
-        $token = md5(uniqid() . mt_rand());
203
-        return $prefix ? $prefix . '_' . $token : $token;
204
-    }
192
+	/**
193
+	 * This generates a unique site-specific string.
194
+	 * An example usage for this string would be to save as a unique identifier for a record in the db for usage in
195
+	 * urls.
196
+	 *
197
+	 * @param string $prefix Use this to prefix the string with something.
198
+	 * @return string
199
+	 */
200
+	public static function generate_unique_token(string $prefix = ''): string
201
+	{
202
+		$token = md5(uniqid() . mt_rand());
203
+		return $prefix ? $prefix . '_' . $token : $token;
204
+	}
205 205
 
206 206
 
207
-    /**
208
-     * filter_input_server_url
209
-     * uses filter_input() to sanitize one of the INPUT_SERVER URL values
210
-     * but adds a backup in case filter_input() returns nothing, which can erringly happen on some servers
211
-     *
212
-     * @param string $server_variable
213
-     * @return string
214
-     */
215
-    public static function filter_input_server_url(string $server_variable = 'REQUEST_URI'): string
216
-    {
217
-        $URL              = '';
218
-        $server_variables = [
219
-            'REQUEST_URI' => 1,
220
-            'HTTP_HOST'   => 1,
221
-            'PHP_SELF'    => 1,
222
-        ];
223
-        $server_variable  = strtoupper($server_variable);
224
-        // whitelist INPUT_SERVER var
225
-        if (isset($server_variables[ $server_variable ])) {
226
-            $URL = filter_input(INPUT_SERVER, $server_variable, FILTER_SANITIZE_URL, FILTER_NULL_ON_FAILURE);
227
-            if (empty($URL) || $URL !== $_SERVER[ $server_variable ]) {
228
-                // fallback sanitization if the above fails or URL has changed after filtering
229
-                $URL = wp_sanitize_redirect($_SERVER[ $server_variable ]);
230
-            }
231
-        }
232
-        return $URL;
233
-    }
207
+	/**
208
+	 * filter_input_server_url
209
+	 * uses filter_input() to sanitize one of the INPUT_SERVER URL values
210
+	 * but adds a backup in case filter_input() returns nothing, which can erringly happen on some servers
211
+	 *
212
+	 * @param string $server_variable
213
+	 * @return string
214
+	 */
215
+	public static function filter_input_server_url(string $server_variable = 'REQUEST_URI'): string
216
+	{
217
+		$URL              = '';
218
+		$server_variables = [
219
+			'REQUEST_URI' => 1,
220
+			'HTTP_HOST'   => 1,
221
+			'PHP_SELF'    => 1,
222
+		];
223
+		$server_variable  = strtoupper($server_variable);
224
+		// whitelist INPUT_SERVER var
225
+		if (isset($server_variables[ $server_variable ])) {
226
+			$URL = filter_input(INPUT_SERVER, $server_variable, FILTER_SANITIZE_URL, FILTER_NULL_ON_FAILURE);
227
+			if (empty($URL) || $URL !== $_SERVER[ $server_variable ]) {
228
+				// fallback sanitization if the above fails or URL has changed after filtering
229
+				$URL = wp_sanitize_redirect($_SERVER[ $server_variable ]);
230
+			}
231
+		}
232
+		return $URL;
233
+	}
234 234
 
235 235
 
236
-    /**
237
-     * Gets the current page's full URL.
238
-     *
239
-     * @return string
240
-     */
241
-    public static function current_url(): string
242
-    {
243
-        $url = '';
244
-        if (
245
-            EEH_URL::getRequest()->serverParamIsSet('HTTP_HOST')
246
-            && EEH_URL::getRequest()->serverParamIsSet('REQUEST_URI')
247
-        ) {
248
-            $url = is_ssl() ? 'https://' : 'http://';
249
-            $url .= EEH_URL::filter_input_server_url('HTTP_HOST');
250
-            $url .= EEH_URL::filter_input_server_url();
251
-        }
252
-        return $url;
253
-    }
236
+	/**
237
+	 * Gets the current page's full URL.
238
+	 *
239
+	 * @return string
240
+	 */
241
+	public static function current_url(): string
242
+	{
243
+		$url = '';
244
+		if (
245
+			EEH_URL::getRequest()->serverParamIsSet('HTTP_HOST')
246
+			&& EEH_URL::getRequest()->serverParamIsSet('REQUEST_URI')
247
+		) {
248
+			$url = is_ssl() ? 'https://' : 'http://';
249
+			$url .= EEH_URL::filter_input_server_url('HTTP_HOST');
250
+			$url .= EEH_URL::filter_input_server_url();
251
+		}
252
+		return $url;
253
+	}
254 254
 
255 255
 
256
-    /**
257
-     * Identical in functionality to EEH_current_url except it removes any provided query_parameters from it.
258
-     *
259
-     * @param array $query_parameters An array of query_parameters to remove from the current url.
260
-     * @return string
261
-     * @since 4.9.46.rc.029
262
-     */
263
-    public static function current_url_without_query_paramaters(array $query_parameters): string
264
-    {
265
-        return remove_query_arg($query_parameters, EEH_URL::current_url());
266
-    }
256
+	/**
257
+	 * Identical in functionality to EEH_current_url except it removes any provided query_parameters from it.
258
+	 *
259
+	 * @param array $query_parameters An array of query_parameters to remove from the current url.
260
+	 * @return string
261
+	 * @since 4.9.46.rc.029
262
+	 */
263
+	public static function current_url_without_query_paramaters(array $query_parameters): string
264
+	{
265
+		return remove_query_arg($query_parameters, EEH_URL::current_url());
266
+	}
267 267
 
268 268
 
269
-    /**
270
-     * @param string $location
271
-     * @param int    $status
272
-     * @param string $exit_notice
273
-     */
274
-    public static function safeRedirectAndExit(string $location, int $status = 302, string $exit_notice = '')
275
-    {
276
-        EE_Error::get_notices(false, true);
277
-        wp_safe_redirect($location, $status);
278
-        exit($exit_notice);
279
-    }
269
+	/**
270
+	 * @param string $location
271
+	 * @param int    $status
272
+	 * @param string $exit_notice
273
+	 */
274
+	public static function safeRedirectAndExit(string $location, int $status = 302, string $exit_notice = '')
275
+	{
276
+		EE_Error::get_notices(false, true);
277
+		wp_safe_redirect($location, $status);
278
+		exit($exit_notice);
279
+	}
280 280
 
281 281
 
282
-    /**
283
-     * Slugifies text for usage in a URL.
284
-     * Currently, this isn't just calling `sanitize_title()` on it, because that percent-encodes unicode characters,
285
-     * and WordPress chokes on them when used as CPT and custom taxonomy slugs.
286
-     *
287
-     * @param string $text
288
-     * @param string $fallback
289
-     * @return string which can be used in a URL
290
-     * @since 4.9.66.p
291
-     */
292
-    public static function slugify(string $text, string $fallback): string
293
-    {
294
-        // url decode after sanitizing title to restore unicode characters,
295
-        // see https://github.com/eventespresso/event-espresso-core/issues/575
296
-        return urldecode(sanitize_title($text, $fallback));
297
-    }
282
+	/**
283
+	 * Slugifies text for usage in a URL.
284
+	 * Currently, this isn't just calling `sanitize_title()` on it, because that percent-encodes unicode characters,
285
+	 * and WordPress chokes on them when used as CPT and custom taxonomy slugs.
286
+	 *
287
+	 * @param string $text
288
+	 * @param string $fallback
289
+	 * @return string which can be used in a URL
290
+	 * @since 4.9.66.p
291
+	 */
292
+	public static function slugify(string $text, string $fallback): string
293
+	{
294
+		// url decode after sanitizing title to restore unicode characters,
295
+		// see https://github.com/eventespresso/event-espresso-core/issues/575
296
+		return urldecode(sanitize_title($text, $fallback));
297
+	}
298 298
 
299 299
 
300
-    /**
301
-     * @return RequestInterface
302
-     * @since   4.10.14.p
303
-     */
304
-    protected static function getRequest()
305
-    {
306
-        static $request;
307
-        if (! $request instanceof RequestInterface) {
308
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
309
-        }
310
-        return $request;
311
-    }
300
+	/**
301
+	 * @return RequestInterface
302
+	 * @since   4.10.14.p
303
+	 */
304
+	protected static function getRequest()
305
+	{
306
+		static $request;
307
+		if (! $request instanceof RequestInterface) {
308
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
309
+		}
310
+		return $request;
311
+	}
312 312
 }
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -37,12 +37,12 @@  discard block
 block discarded – undo
37 37
         int $context = EEH_URL::CONTEXT_NONE
38 38
     ): string {
39 39
         // check that an action exists and add nonce
40
-        if (! $exclude_nonce) {
41
-            if (! empty($args['action'])) {
40
+        if ( ! $exclude_nonce) {
41
+            if ( ! empty($args['action'])) {
42 42
                 $args = array_merge(
43 43
                     $args,
44 44
                     [
45
-                        $args['action'] . '_nonce' => wp_create_nonce($args['action'] . '_nonce'),
45
+                        $args['action'].'_nonce' => wp_create_nonce($args['action'].'_nonce'),
46 46
                     ]
47 47
                 );
48 48
             } else {
@@ -116,25 +116,25 @@  discard block
 block discarded – undo
116 116
         // break apart incoming URL
117 117
         $url_bits = parse_url($url);
118 118
         // HTTP or HTTPS ?
119
-        $scheme = isset($url_bits['scheme']) ? $url_bits['scheme'] . '://' : 'https://';
119
+        $scheme = isset($url_bits['scheme']) ? $url_bits['scheme'].'://' : 'https://';
120 120
         // domain
121 121
         $host = isset($url_bits['host']) ? $url_bits['host'] : '';
122 122
         // if only the base URL is requested, then return that now
123 123
         if ($base_url_only) {
124
-            return $scheme . $host;
124
+            return $scheme.$host;
125 125
         }
126
-        $port = isset($url_bits['port']) ? ':' . $url_bits['port'] : '';
126
+        $port = isset($url_bits['port']) ? ':'.$url_bits['port'] : '';
127 127
         $user = isset($url_bits['user']) ? $url_bits['user'] : '';
128
-        $pass = isset($url_bits['pass']) ? ':' . $url_bits['pass'] : '';
129
-        $pass = ($user || $pass) ? $pass . '@' : '';
128
+        $pass = isset($url_bits['pass']) ? ':'.$url_bits['pass'] : '';
129
+        $pass = ($user || $pass) ? $pass.'@' : '';
130 130
         $path = isset($url_bits['path']) ? $url_bits['path'] : '';
131 131
         // if the query string is not required, then return what we have so far
132 132
         if ($remove_query) {
133
-            return $scheme . $user . $pass . $host . $port . $path;
133
+            return $scheme.$user.$pass.$host.$port.$path;
134 134
         }
135
-        $query    = isset($url_bits['query']) ? '?' . $url_bits['query'] : '';
136
-        $fragment = isset($url_bits['fragment']) ? '#' . $url_bits['fragment'] : '';
137
-        return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
135
+        $query    = isset($url_bits['query']) ? '?'.$url_bits['query'] : '';
136
+        $fragment = isset($url_bits['fragment']) ? '#'.$url_bits['fragment'] : '';
137
+        return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
138 138
     }
139 139
 
140 140
 
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
         // grab query string from URL
155 155
         $query = isset($url_bits['query']) ? $url_bits['query'] : '';
156 156
         // if we don't want the query string formatted into an array of key => value pairs, then just return it as is
157
-        if (! $as_array) {
157
+        if ( ! $as_array) {
158 158
             return $query;
159 159
         }
160 160
         // if no query string exists then just return an empty array now
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
             // break apart the key value pairs
171 171
             $query_args = explode('=', $query_args);
172 172
             // and add to our results array
173
-            $query_params[ $query_args[0] ] = $query_args[1];
173
+            $query_params[$query_args[0]] = $query_args[1];
174 174
         }
175 175
         return $query_params;
176 176
     }
@@ -199,8 +199,8 @@  discard block
 block discarded – undo
199 199
      */
200 200
     public static function generate_unique_token(string $prefix = ''): string
201 201
     {
202
-        $token = md5(uniqid() . mt_rand());
203
-        return $prefix ? $prefix . '_' . $token : $token;
202
+        $token = md5(uniqid().mt_rand());
203
+        return $prefix ? $prefix.'_'.$token : $token;
204 204
     }
205 205
 
206 206
 
@@ -220,13 +220,13 @@  discard block
 block discarded – undo
220 220
             'HTTP_HOST'   => 1,
221 221
             'PHP_SELF'    => 1,
222 222
         ];
223
-        $server_variable  = strtoupper($server_variable);
223
+        $server_variable = strtoupper($server_variable);
224 224
         // whitelist INPUT_SERVER var
225
-        if (isset($server_variables[ $server_variable ])) {
225
+        if (isset($server_variables[$server_variable])) {
226 226
             $URL = filter_input(INPUT_SERVER, $server_variable, FILTER_SANITIZE_URL, FILTER_NULL_ON_FAILURE);
227
-            if (empty($URL) || $URL !== $_SERVER[ $server_variable ]) {
227
+            if (empty($URL) || $URL !== $_SERVER[$server_variable]) {
228 228
                 // fallback sanitization if the above fails or URL has changed after filtering
229
-                $URL = wp_sanitize_redirect($_SERVER[ $server_variable ]);
229
+                $URL = wp_sanitize_redirect($_SERVER[$server_variable]);
230 230
             }
231 231
         }
232 232
         return $URL;
@@ -304,7 +304,7 @@  discard block
 block discarded – undo
304 304
     protected static function getRequest()
305 305
     {
306 306
         static $request;
307
-        if (! $request instanceof RequestInterface) {
307
+        if ( ! $request instanceof RequestInterface) {
308 308
             $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
309 309
         }
310 310
         return $request;
Please login to merge, or discard this patch.