Completed
Branch FET/11450/reserved-instance-in... (8adea5)
by
unknown
12:37
created
core/data_migration_scripts/EE_DMS_Core_4_1_0.dms.php 1 patch
Indentation   +1137 added lines, -1137 removed lines patch added patch discarded remove patch
@@ -12,11 +12,11 @@  discard block
 block discarded – undo
12 12
 $stages = glob(EE_CORE . 'data_migration_scripts/4_1_0_stages/*');
13 13
 $class_to_filepath = array();
14 14
 if ( ! empty($stages)) {
15
-    foreach ($stages as $filepath) {
16
-        $matches = array();
17
-        preg_match('~4_1_0_stages/(.*).dmsstage.php~', $filepath, $matches);
18
-        $class_to_filepath[$matches[1]] = $filepath;
19
-    }
15
+	foreach ($stages as $filepath) {
16
+		$matches = array();
17
+		preg_match('~4_1_0_stages/(.*).dmsstage.php~', $filepath, $matches);
18
+		$class_to_filepath[$matches[1]] = $filepath;
19
+	}
20 20
 }
21 21
 //give addons a chance to autoload their stages too
22 22
 $class_to_filepath = apply_filters('FHEE__EE_DMS_4_1_0__autoloaded_stages', $class_to_filepath);
@@ -44,91 +44,91 @@  discard block
 block discarded – undo
44 44
 
45 45
 
46 46
 
47
-    /**
48
-     * EE_DMS_Core_4_1_0 constructor.
49
-     *
50
-     * @param TableManager  $table_manager
51
-     * @param TableAnalysis $table_analysis
52
-     */
53
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
54
-    {
55
-        $this->_pretty_name = esc_html__("Data Migration from Event Espresso 3 to Event Espresso 4.1.0", "event_espresso");
56
-        $this->_priority = 10;
57
-        $this->_migration_stages = array(
58
-                new EE_DMS_4_1_0_org_options(),
59
-                new EE_DMS_4_1_0_shortcodes(),
60
-                new EE_DMS_4_1_0_gateways(),
61
-                new EE_DMS_4_1_0_events(),
62
-                new EE_DMS_4_1_0_prices(),
63
-                new EE_DMS_4_1_0_category_details(),
64
-                new EE_DMS_4_1_0_event_category(),
65
-                new EE_DMS_4_1_0_venues(),
66
-                new EE_DMS_4_1_0_event_venue(),
67
-                new EE_DMS_4_1_0_question_groups(),
68
-                new EE_DMS_4_1_0_questions(),
69
-                new EE_DMS_4_1_0_question_group_question(),
70
-                new EE_DMS_4_1_0_event_question_group(),
71
-                new EE_DMS_4_1_0_attendees(),
72
-                new EE_DMS_4_1_0_line_items(),
73
-                new EE_DMS_4_1_0_answers(),
74
-                new EE_DMS_4_1_0_checkins(),
75
-        );
76
-        parent::__construct($table_manager, $table_analysis);
77
-    }
78
-
79
-
80
-
81
-    /**
82
-     * Checks if this 3.1 Check-in table exists. If it doesn't we can't migrate Check-ins
83
-     *
84
-     * @global wpdb $wpdb
85
-     * @return boolean
86
-     */
87
-    private function _checkin_table_exists()
88
-    {
89
-        global $wpdb;
90
-        $results = $wpdb->get_results("SHOW TABLES LIKE '" . $wpdb->prefix . "events_attendee_checkin" . "'");
91
-        if ($results) {
92
-            return true;
93
-        } else {
94
-            return false;
95
-        }
96
-    }
97
-
98
-
99
-
100
-    public function can_migrate_from_version($version_array)
101
-    {
102
-        $version_string = $version_array['Core'];
103
-        if (version_compare($version_string, '4.0.0', '<=') && version_compare($version_string, '3.1.26', '>=')) {
47
+	/**
48
+	 * EE_DMS_Core_4_1_0 constructor.
49
+	 *
50
+	 * @param TableManager  $table_manager
51
+	 * @param TableAnalysis $table_analysis
52
+	 */
53
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
54
+	{
55
+		$this->_pretty_name = esc_html__("Data Migration from Event Espresso 3 to Event Espresso 4.1.0", "event_espresso");
56
+		$this->_priority = 10;
57
+		$this->_migration_stages = array(
58
+				new EE_DMS_4_1_0_org_options(),
59
+				new EE_DMS_4_1_0_shortcodes(),
60
+				new EE_DMS_4_1_0_gateways(),
61
+				new EE_DMS_4_1_0_events(),
62
+				new EE_DMS_4_1_0_prices(),
63
+				new EE_DMS_4_1_0_category_details(),
64
+				new EE_DMS_4_1_0_event_category(),
65
+				new EE_DMS_4_1_0_venues(),
66
+				new EE_DMS_4_1_0_event_venue(),
67
+				new EE_DMS_4_1_0_question_groups(),
68
+				new EE_DMS_4_1_0_questions(),
69
+				new EE_DMS_4_1_0_question_group_question(),
70
+				new EE_DMS_4_1_0_event_question_group(),
71
+				new EE_DMS_4_1_0_attendees(),
72
+				new EE_DMS_4_1_0_line_items(),
73
+				new EE_DMS_4_1_0_answers(),
74
+				new EE_DMS_4_1_0_checkins(),
75
+		);
76
+		parent::__construct($table_manager, $table_analysis);
77
+	}
78
+
79
+
80
+
81
+	/**
82
+	 * Checks if this 3.1 Check-in table exists. If it doesn't we can't migrate Check-ins
83
+	 *
84
+	 * @global wpdb $wpdb
85
+	 * @return boolean
86
+	 */
87
+	private function _checkin_table_exists()
88
+	{
89
+		global $wpdb;
90
+		$results = $wpdb->get_results("SHOW TABLES LIKE '" . $wpdb->prefix . "events_attendee_checkin" . "'");
91
+		if ($results) {
92
+			return true;
93
+		} else {
94
+			return false;
95
+		}
96
+	}
97
+
98
+
99
+
100
+	public function can_migrate_from_version($version_array)
101
+	{
102
+		$version_string = $version_array['Core'];
103
+		if (version_compare($version_string, '4.0.0', '<=') && version_compare($version_string, '3.1.26', '>=')) {
104 104
 //			echo "$version_string can be migrated fro";
105
-            return true;
106
-        } elseif ( ! $version_string) {
105
+			return true;
106
+		} elseif ( ! $version_string) {
107 107
 //			echo "no version string provided: $version_string";
108
-            //no version string provided... this must be pre 4.1
109
-            //because since 4.1 we're
110
-            return false;//changed mind. dont want people thinking they should migrate yet because they cant
111
-        } else {
108
+			//no version string provided... this must be pre 4.1
109
+			//because since 4.1 we're
110
+			return false;//changed mind. dont want people thinking they should migrate yet because they cant
111
+		} else {
112 112
 //			echo "$version_string doesnt apply";
113
-            return false;
114
-        }
115
-    }
113
+			return false;
114
+		}
115
+	}
116 116
 
117 117
 
118 118
 
119
-    public function schema_changes_before_migration()
120
-    {
121
-        //relies on 4.1's EEH_Activation::create_table
122
-        require_once(EE_HELPERS . 'EEH_Activation.helper.php');
123
-        $table_name = 'esp_answer';
124
-        $sql = " ANS_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
119
+	public function schema_changes_before_migration()
120
+	{
121
+		//relies on 4.1's EEH_Activation::create_table
122
+		require_once(EE_HELPERS . 'EEH_Activation.helper.php');
123
+		$table_name = 'esp_answer';
124
+		$sql = " ANS_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
125 125
 					REG_ID INT UNSIGNED NOT NULL,
126 126
 					QST_ID INT UNSIGNED NOT NULL,
127 127
 					ANS_value TEXT NOT NULL,
128 128
 					PRIMARY KEY  (ANS_ID)";
129
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
130
-        $table_name = 'esp_attendee_meta';
131
-        $sql = "ATTM_ID INT(10) UNSIGNED NOT	NULL AUTO_INCREMENT,
129
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
130
+		$table_name = 'esp_attendee_meta';
131
+		$sql = "ATTM_ID INT(10) UNSIGNED NOT	NULL AUTO_INCREMENT,
132 132
 						ATT_ID BIGINT(20) UNSIGNED NOT NULL,
133 133
 						ATT_fname VARCHAR(45) NOT NULL,
134 134
 						ATT_lname VARCHAR(45) NOT	NULL,
@@ -144,9 +144,9 @@  discard block
 block discarded – undo
144 144
 								KEY ATT_fname (ATT_fname),
145 145
 								KEY ATT_lname (ATT_lname),
146 146
 								KEY ATT_email (ATT_email)";
147
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB ');
148
-        $table_name = 'esp_country';
149
-        $sql = "CNT_ISO VARCHAR(2) COLLATE utf8_bin NOT NULL,
147
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB ');
148
+		$table_name = 'esp_country';
149
+		$sql = "CNT_ISO VARCHAR(2) COLLATE utf8_bin NOT NULL,
150 150
 					  CNT_ISO3 VARCHAR(3) COLLATE utf8_bin NOT NULL,
151 151
 					  RGN_ID TINYINT(3) UNSIGNED DEFAULT NULL,
152 152
 					  CNT_name VARCHAR(45) COLLATE utf8_bin NOT NULL,
@@ -162,9 +162,9 @@  discard block
 block discarded – undo
162 162
 					  CNT_is_EU TINYINT(1) DEFAULT '0',
163 163
 					  CNT_active TINYINT(1) DEFAULT '0',
164 164
 					  PRIMARY KEY  (CNT_ISO)";
165
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
166
-        $table_name = 'esp_datetime';
167
-        $sql = "DTT_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
165
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
166
+		$table_name = 'esp_datetime';
167
+		$sql = "DTT_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
168 168
 				  EVT_ID BIGINT(20) UNSIGNED NOT NULL,
169 169
 				  DTT_EVT_start DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
170 170
 				  DTT_EVT_end DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
@@ -177,9 +177,9 @@  discard block
 block discarded – undo
177 177
 						PRIMARY KEY  (DTT_ID),
178 178
 						KEY EVT_ID (EVT_ID),
179 179
 						KEY DTT_is_primary (DTT_is_primary)";
180
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
181
-        $table_name = 'esp_event_meta';
182
-        $sql = "
180
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
181
+		$table_name = 'esp_event_meta';
182
+		$sql = "
183 183
 			EVTM_ID INT NOT NULL AUTO_INCREMENT,
184 184
 			EVT_ID BIGINT(20) UNSIGNED NOT NULL,
185 185
 			EVT_display_desc TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
@@ -194,31 +194,31 @@  discard block
 block discarded – undo
194 194
 			EVT_external_URL VARCHAR(200) NULL,
195 195
 			EVT_donations TINYINT(1) NULL,
196 196
 			PRIMARY KEY  (EVTM_ID)";
197
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
198
-        $table_name = 'esp_event_question_group';
199
-        $sql = "EQG_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
197
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
198
+		$table_name = 'esp_event_question_group';
199
+		$sql = "EQG_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
200 200
 					EVT_ID BIGINT(20) UNSIGNED NOT NULL,
201 201
 					QSG_ID INT UNSIGNED NOT NULL,
202 202
 					EQG_primary TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
203 203
 					PRIMARY KEY  (EQG_ID)";
204
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
205
-        $table_name = 'esp_event_venue';
206
-        $sql = "EVV_ID INT(11) NOT NULL AUTO_INCREMENT,
204
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
205
+		$table_name = 'esp_event_venue';
206
+		$sql = "EVV_ID INT(11) NOT NULL AUTO_INCREMENT,
207 207
 				EVT_ID BIGINT(20) UNSIGNED NOT NULL,
208 208
 				VNU_ID BIGINT(20) UNSIGNED NOT NULL,
209 209
 				EVV_primary TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
210 210
 				PRIMARY KEY  (EVV_ID)";
211
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
212
-        $table_name = 'esp_extra_meta';
213
-        $sql = "EXM_ID INT(11) NOT NULL AUTO_INCREMENT,
211
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
212
+		$table_name = 'esp_extra_meta';
213
+		$sql = "EXM_ID INT(11) NOT NULL AUTO_INCREMENT,
214 214
 				OBJ_ID INT(11) DEFAULT NULL,
215 215
 				EXM_type VARCHAR(45) DEFAULT NULL,
216 216
 				EXM_key VARCHAR(45) DEFAULT NULL,
217 217
 				EXM_value TEXT,
218 218
 				PRIMARY KEY  (EXM_ID)";
219
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
220
-        $table_name = 'esp_line_item';
221
-        $sql = "LIN_ID INT(11) NOT NULL AUTO_INCREMENT,
219
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
220
+		$table_name = 'esp_line_item';
221
+		$sql = "LIN_ID INT(11) NOT NULL AUTO_INCREMENT,
222 222
 				LIN_code VARCHAR(245) NOT NULL DEFAULT '',
223 223
 				TXN_ID INT(11) DEFAULT NULL,
224 224
 				LIN_name VARCHAR(245) NOT NULL DEFAULT '',
@@ -234,18 +234,18 @@  discard block
 block discarded – undo
234 234
 				OBJ_ID INT(11) DEFAULT NULL,
235 235
 				OBJ_type VARCHAR(45)DEFAULT NULL,
236 236
 				PRIMARY KEY  (LIN_ID)";
237
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
238
-        $table_name = 'esp_message_template';
239
-        $sql = "MTP_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
237
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
238
+		$table_name = 'esp_message_template';
239
+		$sql = "MTP_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
240 240
 					GRP_ID INT(10) UNSIGNED NOT NULL,
241 241
 					MTP_context VARCHAR(50) NOT NULL,
242 242
 					MTP_template_field VARCHAR(30) NOT NULL,
243 243
 					MTP_content TEXT NOT NULL,
244 244
 					PRIMARY KEY  (MTP_ID),
245 245
 					KEY GRP_ID (GRP_ID)";
246
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
247
-        $table_name = 'esp_message_template_group';
248
-        $sql = "GRP_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
246
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
247
+		$table_name = 'esp_message_template_group';
248
+		$sql = "GRP_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
249 249
 					EVT_ID BIGINT(20) UNSIGNED DEFAULT NULL,
250 250
 					MTP_user_id INT(10) NOT NULL DEFAULT '1',
251 251
 					MTP_messenger VARCHAR(30) NOT NULL,
@@ -257,9 +257,9 @@  discard block
 block discarded – undo
257 257
 					PRIMARY KEY  (GRP_ID),
258 258
 					KEY EVT_ID (EVT_ID),
259 259
 					KEY MTP_user_id (MTP_user_id)";
260
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
261
-        $table_name = 'esp_payment';
262
-        $sql = "PAY_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
260
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
261
+		$table_name = 'esp_payment';
262
+		$sql = "PAY_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
263 263
 					TXN_ID INT(10) UNSIGNED DEFAULT NULL,
264 264
 					STS_ID VARCHAR(3) COLLATE utf8_bin DEFAULT NULL,
265 265
 					PAY_timestamp DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
@@ -275,9 +275,9 @@  discard block
 block discarded – undo
275 275
 					PRIMARY KEY  (PAY_ID),
276 276
 					KEY TXN_ID (TXN_ID),
277 277
 					KEY PAY_timestamp (PAY_timestamp)";
278
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB ');
279
-        $table_name = "esp_ticket";
280
-        $sql = "TKT_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
278
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB ');
279
+		$table_name = "esp_ticket";
280
+		$sql = "TKT_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
281 281
 					  TTM_ID INT(10) UNSIGNED NOT NULL,
282 282
 					  TKT_name VARCHAR(245) NOT NULL DEFAULT '',
283 283
 					  TKT_description TEXT NOT NULL,
@@ -296,28 +296,28 @@  discard block
 block discarded – undo
296 296
 					  TKT_parent INT(10) UNSIGNED DEFAULT '0',
297 297
 					  TKT_deleted TINYINT(1) NOT NULL DEFAULT '0',
298 298
 					  PRIMARY KEY  (TKT_ID)";
299
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
300
-        $table_name = "esp_ticket_price";
301
-        $sql = "TKP_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
299
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
300
+		$table_name = "esp_ticket_price";
301
+		$sql = "TKP_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
302 302
 					  TKT_ID INT(10) UNSIGNED NOT NULL,
303 303
 					  PRC_ID INT(10) UNSIGNED NOT NULL,
304 304
 					  PRIMARY KEY  (TKP_ID)";
305
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
306
-        $table_name = "esp_datetime_ticket";
307
-        $sql = "DTK_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
305
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
306
+		$table_name = "esp_datetime_ticket";
307
+		$sql = "DTK_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
308 308
 					  DTT_ID INT(10) UNSIGNED NOT NULL,
309 309
 					  TKT_ID INT(10) UNSIGNED NOT NULL,
310 310
 					  PRIMARY KEY  (DTK_ID)";
311
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
312
-        $table_name = "esp_ticket_template";
313
-        $sql = "TTM_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
311
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
312
+		$table_name = "esp_ticket_template";
313
+		$sql = "TTM_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
314 314
 					  TTM_name VARCHAR(45) NOT NULL,
315 315
 					  TTM_description TEXT,
316 316
 					  TTM_file VARCHAR(45),
317 317
 					  PRIMARY KEY  (TTM_ID)";
318
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
319
-        $table_name = "esp_price";
320
-        $sql = "PRC_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
318
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
319
+		$table_name = "esp_price";
320
+		$sql = "PRC_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
321 321
 					  PRT_ID TINYINT(3) UNSIGNED NOT NULL,
322 322
 					  PRC_amount DECIMAL(10,3) NOT NULL DEFAULT '0.00',
323 323
 					  PRC_name VARCHAR(245) NOT NULL,
@@ -328,9 +328,9 @@  discard block
 block discarded – undo
328 328
 					  PRC_order TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
329 329
 					  PRC_parent INT(10) UNSIGNED DEFAULT 0,
330 330
 					  PRIMARY KEY  (PRC_ID)";
331
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
332
-        $table_name = "esp_price_type";
333
-        $sql = "PRT_ID TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
331
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
332
+		$table_name = "esp_price_type";
333
+		$sql = "PRT_ID TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
334 334
 				  PRT_name VARCHAR(45) NOT NULL,
335 335
 				  PBT_ID TINYINT(3) UNSIGNED NOT NULL DEFAULT '1',
336 336
 				  PRT_is_percent TINYINT(1) NOT NULL DEFAULT '0',
@@ -338,9 +338,9 @@  discard block
 block discarded – undo
338 338
 				  PRT_deleted TINYINT(1) NOT NULL DEFAULT '0',
339 339
 				  UNIQUE KEY PRT_name_UNIQUE (PRT_name),
340 340
 				  PRIMARY KEY  (PRT_ID)";
341
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
342
-        $table_name = 'esp_question';
343
-        $sql = 'QST_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
341
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
342
+		$table_name = 'esp_question';
343
+		$sql = 'QST_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
344 344
 					QST_display_text TEXT NOT NULL,
345 345
 					QST_admin_label VARCHAR(255) NOT NULL,
346 346
 					QST_system VARCHAR(25) DEFAULT NULL,
@@ -352,10 +352,10 @@  discard block
 block discarded – undo
352 352
 					QST_wp_user BIGINT UNSIGNED NULL,
353 353
 					QST_deleted TINYINT UNSIGNED NOT NULL DEFAULT 0,
354 354
 					PRIMARY KEY  (QST_ID)';
355
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
356
-        $this->_get_table_manager()->dropIndex('esp_question_group', 'QSG_identifier_UNIQUE');
357
-        $table_name = 'esp_question_group';
358
-        $sql = 'QSG_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
355
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
356
+		$this->_get_table_manager()->dropIndex('esp_question_group', 'QSG_identifier_UNIQUE');
357
+		$table_name = 'esp_question_group';
358
+		$sql = 'QSG_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
359 359
 					QSG_name VARCHAR(255) NOT NULL,
360 360
 					QSG_identifier VARCHAR(100) NOT NULL,
361 361
 					QSG_desc TEXT NULL,
@@ -366,23 +366,23 @@  discard block
 block discarded – undo
366 366
 					QSG_deleted TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
367 367
 					PRIMARY KEY  (QSG_ID),
368 368
 					UNIQUE KEY QSG_identifier_UNIQUE (QSG_identifier ASC)';
369
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
370
-        $table_name = 'esp_question_group_question';
371
-        $sql = "QGQ_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
369
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
370
+		$table_name = 'esp_question_group_question';
371
+		$sql = "QGQ_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
372 372
 					QSG_ID INT UNSIGNED NOT NULL,
373 373
 					QST_ID INT UNSIGNED NOT NULL,
374 374
 					PRIMARY KEY  (QGQ_ID) ";
375
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
376
-        $table_name = 'esp_question_option';
377
-        $sql = "QSO_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
375
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
376
+		$table_name = 'esp_question_option';
377
+		$sql = "QSO_ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
378 378
 					QSO_value VARCHAR(255) NOT NULL,
379 379
 					QSO_desc TEXT NOT NULL,
380 380
 					QST_ID INT UNSIGNED NOT NULL,
381 381
 					QSO_deleted TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
382 382
 					PRIMARY KEY  (QSO_ID)";
383
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
384
-        $table_name = 'esp_registration';
385
-        $sql = "REG_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
383
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
384
+		$table_name = 'esp_registration';
385
+		$sql = "REG_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
386 386
 					  EVT_ID BIGINT(20) UNSIGNED NOT NULL,
387 387
 					  ATT_ID BIGINT(20) UNSIGNED NOT NULL,
388 388
 					  TXN_ID INT(10) UNSIGNED NOT NULL,
@@ -405,25 +405,25 @@  discard block
 block discarded – undo
405 405
 					  KEY STS_ID (STS_ID),
406 406
 					  KEY REG_url_link (REG_url_link),
407 407
 					  KEY REG_code (REG_code)";
408
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB ');
409
-        $table_name = 'esp_checkin';
410
-        $sql = "CHK_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
408
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB ');
409
+		$table_name = 'esp_checkin';
410
+		$sql = "CHK_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
411 411
 					REG_ID INT(10) UNSIGNED NOT NULL,
412 412
 					DTT_ID INT(10) UNSIGNED NOT NULL,
413 413
 					CHK_in TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
414 414
 					CHK_timestamp DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
415 415
 					PRIMARY KEY  (CHK_ID)";
416
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
417
-        $table_name = 'esp_state';
418
-        $sql = "STA_ID smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT,
416
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
417
+		$table_name = 'esp_state';
418
+		$sql = "STA_ID smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT,
419 419
 					  CNT_ISO VARCHAR(2) COLLATE utf8_bin NOT NULL,
420 420
 					  STA_abbrev VARCHAR(6) COLLATE utf8_bin NOT NULL,
421 421
 					  STA_name VARCHAR(100) COLLATE utf8_bin NOT NULL,
422 422
 					  STA_active TINYINT(1) DEFAULT '1',
423 423
 					  PRIMARY KEY  (STA_ID)";
424
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
425
-        $table_name = 'esp_status';
426
-        $sql = "STS_ID VARCHAR(3) COLLATE utf8_bin NOT NULL,
424
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
425
+		$table_name = 'esp_status';
426
+		$sql = "STS_ID VARCHAR(3) COLLATE utf8_bin NOT NULL,
427 427
 					  STS_code VARCHAR(45) COLLATE utf8_bin NOT NULL,
428 428
 					  STS_type set('event','registration','transaction','payment','email') COLLATE utf8_bin NOT NULL,
429 429
 					  STS_can_edit TINYINT(1) NOT NULL DEFAULT 0,
@@ -431,9 +431,9 @@  discard block
 block discarded – undo
431 431
 					  STS_open TINYINT(1) NOT NULL DEFAULT 1,
432 432
 					  UNIQUE KEY STS_ID_UNIQUE (STS_ID),
433 433
 					  KEY STS_type (STS_type)";
434
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
435
-        $table_name = 'esp_transaction';
436
-        $sql = "TXN_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
434
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
435
+		$table_name = 'esp_transaction';
436
+		$sql = "TXN_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
437 437
 					  TXN_timestamp DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
438 438
 					  TXN_total DECIMAL(10,3) DEFAULT '0.00',
439 439
 					  TXN_paid DECIMAL(10,3) NOT NULL DEFAULT '0.00',
@@ -443,9 +443,9 @@  discard block
 block discarded – undo
443 443
 					  PRIMARY KEY  (TXN_ID),
444 444
 					  KEY TXN_timestamp (TXN_timestamp),
445 445
 					  KEY STS_ID (STS_ID)";
446
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
447
-        $table_name = 'esp_venue_meta';
448
-        $sql = "VNUM_ID INT(11) NOT NULL AUTO_INCREMENT,
446
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
447
+		$table_name = 'esp_venue_meta';
448
+		$sql = "VNUM_ID INT(11) NOT NULL AUTO_INCREMENT,
449 449
 			VNU_ID BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
450 450
 			VNU_address VARCHAR(255) DEFAULT NULL,
451 451
 			VNU_address2 VARCHAR(255) DEFAULT NULL,
@@ -463,52 +463,52 @@  discard block
 block discarded – undo
463 463
 			PRIMARY KEY  (VNUM_ID),
464 464
 			KEY STA_ID (STA_ID),
465 465
 			KEY CNT_ISO (CNT_ISO)";
466
-        $this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
467
-        //setting up the DEFAULT stats and countries is also essential for the data migrations to run
468
-        //(because many need to convert old string states to foreign keys into the states table)
469
-        $this->insert_default_states();
470
-        $this->insert_default_countries();
471
-        //setting up DEFAULT prices, price types, and tickets is also essential for the price migrations
472
-        $this->insert_default_price_types();
473
-        $this->insert_default_prices();
474
-        $this->insert_default_tickets();
475
-        //setting up the config wp option pretty well counts as a 'schema change', or at least should happen ehre
476
-        EE_Config::instance()->update_espresso_config(false, true);
477
-        return true;
478
-    }
479
-
480
-
481
-
482
-    /**
483
-     * Yes we could have cleaned up the ee3 tables here. But just in case someone
484
-     * didn't backup their DB, and decides they want ot keep using EE3, we'll
485
-     * leave them for now. Mayeb remove them in 4.5 or something.
486
-     *
487
-     * @return boolean
488
-     */
489
-    public function schema_changes_after_migration()
490
-    {
491
-        return true;
492
-    }
493
-
494
-
495
-
496
-    /**
497
-     * insert_default_states
498
-     *
499
-     * @access public
500
-     * @static
501
-     * @return void
502
-     */
503
-    public function insert_default_states()
504
-    {
505
-        global $wpdb;
506
-        $state_table = $wpdb->prefix . "esp_state";
507
-        if ($this->_get_table_analysis()->tableExists($state_table)) {
508
-            $SQL = "SELECT COUNT('STA_ID') FROM " . $state_table;
509
-            $states = $wpdb->get_var($SQL);
510
-            if ( ! $states) {
511
-                $SQL = "INSERT INTO " . $state_table . "
466
+		$this->_table_is_new_in_this_version($table_name, $sql, 'ENGINE=InnoDB');
467
+		//setting up the DEFAULT stats and countries is also essential for the data migrations to run
468
+		//(because many need to convert old string states to foreign keys into the states table)
469
+		$this->insert_default_states();
470
+		$this->insert_default_countries();
471
+		//setting up DEFAULT prices, price types, and tickets is also essential for the price migrations
472
+		$this->insert_default_price_types();
473
+		$this->insert_default_prices();
474
+		$this->insert_default_tickets();
475
+		//setting up the config wp option pretty well counts as a 'schema change', or at least should happen ehre
476
+		EE_Config::instance()->update_espresso_config(false, true);
477
+		return true;
478
+	}
479
+
480
+
481
+
482
+	/**
483
+	 * Yes we could have cleaned up the ee3 tables here. But just in case someone
484
+	 * didn't backup their DB, and decides they want ot keep using EE3, we'll
485
+	 * leave them for now. Mayeb remove them in 4.5 or something.
486
+	 *
487
+	 * @return boolean
488
+	 */
489
+	public function schema_changes_after_migration()
490
+	{
491
+		return true;
492
+	}
493
+
494
+
495
+
496
+	/**
497
+	 * insert_default_states
498
+	 *
499
+	 * @access public
500
+	 * @static
501
+	 * @return void
502
+	 */
503
+	public function insert_default_states()
504
+	{
505
+		global $wpdb;
506
+		$state_table = $wpdb->prefix . "esp_state";
507
+		if ($this->_get_table_analysis()->tableExists($state_table)) {
508
+			$SQL = "SELECT COUNT('STA_ID') FROM " . $state_table;
509
+			$states = $wpdb->get_var($SQL);
510
+			if ( ! $states) {
511
+				$SQL = "INSERT INTO " . $state_table . "
512 512
 				(STA_ID, CNT_ISO, STA_abbrev, STA_name, STA_active) VALUES
513 513
 				(1, 'US', 'AK', 'Alaska', 1),
514 514
 				(2, 'US', 'AL', 'Alabama', 1),
@@ -579,29 +579,29 @@  discard block
 block discarded – undo
579 579
 				(67, 'CA', 'PE', 'Prince Edward Island', 1),
580 580
 				(68, 'CA', 'QC', 'Quebec', 1),
581 581
 				(69, 'CA', 'SK', 'Saskatchewan', 1);";
582
-                $wpdb->query($SQL);
583
-            }
584
-        }
585
-    }
586
-
587
-
588
-
589
-    /**
590
-     * insert_default_countries
591
-     *
592
-     * @access public
593
-     * @static
594
-     * @return void
595
-     */
596
-    public function insert_default_countries()
597
-    {
598
-        global $wpdb;
599
-        $country_table = $wpdb->prefix . "esp_country";
600
-        if ($this->_get_table_analysis()->tableExists($country_table)) {
601
-            $SQL = "SELECT COUNT('CNT_ISO') FROM " . $country_table;
602
-            $countries = $wpdb->get_var($SQL);
603
-            if ( ! $countries) {
604
-                $SQL = "INSERT INTO " . $country_table . "
582
+				$wpdb->query($SQL);
583
+			}
584
+		}
585
+	}
586
+
587
+
588
+
589
+	/**
590
+	 * insert_default_countries
591
+	 *
592
+	 * @access public
593
+	 * @static
594
+	 * @return void
595
+	 */
596
+	public function insert_default_countries()
597
+	{
598
+		global $wpdb;
599
+		$country_table = $wpdb->prefix . "esp_country";
600
+		if ($this->_get_table_analysis()->tableExists($country_table)) {
601
+			$SQL = "SELECT COUNT('CNT_ISO') FROM " . $country_table;
602
+			$countries = $wpdb->get_var($SQL);
603
+			if ( ! $countries) {
604
+				$SQL = "INSERT INTO " . $country_table . "
605 605
 				(CNT_ISO, CNT_ISO3, RGN_ID, CNT_name, CNT_cur_code, CNT_cur_single, CNT_cur_plural, CNT_cur_sign, CNT_cur_sign_b4, CNT_cur_dec_plc, CNT_tel_code, CNT_is_EU, CNT_active) VALUES
606 606
 				('AD', 'AND', 0, 'Andorra', 'EUR', 'Euro', 'Euros', '€', 1, 2, '+376', 0, 0),
607 607
 				('AE', 'ARE', 0, 'United Arab Emirates', 'AED', 'Dirham', 'Dirhams', 'د.إ', 1, 2, '+971', 0, 0),
@@ -829,941 +829,941 @@  discard block
 block discarded – undo
829 829
 				('ZA', 'ZAF', 0, 'South Africa', 'ZAR', 'Rand', 'Rands', 'R', 1, 2, '+27', 0, 0),
830 830
 				('ZM', 'ZMB', 0, 'Zambia', 'ZMK', 'Kwacha', 'Kwachas', '', 1, 2, '+260', 0, 0),
831 831
 				('ZW', 'ZWE', 0, 'Zimbabwe', 'ZWD', 'Dollar', 'Dollars', 'Z$', 1, 2, '+263', 0, 0);";
832
-                $wpdb->query($SQL);
833
-            }
834
-        }
835
-    }
836
-
837
-
838
-
839
-    /**
840
-     * insert_default_price_types
841
-     *
842
-     * @access public
843
-     * @static
844
-     * @return void
845
-     */
846
-    public function insert_default_price_types()
847
-    {
848
-        global $wpdb;
849
-        $price_type_table = $wpdb->prefix . "esp_price_type";
850
-        if ($this->_get_table_analysis()->tableExists($price_type_table)) {
851
-            $SQL = 'SELECT COUNT(PRT_ID) FROM ' . $price_type_table;
852
-            $price_types_exist = $wpdb->get_var($SQL);
853
-            if ( ! $price_types_exist) {
854
-                $SQL = "INSERT INTO $price_type_table ( PRT_ID, PRT_name, PBT_ID, PRT_is_percent, PRT_order, PRT_deleted ) VALUES
832
+				$wpdb->query($SQL);
833
+			}
834
+		}
835
+	}
836
+
837
+
838
+
839
+	/**
840
+	 * insert_default_price_types
841
+	 *
842
+	 * @access public
843
+	 * @static
844
+	 * @return void
845
+	 */
846
+	public function insert_default_price_types()
847
+	{
848
+		global $wpdb;
849
+		$price_type_table = $wpdb->prefix . "esp_price_type";
850
+		if ($this->_get_table_analysis()->tableExists($price_type_table)) {
851
+			$SQL = 'SELECT COUNT(PRT_ID) FROM ' . $price_type_table;
852
+			$price_types_exist = $wpdb->get_var($SQL);
853
+			if ( ! $price_types_exist) {
854
+				$SQL = "INSERT INTO $price_type_table ( PRT_ID, PRT_name, PBT_ID, PRT_is_percent, PRT_order, PRT_deleted ) VALUES
855 855
 							(1, '" . esc_html__('Base Price', 'event_espresso') . "', 1,  0, 0, 0),
856 856
 							(2, '" . esc_html__('Percent Discount', 'event_espresso') . "', 2,  1, 20, 0),
857 857
 							(3, '" . esc_html__('Fixed Discount', 'event_espresso') . "', 2,  0, 30, 0),
858 858
 							(4, '" . esc_html__('Percent Surcharge', 'event_espresso') . "', 3,  1, 40, 0),
859 859
 							(5, '" . esc_html__('Fixed Surcharge', 'event_espresso') . "', 3,  0, 50, 0);";
860
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_price_types__SQL', $SQL);
861
-                $wpdb->query($SQL);
862
-            }
863
-        }
864
-    }
865
-
866
-
867
-
868
-    /**
869
-     * insert_default_prices. We assume we're upgrading to regular here.
870
-     * If we're INSTALLING 4.1 CAF, then we add a few extra DEFAULT prices
871
-     * when EEH_Activaion's initialize_db_content is called via  ahook in
872
-     * EE_BRewing_regular
873
-     *
874
-     * @access public
875
-     * @static
876
-     * @return void
877
-     */
878
-    public function insert_default_prices()
879
-    {
880
-        global $wpdb;
881
-        $price_table = $wpdb->prefix . "esp_price";
882
-        if ($this->_get_table_analysis()->tableExists($price_table)) {
883
-            $SQL = 'SELECT COUNT(PRC_ID) FROM ' . $price_table;
884
-            $prices_exist = $wpdb->get_var($SQL);
885
-            if ( ! $prices_exist) {
886
-                $SQL = "INSERT INTO $price_table
860
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_price_types__SQL', $SQL);
861
+				$wpdb->query($SQL);
862
+			}
863
+		}
864
+	}
865
+
866
+
867
+
868
+	/**
869
+	 * insert_default_prices. We assume we're upgrading to regular here.
870
+	 * If we're INSTALLING 4.1 CAF, then we add a few extra DEFAULT prices
871
+	 * when EEH_Activaion's initialize_db_content is called via  ahook in
872
+	 * EE_BRewing_regular
873
+	 *
874
+	 * @access public
875
+	 * @static
876
+	 * @return void
877
+	 */
878
+	public function insert_default_prices()
879
+	{
880
+		global $wpdb;
881
+		$price_table = $wpdb->prefix . "esp_price";
882
+		if ($this->_get_table_analysis()->tableExists($price_table)) {
883
+			$SQL = 'SELECT COUNT(PRC_ID) FROM ' . $price_table;
884
+			$prices_exist = $wpdb->get_var($SQL);
885
+			if ( ! $prices_exist) {
886
+				$SQL = "INSERT INTO $price_table
887 887
 							(PRC_ID, PRT_ID, PRC_amount, PRC_name, PRC_desc,  PRC_is_default, PRC_overrides, PRC_order, PRC_deleted, PRC_parent ) VALUES
888 888
 							(1, 1, '0.00', 'Free Admission', '', 1, NULL, 0, 0, 0);";
889
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_prices__SQL', $SQL);
890
-                $wpdb->query($SQL);
891
-            }
892
-        }
893
-    }
894
-
895
-
896
-
897
-    /**
898
-     * insert DEFAULT ticket
899
-     *
900
-     * @access public
901
-     * @static
902
-     * @return void
903
-     */
904
-    public function insert_default_tickets()
905
-    {
906
-        global $wpdb;
907
-        $ticket_table = $wpdb->prefix . "esp_ticket";
908
-        if ($this->_get_table_analysis()->tableExists($ticket_table)) {
909
-            $SQL = 'SELECT COUNT(TKT_ID) FROM ' . $ticket_table;
910
-            $tickets_exist = $wpdb->get_var($SQL);
911
-            if ( ! $tickets_exist) {
912
-                $SQL = "INSERT INTO $ticket_table
889
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_prices__SQL', $SQL);
890
+				$wpdb->query($SQL);
891
+			}
892
+		}
893
+	}
894
+
895
+
896
+
897
+	/**
898
+	 * insert DEFAULT ticket
899
+	 *
900
+	 * @access public
901
+	 * @static
902
+	 * @return void
903
+	 */
904
+	public function insert_default_tickets()
905
+	{
906
+		global $wpdb;
907
+		$ticket_table = $wpdb->prefix . "esp_ticket";
908
+		if ($this->_get_table_analysis()->tableExists($ticket_table)) {
909
+			$SQL = 'SELECT COUNT(TKT_ID) FROM ' . $ticket_table;
910
+			$tickets_exist = $wpdb->get_var($SQL);
911
+			if ( ! $tickets_exist) {
912
+				$SQL = "INSERT INTO $ticket_table
913 913
 					( TKT_ID, TTM_ID, TKT_name, TKT_description, TKT_qty, TKT_sold, TKT_uses, TKT_min, TKT_max, TKT_price, TKT_start_date, TKT_end_date, TKT_taxable, TKT_order, TKT_row, TKT_is_default, TKT_parent, TKT_deleted ) VALUES
914 914
 					( 1, 0, '"
915
-                       . esc_html__("Free Ticket", "event_espresso")
916
-                       . "', '', 100, 0, -1, 0, -1, 0.00, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 0, 1, 1, 0, 0);";
917
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL', $SQL);
918
-                $wpdb->query($SQL);
919
-            }
920
-        }
921
-        $ticket_price_table = $wpdb->prefix . "esp_ticket_price";
922
-        if ($this->_get_table_analysis()->tableExists($ticket_price_table)) {
923
-            $SQL = 'SELECT COUNT(TKP_ID) FROM ' . $ticket_price_table;
924
-            $ticket_prc_exist = $wpdb->get_var($SQL);
925
-            if ( ! $ticket_prc_exist) {
926
-                $SQL = "INSERT INTO $ticket_price_table
915
+					   . esc_html__("Free Ticket", "event_espresso")
916
+					   . "', '', 100, 0, -1, 0, -1, 0.00, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 0, 1, 1, 0, 0);";
917
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL', $SQL);
918
+				$wpdb->query($SQL);
919
+			}
920
+		}
921
+		$ticket_price_table = $wpdb->prefix . "esp_ticket_price";
922
+		if ($this->_get_table_analysis()->tableExists($ticket_price_table)) {
923
+			$SQL = 'SELECT COUNT(TKP_ID) FROM ' . $ticket_price_table;
924
+			$ticket_prc_exist = $wpdb->get_var($SQL);
925
+			if ( ! $ticket_prc_exist) {
926
+				$SQL = "INSERT INTO $ticket_price_table
927 927
 				( TKP_ID, TKT_ID, PRC_ID ) VALUES
928 928
 				( 1, 1, 1 )
929 929
 				";
930
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL__ticket_price', $SQL);
931
-                $wpdb->query($SQL);
932
-            }
933
-        }
934
-    }
935
-
936
-
937
-
938
-    /**
939
-     * Gets a country entry as an array, or creates one if none is found. Much like EEM_Country::instance()->get_one(),
940
-     * but is independent of outside code which can change in future versions of EE. Also, $country_name CAN be a 3.1
941
-     * country ID (int), a 2-letter ISO, 3-letter ISO, or name
942
-     *
943
-     * @global type  $wpdb
944
-     * @param string $country_name
945
-     * @return array where keys are columns, values are column values
946
-     */
947
-    public function get_or_create_country($country_name)
948
-    {
949
-        if ( ! $country_name) {
950
-            throw new EE_Error(esc_html__("Could not get a country because country name is blank", "event_espresso"));
951
-        }
952
-        global $wpdb;
953
-        $country_table = $wpdb->prefix . "esp_country";
954
-        if (is_int($country_name)) {
955
-            $country_name = $this->get_iso_from_3_1_country_id($country_name);
956
-        }
957
-        $country = $wpdb->get_row($wpdb->prepare("SELECT * FROM $country_table WHERE
930
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL__ticket_price', $SQL);
931
+				$wpdb->query($SQL);
932
+			}
933
+		}
934
+	}
935
+
936
+
937
+
938
+	/**
939
+	 * Gets a country entry as an array, or creates one if none is found. Much like EEM_Country::instance()->get_one(),
940
+	 * but is independent of outside code which can change in future versions of EE. Also, $country_name CAN be a 3.1
941
+	 * country ID (int), a 2-letter ISO, 3-letter ISO, or name
942
+	 *
943
+	 * @global type  $wpdb
944
+	 * @param string $country_name
945
+	 * @return array where keys are columns, values are column values
946
+	 */
947
+	public function get_or_create_country($country_name)
948
+	{
949
+		if ( ! $country_name) {
950
+			throw new EE_Error(esc_html__("Could not get a country because country name is blank", "event_espresso"));
951
+		}
952
+		global $wpdb;
953
+		$country_table = $wpdb->prefix . "esp_country";
954
+		if (is_int($country_name)) {
955
+			$country_name = $this->get_iso_from_3_1_country_id($country_name);
956
+		}
957
+		$country = $wpdb->get_row($wpdb->prepare("SELECT * FROM $country_table WHERE
958 958
 			CNT_ISO LIKE %s OR
959 959
 			CNT_ISO3 LIKE %s OR
960 960
 			CNT_name LIKE %s LIMIT 1", $country_name, $country_name, $country_name), ARRAY_A);
961
-        if ( ! $country) {
962
-            //insert a new one then
963
-            $cols_n_values = array(
964
-                    'CNT_ISO'         => $this->_find_available_country_iso(2),
965
-                    'CNT_ISO3'        => $this->_find_available_country_iso(3),
966
-                    'RGN_ID'          => 0,
967
-                    'CNT_name'        => $country_name,
968
-                    'CNT_cur_code'    => 'USD',
969
-                    'CNT_cur_single'  => 'Dollar',
970
-                    'CNT_cur_plural'  => 'Dollars',
971
-                    'CNT_cur_sign'    => '&#36;',
972
-                    'CNT_cur_sign_b4' => true,
973
-                    'CNT_cur_dec_plc' => 2,
974
-                    'CNT_cur_dec_mrk' => '.',
975
-                    'CNT_cur_thsnds'  => ',',
976
-                    'CNT_tel_code'    => '+1',
977
-                    'CNT_is_EU'       => false,
978
-                    'CNT_active'      => true,
979
-            );
980
-            $data_types = array(
981
-                    '%s',//CNT_ISO
982
-                    '%s',//CNT_ISO3
983
-                    '%d',//RGN_ID
984
-                    '%s',//CNT_name
985
-                    '%s',//CNT_cur_code
986
-                    '%s',//CNT_cur_single
987
-                    '%s',//CNT_cur_plural
988
-                    '%s',//CNT_cur_sign
989
-                    '%d',//CNT_cur_sign_b4
990
-                    '%d',//CNT_cur_dec_plc
991
-                    '%s',//CNT_cur_dec_mrk
992
-                    '%s',//CNT_cur_thsnds
993
-                    '%s',//CNT_tel_code
994
-                    '%d',//CNT_is_EU
995
-                    '%d',//CNT_active
996
-            );
997
-            $success = $wpdb->insert($country_table,
998
-                    $cols_n_values,
999
-                    $data_types);
1000
-            if ( ! $success) {
1001
-                throw new EE_Error($this->_create_error_message_for_db_insertion('N/A',
1002
-                        array('country_id' => $country_name), $country_table, $cols_n_values, $data_types));
1003
-            }
1004
-            $country = $cols_n_values;
1005
-        }
1006
-        return $country;
1007
-    }
1008
-
1009
-
1010
-
1011
-    /**
1012
-     * finds a country iso which hasnt been used yet
1013
-     *
1014
-     * @global type $wpdb
1015
-     * @return string
1016
-     */
1017
-    private function _find_available_country_iso($num_letters = 2)
1018
-    {
1019
-        global $wpdb;
1020
-        $country_table = $wpdb->prefix . "esp_country";
1021
-        $attempts = 0;
1022
-        do {
1023
-            $current_iso = strtoupper(wp_generate_password($num_letters, false));
1024
-            $country_with_that_iso = $wpdb->get_var($wpdb->prepare("SELECT count(CNT_ISO) FROM "
1025
-                                                                   . $country_table
1026
-                                                                   . " WHERE CNT_ISO=%s", $current_iso));
1027
-            $attempts++;
1028
-            //keep going until we find an available country code, or we arbitrarily
1029
-            //decide we've tried this enough. Somehow they have way too many countries
1030
-            //(probably because they're mis-using the EE3 country_id like a custom question)
1031
-        } while (intval($country_with_that_iso) && $attempts < 200);
1032
-        return $current_iso;
1033
-    }
1034
-
1035
-
1036
-
1037
-    /**
1038
-     * Gets a state entry as an array, or creates one if none is found. Much like EEM_State::instance()->get_one(), but
1039
-     * is independent of outside code which can change in future versions of EE
1040
-     *
1041
-     * @global type  $wpdb
1042
-     * @param string $state_name
1043
-     * @return array where keys are columns, values are column values
1044
-     */
1045
-    public function get_or_create_state($state_name, $country_name = '')
1046
-    {
1047
-        if ( ! $state_name) {
1048
-            throw new EE_Error(esc_html__("Could not get-or-create state because no state name was provided",
1049
-                    "event_espresso"));
1050
-        }
1051
-        try {
1052
-            $country = $this->get_or_create_country($country_name);
1053
-            $country_iso = $country['CNT_ISO'];
1054
-        } catch (EE_Error $e) {
1055
-            $country_iso = $this->get_default_country_iso();
1056
-        }
1057
-        global $wpdb;
1058
-        $state_table = $wpdb->prefix . "esp_state";
1059
-        $state = $wpdb->get_row($wpdb->prepare("SELECT * FROM $state_table WHERE
961
+		if ( ! $country) {
962
+			//insert a new one then
963
+			$cols_n_values = array(
964
+					'CNT_ISO'         => $this->_find_available_country_iso(2),
965
+					'CNT_ISO3'        => $this->_find_available_country_iso(3),
966
+					'RGN_ID'          => 0,
967
+					'CNT_name'        => $country_name,
968
+					'CNT_cur_code'    => 'USD',
969
+					'CNT_cur_single'  => 'Dollar',
970
+					'CNT_cur_plural'  => 'Dollars',
971
+					'CNT_cur_sign'    => '&#36;',
972
+					'CNT_cur_sign_b4' => true,
973
+					'CNT_cur_dec_plc' => 2,
974
+					'CNT_cur_dec_mrk' => '.',
975
+					'CNT_cur_thsnds'  => ',',
976
+					'CNT_tel_code'    => '+1',
977
+					'CNT_is_EU'       => false,
978
+					'CNT_active'      => true,
979
+			);
980
+			$data_types = array(
981
+					'%s',//CNT_ISO
982
+					'%s',//CNT_ISO3
983
+					'%d',//RGN_ID
984
+					'%s',//CNT_name
985
+					'%s',//CNT_cur_code
986
+					'%s',//CNT_cur_single
987
+					'%s',//CNT_cur_plural
988
+					'%s',//CNT_cur_sign
989
+					'%d',//CNT_cur_sign_b4
990
+					'%d',//CNT_cur_dec_plc
991
+					'%s',//CNT_cur_dec_mrk
992
+					'%s',//CNT_cur_thsnds
993
+					'%s',//CNT_tel_code
994
+					'%d',//CNT_is_EU
995
+					'%d',//CNT_active
996
+			);
997
+			$success = $wpdb->insert($country_table,
998
+					$cols_n_values,
999
+					$data_types);
1000
+			if ( ! $success) {
1001
+				throw new EE_Error($this->_create_error_message_for_db_insertion('N/A',
1002
+						array('country_id' => $country_name), $country_table, $cols_n_values, $data_types));
1003
+			}
1004
+			$country = $cols_n_values;
1005
+		}
1006
+		return $country;
1007
+	}
1008
+
1009
+
1010
+
1011
+	/**
1012
+	 * finds a country iso which hasnt been used yet
1013
+	 *
1014
+	 * @global type $wpdb
1015
+	 * @return string
1016
+	 */
1017
+	private function _find_available_country_iso($num_letters = 2)
1018
+	{
1019
+		global $wpdb;
1020
+		$country_table = $wpdb->prefix . "esp_country";
1021
+		$attempts = 0;
1022
+		do {
1023
+			$current_iso = strtoupper(wp_generate_password($num_letters, false));
1024
+			$country_with_that_iso = $wpdb->get_var($wpdb->prepare("SELECT count(CNT_ISO) FROM "
1025
+																   . $country_table
1026
+																   . " WHERE CNT_ISO=%s", $current_iso));
1027
+			$attempts++;
1028
+			//keep going until we find an available country code, or we arbitrarily
1029
+			//decide we've tried this enough. Somehow they have way too many countries
1030
+			//(probably because they're mis-using the EE3 country_id like a custom question)
1031
+		} while (intval($country_with_that_iso) && $attempts < 200);
1032
+		return $current_iso;
1033
+	}
1034
+
1035
+
1036
+
1037
+	/**
1038
+	 * Gets a state entry as an array, or creates one if none is found. Much like EEM_State::instance()->get_one(), but
1039
+	 * is independent of outside code which can change in future versions of EE
1040
+	 *
1041
+	 * @global type  $wpdb
1042
+	 * @param string $state_name
1043
+	 * @return array where keys are columns, values are column values
1044
+	 */
1045
+	public function get_or_create_state($state_name, $country_name = '')
1046
+	{
1047
+		if ( ! $state_name) {
1048
+			throw new EE_Error(esc_html__("Could not get-or-create state because no state name was provided",
1049
+					"event_espresso"));
1050
+		}
1051
+		try {
1052
+			$country = $this->get_or_create_country($country_name);
1053
+			$country_iso = $country['CNT_ISO'];
1054
+		} catch (EE_Error $e) {
1055
+			$country_iso = $this->get_default_country_iso();
1056
+		}
1057
+		global $wpdb;
1058
+		$state_table = $wpdb->prefix . "esp_state";
1059
+		$state = $wpdb->get_row($wpdb->prepare("SELECT * FROM $state_table WHERE
1060 1060
 			(STA_abbrev LIKE %s OR
1061 1061
 			STA_name LIKE %s) AND
1062 1062
 			CNT_ISO LIKE %s LIMIT 1", $state_name, $state_name, $country_iso), ARRAY_A);
1063
-        if ( ! $state) {
1064
-            //insert a new one then
1065
-            $cols_n_values = array(
1066
-                    'CNT_ISO'    => $country_iso,
1067
-                    'STA_abbrev' => substr($state_name, 0, 6),
1068
-                    'STA_name'   => $state_name,
1069
-                    'STA_active' => true,
1070
-            );
1071
-            $data_types = array(
1072
-                    '%s',//CNT_ISO
1073
-                    '%s',//STA_abbrev
1074
-                    '%s',//STA_name
1075
-                    '%d',//STA_active
1076
-            );
1077
-            $success = $wpdb->insert($state_table, $cols_n_values, $data_types);
1078
-            if ( ! $success) {
1079
-                throw new EE_Error($this->_create_error_message_for_db_insertion('N/A',
1080
-                        array('state' => $state_name, 'country_id' => $country_name), $state_table, $cols_n_values,
1081
-                        $data_types));
1082
-            }
1083
-            $state = $cols_n_values;
1084
-            $state['STA_ID'] = $wpdb->insert_id;
1085
-        }
1086
-        return $state;
1087
-    }
1088
-
1089
-
1090
-
1091
-    /**
1092
-     * Fixes times like "5:00 PM" into the expected 24-hour format "17:00".
1093
-     * THis is actually just copied from the 3.1 JSON API because it needed to do the exact same thing
1094
-     *
1095
-     * @param type $timeString
1096
-     * @return string in the php DATETIME format: "G:i" (24-hour format hour with leading zeros, a colon, and minutes
1097
-     *                with leading zeros)
1098
-     */
1099
-    public function convertTimeFromAMPM($timeString)
1100
-    {
1101
-        $matches = array();
1102
-        preg_match("~(\\d*):(\\d*)~", $timeString, $matches);
1103
-        if ( ! $matches || count($matches) < 3) {
1104
-            $hour = '00';
1105
-            $minutes = '00';
1106
-        } else {
1107
-            $hour = intval($matches[1]);
1108
-            $minutes = $matches[2];
1109
-        }
1110
-        if (strpos($timeString, 'PM') || strpos($timeString, 'pm')) {
1111
-            $hour = intval($hour) + 12;
1112
-        }
1113
-        $hour = str_pad("$hour", 2, '0', STR_PAD_LEFT);
1114
-        $minutes = str_pad("$minutes", 2, '0', STR_PAD_LEFT);
1115
-        return "$hour:$minutes";
1116
-    }
1117
-
1118
-
1119
-
1120
-    /**
1121
-     * Gets the ISO3 fora country given its 3.1 country ID.
1122
-     *
1123
-     * @param int $country_id
1124
-     * @return string the country's ISO3 code
1125
-     */
1126
-    public function get_iso_from_3_1_country_id($country_id)
1127
-    {
1128
-        $old_countries = array(
1129
-                array(64, 'United States', 'US', 'USA', 1),
1130
-                array(15, 'Australia', 'AU', 'AUS', 1),
1131
-                array(39, 'Canada', 'CA', 'CAN', 1),
1132
-                array(171, 'United Kingdom', 'GB', 'GBR', 1),
1133
-                array(70, 'France', 'FR', 'FRA', 2),
1134
-                array(111, 'Italy', 'IT', 'ITA', 2),
1135
-                array(63, 'Spain', 'ES', 'ESP', 2),
1136
-                array(1, 'Afghanistan', 'AF', 'AFG', 1),
1137
-                array(2, 'Albania', 'AL', 'ALB', 1),
1138
-                array(3, 'Germany', 'DE', 'DEU', 2),
1139
-                array(198, 'Switzerland', 'CH', 'CHE', 1),
1140
-                array(87, 'Netherlands', 'NL', 'NLD', 2),
1141
-                array(197, 'Sweden', 'SE', 'SWE', 1),
1142
-                array(230, 'Akrotiri and Dhekelia', 'CY', 'CYP', 2),
1143
-                array(4, 'Andorra', 'AD', 'AND', 2),
1144
-                array(5, 'Angola', 'AO', 'AGO', 1),
1145
-                array(6, 'Anguilla', 'AI', 'AIA', 1),
1146
-                array(7, 'Antarctica', 'AQ', 'ATA', 1),
1147
-                array(8, 'Antigua and Barbuda', 'AG', 'ATG', 1),
1148
-                array(10, 'Saudi Arabia', 'SA', 'SAU', 1),
1149
-                array(11, 'Algeria', 'DZ', 'DZA', 1),
1150
-                array(12, 'Argentina', 'AR', 'ARG', 1),
1151
-                array(13, 'Armenia', 'AM', 'ARM', 1),
1152
-                array(14, 'Aruba', 'AW', 'ABW', 1),
1153
-                array(16, 'Austria', 'AT', 'AUT', 2),
1154
-                array(17, 'Azerbaijan', 'AZ', 'AZE', 1),
1155
-                array(18, 'Bahamas', 'BS', 'BHS', 1),
1156
-                array(19, 'Bahrain', 'BH', 'BHR', 1),
1157
-                array(20, 'Bangladesh', 'BD', 'BGD', 1),
1158
-                array(21, 'Barbados', 'BB', 'BRB', 1),
1159
-                array(22, 'Belgium ', 'BE', 'BEL', 2),
1160
-                array(23, 'Belize', 'BZ', 'BLZ', 1),
1161
-                array(24, 'Benin', 'BJ', 'BEN', 1),
1162
-                array(25, 'Bermudas', 'BM', 'BMU', 1),
1163
-                array(26, 'Belarus', 'BY', 'BLR', 1),
1164
-                array(27, 'Bolivia', 'BO', 'BOL', 1),
1165
-                array(28, 'Bosnia and Herzegovina', 'BA', 'BIH', 1),
1166
-                array(29, 'Botswana', 'BW', 'BWA', 1),
1167
-                array(96, 'Bouvet Island', 'BV', 'BVT', 1),
1168
-                array(30, 'Brazil', 'BR', 'BRA', 1),
1169
-                array(31, 'Brunei', 'BN', 'BRN', 1),
1170
-                array(32, 'Bulgaria', 'BG', 'BGR', 1),
1171
-                array(33, 'Burkina Faso', 'BF', 'BFA', 1),
1172
-                array(34, 'Burundi', 'BI', 'BDI', 1),
1173
-                array(35, 'Bhutan', 'BT', 'BTN', 1),
1174
-                array(36, 'Cape Verde', 'CV', 'CPV', 1),
1175
-                array(37, 'Cambodia', 'KH', 'KHM', 1),
1176
-                array(38, 'Cameroon', 'CM', 'CMR', 1),
1177
-                array(98, 'Cayman Islands', 'KY', 'CYM', 1),
1178
-                array(172, 'Central African Republic', 'CF', 'CAF', 1),
1179
-                array(40, 'Chad', 'TD', 'TCD', 1),
1180
-                array(41, 'Chile', 'CL', 'CHL', 1),
1181
-                array(42, 'China', 'CN', 'CHN', 1),
1182
-                array(105, 'Christmas Island', 'CX', 'CXR', 1),
1183
-                array(43, 'Cyprus', 'CY', 'CYP', 2),
1184
-                array(99, 'Cocos Island', 'CC', 'CCK', 1),
1185
-                array(100, 'Cook Islands', 'CK', 'COK', 1),
1186
-                array(44, 'Colombia', 'CO', 'COL', 1),
1187
-                array(45, 'Comoros', 'KM', 'COM', 1),
1188
-                array(46, 'Congo', 'CG', 'COG', 1),
1189
-                array(47, 'North Korea', 'KP', 'PRK', 1),
1190
-                array(50, 'Costa Rica', 'CR', 'CRI', 1),
1191
-                array(51, 'Croatia', 'HR', 'HRV', 1),
1192
-                array(52, 'Cuba', 'CU', 'CUB', 1),
1193
-                array(173, 'Czech Republic', 'CZ', 'CZE', 1),
1194
-                array(53, 'Denmark', 'DK', 'DNK', 1),
1195
-                array(54, 'Djibouti', 'DJ', 'DJI', 1),
1196
-                array(55, 'Dominica', 'DM', 'DMA', 1),
1197
-                array(174, 'Dominican Republic', 'DO', 'DOM', 1),
1198
-                array(56, 'Ecuador', 'EC', 'ECU', 1),
1199
-                array(57, 'Egypt', 'EG', 'EGY', 1),
1200
-                array(58, 'El Salvador', 'SV', 'SLV', 1),
1201
-                array(60, 'Eritrea', 'ER', 'ERI', 1),
1202
-                array(61, 'Slovakia', 'SK', 'SVK', 2),
1203
-                array(62, 'Slovenia', 'SI', 'SVN', 2),
1204
-                array(65, 'Estonia', 'EE', 'EST', 2),
1205
-                array(66, 'Ethiopia', 'ET', 'ETH', 1),
1206
-                array(102, 'Faroe islands', 'FO', 'FRO', 1),
1207
-                array(103, 'Falkland Islands', 'FK', 'FLK', 1),
1208
-                array(67, 'Fiji', 'FJ', 'FJI', 1),
1209
-                array(69, 'Finland', 'FI', 'FIN', 2),
1210
-                array(71, 'Gabon', 'GA', 'GAB', 1),
1211
-                array(72, 'Gambia', 'GM', 'GMB', 1),
1212
-                array(73, 'Georgia', 'GE', 'GEO', 1),
1213
-                array(74, 'Ghana', 'GH', 'GHA', 1),
1214
-                array(75, 'Gibraltar', 'GI', 'GIB', 1),
1215
-                array(76, 'Greece', 'GR', 'GRC', 2),
1216
-                array(77, 'Grenada', 'GD', 'GRD', 1),
1217
-                array(78, 'Greenland', 'GL', 'GRL', 1),
1218
-                array(79, 'Guadeloupe', 'GP', 'GLP', 1),
1219
-                array(80, 'Guam', 'GU', 'GUM', 1),
1220
-                array(81, 'Guatemala', 'GT', 'GTM', 1),
1221
-                array(82, 'Guinea', 'GN', 'GIN', 1),
1222
-                array(83, 'Equatorial Guinea', 'GQ', 'GNQ', 1),
1223
-                array(84, 'Guinea-Bissau', 'GW', 'GNB', 1),
1224
-                array(85, 'Guyana', 'GY', 'GUY', 1),
1225
-                array(86, 'Haiti', 'HT', 'HTI', 1),
1226
-                array(88, 'Honduras', 'HN', 'HND', 1),
1227
-                array(89, 'Hong Kong', 'HK', 'HKG', 1),
1228
-                array(90, 'Hungary', 'HU', 'HUN', 1),
1229
-                array(91, 'India', 'IN', 'IND', 1),
1230
-                array(205, 'British Indian Ocean Territory', 'IO', 'IOT', 1),
1231
-                array(92, 'Indonesia', 'ID', 'IDN', 1),
1232
-                array(93, 'Iraq', 'IQ', 'IRQ', 1),
1233
-                array(94, 'Iran', 'IR', 'IRN', 1),
1234
-                array(95, 'Ireland', 'IE', 'IRL', 2),
1235
-                array(97, 'Iceland', 'IS', 'ISL', 1),
1236
-                array(110, 'Israel', 'IL', 'ISR', 1),
1237
-                array(49, 'Ivory Coast ', 'CI', 'CIV', 1),
1238
-                array(112, 'Jamaica', 'JM', 'JAM', 1),
1239
-                array(113, 'Japan', 'JP', 'JPN', 1),
1240
-                array(114, 'Jordan', 'JO', 'JOR', 1),
1241
-                array(115, 'Kazakhstan', 'KZ', 'KAZ', 1),
1242
-                array(116, 'Kenya', 'KE', 'KEN', 1),
1243
-                array(117, 'Kyrgyzstan', 'KG', 'KGZ', 1),
1244
-                array(118, 'Kiribati', 'KI', 'KIR', 1),
1245
-                array(48, 'South Korea', 'KR', 'KOR', 1),
1246
-                array(228, 'Kosovo', 'XK', 'XKV', 2),
1247
-                // there is no official ISO code for Kosovo yet (http://geonames.wordpress.com/2010/03/08/xk-country-code-for-kosovo/) so using a temporary country code and a modified 3 character code for ISO code -- this should be updated if/when Kosovo gets its own ISO code
1248
-                array(119, 'Kuwait', 'KW', 'KWT', 1),
1249
-                array(120, 'Laos', 'LA', 'LAO', 1),
1250
-                array(121, 'Latvia', 'LV', 'LVA', 2),
1251
-                array(122, 'Lesotho', 'LS', 'LSO', 1),
1252
-                array(123, 'Lebanon', 'LB', 'LBN', 1),
1253
-                array(124, 'Liberia', 'LR', 'LBR', 1),
1254
-                array(125, 'Libya', 'LY', 'LBY', 1),
1255
-                array(126, 'Liechtenstein', 'LI', 'LIE', 1),
1256
-                array(127, 'Lithuania', 'LT', 'LTU', 2),
1257
-                array(128, 'Luxemburg', 'LU', 'LUX', 2),
1258
-                array(129, 'Macao', 'MO', 'MAC', 1),
1259
-                array(130, 'Macedonia', 'MK', 'MKD', 1),
1260
-                array(131, 'Madagascar', 'MG', 'MDG', 1),
1261
-                array(132, 'Malaysia', 'MY', 'MYS', 1),
1262
-                array(133, 'Malawi', 'MW', 'MWI', 1),
1263
-                array(134, 'Maldivas', 'MV', 'MDV', 1),
1264
-                array(135, 'Mali', 'ML', 'MLI', 1),
1265
-                array(136, 'Malta', 'MT', 'MLT', 2),
1266
-                array(101, 'Northern Marianas', 'MP', 'MNP', 1),
1267
-                array(137, 'Morocco', 'MA', 'MAR', 1),
1268
-                array(104, 'Marshall islands', 'MH', 'MHL', 1),
1269
-                array(138, 'Martinique', 'MQ', 'MTQ', 1),
1270
-                array(139, 'Mauritius', 'MU', 'MUS', 1),
1271
-                array(140, 'Mauritania', 'MR', 'MRT', 1),
1272
-                array(141, 'Mayote', 'YT', 'MYT', 2),
1273
-                array(142, 'Mexico', 'MX', 'MEX', 1),
1274
-                array(143, 'Micronesia', 'FM', 'FSM', 1),
1275
-                array(144, 'Moldova', 'MD', 'MDA', 1),
1276
-                array(145, 'Monaco', 'MC', 'MCO', 2),
1277
-                array(146, 'Mongolia', 'MN', 'MNG', 1),
1278
-                array(147, 'Montserrat', 'MS', 'MSR', 1),
1279
-                array(227, 'Montenegro', 'ME', 'MNE', 2),
1280
-                array(148, 'Mozambique', 'MZ', 'MOZ', 1),
1281
-                array(149, 'Myanmar', 'MM', 'MMR', 1),
1282
-                array(150, 'Namibia', 'NA', 'NAM', 1),
1283
-                array(151, 'Nauru', 'NR', 'NRU', 1),
1284
-                array(152, 'Nepal', 'NP', 'NPL', 1),
1285
-                array(9, 'Netherlands Antilles', 'AN', 'ANT', 1),
1286
-                array(153, 'Nicaragua', 'NI', 'NIC', 1),
1287
-                array(154, 'Niger', 'NE', 'NER', 1),
1288
-                array(155, 'Nigeria', 'NG', 'NGA', 1),
1289
-                array(156, 'Niue', 'NU', 'NIU', 1),
1290
-                array(157, 'Norway', 'NO', 'NOR', 1),
1291
-                array(158, 'New Caledonia', 'NC', 'NCL', 1),
1292
-                array(159, 'New Zealand', 'NZ', 'NZL', 1),
1293
-                array(160, 'Oman', 'OM', 'OMN', 1),
1294
-                array(161, 'Pakistan', 'PK', 'PAK', 1),
1295
-                array(162, 'Palau', 'PW', 'PLW', 1),
1296
-                array(163, 'Panama', 'PA', 'PAN', 1),
1297
-                array(164, 'Papua New Guinea', 'PG', 'PNG', 1),
1298
-                array(165, 'Paraguay', 'PY', 'PRY', 1),
1299
-                array(166, 'Peru', 'PE', 'PER', 1),
1300
-                array(68, 'Philippines', 'PH', 'PHL', 1),
1301
-                array(167, 'Poland', 'PL', 'POL', 1),
1302
-                array(168, 'Portugal', 'PT', 'PRT', 2),
1303
-                array(169, 'Puerto Rico', 'PR', 'PRI', 1),
1304
-                array(170, 'Qatar', 'QA', 'QAT', 1),
1305
-                array(176, 'Rwanda', 'RW', 'RWA', 1),
1306
-                array(177, 'Romania', 'RO', 'ROM', 2),
1307
-                array(178, 'Russia', 'RU', 'RUS', 1),
1308
-                array(229, 'Saint Pierre and Miquelon', 'PM', 'SPM', 2),
1309
-                array(180, 'Samoa', 'WS', 'WSM', 1),
1310
-                array(181, 'American Samoa', 'AS', 'ASM', 1),
1311
-                array(183, 'San Marino', 'SM', 'SMR', 2),
1312
-                array(184, 'Saint Vincent and the Grenadines', 'VC', 'VCT', 1),
1313
-                array(185, 'Saint Helena', 'SH', 'SHN', 1),
1314
-                array(186, 'Saint Lucia', 'LC', 'LCA', 1),
1315
-                array(188, 'Senegal', 'SN', 'SEN', 1),
1316
-                array(189, 'Seychelles', 'SC', 'SYC', 1),
1317
-                array(190, 'Sierra Leona', 'SL', 'SLE', 1),
1318
-                array(191, 'Singapore', 'SG', 'SGP', 1),
1319
-                array(192, 'Syria', 'SY', 'SYR', 1),
1320
-                array(193, 'Somalia', 'SO', 'SOM', 1),
1321
-                array(194, 'Sri Lanka', 'LK', 'LKA', 1),
1322
-                array(195, 'South Africa', 'ZA', 'ZAF', 1),
1323
-                array(196, 'Sudan', 'SD', 'SDN', 1),
1324
-                array(199, 'Suriname', 'SR', 'SUR', 1),
1325
-                array(200, 'Swaziland', 'SZ', 'SWZ', 1),
1326
-                array(201, 'Thailand', 'TH', 'THA', 1),
1327
-                array(202, 'Taiwan', 'TW', 'TWN', 1),
1328
-                array(203, 'Tanzania', 'TZ', 'TZA', 1),
1329
-                array(204, 'Tajikistan', 'TJ', 'TJK', 1),
1330
-                array(206, 'Timor-Leste', 'TL', 'TLS', 1),
1331
-                array(207, 'Togo', 'TG', 'TGO', 1),
1332
-                array(208, 'Tokelau', 'TK', 'TKL', 1),
1333
-                array(209, 'Tonga', 'TO', 'TON', 1),
1334
-                array(210, 'Trinidad and Tobago', 'TT', 'TTO', 1),
1335
-                array(211, 'Tunisia', 'TN', 'TUN', 1),
1336
-                array(212, 'Turkmenistan', 'TM', 'TKM', 1),
1337
-                array(213, 'Turkey', 'TR', 'TUR', 1),
1338
-                array(214, 'Tuvalu', 'TV', 'TUV', 1),
1339
-                array(215, 'Ukraine', 'UA', 'UKR', 1),
1340
-                array(216, 'Uganda', 'UG', 'UGA', 1),
1341
-                array(59, 'United Arab Emirates', 'AE', 'ARE', 1),
1342
-                array(217, 'Uruguay', 'UY', 'URY', 1),
1343
-                array(218, 'Uzbekistan', 'UZ', 'UZB', 1),
1344
-                array(219, 'Vanuatu', 'VU', 'VUT', 1),
1345
-                array(220, 'Vatican City', 'VA', 'VAT', 2),
1346
-                array(221, 'Venezuela', 'VE', 'VEN', 1),
1347
-                array(222, 'Vietnam', 'VN', 'VNM', 1),
1348
-                array(108, 'Virgin Islands', 'VI', 'VIR', 1),
1349
-                array(223, 'Yemen', 'YE', 'YEM', 1),
1350
-                array(225, 'Zambia', 'ZM', 'ZMB', 1),
1351
-                array(226, 'Zimbabwe', 'ZW', 'ZWE', 1),
1352
-        );
1353
-        $country_iso = 'US';
1354
-        foreach ($old_countries as $country_array) {
1355
-            //note: index 0 is the 3.1 country ID
1356
-            if ($country_array[0] == $country_id) {
1357
-                //note: index 2 is the ISO
1358
-                $country_iso = $country_array[2];
1359
-                break;
1360
-            }
1361
-        }
1362
-        return $country_iso;
1363
-    }
1364
-
1365
-
1366
-
1367
-    /**
1368
-     * Gets the ISO3 for the
1369
-     *
1370
-     * @return string
1371
-     */
1372
-    public function get_default_country_iso()
1373
-    {
1374
-        $old_org_options = get_option('events_organization_settings');
1375
-        $iso = $this->get_iso_from_3_1_country_id($old_org_options['organization_country']);
1376
-        return $iso;
1377
-    }
1378
-
1379
-
1380
-
1381
-    /**
1382
-     * Converst a 3.1 payment status to its equivalent 4.1 regisration status
1383
-     *
1384
-     * @param string  $payment_status                   possible value for 3.1's evens_attendee.payment_status
1385
-     * @param boolean $this_thing_required_pre_approval whether the thing we're considering (the general setting's
1386
-     *                                                  DEFAULT payment status, the event's DEFAULT payment status, or
1387
-     *                                                  the attendee's payment status) required pre-approval.
1388
-     * @return string STS_ID for use in 4.1
1389
-     */
1390
-    public function convert_3_1_payment_status_to_4_1_STS_ID($payment_status, $this_thing_required_pre_approval = false)
1391
-    {
1392
-        //EE team can read the related discussion: https://app.asana.com/0/2400967562914/9418495544455
1393
-        if ($this_thing_required_pre_approval) {
1394
-            return 'RNA';
1395
-        } else {
1396
-            $mapping = $default_reg_stati_conversions = array(
1397
-                    'Completed'        => 'RAP',
1398
-                    ''                 => 'RPP',
1399
-                    'Incomplete'       => 'RPP',
1400
-                    'Pending'          => 'RAP',
1401
-                    //stati that only occurred on 3.1 attendees:
1402
-                    'Payment Declined' => 'RPP',
1403
-                    'Not Completed'    => 'RPP',
1404
-                    'Cancelled'        => 'RPP',
1405
-                    'Declined'         => 'RPP',
1406
-            );
1407
-        }
1408
-        return isset($mapping[$payment_status]) ? $mapping[$payment_status] : 'RNA';
1409
-    }
1410
-
1411
-
1412
-
1413
-    /**
1414
-     * Makes sure the 3.1's image url is converted to an image attachment post to the 4.1 CPT event
1415
-     * and sets it as the featured image on the CPT event
1416
-     *
1417
-     * @param type                            $old_event
1418
-     * @param type                            $new_cpt_id
1419
-     * @param  EE_Data_Migration_Script_Stage $migration_stage the stage which called this, where errors should be added
1420
-     * @return boolean whether or not we had to do the big job of creating an image attachment
1421
-     */
1422
-    public function convert_image_url_to_attachment_and_attach_to_post(
1423
-            $guid,
1424
-            $new_cpt_id,
1425
-            EE_Data_Migration_Script_Stage $migration_stage
1426
-    ) {
1427
-        $created_attachment_post = false;
1428
-        $guid = $this->_get_original_guid($guid);
1429
-        if ($guid) {
1430
-            //check for an existing attachment post with this guid
1431
-            $attachment_post_id = $this->_get_image_attachment_id_by_GUID($guid);
1432
-            if ( ! $attachment_post_id) {
1433
-                //post thumbnail with that GUID doesn't exist, we should create one
1434
-                $attachment_post_id = $this->_create_image_attachment_from_GUID($guid, $migration_stage);
1435
-                $created_attachment_post = true;
1436
-            }
1437
-            //double-check we actually have an attachment post
1438
-            if ($attachment_post_id) {
1439
-                update_post_meta($new_cpt_id, '_thumbnail_id', $attachment_post_id);
1440
-            } else {
1441
-                $migration_stage->add_error(sprintf(esc_html__("Could not update event image %s for CPT with ID %d, but attachments post ID is %d",
1442
-                        "event_espresso"), $guid, $new_cpt_id, $attachment_post_id));
1443
-            }
1444
-        }
1445
-        return $created_attachment_post;
1446
-    }
1447
-
1448
-
1449
-
1450
-    /**
1451
-     * In 3.1, the event thumbnail image DOESN'T point to the orignal image, but instead
1452
-     * to a large thumbnail (which has nearly the same GUID, except it adds "-{width}x{height}" before the filetype,
1453
-     * or whatever dimensions it is. Eg 'http://mysite.com/image1-300x400.jpg' instead of
1454
-     * 'http://mysite.com/image1.jpg' ). This function attempts to strip that off and get the original file, if it
1455
-     * exists
1456
-     *
1457
-     * @param string $guid_in_old_event
1458
-     * @return string either the original guid, or $guid_in_old_event if we couldn't figure out what the original was
1459
-     */
1460
-    private function _get_original_guid($guid_in_old_event)
1461
-    {
1462
-        $original_guid = preg_replace('~-\d*x\d*\.~', '.', $guid_in_old_event, 1);
1463
-        //do a head request to verify the file exists
1464
-        $head_response = wp_remote_head($original_guid);
1465
-        if ( ! $head_response instanceof WP_Error && $head_response['response']['message'] == 'OK') {
1466
-            return $original_guid;
1467
-        } else {
1468
-            return $guid_in_old_event;
1469
-        }
1470
-    }
1471
-
1472
-
1473
-
1474
-    /**
1475
-     * Creates an image attachment post for the GUID. If the GUID points to a remote image,
1476
-     * we download it to our uploads directory so that it can be properly processed (eg, creates different sizes of
1477
-     * thumbnails)
1478
-     *
1479
-     * @param type                           $guid
1480
-     * @param EE_Data_Migration_Script_Stage $migration_stage
1481
-     * @return int
1482
-     */
1483
-    private function _create_image_attachment_from_GUID($guid, EE_Data_Migration_Script_Stage $migration_stage)
1484
-    {
1485
-        if ( ! $guid) {
1486
-            $migration_stage->add_error(sprintf(esc_html__("Cannot create image attachment for a blank GUID!",
1487
-                    "event_espresso")));
1488
-            return 0;
1489
-        }
1490
-        $wp_filetype = wp_check_filetype(basename($guid), null);
1491
-        $wp_upload_dir = wp_upload_dir();
1492
-        //if the file is located remotely, download it to our uploads DIR, because wp_genereate_attachmnet_metadata needs the file to be local
1493
-        if (strpos($guid, $wp_upload_dir['url']) === false) {
1494
-            //image is located remotely. download it and place it in the uploads directory
1495
-            if ( ! is_readable($guid)) {
1496
-                $migration_stage->add_error(sprintf(esc_html__("Could not create image attachment from non-existent file: %s",
1497
-                        "event_espresso"), $guid));
1498
-                return 0;
1499
-            }
1500
-            $contents = file_get_contents($guid);
1501
-            if ($contents === false) {
1502
-                $migration_stage->add_error(sprintf(esc_html__("Could not read image at %s, and therefore couldnt create an attachment post for it.",
1503
-                        "event_espresso"), $guid));
1504
-                return false;
1505
-            }
1506
-            $local_filepath = $wp_upload_dir['path'] . DS . basename($guid);
1507
-            $savefile = fopen($local_filepath, 'w');
1508
-            fwrite($savefile, $contents);
1509
-            fclose($savefile);
1510
-            $guid = str_replace($wp_upload_dir['path'], $wp_upload_dir['url'], $local_filepath);
1511
-        } else {
1512
-            $local_filepath = str_replace($wp_upload_dir['url'], $wp_upload_dir['path'], $guid);
1513
-        }
1514
-        $attachment = array(
1515
-                'guid'           => $guid,
1516
-                'post_mime_type' => $wp_filetype['type'],
1517
-                'post_title'     => preg_replace('/\.[^.]+$/', '', basename($guid)),
1518
-                'post_content'   => '',
1519
-                'post_status'    => 'inherit',
1520
-        );
1521
-        $attach_id = wp_insert_attachment($attachment, $guid);
1522
-        if ( ! $attach_id) {
1523
-            $migration_stage->add_error(sprintf(esc_html__("Could not create image attachment post from image '%s'. Attachment data was %s.",
1524
-                    "event_espresso"), $guid, $this->_json_encode($attachment)));
1525
-            return $attach_id;
1526
-        }
1527
-        // you must first include the image.php file
1528
-        // for the function wp_generate_attachment_metadata() to work
1529
-        require_once(ABSPATH . 'wp-admin/includes/image.php');
1530
-        $attach_data = wp_generate_attachment_metadata($attach_id, $local_filepath);
1531
-        if ( ! $attach_data) {
1532
-            $migration_stage->add_error(sprintf(esc_html__("Coudl not genereate attachment metadata for attachment post %d with filepath %s and GUID %s. Please check the file was downloaded properly.",
1533
-                    "event_espresso"), $attach_id, $local_filepath, $guid));
1534
-            return $attach_id;
1535
-        }
1536
-        $metadata_save_result = wp_update_attachment_metadata($attach_id, $attach_data);
1537
-        if ( ! $metadata_save_result) {
1538
-            $migration_stage->add_error(sprintf(esc_html__("Could not update attachment metadata for attachment %d with data %s",
1539
-                    "event_espresso"), $attach_id, $this->_json_encode($attach_data)));
1540
-        }
1541
-        return $attach_id;
1542
-    }
1543
-
1544
-
1545
-
1546
-    /**
1547
-     * Finds the attachment post containing info about an image attachment given the GUID (link to the image itself),
1548
-     * and returns its ID.
1549
-     *
1550
-     * @global type  $wpdb
1551
-     * @param string $guid
1552
-     * @return int
1553
-     */
1554
-    private function _get_image_attachment_id_by_GUID($guid)
1555
-    {
1556
-        global $wpdb;
1557
-        $attachment_id = $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid=%s LIMIT 1", $guid));
1558
-        return $attachment_id;
1559
-    }
1560
-
1561
-
1562
-
1563
-    /**
1564
-     * Returns a mysql-formatted DATETIME in UTC time, given a $DATETIME_string
1565
-     * (and optionally a timezone; if none is given, the wp DEFAULT is used)
1566
-     *
1567
-     * @param EE_Data_Migration_Script_base $stage
1568
-     * @param array                         $row_of_data , the row from the DB (as an array) we're trying to find the
1569
-     *                                                   UTC time for
1570
-     * @param string                        $DATETIME_string
1571
-     * @param string                        $timezone
1572
-     * @return string
1573
-     */
1574
-    public function convert_date_string_to_utc(
1575
-            EE_Data_Migration_Script_Stage $stage,
1576
-            $row_of_data,
1577
-            $DATETIME_string,
1578
-            $timezone = null
1579
-    ) {
1580
-        $original_tz = $timezone;
1581
-        if ( ! $timezone) {
1582
-            $timezone = $this->_get_wp_timezone();
1583
-        }
1584
-        if ( ! $timezone) {
1585
-            $stage->add_error(sprintf(esc_html__("Could not find timezone given %s for %s", "event_espresso"), $original_tz,
1586
-                    $row_of_data));
1587
-            $timezone = 'UTC';
1588
-        }
1589
-        try {
1590
-            $date_obj = new DateTime($DATETIME_string, new DateTimeZone($timezone));
1591
-            EEH_DTT_Helper::setTimezone($date_obj, new DateTimeZone('UTC'));
1592
-        } catch (Exception $e) {
1593
-            $stage->add_error(sprintf(esc_html__("Could not convert time string '%s' using timezone '%s' into a proper DATETIME. Using current time instead.",
1594
-                    "event_espresso"), $DATETIME_string, $timezone));
1595
-            $date_obj = new DateTime();
1596
-        }
1597
-        return $date_obj->format('Y-m-d H:i:s');
1598
-    }
1599
-
1600
-
1601
-
1602
-    /**
1603
-     * Gets the DEFAULT timezone string from wordpress (even if they set a gmt offset)
1604
-     *
1605
-     * @return string
1606
-     */
1607
-    private function _get_wp_timezone()
1608
-    {
1609
-        $timezone = empty($timezone) ? get_option('timezone_string') : $timezone;
1610
-        //if timezone is STILL empty then let's get the GMT offset and then set the timezone_string using our converter
1611
-        if (empty($timezone)) {
1612
-            //let's get a the WordPress UTC offset
1613
-            $offset = get_option('gmt_offset');
1614
-            $timezone = $this->timezone_convert_to_string_from_offset($offset);
1615
-        }
1616
-        return $timezone;
1617
-    }
1618
-
1619
-
1620
-
1621
-    /**
1622
-     * Gets the wordpress timezone string from a UTC offset
1623
-     *
1624
-     * @param int $offset
1625
-     * @return boolean
1626
-     */
1627
-    private function timezone_convert_to_string_from_offset($offset)
1628
-    {
1629
-        //shamelessly taken from bottom comment at http://ca1.php.net/manual/en/function.timezone-name-from-abbr.php because timezone_name_from_abbr() did NOT work as expected - its not reliable
1630
-        $offset *= 3600; // convert hour offset to seconds
1631
-        $abbrarray = timezone_abbreviations_list();
1632
-        foreach ($abbrarray as $abbr) {
1633
-            foreach ($abbr as $city) {
1634
-                if ($city['offset'] == $offset) {
1635
-                    return $city['timezone_id'];
1636
-                }
1637
-            }
1638
-        }
1639
-        return false;
1640
-    }
1641
-
1642
-
1643
-
1644
-    public function migration_page_hooks()
1645
-    {
1646
-        add_filter(
1647
-                'FHEE__ee_migration_page__header',
1648
-                array($this, '_migrate_page_hook_simplify_version_strings'),
1649
-                10,
1650
-                3
1651
-        );
1652
-        add_filter(
1653
-                'FHEE__ee_migration_page__p_after_header',
1654
-                array($this, '_migration_page_hook_simplify_next_db_state'),
1655
-                10,
1656
-                2
1657
-        );
1658
-        add_filter(
1659
-                'FHEE__ee_migration_page__option_1_main',
1660
-                array($this, '_migrate_page_hook_simplify_version_strings'),
1661
-                10,
1662
-                3
1663
-        );
1664
-        add_filter(
1665
-                'FHEE__ee_migration_page__option_1_button_text',
1666
-                array($this, '_migrate_page_hook_simplify_version_strings'),
1667
-                10,
1668
-                3
1669
-        );
1670
-        add_action(
1671
-                'AHEE__ee_migration_page__option_1_extra_details',
1672
-                array($this, '_migration_page_hook_option_1_extra_details'),
1673
-                10,
1674
-                3
1675
-        );
1676
-        add_filter(
1677
-                'FHEE__ee_migration_page__option_2_main',
1678
-                array($this, '_migrate_page_hook_simplify_version_strings'),
1679
-                10,
1680
-                4
1681
-        );
1682
-        add_filter(
1683
-                'FHEE__ee_migration_page__option_2_button_text',
1684
-                array($this, '_migration_page_hook_simplify_next_db_state'),
1685
-                10,
1686
-                2
1687
-        );
1688
-        add_filter(
1689
-                'FHEE__ee_migration_page__option_2_details',
1690
-                array($this, '_migration_page_hook_simplify_next_db_state'),
1691
-                10,
1692
-                2
1693
-        );
1694
-        add_action(
1695
-                'AHEE__ee_migration_page__after_migration_options_table',
1696
-                array($this, '_migration_page_hook_after_migration_options_table')
1697
-        );
1698
-        add_filter(
1699
-                'FHEE__ee_migration_page__done_migration_header',
1700
-                array($this, '_migration_page_hook_simplify_next_db_state'),
1701
-                10,
1702
-                2
1703
-        );
1704
-        add_filter(
1705
-                'FHEE__ee_migration_page__p_after_done_migration_header',
1706
-                array($this, '_migration_page_hook_simplify_next_db_state'),
1707
-                10,
1708
-                2
1709
-        );
1710
-        add_filter(
1711
-                'FHEE__ee_migration_page__migration_options_template',
1712
-                array($this,'use_migration_options_from_ee3_template')
1713
-        );
1714
-    }
1715
-
1716
-
1717
-
1718
-    public function _migrate_page_hook_simplify_version_strings(
1719
-            $old_content,
1720
-            $current_db_state,
1721
-            $next_db_state,
1722
-            $ultimate_db_state = null
1723
-    ) {
1724
-        return str_replace(array($current_db_state, $next_db_state, $ultimate_db_state),
1725
-                array(esc_html__('EE3', 'event_espresso'), esc_html__('EE4', 'event_espresso'), esc_html__("EE4", 'event_espresso')),
1726
-                $old_content);
1727
-    }
1728
-
1729
-
1730
-
1731
-    public function _migration_page_hook_simplify_next_db_state($old_content, $next_db_state)
1732
-    {
1733
-        return str_replace($next_db_state, esc_html__("EE4", 'event_espresso'), $old_content);
1734
-    }
1735
-
1736
-
1737
-
1738
-    public function _migration_page_hook_option_1_extra_details()
1739
-    {
1740
-        ?>
1063
+		if ( ! $state) {
1064
+			//insert a new one then
1065
+			$cols_n_values = array(
1066
+					'CNT_ISO'    => $country_iso,
1067
+					'STA_abbrev' => substr($state_name, 0, 6),
1068
+					'STA_name'   => $state_name,
1069
+					'STA_active' => true,
1070
+			);
1071
+			$data_types = array(
1072
+					'%s',//CNT_ISO
1073
+					'%s',//STA_abbrev
1074
+					'%s',//STA_name
1075
+					'%d',//STA_active
1076
+			);
1077
+			$success = $wpdb->insert($state_table, $cols_n_values, $data_types);
1078
+			if ( ! $success) {
1079
+				throw new EE_Error($this->_create_error_message_for_db_insertion('N/A',
1080
+						array('state' => $state_name, 'country_id' => $country_name), $state_table, $cols_n_values,
1081
+						$data_types));
1082
+			}
1083
+			$state = $cols_n_values;
1084
+			$state['STA_ID'] = $wpdb->insert_id;
1085
+		}
1086
+		return $state;
1087
+	}
1088
+
1089
+
1090
+
1091
+	/**
1092
+	 * Fixes times like "5:00 PM" into the expected 24-hour format "17:00".
1093
+	 * THis is actually just copied from the 3.1 JSON API because it needed to do the exact same thing
1094
+	 *
1095
+	 * @param type $timeString
1096
+	 * @return string in the php DATETIME format: "G:i" (24-hour format hour with leading zeros, a colon, and minutes
1097
+	 *                with leading zeros)
1098
+	 */
1099
+	public function convertTimeFromAMPM($timeString)
1100
+	{
1101
+		$matches = array();
1102
+		preg_match("~(\\d*):(\\d*)~", $timeString, $matches);
1103
+		if ( ! $matches || count($matches) < 3) {
1104
+			$hour = '00';
1105
+			$minutes = '00';
1106
+		} else {
1107
+			$hour = intval($matches[1]);
1108
+			$minutes = $matches[2];
1109
+		}
1110
+		if (strpos($timeString, 'PM') || strpos($timeString, 'pm')) {
1111
+			$hour = intval($hour) + 12;
1112
+		}
1113
+		$hour = str_pad("$hour", 2, '0', STR_PAD_LEFT);
1114
+		$minutes = str_pad("$minutes", 2, '0', STR_PAD_LEFT);
1115
+		return "$hour:$minutes";
1116
+	}
1117
+
1118
+
1119
+
1120
+	/**
1121
+	 * Gets the ISO3 fora country given its 3.1 country ID.
1122
+	 *
1123
+	 * @param int $country_id
1124
+	 * @return string the country's ISO3 code
1125
+	 */
1126
+	public function get_iso_from_3_1_country_id($country_id)
1127
+	{
1128
+		$old_countries = array(
1129
+				array(64, 'United States', 'US', 'USA', 1),
1130
+				array(15, 'Australia', 'AU', 'AUS', 1),
1131
+				array(39, 'Canada', 'CA', 'CAN', 1),
1132
+				array(171, 'United Kingdom', 'GB', 'GBR', 1),
1133
+				array(70, 'France', 'FR', 'FRA', 2),
1134
+				array(111, 'Italy', 'IT', 'ITA', 2),
1135
+				array(63, 'Spain', 'ES', 'ESP', 2),
1136
+				array(1, 'Afghanistan', 'AF', 'AFG', 1),
1137
+				array(2, 'Albania', 'AL', 'ALB', 1),
1138
+				array(3, 'Germany', 'DE', 'DEU', 2),
1139
+				array(198, 'Switzerland', 'CH', 'CHE', 1),
1140
+				array(87, 'Netherlands', 'NL', 'NLD', 2),
1141
+				array(197, 'Sweden', 'SE', 'SWE', 1),
1142
+				array(230, 'Akrotiri and Dhekelia', 'CY', 'CYP', 2),
1143
+				array(4, 'Andorra', 'AD', 'AND', 2),
1144
+				array(5, 'Angola', 'AO', 'AGO', 1),
1145
+				array(6, 'Anguilla', 'AI', 'AIA', 1),
1146
+				array(7, 'Antarctica', 'AQ', 'ATA', 1),
1147
+				array(8, 'Antigua and Barbuda', 'AG', 'ATG', 1),
1148
+				array(10, 'Saudi Arabia', 'SA', 'SAU', 1),
1149
+				array(11, 'Algeria', 'DZ', 'DZA', 1),
1150
+				array(12, 'Argentina', 'AR', 'ARG', 1),
1151
+				array(13, 'Armenia', 'AM', 'ARM', 1),
1152
+				array(14, 'Aruba', 'AW', 'ABW', 1),
1153
+				array(16, 'Austria', 'AT', 'AUT', 2),
1154
+				array(17, 'Azerbaijan', 'AZ', 'AZE', 1),
1155
+				array(18, 'Bahamas', 'BS', 'BHS', 1),
1156
+				array(19, 'Bahrain', 'BH', 'BHR', 1),
1157
+				array(20, 'Bangladesh', 'BD', 'BGD', 1),
1158
+				array(21, 'Barbados', 'BB', 'BRB', 1),
1159
+				array(22, 'Belgium ', 'BE', 'BEL', 2),
1160
+				array(23, 'Belize', 'BZ', 'BLZ', 1),
1161
+				array(24, 'Benin', 'BJ', 'BEN', 1),
1162
+				array(25, 'Bermudas', 'BM', 'BMU', 1),
1163
+				array(26, 'Belarus', 'BY', 'BLR', 1),
1164
+				array(27, 'Bolivia', 'BO', 'BOL', 1),
1165
+				array(28, 'Bosnia and Herzegovina', 'BA', 'BIH', 1),
1166
+				array(29, 'Botswana', 'BW', 'BWA', 1),
1167
+				array(96, 'Bouvet Island', 'BV', 'BVT', 1),
1168
+				array(30, 'Brazil', 'BR', 'BRA', 1),
1169
+				array(31, 'Brunei', 'BN', 'BRN', 1),
1170
+				array(32, 'Bulgaria', 'BG', 'BGR', 1),
1171
+				array(33, 'Burkina Faso', 'BF', 'BFA', 1),
1172
+				array(34, 'Burundi', 'BI', 'BDI', 1),
1173
+				array(35, 'Bhutan', 'BT', 'BTN', 1),
1174
+				array(36, 'Cape Verde', 'CV', 'CPV', 1),
1175
+				array(37, 'Cambodia', 'KH', 'KHM', 1),
1176
+				array(38, 'Cameroon', 'CM', 'CMR', 1),
1177
+				array(98, 'Cayman Islands', 'KY', 'CYM', 1),
1178
+				array(172, 'Central African Republic', 'CF', 'CAF', 1),
1179
+				array(40, 'Chad', 'TD', 'TCD', 1),
1180
+				array(41, 'Chile', 'CL', 'CHL', 1),
1181
+				array(42, 'China', 'CN', 'CHN', 1),
1182
+				array(105, 'Christmas Island', 'CX', 'CXR', 1),
1183
+				array(43, 'Cyprus', 'CY', 'CYP', 2),
1184
+				array(99, 'Cocos Island', 'CC', 'CCK', 1),
1185
+				array(100, 'Cook Islands', 'CK', 'COK', 1),
1186
+				array(44, 'Colombia', 'CO', 'COL', 1),
1187
+				array(45, 'Comoros', 'KM', 'COM', 1),
1188
+				array(46, 'Congo', 'CG', 'COG', 1),
1189
+				array(47, 'North Korea', 'KP', 'PRK', 1),
1190
+				array(50, 'Costa Rica', 'CR', 'CRI', 1),
1191
+				array(51, 'Croatia', 'HR', 'HRV', 1),
1192
+				array(52, 'Cuba', 'CU', 'CUB', 1),
1193
+				array(173, 'Czech Republic', 'CZ', 'CZE', 1),
1194
+				array(53, 'Denmark', 'DK', 'DNK', 1),
1195
+				array(54, 'Djibouti', 'DJ', 'DJI', 1),
1196
+				array(55, 'Dominica', 'DM', 'DMA', 1),
1197
+				array(174, 'Dominican Republic', 'DO', 'DOM', 1),
1198
+				array(56, 'Ecuador', 'EC', 'ECU', 1),
1199
+				array(57, 'Egypt', 'EG', 'EGY', 1),
1200
+				array(58, 'El Salvador', 'SV', 'SLV', 1),
1201
+				array(60, 'Eritrea', 'ER', 'ERI', 1),
1202
+				array(61, 'Slovakia', 'SK', 'SVK', 2),
1203
+				array(62, 'Slovenia', 'SI', 'SVN', 2),
1204
+				array(65, 'Estonia', 'EE', 'EST', 2),
1205
+				array(66, 'Ethiopia', 'ET', 'ETH', 1),
1206
+				array(102, 'Faroe islands', 'FO', 'FRO', 1),
1207
+				array(103, 'Falkland Islands', 'FK', 'FLK', 1),
1208
+				array(67, 'Fiji', 'FJ', 'FJI', 1),
1209
+				array(69, 'Finland', 'FI', 'FIN', 2),
1210
+				array(71, 'Gabon', 'GA', 'GAB', 1),
1211
+				array(72, 'Gambia', 'GM', 'GMB', 1),
1212
+				array(73, 'Georgia', 'GE', 'GEO', 1),
1213
+				array(74, 'Ghana', 'GH', 'GHA', 1),
1214
+				array(75, 'Gibraltar', 'GI', 'GIB', 1),
1215
+				array(76, 'Greece', 'GR', 'GRC', 2),
1216
+				array(77, 'Grenada', 'GD', 'GRD', 1),
1217
+				array(78, 'Greenland', 'GL', 'GRL', 1),
1218
+				array(79, 'Guadeloupe', 'GP', 'GLP', 1),
1219
+				array(80, 'Guam', 'GU', 'GUM', 1),
1220
+				array(81, 'Guatemala', 'GT', 'GTM', 1),
1221
+				array(82, 'Guinea', 'GN', 'GIN', 1),
1222
+				array(83, 'Equatorial Guinea', 'GQ', 'GNQ', 1),
1223
+				array(84, 'Guinea-Bissau', 'GW', 'GNB', 1),
1224
+				array(85, 'Guyana', 'GY', 'GUY', 1),
1225
+				array(86, 'Haiti', 'HT', 'HTI', 1),
1226
+				array(88, 'Honduras', 'HN', 'HND', 1),
1227
+				array(89, 'Hong Kong', 'HK', 'HKG', 1),
1228
+				array(90, 'Hungary', 'HU', 'HUN', 1),
1229
+				array(91, 'India', 'IN', 'IND', 1),
1230
+				array(205, 'British Indian Ocean Territory', 'IO', 'IOT', 1),
1231
+				array(92, 'Indonesia', 'ID', 'IDN', 1),
1232
+				array(93, 'Iraq', 'IQ', 'IRQ', 1),
1233
+				array(94, 'Iran', 'IR', 'IRN', 1),
1234
+				array(95, 'Ireland', 'IE', 'IRL', 2),
1235
+				array(97, 'Iceland', 'IS', 'ISL', 1),
1236
+				array(110, 'Israel', 'IL', 'ISR', 1),
1237
+				array(49, 'Ivory Coast ', 'CI', 'CIV', 1),
1238
+				array(112, 'Jamaica', 'JM', 'JAM', 1),
1239
+				array(113, 'Japan', 'JP', 'JPN', 1),
1240
+				array(114, 'Jordan', 'JO', 'JOR', 1),
1241
+				array(115, 'Kazakhstan', 'KZ', 'KAZ', 1),
1242
+				array(116, 'Kenya', 'KE', 'KEN', 1),
1243
+				array(117, 'Kyrgyzstan', 'KG', 'KGZ', 1),
1244
+				array(118, 'Kiribati', 'KI', 'KIR', 1),
1245
+				array(48, 'South Korea', 'KR', 'KOR', 1),
1246
+				array(228, 'Kosovo', 'XK', 'XKV', 2),
1247
+				// there is no official ISO code for Kosovo yet (http://geonames.wordpress.com/2010/03/08/xk-country-code-for-kosovo/) so using a temporary country code and a modified 3 character code for ISO code -- this should be updated if/when Kosovo gets its own ISO code
1248
+				array(119, 'Kuwait', 'KW', 'KWT', 1),
1249
+				array(120, 'Laos', 'LA', 'LAO', 1),
1250
+				array(121, 'Latvia', 'LV', 'LVA', 2),
1251
+				array(122, 'Lesotho', 'LS', 'LSO', 1),
1252
+				array(123, 'Lebanon', 'LB', 'LBN', 1),
1253
+				array(124, 'Liberia', 'LR', 'LBR', 1),
1254
+				array(125, 'Libya', 'LY', 'LBY', 1),
1255
+				array(126, 'Liechtenstein', 'LI', 'LIE', 1),
1256
+				array(127, 'Lithuania', 'LT', 'LTU', 2),
1257
+				array(128, 'Luxemburg', 'LU', 'LUX', 2),
1258
+				array(129, 'Macao', 'MO', 'MAC', 1),
1259
+				array(130, 'Macedonia', 'MK', 'MKD', 1),
1260
+				array(131, 'Madagascar', 'MG', 'MDG', 1),
1261
+				array(132, 'Malaysia', 'MY', 'MYS', 1),
1262
+				array(133, 'Malawi', 'MW', 'MWI', 1),
1263
+				array(134, 'Maldivas', 'MV', 'MDV', 1),
1264
+				array(135, 'Mali', 'ML', 'MLI', 1),
1265
+				array(136, 'Malta', 'MT', 'MLT', 2),
1266
+				array(101, 'Northern Marianas', 'MP', 'MNP', 1),
1267
+				array(137, 'Morocco', 'MA', 'MAR', 1),
1268
+				array(104, 'Marshall islands', 'MH', 'MHL', 1),
1269
+				array(138, 'Martinique', 'MQ', 'MTQ', 1),
1270
+				array(139, 'Mauritius', 'MU', 'MUS', 1),
1271
+				array(140, 'Mauritania', 'MR', 'MRT', 1),
1272
+				array(141, 'Mayote', 'YT', 'MYT', 2),
1273
+				array(142, 'Mexico', 'MX', 'MEX', 1),
1274
+				array(143, 'Micronesia', 'FM', 'FSM', 1),
1275
+				array(144, 'Moldova', 'MD', 'MDA', 1),
1276
+				array(145, 'Monaco', 'MC', 'MCO', 2),
1277
+				array(146, 'Mongolia', 'MN', 'MNG', 1),
1278
+				array(147, 'Montserrat', 'MS', 'MSR', 1),
1279
+				array(227, 'Montenegro', 'ME', 'MNE', 2),
1280
+				array(148, 'Mozambique', 'MZ', 'MOZ', 1),
1281
+				array(149, 'Myanmar', 'MM', 'MMR', 1),
1282
+				array(150, 'Namibia', 'NA', 'NAM', 1),
1283
+				array(151, 'Nauru', 'NR', 'NRU', 1),
1284
+				array(152, 'Nepal', 'NP', 'NPL', 1),
1285
+				array(9, 'Netherlands Antilles', 'AN', 'ANT', 1),
1286
+				array(153, 'Nicaragua', 'NI', 'NIC', 1),
1287
+				array(154, 'Niger', 'NE', 'NER', 1),
1288
+				array(155, 'Nigeria', 'NG', 'NGA', 1),
1289
+				array(156, 'Niue', 'NU', 'NIU', 1),
1290
+				array(157, 'Norway', 'NO', 'NOR', 1),
1291
+				array(158, 'New Caledonia', 'NC', 'NCL', 1),
1292
+				array(159, 'New Zealand', 'NZ', 'NZL', 1),
1293
+				array(160, 'Oman', 'OM', 'OMN', 1),
1294
+				array(161, 'Pakistan', 'PK', 'PAK', 1),
1295
+				array(162, 'Palau', 'PW', 'PLW', 1),
1296
+				array(163, 'Panama', 'PA', 'PAN', 1),
1297
+				array(164, 'Papua New Guinea', 'PG', 'PNG', 1),
1298
+				array(165, 'Paraguay', 'PY', 'PRY', 1),
1299
+				array(166, 'Peru', 'PE', 'PER', 1),
1300
+				array(68, 'Philippines', 'PH', 'PHL', 1),
1301
+				array(167, 'Poland', 'PL', 'POL', 1),
1302
+				array(168, 'Portugal', 'PT', 'PRT', 2),
1303
+				array(169, 'Puerto Rico', 'PR', 'PRI', 1),
1304
+				array(170, 'Qatar', 'QA', 'QAT', 1),
1305
+				array(176, 'Rwanda', 'RW', 'RWA', 1),
1306
+				array(177, 'Romania', 'RO', 'ROM', 2),
1307
+				array(178, 'Russia', 'RU', 'RUS', 1),
1308
+				array(229, 'Saint Pierre and Miquelon', 'PM', 'SPM', 2),
1309
+				array(180, 'Samoa', 'WS', 'WSM', 1),
1310
+				array(181, 'American Samoa', 'AS', 'ASM', 1),
1311
+				array(183, 'San Marino', 'SM', 'SMR', 2),
1312
+				array(184, 'Saint Vincent and the Grenadines', 'VC', 'VCT', 1),
1313
+				array(185, 'Saint Helena', 'SH', 'SHN', 1),
1314
+				array(186, 'Saint Lucia', 'LC', 'LCA', 1),
1315
+				array(188, 'Senegal', 'SN', 'SEN', 1),
1316
+				array(189, 'Seychelles', 'SC', 'SYC', 1),
1317
+				array(190, 'Sierra Leona', 'SL', 'SLE', 1),
1318
+				array(191, 'Singapore', 'SG', 'SGP', 1),
1319
+				array(192, 'Syria', 'SY', 'SYR', 1),
1320
+				array(193, 'Somalia', 'SO', 'SOM', 1),
1321
+				array(194, 'Sri Lanka', 'LK', 'LKA', 1),
1322
+				array(195, 'South Africa', 'ZA', 'ZAF', 1),
1323
+				array(196, 'Sudan', 'SD', 'SDN', 1),
1324
+				array(199, 'Suriname', 'SR', 'SUR', 1),
1325
+				array(200, 'Swaziland', 'SZ', 'SWZ', 1),
1326
+				array(201, 'Thailand', 'TH', 'THA', 1),
1327
+				array(202, 'Taiwan', 'TW', 'TWN', 1),
1328
+				array(203, 'Tanzania', 'TZ', 'TZA', 1),
1329
+				array(204, 'Tajikistan', 'TJ', 'TJK', 1),
1330
+				array(206, 'Timor-Leste', 'TL', 'TLS', 1),
1331
+				array(207, 'Togo', 'TG', 'TGO', 1),
1332
+				array(208, 'Tokelau', 'TK', 'TKL', 1),
1333
+				array(209, 'Tonga', 'TO', 'TON', 1),
1334
+				array(210, 'Trinidad and Tobago', 'TT', 'TTO', 1),
1335
+				array(211, 'Tunisia', 'TN', 'TUN', 1),
1336
+				array(212, 'Turkmenistan', 'TM', 'TKM', 1),
1337
+				array(213, 'Turkey', 'TR', 'TUR', 1),
1338
+				array(214, 'Tuvalu', 'TV', 'TUV', 1),
1339
+				array(215, 'Ukraine', 'UA', 'UKR', 1),
1340
+				array(216, 'Uganda', 'UG', 'UGA', 1),
1341
+				array(59, 'United Arab Emirates', 'AE', 'ARE', 1),
1342
+				array(217, 'Uruguay', 'UY', 'URY', 1),
1343
+				array(218, 'Uzbekistan', 'UZ', 'UZB', 1),
1344
+				array(219, 'Vanuatu', 'VU', 'VUT', 1),
1345
+				array(220, 'Vatican City', 'VA', 'VAT', 2),
1346
+				array(221, 'Venezuela', 'VE', 'VEN', 1),
1347
+				array(222, 'Vietnam', 'VN', 'VNM', 1),
1348
+				array(108, 'Virgin Islands', 'VI', 'VIR', 1),
1349
+				array(223, 'Yemen', 'YE', 'YEM', 1),
1350
+				array(225, 'Zambia', 'ZM', 'ZMB', 1),
1351
+				array(226, 'Zimbabwe', 'ZW', 'ZWE', 1),
1352
+		);
1353
+		$country_iso = 'US';
1354
+		foreach ($old_countries as $country_array) {
1355
+			//note: index 0 is the 3.1 country ID
1356
+			if ($country_array[0] == $country_id) {
1357
+				//note: index 2 is the ISO
1358
+				$country_iso = $country_array[2];
1359
+				break;
1360
+			}
1361
+		}
1362
+		return $country_iso;
1363
+	}
1364
+
1365
+
1366
+
1367
+	/**
1368
+	 * Gets the ISO3 for the
1369
+	 *
1370
+	 * @return string
1371
+	 */
1372
+	public function get_default_country_iso()
1373
+	{
1374
+		$old_org_options = get_option('events_organization_settings');
1375
+		$iso = $this->get_iso_from_3_1_country_id($old_org_options['organization_country']);
1376
+		return $iso;
1377
+	}
1378
+
1379
+
1380
+
1381
+	/**
1382
+	 * Converst a 3.1 payment status to its equivalent 4.1 regisration status
1383
+	 *
1384
+	 * @param string  $payment_status                   possible value for 3.1's evens_attendee.payment_status
1385
+	 * @param boolean $this_thing_required_pre_approval whether the thing we're considering (the general setting's
1386
+	 *                                                  DEFAULT payment status, the event's DEFAULT payment status, or
1387
+	 *                                                  the attendee's payment status) required pre-approval.
1388
+	 * @return string STS_ID for use in 4.1
1389
+	 */
1390
+	public function convert_3_1_payment_status_to_4_1_STS_ID($payment_status, $this_thing_required_pre_approval = false)
1391
+	{
1392
+		//EE team can read the related discussion: https://app.asana.com/0/2400967562914/9418495544455
1393
+		if ($this_thing_required_pre_approval) {
1394
+			return 'RNA';
1395
+		} else {
1396
+			$mapping = $default_reg_stati_conversions = array(
1397
+					'Completed'        => 'RAP',
1398
+					''                 => 'RPP',
1399
+					'Incomplete'       => 'RPP',
1400
+					'Pending'          => 'RAP',
1401
+					//stati that only occurred on 3.1 attendees:
1402
+					'Payment Declined' => 'RPP',
1403
+					'Not Completed'    => 'RPP',
1404
+					'Cancelled'        => 'RPP',
1405
+					'Declined'         => 'RPP',
1406
+			);
1407
+		}
1408
+		return isset($mapping[$payment_status]) ? $mapping[$payment_status] : 'RNA';
1409
+	}
1410
+
1411
+
1412
+
1413
+	/**
1414
+	 * Makes sure the 3.1's image url is converted to an image attachment post to the 4.1 CPT event
1415
+	 * and sets it as the featured image on the CPT event
1416
+	 *
1417
+	 * @param type                            $old_event
1418
+	 * @param type                            $new_cpt_id
1419
+	 * @param  EE_Data_Migration_Script_Stage $migration_stage the stage which called this, where errors should be added
1420
+	 * @return boolean whether or not we had to do the big job of creating an image attachment
1421
+	 */
1422
+	public function convert_image_url_to_attachment_and_attach_to_post(
1423
+			$guid,
1424
+			$new_cpt_id,
1425
+			EE_Data_Migration_Script_Stage $migration_stage
1426
+	) {
1427
+		$created_attachment_post = false;
1428
+		$guid = $this->_get_original_guid($guid);
1429
+		if ($guid) {
1430
+			//check for an existing attachment post with this guid
1431
+			$attachment_post_id = $this->_get_image_attachment_id_by_GUID($guid);
1432
+			if ( ! $attachment_post_id) {
1433
+				//post thumbnail with that GUID doesn't exist, we should create one
1434
+				$attachment_post_id = $this->_create_image_attachment_from_GUID($guid, $migration_stage);
1435
+				$created_attachment_post = true;
1436
+			}
1437
+			//double-check we actually have an attachment post
1438
+			if ($attachment_post_id) {
1439
+				update_post_meta($new_cpt_id, '_thumbnail_id', $attachment_post_id);
1440
+			} else {
1441
+				$migration_stage->add_error(sprintf(esc_html__("Could not update event image %s for CPT with ID %d, but attachments post ID is %d",
1442
+						"event_espresso"), $guid, $new_cpt_id, $attachment_post_id));
1443
+			}
1444
+		}
1445
+		return $created_attachment_post;
1446
+	}
1447
+
1448
+
1449
+
1450
+	/**
1451
+	 * In 3.1, the event thumbnail image DOESN'T point to the orignal image, but instead
1452
+	 * to a large thumbnail (which has nearly the same GUID, except it adds "-{width}x{height}" before the filetype,
1453
+	 * or whatever dimensions it is. Eg 'http://mysite.com/image1-300x400.jpg' instead of
1454
+	 * 'http://mysite.com/image1.jpg' ). This function attempts to strip that off and get the original file, if it
1455
+	 * exists
1456
+	 *
1457
+	 * @param string $guid_in_old_event
1458
+	 * @return string either the original guid, or $guid_in_old_event if we couldn't figure out what the original was
1459
+	 */
1460
+	private function _get_original_guid($guid_in_old_event)
1461
+	{
1462
+		$original_guid = preg_replace('~-\d*x\d*\.~', '.', $guid_in_old_event, 1);
1463
+		//do a head request to verify the file exists
1464
+		$head_response = wp_remote_head($original_guid);
1465
+		if ( ! $head_response instanceof WP_Error && $head_response['response']['message'] == 'OK') {
1466
+			return $original_guid;
1467
+		} else {
1468
+			return $guid_in_old_event;
1469
+		}
1470
+	}
1471
+
1472
+
1473
+
1474
+	/**
1475
+	 * Creates an image attachment post for the GUID. If the GUID points to a remote image,
1476
+	 * we download it to our uploads directory so that it can be properly processed (eg, creates different sizes of
1477
+	 * thumbnails)
1478
+	 *
1479
+	 * @param type                           $guid
1480
+	 * @param EE_Data_Migration_Script_Stage $migration_stage
1481
+	 * @return int
1482
+	 */
1483
+	private function _create_image_attachment_from_GUID($guid, EE_Data_Migration_Script_Stage $migration_stage)
1484
+	{
1485
+		if ( ! $guid) {
1486
+			$migration_stage->add_error(sprintf(esc_html__("Cannot create image attachment for a blank GUID!",
1487
+					"event_espresso")));
1488
+			return 0;
1489
+		}
1490
+		$wp_filetype = wp_check_filetype(basename($guid), null);
1491
+		$wp_upload_dir = wp_upload_dir();
1492
+		//if the file is located remotely, download it to our uploads DIR, because wp_genereate_attachmnet_metadata needs the file to be local
1493
+		if (strpos($guid, $wp_upload_dir['url']) === false) {
1494
+			//image is located remotely. download it and place it in the uploads directory
1495
+			if ( ! is_readable($guid)) {
1496
+				$migration_stage->add_error(sprintf(esc_html__("Could not create image attachment from non-existent file: %s",
1497
+						"event_espresso"), $guid));
1498
+				return 0;
1499
+			}
1500
+			$contents = file_get_contents($guid);
1501
+			if ($contents === false) {
1502
+				$migration_stage->add_error(sprintf(esc_html__("Could not read image at %s, and therefore couldnt create an attachment post for it.",
1503
+						"event_espresso"), $guid));
1504
+				return false;
1505
+			}
1506
+			$local_filepath = $wp_upload_dir['path'] . DS . basename($guid);
1507
+			$savefile = fopen($local_filepath, 'w');
1508
+			fwrite($savefile, $contents);
1509
+			fclose($savefile);
1510
+			$guid = str_replace($wp_upload_dir['path'], $wp_upload_dir['url'], $local_filepath);
1511
+		} else {
1512
+			$local_filepath = str_replace($wp_upload_dir['url'], $wp_upload_dir['path'], $guid);
1513
+		}
1514
+		$attachment = array(
1515
+				'guid'           => $guid,
1516
+				'post_mime_type' => $wp_filetype['type'],
1517
+				'post_title'     => preg_replace('/\.[^.]+$/', '', basename($guid)),
1518
+				'post_content'   => '',
1519
+				'post_status'    => 'inherit',
1520
+		);
1521
+		$attach_id = wp_insert_attachment($attachment, $guid);
1522
+		if ( ! $attach_id) {
1523
+			$migration_stage->add_error(sprintf(esc_html__("Could not create image attachment post from image '%s'. Attachment data was %s.",
1524
+					"event_espresso"), $guid, $this->_json_encode($attachment)));
1525
+			return $attach_id;
1526
+		}
1527
+		// you must first include the image.php file
1528
+		// for the function wp_generate_attachment_metadata() to work
1529
+		require_once(ABSPATH . 'wp-admin/includes/image.php');
1530
+		$attach_data = wp_generate_attachment_metadata($attach_id, $local_filepath);
1531
+		if ( ! $attach_data) {
1532
+			$migration_stage->add_error(sprintf(esc_html__("Coudl not genereate attachment metadata for attachment post %d with filepath %s and GUID %s. Please check the file was downloaded properly.",
1533
+					"event_espresso"), $attach_id, $local_filepath, $guid));
1534
+			return $attach_id;
1535
+		}
1536
+		$metadata_save_result = wp_update_attachment_metadata($attach_id, $attach_data);
1537
+		if ( ! $metadata_save_result) {
1538
+			$migration_stage->add_error(sprintf(esc_html__("Could not update attachment metadata for attachment %d with data %s",
1539
+					"event_espresso"), $attach_id, $this->_json_encode($attach_data)));
1540
+		}
1541
+		return $attach_id;
1542
+	}
1543
+
1544
+
1545
+
1546
+	/**
1547
+	 * Finds the attachment post containing info about an image attachment given the GUID (link to the image itself),
1548
+	 * and returns its ID.
1549
+	 *
1550
+	 * @global type  $wpdb
1551
+	 * @param string $guid
1552
+	 * @return int
1553
+	 */
1554
+	private function _get_image_attachment_id_by_GUID($guid)
1555
+	{
1556
+		global $wpdb;
1557
+		$attachment_id = $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid=%s LIMIT 1", $guid));
1558
+		return $attachment_id;
1559
+	}
1560
+
1561
+
1562
+
1563
+	/**
1564
+	 * Returns a mysql-formatted DATETIME in UTC time, given a $DATETIME_string
1565
+	 * (and optionally a timezone; if none is given, the wp DEFAULT is used)
1566
+	 *
1567
+	 * @param EE_Data_Migration_Script_base $stage
1568
+	 * @param array                         $row_of_data , the row from the DB (as an array) we're trying to find the
1569
+	 *                                                   UTC time for
1570
+	 * @param string                        $DATETIME_string
1571
+	 * @param string                        $timezone
1572
+	 * @return string
1573
+	 */
1574
+	public function convert_date_string_to_utc(
1575
+			EE_Data_Migration_Script_Stage $stage,
1576
+			$row_of_data,
1577
+			$DATETIME_string,
1578
+			$timezone = null
1579
+	) {
1580
+		$original_tz = $timezone;
1581
+		if ( ! $timezone) {
1582
+			$timezone = $this->_get_wp_timezone();
1583
+		}
1584
+		if ( ! $timezone) {
1585
+			$stage->add_error(sprintf(esc_html__("Could not find timezone given %s for %s", "event_espresso"), $original_tz,
1586
+					$row_of_data));
1587
+			$timezone = 'UTC';
1588
+		}
1589
+		try {
1590
+			$date_obj = new DateTime($DATETIME_string, new DateTimeZone($timezone));
1591
+			EEH_DTT_Helper::setTimezone($date_obj, new DateTimeZone('UTC'));
1592
+		} catch (Exception $e) {
1593
+			$stage->add_error(sprintf(esc_html__("Could not convert time string '%s' using timezone '%s' into a proper DATETIME. Using current time instead.",
1594
+					"event_espresso"), $DATETIME_string, $timezone));
1595
+			$date_obj = new DateTime();
1596
+		}
1597
+		return $date_obj->format('Y-m-d H:i:s');
1598
+	}
1599
+
1600
+
1601
+
1602
+	/**
1603
+	 * Gets the DEFAULT timezone string from wordpress (even if they set a gmt offset)
1604
+	 *
1605
+	 * @return string
1606
+	 */
1607
+	private function _get_wp_timezone()
1608
+	{
1609
+		$timezone = empty($timezone) ? get_option('timezone_string') : $timezone;
1610
+		//if timezone is STILL empty then let's get the GMT offset and then set the timezone_string using our converter
1611
+		if (empty($timezone)) {
1612
+			//let's get a the WordPress UTC offset
1613
+			$offset = get_option('gmt_offset');
1614
+			$timezone = $this->timezone_convert_to_string_from_offset($offset);
1615
+		}
1616
+		return $timezone;
1617
+	}
1618
+
1619
+
1620
+
1621
+	/**
1622
+	 * Gets the wordpress timezone string from a UTC offset
1623
+	 *
1624
+	 * @param int $offset
1625
+	 * @return boolean
1626
+	 */
1627
+	private function timezone_convert_to_string_from_offset($offset)
1628
+	{
1629
+		//shamelessly taken from bottom comment at http://ca1.php.net/manual/en/function.timezone-name-from-abbr.php because timezone_name_from_abbr() did NOT work as expected - its not reliable
1630
+		$offset *= 3600; // convert hour offset to seconds
1631
+		$abbrarray = timezone_abbreviations_list();
1632
+		foreach ($abbrarray as $abbr) {
1633
+			foreach ($abbr as $city) {
1634
+				if ($city['offset'] == $offset) {
1635
+					return $city['timezone_id'];
1636
+				}
1637
+			}
1638
+		}
1639
+		return false;
1640
+	}
1641
+
1642
+
1643
+
1644
+	public function migration_page_hooks()
1645
+	{
1646
+		add_filter(
1647
+				'FHEE__ee_migration_page__header',
1648
+				array($this, '_migrate_page_hook_simplify_version_strings'),
1649
+				10,
1650
+				3
1651
+		);
1652
+		add_filter(
1653
+				'FHEE__ee_migration_page__p_after_header',
1654
+				array($this, '_migration_page_hook_simplify_next_db_state'),
1655
+				10,
1656
+				2
1657
+		);
1658
+		add_filter(
1659
+				'FHEE__ee_migration_page__option_1_main',
1660
+				array($this, '_migrate_page_hook_simplify_version_strings'),
1661
+				10,
1662
+				3
1663
+		);
1664
+		add_filter(
1665
+				'FHEE__ee_migration_page__option_1_button_text',
1666
+				array($this, '_migrate_page_hook_simplify_version_strings'),
1667
+				10,
1668
+				3
1669
+		);
1670
+		add_action(
1671
+				'AHEE__ee_migration_page__option_1_extra_details',
1672
+				array($this, '_migration_page_hook_option_1_extra_details'),
1673
+				10,
1674
+				3
1675
+		);
1676
+		add_filter(
1677
+				'FHEE__ee_migration_page__option_2_main',
1678
+				array($this, '_migrate_page_hook_simplify_version_strings'),
1679
+				10,
1680
+				4
1681
+		);
1682
+		add_filter(
1683
+				'FHEE__ee_migration_page__option_2_button_text',
1684
+				array($this, '_migration_page_hook_simplify_next_db_state'),
1685
+				10,
1686
+				2
1687
+		);
1688
+		add_filter(
1689
+				'FHEE__ee_migration_page__option_2_details',
1690
+				array($this, '_migration_page_hook_simplify_next_db_state'),
1691
+				10,
1692
+				2
1693
+		);
1694
+		add_action(
1695
+				'AHEE__ee_migration_page__after_migration_options_table',
1696
+				array($this, '_migration_page_hook_after_migration_options_table')
1697
+		);
1698
+		add_filter(
1699
+				'FHEE__ee_migration_page__done_migration_header',
1700
+				array($this, '_migration_page_hook_simplify_next_db_state'),
1701
+				10,
1702
+				2
1703
+		);
1704
+		add_filter(
1705
+				'FHEE__ee_migration_page__p_after_done_migration_header',
1706
+				array($this, '_migration_page_hook_simplify_next_db_state'),
1707
+				10,
1708
+				2
1709
+		);
1710
+		add_filter(
1711
+				'FHEE__ee_migration_page__migration_options_template',
1712
+				array($this,'use_migration_options_from_ee3_template')
1713
+		);
1714
+	}
1715
+
1716
+
1717
+
1718
+	public function _migrate_page_hook_simplify_version_strings(
1719
+			$old_content,
1720
+			$current_db_state,
1721
+			$next_db_state,
1722
+			$ultimate_db_state = null
1723
+	) {
1724
+		return str_replace(array($current_db_state, $next_db_state, $ultimate_db_state),
1725
+				array(esc_html__('EE3', 'event_espresso'), esc_html__('EE4', 'event_espresso'), esc_html__("EE4", 'event_espresso')),
1726
+				$old_content);
1727
+	}
1728
+
1729
+
1730
+
1731
+	public function _migration_page_hook_simplify_next_db_state($old_content, $next_db_state)
1732
+	{
1733
+		return str_replace($next_db_state, esc_html__("EE4", 'event_espresso'), $old_content);
1734
+	}
1735
+
1736
+
1737
+
1738
+	public function _migration_page_hook_option_1_extra_details()
1739
+	{
1740
+		?>
1741 1741
         <p><?php printf(esc_html__("Note: many of your EE3 shortcodes will be changed to EE4 shortcodes during this migration (among many other things). Should you revert to EE3, then you should restore to your backup or manually change the EE4 shortcodes back to their EE3 equivalents",
1742
-            "event_espresso")); ?></p><?php
1743
-    }
1742
+			"event_espresso")); ?></p><?php
1743
+	}
1744 1744
 
1745 1745
 
1746 1746
 
1747
-    public function _migration_page_hook_after_migration_options_table()
1748
-    {
1749
-        ?><p class="ee-attention">
1747
+	public function _migration_page_hook_after_migration_options_table()
1748
+	{
1749
+		?><p class="ee-attention">
1750 1750
         <strong><span class="reminder-spn"><?php _e("Important note to those using Event Espresso 3 addons: ",
1751
-                        "event_espresso"); ?></span></strong>
1751
+						"event_espresso"); ?></span></strong>
1752 1752
         <br/><?php _e("Unless an addon's description on our website explicitly states that it is compatible with EE4, you should consider it incompatible and know that it WILL NOT WORK correctly with this new version of Event Espresso 4 (EE4). As well, any data for incompatible addons will NOT BE MIGRATED until an updated EE4 compatible version of the addon is available. If you want, or need to keep using your EE3 addons, you should simply continue using EE3 until EE4 compatible versions of your addons become available. To continue using EE3 for now, just deactivate EE4 and reactivate EE3.",
1753
-            "event_espresso"); ?>
1753
+			"event_espresso"); ?>
1754 1754
         </p><?php
1755
-    }
1755
+	}
1756 1756
 
1757 1757
 
1758 1758
 
1759
-    /**
1760
-     * When showing the migration options, show more options and info than normal (ie, give folks the option
1761
-     * to start using EE4 without migrating. From EE3 that's fine, because it doesn't actually remove any data, because
1762
-     * EE4 doesn't have any yet. But when migrating from EE4 it would remove old data, so its not a great idea).
1763
-     * @param $template_filepath
1764
-     * @return string
1765
-     */
1766
-    public function use_migration_options_from_ee3_template( $template_filepath ) {
1767
-        return EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee3.template.php';
1768
-    }
1759
+	/**
1760
+	 * When showing the migration options, show more options and info than normal (ie, give folks the option
1761
+	 * to start using EE4 without migrating. From EE3 that's fine, because it doesn't actually remove any data, because
1762
+	 * EE4 doesn't have any yet. But when migrating from EE4 it would remove old data, so its not a great idea).
1763
+	 * @param $template_filepath
1764
+	 * @return string
1765
+	 */
1766
+	public function use_migration_options_from_ee3_template( $template_filepath ) {
1767
+		return EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee3.template.php';
1768
+	}
1769 1769
 }
Please login to merge, or discard this patch.
core/helpers/EEH_DTT_Helper.helper.php 1 patch
Indentation   +1027 added lines, -1027 removed lines patch added patch discarded remove patch
@@ -21,1031 +21,1031 @@
 block discarded – undo
21 21
 {
22 22
 
23 23
 
24
-    /**
25
-     * return the timezone set for the WP install
26
-     *
27
-     * @return string valid timezone string for PHP DateTimeZone() class
28
-     * @throws InvalidArgumentException
29
-     * @throws InvalidDataTypeException
30
-     * @throws InvalidInterfaceException
31
-     */
32
-    public static function get_timezone()
33
-    {
34
-        return EEH_DTT_Helper::get_valid_timezone_string();
35
-    }
36
-
37
-
38
-    /**
39
-     * get_valid_timezone_string
40
-     *    ensures that a valid timezone string is returned
41
-     *
42
-     * @param string $timezone_string
43
-     * @return string
44
-     * @throws InvalidArgumentException
45
-     * @throws InvalidDataTypeException
46
-     * @throws InvalidInterfaceException
47
-     */
48
-    public static function get_valid_timezone_string($timezone_string = '')
49
-    {
50
-        return self::getHelperAdapter()->getValidTimezoneString($timezone_string);
51
-    }
52
-
53
-
54
-    /**
55
-     * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
56
-     *
57
-     * @static
58
-     * @param  string $timezone_string Timezone string to check
59
-     * @param bool    $throw_error
60
-     * @return bool
61
-     * @throws InvalidArgumentException
62
-     * @throws InvalidDataTypeException
63
-     * @throws InvalidInterfaceException
64
-     */
65
-    public static function validate_timezone($timezone_string, $throw_error = true)
66
-    {
67
-        return self::getHelperAdapter()->validateTimezone($timezone_string, $throw_error);
68
-    }
69
-
70
-
71
-    /**
72
-     * This returns a string that can represent the provided gmt offset in format that can be passed into
73
-     * DateTimeZone.  This is NOT a string that can be passed as a value on the WordPress timezone_string option.
74
-     *
75
-     * @param float|string $gmt_offset
76
-     * @return string
77
-     * @throws InvalidArgumentException
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     */
81
-    public static function get_timezone_string_from_gmt_offset($gmt_offset = '')
82
-    {
83
-        return self::getHelperAdapter()->getTimezoneStringFromGmtOffset($gmt_offset);
84
-    }
85
-
86
-
87
-    /**
88
-     * Gets the site's GMT offset based on either the timezone string
89
-     * (in which case teh gmt offset will vary depending on the location's
90
-     * observance of daylight savings time) or the gmt_offset wp option
91
-     *
92
-     * @return int seconds offset
93
-     * @throws InvalidArgumentException
94
-     * @throws InvalidDataTypeException
95
-     * @throws InvalidInterfaceException
96
-     */
97
-    public static function get_site_timezone_gmt_offset()
98
-    {
99
-        return self::getHelperAdapter()->getSiteTimezoneGmtOffset();
100
-    }
101
-
102
-
103
-    /**
104
-     * Depending on PHP version,
105
-     * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
106
-     * To get around that, for these fringe timezones we bump them to a known valid offset.
107
-     * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
108
-     *
109
-     * @deprecated 4.9.54.rc    Developers this was always meant to only be an internally used method.  This will be
110
-     *                          removed in a future version of EE.
111
-     * @param int $gmt_offset
112
-     * @return int
113
-     * @throws InvalidArgumentException
114
-     * @throws InvalidDataTypeException
115
-     * @throws InvalidInterfaceException
116
-     */
117
-    public static function adjust_invalid_gmt_offsets($gmt_offset = 0)
118
-    {
119
-        return self::getHelperAdapter()->adjustInvalidGmtOffsets($gmt_offset);
120
-    }
121
-
122
-
123
-    /**
124
-     * get_timezone_string_from_abbreviations_list
125
-     *
126
-     * @deprecated 4.9.54.rc  Developers, this was never intended to be public.  This is a soft deprecation for now.
127
-     *                        If you are using this, you'll want to work out an alternate way of getting the value.
128
-     * @param int  $gmt_offset
129
-     * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset.
130
-     * @return string
131
-     * @throws EE_Error
132
-     * @throws InvalidArgumentException
133
-     * @throws InvalidDataTypeException
134
-     * @throws InvalidInterfaceException
135
-     */
136
-    public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true)
137
-    {
138
-        $gmt_offset =  (int) $gmt_offset;
139
-        /** @var array[] $abbreviations */
140
-        $abbreviations = DateTimeZone::listAbbreviations();
141
-        foreach ($abbreviations as $abbreviation) {
142
-            foreach ($abbreviation as $timezone) {
143
-                if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
144
-                    try {
145
-                        $offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id']));
146
-                        if ($offset !== $gmt_offset) {
147
-                            continue;
148
-                        }
149
-                        return $timezone['timezone_id'];
150
-                    } catch (Exception $e) {
151
-                        continue;
152
-                    }
153
-                }
154
-            }
155
-        }
156
-        //if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
157
-        if ($coerce === true) {
158
-            $timezone_string = self::get_timezone_string_from_abbreviations_list(
159
-                self::adjust_invalid_gmt_offsets($gmt_offset),
160
-                false
161
-            );
162
-            if ($timezone_string) {
163
-                return $timezone_string;
164
-            }
165
-        }
166
-        throw new EE_Error(
167
-            sprintf(
168
-                esc_html__(
169
-                    'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
170
-                    'event_espresso'
171
-                ),
172
-                $gmt_offset / HOUR_IN_SECONDS,
173
-                '<a href="http://www.php.net/manual/en/timezones.php">',
174
-                '</a>'
175
-            )
176
-        );
177
-    }
178
-
179
-
180
-    /**
181
-     * Get Timezone Transitions
182
-     *
183
-     * @param DateTimeZone $date_time_zone
184
-     * @param int|null     $time
185
-     * @param bool         $first_only
186
-     * @return array
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     */
191
-    public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
192
-    {
193
-        return self::getHelperAdapter()->getTimezoneTransitions($date_time_zone, $time, $first_only);
194
-    }
195
-
196
-
197
-    /**
198
-     * Get Timezone Offset for given timezone object.
199
-     *
200
-     * @param DateTimeZone $date_time_zone
201
-     * @param null         $time
202
-     * @return mixed
203
-     * @throws InvalidArgumentException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     */
207
-    public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null)
208
-    {
209
-        return self::getHelperAdapter()->getTimezoneOffset($date_time_zone, $time);
210
-    }
211
-
212
-
213
-    /**
214
-     * Prints a select input for the given timezone string.
215
-     * @param string $timezone_string
216
-     * @deprecatd 4.9.54.rc   Soft deprecation.  Consider using \EEH_DTT_Helper::wp_timezone_choice instead.
217
-     * @throws InvalidArgumentException
218
-     * @throws InvalidDataTypeException
219
-     * @throws InvalidInterfaceException
220
-     */
221
-    public static function timezone_select_input($timezone_string = '')
222
-    {
223
-        self::getHelperAdapter()->timezoneSelectInput($timezone_string);
224
-    }
225
-
226
-
227
-    /**
228
-     * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
229
-     * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
230
-     * the site is used.
231
-     * This is used typically when using a Unix timestamp any core WP functions that expect their specially
232
-     * computed timestamp (i.e. date_i18n() )
233
-     *
234
-     * @param int    $unix_timestamp                  if 0, then time() will be used.
235
-     * @param string $timezone_string                 timezone_string. If empty, then the current set timezone for the
236
-     *                                                site will be used.
237
-     * @return int $unix_timestamp with the offset applied for the given timezone.
238
-     * @throws InvalidArgumentException
239
-     * @throws InvalidDataTypeException
240
-     * @throws InvalidInterfaceException
241
-     */
242
-    public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '')
243
-    {
244
-        return self::getHelperAdapter()->getTimestampWithOffset($unix_timestamp, $timezone_string);
245
-    }
246
-
247
-
248
-    /**
249
-     *    _set_date_time_field
250
-     *    modifies EE_Base_Class EE_Datetime_Field objects
251
-     *
252
-     * @param  EE_Base_Class $obj                 EE_Base_Class object
253
-     * @param    DateTime    $DateTime            PHP DateTime object
254
-     * @param  string        $datetime_field_name the datetime fieldname to be manipulated
255
-     * @return EE_Base_Class
256
-     * @throws EE_Error
257
-     */
258
-    protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name)
259
-    {
260
-        // grab current datetime format
261
-        $current_format = $obj->get_format();
262
-        // set new full timestamp format
263
-        $obj->set_date_format(EE_Datetime_Field::mysql_date_format);
264
-        $obj->set_time_format(EE_Datetime_Field::mysql_time_format);
265
-        // set the new date value using a full timestamp format so that no data is lost
266
-        $obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format));
267
-        // reset datetime formats
268
-        $obj->set_date_format($current_format[0]);
269
-        $obj->set_time_format($current_format[1]);
270
-        return $obj;
271
-    }
272
-
273
-
274
-    /**
275
-     *    date_time_add
276
-     *    helper for doing simple datetime calculations on a given datetime from EE_Base_Class
277
-     *    and modifying it IN the EE_Base_Class so you don't have to do anything else.
278
-     *
279
-     * @param  EE_Base_Class $obj                 EE_Base_Class object
280
-     * @param  string        $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
281
-     * @param  string        $period              what you are adding. The options are (years, months, days, hours,
282
-     *                                            minutes, seconds) defaults to years
283
-     * @param  integer       $value               what you want to increment the time by
284
-     * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it
285
-     *                                            (chaining)
286
-     * @throws EE_Error
287
-     * @throws Exception
288
-     */
289
-    public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
290
-    {
291
-        //get the raw UTC date.
292
-        $DateTime = $obj->get_DateTime_object($datetime_field_name);
293
-        $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value);
294
-        return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
295
-    }
296
-
297
-
298
-    /**
299
-     *    date_time_subtract
300
-     *    same as date_time_add except subtracting value instead of adding.
301
-     *
302
-     * @param EE_Base_Class $obj
303
-     * @param  string       $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
304
-     * @param string        $period
305
-     * @param int           $value
306
-     * @return EE_Base_Class
307
-     * @throws EE_Error
308
-     * @throws Exception
309
-     */
310
-    public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
311
-    {
312
-        //get the raw UTC date
313
-        $DateTime = $obj->get_DateTime_object($datetime_field_name);
314
-        $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-');
315
-        return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
316
-    }
317
-
318
-
319
-    /**
320
-     * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters
321
-     *
322
-     * @param  DateTime   $DateTime DateTime object
323
-     * @param  string     $period   a value to indicate what interval is being used in the calculation. The options are
324
-     *                              'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
325
-     * @param  int|string $value    What you want to increment the date by
326
-     * @param  string     $operand  What operand you wish to use for the calculation
327
-     * @return DateTime return whatever type came in.
328
-     * @throws Exception
329
-     * @throws EE_Error
330
-     */
331
-    protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+')
332
-    {
333
-        if (! $DateTime instanceof DateTime) {
334
-            throw new EE_Error(
335
-                sprintf(
336
-                    esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'),
337
-                    print_r($DateTime, true)
338
-                )
339
-            );
340
-        }
341
-        switch ($period) {
342
-            case 'years' :
343
-                $value = 'P' . $value . 'Y';
344
-                break;
345
-            case 'months' :
346
-                $value = 'P' . $value . 'M';
347
-                break;
348
-            case 'weeks' :
349
-                $value = 'P' . $value . 'W';
350
-                break;
351
-            case 'days' :
352
-                $value = 'P' . $value . 'D';
353
-                break;
354
-            case 'hours' :
355
-                $value = 'PT' . $value . 'H';
356
-                break;
357
-            case 'minutes' :
358
-                $value = 'PT' . $value . 'M';
359
-                break;
360
-            case 'seconds' :
361
-                $value = 'PT' . $value . 'S';
362
-                break;
363
-        }
364
-        switch ($operand) {
365
-            case '+':
366
-                $DateTime->add(new DateInterval($value));
367
-                break;
368
-            case '-':
369
-                $DateTime->sub(new DateInterval($value));
370
-                break;
371
-        }
372
-        return $DateTime;
373
-    }
374
-
375
-
376
-    /**
377
-     * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters
378
-     *
379
-     * @param  int     $timestamp Unix timestamp
380
-     * @param  string  $period    a value to indicate what interval is being used in the calculation. The options are
381
-     *                            'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
382
-     * @param  integer $value     What you want to increment the date by
383
-     * @param  string  $operand   What operand you wish to use for the calculation
384
-     * @return int
385
-     * @throws EE_Error
386
-     */
387
-    protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+')
388
-    {
389
-        if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) {
390
-            throw new EE_Error(
391
-                sprintf(
392
-                    esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'),
393
-                    print_r($timestamp, true)
394
-                )
395
-            );
396
-        }
397
-        switch ($period) {
398
-            case 'years' :
399
-                $value = YEAR_IN_SECONDS * $value;
400
-                break;
401
-            case 'months' :
402
-                $value = YEAR_IN_SECONDS / 12 * $value;
403
-                break;
404
-            case 'weeks' :
405
-                $value = WEEK_IN_SECONDS * $value;
406
-                break;
407
-            case 'days' :
408
-                $value = DAY_IN_SECONDS * $value;
409
-                break;
410
-            case 'hours' :
411
-                $value = HOUR_IN_SECONDS * $value;
412
-                break;
413
-            case 'minutes' :
414
-                $value = MINUTE_IN_SECONDS * $value;
415
-                break;
416
-        }
417
-        switch ($operand) {
418
-            case '+':
419
-                $timestamp += $value;
420
-                break;
421
-            case '-':
422
-                $timestamp -= $value;
423
-                break;
424
-        }
425
-        return $timestamp;
426
-    }
427
-
428
-
429
-    /**
430
-     * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming
431
-     * parameters and returns the new timestamp or DateTime.
432
-     *
433
-     * @param  int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp
434
-     * @param  string         $period                a value to indicate what interval is being used in the
435
-     *                                               calculation. The options are 'years', 'months', 'days', 'hours',
436
-     *                                               'minutes', 'seconds'. Defaults to years.
437
-     * @param  integer        $value                 What you want to increment the date by
438
-     * @param  string         $operand               What operand you wish to use for the calculation
439
-     * @return mixed string|DateTime          return whatever type came in.
440
-     * @throws Exception
441
-     * @throws EE_Error
442
-     */
443
-    public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+')
444
-    {
445
-        if ($DateTime_or_timestamp instanceof DateTime) {
446
-            return EEH_DTT_Helper::_modify_datetime_object(
447
-                $DateTime_or_timestamp,
448
-                $period,
449
-                $value,
450
-                $operand
451
-            );
452
-        }
453
-        if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) {
454
-            return EEH_DTT_Helper::_modify_timestamp(
455
-                $DateTime_or_timestamp,
456
-                $period,
457
-                $value,
458
-                $operand
459
-            );
460
-        }
461
-        //error
462
-        return $DateTime_or_timestamp;
463
-    }
464
-
465
-
466
-    /**
467
-     * The purpose of this helper method is to receive an incoming format string in php date/time format
468
-     * and spit out the js and moment.js equivalent formats.
469
-     * Note, if no format string is given, then it is assumed the user wants what is set for WP.
470
-     * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date-
471
-     * time picker.
472
-     *
473
-     * @see http://stackoverflow.com/posts/16725290/ for the code inspiration.
474
-     * @param string $date_format_string
475
-     * @param string $time_format_string
476
-     * @return array
477
-     *              array(
478
-     *              'js' => array (
479
-     *              'date' => //date format
480
-     *              'time' => //time format
481
-     *              ),
482
-     *              'moment' => //date and time format.
483
-     *              )
484
-     */
485
-    public static function convert_php_to_js_and_moment_date_formats(
486
-        $date_format_string = null,
487
-        $time_format_string = null
488
-    ) {
489
-        if ($date_format_string === null) {
490
-            $date_format_string = (string) get_option('date_format');
491
-        }
492
-        if ($time_format_string === null) {
493
-            $time_format_string = (string) get_option('time_format');
494
-        }
495
-        $date_format = self::_php_to_js_moment_converter($date_format_string);
496
-        $time_format = self::_php_to_js_moment_converter($time_format_string);
497
-        return array(
498
-            'js'     => array(
499
-                'date' => $date_format['js'],
500
-                'time' => $time_format['js'],
501
-            ),
502
-            'moment' => $date_format['moment'] . ' ' . $time_format['moment'],
503
-        );
504
-    }
505
-
506
-
507
-    /**
508
-     * This converts incoming format string into js and moment variations.
509
-     *
510
-     * @param string $format_string incoming php format string
511
-     * @return array js and moment formats.
512
-     */
513
-    protected static function _php_to_js_moment_converter($format_string)
514
-    {
515
-        /**
516
-         * This is a map of symbols for formats.
517
-         * The index is the php symbol, the equivalent values are in the array.
518
-         *
519
-         * @var array
520
-         */
521
-        $symbols_map          = array(
522
-            // Day
523
-            //01
524
-            'd' => array(
525
-                'js'     => 'dd',
526
-                'moment' => 'DD',
527
-            ),
528
-            //Mon
529
-            'D' => array(
530
-                'js'     => 'D',
531
-                'moment' => 'ddd',
532
-            ),
533
-            //1,2,...31
534
-            'j' => array(
535
-                'js'     => 'd',
536
-                'moment' => 'D',
537
-            ),
538
-            //Monday
539
-            'l' => array(
540
-                'js'     => 'DD',
541
-                'moment' => 'dddd',
542
-            ),
543
-            //ISO numeric representation of the day of the week (1-6)
544
-            'N' => array(
545
-                'js'     => '',
546
-                'moment' => 'E',
547
-            ),
548
-            //st,nd.rd
549
-            'S' => array(
550
-                'js'     => '',
551
-                'moment' => 'o',
552
-            ),
553
-            //numeric representation of day of week (0-6)
554
-            'w' => array(
555
-                'js'     => '',
556
-                'moment' => 'd',
557
-            ),
558
-            //day of year starting from 0 (0-365)
559
-            'z' => array(
560
-                'js'     => 'o',
561
-                'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1
562
-            ),
563
-            // Week
564
-            //ISO-8601 week number of year (weeks starting on monday)
565
-            'W' => array(
566
-                'js'     => '',
567
-                'moment' => 'w',
568
-            ),
569
-            // Month
570
-            // January...December
571
-            'F' => array(
572
-                'js'     => 'MM',
573
-                'moment' => 'MMMM',
574
-            ),
575
-            //01...12
576
-            'm' => array(
577
-                'js'     => 'mm',
578
-                'moment' => 'MM',
579
-            ),
580
-            //Jan...Dec
581
-            'M' => array(
582
-                'js'     => 'M',
583
-                'moment' => 'MMM',
584
-            ),
585
-            //1-12
586
-            'n' => array(
587
-                'js'     => 'm',
588
-                'moment' => 'M',
589
-            ),
590
-            //number of days in given month
591
-            't' => array(
592
-                'js'     => '',
593
-                'moment' => '',
594
-            ),
595
-            // Year
596
-            //whether leap year or not 1/0
597
-            'L' => array(
598
-                'js'     => '',
599
-                'moment' => '',
600
-            ),
601
-            //ISO-8601 year number
602
-            'o' => array(
603
-                'js'     => '',
604
-                'moment' => 'GGGG',
605
-            ),
606
-            //1999...2003
607
-            'Y' => array(
608
-                'js'     => 'yy',
609
-                'moment' => 'YYYY',
610
-            ),
611
-            //99...03
612
-            'y' => array(
613
-                'js'     => 'y',
614
-                'moment' => 'YY',
615
-            ),
616
-            // Time
617
-            // am/pm
618
-            'a' => array(
619
-                'js'     => 'tt',
620
-                'moment' => 'a',
621
-            ),
622
-            // AM/PM
623
-            'A' => array(
624
-                'js'     => 'TT',
625
-                'moment' => 'A',
626
-            ),
627
-            // Swatch Internet Time?!?
628
-            'B' => array(
629
-                'js'     => '',
630
-                'moment' => '',
631
-            ),
632
-            //1...12
633
-            'g' => array(
634
-                'js'     => 'h',
635
-                'moment' => 'h',
636
-            ),
637
-            //0...23
638
-            'G' => array(
639
-                'js'     => 'H',
640
-                'moment' => 'H',
641
-            ),
642
-            //01...12
643
-            'h' => array(
644
-                'js'     => 'hh',
645
-                'moment' => 'hh',
646
-            ),
647
-            //00...23
648
-            'H' => array(
649
-                'js'     => 'HH',
650
-                'moment' => 'HH',
651
-            ),
652
-            //00..59
653
-            'i' => array(
654
-                'js'     => 'mm',
655
-                'moment' => 'mm',
656
-            ),
657
-            //seconds... 00...59
658
-            's' => array(
659
-                'js'     => 'ss',
660
-                'moment' => 'ss',
661
-            ),
662
-            //microseconds
663
-            'u' => array(
664
-                'js'     => '',
665
-                'moment' => '',
666
-            ),
667
-        );
668
-        $jquery_ui_format     = '';
669
-        $moment_format        = '';
670
-        $escaping             = false;
671
-        $format_string_length = strlen($format_string);
672
-        for ($i = 0; $i < $format_string_length; $i++) {
673
-            $char = $format_string[ $i ];
674
-            if ($char === '\\') { // PHP date format escaping character
675
-                $i++;
676
-                if ($escaping) {
677
-                    $jquery_ui_format .= $format_string[ $i ];
678
-                    $moment_format    .= $format_string[ $i ];
679
-                } else {
680
-                    $jquery_ui_format .= '\'' . $format_string[ $i ];
681
-                    $moment_format    .= $format_string[ $i ];
682
-                }
683
-                $escaping = true;
684
-            } else {
685
-                if ($escaping) {
686
-                    $jquery_ui_format .= "'";
687
-                    $moment_format    .= "'";
688
-                    $escaping         = false;
689
-                }
690
-                if (isset($symbols_map[ $char ])) {
691
-                    $jquery_ui_format .= $symbols_map[ $char ]['js'];
692
-                    $moment_format    .= $symbols_map[ $char ]['moment'];
693
-                } else {
694
-                    $jquery_ui_format .= $char;
695
-                    $moment_format    .= $char;
696
-                }
697
-            }
698
-        }
699
-        return array('js' => $jquery_ui_format, 'moment' => $moment_format);
700
-    }
701
-
702
-
703
-    /**
704
-     * This takes an incoming format string and validates it to ensure it will work fine with PHP.
705
-     *
706
-     * @param string $format_string   Incoming format string for php date().
707
-     * @return mixed bool|array  If all is okay then TRUE is returned.  Otherwise an array of validation
708
-     *                                errors is returned.  So for client code calling, check for is_array() to
709
-     *                                indicate failed validations.
710
-     */
711
-    public static function validate_format_string($format_string)
712
-    {
713
-        $error_msg = array();
714
-        //time format checks
715
-        switch (true) {
716
-            case   strpos($format_string, 'h') !== false  :
717
-            case   strpos($format_string, 'g') !== false :
718
-                /**
719
-                 * if the time string has a lowercase 'h' which == 12 hour time format and there
720
-                 * is not any ante meridiem format ('a' or 'A').  Then throw an error because its
721
-                 * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am.
722
-                 */
723
-                if (stripos($format_string, 'A') === false) {
724
-                    $error_msg[] = esc_html__(
725
-                        'There is a  time format for 12 hour time but no  "a" or "A" to indicate am/pm.  Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".',
726
-                        'event_espresso'
727
-                    );
728
-                }
729
-                break;
730
-        }
731
-        return empty($error_msg) ? true : $error_msg;
732
-    }
733
-
734
-
735
-    /**
736
-     *     If the the first date starts at midnight on one day, and the next date ends at midnight on the
737
-     *     very next day then this method will return true.
738
-     *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true.
739
-     *    If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false.
740
-     *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true.
741
-     *
742
-     * @param mixed $date_1
743
-     * @param mixed $date_2
744
-     * @return bool
745
-     */
746
-    public static function dates_represent_one_24_hour_date($date_1, $date_2)
747
-    {
748
-
749
-        if (
750
-            (! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime)
751
-            || ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00'
752
-                || $date_2->format(
753
-                    EE_Datetime_Field::mysql_time_format
754
-                ) !== '00:00:00')
755
-        ) {
756
-            return false;
757
-        }
758
-        return $date_2->format('U') - $date_1->format('U') === 86400;
759
-    }
760
-
761
-
762
-    /**
763
-     * This returns the appropriate query interval string that can be used in sql queries involving mysql Date
764
-     * Functions.
765
-     *
766
-     * @param string $timezone_string    A timezone string in a valid format to instantiate a DateTimeZone object.
767
-     * @param string $field_for_interval The Database field that is the interval is applied to in the query.
768
-     * @return string
769
-     */
770
-    public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval)
771
-    {
772
-        try {
773
-            /** need to account for timezone offset on the selects */
774
-            $DateTimeZone = new DateTimeZone($timezone_string);
775
-        } catch (Exception $e) {
776
-            $DateTimeZone = null;
777
-        }
778
-        /**
779
-         * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds.
780
-         * Hence we do the calc for DateTimeZone::getOffset.
781
-         */
782
-        $offset         = $DateTimeZone instanceof DateTimeZone
783
-            ? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS
784
-            : (float) get_option('gmt_offset');
785
-        $query_interval = $offset < 0
786
-            ? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)'
787
-            : 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)';
788
-        return $query_interval;
789
-    }
790
-
791
-
792
-    /**
793
-     * Retrieves the site's default timezone and returns it formatted so it's ready for display
794
-     * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string'
795
-     * and 'gmt_offset' WordPress options directly; or use the filter
796
-     * FHEE__EEH_DTT_Helper__get_timezone_string_for_display
797
-     * (although note that we remove any HTML that may be added)
798
-     *
799
-     * @return string
800
-     */
801
-    public static function get_timezone_string_for_display()
802
-    {
803
-        $pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', '');
804
-        if (! empty($pretty_timezone)) {
805
-            return esc_html($pretty_timezone);
806
-        }
807
-        $timezone_string = get_option('timezone_string');
808
-        if ($timezone_string) {
809
-            static $mo_loaded = false;
810
-            // Load translations for continents and cities just like wp_timezone_choice does
811
-            if (! $mo_loaded) {
812
-                $locale = get_locale();
813
-                $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
814
-                load_textdomain('continents-cities', $mofile);
815
-                $mo_loaded = true;
816
-            }
817
-            //well that was easy.
818
-            $parts = explode('/', $timezone_string);
819
-            //remove the continent
820
-            unset($parts[0]);
821
-            $t_parts = array();
822
-            foreach ($parts as $part) {
823
-                $t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities');
824
-            }
825
-            return implode(' - ', $t_parts);
826
-        }
827
-        //they haven't set the timezone string, so let's return a string like "UTC+1"
828
-        $gmt_offset = get_option('gmt_offset');
829
-        $prefix     = (int) $gmt_offset >= 0 ? '+' : '';
830
-        $parts      = explode('.', (string) $gmt_offset);
831
-        if (count($parts) === 1) {
832
-            $parts[1] = '00';
833
-        } else {
834
-            //convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25)
835
-            //to minutes, eg 30 or 15, respectively
836
-            $hour_fraction = (float) ('0.' . $parts[1]);
837
-            $parts[1]      = (string) $hour_fraction * 60;
838
-        }
839
-        return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts));
840
-    }
841
-
842
-
843
-
844
-    /**
845
-     * So PHP does this awesome thing where if you are trying to get a timestamp
846
-     * for a month using a string like "February" or "February 2017",
847
-     * and you don't specify a day as part of your string,
848
-     * then PHP will use whatever the current day of the month is.
849
-     * IF the current day of the month happens to be the 30th or 31st,
850
-     * then PHP gets really confused by a date like February 30,
851
-     * so instead of saying
852
-     *      "Hey February only has 28 days (this year)...
853
-     *      ...you must have meant the last day of the month!"
854
-     * PHP does the next most logical thing, and bumps the date up to March 2nd,
855
-     * because someone requesting February 30th obviously meant March 1st!
856
-     * The way around this is to always set the day to the first,
857
-     * so that the month will stay on the month you wanted.
858
-     * this method will add that "1" into your date regardless of the format.
859
-     *
860
-     * @param string $month
861
-     * @return string
862
-     */
863
-    public static function first_of_month_timestamp($month = '')
864
-    {
865
-        $month = (string) $month;
866
-        $year  = '';
867
-        // check if the incoming string has a year in it or not
868
-        if (preg_match('/\b\d{4}\b/', $month, $matches)) {
869
-            $year = $matches[0];
870
-            // ten remove that from the month string as well as any spaces
871
-            $month = trim(str_replace($year, '', $month));
872
-            // add a space before the year
873
-            $year = " {$year}";
874
-        }
875
-        // return timestamp for something like "February 1 2017"
876
-        return strtotime("{$month} 1{$year}");
877
-    }
878
-
879
-
880
-    /**
881
-     * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone.  So it may be midnight
882
-     * for this sites timezone, but the timestamp could be some other time GMT.
883
-     */
884
-    public static function tomorrow()
885
-    {
886
-        //The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive
887
-        //before adding to the timestamp.  Why? Because we want tomorrow to be for midnight the next day in THIS timezone
888
-        //not an offset from midnight in UTC.  So if we're starting with UTC 00:00:00, then we want to make sure the
889
-        //final timestamp is equivalent to midnight in this timezone as represented in GMT.
890
-        return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1);
891
-    }
892
-
893
-
894
-    /**
895
-     * **
896
-     * Gives a nicely-formatted list of timezone strings.
897
-     * Copied from the core wp function by the same name so we could customize to remove UTC offsets.
898
-     *
899
-     * @since     4.9.40.rc.008
900
-     * @staticvar bool $mo_loaded
901
-     * @staticvar string $locale_loaded
902
-     * @param string $selected_zone Selected timezone.
903
-     * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
904
-     * @return string
905
-     */
906
-    public static function wp_timezone_choice($selected_zone, $locale = null)
907
-    {
908
-        static $mo_loaded = false, $locale_loaded = null;
909
-        $continents = array(
910
-            'Africa',
911
-            'America',
912
-            'Antarctica',
913
-            'Arctic',
914
-            'Asia',
915
-            'Atlantic',
916
-            'Australia',
917
-            'Europe',
918
-            'Indian',
919
-            'Pacific',
920
-        );
921
-        // Load translations for continents and cities.
922
-        if (! $mo_loaded || $locale !== $locale_loaded) {
923
-            $locale_loaded = $locale ? $locale : get_locale();
924
-            $mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
925
-            unload_textdomain('continents-cities');
926
-            load_textdomain('continents-cities', $mofile);
927
-            $mo_loaded = true;
928
-        }
929
-        $zone_data = array();
930
-        foreach (timezone_identifiers_list() as $zone) {
931
-            $zone = explode('/', $zone);
932
-            if (! in_array($zone[0], $continents, true)) {
933
-                continue;
934
-            }
935
-            // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
936
-            $exists      = array(
937
-                0 => isset($zone[0]) && $zone[0],
938
-                1 => isset($zone[1]) && $zone[1],
939
-                2 => isset($zone[2]) && $zone[2],
940
-            );
941
-            $exists[3]   = $exists[0] && $zone[0] !== 'Etc';
942
-            $exists[4]   = $exists[1] && $exists[3];
943
-            $exists[5]   = $exists[2] && $exists[3];
944
-            $zone_data[] = array(
945
-                'continent'   => $exists[0] ? $zone[0] : '',
946
-                'city'        => $exists[1] ? $zone[1] : '',
947
-                'subcity'     => $exists[2] ? $zone[2] : '',
948
-                't_continent' => $exists[3]
949
-                    ? translate(str_replace('_', ' ', $zone[0]), 'continents-cities')
950
-                    : '',
951
-                't_city'      => $exists[4]
952
-                    ? translate(str_replace('_', ' ', $zone[1]), 'continents-cities')
953
-                    : '',
954
-                't_subcity'   => $exists[5]
955
-                    ? translate(str_replace('_', ' ', $zone[2]), 'continents-cities')
956
-                    : '',
957
-            );
958
-        }
959
-        usort($zone_data, '_wp_timezone_choice_usort_callback');
960
-        $structure = array();
961
-        if (empty($selected_zone)) {
962
-            $structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>';
963
-        }
964
-        foreach ($zone_data as $key => $zone) {
965
-            // Build value in an array to join later
966
-            $value = array($zone['continent']);
967
-            if (empty($zone['city'])) {
968
-                // It's at the continent level (generally won't happen)
969
-                $display = $zone['t_continent'];
970
-            } else {
971
-                // It's inside a continent group
972
-                // Continent optgroup
973
-                if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) {
974
-                    $label       = $zone['t_continent'];
975
-                    $structure[] = '<optgroup label="' . esc_attr($label) . '">';
976
-                }
977
-                // Add the city to the value
978
-                $value[] = $zone['city'];
979
-                $display = $zone['t_city'];
980
-                if (! empty($zone['subcity'])) {
981
-                    // Add the subcity to the value
982
-                    $value[] = $zone['subcity'];
983
-                    $display .= ' - ' . $zone['t_subcity'];
984
-                }
985
-            }
986
-            // Build the value
987
-            $value       = implode('/', $value);
988
-            $selected    = $value === $selected_zone ? ' selected="selected"' : '';
989
-            $structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>'
990
-                           . esc_html($display)
991
-                           . '</option>';
992
-            // Close continent optgroup
993
-            if (! empty($zone['city'])
994
-                && (
995
-                    ! isset($zone_data[ $key + 1 ])
996
-                    || (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent'])
997
-                )
998
-            ) {
999
-                $structure[] = '</optgroup>';
1000
-            }
1001
-        }
1002
-        return implode("\n", $structure);
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0
1008
-     *
1009
-     * @param int|WP_User $user_id
1010
-     * @return string
1011
-     */
1012
-    public static function get_user_locale($user_id = 0)
1013
-    {
1014
-        if (function_exists('get_user_locale')) {
1015
-            return get_user_locale($user_id);
1016
-        }
1017
-        return get_locale();
1018
-    }
1019
-
1020
-
1021
-    /**
1022
-     * Return the appropriate helper adapter for DTT related things.
1023
-     *
1024
-     * @return HelperInterface
1025
-     * @throws InvalidArgumentException
1026
-     * @throws InvalidDataTypeException
1027
-     * @throws InvalidInterfaceException
1028
-     */
1029
-    private static function getHelperAdapter() {
1030
-        $dtt_helper_fqcn = PHP_VERSION_ID < 50600
1031
-            ? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
1032
-            : 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper';
1033
-        return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn);
1034
-    }
1035
-
1036
-
1037
-    /**
1038
-     * Helper function for setting the timezone on a DateTime object.
1039
-     * This is implemented to standardize a workaround for a PHP bug outlined in
1040
-     * https://events.codebasehq.com/projects/event-espresso/tickets/11407 and
1041
-     * https://events.codebasehq.com/projects/event-espresso/tickets/11233
1042
-     *
1043
-     * @param DateTime     $datetime
1044
-     * @param DateTimeZone $timezone
1045
-     */
1046
-    public static function setTimezone(DateTime $datetime, DateTimeZone $timezone)
1047
-    {
1048
-        $datetime->setTimezone($timezone);
1049
-        $datetime->getTimestamp();
1050
-    }
24
+	/**
25
+	 * return the timezone set for the WP install
26
+	 *
27
+	 * @return string valid timezone string for PHP DateTimeZone() class
28
+	 * @throws InvalidArgumentException
29
+	 * @throws InvalidDataTypeException
30
+	 * @throws InvalidInterfaceException
31
+	 */
32
+	public static function get_timezone()
33
+	{
34
+		return EEH_DTT_Helper::get_valid_timezone_string();
35
+	}
36
+
37
+
38
+	/**
39
+	 * get_valid_timezone_string
40
+	 *    ensures that a valid timezone string is returned
41
+	 *
42
+	 * @param string $timezone_string
43
+	 * @return string
44
+	 * @throws InvalidArgumentException
45
+	 * @throws InvalidDataTypeException
46
+	 * @throws InvalidInterfaceException
47
+	 */
48
+	public static function get_valid_timezone_string($timezone_string = '')
49
+	{
50
+		return self::getHelperAdapter()->getValidTimezoneString($timezone_string);
51
+	}
52
+
53
+
54
+	/**
55
+	 * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
56
+	 *
57
+	 * @static
58
+	 * @param  string $timezone_string Timezone string to check
59
+	 * @param bool    $throw_error
60
+	 * @return bool
61
+	 * @throws InvalidArgumentException
62
+	 * @throws InvalidDataTypeException
63
+	 * @throws InvalidInterfaceException
64
+	 */
65
+	public static function validate_timezone($timezone_string, $throw_error = true)
66
+	{
67
+		return self::getHelperAdapter()->validateTimezone($timezone_string, $throw_error);
68
+	}
69
+
70
+
71
+	/**
72
+	 * This returns a string that can represent the provided gmt offset in format that can be passed into
73
+	 * DateTimeZone.  This is NOT a string that can be passed as a value on the WordPress timezone_string option.
74
+	 *
75
+	 * @param float|string $gmt_offset
76
+	 * @return string
77
+	 * @throws InvalidArgumentException
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 */
81
+	public static function get_timezone_string_from_gmt_offset($gmt_offset = '')
82
+	{
83
+		return self::getHelperAdapter()->getTimezoneStringFromGmtOffset($gmt_offset);
84
+	}
85
+
86
+
87
+	/**
88
+	 * Gets the site's GMT offset based on either the timezone string
89
+	 * (in which case teh gmt offset will vary depending on the location's
90
+	 * observance of daylight savings time) or the gmt_offset wp option
91
+	 *
92
+	 * @return int seconds offset
93
+	 * @throws InvalidArgumentException
94
+	 * @throws InvalidDataTypeException
95
+	 * @throws InvalidInterfaceException
96
+	 */
97
+	public static function get_site_timezone_gmt_offset()
98
+	{
99
+		return self::getHelperAdapter()->getSiteTimezoneGmtOffset();
100
+	}
101
+
102
+
103
+	/**
104
+	 * Depending on PHP version,
105
+	 * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables.
106
+	 * To get around that, for these fringe timezones we bump them to a known valid offset.
107
+	 * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset.
108
+	 *
109
+	 * @deprecated 4.9.54.rc    Developers this was always meant to only be an internally used method.  This will be
110
+	 *                          removed in a future version of EE.
111
+	 * @param int $gmt_offset
112
+	 * @return int
113
+	 * @throws InvalidArgumentException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws InvalidInterfaceException
116
+	 */
117
+	public static function adjust_invalid_gmt_offsets($gmt_offset = 0)
118
+	{
119
+		return self::getHelperAdapter()->adjustInvalidGmtOffsets($gmt_offset);
120
+	}
121
+
122
+
123
+	/**
124
+	 * get_timezone_string_from_abbreviations_list
125
+	 *
126
+	 * @deprecated 4.9.54.rc  Developers, this was never intended to be public.  This is a soft deprecation for now.
127
+	 *                        If you are using this, you'll want to work out an alternate way of getting the value.
128
+	 * @param int  $gmt_offset
129
+	 * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset.
130
+	 * @return string
131
+	 * @throws EE_Error
132
+	 * @throws InvalidArgumentException
133
+	 * @throws InvalidDataTypeException
134
+	 * @throws InvalidInterfaceException
135
+	 */
136
+	public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true)
137
+	{
138
+		$gmt_offset =  (int) $gmt_offset;
139
+		/** @var array[] $abbreviations */
140
+		$abbreviations = DateTimeZone::listAbbreviations();
141
+		foreach ($abbreviations as $abbreviation) {
142
+			foreach ($abbreviation as $timezone) {
143
+				if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) {
144
+					try {
145
+						$offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id']));
146
+						if ($offset !== $gmt_offset) {
147
+							continue;
148
+						}
149
+						return $timezone['timezone_id'];
150
+					} catch (Exception $e) {
151
+						continue;
152
+					}
153
+				}
154
+			}
155
+		}
156
+		//if $coerce is true, let's see if we can get a timezone string after the offset is adjusted
157
+		if ($coerce === true) {
158
+			$timezone_string = self::get_timezone_string_from_abbreviations_list(
159
+				self::adjust_invalid_gmt_offsets($gmt_offset),
160
+				false
161
+			);
162
+			if ($timezone_string) {
163
+				return $timezone_string;
164
+			}
165
+		}
166
+		throw new EE_Error(
167
+			sprintf(
168
+				esc_html__(
169
+					'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
170
+					'event_espresso'
171
+				),
172
+				$gmt_offset / HOUR_IN_SECONDS,
173
+				'<a href="http://www.php.net/manual/en/timezones.php">',
174
+				'</a>'
175
+			)
176
+		);
177
+	}
178
+
179
+
180
+	/**
181
+	 * Get Timezone Transitions
182
+	 *
183
+	 * @param DateTimeZone $date_time_zone
184
+	 * @param int|null     $time
185
+	 * @param bool         $first_only
186
+	 * @return array
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 */
191
+	public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
192
+	{
193
+		return self::getHelperAdapter()->getTimezoneTransitions($date_time_zone, $time, $first_only);
194
+	}
195
+
196
+
197
+	/**
198
+	 * Get Timezone Offset for given timezone object.
199
+	 *
200
+	 * @param DateTimeZone $date_time_zone
201
+	 * @param null         $time
202
+	 * @return mixed
203
+	 * @throws InvalidArgumentException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 */
207
+	public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null)
208
+	{
209
+		return self::getHelperAdapter()->getTimezoneOffset($date_time_zone, $time);
210
+	}
211
+
212
+
213
+	/**
214
+	 * Prints a select input for the given timezone string.
215
+	 * @param string $timezone_string
216
+	 * @deprecatd 4.9.54.rc   Soft deprecation.  Consider using \EEH_DTT_Helper::wp_timezone_choice instead.
217
+	 * @throws InvalidArgumentException
218
+	 * @throws InvalidDataTypeException
219
+	 * @throws InvalidInterfaceException
220
+	 */
221
+	public static function timezone_select_input($timezone_string = '')
222
+	{
223
+		self::getHelperAdapter()->timezoneSelectInput($timezone_string);
224
+	}
225
+
226
+
227
+	/**
228
+	 * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
229
+	 * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
230
+	 * the site is used.
231
+	 * This is used typically when using a Unix timestamp any core WP functions that expect their specially
232
+	 * computed timestamp (i.e. date_i18n() )
233
+	 *
234
+	 * @param int    $unix_timestamp                  if 0, then time() will be used.
235
+	 * @param string $timezone_string                 timezone_string. If empty, then the current set timezone for the
236
+	 *                                                site will be used.
237
+	 * @return int $unix_timestamp with the offset applied for the given timezone.
238
+	 * @throws InvalidArgumentException
239
+	 * @throws InvalidDataTypeException
240
+	 * @throws InvalidInterfaceException
241
+	 */
242
+	public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '')
243
+	{
244
+		return self::getHelperAdapter()->getTimestampWithOffset($unix_timestamp, $timezone_string);
245
+	}
246
+
247
+
248
+	/**
249
+	 *    _set_date_time_field
250
+	 *    modifies EE_Base_Class EE_Datetime_Field objects
251
+	 *
252
+	 * @param  EE_Base_Class $obj                 EE_Base_Class object
253
+	 * @param    DateTime    $DateTime            PHP DateTime object
254
+	 * @param  string        $datetime_field_name the datetime fieldname to be manipulated
255
+	 * @return EE_Base_Class
256
+	 * @throws EE_Error
257
+	 */
258
+	protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name)
259
+	{
260
+		// grab current datetime format
261
+		$current_format = $obj->get_format();
262
+		// set new full timestamp format
263
+		$obj->set_date_format(EE_Datetime_Field::mysql_date_format);
264
+		$obj->set_time_format(EE_Datetime_Field::mysql_time_format);
265
+		// set the new date value using a full timestamp format so that no data is lost
266
+		$obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format));
267
+		// reset datetime formats
268
+		$obj->set_date_format($current_format[0]);
269
+		$obj->set_time_format($current_format[1]);
270
+		return $obj;
271
+	}
272
+
273
+
274
+	/**
275
+	 *    date_time_add
276
+	 *    helper for doing simple datetime calculations on a given datetime from EE_Base_Class
277
+	 *    and modifying it IN the EE_Base_Class so you don't have to do anything else.
278
+	 *
279
+	 * @param  EE_Base_Class $obj                 EE_Base_Class object
280
+	 * @param  string        $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
281
+	 * @param  string        $period              what you are adding. The options are (years, months, days, hours,
282
+	 *                                            minutes, seconds) defaults to years
283
+	 * @param  integer       $value               what you want to increment the time by
284
+	 * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it
285
+	 *                                            (chaining)
286
+	 * @throws EE_Error
287
+	 * @throws Exception
288
+	 */
289
+	public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
290
+	{
291
+		//get the raw UTC date.
292
+		$DateTime = $obj->get_DateTime_object($datetime_field_name);
293
+		$DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value);
294
+		return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
295
+	}
296
+
297
+
298
+	/**
299
+	 *    date_time_subtract
300
+	 *    same as date_time_add except subtracting value instead of adding.
301
+	 *
302
+	 * @param EE_Base_Class $obj
303
+	 * @param  string       $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated
304
+	 * @param string        $period
305
+	 * @param int           $value
306
+	 * @return EE_Base_Class
307
+	 * @throws EE_Error
308
+	 * @throws Exception
309
+	 */
310
+	public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1)
311
+	{
312
+		//get the raw UTC date
313
+		$DateTime = $obj->get_DateTime_object($datetime_field_name);
314
+		$DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-');
315
+		return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name);
316
+	}
317
+
318
+
319
+	/**
320
+	 * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters
321
+	 *
322
+	 * @param  DateTime   $DateTime DateTime object
323
+	 * @param  string     $period   a value to indicate what interval is being used in the calculation. The options are
324
+	 *                              'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
325
+	 * @param  int|string $value    What you want to increment the date by
326
+	 * @param  string     $operand  What operand you wish to use for the calculation
327
+	 * @return DateTime return whatever type came in.
328
+	 * @throws Exception
329
+	 * @throws EE_Error
330
+	 */
331
+	protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+')
332
+	{
333
+		if (! $DateTime instanceof DateTime) {
334
+			throw new EE_Error(
335
+				sprintf(
336
+					esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'),
337
+					print_r($DateTime, true)
338
+				)
339
+			);
340
+		}
341
+		switch ($period) {
342
+			case 'years' :
343
+				$value = 'P' . $value . 'Y';
344
+				break;
345
+			case 'months' :
346
+				$value = 'P' . $value . 'M';
347
+				break;
348
+			case 'weeks' :
349
+				$value = 'P' . $value . 'W';
350
+				break;
351
+			case 'days' :
352
+				$value = 'P' . $value . 'D';
353
+				break;
354
+			case 'hours' :
355
+				$value = 'PT' . $value . 'H';
356
+				break;
357
+			case 'minutes' :
358
+				$value = 'PT' . $value . 'M';
359
+				break;
360
+			case 'seconds' :
361
+				$value = 'PT' . $value . 'S';
362
+				break;
363
+		}
364
+		switch ($operand) {
365
+			case '+':
366
+				$DateTime->add(new DateInterval($value));
367
+				break;
368
+			case '-':
369
+				$DateTime->sub(new DateInterval($value));
370
+				break;
371
+		}
372
+		return $DateTime;
373
+	}
374
+
375
+
376
+	/**
377
+	 * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters
378
+	 *
379
+	 * @param  int     $timestamp Unix timestamp
380
+	 * @param  string  $period    a value to indicate what interval is being used in the calculation. The options are
381
+	 *                            'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years.
382
+	 * @param  integer $value     What you want to increment the date by
383
+	 * @param  string  $operand   What operand you wish to use for the calculation
384
+	 * @return int
385
+	 * @throws EE_Error
386
+	 */
387
+	protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+')
388
+	{
389
+		if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) {
390
+			throw new EE_Error(
391
+				sprintf(
392
+					esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'),
393
+					print_r($timestamp, true)
394
+				)
395
+			);
396
+		}
397
+		switch ($period) {
398
+			case 'years' :
399
+				$value = YEAR_IN_SECONDS * $value;
400
+				break;
401
+			case 'months' :
402
+				$value = YEAR_IN_SECONDS / 12 * $value;
403
+				break;
404
+			case 'weeks' :
405
+				$value = WEEK_IN_SECONDS * $value;
406
+				break;
407
+			case 'days' :
408
+				$value = DAY_IN_SECONDS * $value;
409
+				break;
410
+			case 'hours' :
411
+				$value = HOUR_IN_SECONDS * $value;
412
+				break;
413
+			case 'minutes' :
414
+				$value = MINUTE_IN_SECONDS * $value;
415
+				break;
416
+		}
417
+		switch ($operand) {
418
+			case '+':
419
+				$timestamp += $value;
420
+				break;
421
+			case '-':
422
+				$timestamp -= $value;
423
+				break;
424
+		}
425
+		return $timestamp;
426
+	}
427
+
428
+
429
+	/**
430
+	 * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming
431
+	 * parameters and returns the new timestamp or DateTime.
432
+	 *
433
+	 * @param  int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp
434
+	 * @param  string         $period                a value to indicate what interval is being used in the
435
+	 *                                               calculation. The options are 'years', 'months', 'days', 'hours',
436
+	 *                                               'minutes', 'seconds'. Defaults to years.
437
+	 * @param  integer        $value                 What you want to increment the date by
438
+	 * @param  string         $operand               What operand you wish to use for the calculation
439
+	 * @return mixed string|DateTime          return whatever type came in.
440
+	 * @throws Exception
441
+	 * @throws EE_Error
442
+	 */
443
+	public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+')
444
+	{
445
+		if ($DateTime_or_timestamp instanceof DateTime) {
446
+			return EEH_DTT_Helper::_modify_datetime_object(
447
+				$DateTime_or_timestamp,
448
+				$period,
449
+				$value,
450
+				$operand
451
+			);
452
+		}
453
+		if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) {
454
+			return EEH_DTT_Helper::_modify_timestamp(
455
+				$DateTime_or_timestamp,
456
+				$period,
457
+				$value,
458
+				$operand
459
+			);
460
+		}
461
+		//error
462
+		return $DateTime_or_timestamp;
463
+	}
464
+
465
+
466
+	/**
467
+	 * The purpose of this helper method is to receive an incoming format string in php date/time format
468
+	 * and spit out the js and moment.js equivalent formats.
469
+	 * Note, if no format string is given, then it is assumed the user wants what is set for WP.
470
+	 * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date-
471
+	 * time picker.
472
+	 *
473
+	 * @see http://stackoverflow.com/posts/16725290/ for the code inspiration.
474
+	 * @param string $date_format_string
475
+	 * @param string $time_format_string
476
+	 * @return array
477
+	 *              array(
478
+	 *              'js' => array (
479
+	 *              'date' => //date format
480
+	 *              'time' => //time format
481
+	 *              ),
482
+	 *              'moment' => //date and time format.
483
+	 *              )
484
+	 */
485
+	public static function convert_php_to_js_and_moment_date_formats(
486
+		$date_format_string = null,
487
+		$time_format_string = null
488
+	) {
489
+		if ($date_format_string === null) {
490
+			$date_format_string = (string) get_option('date_format');
491
+		}
492
+		if ($time_format_string === null) {
493
+			$time_format_string = (string) get_option('time_format');
494
+		}
495
+		$date_format = self::_php_to_js_moment_converter($date_format_string);
496
+		$time_format = self::_php_to_js_moment_converter($time_format_string);
497
+		return array(
498
+			'js'     => array(
499
+				'date' => $date_format['js'],
500
+				'time' => $time_format['js'],
501
+			),
502
+			'moment' => $date_format['moment'] . ' ' . $time_format['moment'],
503
+		);
504
+	}
505
+
506
+
507
+	/**
508
+	 * This converts incoming format string into js and moment variations.
509
+	 *
510
+	 * @param string $format_string incoming php format string
511
+	 * @return array js and moment formats.
512
+	 */
513
+	protected static function _php_to_js_moment_converter($format_string)
514
+	{
515
+		/**
516
+		 * This is a map of symbols for formats.
517
+		 * The index is the php symbol, the equivalent values are in the array.
518
+		 *
519
+		 * @var array
520
+		 */
521
+		$symbols_map          = array(
522
+			// Day
523
+			//01
524
+			'd' => array(
525
+				'js'     => 'dd',
526
+				'moment' => 'DD',
527
+			),
528
+			//Mon
529
+			'D' => array(
530
+				'js'     => 'D',
531
+				'moment' => 'ddd',
532
+			),
533
+			//1,2,...31
534
+			'j' => array(
535
+				'js'     => 'd',
536
+				'moment' => 'D',
537
+			),
538
+			//Monday
539
+			'l' => array(
540
+				'js'     => 'DD',
541
+				'moment' => 'dddd',
542
+			),
543
+			//ISO numeric representation of the day of the week (1-6)
544
+			'N' => array(
545
+				'js'     => '',
546
+				'moment' => 'E',
547
+			),
548
+			//st,nd.rd
549
+			'S' => array(
550
+				'js'     => '',
551
+				'moment' => 'o',
552
+			),
553
+			//numeric representation of day of week (0-6)
554
+			'w' => array(
555
+				'js'     => '',
556
+				'moment' => 'd',
557
+			),
558
+			//day of year starting from 0 (0-365)
559
+			'z' => array(
560
+				'js'     => 'o',
561
+				'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1
562
+			),
563
+			// Week
564
+			//ISO-8601 week number of year (weeks starting on monday)
565
+			'W' => array(
566
+				'js'     => '',
567
+				'moment' => 'w',
568
+			),
569
+			// Month
570
+			// January...December
571
+			'F' => array(
572
+				'js'     => 'MM',
573
+				'moment' => 'MMMM',
574
+			),
575
+			//01...12
576
+			'm' => array(
577
+				'js'     => 'mm',
578
+				'moment' => 'MM',
579
+			),
580
+			//Jan...Dec
581
+			'M' => array(
582
+				'js'     => 'M',
583
+				'moment' => 'MMM',
584
+			),
585
+			//1-12
586
+			'n' => array(
587
+				'js'     => 'm',
588
+				'moment' => 'M',
589
+			),
590
+			//number of days in given month
591
+			't' => array(
592
+				'js'     => '',
593
+				'moment' => '',
594
+			),
595
+			// Year
596
+			//whether leap year or not 1/0
597
+			'L' => array(
598
+				'js'     => '',
599
+				'moment' => '',
600
+			),
601
+			//ISO-8601 year number
602
+			'o' => array(
603
+				'js'     => '',
604
+				'moment' => 'GGGG',
605
+			),
606
+			//1999...2003
607
+			'Y' => array(
608
+				'js'     => 'yy',
609
+				'moment' => 'YYYY',
610
+			),
611
+			//99...03
612
+			'y' => array(
613
+				'js'     => 'y',
614
+				'moment' => 'YY',
615
+			),
616
+			// Time
617
+			// am/pm
618
+			'a' => array(
619
+				'js'     => 'tt',
620
+				'moment' => 'a',
621
+			),
622
+			// AM/PM
623
+			'A' => array(
624
+				'js'     => 'TT',
625
+				'moment' => 'A',
626
+			),
627
+			// Swatch Internet Time?!?
628
+			'B' => array(
629
+				'js'     => '',
630
+				'moment' => '',
631
+			),
632
+			//1...12
633
+			'g' => array(
634
+				'js'     => 'h',
635
+				'moment' => 'h',
636
+			),
637
+			//0...23
638
+			'G' => array(
639
+				'js'     => 'H',
640
+				'moment' => 'H',
641
+			),
642
+			//01...12
643
+			'h' => array(
644
+				'js'     => 'hh',
645
+				'moment' => 'hh',
646
+			),
647
+			//00...23
648
+			'H' => array(
649
+				'js'     => 'HH',
650
+				'moment' => 'HH',
651
+			),
652
+			//00..59
653
+			'i' => array(
654
+				'js'     => 'mm',
655
+				'moment' => 'mm',
656
+			),
657
+			//seconds... 00...59
658
+			's' => array(
659
+				'js'     => 'ss',
660
+				'moment' => 'ss',
661
+			),
662
+			//microseconds
663
+			'u' => array(
664
+				'js'     => '',
665
+				'moment' => '',
666
+			),
667
+		);
668
+		$jquery_ui_format     = '';
669
+		$moment_format        = '';
670
+		$escaping             = false;
671
+		$format_string_length = strlen($format_string);
672
+		for ($i = 0; $i < $format_string_length; $i++) {
673
+			$char = $format_string[ $i ];
674
+			if ($char === '\\') { // PHP date format escaping character
675
+				$i++;
676
+				if ($escaping) {
677
+					$jquery_ui_format .= $format_string[ $i ];
678
+					$moment_format    .= $format_string[ $i ];
679
+				} else {
680
+					$jquery_ui_format .= '\'' . $format_string[ $i ];
681
+					$moment_format    .= $format_string[ $i ];
682
+				}
683
+				$escaping = true;
684
+			} else {
685
+				if ($escaping) {
686
+					$jquery_ui_format .= "'";
687
+					$moment_format    .= "'";
688
+					$escaping         = false;
689
+				}
690
+				if (isset($symbols_map[ $char ])) {
691
+					$jquery_ui_format .= $symbols_map[ $char ]['js'];
692
+					$moment_format    .= $symbols_map[ $char ]['moment'];
693
+				} else {
694
+					$jquery_ui_format .= $char;
695
+					$moment_format    .= $char;
696
+				}
697
+			}
698
+		}
699
+		return array('js' => $jquery_ui_format, 'moment' => $moment_format);
700
+	}
701
+
702
+
703
+	/**
704
+	 * This takes an incoming format string and validates it to ensure it will work fine with PHP.
705
+	 *
706
+	 * @param string $format_string   Incoming format string for php date().
707
+	 * @return mixed bool|array  If all is okay then TRUE is returned.  Otherwise an array of validation
708
+	 *                                errors is returned.  So for client code calling, check for is_array() to
709
+	 *                                indicate failed validations.
710
+	 */
711
+	public static function validate_format_string($format_string)
712
+	{
713
+		$error_msg = array();
714
+		//time format checks
715
+		switch (true) {
716
+			case   strpos($format_string, 'h') !== false  :
717
+			case   strpos($format_string, 'g') !== false :
718
+				/**
719
+				 * if the time string has a lowercase 'h' which == 12 hour time format and there
720
+				 * is not any ante meridiem format ('a' or 'A').  Then throw an error because its
721
+				 * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am.
722
+				 */
723
+				if (stripos($format_string, 'A') === false) {
724
+					$error_msg[] = esc_html__(
725
+						'There is a  time format for 12 hour time but no  "a" or "A" to indicate am/pm.  Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".',
726
+						'event_espresso'
727
+					);
728
+				}
729
+				break;
730
+		}
731
+		return empty($error_msg) ? true : $error_msg;
732
+	}
733
+
734
+
735
+	/**
736
+	 *     If the the first date starts at midnight on one day, and the next date ends at midnight on the
737
+	 *     very next day then this method will return true.
738
+	 *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true.
739
+	 *    If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false.
740
+	 *    If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true.
741
+	 *
742
+	 * @param mixed $date_1
743
+	 * @param mixed $date_2
744
+	 * @return bool
745
+	 */
746
+	public static function dates_represent_one_24_hour_date($date_1, $date_2)
747
+	{
748
+
749
+		if (
750
+			(! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime)
751
+			|| ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00'
752
+				|| $date_2->format(
753
+					EE_Datetime_Field::mysql_time_format
754
+				) !== '00:00:00')
755
+		) {
756
+			return false;
757
+		}
758
+		return $date_2->format('U') - $date_1->format('U') === 86400;
759
+	}
760
+
761
+
762
+	/**
763
+	 * This returns the appropriate query interval string that can be used in sql queries involving mysql Date
764
+	 * Functions.
765
+	 *
766
+	 * @param string $timezone_string    A timezone string in a valid format to instantiate a DateTimeZone object.
767
+	 * @param string $field_for_interval The Database field that is the interval is applied to in the query.
768
+	 * @return string
769
+	 */
770
+	public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval)
771
+	{
772
+		try {
773
+			/** need to account for timezone offset on the selects */
774
+			$DateTimeZone = new DateTimeZone($timezone_string);
775
+		} catch (Exception $e) {
776
+			$DateTimeZone = null;
777
+		}
778
+		/**
779
+		 * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds.
780
+		 * Hence we do the calc for DateTimeZone::getOffset.
781
+		 */
782
+		$offset         = $DateTimeZone instanceof DateTimeZone
783
+			? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS
784
+			: (float) get_option('gmt_offset');
785
+		$query_interval = $offset < 0
786
+			? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)'
787
+			: 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)';
788
+		return $query_interval;
789
+	}
790
+
791
+
792
+	/**
793
+	 * Retrieves the site's default timezone and returns it formatted so it's ready for display
794
+	 * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string'
795
+	 * and 'gmt_offset' WordPress options directly; or use the filter
796
+	 * FHEE__EEH_DTT_Helper__get_timezone_string_for_display
797
+	 * (although note that we remove any HTML that may be added)
798
+	 *
799
+	 * @return string
800
+	 */
801
+	public static function get_timezone_string_for_display()
802
+	{
803
+		$pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', '');
804
+		if (! empty($pretty_timezone)) {
805
+			return esc_html($pretty_timezone);
806
+		}
807
+		$timezone_string = get_option('timezone_string');
808
+		if ($timezone_string) {
809
+			static $mo_loaded = false;
810
+			// Load translations for continents and cities just like wp_timezone_choice does
811
+			if (! $mo_loaded) {
812
+				$locale = get_locale();
813
+				$mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
814
+				load_textdomain('continents-cities', $mofile);
815
+				$mo_loaded = true;
816
+			}
817
+			//well that was easy.
818
+			$parts = explode('/', $timezone_string);
819
+			//remove the continent
820
+			unset($parts[0]);
821
+			$t_parts = array();
822
+			foreach ($parts as $part) {
823
+				$t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities');
824
+			}
825
+			return implode(' - ', $t_parts);
826
+		}
827
+		//they haven't set the timezone string, so let's return a string like "UTC+1"
828
+		$gmt_offset = get_option('gmt_offset');
829
+		$prefix     = (int) $gmt_offset >= 0 ? '+' : '';
830
+		$parts      = explode('.', (string) $gmt_offset);
831
+		if (count($parts) === 1) {
832
+			$parts[1] = '00';
833
+		} else {
834
+			//convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25)
835
+			//to minutes, eg 30 or 15, respectively
836
+			$hour_fraction = (float) ('0.' . $parts[1]);
837
+			$parts[1]      = (string) $hour_fraction * 60;
838
+		}
839
+		return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts));
840
+	}
841
+
842
+
843
+
844
+	/**
845
+	 * So PHP does this awesome thing where if you are trying to get a timestamp
846
+	 * for a month using a string like "February" or "February 2017",
847
+	 * and you don't specify a day as part of your string,
848
+	 * then PHP will use whatever the current day of the month is.
849
+	 * IF the current day of the month happens to be the 30th or 31st,
850
+	 * then PHP gets really confused by a date like February 30,
851
+	 * so instead of saying
852
+	 *      "Hey February only has 28 days (this year)...
853
+	 *      ...you must have meant the last day of the month!"
854
+	 * PHP does the next most logical thing, and bumps the date up to March 2nd,
855
+	 * because someone requesting February 30th obviously meant March 1st!
856
+	 * The way around this is to always set the day to the first,
857
+	 * so that the month will stay on the month you wanted.
858
+	 * this method will add that "1" into your date regardless of the format.
859
+	 *
860
+	 * @param string $month
861
+	 * @return string
862
+	 */
863
+	public static function first_of_month_timestamp($month = '')
864
+	{
865
+		$month = (string) $month;
866
+		$year  = '';
867
+		// check if the incoming string has a year in it or not
868
+		if (preg_match('/\b\d{4}\b/', $month, $matches)) {
869
+			$year = $matches[0];
870
+			// ten remove that from the month string as well as any spaces
871
+			$month = trim(str_replace($year, '', $month));
872
+			// add a space before the year
873
+			$year = " {$year}";
874
+		}
875
+		// return timestamp for something like "February 1 2017"
876
+		return strtotime("{$month} 1{$year}");
877
+	}
878
+
879
+
880
+	/**
881
+	 * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone.  So it may be midnight
882
+	 * for this sites timezone, but the timestamp could be some other time GMT.
883
+	 */
884
+	public static function tomorrow()
885
+	{
886
+		//The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive
887
+		//before adding to the timestamp.  Why? Because we want tomorrow to be for midnight the next day in THIS timezone
888
+		//not an offset from midnight in UTC.  So if we're starting with UTC 00:00:00, then we want to make sure the
889
+		//final timestamp is equivalent to midnight in this timezone as represented in GMT.
890
+		return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1);
891
+	}
892
+
893
+
894
+	/**
895
+	 * **
896
+	 * Gives a nicely-formatted list of timezone strings.
897
+	 * Copied from the core wp function by the same name so we could customize to remove UTC offsets.
898
+	 *
899
+	 * @since     4.9.40.rc.008
900
+	 * @staticvar bool $mo_loaded
901
+	 * @staticvar string $locale_loaded
902
+	 * @param string $selected_zone Selected timezone.
903
+	 * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
904
+	 * @return string
905
+	 */
906
+	public static function wp_timezone_choice($selected_zone, $locale = null)
907
+	{
908
+		static $mo_loaded = false, $locale_loaded = null;
909
+		$continents = array(
910
+			'Africa',
911
+			'America',
912
+			'Antarctica',
913
+			'Arctic',
914
+			'Asia',
915
+			'Atlantic',
916
+			'Australia',
917
+			'Europe',
918
+			'Indian',
919
+			'Pacific',
920
+		);
921
+		// Load translations for continents and cities.
922
+		if (! $mo_loaded || $locale !== $locale_loaded) {
923
+			$locale_loaded = $locale ? $locale : get_locale();
924
+			$mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
925
+			unload_textdomain('continents-cities');
926
+			load_textdomain('continents-cities', $mofile);
927
+			$mo_loaded = true;
928
+		}
929
+		$zone_data = array();
930
+		foreach (timezone_identifiers_list() as $zone) {
931
+			$zone = explode('/', $zone);
932
+			if (! in_array($zone[0], $continents, true)) {
933
+				continue;
934
+			}
935
+			// This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
936
+			$exists      = array(
937
+				0 => isset($zone[0]) && $zone[0],
938
+				1 => isset($zone[1]) && $zone[1],
939
+				2 => isset($zone[2]) && $zone[2],
940
+			);
941
+			$exists[3]   = $exists[0] && $zone[0] !== 'Etc';
942
+			$exists[4]   = $exists[1] && $exists[3];
943
+			$exists[5]   = $exists[2] && $exists[3];
944
+			$zone_data[] = array(
945
+				'continent'   => $exists[0] ? $zone[0] : '',
946
+				'city'        => $exists[1] ? $zone[1] : '',
947
+				'subcity'     => $exists[2] ? $zone[2] : '',
948
+				't_continent' => $exists[3]
949
+					? translate(str_replace('_', ' ', $zone[0]), 'continents-cities')
950
+					: '',
951
+				't_city'      => $exists[4]
952
+					? translate(str_replace('_', ' ', $zone[1]), 'continents-cities')
953
+					: '',
954
+				't_subcity'   => $exists[5]
955
+					? translate(str_replace('_', ' ', $zone[2]), 'continents-cities')
956
+					: '',
957
+			);
958
+		}
959
+		usort($zone_data, '_wp_timezone_choice_usort_callback');
960
+		$structure = array();
961
+		if (empty($selected_zone)) {
962
+			$structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>';
963
+		}
964
+		foreach ($zone_data as $key => $zone) {
965
+			// Build value in an array to join later
966
+			$value = array($zone['continent']);
967
+			if (empty($zone['city'])) {
968
+				// It's at the continent level (generally won't happen)
969
+				$display = $zone['t_continent'];
970
+			} else {
971
+				// It's inside a continent group
972
+				// Continent optgroup
973
+				if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) {
974
+					$label       = $zone['t_continent'];
975
+					$structure[] = '<optgroup label="' . esc_attr($label) . '">';
976
+				}
977
+				// Add the city to the value
978
+				$value[] = $zone['city'];
979
+				$display = $zone['t_city'];
980
+				if (! empty($zone['subcity'])) {
981
+					// Add the subcity to the value
982
+					$value[] = $zone['subcity'];
983
+					$display .= ' - ' . $zone['t_subcity'];
984
+				}
985
+			}
986
+			// Build the value
987
+			$value       = implode('/', $value);
988
+			$selected    = $value === $selected_zone ? ' selected="selected"' : '';
989
+			$structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>'
990
+						   . esc_html($display)
991
+						   . '</option>';
992
+			// Close continent optgroup
993
+			if (! empty($zone['city'])
994
+				&& (
995
+					! isset($zone_data[ $key + 1 ])
996
+					|| (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent'])
997
+				)
998
+			) {
999
+				$structure[] = '</optgroup>';
1000
+			}
1001
+		}
1002
+		return implode("\n", $structure);
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0
1008
+	 *
1009
+	 * @param int|WP_User $user_id
1010
+	 * @return string
1011
+	 */
1012
+	public static function get_user_locale($user_id = 0)
1013
+	{
1014
+		if (function_exists('get_user_locale')) {
1015
+			return get_user_locale($user_id);
1016
+		}
1017
+		return get_locale();
1018
+	}
1019
+
1020
+
1021
+	/**
1022
+	 * Return the appropriate helper adapter for DTT related things.
1023
+	 *
1024
+	 * @return HelperInterface
1025
+	 * @throws InvalidArgumentException
1026
+	 * @throws InvalidDataTypeException
1027
+	 * @throws InvalidInterfaceException
1028
+	 */
1029
+	private static function getHelperAdapter() {
1030
+		$dtt_helper_fqcn = PHP_VERSION_ID < 50600
1031
+			? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper'
1032
+			: 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper';
1033
+		return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn);
1034
+	}
1035
+
1036
+
1037
+	/**
1038
+	 * Helper function for setting the timezone on a DateTime object.
1039
+	 * This is implemented to standardize a workaround for a PHP bug outlined in
1040
+	 * https://events.codebasehq.com/projects/event-espresso/tickets/11407 and
1041
+	 * https://events.codebasehq.com/projects/event-espresso/tickets/11233
1042
+	 *
1043
+	 * @param DateTime     $datetime
1044
+	 * @param DateTimeZone $timezone
1045
+	 */
1046
+	public static function setTimezone(DateTime $datetime, DateTimeZone $timezone)
1047
+	{
1048
+		$datetime->setTimezone($timezone);
1049
+		$datetime->getTimestamp();
1050
+	}
1051 1051
 }
1052 1052
\ No newline at end of file
Please login to merge, or discard this patch.
admin_pages/transactions/templates/txn_admin_details_header.template.php 1 patch
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -1,17 +1,17 @@
 block discarded – undo
1 1
 
2
-		<h3 class="txn-navigation-strip"><?php echo $previous_transaction . '&nbsp;'; echo __( 'Transaction # ', 'event_espresso' ) . $txn_nmbr['value']; echo '&nbsp;' . $next_transaction; ?></h3>
3
-		<h2 id="txn-date-h2" class="txn-date-h2"><?php echo $txn_datetime['value'];?></h2>
2
+		<h3 class="txn-navigation-strip"><?php echo $previous_transaction.'&nbsp;'; echo __('Transaction # ', 'event_espresso').$txn_nmbr['value']; echo '&nbsp;'.$next_transaction; ?></h3>
3
+		<h2 id="txn-date-h2" class="txn-date-h2"><?php echo $txn_datetime['value']; ?></h2>
4 4
 		<h2 id="txn-status-h2" class="txn-status-h2">
5
-			<?php echo __( 'Transaction Status: ', 'event_espresso' );?><span id="txn-status" class="<?php echo $txn_status['class'];?>"><?php echo $txn_status['value'];?></span>
5
+			<?php echo __('Transaction Status: ', 'event_espresso'); ?><span id="txn-status" class="<?php echo $txn_status['class']; ?>"><?php echo $txn_status['value']; ?></span>
6 6
 		</h2>
7 7
 
8 8
 	<?php $attributes = $amount_due ? 'class="txn-amount-due-h2"' : 'class="txn-amount-due-h2 hidden"'; ?>
9 9
 		<h2 id="txn-amount-due-h2" <?php echo $attributes; ?>>
10
-			<?php echo __( 'Total Amount Due: ', 'event_espresso' );?><span id="txn-admin-total-amount-due" class="<?php echo $amount_due_class;?>"><?php echo $amount_due;?></span>
10
+			<?php echo __('Total Amount Due: ', 'event_espresso'); ?><span id="txn-admin-total-amount-due" class="<?php echo $amount_due_class; ?>"><?php echo $amount_due; ?></span>
11 11
 		</h2>
12 12
 
13 13
 		<h3 id="txn-selected-method-of-payment-h3" class="txn-selected-method-of-payment-h3">
14
-			<?php echo __( 'Last Method of Payment: ', 'event_espresso' );?><?php echo $method_of_payment_name;?>
14
+			<?php echo __('Last Method of Payment: ', 'event_espresso'); ?><?php echo $method_of_payment_name; ?>
15 15
 		</h3>
16 16
 
17 17
 
Please login to merge, or discard this patch.
reg_steps/payment_options/EE_SPCO_Reg_Step_Payment_Options.class.php 1 patch
Indentation   +2870 added lines, -2870 removed lines patch added patch discarded remove patch
@@ -15,2874 +15,2874 @@
 block discarded – undo
15 15
 class EE_SPCO_Reg_Step_Payment_Options extends EE_SPCO_Reg_Step
16 16
 {
17 17
 
18
-    /**
19
-     * @access protected
20
-     * @var EE_Line_Item_Display $Line_Item_Display
21
-     */
22
-    protected $line_item_display;
23
-
24
-    /**
25
-     * @access protected
26
-     * @var boolean $handle_IPN_in_this_request
27
-     */
28
-    protected $handle_IPN_in_this_request = false;
29
-
30
-
31
-    /**
32
-     *    set_hooks - for hooking into EE Core, other modules, etc
33
-     *
34
-     * @access    public
35
-     * @return    void
36
-     */
37
-    public static function set_hooks()
38
-    {
39
-        add_filter(
40
-            'FHEE__SPCO__EE_Line_Item_Filter_Collection',
41
-            array('EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters')
42
-        );
43
-        add_action(
44
-            'wp_ajax_switch_spco_billing_form',
45
-            array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
46
-        );
47
-        add_action(
48
-            'wp_ajax_nopriv_switch_spco_billing_form',
49
-            array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
50
-        );
51
-        add_action('wp_ajax_save_payer_details', array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details'));
52
-        add_action(
53
-            'wp_ajax_nopriv_save_payer_details',
54
-            array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details')
55
-        );
56
-        add_action(
57
-            'wp_ajax_get_transaction_details_for_gateways',
58
-            array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
59
-        );
60
-        add_action(
61
-            'wp_ajax_nopriv_get_transaction_details_for_gateways',
62
-            array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
63
-        );
64
-        add_filter(
65
-            'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
66
-            array('EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'),
67
-            10,
68
-            1
69
-        );
70
-    }
71
-
72
-
73
-    /**
74
-     *    ajax switch_spco_billing_form
75
-     *
76
-     * @throws \EE_Error
77
-     */
78
-    public static function switch_spco_billing_form()
79
-    {
80
-        EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
81
-    }
82
-
83
-
84
-    /**
85
-     *    ajax save_payer_details
86
-     *
87
-     * @throws \EE_Error
88
-     */
89
-    public static function save_payer_details()
90
-    {
91
-        EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
92
-    }
93
-
94
-
95
-    /**
96
-     *    ajax get_transaction_details
97
-     *
98
-     * @throws \EE_Error
99
-     */
100
-    public static function get_transaction_details()
101
-    {
102
-        EED_Single_Page_Checkout::process_ajax_request('get_transaction_details_for_gateways');
103
-    }
104
-
105
-
106
-    /**
107
-     * bypass_recaptcha_for_load_payment_method
108
-     *
109
-     * @access public
110
-     * @return array
111
-     * @throws InvalidArgumentException
112
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
113
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
114
-     */
115
-    public static function bypass_recaptcha_for_load_payment_method()
116
-    {
117
-        return array(
118
-            'EESID'  => EE_Registry::instance()->SSN->id(),
119
-            'step'   => 'payment_options',
120
-            'action' => 'spco_billing_form',
121
-        );
122
-    }
123
-
124
-
125
-    /**
126
-     *    class constructor
127
-     *
128
-     * @access    public
129
-     * @param    EE_Checkout $checkout
130
-     */
131
-    public function __construct(EE_Checkout $checkout)
132
-    {
133
-        $this->_slug     = 'payment_options';
134
-        $this->_name     = esc_html__('Payment Options', 'event_espresso');
135
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
136
-        $this->checkout  = $checkout;
137
-        $this->_reset_success_message();
138
-        $this->set_instructions(
139
-            esc_html__(
140
-                'Please select a method of payment and provide any necessary billing information before proceeding.',
141
-                'event_espresso'
142
-            )
143
-        );
144
-    }
145
-
146
-
147
-    /**
148
-     * @return null
149
-     */
150
-    public function line_item_display()
151
-    {
152
-        return $this->line_item_display;
153
-    }
154
-
155
-
156
-    /**
157
-     * @param null $line_item_display
158
-     */
159
-    public function set_line_item_display($line_item_display)
160
-    {
161
-        $this->line_item_display = $line_item_display;
162
-    }
163
-
164
-
165
-    /**
166
-     * @return boolean
167
-     */
168
-    public function handle_IPN_in_this_request()
169
-    {
170
-        return $this->handle_IPN_in_this_request;
171
-    }
172
-
173
-
174
-    /**
175
-     * @param boolean $handle_IPN_in_this_request
176
-     */
177
-    public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
178
-    {
179
-        $this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
180
-    }
181
-
182
-
183
-    /**
184
-     * translate_js_strings
185
-     *
186
-     * @return void
187
-     */
188
-    public function translate_js_strings()
189
-    {
190
-        EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
191
-            'Please select a method of payment in order to continue.',
192
-            'event_espresso'
193
-        );
194
-        EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__(
195
-            'A valid method of payment could not be determined. Please refresh the page and try again.',
196
-            'event_espresso'
197
-        );
198
-        EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
199
-            'Forwarding to Secure Payment Provider.',
200
-            'event_espresso'
201
-        );
202
-    }
203
-
204
-
205
-    /**
206
-     * enqueue_styles_and_scripts
207
-     *
208
-     * @return void
209
-     * @throws EE_Error
210
-     * @throws InvalidArgumentException
211
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
212
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
213
-     */
214
-    public function enqueue_styles_and_scripts()
215
-    {
216
-        $transaction = $this->checkout->transaction;
217
-        //if the transaction isn't set or nothing is owed on it, don't enqueue any JS
218
-        if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
219
-            return;
220
-        }
221
-        foreach (EEM_Payment_Method::instance()->get_all_for_transaction($transaction, EEM_Payment_Method::scope_cart) as $payment_method) {
222
-            $type_obj = $payment_method->type_obj();
223
-            if ($type_obj instanceof EE_PMT_Base) {
224
-                $billing_form = $type_obj->generate_new_billing_form($transaction);
225
-                if ($billing_form instanceof EE_Form_Section_Proper) {
226
-                    $billing_form->enqueue_js();
227
-                }
228
-            }
229
-        }
230
-    }
231
-
232
-
233
-    /**
234
-     * initialize_reg_step
235
-     *
236
-     * @return bool
237
-     * @throws EE_Error
238
-     * @throws InvalidArgumentException
239
-     * @throws ReflectionException
240
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
241
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
242
-     */
243
-    public function initialize_reg_step()
244
-    {
245
-        // TODO: if /when we implement donations, then this will need overriding
246
-        if (// don't need payment options for:
247
-            // 	registrations made via the admin
248
-            // 	completed transactions
249
-            // 	overpaid transactions
250
-            // 	$ 0.00 transactions (no payment required)
251
-            ! $this->checkout->payment_required()
252
-            // but do NOT remove if current action being called belongs to this reg step
253
-            && ! is_callable(array($this, $this->checkout->action))
254
-            && ! $this->completed()
255
-        ) {
256
-            // and if so, then we no longer need the Payment Options step
257
-            if ($this->is_current_step()) {
258
-                $this->checkout->generate_reg_form = false;
259
-            }
260
-            $this->checkout->remove_reg_step($this->_slug);
261
-            // DEBUG LOG
262
-            //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
263
-            return false;
264
-        }
265
-        // load EEM_Payment_Method
266
-        EE_Registry::instance()->load_model('Payment_Method');
267
-        // get all active payment methods
268
-        $this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
269
-            $this->checkout->transaction,
270
-            EEM_Payment_Method::scope_cart
271
-        );
272
-        return true;
273
-    }
274
-
275
-
276
-    /**
277
-     * @return EE_Form_Section_Proper
278
-     * @throws EE_Error
279
-     * @throws InvalidArgumentException
280
-     * @throws ReflectionException
281
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
282
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
283
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
284
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
285
-     */
286
-    public function generate_reg_form()
287
-    {
288
-        // reset in case someone changes their mind
289
-        $this->_reset_selected_method_of_payment();
290
-        // set some defaults
291
-        $this->checkout->selected_method_of_payment = 'payments_closed';
292
-        $registrations_requiring_payment            = array();
293
-        $registrations_for_free_events              = array();
294
-        $registrations_requiring_pre_approval       = array();
295
-        $sold_out_events                            = array();
296
-        $insufficient_spaces_available              = array();
297
-        $no_payment_required                        = true;
298
-        // loop thru registrations to gather info
299
-        $registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
300
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
301
-            $registrations,
302
-            $this->checkout->revisit
303
-        );
304
-        foreach ($registrations as $REG_ID => $registration) {
305
-            /** @var $registration EE_Registration */
306
-            // has this registration lost it's space ?
307
-            if (isset($ejected_registrations[ $REG_ID ])) {
308
-                if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
309
-                    $sold_out_events[ $registration->event()->ID() ] = $registration->event();
310
-                } else {
311
-                    $insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
312
-                }
313
-                continue;
314
-            }
315
-            // event requires admin approval
316
-            if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
317
-                // add event to list of events with pre-approval reg status
318
-                $registrations_requiring_pre_approval[$REG_ID] = $registration;
319
-                do_action(
320
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
321
-                    $registration->event(),
322
-                    $this
323
-                );
324
-                continue;
325
-            }
326
-            if ($this->checkout->revisit
327
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
328
-                && (
329
-                    $registration->event()->is_sold_out()
330
-                    || $registration->event()->is_sold_out(true)
331
-                )
332
-            ) {
333
-                // add event to list of events that are sold out
334
-                $sold_out_events[$registration->event()->ID()] = $registration->event();
335
-                do_action(
336
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
337
-                    $registration->event(),
338
-                    $this
339
-                );
340
-                continue;
341
-            }
342
-            // are they allowed to pay now and is there monies owing?
343
-            if ($registration->owes_monies_and_can_pay()) {
344
-                $registrations_requiring_payment[$REG_ID] = $registration;
345
-                do_action(
346
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
347
-                    $registration->event(),
348
-                    $this
349
-                );
350
-            } elseif (! $this->checkout->revisit
351
-                && $registration->status_ID() !== EEM_Registration::status_id_not_approved
352
-                && $registration->ticket()->is_free()
353
-            ) {
354
-                $registrations_for_free_events[$registration->event()->ID()] = $registration;
355
-            }
356
-        }
357
-        $subsections = array();
358
-        // now decide which template to load
359
-        if (! empty($sold_out_events)) {
360
-            $subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
361
-        }
362
-        if (! empty($insufficient_spaces_available)) {
363
-            $subsections['insufficient_space'] = $this->_insufficient_spaces_available(
364
-                $insufficient_spaces_available
365
-            );
366
-        }
367
-        if (! empty($registrations_requiring_pre_approval)) {
368
-            $subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
369
-                $registrations_requiring_pre_approval
370
-            );
371
-        }
372
-        if (! empty($registrations_for_free_events)) {
373
-            $subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
374
-        }
375
-        if (! empty($registrations_requiring_payment)) {
376
-            if ($this->checkout->amount_owing > 0) {
377
-                // autoload Line_Item_Display classes
378
-                EEH_Autoloader::register_line_item_filter_autoloaders();
379
-                $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
380
-                    apply_filters(
381
-                        'FHEE__SPCO__EE_Line_Item_Filter_Collection',
382
-                        new EE_Line_Item_Filter_Collection()
383
-                    ),
384
-                    $this->checkout->cart->get_grand_total()
385
-                );
386
-                /** @var EE_Line_Item $filtered_line_item_tree */
387
-                $filtered_line_item_tree = $line_item_filter_processor->process();
388
-                EEH_Autoloader::register_line_item_display_autoloaders();
389
-                $this->set_line_item_display(new EE_Line_Item_Display('spco'));
390
-                $subsections['payment_options'] = $this->_display_payment_options(
391
-                    $this->line_item_display->display_line_item(
392
-                        $filtered_line_item_tree,
393
-                        array('registrations' => $registrations)
394
-                    )
395
-                );
396
-                $this->checkout->amount_owing   = $filtered_line_item_tree->total();
397
-                $this->_apply_registration_payments_to_amount_owing($registrations);
398
-            }
399
-            $no_payment_required = false;
400
-        } else {
401
-            $this->_hide_reg_step_submit_button_if_revisit();
402
-        }
403
-        $this->_save_selected_method_of_payment();
404
-
405
-        $subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
406
-        $subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
407
-
408
-        return new EE_Form_Section_Proper(
409
-            array(
410
-                'name'            => $this->reg_form_name(),
411
-                'html_id'         => $this->reg_form_name(),
412
-                'subsections'     => $subsections,
413
-                'layout_strategy' => new EE_No_Layout(),
414
-            )
415
-        );
416
-    }
417
-
418
-
419
-    /**
420
-     * add line item filters required for this reg step
421
-     * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
422
-     *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
423
-     *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
424
-     *        payment options reg step, can apply these filters via the following: apply_filters(
425
-     *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
426
-     *        filter collection by passing that instead of instantiating a new collection
427
-     *
428
-     * @param \EE_Line_Item_Filter_Collection $line_item_filter_collection
429
-     * @return EE_Line_Item_Filter_Collection
430
-     * @throws EE_Error
431
-     * @throws InvalidArgumentException
432
-     * @throws ReflectionException
433
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
434
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
435
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
436
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
437
-     */
438
-    public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
439
-    {
440
-        if (! EE_Registry::instance()->SSN instanceof EE_Session) {
441
-            return $line_item_filter_collection;
442
-        }
443
-        if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
444
-            return $line_item_filter_collection;
445
-        }
446
-        if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
447
-            return $line_item_filter_collection;
448
-        }
449
-        $line_item_filter_collection->add(
450
-            new EE_Billable_Line_Item_Filter(
451
-                EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
452
-                    EE_Registry::instance()->SSN->checkout()->transaction->registrations(
453
-                        EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
454
-                    )
455
-                )
456
-            )
457
-        );
458
-        $line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
459
-        return $line_item_filter_collection;
460
-    }
461
-
462
-
463
-    /**
464
-     * remove_ejected_registrations
465
-     * if a registrant has lost their potential space at an event due to lack of payment,
466
-     * then this method removes them from the list of registrations being paid for during this request
467
-     *
468
-     * @param \EE_Registration[] $registrations
469
-     * @return EE_Registration[]
470
-     * @throws EE_Error
471
-     * @throws InvalidArgumentException
472
-     * @throws ReflectionException
473
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
474
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
475
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
476
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
477
-     */
478
-    public static function remove_ejected_registrations(array $registrations)
479
-    {
480
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
481
-            $registrations,
482
-            EE_Registry::instance()->SSN->checkout()->revisit
483
-        );
484
-        foreach ($registrations as $REG_ID => $registration) {
485
-            // has this registration lost it's space ?
486
-            if (isset($ejected_registrations[$REG_ID])) {
487
-                unset($registrations[$REG_ID]);
488
-                continue;
489
-            }
490
-        }
491
-        return $registrations;
492
-    }
493
-
494
-
495
-    /**
496
-     * find_registrations_that_lost_their_space
497
-     * If a registrant chooses an offline payment method like Invoice,
498
-     * then no space is reserved for them at the event until they fully pay fo that site
499
-     * (unless the event's default reg status is set to APPROVED)
500
-     * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
501
-     * then this method will determine which registrations have lost the ability to complete the reg process.
502
-     *
503
-     * @param \EE_Registration[] $registrations
504
-     * @param bool               $revisit
505
-     * @return array
506
-     * @throws EE_Error
507
-     * @throws InvalidArgumentException
508
-     * @throws ReflectionException
509
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
510
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
511
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
512
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
513
-     */
514
-    public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
515
-    {
516
-        // registrations per event
517
-        $event_reg_count = array();
518
-        // spaces left per event
519
-        $event_spaces_remaining = array();
520
-        // tickets left sorted by ID
521
-        $tickets_remaining = array();
522
-        // registrations that have lost their space
523
-        $ejected_registrations = array();
524
-        foreach ($registrations as $REG_ID => $registration) {
525
-            if ($registration->status_ID() === EEM_Registration::status_id_approved
526
-                || apply_filters(
527
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
528
-                    false,
529
-                    $registration,
530
-                    $revisit
531
-                )
532
-            ) {
533
-                continue;
534
-            }
535
-            $EVT_ID = $registration->event_ID();
536
-            $ticket = $registration->ticket();
537
-            if (! isset($tickets_remaining[$ticket->ID()])) {
538
-                $tickets_remaining[$ticket->ID()] = $ticket->remaining();
539
-            }
540
-            if ($tickets_remaining[$ticket->ID()] > 0) {
541
-                if (! isset($event_reg_count[$EVT_ID])) {
542
-                    $event_reg_count[$EVT_ID] = 0;
543
-                }
544
-                $event_reg_count[$EVT_ID]++;
545
-                if (! isset($event_spaces_remaining[$EVT_ID])) {
546
-                    $event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
547
-                }
548
-            }
549
-            if ($revisit
550
-                && ($tickets_remaining[$ticket->ID()] === 0
551
-                    || $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
552
-                )
553
-            ) {
554
-                $ejected_registrations[$REG_ID] = $registration->event();
555
-                if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
556
-                    /** @type EE_Registration_Processor $registration_processor */
557
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
558
-                    // at this point, we should have enough details about the registrant to consider the registration
559
-                    // NOT incomplete
560
-                    $registration_processor->manually_update_registration_status(
561
-                        $registration,
562
-                        EEM_Registration::status_id_wait_list
563
-                    );
564
-                }
565
-            }
566
-        }
567
-        return $ejected_registrations;
568
-    }
569
-
570
-
571
-    /**
572
-     * _hide_reg_step_submit_button
573
-     * removes the html for the reg step submit button
574
-     * by replacing it with an empty string via filter callback
575
-     *
576
-     * @return void
577
-     */
578
-    protected function _adjust_registration_status_if_event_old_sold()
579
-    {
580
-    }
581
-
582
-
583
-    /**
584
-     * _hide_reg_step_submit_button
585
-     * removes the html for the reg step submit button
586
-     * by replacing it with an empty string via filter callback
587
-     *
588
-     * @return void
589
-     */
590
-    protected function _hide_reg_step_submit_button_if_revisit()
591
-    {
592
-        if ($this->checkout->revisit) {
593
-            add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
594
-        }
595
-    }
596
-
597
-
598
-    /**
599
-     * sold_out_events
600
-     * displays notices regarding events that have sold out since hte registrant first signed up
601
-     *
602
-     * @param \EE_Event[] $sold_out_events_array
603
-     * @return \EE_Form_Section_Proper
604
-     * @throws \EE_Error
605
-     */
606
-    private function _sold_out_events($sold_out_events_array = array())
607
-    {
608
-        // set some defaults
609
-        $this->checkout->selected_method_of_payment = 'events_sold_out';
610
-        $sold_out_events                            = '';
611
-        foreach ($sold_out_events_array as $sold_out_event) {
612
-            $sold_out_events .= EEH_HTML::li(
613
-                EEH_HTML::span(
614
-                    '  ' . $sold_out_event->name(),
615
-                    '',
616
-                    'dashicons dashicons-marker ee-icon-size-16 pink-text'
617
-                )
618
-            );
619
-        }
620
-        return new EE_Form_Section_Proper(
621
-            array(
622
-                'layout_strategy' => new EE_Template_Layout(
623
-                    array(
624
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
625
-                                                  . $this->_slug
626
-                                                  . DS
627
-                                                  . 'sold_out_events.template.php',
628
-                        'template_args'        => apply_filters(
629
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
630
-                            array(
631
-                                'sold_out_events'     => $sold_out_events,
632
-                                'sold_out_events_msg' => apply_filters(
633
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
634
-                                    sprintf(
635
-                                        esc_html__(
636
-                                            'It appears that the event you were about to make a payment for has sold out since you first registered. If you have already made a partial payment towards this event, please contact the event administrator for a refund.%3$s%3$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%2$s',
637
-                                            'event_espresso'
638
-                                        ),
639
-                                        '<strong>',
640
-                                        '</strong>',
641
-                                        '<br />'
642
-                                    )
643
-                                ),
644
-                            )
645
-                        ),
646
-                    )
647
-                ),
648
-            )
649
-        );
650
-    }
651
-
652
-
653
-    /**
654
-     * _insufficient_spaces_available
655
-     * displays notices regarding events that do not have enough remaining spaces
656
-     * to satisfy the current number of registrations looking to pay
657
-     *
658
-     * @param \EE_Event[] $insufficient_spaces_events_array
659
-     * @return \EE_Form_Section_Proper
660
-     * @throws \EE_Error
661
-     */
662
-    private function _insufficient_spaces_available($insufficient_spaces_events_array = array())
663
-    {
664
-        // set some defaults
665
-        $this->checkout->selected_method_of_payment = 'invoice';
666
-        $insufficient_space_events                  = '';
667
-        foreach ($insufficient_spaces_events_array as $event) {
668
-            if ($event instanceof EE_Event) {
669
-                $insufficient_space_events .= EEH_HTML::li(
670
-                    EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
671
-                );
672
-            }
673
-        }
674
-        return new EE_Form_Section_Proper(
675
-            array(
676
-                'subsections'     => array(
677
-                    'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
678
-                    'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
679
-                ),
680
-                'layout_strategy' => new EE_Template_Layout(
681
-                    array(
682
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
683
-                                                  . $this->_slug
684
-                                                  . DS
685
-                                                  . 'sold_out_events.template.php',
686
-                        'template_args'        => apply_filters(
687
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
688
-                            array(
689
-                                'sold_out_events'     => $insufficient_space_events,
690
-                                'sold_out_events_msg' => apply_filters(
691
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
692
-                                    esc_html__(
693
-                                        'It appears that the event you were about to make a payment for has sold additional tickets since you first registered, and there are no longer enough spaces left to accommodate your selections. You may continue to pay and secure the available space(s) remaining, or simply cancel if you no longer wish to purchase. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
694
-                                        'event_espresso'
695
-                                    )
696
-                                ),
697
-                            )
698
-                        ),
699
-                    )
700
-                ),
701
-            )
702
-        );
703
-    }
704
-
705
-
706
-    /**
707
-     * registrations_requiring_pre_approval
708
-     *
709
-     * @param array $registrations_requiring_pre_approval
710
-     * @return EE_Form_Section_Proper
711
-     * @throws EE_Error
712
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
713
-     */
714
-    private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = array())
715
-    {
716
-        $events_requiring_pre_approval = '';
717
-        foreach ($registrations_requiring_pre_approval as $registration) {
718
-            if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
719
-                $events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
720
-                    EEH_HTML::span(
721
-                        '',
722
-                        '',
723
-                        'dashicons dashicons-marker ee-icon-size-16 orange-text'
724
-                    )
725
-                    . EEH_HTML::span($registration->event()->name(), '', 'orange-text')
726
-                );
727
-            }
728
-        }
729
-        return new EE_Form_Section_Proper(
730
-            array(
731
-                'layout_strategy' => new EE_Template_Layout(
732
-                    array(
733
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
734
-                                                  . $this->_slug
735
-                                                  . DS
736
-                                                  . 'events_requiring_pre_approval.template.php', // layout_template
737
-                        'template_args'        => apply_filters(
738
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
739
-                            array(
740
-                                'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
741
-                                'events_requiring_pre_approval_msg' => apply_filters(
742
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
743
-                                    esc_html__(
744
-                                        'The following events do not require payment at this time and will not be billed during this transaction. Billing will only occur after the attendee has been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
745
-                                        'event_espresso'
746
-                                    )
747
-                                ),
748
-                            )
749
-                        ),
750
-                    )
751
-                ),
752
-            )
753
-        );
754
-    }
755
-
756
-
757
-    /**
758
-     * _no_payment_required
759
-     *
760
-     * @param \EE_Event[] $registrations_for_free_events
761
-     * @return \EE_Form_Section_Proper
762
-     * @throws \EE_Error
763
-     */
764
-    private function _no_payment_required($registrations_for_free_events = array())
765
-    {
766
-        // set some defaults
767
-        $this->checkout->selected_method_of_payment = 'no_payment_required';
768
-        // generate no_payment_required form
769
-        return new EE_Form_Section_Proper(
770
-            array(
771
-                'layout_strategy' => new EE_Template_Layout(
772
-                    array(
773
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
774
-                                                  . $this->_slug
775
-                                                  . DS
776
-                                                  . 'no_payment_required.template.php', // layout_template
777
-                        'template_args'        => apply_filters(
778
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
779
-                            array(
780
-                                'revisit'                       => $this->checkout->revisit,
781
-                                'registrations'                 => array(),
782
-                                'ticket_count'                  => array(),
783
-                                'registrations_for_free_events' => $registrations_for_free_events,
784
-                                'no_payment_required_msg'       => EEH_HTML::p(
785
-                                    esc_html__('This is a free event, so no billing will occur.', 'event_espresso')
786
-                                ),
787
-                            )
788
-                        ),
789
-                    )
790
-                ),
791
-            )
792
-        );
793
-    }
794
-
795
-
796
-    /**
797
-     * _display_payment_options
798
-     *
799
-     * @param string $transaction_details
800
-     * @return EE_Form_Section_Proper
801
-     * @throws EE_Error
802
-     * @throws InvalidArgumentException
803
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
804
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
805
-     */
806
-    private function _display_payment_options($transaction_details = '')
807
-    {
808
-        // has method_of_payment been set by no-js user?
809
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
810
-        // build payment options form
811
-        return apply_filters(
812
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
813
-            new EE_Form_Section_Proper(
814
-                array(
815
-                    'subsections'     => array(
816
-                        'before_payment_options' => apply_filters(
817
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
818
-                            new EE_Form_Section_Proper(
819
-                                array('layout_strategy' => new EE_Div_Per_Section_Layout())
820
-                            )
821
-                        ),
822
-                        'payment_options'        => $this->_setup_payment_options(),
823
-                        'after_payment_options'  => apply_filters(
824
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
825
-                            new EE_Form_Section_Proper(
826
-                                array('layout_strategy' => new EE_Div_Per_Section_Layout())
827
-                            )
828
-                        ),
829
-                    ),
830
-                    'layout_strategy' => new EE_Template_Layout(
831
-                        array(
832
-                            'layout_template_file' => $this->_template,
833
-                            'template_args'        => apply_filters(
834
-                                'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
835
-                                array(
836
-                                    'reg_count'                 => $this->line_item_display->total_items(),
837
-                                    'transaction_details'       => $transaction_details,
838
-                                    'available_payment_methods' => array(),
839
-                                )
840
-                            ),
841
-                        )
842
-                    ),
843
-                )
844
-            )
845
-        );
846
-    }
847
-
848
-
849
-    /**
850
-     * _extra_hidden_inputs
851
-     *
852
-     * @param bool $no_payment_required
853
-     * @return \EE_Form_Section_Proper
854
-     * @throws \EE_Error
855
-     */
856
-    private function _extra_hidden_inputs($no_payment_required = true)
857
-    {
858
-        return new EE_Form_Section_Proper(
859
-            array(
860
-                'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
861
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
862
-                'subsections'     => array(
863
-                    'spco_no_payment_required' => new EE_Hidden_Input(
864
-                        array(
865
-                            'normalization_strategy' => new EE_Boolean_Normalization(),
866
-                            'html_name'              => 'spco_no_payment_required',
867
-                            'html_id'                => 'spco-no-payment-required-payment_options',
868
-                            'default'                => $no_payment_required,
869
-                        )
870
-                    ),
871
-                    'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
872
-                        array(
873
-                            'normalization_strategy' => new EE_Int_Normalization(),
874
-                            'html_name'              => 'spco_transaction_id',
875
-                            'html_id'                => 'spco-transaction-id',
876
-                            'default'                => $this->checkout->transaction->ID(),
877
-                        )
878
-                    ),
879
-                ),
880
-            )
881
-        );
882
-    }
883
-
884
-
885
-    /**
886
-     *    _apply_registration_payments_to_amount_owing
887
-     *
888
-     * @access protected
889
-     * @param array $registrations
890
-     * @throws EE_Error
891
-     */
892
-    protected function _apply_registration_payments_to_amount_owing(array $registrations)
893
-    {
894
-        $payments = array();
895
-        foreach ($registrations as $registration) {
896
-            if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
897
-                $payments += $registration->registration_payments();
898
-            }
899
-        }
900
-        if (! empty($payments)) {
901
-            foreach ($payments as $payment) {
902
-                if ($payment instanceof EE_Registration_Payment) {
903
-                    $this->checkout->amount_owing -= $payment->amount();
904
-                }
905
-            }
906
-        }
907
-    }
908
-
909
-
910
-    /**
911
-     *    _reset_selected_method_of_payment
912
-     *
913
-     * @access    private
914
-     * @param    bool $force_reset
915
-     * @return void
916
-     * @throws InvalidArgumentException
917
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919
-     */
920
-    private function _reset_selected_method_of_payment($force_reset = false)
921
-    {
922
-        $reset_payment_method = $force_reset
923
-            ? true
924
-            : sanitize_text_field(EE_Registry::instance()->REQ->get('reset_payment_method', false));
925
-        if ($reset_payment_method) {
926
-            $this->checkout->selected_method_of_payment = null;
927
-            $this->checkout->payment_method             = null;
928
-            $this->checkout->billing_form               = null;
929
-            $this->_save_selected_method_of_payment();
930
-        }
931
-    }
932
-
933
-
934
-    /**
935
-     * _save_selected_method_of_payment
936
-     * stores the selected_method_of_payment in the session
937
-     * so that it's available for all subsequent requests including AJAX
938
-     *
939
-     * @access        private
940
-     * @param string $selected_method_of_payment
941
-     * @return void
942
-     * @throws InvalidArgumentException
943
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
944
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
945
-     */
946
-    private function _save_selected_method_of_payment($selected_method_of_payment = '')
947
-    {
948
-        $selected_method_of_payment = ! empty($selected_method_of_payment)
949
-            ? $selected_method_of_payment
950
-            : $this->checkout->selected_method_of_payment;
951
-        EE_Registry::instance()->SSN->set_session_data(
952
-            array('selected_method_of_payment' => $selected_method_of_payment)
953
-        );
954
-    }
955
-
956
-
957
-    /**
958
-     * _setup_payment_options
959
-     *
960
-     * @return EE_Form_Section_Proper
961
-     * @throws EE_Error
962
-     * @throws InvalidArgumentException
963
-     * @throws ReflectionException
964
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
965
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
966
-     */
967
-    public function _setup_payment_options()
968
-    {
969
-        // load payment method classes
970
-        $this->checkout->available_payment_methods = $this->_get_available_payment_methods();
971
-        if (empty($this->checkout->available_payment_methods)) {
972
-            EE_Error::add_error(
973
-                apply_filters(
974
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__error_message_no_payment_methods',
975
-                    sprintf(
976
-                        esc_html__(
977
-                            'Sorry, you cannot complete your purchase because a payment method is not active.%1$s Please contact %2$s for assistance and provide a description of the problem.',
978
-                            'event_espresso'
979
-                        ),
980
-                        '<br>',
981
-                        EE_Registry::instance()->CFG->organization->get_pretty('email')
982
-                    )
983
-                ),
984
-                __FILE__,
985
-                __FUNCTION__,
986
-                __LINE__
987
-            );
988
-        }
989
-        // switch up header depending on number of available payment methods
990
-        $payment_method_header     = count($this->checkout->available_payment_methods) > 1
991
-            ? apply_filters(
992
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
993
-                esc_html__('Please Select Your Method of Payment', 'event_espresso')
994
-            )
995
-            : apply_filters(
996
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
997
-                esc_html__('Method of Payment', 'event_espresso')
998
-            );
999
-        $available_payment_methods = array(
1000
-            // display the "Payment Method" header
1001
-            'payment_method_header' => new EE_Form_Section_HTML(
1002
-                EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr')
1003
-            ),
1004
-        );
1005
-        // the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
1006
-        $available_payment_method_options = array();
1007
-        $default_payment_method_option    = array();
1008
-        // additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
1009
-        $payment_methods_billing_info = array(
1010
-            new EE_Form_Section_HTML(
1011
-                EEH_HTML::div('<br />', '', '', 'clear:both;')
1012
-            ),
1013
-        );
1014
-        // loop through payment methods
1015
-        foreach ($this->checkout->available_payment_methods as $payment_method) {
1016
-            if ($payment_method instanceof EE_Payment_Method) {
1017
-                $payment_method_button = EEH_HTML::img(
1018
-                    $payment_method->button_url(),
1019
-                    $payment_method->name(),
1020
-                    'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1021
-                    'spco-payment-method-btn-img'
1022
-                );
1023
-                // check if any payment methods are set as default
1024
-                // if payment method is already selected OR nothing is selected and this payment method should be
1025
-                // open_by_default
1026
-                if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1027
-                    || (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1028
-                ) {
1029
-                    $this->checkout->selected_method_of_payment = $payment_method->slug();
1030
-                    $this->_save_selected_method_of_payment();
1031
-                    $default_payment_method_option[$payment_method->slug()] = $payment_method_button;
1032
-                } else {
1033
-                    $available_payment_method_options[$payment_method->slug()] = $payment_method_button;
1034
-                }
1035
-                $payment_methods_billing_info[$payment_method->slug() . '-info'] = $this->_payment_method_billing_info(
1036
-                    $payment_method
1037
-                );
1038
-            }
1039
-        }
1040
-        // prepend available_payment_method_options with default_payment_method_option so that it appears first in list
1041
-        // of PMs
1042
-        $available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
1043
-        // now generate the actual form  inputs
1044
-        $available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1045
-            $available_payment_method_options
1046
-        );
1047
-        $available_payment_methods                              += $payment_methods_billing_info;
1048
-        // build the available payment methods form
1049
-        return new EE_Form_Section_Proper(
1050
-            array(
1051
-                'html_id'         => 'spco-available-methods-of-payment-dv',
1052
-                'subsections'     => $available_payment_methods,
1053
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1054
-            )
1055
-        );
1056
-    }
1057
-
1058
-
1059
-    /**
1060
-     * _get_available_payment_methods
1061
-     *
1062
-     * @return EE_Payment_Method[]
1063
-     * @throws EE_Error
1064
-     * @throws InvalidArgumentException
1065
-     * @throws ReflectionException
1066
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1067
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1068
-     */
1069
-    protected function _get_available_payment_methods()
1070
-    {
1071
-        if (! empty($this->checkout->available_payment_methods)) {
1072
-            return $this->checkout->available_payment_methods;
1073
-        }
1074
-        $available_payment_methods = array();
1075
-        // load EEM_Payment_Method
1076
-        EE_Registry::instance()->load_model('Payment_Method');
1077
-        /** @type EEM_Payment_Method $EEM_Payment_Method */
1078
-        $EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
1079
-        // get all active payment methods
1080
-        $payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1081
-            $this->checkout->transaction,
1082
-            EEM_Payment_Method::scope_cart
1083
-        );
1084
-        foreach ($payment_methods as $payment_method) {
1085
-            if ($payment_method instanceof EE_Payment_Method) {
1086
-                $available_payment_methods[$payment_method->slug()] = $payment_method;
1087
-            }
1088
-        }
1089
-        return $available_payment_methods;
1090
-    }
1091
-
1092
-
1093
-    /**
1094
-     *    _available_payment_method_inputs
1095
-     *
1096
-     * @access    private
1097
-     * @param    array $available_payment_method_options
1098
-     * @return    \EE_Form_Section_Proper
1099
-     */
1100
-    private function _available_payment_method_inputs($available_payment_method_options = array())
1101
-    {
1102
-        // generate inputs
1103
-        return new EE_Form_Section_Proper(
1104
-            array(
1105
-                'html_id'         => 'ee-available-payment-method-inputs',
1106
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1107
-                'subsections'     => array(
1108
-                    '' => new EE_Radio_Button_Input(
1109
-                        $available_payment_method_options,
1110
-                        array(
1111
-                            'html_name'          => 'selected_method_of_payment',
1112
-                            'html_class'         => 'spco-payment-method',
1113
-                            'default'            => $this->checkout->selected_method_of_payment,
1114
-                            'label_size'         => 11,
1115
-                            'enforce_label_size' => true,
1116
-                        )
1117
-                    ),
1118
-                ),
1119
-            )
1120
-        );
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     *    _payment_method_billing_info
1126
-     *
1127
-     * @access    private
1128
-     * @param    EE_Payment_Method $payment_method
1129
-     * @return EE_Form_Section_Proper
1130
-     * @throws EE_Error
1131
-     * @throws InvalidArgumentException
1132
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1133
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1134
-     */
1135
-    private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1136
-    {
1137
-        $currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug()
1138
-            ? true
1139
-            : false;
1140
-        // generate the billing form for payment method
1141
-        $billing_form                 = $currently_selected
1142
-            ? $this->_get_billing_form_for_payment_method($payment_method)
1143
-            : new EE_Form_Section_HTML();
1144
-        $this->checkout->billing_form = $currently_selected
1145
-            ? $billing_form
1146
-            : $this->checkout->billing_form;
1147
-        // it's all in the details
1148
-        $info_html = EEH_HTML::h3(
1149
-            esc_html__('Important information regarding your payment', 'event_espresso'),
1150
-            '',
1151
-            'spco-payment-method-hdr'
1152
-        );
1153
-        // add some info regarding the step, either from what's saved in the admin,
1154
-        // or a default string depending on whether the PM has a billing form or not
1155
-        if ($payment_method->description()) {
1156
-            $payment_method_info = $payment_method->description();
1157
-        } elseif ($billing_form instanceof EE_Billing_Info_Form) {
1158
-            $payment_method_info = sprintf(
1159
-                esc_html__(
1160
-                    'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1161
-                    'event_espresso'
1162
-                ),
1163
-                $this->submit_button_text()
1164
-            );
1165
-        } else {
1166
-            $payment_method_info = sprintf(
1167
-                esc_html__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1168
-                $this->submit_button_text()
1169
-            );
1170
-        }
1171
-        $info_html .= EEH_HTML::p(
1172
-            apply_filters(
1173
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1174
-                $payment_method_info
1175
-            ),
1176
-            '',
1177
-            'spco-payment-method-desc ee-attention'
1178
-        );
1179
-        return new EE_Form_Section_Proper(
1180
-            array(
1181
-                'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1182
-                'html_class'      => 'spco-payment-method-info-dv',
1183
-                // only display the selected or default PM
1184
-                'html_style'      => $currently_selected ? '' : 'display:none;',
1185
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1186
-                'subsections'     => array(
1187
-                    'info'         => new EE_Form_Section_HTML($info_html),
1188
-                    'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1189
-                ),
1190
-            )
1191
-        );
1192
-    }
1193
-
1194
-
1195
-    /**
1196
-     * get_billing_form_html_for_payment_method
1197
-     *
1198
-     * @access public
1199
-     * @return string
1200
-     * @throws EE_Error
1201
-     * @throws InvalidArgumentException
1202
-     * @throws ReflectionException
1203
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1204
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1205
-     */
1206
-    public function get_billing_form_html_for_payment_method()
1207
-    {
1208
-        // how have they chosen to pay?
1209
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1210
-        $this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1211
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1212
-            return false;
1213
-        }
1214
-        if (apply_filters(
1215
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1216
-            false
1217
-        )) {
1218
-            EE_Error::add_success(
1219
-                apply_filters(
1220
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1221
-                    sprintf(
1222
-                        esc_html__(
1223
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1224
-                            'event_espresso'
1225
-                        ),
1226
-                        $this->checkout->payment_method->name()
1227
-                    )
1228
-                )
1229
-            );
1230
-        }
1231
-        // now generate billing form for selected method of payment
1232
-        $payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1233
-        // fill form with attendee info if applicable
1234
-        if ($payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1235
-            && $this->checkout->transaction_has_primary_registrant()
1236
-        ) {
1237
-            $payment_method_billing_form->populate_from_attendee(
1238
-                $this->checkout->transaction->primary_registration()->attendee()
1239
-            );
1240
-        }
1241
-        // and debug content
1242
-        if ($payment_method_billing_form instanceof EE_Billing_Info_Form
1243
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1244
-        ) {
1245
-            $payment_method_billing_form =
1246
-                $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1247
-                    $payment_method_billing_form
1248
-                );
1249
-        }
1250
-        $billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1251
-            ? $payment_method_billing_form->get_html()
1252
-            : '';
1253
-        $this->checkout->json_response->set_return_data(array('payment_method_info' => $billing_info));
1254
-        // localize validation rules for main form
1255
-        $this->checkout->current_step->reg_form->localize_validation_rules();
1256
-        $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1257
-        return true;
1258
-    }
1259
-
1260
-
1261
-    /**
1262
-     * _get_billing_form_for_payment_method
1263
-     *
1264
-     * @access private
1265
-     * @param EE_Payment_Method $payment_method
1266
-     * @return EE_Billing_Info_Form|EE_Form_Section_HTML
1267
-     * @throws EE_Error
1268
-     * @throws InvalidArgumentException
1269
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1270
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1271
-     */
1272
-    private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
1273
-    {
1274
-        $billing_form = $payment_method->type_obj()->billing_form(
1275
-            $this->checkout->transaction,
1276
-            array('amount_owing' => $this->checkout->amount_owing)
1277
-        );
1278
-        if ($billing_form instanceof EE_Billing_Info_Form) {
1279
-            if (apply_filters(
1280
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1281
-                false
1282
-            )
1283
-                && EE_Registry::instance()->REQ->is_set('payment_method')
1284
-            ) {
1285
-                EE_Error::add_success(
1286
-                    apply_filters(
1287
-                        'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1288
-                        sprintf(
1289
-                            esc_html__(
1290
-                                'You have selected "%s" as your method of payment. Please note the important payment information below.',
1291
-                                'event_espresso'
1292
-                            ),
1293
-                            $payment_method->name()
1294
-                        )
1295
-                    )
1296
-                );
1297
-            }
1298
-            return apply_filters(
1299
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
1300
-                $billing_form,
1301
-                $payment_method
1302
-            );
1303
-        }
1304
-        // no actual billing form, so return empty HTML form section
1305
-        return new EE_Form_Section_HTML();
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * _get_selected_method_of_payment
1311
-     *
1312
-     * @access private
1313
-     * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1314
-     *                          is not found in the incoming request
1315
-     * @param string  $request_param
1316
-     * @return NULL|string
1317
-     * @throws EE_Error
1318
-     * @throws InvalidArgumentException
1319
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1320
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1321
-     */
1322
-    private function _get_selected_method_of_payment(
1323
-        $required = false,
1324
-        $request_param = 'selected_method_of_payment'
1325
-    ) {
1326
-        // is selected_method_of_payment set in the request ?
1327
-        $selected_method_of_payment = EE_Registry::instance()->REQ->get($request_param, false);
1328
-        if ($selected_method_of_payment) {
1329
-            // sanitize it
1330
-            $selected_method_of_payment = is_array($selected_method_of_payment)
1331
-                ? array_shift($selected_method_of_payment)
1332
-                : $selected_method_of_payment;
1333
-            $selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1334
-            // store it in the session so that it's available for all subsequent requests including AJAX
1335
-            $this->_save_selected_method_of_payment($selected_method_of_payment);
1336
-        } else {
1337
-            // or is is set in the session ?
1338
-            $selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1339
-                'selected_method_of_payment'
1340
-            );
1341
-        }
1342
-        // do ya really really gotta have it?
1343
-        if (empty($selected_method_of_payment) && $required) {
1344
-            EE_Error::add_error(
1345
-                sprintf(
1346
-                    esc_html__(
1347
-                        'The selected method of payment could not be determined.%sPlease ensure that you have selected one before proceeding.%sIf you continue to experience difficulties, then refresh your browser and try again, or contact %s for assistance.',
1348
-                        'event_espresso'
1349
-                    ),
1350
-                    '<br/>',
1351
-                    '<br/>',
1352
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
1353
-                ),
1354
-                __FILE__,
1355
-                __FUNCTION__,
1356
-                __LINE__
1357
-            );
1358
-            return null;
1359
-        }
1360
-        return $selected_method_of_payment;
1361
-    }
1362
-
1363
-
1364
-
1365
-
1366
-
1367
-
1368
-    /********************************************************************************************************/
1369
-    /***********************************  SWITCH PAYMENT METHOD  ************************************/
1370
-    /********************************************************************************************************/
1371
-    /**
1372
-     * switch_payment_method
1373
-     *
1374
-     * @access public
1375
-     * @return string
1376
-     * @throws EE_Error
1377
-     * @throws InvalidArgumentException
1378
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1379
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1380
-     */
1381
-    public function switch_payment_method()
1382
-    {
1383
-        if (! $this->_verify_payment_method_is_set()) {
1384
-            return false;
1385
-        }
1386
-        if (apply_filters(
1387
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1388
-            false
1389
-        )) {
1390
-            EE_Error::add_success(
1391
-                apply_filters(
1392
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1393
-                    sprintf(
1394
-                        esc_html__(
1395
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1396
-                            'event_espresso'
1397
-                        ),
1398
-                        $this->checkout->payment_method->name()
1399
-                    )
1400
-                )
1401
-            );
1402
-        }
1403
-        // generate billing form for selected method of payment if it hasn't been done already
1404
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1405
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1406
-                $this->checkout->payment_method
1407
-            );
1408
-        }
1409
-        // fill form with attendee info if applicable
1410
-        if (apply_filters(
1411
-            'FHEE__populate_billing_form_fields_from_attendee',
1412
-            (
1413
-                $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1414
-                && $this->checkout->transaction_has_primary_registrant()
1415
-            ),
1416
-            $this->checkout->billing_form,
1417
-            $this->checkout->transaction
1418
-        )
1419
-        ) {
1420
-            $this->checkout->billing_form->populate_from_attendee(
1421
-                $this->checkout->transaction->primary_registration()->attendee()
1422
-            );
1423
-        }
1424
-        // and debug content
1425
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1426
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1427
-        ) {
1428
-            $this->checkout->billing_form =
1429
-                $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1430
-                    $this->checkout->billing_form
1431
-                );
1432
-        }
1433
-        // get html and validation rules for form
1434
-        if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1435
-            $this->checkout->json_response->set_return_data(
1436
-                array('payment_method_info' => $this->checkout->billing_form->get_html())
1437
-            );
1438
-            // localize validation rules for main form
1439
-            $this->checkout->billing_form->localize_validation_rules(true);
1440
-            $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1441
-        } else {
1442
-            $this->checkout->json_response->set_return_data(array('payment_method_info' => ''));
1443
-        }
1444
-        //prevents advancement to next step
1445
-        $this->checkout->continue_reg = false;
1446
-        return true;
1447
-    }
1448
-
1449
-
1450
-    /**
1451
-     * _verify_payment_method_is_set
1452
-     *
1453
-     * @return bool
1454
-     * @throws EE_Error
1455
-     * @throws InvalidArgumentException
1456
-     * @throws ReflectionException
1457
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1458
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1459
-     */
1460
-    protected function _verify_payment_method_is_set()
1461
-    {
1462
-        // generate billing form for selected method of payment if it hasn't been done already
1463
-        if (empty($this->checkout->selected_method_of_payment)) {
1464
-            // how have they chosen to pay?
1465
-            $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1466
-        } else {
1467
-            // choose your own adventure based on method_of_payment
1468
-            switch ($this->checkout->selected_method_of_payment) {
1469
-                case 'events_sold_out' :
1470
-                    EE_Error::add_attention(
1471
-                        apply_filters(
1472
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1473
-                            esc_html__(
1474
-                                'It appears that the event you were about to make a payment for has sold out since this form first loaded. Please contact the event administrator if you believe this is an error.',
1475
-                                'event_espresso'
1476
-                            )
1477
-                        ),
1478
-                        __FILE__, __FUNCTION__, __LINE__
1479
-                    );
1480
-                    return false;
1481
-                    break;
1482
-                case 'payments_closed' :
1483
-                    EE_Error::add_attention(
1484
-                        apply_filters(
1485
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__payments_closed_msg',
1486
-                            esc_html__(
1487
-                                'It appears that the event you were about to make a payment for is not accepting payments at this time. Please contact the event administrator if you believe this is an error.',
1488
-                                'event_espresso'
1489
-                            )
1490
-                        ),
1491
-                        __FILE__, __FUNCTION__, __LINE__
1492
-                    );
1493
-                    return false;
1494
-                    break;
1495
-                case 'no_payment_required' :
1496
-                    EE_Error::add_attention(
1497
-                        apply_filters(
1498
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1499
-                            esc_html__(
1500
-                                'It appears that the event you were about to make a payment for does not require payment. Please contact the event administrator if you believe this is an error.',
1501
-                                'event_espresso'
1502
-                            )
1503
-                        ),
1504
-                        __FILE__, __FUNCTION__, __LINE__
1505
-                    );
1506
-                    return false;
1507
-                    break;
1508
-                default:
1509
-            }
1510
-        }
1511
-        // verify payment method
1512
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1513
-            // get payment method for selected method of payment
1514
-            $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1515
-        }
1516
-        return $this->checkout->payment_method instanceof EE_Payment_Method ? true : false;
1517
-    }
1518
-
1519
-
1520
-
1521
-    /********************************************************************************************************/
1522
-    /***************************************  SAVE PAYER DETAILS  ****************************************/
1523
-    /********************************************************************************************************/
1524
-    /**
1525
-     * save_payer_details_via_ajax
1526
-     *
1527
-     * @return void
1528
-     * @throws EE_Error
1529
-     * @throws InvalidArgumentException
1530
-     * @throws ReflectionException
1531
-     * @throws RuntimeException
1532
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1533
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1534
-     */
1535
-    public function save_payer_details_via_ajax()
1536
-    {
1537
-        if (! $this->_verify_payment_method_is_set()) {
1538
-            return;
1539
-        }
1540
-        // generate billing form for selected method of payment if it hasn't been done already
1541
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1542
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1543
-                $this->checkout->payment_method
1544
-            );
1545
-        }
1546
-        // generate primary attendee from payer info if applicable
1547
-        if (! $this->checkout->transaction_has_primary_registrant()) {
1548
-            $attendee = $this->_create_attendee_from_request_data();
1549
-            if ($attendee instanceof EE_Attendee) {
1550
-                foreach ($this->checkout->transaction->registrations() as $registration) {
1551
-                    if ($registration->is_primary_registrant()) {
1552
-                        $this->checkout->primary_attendee_obj = $attendee;
1553
-                        $registration->_add_relation_to($attendee, 'Attendee');
1554
-                        $registration->set_attendee_id($attendee->ID());
1555
-                        $registration->update_cache_after_object_save('Attendee', $attendee);
1556
-                    }
1557
-                }
1558
-            }
1559
-        }
1560
-    }
1561
-
1562
-
1563
-    /**
1564
-     * create_attendee_from_request_data
1565
-     * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1566
-     *
1567
-     * @return EE_Attendee
1568
-     * @throws EE_Error
1569
-     * @throws InvalidArgumentException
1570
-     * @throws ReflectionException
1571
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1572
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1573
-     */
1574
-    protected function _create_attendee_from_request_data()
1575
-    {
1576
-        // get State ID
1577
-        $STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1578
-        if (! empty($STA_ID)) {
1579
-            // can we get state object from name ?
1580
-            EE_Registry::instance()->load_model('State');
1581
-            $state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
1582
-            $STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1583
-        }
1584
-        // get Country ISO
1585
-        $CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1586
-        if (! empty($CNT_ISO)) {
1587
-            // can we get country object from name ?
1588
-            EE_Registry::instance()->load_model('Country');
1589
-            $country = EEM_Country::instance()->get_col(
1590
-                array(array('CNT_name' => $CNT_ISO), 'limit' => 1),
1591
-                'CNT_ISO'
1592
-            );
1593
-            $CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1594
-        }
1595
-        // grab attendee data
1596
-        $attendee_data = array(
1597
-            'ATT_fname'    => ! empty($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : '',
1598
-            'ATT_lname'    => ! empty($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : '',
1599
-            'ATT_email'    => ! empty($_REQUEST['email']) ? sanitize_email($_REQUEST['email']) : '',
1600
-            'ATT_address'  => ! empty($_REQUEST['address']) ? sanitize_text_field($_REQUEST['address']) : '',
1601
-            'ATT_address2' => ! empty($_REQUEST['address2']) ? sanitize_text_field($_REQUEST['address2']) : '',
1602
-            'ATT_city'     => ! empty($_REQUEST['city']) ? sanitize_text_field($_REQUEST['city']) : '',
1603
-            'STA_ID'       => $STA_ID,
1604
-            'CNT_ISO'      => $CNT_ISO,
1605
-            'ATT_zip'      => ! empty($_REQUEST['zip']) ? sanitize_text_field($_REQUEST['zip']) : '',
1606
-            'ATT_phone'    => ! empty($_REQUEST['phone']) ? sanitize_text_field($_REQUEST['phone']) : '',
1607
-        );
1608
-        // validate the email address since it is the most important piece of info
1609
-        if (empty($attendee_data['ATT_email']) || $attendee_data['ATT_email'] !== $_REQUEST['email']) {
1610
-            EE_Error::add_error(
1611
-                esc_html__('An invalid email address was submitted.', 'event_espresso'),
1612
-                __FILE__,
1613
-                __FUNCTION__,
1614
-                __LINE__
1615
-            );
1616
-        }
1617
-        // does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1618
-        // AND email address
1619
-        if (! empty($attendee_data['ATT_fname'])
1620
-            && ! empty($attendee_data['ATT_lname'])
1621
-            && ! empty($attendee_data['ATT_email'])
1622
-        ) {
1623
-            $existing_attendee = EE_Registry::instance()->LIB->EEM_Attendee->find_existing_attendee(
1624
-                array(
1625
-                    'ATT_fname' => $attendee_data['ATT_fname'],
1626
-                    'ATT_lname' => $attendee_data['ATT_lname'],
1627
-                    'ATT_email' => $attendee_data['ATT_email'],
1628
-                )
1629
-            );
1630
-            if ($existing_attendee instanceof EE_Attendee) {
1631
-                return $existing_attendee;
1632
-            }
1633
-        }
1634
-        // no existing attendee? kk let's create a new one
1635
-        // kinda lame, but we need a first and last name to create an attendee, so use the email address if those
1636
-        // don't exist
1637
-        $attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1638
-            ? $attendee_data['ATT_fname']
1639
-            : $attendee_data['ATT_email'];
1640
-        $attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1641
-            ? $attendee_data['ATT_lname']
1642
-            : $attendee_data['ATT_email'];
1643
-        return EE_Attendee::new_instance($attendee_data);
1644
-    }
1645
-
1646
-
1647
-
1648
-    /********************************************************************************************************/
1649
-    /****************************************  PROCESS REG STEP  *****************************************/
1650
-    /********************************************************************************************************/
1651
-    /**
1652
-     * process_reg_step
1653
-     *
1654
-     * @return bool
1655
-     * @throws EE_Error
1656
-     * @throws InvalidArgumentException
1657
-     * @throws ReflectionException
1658
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1659
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1660
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1661
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
1662
-     */
1663
-    public function process_reg_step()
1664
-    {
1665
-        // how have they chosen to pay?
1666
-        $this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1667
-            ? 'no_payment_required'
1668
-            : $this->_get_selected_method_of_payment(true);
1669
-        // choose your own adventure based on method_of_payment
1670
-        switch ($this->checkout->selected_method_of_payment) {
1671
-
1672
-            case 'events_sold_out' :
1673
-                $this->checkout->redirect     = true;
1674
-                $this->checkout->redirect_url = $this->checkout->cancel_page_url;
1675
-                $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1676
-                // mark this reg step as completed
1677
-                $this->set_completed();
1678
-                return false;
1679
-                break;
1680
-
1681
-            case 'payments_closed' :
1682
-                if (apply_filters(
1683
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__payments_closed__display_success',
1684
-                    false
1685
-                )) {
1686
-                    EE_Error::add_success(
1687
-                        esc_html__('no payment required at this time.', 'event_espresso'),
1688
-                        __FILE__,
1689
-                        __FUNCTION__,
1690
-                        __LINE__
1691
-                    );
1692
-                }
1693
-                // mark this reg step as completed
1694
-                $this->set_completed();
1695
-                return true;
1696
-                break;
1697
-
1698
-            case 'no_payment_required' :
1699
-                if (apply_filters(
1700
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1701
-                    false
1702
-                )) {
1703
-                    EE_Error::add_success(
1704
-                        esc_html__('no payment required.', 'event_espresso'),
1705
-                        __FILE__,
1706
-                        __FUNCTION__,
1707
-                        __LINE__
1708
-                    );
1709
-                }
1710
-                // mark this reg step as completed
1711
-                $this->set_completed();
1712
-                return true;
1713
-                break;
1714
-
1715
-            default:
1716
-                $registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1717
-                    EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1718
-                );
1719
-                $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1720
-                    $registrations,
1721
-                    EE_Registry::instance()->SSN->checkout()->revisit
1722
-                );
1723
-                // calculate difference between the two arrays
1724
-                $registrations = array_diff($registrations, $ejected_registrations);
1725
-                if (empty($registrations)) {
1726
-                    $this->_redirect_because_event_sold_out();
1727
-                    return false;
1728
-                }
1729
-                $payment_successful = $this->_process_payment();
1730
-                if ($payment_successful) {
1731
-                    $this->checkout->continue_reg = true;
1732
-                    $this->_maybe_set_completed($this->checkout->payment_method);
1733
-                } else {
1734
-                    $this->checkout->continue_reg = false;
1735
-                }
1736
-                return $payment_successful;
1737
-        }
1738
-    }
1739
-
1740
-
1741
-    /**
1742
-     * _redirect_because_event_sold_out
1743
-     *
1744
-     * @access protected
1745
-     * @return void
1746
-     */
1747
-    protected function _redirect_because_event_sold_out()
1748
-    {
1749
-        $this->checkout->continue_reg = false;
1750
-        // set redirect URL
1751
-        $this->checkout->redirect_url = add_query_arg(
1752
-            array('e_reg_url_link' => $this->checkout->reg_url_link),
1753
-            $this->checkout->current_step->reg_step_url()
1754
-        );
1755
-        $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1756
-    }
1757
-
1758
-
1759
-    /**
1760
-     * _maybe_set_completed
1761
-     *
1762
-     * @access protected
1763
-     * @param \EE_Payment_Method $payment_method
1764
-     * @return void
1765
-     * @throws \EE_Error
1766
-     */
1767
-    protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1768
-    {
1769
-        switch ($payment_method->type_obj()->payment_occurs()) {
1770
-            case EE_PMT_Base::offsite :
1771
-                break;
1772
-            case EE_PMT_Base::onsite :
1773
-            case EE_PMT_Base::offline :
1774
-                // mark this reg step as completed
1775
-                $this->set_completed();
1776
-                break;
1777
-        }
1778
-    }
1779
-
1780
-
1781
-    /**
1782
-     *    update_reg_step
1783
-     *    this is the final step after a user  revisits the site to retry a payment
1784
-     *
1785
-     * @return bool
1786
-     * @throws EE_Error
1787
-     * @throws InvalidArgumentException
1788
-     * @throws ReflectionException
1789
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1790
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1791
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1792
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
1793
-     */
1794
-    public function update_reg_step()
1795
-    {
1796
-        $success = true;
1797
-        // if payment required
1798
-        if ($this->checkout->transaction->total() > 0) {
1799
-            do_action(
1800
-                'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1801
-                $this->checkout->transaction
1802
-            );
1803
-            // attempt payment via payment method
1804
-            $success = $this->process_reg_step();
1805
-        }
1806
-        if ($success && ! $this->checkout->redirect) {
1807
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1808
-                $this->checkout->transaction->ID()
1809
-            );
1810
-            // set return URL
1811
-            $this->checkout->redirect_url = add_query_arg(
1812
-                array('e_reg_url_link' => $this->checkout->reg_url_link),
1813
-                $this->checkout->thank_you_page_url
1814
-            );
1815
-        }
1816
-        return $success;
1817
-    }
1818
-
1819
-
1820
-    /**
1821
-     *    _process_payment
1822
-     *
1823
-     * @access private
1824
-     * @return bool
1825
-     * @throws EE_Error
1826
-     * @throws InvalidArgumentException
1827
-     * @throws ReflectionException
1828
-     * @throws RuntimeException
1829
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1830
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1831
-     */
1832
-    private function _process_payment()
1833
-    {
1834
-        // basically confirm that the event hasn't sold out since they hit the page
1835
-        if (! $this->_last_second_ticket_verifications()) {
1836
-            return false;
1837
-        }
1838
-        // ya gotta make a choice man
1839
-        if (empty($this->checkout->selected_method_of_payment)) {
1840
-            $this->checkout->json_response->set_plz_select_method_of_payment(
1841
-                esc_html__('Please select a method of payment before proceeding.', 'event_espresso')
1842
-            );
1843
-            return false;
1844
-        }
1845
-        // get EE_Payment_Method object
1846
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1847
-            return false;
1848
-        }
1849
-        // setup billing form
1850
-        if ($this->checkout->payment_method->is_on_site()) {
1851
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1852
-                $this->checkout->payment_method
1853
-            );
1854
-            // bad billing form ?
1855
-            if (! $this->_billing_form_is_valid()) {
1856
-                return false;
1857
-            }
1858
-        }
1859
-        // ensure primary registrant has been fully processed
1860
-        if (! $this->_setup_primary_registrant_prior_to_payment()) {
1861
-            return false;
1862
-        }
1863
-        // if session is close to expiring (under 10 minutes by default)
1864
-        if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1865
-            // add some time to session expiration so that payment can be completed
1866
-            EE_Registry::instance()->SSN->extend_expiration();
1867
-        }
1868
-        /** @type EE_Transaction_Processor $transaction_processor */
1869
-        //$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1870
-        // in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations
1871
-        // for events with a default reg status of Approved
1872
-        // $transaction_processor->toggle_registration_statuses_for_default_approved_events(
1873
-        //      $this->checkout->transaction, $this->checkout->reg_cache_where_params
1874
-        // );
1875
-        // attempt payment
1876
-        $payment = $this->_attempt_payment($this->checkout->payment_method);
1877
-        // process results
1878
-        $payment = $this->_validate_payment($payment);
1879
-        $payment = $this->_post_payment_processing($payment);
1880
-        // verify payment
1881
-        if ($payment instanceof EE_Payment) {
1882
-            // store that for later
1883
-            $this->checkout->payment = $payment;
1884
-            // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1885
-            $this->checkout->transaction->toggle_failed_transaction_status();
1886
-            $payment_status = $payment->status();
1887
-            if (
1888
-                $payment_status === EEM_Payment::status_id_approved
1889
-                || $payment_status === EEM_Payment::status_id_pending
1890
-            ) {
1891
-                return true;
1892
-            } else {
1893
-                return false;
1894
-            }
1895
-        } else if ($payment === true) {
1896
-            // please note that offline payment methods will NOT make a payment,
1897
-            // but instead just mark themselves as the PMD_ID on the transaction, and return true
1898
-            $this->checkout->payment = $payment;
1899
-            return true;
1900
-        }
1901
-        // where's my money?
1902
-        return false;
1903
-    }
1904
-
1905
-
1906
-    /**
1907
-     * _last_second_ticket_verifications
1908
-     *
1909
-     * @access public
1910
-     * @return bool
1911
-     * @throws EE_Error
1912
-     */
1913
-    protected function _last_second_ticket_verifications()
1914
-    {
1915
-        // don't bother re-validating if not a return visit
1916
-        if (! $this->checkout->revisit) {
1917
-            return true;
1918
-        }
1919
-        $registrations = $this->checkout->transaction->registrations();
1920
-        if (empty($registrations)) {
1921
-            return false;
1922
-        }
1923
-        foreach ($registrations as $registration) {
1924
-            if ($registration instanceof EE_Registration && ! $registration->is_approved()) {
1925
-                $event = $registration->event_obj();
1926
-                if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1927
-                    EE_Error::add_error(
1928
-                        apply_filters(
1929
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1930
-                            sprintf(
1931
-                                esc_html__(
1932
-                                    'It appears that the %1$s event that you were about to make a payment for has sold out since you first registered and/or arrived at this page. Please refresh the page and try again. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
1933
-                                    'event_espresso'
1934
-                                ),
1935
-                                $event->name()
1936
-                            )
1937
-                        ),
1938
-                        __FILE__,
1939
-                        __FUNCTION__,
1940
-                        __LINE__
1941
-                    );
1942
-                    return false;
1943
-                }
1944
-            }
1945
-        }
1946
-        return true;
1947
-    }
1948
-
1949
-
1950
-    /**
1951
-     * redirect_form
1952
-     *
1953
-     * @access public
1954
-     * @return bool
1955
-     * @throws EE_Error
1956
-     * @throws InvalidArgumentException
1957
-     * @throws ReflectionException
1958
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1959
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1960
-     */
1961
-    public function redirect_form()
1962
-    {
1963
-        $payment_method_billing_info = $this->_payment_method_billing_info(
1964
-            $this->_get_payment_method_for_selected_method_of_payment()
1965
-        );
1966
-        $html                        = $payment_method_billing_info->get_html();
1967
-        $html                        .= $this->checkout->redirect_form;
1968
-        EE_Registry::instance()->REQ->add_output($html);
1969
-        return true;
1970
-    }
1971
-
1972
-
1973
-    /**
1974
-     * _billing_form_is_valid
1975
-     *
1976
-     * @access private
1977
-     * @return bool
1978
-     * @throws \EE_Error
1979
-     */
1980
-    private function _billing_form_is_valid()
1981
-    {
1982
-        if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1983
-            return true;
1984
-        }
1985
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1986
-            if ($this->checkout->billing_form->was_submitted()) {
1987
-                $this->checkout->billing_form->receive_form_submission();
1988
-                if ($this->checkout->billing_form->is_valid()) {
1989
-                    return true;
1990
-                }
1991
-                $validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1992
-                $error_strings     = array();
1993
-                foreach ($validation_errors as $validation_error) {
1994
-                    if ($validation_error instanceof EE_Validation_Error) {
1995
-                        $form_section = $validation_error->get_form_section();
1996
-                        if ($form_section instanceof EE_Form_Input_Base) {
1997
-                            $label = $form_section->html_label_text();
1998
-                        } elseif ($form_section instanceof EE_Form_Section_Base) {
1999
-                            $label = $form_section->name();
2000
-                        } else {
2001
-                            $label = esc_html__('Validation Error', 'event_espresso');
2002
-                        }
2003
-                        $error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
2004
-                    }
2005
-                }
2006
-                EE_Error::add_error(
2007
-                    sprintf(
2008
-                        esc_html__(
2009
-                            'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
2010
-                            'event_espresso'
2011
-                        ),
2012
-                        '<br/>',
2013
-                        implode('<br/>', $error_strings)
2014
-                    ),
2015
-                    __FILE__,
2016
-                    __FUNCTION__,
2017
-                    __LINE__
2018
-                );
2019
-            } else {
2020
-                EE_Error::add_error(
2021
-                    esc_html__(
2022
-                        'The billing form was not submitted or something prevented it\'s submission.',
2023
-                        'event_espresso'
2024
-                    ),
2025
-                    __FILE__,
2026
-                    __FUNCTION__,
2027
-                    __LINE__
2028
-                );
2029
-            }
2030
-        } else {
2031
-            EE_Error::add_error(
2032
-                esc_html__('The submitted billing form is invalid possibly due to a technical reason.', 'event_espresso'),
2033
-                __FILE__,
2034
-                __FUNCTION__,
2035
-                __LINE__
2036
-            );
2037
-        }
2038
-        return false;
2039
-    }
2040
-
2041
-
2042
-    /**
2043
-     * _setup_primary_registrant_prior_to_payment
2044
-     * ensures that the primary registrant has a valid attendee object created with the critical details populated
2045
-     * (first & last name & email) and that both the transaction object and primary registration object have been saved
2046
-     * plz note that any other registrations will NOT be saved at this point (because they may not have any details
2047
-     * yet)
2048
-     *
2049
-     * @access private
2050
-     * @return bool
2051
-     * @throws EE_Error
2052
-     * @throws InvalidArgumentException
2053
-     * @throws ReflectionException
2054
-     * @throws RuntimeException
2055
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2056
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2057
-     */
2058
-    private function _setup_primary_registrant_prior_to_payment()
2059
-    {
2060
-        // check if transaction has a primary registrant and that it has a related Attendee object
2061
-        // if not, then we need to at least gather some primary registrant data before attempting payment
2062
-        if (
2063
-            $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
2064
-            && ! $this->checkout->transaction_has_primary_registrant()
2065
-            && ! $this->_capture_primary_registration_data_from_billing_form()
2066
-        ) {
2067
-            return false;
2068
-        }
2069
-        // because saving an object clears it's cache, we need to do the chevy shuffle
2070
-        // grab the primary_registration object
2071
-        $primary_registration = $this->checkout->transaction->primary_registration();
2072
-        // at this point we'll consider a TXN to not have been failed
2073
-        $this->checkout->transaction->toggle_failed_transaction_status();
2074
-        // save the TXN ( which clears cached copy of primary_registration)
2075
-        $this->checkout->transaction->save();
2076
-        // grab TXN ID and save it to the primary_registration
2077
-        $primary_registration->set_transaction_id($this->checkout->transaction->ID());
2078
-        // save what we have so far
2079
-        $primary_registration->save();
2080
-        return true;
2081
-    }
2082
-
2083
-
2084
-    /**
2085
-     * _capture_primary_registration_data_from_billing_form
2086
-     *
2087
-     * @access private
2088
-     * @return bool
2089
-     * @throws EE_Error
2090
-     * @throws InvalidArgumentException
2091
-     * @throws ReflectionException
2092
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2093
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2094
-     */
2095
-    private function _capture_primary_registration_data_from_billing_form()
2096
-    {
2097
-        // convert billing form data into an attendee
2098
-        $this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2099
-        if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2100
-            EE_Error::add_error(
2101
-                sprintf(
2102
-                    esc_html__(
2103
-                        'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
2104
-                        'event_espresso'
2105
-                    ),
2106
-                    '<br/>',
2107
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2108
-                ),
2109
-                __FILE__,
2110
-                __FUNCTION__,
2111
-                __LINE__
2112
-            );
2113
-            return false;
2114
-        }
2115
-        $primary_registration = $this->checkout->transaction->primary_registration();
2116
-        if (! $primary_registration instanceof EE_Registration) {
2117
-            EE_Error::add_error(
2118
-                sprintf(
2119
-                    esc_html__(
2120
-                        'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2121
-                        'event_espresso'
2122
-                    ),
2123
-                    '<br/>',
2124
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2125
-                ),
2126
-                __FILE__,
2127
-                __FUNCTION__,
2128
-                __LINE__
2129
-            );
2130
-            return false;
2131
-        }
2132
-        if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2133
-              instanceof
2134
-              EE_Attendee
2135
-        ) {
2136
-            EE_Error::add_error(
2137
-                sprintf(
2138
-                    esc_html__(
2139
-                        'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
2140
-                        'event_espresso'
2141
-                    ),
2142
-                    '<br/>',
2143
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2144
-                ),
2145
-                __FILE__,
2146
-                __FUNCTION__,
2147
-                __LINE__
2148
-            );
2149
-            return false;
2150
-        }
2151
-        /** @type EE_Registration_Processor $registration_processor */
2152
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2153
-        // at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2154
-        $registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2155
-        return true;
2156
-    }
2157
-
2158
-
2159
-    /**
2160
-     * _get_payment_method_for_selected_method_of_payment
2161
-     * retrieves a valid payment method
2162
-     *
2163
-     * @access public
2164
-     * @return EE_Payment_Method
2165
-     * @throws EE_Error
2166
-     * @throws InvalidArgumentException
2167
-     * @throws ReflectionException
2168
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2169
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2170
-     */
2171
-    private function _get_payment_method_for_selected_method_of_payment()
2172
-    {
2173
-        if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2174
-            $this->_redirect_because_event_sold_out();
2175
-            return null;
2176
-        }
2177
-        // get EE_Payment_Method object
2178
-        if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2179
-            $payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2180
-        } else {
2181
-            // load EEM_Payment_Method
2182
-            EE_Registry::instance()->load_model('Payment_Method');
2183
-            /** @type EEM_Payment_Method $EEM_Payment_Method */
2184
-            $EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
2185
-            $payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2186
-        }
2187
-        // verify $payment_method
2188
-        if (! $payment_method instanceof EE_Payment_Method) {
2189
-            // not a payment
2190
-            EE_Error::add_error(
2191
-                sprintf(
2192
-                    esc_html__(
2193
-                        'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2194
-                        'event_espresso'
2195
-                    ),
2196
-                    '<br/>',
2197
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2198
-                ),
2199
-                __FILE__,
2200
-                __FUNCTION__,
2201
-                __LINE__
2202
-            );
2203
-            return null;
2204
-        }
2205
-        // and verify it has a valid Payment_Method Type object
2206
-        if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2207
-            // not a payment
2208
-            EE_Error::add_error(
2209
-                sprintf(
2210
-                    esc_html__(
2211
-                        'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2212
-                        'event_espresso'
2213
-                    ),
2214
-                    '<br/>',
2215
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2216
-                ),
2217
-                __FILE__,
2218
-                __FUNCTION__,
2219
-                __LINE__
2220
-            );
2221
-            return null;
2222
-        }
2223
-        return $payment_method;
2224
-    }
2225
-
2226
-
2227
-    /**
2228
-     *    _attempt_payment
2229
-     *
2230
-     * @access    private
2231
-     * @type    EE_Payment_Method $payment_method
2232
-     * @return mixed EE_Payment | boolean
2233
-     * @throws EE_Error
2234
-     * @throws InvalidArgumentException
2235
-     * @throws ReflectionException
2236
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2237
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2238
-     */
2239
-    private function _attempt_payment(EE_Payment_Method $payment_method)
2240
-    {
2241
-        $payment = null;
2242
-        $this->checkout->transaction->save();
2243
-        $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2244
-        if (! $payment_processor instanceof EE_Payment_Processor) {
2245
-            return false;
2246
-        }
2247
-        try {
2248
-            $payment_processor->set_revisit($this->checkout->revisit);
2249
-            // generate payment object
2250
-            $payment = $payment_processor->process_payment(
2251
-                $payment_method,
2252
-                $this->checkout->transaction,
2253
-                $this->checkout->amount_owing,
2254
-                $this->checkout->billing_form,
2255
-                $this->_get_return_url($payment_method),
2256
-                'CART',
2257
-                $this->checkout->admin_request,
2258
-                true,
2259
-                $this->reg_step_url()
2260
-            );
2261
-        } catch (Exception $e) {
2262
-            $this->_handle_payment_processor_exception($e);
2263
-        }
2264
-        return $payment;
2265
-    }
2266
-
2267
-
2268
-    /**
2269
-     * _handle_payment_processor_exception
2270
-     *
2271
-     * @access protected
2272
-     * @param \Exception $e
2273
-     * @return void
2274
-     * @throws EE_Error
2275
-     * @throws InvalidArgumentException
2276
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2277
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2278
-     */
2279
-    protected function _handle_payment_processor_exception(Exception $e)
2280
-    {
2281
-        EE_Error::add_error(
2282
-            sprintf(
2283
-                esc_html__(
2284
-                    'The payment could not br processed due to a technical issue.%1$sPlease try again or contact %2$s for assistance.||The following Exception was thrown in %4$s on line %5$s:%1$s%3$s',
2285
-                    'event_espresso'
2286
-                ),
2287
-                '<br/>',
2288
-                EE_Registry::instance()->CFG->organization->get_pretty('email'),
2289
-                $e->getMessage(),
2290
-                $e->getFile(),
2291
-                $e->getLine()
2292
-            ),
2293
-            __FILE__,
2294
-            __FUNCTION__,
2295
-            __LINE__
2296
-        );
2297
-    }
2298
-
2299
-
2300
-    /**
2301
-     * _get_return_url
2302
-     *
2303
-     * @access protected
2304
-     * @param \EE_Payment_Method $payment_method
2305
-     * @return string
2306
-     * @throws \EE_Error
2307
-     */
2308
-    protected function _get_return_url(EE_Payment_Method $payment_method)
2309
-    {
2310
-        $return_url = '';
2311
-        switch ($payment_method->type_obj()->payment_occurs()) {
2312
-            case EE_PMT_Base::offsite :
2313
-                $return_url = add_query_arg(
2314
-                    array(
2315
-                        'action'                     => 'process_gateway_response',
2316
-                        'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2317
-                        'spco_txn'                   => $this->checkout->transaction->ID(),
2318
-                    ),
2319
-                    $this->reg_step_url()
2320
-                );
2321
-                break;
2322
-            case EE_PMT_Base::onsite :
2323
-            case EE_PMT_Base::offline :
2324
-                $return_url = $this->checkout->next_step->reg_step_url();
2325
-                break;
2326
-        }
2327
-        return $return_url;
2328
-    }
2329
-
2330
-
2331
-    /**
2332
-     * _validate_payment
2333
-     *
2334
-     * @access private
2335
-     * @param EE_Payment $payment
2336
-     * @return EE_Payment|FALSE
2337
-     * @throws EE_Error
2338
-     * @throws InvalidArgumentException
2339
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2340
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2341
-     */
2342
-    private function _validate_payment($payment = null)
2343
-    {
2344
-        if ($this->checkout->payment_method->is_off_line()) {
2345
-            return true;
2346
-        }
2347
-        // verify payment object
2348
-        if (! $payment instanceof EE_Payment) {
2349
-            // not a payment
2350
-            EE_Error::add_error(
2351
-                sprintf(
2352
-                    esc_html__(
2353
-                        'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2354
-                        'event_espresso'
2355
-                    ),
2356
-                    '<br/>',
2357
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2358
-                ),
2359
-                __FILE__,
2360
-                __FUNCTION__,
2361
-                __LINE__
2362
-            );
2363
-            return false;
2364
-        }
2365
-        return $payment;
2366
-    }
2367
-
2368
-
2369
-    /**
2370
-     * _post_payment_processing
2371
-     *
2372
-     * @access private
2373
-     * @param EE_Payment|bool $payment
2374
-     * @return bool
2375
-     * @throws EE_Error
2376
-     * @throws InvalidArgumentException
2377
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2378
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2379
-     */
2380
-    private function _post_payment_processing($payment = null)
2381
-    {
2382
-        // Off-Line payment?
2383
-        if ($payment === true) {
2384
-            //$this->_setup_redirect_for_next_step();
2385
-            return true;
2386
-            // On-Site payment?
2387
-        } else if ($this->checkout->payment_method->is_on_site()) {
2388
-            if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2389
-                //$this->_setup_redirect_for_next_step();
2390
-                $this->checkout->continue_reg = false;
2391
-            }
2392
-            // Off-Site payment?
2393
-        } else if ($this->checkout->payment_method->is_off_site()) {
2394
-            // if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2395
-            if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2396
-                do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2397
-                $this->checkout->redirect      = true;
2398
-                $this->checkout->redirect_form = $payment->redirect_form();
2399
-                $this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2400
-                // set JSON response
2401
-                $this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2402
-                // and lastly, let's bump the payment status to pending
2403
-                $payment->set_status(EEM_Payment::status_id_pending);
2404
-                $payment->save();
2405
-            } else {
2406
-                // not a payment
2407
-                $this->checkout->continue_reg = false;
2408
-                EE_Error::add_error(
2409
-                    sprintf(
2410
-                        esc_html__(
2411
-                            'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2412
-                            'event_espresso'
2413
-                        ),
2414
-                        '<br/>',
2415
-                        EE_Registry::instance()->CFG->organization->get_pretty('email')
2416
-                    ),
2417
-                    __FILE__,
2418
-                    __FUNCTION__,
2419
-                    __LINE__
2420
-                );
2421
-            }
2422
-        } else {
2423
-            // ummm ya... not Off-Line, not On-Site, not off-Site ????
2424
-            $this->checkout->continue_reg = false;
2425
-            return false;
2426
-        }
2427
-        return $payment;
2428
-    }
2429
-
2430
-
2431
-    /**
2432
-     *    _process_payment_status
2433
-     *
2434
-     * @access private
2435
-     * @type    EE_Payment $payment
2436
-     * @param string       $payment_occurs
2437
-     * @return bool
2438
-     * @throws EE_Error
2439
-     * @throws InvalidArgumentException
2440
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2441
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2442
-     */
2443
-    private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2444
-    {
2445
-        // off-line payment? carry on
2446
-        if ($payment_occurs === EE_PMT_Base::offline) {
2447
-            return true;
2448
-        }
2449
-        // verify payment validity
2450
-        if ($payment instanceof EE_Payment) {
2451
-            do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2452
-            $msg = $payment->gateway_response();
2453
-            // check results
2454
-            switch ($payment->status()) {
2455
-                // good payment
2456
-                case EEM_Payment::status_id_approved :
2457
-                    EE_Error::add_success(
2458
-                        esc_html__('Your payment was processed successfully.', 'event_espresso'),
2459
-                        __FILE__,
2460
-                        __FUNCTION__,
2461
-                        __LINE__
2462
-                    );
2463
-                    return true;
2464
-                    break;
2465
-                // slow payment
2466
-                case EEM_Payment::status_id_pending :
2467
-                    if (empty($msg)) {
2468
-                        $msg = esc_html__(
2469
-                            'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2470
-                            'event_espresso'
2471
-                        );
2472
-                    }
2473
-                    EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2474
-                    return true;
2475
-                    break;
2476
-                // don't wanna payment
2477
-                case EEM_Payment::status_id_cancelled :
2478
-                    if (empty($msg)) {
2479
-                        $msg = _n(
2480
-                            'Payment cancelled. Please try again.',
2481
-                            'Payment cancelled. Please try again or select another method of payment.',
2482
-                            count($this->checkout->available_payment_methods),
2483
-                            'event_espresso'
2484
-                        );
2485
-                    }
2486
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2487
-                    return false;
2488
-                    break;
2489
-                // not enough payment
2490
-                case EEM_Payment::status_id_declined :
2491
-                    if (empty($msg)) {
2492
-                        $msg = _n(
2493
-                            'We\'re sorry but your payment was declined. Please try again.',
2494
-                            'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2495
-                            count($this->checkout->available_payment_methods),
2496
-                            'event_espresso'
2497
-                        );
2498
-                    }
2499
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2500
-                    return false;
2501
-                    break;
2502
-                // bad payment
2503
-                case EEM_Payment::status_id_failed :
2504
-                    if (! empty($msg)) {
2505
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2506
-                        return false;
2507
-                    }
2508
-                    // default to error below
2509
-                    break;
2510
-            }
2511
-        }
2512
-        // off-site payment gateway responses are too unreliable, so let's just assume that
2513
-        // the payment processing is just running slower than the registrant's request
2514
-        if ($payment_occurs === EE_PMT_Base::offsite) {
2515
-            return true;
2516
-        }
2517
-        EE_Error::add_error(
2518
-            sprintf(
2519
-                esc_html__(
2520
-                    'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2521
-                    'event_espresso'
2522
-                ),
2523
-                '<br/>',
2524
-                EE_Registry::instance()->CFG->organization->get_pretty('email')
2525
-            ),
2526
-            __FILE__,
2527
-            __FUNCTION__,
2528
-            __LINE__
2529
-        );
2530
-        return false;
2531
-    }
2532
-
2533
-
2534
-
2535
-
2536
-
2537
-
2538
-    /********************************************************************************************************/
2539
-    /**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2540
-    /********************************************************************************************************/
2541
-    /**
2542
-     * process_gateway_response
2543
-     * this is the return point for Off-Site Payment Methods
2544
-     * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2545
-     * otherwise, it will load up the last payment made for the TXN.
2546
-     * If the payment retrieved looks good, it will then either:
2547
-     *    complete the current step and allow advancement to the next reg step
2548
-     *        or present the payment options again
2549
-     *
2550
-     * @access private
2551
-     * @return EE_Payment|FALSE
2552
-     * @throws EE_Error
2553
-     * @throws InvalidArgumentException
2554
-     * @throws ReflectionException
2555
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2556
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2557
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2558
-     */
2559
-    public function process_gateway_response()
2560
-    {
2561
-        $payment = null;
2562
-        // how have they chosen to pay?
2563
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2564
-        // get EE_Payment_Method object
2565
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2566
-            $this->checkout->continue_reg = false;
2567
-            return false;
2568
-        }
2569
-        if (! $this->checkout->payment_method->is_off_site()) {
2570
-            return false;
2571
-        }
2572
-        $this->_validate_offsite_return();
2573
-        // DEBUG LOG
2574
-        //$this->checkout->log(
2575
-        //	__CLASS__, __FUNCTION__, __LINE__,
2576
-        //	array(
2577
-        //		'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2578
-        //		'payment_method' => $this->checkout->payment_method,
2579
-        //	),
2580
-        //	true
2581
-        //);
2582
-        // verify TXN
2583
-        if ($this->checkout->transaction instanceof EE_Transaction) {
2584
-            $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2585
-            if (! $gateway instanceof EE_Offsite_Gateway) {
2586
-                $this->checkout->continue_reg = false;
2587
-                return false;
2588
-            }
2589
-            $payment = $this->_process_off_site_payment($gateway);
2590
-            $payment = $this->_process_cancelled_payments($payment);
2591
-            $payment = $this->_validate_payment($payment);
2592
-            // if payment was not declined by the payment gateway or cancelled by the registrant
2593
-            if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2594
-                //$this->_setup_redirect_for_next_step();
2595
-                // store that for later
2596
-                $this->checkout->payment = $payment;
2597
-                // mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2598
-                // because we will complete this step during the IPN processing then
2599
-                if ($gateway instanceof EE_Offsite_Gateway && ! $this->handle_IPN_in_this_request()) {
2600
-                    $this->set_completed();
2601
-                }
2602
-                return true;
2603
-            }
2604
-        }
2605
-        // DEBUG LOG
2606
-        //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2607
-        //	array( 'payment' => $payment )
2608
-        //);
2609
-        $this->checkout->continue_reg = false;
2610
-        return false;
2611
-    }
2612
-
2613
-
2614
-    /**
2615
-     * _validate_return
2616
-     *
2617
-     * @access private
2618
-     * @return void
2619
-     * @throws EE_Error
2620
-     * @throws InvalidArgumentException
2621
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2622
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2623
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2624
-     */
2625
-    private function _validate_offsite_return()
2626
-    {
2627
-        $TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2628
-        if ($TXN_ID !== $this->checkout->transaction->ID()) {
2629
-            // Houston... we might have a problem
2630
-            $invalid_TXN = false;
2631
-            // first gather some info
2632
-            $valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2633
-            $primary_registrant = $valid_TXN instanceof EE_Transaction
2634
-                ? $valid_TXN->primary_registration()
2635
-                : null;
2636
-            // let's start by retrieving the cart for this TXN
2637
-            $cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2638
-            if ($cart instanceof EE_Cart) {
2639
-                // verify that the current cart has tickets
2640
-                $tickets = $cart->get_tickets();
2641
-                if (empty($tickets)) {
2642
-                    $invalid_TXN = true;
2643
-                }
2644
-            } else {
2645
-                $invalid_TXN = true;
2646
-            }
2647
-            $valid_TXN_SID = $primary_registrant instanceof EE_Registration
2648
-                ? $primary_registrant->session_ID()
2649
-                : null;
2650
-            // validate current Session ID and compare against valid TXN session ID
2651
-            if (
2652
-                $invalid_TXN // if this is already true, then skip other checks
2653
-                || EE_Session::instance()->id() === null
2654
-                || (
2655
-                    // WARNING !!!
2656
-                    // this could be PayPal sending back duplicate requests (ya they do that)
2657
-                    // or it **could** mean someone is simply registering AGAIN after having just done so
2658
-                    // so now we need to determine if this current TXN looks valid or not
2659
-                    // and whether this reg step has even been started ?
2660
-                    EE_Session::instance()->id() === $valid_TXN_SID
2661
-                    // really? you're half way through this reg step, but you never started it ?
2662
-                    && $this->checkout->transaction->reg_step_completed($this->slug()) === false
2663
-                )
2664
-            ) {
2665
-                $invalid_TXN = true;
2666
-            }
2667
-            if ($invalid_TXN) {
2668
-                // is the valid TXN completed ?
2669
-                if ($valid_TXN instanceof EE_Transaction) {
2670
-                    // has this step even been started ?
2671
-                    $reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2672
-                    if ($reg_step_completed !== false && $reg_step_completed !== true) {
2673
-                        // so it **looks** like this is a double request from PayPal
2674
-                        // so let's try to pick up where we left off
2675
-                        $this->checkout->transaction = $valid_TXN;
2676
-                        $this->checkout->refresh_all_entities(true);
2677
-                        return;
2678
-                    }
2679
-                }
2680
-                // you appear to be lost?
2681
-                $this->_redirect_wayward_request($primary_registrant);
2682
-            }
2683
-        }
2684
-    }
2685
-
2686
-
2687
-    /**
2688
-     * _redirect_wayward_request
2689
-     *
2690
-     * @access private
2691
-     * @param \EE_Registration|null $primary_registrant
2692
-     * @return bool
2693
-     * @throws EE_Error
2694
-     * @throws InvalidArgumentException
2695
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2696
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2697
-     */
2698
-    private function _redirect_wayward_request(EE_Registration $primary_registrant)
2699
-    {
2700
-        if (! $primary_registrant instanceof EE_Registration) {
2701
-            // try redirecting based on the current TXN
2702
-            $primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2703
-                ? $this->checkout->transaction->primary_registration()
2704
-                : null;
2705
-        }
2706
-        if (! $primary_registrant instanceof EE_Registration) {
2707
-            EE_Error::add_error(
2708
-                sprintf(
2709
-                    esc_html__(
2710
-                        'Invalid information was received from the Off-Site Payment Processor and your Transaction details could not be retrieved from the database.%1$sPlease try again or contact %2$s for assistance.',
2711
-                        'event_espresso'
2712
-                    ),
2713
-                    '<br/>',
2714
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2715
-                ),
2716
-                __FILE__,
2717
-                __FUNCTION__,
2718
-                __LINE__
2719
-            );
2720
-            return false;
2721
-        }
2722
-        // make sure transaction is not locked
2723
-        $this->checkout->transaction->unlock();
2724
-        wp_safe_redirect(
2725
-            add_query_arg(
2726
-                array(
2727
-                    'e_reg_url_link' => $primary_registrant->reg_url_link(),
2728
-                ),
2729
-                $this->checkout->thank_you_page_url
2730
-            )
2731
-        );
2732
-        exit();
2733
-    }
2734
-
2735
-
2736
-    /**
2737
-     * _process_off_site_payment
2738
-     *
2739
-     * @access private
2740
-     * @param \EE_Offsite_Gateway $gateway
2741
-     * @return EE_Payment
2742
-     * @throws EE_Error
2743
-     * @throws InvalidArgumentException
2744
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2745
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2746
-     */
2747
-    private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2748
-    {
2749
-        try {
2750
-            $request_data = \EE_Registry::instance()->REQ->params();
2751
-            // if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2752
-            $this->set_handle_IPN_in_this_request(
2753
-                $gateway->handle_IPN_in_this_request($request_data, false)
2754
-            );
2755
-            if ($this->handle_IPN_in_this_request()) {
2756
-                // get payment details and process results
2757
-                /** @type EE_Payment_Processor $payment_processor */
2758
-                $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2759
-                $payment           = $payment_processor->process_ipn(
2760
-                    $request_data,
2761
-                    $this->checkout->transaction,
2762
-                    $this->checkout->payment_method,
2763
-                    true,
2764
-                    false
2765
-                );
2766
-                //$payment_source = 'process_ipn';
2767
-            } else {
2768
-                $payment = $this->checkout->transaction->last_payment();
2769
-                //$payment_source = 'last_payment';
2770
-            }
2771
-        } catch (Exception $e) {
2772
-            // let's just eat the exception and try to move on using any previously set payment info
2773
-            $payment = $this->checkout->transaction->last_payment();
2774
-            //$payment_source = 'last_payment after Exception';
2775
-            // but if we STILL don't have a payment object
2776
-            if (! $payment instanceof EE_Payment) {
2777
-                // then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2778
-                $this->_handle_payment_processor_exception($e);
2779
-            }
2780
-        }
2781
-        // DEBUG LOG
2782
-        //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2783
-        //	array(
2784
-        //		'process_ipn_payment' => $payment,
2785
-        //		'payment_source'      => $payment_source,
2786
-        //	)
2787
-        //);
2788
-        return $payment;
2789
-    }
2790
-
2791
-
2792
-    /**
2793
-     * _process_cancelled_payments
2794
-     * just makes sure that the payment status gets updated correctly
2795
-     * so tha tan error isn't generated during payment validation
2796
-     *
2797
-     * @access private
2798
-     * @param EE_Payment $payment
2799
-     * @return EE_Payment | FALSE
2800
-     * @throws \EE_Error
2801
-     */
2802
-    private function _process_cancelled_payments($payment = null)
2803
-    {
2804
-        if (
2805
-            $payment instanceof EE_Payment
2806
-            && isset($_REQUEST['ee_cancel_payment'])
2807
-            && $payment->status() === EEM_Payment::status_id_failed
2808
-        ) {
2809
-            $payment->set_status(EEM_Payment::status_id_cancelled);
2810
-        }
2811
-        return $payment;
2812
-    }
2813
-
2814
-
2815
-    /**
2816
-     *    get_transaction_details_for_gateways
2817
-     *
2818
-     * @access    public
2819
-     * @return int
2820
-     * @throws EE_Error
2821
-     * @throws InvalidArgumentException
2822
-     * @throws ReflectionException
2823
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2824
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2825
-     */
2826
-    public function get_transaction_details_for_gateways()
2827
-    {
2828
-        $txn_details = array();
2829
-        // ya gotta make a choice man
2830
-        if (empty($this->checkout->selected_method_of_payment)) {
2831
-            $txn_details = array(
2832
-                'error' => esc_html__('Please select a method of payment before proceeding.', 'event_espresso'),
2833
-            );
2834
-        }
2835
-        // get EE_Payment_Method object
2836
-        if (
2837
-            empty($txn_details)
2838
-            &&
2839
-            ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2840
-        ) {
2841
-            $txn_details = array(
2842
-                'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2843
-                'error'                      => esc_html__(
2844
-                    'A valid Payment Method could not be determined.',
2845
-                    'event_espresso'
2846
-                ),
2847
-            );
2848
-        }
2849
-        if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2850
-            $return_url  = $this->_get_return_url($this->checkout->payment_method);
2851
-            $txn_details = array(
2852
-                'TXN_ID'         => $this->checkout->transaction->ID(),
2853
-                'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2854
-                'TXN_total'      => $this->checkout->transaction->total(),
2855
-                'TXN_paid'       => $this->checkout->transaction->paid(),
2856
-                'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2857
-                'STS_ID'         => $this->checkout->transaction->status_ID(),
2858
-                'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2859
-                'payment_amount' => $this->checkout->amount_owing,
2860
-                'return_url'     => $return_url,
2861
-                'cancel_url'     => add_query_arg(array('ee_cancel_payment' => true), $return_url),
2862
-                'notify_url'     => EE_Config::instance()->core->txn_page_url(
2863
-                    array(
2864
-                        'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2865
-                        'ee_payment_method' => $this->checkout->payment_method->slug(),
2866
-                    )
2867
-                ),
2868
-            );
2869
-        }
2870
-        echo wp_json_encode($txn_details);
2871
-        exit();
2872
-    }
2873
-
2874
-
2875
-    /**
2876
-     *    __sleep
2877
-     * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2878
-     * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2879
-     * reg form, because if needed, it will be regenerated anyways
2880
-     *
2881
-     * @return array
2882
-     */
2883
-    public function __sleep()
2884
-    {
2885
-        // remove the reg form and the checkout
2886
-        return array_diff(array_keys(get_object_vars($this)), array('reg_form', 'checkout', 'line_item_display'));
2887
-    }
18
+	/**
19
+	 * @access protected
20
+	 * @var EE_Line_Item_Display $Line_Item_Display
21
+	 */
22
+	protected $line_item_display;
23
+
24
+	/**
25
+	 * @access protected
26
+	 * @var boolean $handle_IPN_in_this_request
27
+	 */
28
+	protected $handle_IPN_in_this_request = false;
29
+
30
+
31
+	/**
32
+	 *    set_hooks - for hooking into EE Core, other modules, etc
33
+	 *
34
+	 * @access    public
35
+	 * @return    void
36
+	 */
37
+	public static function set_hooks()
38
+	{
39
+		add_filter(
40
+			'FHEE__SPCO__EE_Line_Item_Filter_Collection',
41
+			array('EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters')
42
+		);
43
+		add_action(
44
+			'wp_ajax_switch_spco_billing_form',
45
+			array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
46
+		);
47
+		add_action(
48
+			'wp_ajax_nopriv_switch_spco_billing_form',
49
+			array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
50
+		);
51
+		add_action('wp_ajax_save_payer_details', array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details'));
52
+		add_action(
53
+			'wp_ajax_nopriv_save_payer_details',
54
+			array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details')
55
+		);
56
+		add_action(
57
+			'wp_ajax_get_transaction_details_for_gateways',
58
+			array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
59
+		);
60
+		add_action(
61
+			'wp_ajax_nopriv_get_transaction_details_for_gateways',
62
+			array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
63
+		);
64
+		add_filter(
65
+			'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
66
+			array('EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'),
67
+			10,
68
+			1
69
+		);
70
+	}
71
+
72
+
73
+	/**
74
+	 *    ajax switch_spco_billing_form
75
+	 *
76
+	 * @throws \EE_Error
77
+	 */
78
+	public static function switch_spco_billing_form()
79
+	{
80
+		EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
81
+	}
82
+
83
+
84
+	/**
85
+	 *    ajax save_payer_details
86
+	 *
87
+	 * @throws \EE_Error
88
+	 */
89
+	public static function save_payer_details()
90
+	{
91
+		EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
92
+	}
93
+
94
+
95
+	/**
96
+	 *    ajax get_transaction_details
97
+	 *
98
+	 * @throws \EE_Error
99
+	 */
100
+	public static function get_transaction_details()
101
+	{
102
+		EED_Single_Page_Checkout::process_ajax_request('get_transaction_details_for_gateways');
103
+	}
104
+
105
+
106
+	/**
107
+	 * bypass_recaptcha_for_load_payment_method
108
+	 *
109
+	 * @access public
110
+	 * @return array
111
+	 * @throws InvalidArgumentException
112
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
113
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
114
+	 */
115
+	public static function bypass_recaptcha_for_load_payment_method()
116
+	{
117
+		return array(
118
+			'EESID'  => EE_Registry::instance()->SSN->id(),
119
+			'step'   => 'payment_options',
120
+			'action' => 'spco_billing_form',
121
+		);
122
+	}
123
+
124
+
125
+	/**
126
+	 *    class constructor
127
+	 *
128
+	 * @access    public
129
+	 * @param    EE_Checkout $checkout
130
+	 */
131
+	public function __construct(EE_Checkout $checkout)
132
+	{
133
+		$this->_slug     = 'payment_options';
134
+		$this->_name     = esc_html__('Payment Options', 'event_espresso');
135
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
136
+		$this->checkout  = $checkout;
137
+		$this->_reset_success_message();
138
+		$this->set_instructions(
139
+			esc_html__(
140
+				'Please select a method of payment and provide any necessary billing information before proceeding.',
141
+				'event_espresso'
142
+			)
143
+		);
144
+	}
145
+
146
+
147
+	/**
148
+	 * @return null
149
+	 */
150
+	public function line_item_display()
151
+	{
152
+		return $this->line_item_display;
153
+	}
154
+
155
+
156
+	/**
157
+	 * @param null $line_item_display
158
+	 */
159
+	public function set_line_item_display($line_item_display)
160
+	{
161
+		$this->line_item_display = $line_item_display;
162
+	}
163
+
164
+
165
+	/**
166
+	 * @return boolean
167
+	 */
168
+	public function handle_IPN_in_this_request()
169
+	{
170
+		return $this->handle_IPN_in_this_request;
171
+	}
172
+
173
+
174
+	/**
175
+	 * @param boolean $handle_IPN_in_this_request
176
+	 */
177
+	public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
178
+	{
179
+		$this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
180
+	}
181
+
182
+
183
+	/**
184
+	 * translate_js_strings
185
+	 *
186
+	 * @return void
187
+	 */
188
+	public function translate_js_strings()
189
+	{
190
+		EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
191
+			'Please select a method of payment in order to continue.',
192
+			'event_espresso'
193
+		);
194
+		EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__(
195
+			'A valid method of payment could not be determined. Please refresh the page and try again.',
196
+			'event_espresso'
197
+		);
198
+		EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
199
+			'Forwarding to Secure Payment Provider.',
200
+			'event_espresso'
201
+		);
202
+	}
203
+
204
+
205
+	/**
206
+	 * enqueue_styles_and_scripts
207
+	 *
208
+	 * @return void
209
+	 * @throws EE_Error
210
+	 * @throws InvalidArgumentException
211
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
212
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
213
+	 */
214
+	public function enqueue_styles_and_scripts()
215
+	{
216
+		$transaction = $this->checkout->transaction;
217
+		//if the transaction isn't set or nothing is owed on it, don't enqueue any JS
218
+		if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
219
+			return;
220
+		}
221
+		foreach (EEM_Payment_Method::instance()->get_all_for_transaction($transaction, EEM_Payment_Method::scope_cart) as $payment_method) {
222
+			$type_obj = $payment_method->type_obj();
223
+			if ($type_obj instanceof EE_PMT_Base) {
224
+				$billing_form = $type_obj->generate_new_billing_form($transaction);
225
+				if ($billing_form instanceof EE_Form_Section_Proper) {
226
+					$billing_form->enqueue_js();
227
+				}
228
+			}
229
+		}
230
+	}
231
+
232
+
233
+	/**
234
+	 * initialize_reg_step
235
+	 *
236
+	 * @return bool
237
+	 * @throws EE_Error
238
+	 * @throws InvalidArgumentException
239
+	 * @throws ReflectionException
240
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
241
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
242
+	 */
243
+	public function initialize_reg_step()
244
+	{
245
+		// TODO: if /when we implement donations, then this will need overriding
246
+		if (// don't need payment options for:
247
+			// 	registrations made via the admin
248
+			// 	completed transactions
249
+			// 	overpaid transactions
250
+			// 	$ 0.00 transactions (no payment required)
251
+			! $this->checkout->payment_required()
252
+			// but do NOT remove if current action being called belongs to this reg step
253
+			&& ! is_callable(array($this, $this->checkout->action))
254
+			&& ! $this->completed()
255
+		) {
256
+			// and if so, then we no longer need the Payment Options step
257
+			if ($this->is_current_step()) {
258
+				$this->checkout->generate_reg_form = false;
259
+			}
260
+			$this->checkout->remove_reg_step($this->_slug);
261
+			// DEBUG LOG
262
+			//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
263
+			return false;
264
+		}
265
+		// load EEM_Payment_Method
266
+		EE_Registry::instance()->load_model('Payment_Method');
267
+		// get all active payment methods
268
+		$this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
269
+			$this->checkout->transaction,
270
+			EEM_Payment_Method::scope_cart
271
+		);
272
+		return true;
273
+	}
274
+
275
+
276
+	/**
277
+	 * @return EE_Form_Section_Proper
278
+	 * @throws EE_Error
279
+	 * @throws InvalidArgumentException
280
+	 * @throws ReflectionException
281
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
282
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
283
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
284
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
285
+	 */
286
+	public function generate_reg_form()
287
+	{
288
+		// reset in case someone changes their mind
289
+		$this->_reset_selected_method_of_payment();
290
+		// set some defaults
291
+		$this->checkout->selected_method_of_payment = 'payments_closed';
292
+		$registrations_requiring_payment            = array();
293
+		$registrations_for_free_events              = array();
294
+		$registrations_requiring_pre_approval       = array();
295
+		$sold_out_events                            = array();
296
+		$insufficient_spaces_available              = array();
297
+		$no_payment_required                        = true;
298
+		// loop thru registrations to gather info
299
+		$registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
300
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
301
+			$registrations,
302
+			$this->checkout->revisit
303
+		);
304
+		foreach ($registrations as $REG_ID => $registration) {
305
+			/** @var $registration EE_Registration */
306
+			// has this registration lost it's space ?
307
+			if (isset($ejected_registrations[ $REG_ID ])) {
308
+				if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
309
+					$sold_out_events[ $registration->event()->ID() ] = $registration->event();
310
+				} else {
311
+					$insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
312
+				}
313
+				continue;
314
+			}
315
+			// event requires admin approval
316
+			if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
317
+				// add event to list of events with pre-approval reg status
318
+				$registrations_requiring_pre_approval[$REG_ID] = $registration;
319
+				do_action(
320
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
321
+					$registration->event(),
322
+					$this
323
+				);
324
+				continue;
325
+			}
326
+			if ($this->checkout->revisit
327
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
328
+				&& (
329
+					$registration->event()->is_sold_out()
330
+					|| $registration->event()->is_sold_out(true)
331
+				)
332
+			) {
333
+				// add event to list of events that are sold out
334
+				$sold_out_events[$registration->event()->ID()] = $registration->event();
335
+				do_action(
336
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
337
+					$registration->event(),
338
+					$this
339
+				);
340
+				continue;
341
+			}
342
+			// are they allowed to pay now and is there monies owing?
343
+			if ($registration->owes_monies_and_can_pay()) {
344
+				$registrations_requiring_payment[$REG_ID] = $registration;
345
+				do_action(
346
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
347
+					$registration->event(),
348
+					$this
349
+				);
350
+			} elseif (! $this->checkout->revisit
351
+				&& $registration->status_ID() !== EEM_Registration::status_id_not_approved
352
+				&& $registration->ticket()->is_free()
353
+			) {
354
+				$registrations_for_free_events[$registration->event()->ID()] = $registration;
355
+			}
356
+		}
357
+		$subsections = array();
358
+		// now decide which template to load
359
+		if (! empty($sold_out_events)) {
360
+			$subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
361
+		}
362
+		if (! empty($insufficient_spaces_available)) {
363
+			$subsections['insufficient_space'] = $this->_insufficient_spaces_available(
364
+				$insufficient_spaces_available
365
+			);
366
+		}
367
+		if (! empty($registrations_requiring_pre_approval)) {
368
+			$subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
369
+				$registrations_requiring_pre_approval
370
+			);
371
+		}
372
+		if (! empty($registrations_for_free_events)) {
373
+			$subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
374
+		}
375
+		if (! empty($registrations_requiring_payment)) {
376
+			if ($this->checkout->amount_owing > 0) {
377
+				// autoload Line_Item_Display classes
378
+				EEH_Autoloader::register_line_item_filter_autoloaders();
379
+				$line_item_filter_processor = new EE_Line_Item_Filter_Processor(
380
+					apply_filters(
381
+						'FHEE__SPCO__EE_Line_Item_Filter_Collection',
382
+						new EE_Line_Item_Filter_Collection()
383
+					),
384
+					$this->checkout->cart->get_grand_total()
385
+				);
386
+				/** @var EE_Line_Item $filtered_line_item_tree */
387
+				$filtered_line_item_tree = $line_item_filter_processor->process();
388
+				EEH_Autoloader::register_line_item_display_autoloaders();
389
+				$this->set_line_item_display(new EE_Line_Item_Display('spco'));
390
+				$subsections['payment_options'] = $this->_display_payment_options(
391
+					$this->line_item_display->display_line_item(
392
+						$filtered_line_item_tree,
393
+						array('registrations' => $registrations)
394
+					)
395
+				);
396
+				$this->checkout->amount_owing   = $filtered_line_item_tree->total();
397
+				$this->_apply_registration_payments_to_amount_owing($registrations);
398
+			}
399
+			$no_payment_required = false;
400
+		} else {
401
+			$this->_hide_reg_step_submit_button_if_revisit();
402
+		}
403
+		$this->_save_selected_method_of_payment();
404
+
405
+		$subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
406
+		$subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
407
+
408
+		return new EE_Form_Section_Proper(
409
+			array(
410
+				'name'            => $this->reg_form_name(),
411
+				'html_id'         => $this->reg_form_name(),
412
+				'subsections'     => $subsections,
413
+				'layout_strategy' => new EE_No_Layout(),
414
+			)
415
+		);
416
+	}
417
+
418
+
419
+	/**
420
+	 * add line item filters required for this reg step
421
+	 * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
422
+	 *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
423
+	 *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
424
+	 *        payment options reg step, can apply these filters via the following: apply_filters(
425
+	 *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
426
+	 *        filter collection by passing that instead of instantiating a new collection
427
+	 *
428
+	 * @param \EE_Line_Item_Filter_Collection $line_item_filter_collection
429
+	 * @return EE_Line_Item_Filter_Collection
430
+	 * @throws EE_Error
431
+	 * @throws InvalidArgumentException
432
+	 * @throws ReflectionException
433
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
434
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
435
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
436
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
437
+	 */
438
+	public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
439
+	{
440
+		if (! EE_Registry::instance()->SSN instanceof EE_Session) {
441
+			return $line_item_filter_collection;
442
+		}
443
+		if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
444
+			return $line_item_filter_collection;
445
+		}
446
+		if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
447
+			return $line_item_filter_collection;
448
+		}
449
+		$line_item_filter_collection->add(
450
+			new EE_Billable_Line_Item_Filter(
451
+				EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
452
+					EE_Registry::instance()->SSN->checkout()->transaction->registrations(
453
+						EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
454
+					)
455
+				)
456
+			)
457
+		);
458
+		$line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
459
+		return $line_item_filter_collection;
460
+	}
461
+
462
+
463
+	/**
464
+	 * remove_ejected_registrations
465
+	 * if a registrant has lost their potential space at an event due to lack of payment,
466
+	 * then this method removes them from the list of registrations being paid for during this request
467
+	 *
468
+	 * @param \EE_Registration[] $registrations
469
+	 * @return EE_Registration[]
470
+	 * @throws EE_Error
471
+	 * @throws InvalidArgumentException
472
+	 * @throws ReflectionException
473
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
474
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
475
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
476
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
477
+	 */
478
+	public static function remove_ejected_registrations(array $registrations)
479
+	{
480
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
481
+			$registrations,
482
+			EE_Registry::instance()->SSN->checkout()->revisit
483
+		);
484
+		foreach ($registrations as $REG_ID => $registration) {
485
+			// has this registration lost it's space ?
486
+			if (isset($ejected_registrations[$REG_ID])) {
487
+				unset($registrations[$REG_ID]);
488
+				continue;
489
+			}
490
+		}
491
+		return $registrations;
492
+	}
493
+
494
+
495
+	/**
496
+	 * find_registrations_that_lost_their_space
497
+	 * If a registrant chooses an offline payment method like Invoice,
498
+	 * then no space is reserved for them at the event until they fully pay fo that site
499
+	 * (unless the event's default reg status is set to APPROVED)
500
+	 * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
501
+	 * then this method will determine which registrations have lost the ability to complete the reg process.
502
+	 *
503
+	 * @param \EE_Registration[] $registrations
504
+	 * @param bool               $revisit
505
+	 * @return array
506
+	 * @throws EE_Error
507
+	 * @throws InvalidArgumentException
508
+	 * @throws ReflectionException
509
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
510
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
511
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
512
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
513
+	 */
514
+	public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
515
+	{
516
+		// registrations per event
517
+		$event_reg_count = array();
518
+		// spaces left per event
519
+		$event_spaces_remaining = array();
520
+		// tickets left sorted by ID
521
+		$tickets_remaining = array();
522
+		// registrations that have lost their space
523
+		$ejected_registrations = array();
524
+		foreach ($registrations as $REG_ID => $registration) {
525
+			if ($registration->status_ID() === EEM_Registration::status_id_approved
526
+				|| apply_filters(
527
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
528
+					false,
529
+					$registration,
530
+					$revisit
531
+				)
532
+			) {
533
+				continue;
534
+			}
535
+			$EVT_ID = $registration->event_ID();
536
+			$ticket = $registration->ticket();
537
+			if (! isset($tickets_remaining[$ticket->ID()])) {
538
+				$tickets_remaining[$ticket->ID()] = $ticket->remaining();
539
+			}
540
+			if ($tickets_remaining[$ticket->ID()] > 0) {
541
+				if (! isset($event_reg_count[$EVT_ID])) {
542
+					$event_reg_count[$EVT_ID] = 0;
543
+				}
544
+				$event_reg_count[$EVT_ID]++;
545
+				if (! isset($event_spaces_remaining[$EVT_ID])) {
546
+					$event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
547
+				}
548
+			}
549
+			if ($revisit
550
+				&& ($tickets_remaining[$ticket->ID()] === 0
551
+					|| $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
552
+				)
553
+			) {
554
+				$ejected_registrations[$REG_ID] = $registration->event();
555
+				if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
556
+					/** @type EE_Registration_Processor $registration_processor */
557
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
558
+					// at this point, we should have enough details about the registrant to consider the registration
559
+					// NOT incomplete
560
+					$registration_processor->manually_update_registration_status(
561
+						$registration,
562
+						EEM_Registration::status_id_wait_list
563
+					);
564
+				}
565
+			}
566
+		}
567
+		return $ejected_registrations;
568
+	}
569
+
570
+
571
+	/**
572
+	 * _hide_reg_step_submit_button
573
+	 * removes the html for the reg step submit button
574
+	 * by replacing it with an empty string via filter callback
575
+	 *
576
+	 * @return void
577
+	 */
578
+	protected function _adjust_registration_status_if_event_old_sold()
579
+	{
580
+	}
581
+
582
+
583
+	/**
584
+	 * _hide_reg_step_submit_button
585
+	 * removes the html for the reg step submit button
586
+	 * by replacing it with an empty string via filter callback
587
+	 *
588
+	 * @return void
589
+	 */
590
+	protected function _hide_reg_step_submit_button_if_revisit()
591
+	{
592
+		if ($this->checkout->revisit) {
593
+			add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
594
+		}
595
+	}
596
+
597
+
598
+	/**
599
+	 * sold_out_events
600
+	 * displays notices regarding events that have sold out since hte registrant first signed up
601
+	 *
602
+	 * @param \EE_Event[] $sold_out_events_array
603
+	 * @return \EE_Form_Section_Proper
604
+	 * @throws \EE_Error
605
+	 */
606
+	private function _sold_out_events($sold_out_events_array = array())
607
+	{
608
+		// set some defaults
609
+		$this->checkout->selected_method_of_payment = 'events_sold_out';
610
+		$sold_out_events                            = '';
611
+		foreach ($sold_out_events_array as $sold_out_event) {
612
+			$sold_out_events .= EEH_HTML::li(
613
+				EEH_HTML::span(
614
+					'  ' . $sold_out_event->name(),
615
+					'',
616
+					'dashicons dashicons-marker ee-icon-size-16 pink-text'
617
+				)
618
+			);
619
+		}
620
+		return new EE_Form_Section_Proper(
621
+			array(
622
+				'layout_strategy' => new EE_Template_Layout(
623
+					array(
624
+						'layout_template_file' => SPCO_REG_STEPS_PATH
625
+												  . $this->_slug
626
+												  . DS
627
+												  . 'sold_out_events.template.php',
628
+						'template_args'        => apply_filters(
629
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
630
+							array(
631
+								'sold_out_events'     => $sold_out_events,
632
+								'sold_out_events_msg' => apply_filters(
633
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
634
+									sprintf(
635
+										esc_html__(
636
+											'It appears that the event you were about to make a payment for has sold out since you first registered. If you have already made a partial payment towards this event, please contact the event administrator for a refund.%3$s%3$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%2$s',
637
+											'event_espresso'
638
+										),
639
+										'<strong>',
640
+										'</strong>',
641
+										'<br />'
642
+									)
643
+								),
644
+							)
645
+						),
646
+					)
647
+				),
648
+			)
649
+		);
650
+	}
651
+
652
+
653
+	/**
654
+	 * _insufficient_spaces_available
655
+	 * displays notices regarding events that do not have enough remaining spaces
656
+	 * to satisfy the current number of registrations looking to pay
657
+	 *
658
+	 * @param \EE_Event[] $insufficient_spaces_events_array
659
+	 * @return \EE_Form_Section_Proper
660
+	 * @throws \EE_Error
661
+	 */
662
+	private function _insufficient_spaces_available($insufficient_spaces_events_array = array())
663
+	{
664
+		// set some defaults
665
+		$this->checkout->selected_method_of_payment = 'invoice';
666
+		$insufficient_space_events                  = '';
667
+		foreach ($insufficient_spaces_events_array as $event) {
668
+			if ($event instanceof EE_Event) {
669
+				$insufficient_space_events .= EEH_HTML::li(
670
+					EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
671
+				);
672
+			}
673
+		}
674
+		return new EE_Form_Section_Proper(
675
+			array(
676
+				'subsections'     => array(
677
+					'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
678
+					'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
679
+				),
680
+				'layout_strategy' => new EE_Template_Layout(
681
+					array(
682
+						'layout_template_file' => SPCO_REG_STEPS_PATH
683
+												  . $this->_slug
684
+												  . DS
685
+												  . 'sold_out_events.template.php',
686
+						'template_args'        => apply_filters(
687
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
688
+							array(
689
+								'sold_out_events'     => $insufficient_space_events,
690
+								'sold_out_events_msg' => apply_filters(
691
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
692
+									esc_html__(
693
+										'It appears that the event you were about to make a payment for has sold additional tickets since you first registered, and there are no longer enough spaces left to accommodate your selections. You may continue to pay and secure the available space(s) remaining, or simply cancel if you no longer wish to purchase. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
694
+										'event_espresso'
695
+									)
696
+								),
697
+							)
698
+						),
699
+					)
700
+				),
701
+			)
702
+		);
703
+	}
704
+
705
+
706
+	/**
707
+	 * registrations_requiring_pre_approval
708
+	 *
709
+	 * @param array $registrations_requiring_pre_approval
710
+	 * @return EE_Form_Section_Proper
711
+	 * @throws EE_Error
712
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
713
+	 */
714
+	private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = array())
715
+	{
716
+		$events_requiring_pre_approval = '';
717
+		foreach ($registrations_requiring_pre_approval as $registration) {
718
+			if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
719
+				$events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
720
+					EEH_HTML::span(
721
+						'',
722
+						'',
723
+						'dashicons dashicons-marker ee-icon-size-16 orange-text'
724
+					)
725
+					. EEH_HTML::span($registration->event()->name(), '', 'orange-text')
726
+				);
727
+			}
728
+		}
729
+		return new EE_Form_Section_Proper(
730
+			array(
731
+				'layout_strategy' => new EE_Template_Layout(
732
+					array(
733
+						'layout_template_file' => SPCO_REG_STEPS_PATH
734
+												  . $this->_slug
735
+												  . DS
736
+												  . 'events_requiring_pre_approval.template.php', // layout_template
737
+						'template_args'        => apply_filters(
738
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
739
+							array(
740
+								'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
741
+								'events_requiring_pre_approval_msg' => apply_filters(
742
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
743
+									esc_html__(
744
+										'The following events do not require payment at this time and will not be billed during this transaction. Billing will only occur after the attendee has been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
745
+										'event_espresso'
746
+									)
747
+								),
748
+							)
749
+						),
750
+					)
751
+				),
752
+			)
753
+		);
754
+	}
755
+
756
+
757
+	/**
758
+	 * _no_payment_required
759
+	 *
760
+	 * @param \EE_Event[] $registrations_for_free_events
761
+	 * @return \EE_Form_Section_Proper
762
+	 * @throws \EE_Error
763
+	 */
764
+	private function _no_payment_required($registrations_for_free_events = array())
765
+	{
766
+		// set some defaults
767
+		$this->checkout->selected_method_of_payment = 'no_payment_required';
768
+		// generate no_payment_required form
769
+		return new EE_Form_Section_Proper(
770
+			array(
771
+				'layout_strategy' => new EE_Template_Layout(
772
+					array(
773
+						'layout_template_file' => SPCO_REG_STEPS_PATH
774
+												  . $this->_slug
775
+												  . DS
776
+												  . 'no_payment_required.template.php', // layout_template
777
+						'template_args'        => apply_filters(
778
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
779
+							array(
780
+								'revisit'                       => $this->checkout->revisit,
781
+								'registrations'                 => array(),
782
+								'ticket_count'                  => array(),
783
+								'registrations_for_free_events' => $registrations_for_free_events,
784
+								'no_payment_required_msg'       => EEH_HTML::p(
785
+									esc_html__('This is a free event, so no billing will occur.', 'event_espresso')
786
+								),
787
+							)
788
+						),
789
+					)
790
+				),
791
+			)
792
+		);
793
+	}
794
+
795
+
796
+	/**
797
+	 * _display_payment_options
798
+	 *
799
+	 * @param string $transaction_details
800
+	 * @return EE_Form_Section_Proper
801
+	 * @throws EE_Error
802
+	 * @throws InvalidArgumentException
803
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
804
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
805
+	 */
806
+	private function _display_payment_options($transaction_details = '')
807
+	{
808
+		// has method_of_payment been set by no-js user?
809
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
810
+		// build payment options form
811
+		return apply_filters(
812
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
813
+			new EE_Form_Section_Proper(
814
+				array(
815
+					'subsections'     => array(
816
+						'before_payment_options' => apply_filters(
817
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
818
+							new EE_Form_Section_Proper(
819
+								array('layout_strategy' => new EE_Div_Per_Section_Layout())
820
+							)
821
+						),
822
+						'payment_options'        => $this->_setup_payment_options(),
823
+						'after_payment_options'  => apply_filters(
824
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
825
+							new EE_Form_Section_Proper(
826
+								array('layout_strategy' => new EE_Div_Per_Section_Layout())
827
+							)
828
+						),
829
+					),
830
+					'layout_strategy' => new EE_Template_Layout(
831
+						array(
832
+							'layout_template_file' => $this->_template,
833
+							'template_args'        => apply_filters(
834
+								'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
835
+								array(
836
+									'reg_count'                 => $this->line_item_display->total_items(),
837
+									'transaction_details'       => $transaction_details,
838
+									'available_payment_methods' => array(),
839
+								)
840
+							),
841
+						)
842
+					),
843
+				)
844
+			)
845
+		);
846
+	}
847
+
848
+
849
+	/**
850
+	 * _extra_hidden_inputs
851
+	 *
852
+	 * @param bool $no_payment_required
853
+	 * @return \EE_Form_Section_Proper
854
+	 * @throws \EE_Error
855
+	 */
856
+	private function _extra_hidden_inputs($no_payment_required = true)
857
+	{
858
+		return new EE_Form_Section_Proper(
859
+			array(
860
+				'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
861
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
862
+				'subsections'     => array(
863
+					'spco_no_payment_required' => new EE_Hidden_Input(
864
+						array(
865
+							'normalization_strategy' => new EE_Boolean_Normalization(),
866
+							'html_name'              => 'spco_no_payment_required',
867
+							'html_id'                => 'spco-no-payment-required-payment_options',
868
+							'default'                => $no_payment_required,
869
+						)
870
+					),
871
+					'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
872
+						array(
873
+							'normalization_strategy' => new EE_Int_Normalization(),
874
+							'html_name'              => 'spco_transaction_id',
875
+							'html_id'                => 'spco-transaction-id',
876
+							'default'                => $this->checkout->transaction->ID(),
877
+						)
878
+					),
879
+				),
880
+			)
881
+		);
882
+	}
883
+
884
+
885
+	/**
886
+	 *    _apply_registration_payments_to_amount_owing
887
+	 *
888
+	 * @access protected
889
+	 * @param array $registrations
890
+	 * @throws EE_Error
891
+	 */
892
+	protected function _apply_registration_payments_to_amount_owing(array $registrations)
893
+	{
894
+		$payments = array();
895
+		foreach ($registrations as $registration) {
896
+			if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
897
+				$payments += $registration->registration_payments();
898
+			}
899
+		}
900
+		if (! empty($payments)) {
901
+			foreach ($payments as $payment) {
902
+				if ($payment instanceof EE_Registration_Payment) {
903
+					$this->checkout->amount_owing -= $payment->amount();
904
+				}
905
+			}
906
+		}
907
+	}
908
+
909
+
910
+	/**
911
+	 *    _reset_selected_method_of_payment
912
+	 *
913
+	 * @access    private
914
+	 * @param    bool $force_reset
915
+	 * @return void
916
+	 * @throws InvalidArgumentException
917
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919
+	 */
920
+	private function _reset_selected_method_of_payment($force_reset = false)
921
+	{
922
+		$reset_payment_method = $force_reset
923
+			? true
924
+			: sanitize_text_field(EE_Registry::instance()->REQ->get('reset_payment_method', false));
925
+		if ($reset_payment_method) {
926
+			$this->checkout->selected_method_of_payment = null;
927
+			$this->checkout->payment_method             = null;
928
+			$this->checkout->billing_form               = null;
929
+			$this->_save_selected_method_of_payment();
930
+		}
931
+	}
932
+
933
+
934
+	/**
935
+	 * _save_selected_method_of_payment
936
+	 * stores the selected_method_of_payment in the session
937
+	 * so that it's available for all subsequent requests including AJAX
938
+	 *
939
+	 * @access        private
940
+	 * @param string $selected_method_of_payment
941
+	 * @return void
942
+	 * @throws InvalidArgumentException
943
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
944
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
945
+	 */
946
+	private function _save_selected_method_of_payment($selected_method_of_payment = '')
947
+	{
948
+		$selected_method_of_payment = ! empty($selected_method_of_payment)
949
+			? $selected_method_of_payment
950
+			: $this->checkout->selected_method_of_payment;
951
+		EE_Registry::instance()->SSN->set_session_data(
952
+			array('selected_method_of_payment' => $selected_method_of_payment)
953
+		);
954
+	}
955
+
956
+
957
+	/**
958
+	 * _setup_payment_options
959
+	 *
960
+	 * @return EE_Form_Section_Proper
961
+	 * @throws EE_Error
962
+	 * @throws InvalidArgumentException
963
+	 * @throws ReflectionException
964
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
965
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
966
+	 */
967
+	public function _setup_payment_options()
968
+	{
969
+		// load payment method classes
970
+		$this->checkout->available_payment_methods = $this->_get_available_payment_methods();
971
+		if (empty($this->checkout->available_payment_methods)) {
972
+			EE_Error::add_error(
973
+				apply_filters(
974
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__error_message_no_payment_methods',
975
+					sprintf(
976
+						esc_html__(
977
+							'Sorry, you cannot complete your purchase because a payment method is not active.%1$s Please contact %2$s for assistance and provide a description of the problem.',
978
+							'event_espresso'
979
+						),
980
+						'<br>',
981
+						EE_Registry::instance()->CFG->organization->get_pretty('email')
982
+					)
983
+				),
984
+				__FILE__,
985
+				__FUNCTION__,
986
+				__LINE__
987
+			);
988
+		}
989
+		// switch up header depending on number of available payment methods
990
+		$payment_method_header     = count($this->checkout->available_payment_methods) > 1
991
+			? apply_filters(
992
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
993
+				esc_html__('Please Select Your Method of Payment', 'event_espresso')
994
+			)
995
+			: apply_filters(
996
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
997
+				esc_html__('Method of Payment', 'event_espresso')
998
+			);
999
+		$available_payment_methods = array(
1000
+			// display the "Payment Method" header
1001
+			'payment_method_header' => new EE_Form_Section_HTML(
1002
+				EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr')
1003
+			),
1004
+		);
1005
+		// the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
1006
+		$available_payment_method_options = array();
1007
+		$default_payment_method_option    = array();
1008
+		// additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
1009
+		$payment_methods_billing_info = array(
1010
+			new EE_Form_Section_HTML(
1011
+				EEH_HTML::div('<br />', '', '', 'clear:both;')
1012
+			),
1013
+		);
1014
+		// loop through payment methods
1015
+		foreach ($this->checkout->available_payment_methods as $payment_method) {
1016
+			if ($payment_method instanceof EE_Payment_Method) {
1017
+				$payment_method_button = EEH_HTML::img(
1018
+					$payment_method->button_url(),
1019
+					$payment_method->name(),
1020
+					'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1021
+					'spco-payment-method-btn-img'
1022
+				);
1023
+				// check if any payment methods are set as default
1024
+				// if payment method is already selected OR nothing is selected and this payment method should be
1025
+				// open_by_default
1026
+				if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1027
+					|| (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1028
+				) {
1029
+					$this->checkout->selected_method_of_payment = $payment_method->slug();
1030
+					$this->_save_selected_method_of_payment();
1031
+					$default_payment_method_option[$payment_method->slug()] = $payment_method_button;
1032
+				} else {
1033
+					$available_payment_method_options[$payment_method->slug()] = $payment_method_button;
1034
+				}
1035
+				$payment_methods_billing_info[$payment_method->slug() . '-info'] = $this->_payment_method_billing_info(
1036
+					$payment_method
1037
+				);
1038
+			}
1039
+		}
1040
+		// prepend available_payment_method_options with default_payment_method_option so that it appears first in list
1041
+		// of PMs
1042
+		$available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
1043
+		// now generate the actual form  inputs
1044
+		$available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1045
+			$available_payment_method_options
1046
+		);
1047
+		$available_payment_methods                              += $payment_methods_billing_info;
1048
+		// build the available payment methods form
1049
+		return new EE_Form_Section_Proper(
1050
+			array(
1051
+				'html_id'         => 'spco-available-methods-of-payment-dv',
1052
+				'subsections'     => $available_payment_methods,
1053
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1054
+			)
1055
+		);
1056
+	}
1057
+
1058
+
1059
+	/**
1060
+	 * _get_available_payment_methods
1061
+	 *
1062
+	 * @return EE_Payment_Method[]
1063
+	 * @throws EE_Error
1064
+	 * @throws InvalidArgumentException
1065
+	 * @throws ReflectionException
1066
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1067
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1068
+	 */
1069
+	protected function _get_available_payment_methods()
1070
+	{
1071
+		if (! empty($this->checkout->available_payment_methods)) {
1072
+			return $this->checkout->available_payment_methods;
1073
+		}
1074
+		$available_payment_methods = array();
1075
+		// load EEM_Payment_Method
1076
+		EE_Registry::instance()->load_model('Payment_Method');
1077
+		/** @type EEM_Payment_Method $EEM_Payment_Method */
1078
+		$EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
1079
+		// get all active payment methods
1080
+		$payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1081
+			$this->checkout->transaction,
1082
+			EEM_Payment_Method::scope_cart
1083
+		);
1084
+		foreach ($payment_methods as $payment_method) {
1085
+			if ($payment_method instanceof EE_Payment_Method) {
1086
+				$available_payment_methods[$payment_method->slug()] = $payment_method;
1087
+			}
1088
+		}
1089
+		return $available_payment_methods;
1090
+	}
1091
+
1092
+
1093
+	/**
1094
+	 *    _available_payment_method_inputs
1095
+	 *
1096
+	 * @access    private
1097
+	 * @param    array $available_payment_method_options
1098
+	 * @return    \EE_Form_Section_Proper
1099
+	 */
1100
+	private function _available_payment_method_inputs($available_payment_method_options = array())
1101
+	{
1102
+		// generate inputs
1103
+		return new EE_Form_Section_Proper(
1104
+			array(
1105
+				'html_id'         => 'ee-available-payment-method-inputs',
1106
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1107
+				'subsections'     => array(
1108
+					'' => new EE_Radio_Button_Input(
1109
+						$available_payment_method_options,
1110
+						array(
1111
+							'html_name'          => 'selected_method_of_payment',
1112
+							'html_class'         => 'spco-payment-method',
1113
+							'default'            => $this->checkout->selected_method_of_payment,
1114
+							'label_size'         => 11,
1115
+							'enforce_label_size' => true,
1116
+						)
1117
+					),
1118
+				),
1119
+			)
1120
+		);
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 *    _payment_method_billing_info
1126
+	 *
1127
+	 * @access    private
1128
+	 * @param    EE_Payment_Method $payment_method
1129
+	 * @return EE_Form_Section_Proper
1130
+	 * @throws EE_Error
1131
+	 * @throws InvalidArgumentException
1132
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1133
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1134
+	 */
1135
+	private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1136
+	{
1137
+		$currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug()
1138
+			? true
1139
+			: false;
1140
+		// generate the billing form for payment method
1141
+		$billing_form                 = $currently_selected
1142
+			? $this->_get_billing_form_for_payment_method($payment_method)
1143
+			: new EE_Form_Section_HTML();
1144
+		$this->checkout->billing_form = $currently_selected
1145
+			? $billing_form
1146
+			: $this->checkout->billing_form;
1147
+		// it's all in the details
1148
+		$info_html = EEH_HTML::h3(
1149
+			esc_html__('Important information regarding your payment', 'event_espresso'),
1150
+			'',
1151
+			'spco-payment-method-hdr'
1152
+		);
1153
+		// add some info regarding the step, either from what's saved in the admin,
1154
+		// or a default string depending on whether the PM has a billing form or not
1155
+		if ($payment_method->description()) {
1156
+			$payment_method_info = $payment_method->description();
1157
+		} elseif ($billing_form instanceof EE_Billing_Info_Form) {
1158
+			$payment_method_info = sprintf(
1159
+				esc_html__(
1160
+					'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1161
+					'event_espresso'
1162
+				),
1163
+				$this->submit_button_text()
1164
+			);
1165
+		} else {
1166
+			$payment_method_info = sprintf(
1167
+				esc_html__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1168
+				$this->submit_button_text()
1169
+			);
1170
+		}
1171
+		$info_html .= EEH_HTML::p(
1172
+			apply_filters(
1173
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1174
+				$payment_method_info
1175
+			),
1176
+			'',
1177
+			'spco-payment-method-desc ee-attention'
1178
+		);
1179
+		return new EE_Form_Section_Proper(
1180
+			array(
1181
+				'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1182
+				'html_class'      => 'spco-payment-method-info-dv',
1183
+				// only display the selected or default PM
1184
+				'html_style'      => $currently_selected ? '' : 'display:none;',
1185
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1186
+				'subsections'     => array(
1187
+					'info'         => new EE_Form_Section_HTML($info_html),
1188
+					'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1189
+				),
1190
+			)
1191
+		);
1192
+	}
1193
+
1194
+
1195
+	/**
1196
+	 * get_billing_form_html_for_payment_method
1197
+	 *
1198
+	 * @access public
1199
+	 * @return string
1200
+	 * @throws EE_Error
1201
+	 * @throws InvalidArgumentException
1202
+	 * @throws ReflectionException
1203
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1204
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1205
+	 */
1206
+	public function get_billing_form_html_for_payment_method()
1207
+	{
1208
+		// how have they chosen to pay?
1209
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1210
+		$this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1211
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1212
+			return false;
1213
+		}
1214
+		if (apply_filters(
1215
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1216
+			false
1217
+		)) {
1218
+			EE_Error::add_success(
1219
+				apply_filters(
1220
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1221
+					sprintf(
1222
+						esc_html__(
1223
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1224
+							'event_espresso'
1225
+						),
1226
+						$this->checkout->payment_method->name()
1227
+					)
1228
+				)
1229
+			);
1230
+		}
1231
+		// now generate billing form for selected method of payment
1232
+		$payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1233
+		// fill form with attendee info if applicable
1234
+		if ($payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1235
+			&& $this->checkout->transaction_has_primary_registrant()
1236
+		) {
1237
+			$payment_method_billing_form->populate_from_attendee(
1238
+				$this->checkout->transaction->primary_registration()->attendee()
1239
+			);
1240
+		}
1241
+		// and debug content
1242
+		if ($payment_method_billing_form instanceof EE_Billing_Info_Form
1243
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1244
+		) {
1245
+			$payment_method_billing_form =
1246
+				$this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1247
+					$payment_method_billing_form
1248
+				);
1249
+		}
1250
+		$billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1251
+			? $payment_method_billing_form->get_html()
1252
+			: '';
1253
+		$this->checkout->json_response->set_return_data(array('payment_method_info' => $billing_info));
1254
+		// localize validation rules for main form
1255
+		$this->checkout->current_step->reg_form->localize_validation_rules();
1256
+		$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1257
+		return true;
1258
+	}
1259
+
1260
+
1261
+	/**
1262
+	 * _get_billing_form_for_payment_method
1263
+	 *
1264
+	 * @access private
1265
+	 * @param EE_Payment_Method $payment_method
1266
+	 * @return EE_Billing_Info_Form|EE_Form_Section_HTML
1267
+	 * @throws EE_Error
1268
+	 * @throws InvalidArgumentException
1269
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1270
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1271
+	 */
1272
+	private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
1273
+	{
1274
+		$billing_form = $payment_method->type_obj()->billing_form(
1275
+			$this->checkout->transaction,
1276
+			array('amount_owing' => $this->checkout->amount_owing)
1277
+		);
1278
+		if ($billing_form instanceof EE_Billing_Info_Form) {
1279
+			if (apply_filters(
1280
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1281
+				false
1282
+			)
1283
+				&& EE_Registry::instance()->REQ->is_set('payment_method')
1284
+			) {
1285
+				EE_Error::add_success(
1286
+					apply_filters(
1287
+						'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1288
+						sprintf(
1289
+							esc_html__(
1290
+								'You have selected "%s" as your method of payment. Please note the important payment information below.',
1291
+								'event_espresso'
1292
+							),
1293
+							$payment_method->name()
1294
+						)
1295
+					)
1296
+				);
1297
+			}
1298
+			return apply_filters(
1299
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
1300
+				$billing_form,
1301
+				$payment_method
1302
+			);
1303
+		}
1304
+		// no actual billing form, so return empty HTML form section
1305
+		return new EE_Form_Section_HTML();
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * _get_selected_method_of_payment
1311
+	 *
1312
+	 * @access private
1313
+	 * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1314
+	 *                          is not found in the incoming request
1315
+	 * @param string  $request_param
1316
+	 * @return NULL|string
1317
+	 * @throws EE_Error
1318
+	 * @throws InvalidArgumentException
1319
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1320
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1321
+	 */
1322
+	private function _get_selected_method_of_payment(
1323
+		$required = false,
1324
+		$request_param = 'selected_method_of_payment'
1325
+	) {
1326
+		// is selected_method_of_payment set in the request ?
1327
+		$selected_method_of_payment = EE_Registry::instance()->REQ->get($request_param, false);
1328
+		if ($selected_method_of_payment) {
1329
+			// sanitize it
1330
+			$selected_method_of_payment = is_array($selected_method_of_payment)
1331
+				? array_shift($selected_method_of_payment)
1332
+				: $selected_method_of_payment;
1333
+			$selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1334
+			// store it in the session so that it's available for all subsequent requests including AJAX
1335
+			$this->_save_selected_method_of_payment($selected_method_of_payment);
1336
+		} else {
1337
+			// or is is set in the session ?
1338
+			$selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1339
+				'selected_method_of_payment'
1340
+			);
1341
+		}
1342
+		// do ya really really gotta have it?
1343
+		if (empty($selected_method_of_payment) && $required) {
1344
+			EE_Error::add_error(
1345
+				sprintf(
1346
+					esc_html__(
1347
+						'The selected method of payment could not be determined.%sPlease ensure that you have selected one before proceeding.%sIf you continue to experience difficulties, then refresh your browser and try again, or contact %s for assistance.',
1348
+						'event_espresso'
1349
+					),
1350
+					'<br/>',
1351
+					'<br/>',
1352
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
1353
+				),
1354
+				__FILE__,
1355
+				__FUNCTION__,
1356
+				__LINE__
1357
+			);
1358
+			return null;
1359
+		}
1360
+		return $selected_method_of_payment;
1361
+	}
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+
1368
+	/********************************************************************************************************/
1369
+	/***********************************  SWITCH PAYMENT METHOD  ************************************/
1370
+	/********************************************************************************************************/
1371
+	/**
1372
+	 * switch_payment_method
1373
+	 *
1374
+	 * @access public
1375
+	 * @return string
1376
+	 * @throws EE_Error
1377
+	 * @throws InvalidArgumentException
1378
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1379
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1380
+	 */
1381
+	public function switch_payment_method()
1382
+	{
1383
+		if (! $this->_verify_payment_method_is_set()) {
1384
+			return false;
1385
+		}
1386
+		if (apply_filters(
1387
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1388
+			false
1389
+		)) {
1390
+			EE_Error::add_success(
1391
+				apply_filters(
1392
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1393
+					sprintf(
1394
+						esc_html__(
1395
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1396
+							'event_espresso'
1397
+						),
1398
+						$this->checkout->payment_method->name()
1399
+					)
1400
+				)
1401
+			);
1402
+		}
1403
+		// generate billing form for selected method of payment if it hasn't been done already
1404
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1405
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1406
+				$this->checkout->payment_method
1407
+			);
1408
+		}
1409
+		// fill form with attendee info if applicable
1410
+		if (apply_filters(
1411
+			'FHEE__populate_billing_form_fields_from_attendee',
1412
+			(
1413
+				$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1414
+				&& $this->checkout->transaction_has_primary_registrant()
1415
+			),
1416
+			$this->checkout->billing_form,
1417
+			$this->checkout->transaction
1418
+		)
1419
+		) {
1420
+			$this->checkout->billing_form->populate_from_attendee(
1421
+				$this->checkout->transaction->primary_registration()->attendee()
1422
+			);
1423
+		}
1424
+		// and debug content
1425
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1426
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1427
+		) {
1428
+			$this->checkout->billing_form =
1429
+				$this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1430
+					$this->checkout->billing_form
1431
+				);
1432
+		}
1433
+		// get html and validation rules for form
1434
+		if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1435
+			$this->checkout->json_response->set_return_data(
1436
+				array('payment_method_info' => $this->checkout->billing_form->get_html())
1437
+			);
1438
+			// localize validation rules for main form
1439
+			$this->checkout->billing_form->localize_validation_rules(true);
1440
+			$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1441
+		} else {
1442
+			$this->checkout->json_response->set_return_data(array('payment_method_info' => ''));
1443
+		}
1444
+		//prevents advancement to next step
1445
+		$this->checkout->continue_reg = false;
1446
+		return true;
1447
+	}
1448
+
1449
+
1450
+	/**
1451
+	 * _verify_payment_method_is_set
1452
+	 *
1453
+	 * @return bool
1454
+	 * @throws EE_Error
1455
+	 * @throws InvalidArgumentException
1456
+	 * @throws ReflectionException
1457
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1458
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1459
+	 */
1460
+	protected function _verify_payment_method_is_set()
1461
+	{
1462
+		// generate billing form for selected method of payment if it hasn't been done already
1463
+		if (empty($this->checkout->selected_method_of_payment)) {
1464
+			// how have they chosen to pay?
1465
+			$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1466
+		} else {
1467
+			// choose your own adventure based on method_of_payment
1468
+			switch ($this->checkout->selected_method_of_payment) {
1469
+				case 'events_sold_out' :
1470
+					EE_Error::add_attention(
1471
+						apply_filters(
1472
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1473
+							esc_html__(
1474
+								'It appears that the event you were about to make a payment for has sold out since this form first loaded. Please contact the event administrator if you believe this is an error.',
1475
+								'event_espresso'
1476
+							)
1477
+						),
1478
+						__FILE__, __FUNCTION__, __LINE__
1479
+					);
1480
+					return false;
1481
+					break;
1482
+				case 'payments_closed' :
1483
+					EE_Error::add_attention(
1484
+						apply_filters(
1485
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__payments_closed_msg',
1486
+							esc_html__(
1487
+								'It appears that the event you were about to make a payment for is not accepting payments at this time. Please contact the event administrator if you believe this is an error.',
1488
+								'event_espresso'
1489
+							)
1490
+						),
1491
+						__FILE__, __FUNCTION__, __LINE__
1492
+					);
1493
+					return false;
1494
+					break;
1495
+				case 'no_payment_required' :
1496
+					EE_Error::add_attention(
1497
+						apply_filters(
1498
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1499
+							esc_html__(
1500
+								'It appears that the event you were about to make a payment for does not require payment. Please contact the event administrator if you believe this is an error.',
1501
+								'event_espresso'
1502
+							)
1503
+						),
1504
+						__FILE__, __FUNCTION__, __LINE__
1505
+					);
1506
+					return false;
1507
+					break;
1508
+				default:
1509
+			}
1510
+		}
1511
+		// verify payment method
1512
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1513
+			// get payment method for selected method of payment
1514
+			$this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1515
+		}
1516
+		return $this->checkout->payment_method instanceof EE_Payment_Method ? true : false;
1517
+	}
1518
+
1519
+
1520
+
1521
+	/********************************************************************************************************/
1522
+	/***************************************  SAVE PAYER DETAILS  ****************************************/
1523
+	/********************************************************************************************************/
1524
+	/**
1525
+	 * save_payer_details_via_ajax
1526
+	 *
1527
+	 * @return void
1528
+	 * @throws EE_Error
1529
+	 * @throws InvalidArgumentException
1530
+	 * @throws ReflectionException
1531
+	 * @throws RuntimeException
1532
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1533
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1534
+	 */
1535
+	public function save_payer_details_via_ajax()
1536
+	{
1537
+		if (! $this->_verify_payment_method_is_set()) {
1538
+			return;
1539
+		}
1540
+		// generate billing form for selected method of payment if it hasn't been done already
1541
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1542
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1543
+				$this->checkout->payment_method
1544
+			);
1545
+		}
1546
+		// generate primary attendee from payer info if applicable
1547
+		if (! $this->checkout->transaction_has_primary_registrant()) {
1548
+			$attendee = $this->_create_attendee_from_request_data();
1549
+			if ($attendee instanceof EE_Attendee) {
1550
+				foreach ($this->checkout->transaction->registrations() as $registration) {
1551
+					if ($registration->is_primary_registrant()) {
1552
+						$this->checkout->primary_attendee_obj = $attendee;
1553
+						$registration->_add_relation_to($attendee, 'Attendee');
1554
+						$registration->set_attendee_id($attendee->ID());
1555
+						$registration->update_cache_after_object_save('Attendee', $attendee);
1556
+					}
1557
+				}
1558
+			}
1559
+		}
1560
+	}
1561
+
1562
+
1563
+	/**
1564
+	 * create_attendee_from_request_data
1565
+	 * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1566
+	 *
1567
+	 * @return EE_Attendee
1568
+	 * @throws EE_Error
1569
+	 * @throws InvalidArgumentException
1570
+	 * @throws ReflectionException
1571
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1572
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1573
+	 */
1574
+	protected function _create_attendee_from_request_data()
1575
+	{
1576
+		// get State ID
1577
+		$STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1578
+		if (! empty($STA_ID)) {
1579
+			// can we get state object from name ?
1580
+			EE_Registry::instance()->load_model('State');
1581
+			$state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
1582
+			$STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1583
+		}
1584
+		// get Country ISO
1585
+		$CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1586
+		if (! empty($CNT_ISO)) {
1587
+			// can we get country object from name ?
1588
+			EE_Registry::instance()->load_model('Country');
1589
+			$country = EEM_Country::instance()->get_col(
1590
+				array(array('CNT_name' => $CNT_ISO), 'limit' => 1),
1591
+				'CNT_ISO'
1592
+			);
1593
+			$CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1594
+		}
1595
+		// grab attendee data
1596
+		$attendee_data = array(
1597
+			'ATT_fname'    => ! empty($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : '',
1598
+			'ATT_lname'    => ! empty($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : '',
1599
+			'ATT_email'    => ! empty($_REQUEST['email']) ? sanitize_email($_REQUEST['email']) : '',
1600
+			'ATT_address'  => ! empty($_REQUEST['address']) ? sanitize_text_field($_REQUEST['address']) : '',
1601
+			'ATT_address2' => ! empty($_REQUEST['address2']) ? sanitize_text_field($_REQUEST['address2']) : '',
1602
+			'ATT_city'     => ! empty($_REQUEST['city']) ? sanitize_text_field($_REQUEST['city']) : '',
1603
+			'STA_ID'       => $STA_ID,
1604
+			'CNT_ISO'      => $CNT_ISO,
1605
+			'ATT_zip'      => ! empty($_REQUEST['zip']) ? sanitize_text_field($_REQUEST['zip']) : '',
1606
+			'ATT_phone'    => ! empty($_REQUEST['phone']) ? sanitize_text_field($_REQUEST['phone']) : '',
1607
+		);
1608
+		// validate the email address since it is the most important piece of info
1609
+		if (empty($attendee_data['ATT_email']) || $attendee_data['ATT_email'] !== $_REQUEST['email']) {
1610
+			EE_Error::add_error(
1611
+				esc_html__('An invalid email address was submitted.', 'event_espresso'),
1612
+				__FILE__,
1613
+				__FUNCTION__,
1614
+				__LINE__
1615
+			);
1616
+		}
1617
+		// does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1618
+		// AND email address
1619
+		if (! empty($attendee_data['ATT_fname'])
1620
+			&& ! empty($attendee_data['ATT_lname'])
1621
+			&& ! empty($attendee_data['ATT_email'])
1622
+		) {
1623
+			$existing_attendee = EE_Registry::instance()->LIB->EEM_Attendee->find_existing_attendee(
1624
+				array(
1625
+					'ATT_fname' => $attendee_data['ATT_fname'],
1626
+					'ATT_lname' => $attendee_data['ATT_lname'],
1627
+					'ATT_email' => $attendee_data['ATT_email'],
1628
+				)
1629
+			);
1630
+			if ($existing_attendee instanceof EE_Attendee) {
1631
+				return $existing_attendee;
1632
+			}
1633
+		}
1634
+		// no existing attendee? kk let's create a new one
1635
+		// kinda lame, but we need a first and last name to create an attendee, so use the email address if those
1636
+		// don't exist
1637
+		$attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1638
+			? $attendee_data['ATT_fname']
1639
+			: $attendee_data['ATT_email'];
1640
+		$attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1641
+			? $attendee_data['ATT_lname']
1642
+			: $attendee_data['ATT_email'];
1643
+		return EE_Attendee::new_instance($attendee_data);
1644
+	}
1645
+
1646
+
1647
+
1648
+	/********************************************************************************************************/
1649
+	/****************************************  PROCESS REG STEP  *****************************************/
1650
+	/********************************************************************************************************/
1651
+	/**
1652
+	 * process_reg_step
1653
+	 *
1654
+	 * @return bool
1655
+	 * @throws EE_Error
1656
+	 * @throws InvalidArgumentException
1657
+	 * @throws ReflectionException
1658
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1659
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1660
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1661
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
1662
+	 */
1663
+	public function process_reg_step()
1664
+	{
1665
+		// how have they chosen to pay?
1666
+		$this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1667
+			? 'no_payment_required'
1668
+			: $this->_get_selected_method_of_payment(true);
1669
+		// choose your own adventure based on method_of_payment
1670
+		switch ($this->checkout->selected_method_of_payment) {
1671
+
1672
+			case 'events_sold_out' :
1673
+				$this->checkout->redirect     = true;
1674
+				$this->checkout->redirect_url = $this->checkout->cancel_page_url;
1675
+				$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1676
+				// mark this reg step as completed
1677
+				$this->set_completed();
1678
+				return false;
1679
+				break;
1680
+
1681
+			case 'payments_closed' :
1682
+				if (apply_filters(
1683
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__payments_closed__display_success',
1684
+					false
1685
+				)) {
1686
+					EE_Error::add_success(
1687
+						esc_html__('no payment required at this time.', 'event_espresso'),
1688
+						__FILE__,
1689
+						__FUNCTION__,
1690
+						__LINE__
1691
+					);
1692
+				}
1693
+				// mark this reg step as completed
1694
+				$this->set_completed();
1695
+				return true;
1696
+				break;
1697
+
1698
+			case 'no_payment_required' :
1699
+				if (apply_filters(
1700
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1701
+					false
1702
+				)) {
1703
+					EE_Error::add_success(
1704
+						esc_html__('no payment required.', 'event_espresso'),
1705
+						__FILE__,
1706
+						__FUNCTION__,
1707
+						__LINE__
1708
+					);
1709
+				}
1710
+				// mark this reg step as completed
1711
+				$this->set_completed();
1712
+				return true;
1713
+				break;
1714
+
1715
+			default:
1716
+				$registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1717
+					EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1718
+				);
1719
+				$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1720
+					$registrations,
1721
+					EE_Registry::instance()->SSN->checkout()->revisit
1722
+				);
1723
+				// calculate difference between the two arrays
1724
+				$registrations = array_diff($registrations, $ejected_registrations);
1725
+				if (empty($registrations)) {
1726
+					$this->_redirect_because_event_sold_out();
1727
+					return false;
1728
+				}
1729
+				$payment_successful = $this->_process_payment();
1730
+				if ($payment_successful) {
1731
+					$this->checkout->continue_reg = true;
1732
+					$this->_maybe_set_completed($this->checkout->payment_method);
1733
+				} else {
1734
+					$this->checkout->continue_reg = false;
1735
+				}
1736
+				return $payment_successful;
1737
+		}
1738
+	}
1739
+
1740
+
1741
+	/**
1742
+	 * _redirect_because_event_sold_out
1743
+	 *
1744
+	 * @access protected
1745
+	 * @return void
1746
+	 */
1747
+	protected function _redirect_because_event_sold_out()
1748
+	{
1749
+		$this->checkout->continue_reg = false;
1750
+		// set redirect URL
1751
+		$this->checkout->redirect_url = add_query_arg(
1752
+			array('e_reg_url_link' => $this->checkout->reg_url_link),
1753
+			$this->checkout->current_step->reg_step_url()
1754
+		);
1755
+		$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1756
+	}
1757
+
1758
+
1759
+	/**
1760
+	 * _maybe_set_completed
1761
+	 *
1762
+	 * @access protected
1763
+	 * @param \EE_Payment_Method $payment_method
1764
+	 * @return void
1765
+	 * @throws \EE_Error
1766
+	 */
1767
+	protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1768
+	{
1769
+		switch ($payment_method->type_obj()->payment_occurs()) {
1770
+			case EE_PMT_Base::offsite :
1771
+				break;
1772
+			case EE_PMT_Base::onsite :
1773
+			case EE_PMT_Base::offline :
1774
+				// mark this reg step as completed
1775
+				$this->set_completed();
1776
+				break;
1777
+		}
1778
+	}
1779
+
1780
+
1781
+	/**
1782
+	 *    update_reg_step
1783
+	 *    this is the final step after a user  revisits the site to retry a payment
1784
+	 *
1785
+	 * @return bool
1786
+	 * @throws EE_Error
1787
+	 * @throws InvalidArgumentException
1788
+	 * @throws ReflectionException
1789
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1790
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1791
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1792
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
1793
+	 */
1794
+	public function update_reg_step()
1795
+	{
1796
+		$success = true;
1797
+		// if payment required
1798
+		if ($this->checkout->transaction->total() > 0) {
1799
+			do_action(
1800
+				'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1801
+				$this->checkout->transaction
1802
+			);
1803
+			// attempt payment via payment method
1804
+			$success = $this->process_reg_step();
1805
+		}
1806
+		if ($success && ! $this->checkout->redirect) {
1807
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1808
+				$this->checkout->transaction->ID()
1809
+			);
1810
+			// set return URL
1811
+			$this->checkout->redirect_url = add_query_arg(
1812
+				array('e_reg_url_link' => $this->checkout->reg_url_link),
1813
+				$this->checkout->thank_you_page_url
1814
+			);
1815
+		}
1816
+		return $success;
1817
+	}
1818
+
1819
+
1820
+	/**
1821
+	 *    _process_payment
1822
+	 *
1823
+	 * @access private
1824
+	 * @return bool
1825
+	 * @throws EE_Error
1826
+	 * @throws InvalidArgumentException
1827
+	 * @throws ReflectionException
1828
+	 * @throws RuntimeException
1829
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1830
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1831
+	 */
1832
+	private function _process_payment()
1833
+	{
1834
+		// basically confirm that the event hasn't sold out since they hit the page
1835
+		if (! $this->_last_second_ticket_verifications()) {
1836
+			return false;
1837
+		}
1838
+		// ya gotta make a choice man
1839
+		if (empty($this->checkout->selected_method_of_payment)) {
1840
+			$this->checkout->json_response->set_plz_select_method_of_payment(
1841
+				esc_html__('Please select a method of payment before proceeding.', 'event_espresso')
1842
+			);
1843
+			return false;
1844
+		}
1845
+		// get EE_Payment_Method object
1846
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1847
+			return false;
1848
+		}
1849
+		// setup billing form
1850
+		if ($this->checkout->payment_method->is_on_site()) {
1851
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1852
+				$this->checkout->payment_method
1853
+			);
1854
+			// bad billing form ?
1855
+			if (! $this->_billing_form_is_valid()) {
1856
+				return false;
1857
+			}
1858
+		}
1859
+		// ensure primary registrant has been fully processed
1860
+		if (! $this->_setup_primary_registrant_prior_to_payment()) {
1861
+			return false;
1862
+		}
1863
+		// if session is close to expiring (under 10 minutes by default)
1864
+		if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1865
+			// add some time to session expiration so that payment can be completed
1866
+			EE_Registry::instance()->SSN->extend_expiration();
1867
+		}
1868
+		/** @type EE_Transaction_Processor $transaction_processor */
1869
+		//$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1870
+		// in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations
1871
+		// for events with a default reg status of Approved
1872
+		// $transaction_processor->toggle_registration_statuses_for_default_approved_events(
1873
+		//      $this->checkout->transaction, $this->checkout->reg_cache_where_params
1874
+		// );
1875
+		// attempt payment
1876
+		$payment = $this->_attempt_payment($this->checkout->payment_method);
1877
+		// process results
1878
+		$payment = $this->_validate_payment($payment);
1879
+		$payment = $this->_post_payment_processing($payment);
1880
+		// verify payment
1881
+		if ($payment instanceof EE_Payment) {
1882
+			// store that for later
1883
+			$this->checkout->payment = $payment;
1884
+			// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1885
+			$this->checkout->transaction->toggle_failed_transaction_status();
1886
+			$payment_status = $payment->status();
1887
+			if (
1888
+				$payment_status === EEM_Payment::status_id_approved
1889
+				|| $payment_status === EEM_Payment::status_id_pending
1890
+			) {
1891
+				return true;
1892
+			} else {
1893
+				return false;
1894
+			}
1895
+		} else if ($payment === true) {
1896
+			// please note that offline payment methods will NOT make a payment,
1897
+			// but instead just mark themselves as the PMD_ID on the transaction, and return true
1898
+			$this->checkout->payment = $payment;
1899
+			return true;
1900
+		}
1901
+		// where's my money?
1902
+		return false;
1903
+	}
1904
+
1905
+
1906
+	/**
1907
+	 * _last_second_ticket_verifications
1908
+	 *
1909
+	 * @access public
1910
+	 * @return bool
1911
+	 * @throws EE_Error
1912
+	 */
1913
+	protected function _last_second_ticket_verifications()
1914
+	{
1915
+		// don't bother re-validating if not a return visit
1916
+		if (! $this->checkout->revisit) {
1917
+			return true;
1918
+		}
1919
+		$registrations = $this->checkout->transaction->registrations();
1920
+		if (empty($registrations)) {
1921
+			return false;
1922
+		}
1923
+		foreach ($registrations as $registration) {
1924
+			if ($registration instanceof EE_Registration && ! $registration->is_approved()) {
1925
+				$event = $registration->event_obj();
1926
+				if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1927
+					EE_Error::add_error(
1928
+						apply_filters(
1929
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1930
+							sprintf(
1931
+								esc_html__(
1932
+									'It appears that the %1$s event that you were about to make a payment for has sold out since you first registered and/or arrived at this page. Please refresh the page and try again. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
1933
+									'event_espresso'
1934
+								),
1935
+								$event->name()
1936
+							)
1937
+						),
1938
+						__FILE__,
1939
+						__FUNCTION__,
1940
+						__LINE__
1941
+					);
1942
+					return false;
1943
+				}
1944
+			}
1945
+		}
1946
+		return true;
1947
+	}
1948
+
1949
+
1950
+	/**
1951
+	 * redirect_form
1952
+	 *
1953
+	 * @access public
1954
+	 * @return bool
1955
+	 * @throws EE_Error
1956
+	 * @throws InvalidArgumentException
1957
+	 * @throws ReflectionException
1958
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1959
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1960
+	 */
1961
+	public function redirect_form()
1962
+	{
1963
+		$payment_method_billing_info = $this->_payment_method_billing_info(
1964
+			$this->_get_payment_method_for_selected_method_of_payment()
1965
+		);
1966
+		$html                        = $payment_method_billing_info->get_html();
1967
+		$html                        .= $this->checkout->redirect_form;
1968
+		EE_Registry::instance()->REQ->add_output($html);
1969
+		return true;
1970
+	}
1971
+
1972
+
1973
+	/**
1974
+	 * _billing_form_is_valid
1975
+	 *
1976
+	 * @access private
1977
+	 * @return bool
1978
+	 * @throws \EE_Error
1979
+	 */
1980
+	private function _billing_form_is_valid()
1981
+	{
1982
+		if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1983
+			return true;
1984
+		}
1985
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1986
+			if ($this->checkout->billing_form->was_submitted()) {
1987
+				$this->checkout->billing_form->receive_form_submission();
1988
+				if ($this->checkout->billing_form->is_valid()) {
1989
+					return true;
1990
+				}
1991
+				$validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1992
+				$error_strings     = array();
1993
+				foreach ($validation_errors as $validation_error) {
1994
+					if ($validation_error instanceof EE_Validation_Error) {
1995
+						$form_section = $validation_error->get_form_section();
1996
+						if ($form_section instanceof EE_Form_Input_Base) {
1997
+							$label = $form_section->html_label_text();
1998
+						} elseif ($form_section instanceof EE_Form_Section_Base) {
1999
+							$label = $form_section->name();
2000
+						} else {
2001
+							$label = esc_html__('Validation Error', 'event_espresso');
2002
+						}
2003
+						$error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
2004
+					}
2005
+				}
2006
+				EE_Error::add_error(
2007
+					sprintf(
2008
+						esc_html__(
2009
+							'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
2010
+							'event_espresso'
2011
+						),
2012
+						'<br/>',
2013
+						implode('<br/>', $error_strings)
2014
+					),
2015
+					__FILE__,
2016
+					__FUNCTION__,
2017
+					__LINE__
2018
+				);
2019
+			} else {
2020
+				EE_Error::add_error(
2021
+					esc_html__(
2022
+						'The billing form was not submitted or something prevented it\'s submission.',
2023
+						'event_espresso'
2024
+					),
2025
+					__FILE__,
2026
+					__FUNCTION__,
2027
+					__LINE__
2028
+				);
2029
+			}
2030
+		} else {
2031
+			EE_Error::add_error(
2032
+				esc_html__('The submitted billing form is invalid possibly due to a technical reason.', 'event_espresso'),
2033
+				__FILE__,
2034
+				__FUNCTION__,
2035
+				__LINE__
2036
+			);
2037
+		}
2038
+		return false;
2039
+	}
2040
+
2041
+
2042
+	/**
2043
+	 * _setup_primary_registrant_prior_to_payment
2044
+	 * ensures that the primary registrant has a valid attendee object created with the critical details populated
2045
+	 * (first & last name & email) and that both the transaction object and primary registration object have been saved
2046
+	 * plz note that any other registrations will NOT be saved at this point (because they may not have any details
2047
+	 * yet)
2048
+	 *
2049
+	 * @access private
2050
+	 * @return bool
2051
+	 * @throws EE_Error
2052
+	 * @throws InvalidArgumentException
2053
+	 * @throws ReflectionException
2054
+	 * @throws RuntimeException
2055
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2056
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2057
+	 */
2058
+	private function _setup_primary_registrant_prior_to_payment()
2059
+	{
2060
+		// check if transaction has a primary registrant and that it has a related Attendee object
2061
+		// if not, then we need to at least gather some primary registrant data before attempting payment
2062
+		if (
2063
+			$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
2064
+			&& ! $this->checkout->transaction_has_primary_registrant()
2065
+			&& ! $this->_capture_primary_registration_data_from_billing_form()
2066
+		) {
2067
+			return false;
2068
+		}
2069
+		// because saving an object clears it's cache, we need to do the chevy shuffle
2070
+		// grab the primary_registration object
2071
+		$primary_registration = $this->checkout->transaction->primary_registration();
2072
+		// at this point we'll consider a TXN to not have been failed
2073
+		$this->checkout->transaction->toggle_failed_transaction_status();
2074
+		// save the TXN ( which clears cached copy of primary_registration)
2075
+		$this->checkout->transaction->save();
2076
+		// grab TXN ID and save it to the primary_registration
2077
+		$primary_registration->set_transaction_id($this->checkout->transaction->ID());
2078
+		// save what we have so far
2079
+		$primary_registration->save();
2080
+		return true;
2081
+	}
2082
+
2083
+
2084
+	/**
2085
+	 * _capture_primary_registration_data_from_billing_form
2086
+	 *
2087
+	 * @access private
2088
+	 * @return bool
2089
+	 * @throws EE_Error
2090
+	 * @throws InvalidArgumentException
2091
+	 * @throws ReflectionException
2092
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2093
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2094
+	 */
2095
+	private function _capture_primary_registration_data_from_billing_form()
2096
+	{
2097
+		// convert billing form data into an attendee
2098
+		$this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2099
+		if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2100
+			EE_Error::add_error(
2101
+				sprintf(
2102
+					esc_html__(
2103
+						'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
2104
+						'event_espresso'
2105
+					),
2106
+					'<br/>',
2107
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2108
+				),
2109
+				__FILE__,
2110
+				__FUNCTION__,
2111
+				__LINE__
2112
+			);
2113
+			return false;
2114
+		}
2115
+		$primary_registration = $this->checkout->transaction->primary_registration();
2116
+		if (! $primary_registration instanceof EE_Registration) {
2117
+			EE_Error::add_error(
2118
+				sprintf(
2119
+					esc_html__(
2120
+						'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2121
+						'event_espresso'
2122
+					),
2123
+					'<br/>',
2124
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2125
+				),
2126
+				__FILE__,
2127
+				__FUNCTION__,
2128
+				__LINE__
2129
+			);
2130
+			return false;
2131
+		}
2132
+		if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2133
+			  instanceof
2134
+			  EE_Attendee
2135
+		) {
2136
+			EE_Error::add_error(
2137
+				sprintf(
2138
+					esc_html__(
2139
+						'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
2140
+						'event_espresso'
2141
+					),
2142
+					'<br/>',
2143
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2144
+				),
2145
+				__FILE__,
2146
+				__FUNCTION__,
2147
+				__LINE__
2148
+			);
2149
+			return false;
2150
+		}
2151
+		/** @type EE_Registration_Processor $registration_processor */
2152
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2153
+		// at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2154
+		$registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2155
+		return true;
2156
+	}
2157
+
2158
+
2159
+	/**
2160
+	 * _get_payment_method_for_selected_method_of_payment
2161
+	 * retrieves a valid payment method
2162
+	 *
2163
+	 * @access public
2164
+	 * @return EE_Payment_Method
2165
+	 * @throws EE_Error
2166
+	 * @throws InvalidArgumentException
2167
+	 * @throws ReflectionException
2168
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2169
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2170
+	 */
2171
+	private function _get_payment_method_for_selected_method_of_payment()
2172
+	{
2173
+		if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2174
+			$this->_redirect_because_event_sold_out();
2175
+			return null;
2176
+		}
2177
+		// get EE_Payment_Method object
2178
+		if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2179
+			$payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2180
+		} else {
2181
+			// load EEM_Payment_Method
2182
+			EE_Registry::instance()->load_model('Payment_Method');
2183
+			/** @type EEM_Payment_Method $EEM_Payment_Method */
2184
+			$EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
2185
+			$payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2186
+		}
2187
+		// verify $payment_method
2188
+		if (! $payment_method instanceof EE_Payment_Method) {
2189
+			// not a payment
2190
+			EE_Error::add_error(
2191
+				sprintf(
2192
+					esc_html__(
2193
+						'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2194
+						'event_espresso'
2195
+					),
2196
+					'<br/>',
2197
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2198
+				),
2199
+				__FILE__,
2200
+				__FUNCTION__,
2201
+				__LINE__
2202
+			);
2203
+			return null;
2204
+		}
2205
+		// and verify it has a valid Payment_Method Type object
2206
+		if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2207
+			// not a payment
2208
+			EE_Error::add_error(
2209
+				sprintf(
2210
+					esc_html__(
2211
+						'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2212
+						'event_espresso'
2213
+					),
2214
+					'<br/>',
2215
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2216
+				),
2217
+				__FILE__,
2218
+				__FUNCTION__,
2219
+				__LINE__
2220
+			);
2221
+			return null;
2222
+		}
2223
+		return $payment_method;
2224
+	}
2225
+
2226
+
2227
+	/**
2228
+	 *    _attempt_payment
2229
+	 *
2230
+	 * @access    private
2231
+	 * @type    EE_Payment_Method $payment_method
2232
+	 * @return mixed EE_Payment | boolean
2233
+	 * @throws EE_Error
2234
+	 * @throws InvalidArgumentException
2235
+	 * @throws ReflectionException
2236
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2237
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2238
+	 */
2239
+	private function _attempt_payment(EE_Payment_Method $payment_method)
2240
+	{
2241
+		$payment = null;
2242
+		$this->checkout->transaction->save();
2243
+		$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2244
+		if (! $payment_processor instanceof EE_Payment_Processor) {
2245
+			return false;
2246
+		}
2247
+		try {
2248
+			$payment_processor->set_revisit($this->checkout->revisit);
2249
+			// generate payment object
2250
+			$payment = $payment_processor->process_payment(
2251
+				$payment_method,
2252
+				$this->checkout->transaction,
2253
+				$this->checkout->amount_owing,
2254
+				$this->checkout->billing_form,
2255
+				$this->_get_return_url($payment_method),
2256
+				'CART',
2257
+				$this->checkout->admin_request,
2258
+				true,
2259
+				$this->reg_step_url()
2260
+			);
2261
+		} catch (Exception $e) {
2262
+			$this->_handle_payment_processor_exception($e);
2263
+		}
2264
+		return $payment;
2265
+	}
2266
+
2267
+
2268
+	/**
2269
+	 * _handle_payment_processor_exception
2270
+	 *
2271
+	 * @access protected
2272
+	 * @param \Exception $e
2273
+	 * @return void
2274
+	 * @throws EE_Error
2275
+	 * @throws InvalidArgumentException
2276
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2277
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2278
+	 */
2279
+	protected function _handle_payment_processor_exception(Exception $e)
2280
+	{
2281
+		EE_Error::add_error(
2282
+			sprintf(
2283
+				esc_html__(
2284
+					'The payment could not br processed due to a technical issue.%1$sPlease try again or contact %2$s for assistance.||The following Exception was thrown in %4$s on line %5$s:%1$s%3$s',
2285
+					'event_espresso'
2286
+				),
2287
+				'<br/>',
2288
+				EE_Registry::instance()->CFG->organization->get_pretty('email'),
2289
+				$e->getMessage(),
2290
+				$e->getFile(),
2291
+				$e->getLine()
2292
+			),
2293
+			__FILE__,
2294
+			__FUNCTION__,
2295
+			__LINE__
2296
+		);
2297
+	}
2298
+
2299
+
2300
+	/**
2301
+	 * _get_return_url
2302
+	 *
2303
+	 * @access protected
2304
+	 * @param \EE_Payment_Method $payment_method
2305
+	 * @return string
2306
+	 * @throws \EE_Error
2307
+	 */
2308
+	protected function _get_return_url(EE_Payment_Method $payment_method)
2309
+	{
2310
+		$return_url = '';
2311
+		switch ($payment_method->type_obj()->payment_occurs()) {
2312
+			case EE_PMT_Base::offsite :
2313
+				$return_url = add_query_arg(
2314
+					array(
2315
+						'action'                     => 'process_gateway_response',
2316
+						'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2317
+						'spco_txn'                   => $this->checkout->transaction->ID(),
2318
+					),
2319
+					$this->reg_step_url()
2320
+				);
2321
+				break;
2322
+			case EE_PMT_Base::onsite :
2323
+			case EE_PMT_Base::offline :
2324
+				$return_url = $this->checkout->next_step->reg_step_url();
2325
+				break;
2326
+		}
2327
+		return $return_url;
2328
+	}
2329
+
2330
+
2331
+	/**
2332
+	 * _validate_payment
2333
+	 *
2334
+	 * @access private
2335
+	 * @param EE_Payment $payment
2336
+	 * @return EE_Payment|FALSE
2337
+	 * @throws EE_Error
2338
+	 * @throws InvalidArgumentException
2339
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2340
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2341
+	 */
2342
+	private function _validate_payment($payment = null)
2343
+	{
2344
+		if ($this->checkout->payment_method->is_off_line()) {
2345
+			return true;
2346
+		}
2347
+		// verify payment object
2348
+		if (! $payment instanceof EE_Payment) {
2349
+			// not a payment
2350
+			EE_Error::add_error(
2351
+				sprintf(
2352
+					esc_html__(
2353
+						'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2354
+						'event_espresso'
2355
+					),
2356
+					'<br/>',
2357
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2358
+				),
2359
+				__FILE__,
2360
+				__FUNCTION__,
2361
+				__LINE__
2362
+			);
2363
+			return false;
2364
+		}
2365
+		return $payment;
2366
+	}
2367
+
2368
+
2369
+	/**
2370
+	 * _post_payment_processing
2371
+	 *
2372
+	 * @access private
2373
+	 * @param EE_Payment|bool $payment
2374
+	 * @return bool
2375
+	 * @throws EE_Error
2376
+	 * @throws InvalidArgumentException
2377
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2378
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2379
+	 */
2380
+	private function _post_payment_processing($payment = null)
2381
+	{
2382
+		// Off-Line payment?
2383
+		if ($payment === true) {
2384
+			//$this->_setup_redirect_for_next_step();
2385
+			return true;
2386
+			// On-Site payment?
2387
+		} else if ($this->checkout->payment_method->is_on_site()) {
2388
+			if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2389
+				//$this->_setup_redirect_for_next_step();
2390
+				$this->checkout->continue_reg = false;
2391
+			}
2392
+			// Off-Site payment?
2393
+		} else if ($this->checkout->payment_method->is_off_site()) {
2394
+			// if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2395
+			if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2396
+				do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2397
+				$this->checkout->redirect      = true;
2398
+				$this->checkout->redirect_form = $payment->redirect_form();
2399
+				$this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2400
+				// set JSON response
2401
+				$this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2402
+				// and lastly, let's bump the payment status to pending
2403
+				$payment->set_status(EEM_Payment::status_id_pending);
2404
+				$payment->save();
2405
+			} else {
2406
+				// not a payment
2407
+				$this->checkout->continue_reg = false;
2408
+				EE_Error::add_error(
2409
+					sprintf(
2410
+						esc_html__(
2411
+							'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2412
+							'event_espresso'
2413
+						),
2414
+						'<br/>',
2415
+						EE_Registry::instance()->CFG->organization->get_pretty('email')
2416
+					),
2417
+					__FILE__,
2418
+					__FUNCTION__,
2419
+					__LINE__
2420
+				);
2421
+			}
2422
+		} else {
2423
+			// ummm ya... not Off-Line, not On-Site, not off-Site ????
2424
+			$this->checkout->continue_reg = false;
2425
+			return false;
2426
+		}
2427
+		return $payment;
2428
+	}
2429
+
2430
+
2431
+	/**
2432
+	 *    _process_payment_status
2433
+	 *
2434
+	 * @access private
2435
+	 * @type    EE_Payment $payment
2436
+	 * @param string       $payment_occurs
2437
+	 * @return bool
2438
+	 * @throws EE_Error
2439
+	 * @throws InvalidArgumentException
2440
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2441
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2442
+	 */
2443
+	private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2444
+	{
2445
+		// off-line payment? carry on
2446
+		if ($payment_occurs === EE_PMT_Base::offline) {
2447
+			return true;
2448
+		}
2449
+		// verify payment validity
2450
+		if ($payment instanceof EE_Payment) {
2451
+			do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2452
+			$msg = $payment->gateway_response();
2453
+			// check results
2454
+			switch ($payment->status()) {
2455
+				// good payment
2456
+				case EEM_Payment::status_id_approved :
2457
+					EE_Error::add_success(
2458
+						esc_html__('Your payment was processed successfully.', 'event_espresso'),
2459
+						__FILE__,
2460
+						__FUNCTION__,
2461
+						__LINE__
2462
+					);
2463
+					return true;
2464
+					break;
2465
+				// slow payment
2466
+				case EEM_Payment::status_id_pending :
2467
+					if (empty($msg)) {
2468
+						$msg = esc_html__(
2469
+							'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2470
+							'event_espresso'
2471
+						);
2472
+					}
2473
+					EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2474
+					return true;
2475
+					break;
2476
+				// don't wanna payment
2477
+				case EEM_Payment::status_id_cancelled :
2478
+					if (empty($msg)) {
2479
+						$msg = _n(
2480
+							'Payment cancelled. Please try again.',
2481
+							'Payment cancelled. Please try again or select another method of payment.',
2482
+							count($this->checkout->available_payment_methods),
2483
+							'event_espresso'
2484
+						);
2485
+					}
2486
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2487
+					return false;
2488
+					break;
2489
+				// not enough payment
2490
+				case EEM_Payment::status_id_declined :
2491
+					if (empty($msg)) {
2492
+						$msg = _n(
2493
+							'We\'re sorry but your payment was declined. Please try again.',
2494
+							'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2495
+							count($this->checkout->available_payment_methods),
2496
+							'event_espresso'
2497
+						);
2498
+					}
2499
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2500
+					return false;
2501
+					break;
2502
+				// bad payment
2503
+				case EEM_Payment::status_id_failed :
2504
+					if (! empty($msg)) {
2505
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2506
+						return false;
2507
+					}
2508
+					// default to error below
2509
+					break;
2510
+			}
2511
+		}
2512
+		// off-site payment gateway responses are too unreliable, so let's just assume that
2513
+		// the payment processing is just running slower than the registrant's request
2514
+		if ($payment_occurs === EE_PMT_Base::offsite) {
2515
+			return true;
2516
+		}
2517
+		EE_Error::add_error(
2518
+			sprintf(
2519
+				esc_html__(
2520
+					'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2521
+					'event_espresso'
2522
+				),
2523
+				'<br/>',
2524
+				EE_Registry::instance()->CFG->organization->get_pretty('email')
2525
+			),
2526
+			__FILE__,
2527
+			__FUNCTION__,
2528
+			__LINE__
2529
+		);
2530
+		return false;
2531
+	}
2532
+
2533
+
2534
+
2535
+
2536
+
2537
+
2538
+	/********************************************************************************************************/
2539
+	/**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2540
+	/********************************************************************************************************/
2541
+	/**
2542
+	 * process_gateway_response
2543
+	 * this is the return point for Off-Site Payment Methods
2544
+	 * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2545
+	 * otherwise, it will load up the last payment made for the TXN.
2546
+	 * If the payment retrieved looks good, it will then either:
2547
+	 *    complete the current step and allow advancement to the next reg step
2548
+	 *        or present the payment options again
2549
+	 *
2550
+	 * @access private
2551
+	 * @return EE_Payment|FALSE
2552
+	 * @throws EE_Error
2553
+	 * @throws InvalidArgumentException
2554
+	 * @throws ReflectionException
2555
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2556
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2557
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2558
+	 */
2559
+	public function process_gateway_response()
2560
+	{
2561
+		$payment = null;
2562
+		// how have they chosen to pay?
2563
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2564
+		// get EE_Payment_Method object
2565
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2566
+			$this->checkout->continue_reg = false;
2567
+			return false;
2568
+		}
2569
+		if (! $this->checkout->payment_method->is_off_site()) {
2570
+			return false;
2571
+		}
2572
+		$this->_validate_offsite_return();
2573
+		// DEBUG LOG
2574
+		//$this->checkout->log(
2575
+		//	__CLASS__, __FUNCTION__, __LINE__,
2576
+		//	array(
2577
+		//		'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2578
+		//		'payment_method' => $this->checkout->payment_method,
2579
+		//	),
2580
+		//	true
2581
+		//);
2582
+		// verify TXN
2583
+		if ($this->checkout->transaction instanceof EE_Transaction) {
2584
+			$gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2585
+			if (! $gateway instanceof EE_Offsite_Gateway) {
2586
+				$this->checkout->continue_reg = false;
2587
+				return false;
2588
+			}
2589
+			$payment = $this->_process_off_site_payment($gateway);
2590
+			$payment = $this->_process_cancelled_payments($payment);
2591
+			$payment = $this->_validate_payment($payment);
2592
+			// if payment was not declined by the payment gateway or cancelled by the registrant
2593
+			if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2594
+				//$this->_setup_redirect_for_next_step();
2595
+				// store that for later
2596
+				$this->checkout->payment = $payment;
2597
+				// mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2598
+				// because we will complete this step during the IPN processing then
2599
+				if ($gateway instanceof EE_Offsite_Gateway && ! $this->handle_IPN_in_this_request()) {
2600
+					$this->set_completed();
2601
+				}
2602
+				return true;
2603
+			}
2604
+		}
2605
+		// DEBUG LOG
2606
+		//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2607
+		//	array( 'payment' => $payment )
2608
+		//);
2609
+		$this->checkout->continue_reg = false;
2610
+		return false;
2611
+	}
2612
+
2613
+
2614
+	/**
2615
+	 * _validate_return
2616
+	 *
2617
+	 * @access private
2618
+	 * @return void
2619
+	 * @throws EE_Error
2620
+	 * @throws InvalidArgumentException
2621
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2622
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2623
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2624
+	 */
2625
+	private function _validate_offsite_return()
2626
+	{
2627
+		$TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2628
+		if ($TXN_ID !== $this->checkout->transaction->ID()) {
2629
+			// Houston... we might have a problem
2630
+			$invalid_TXN = false;
2631
+			// first gather some info
2632
+			$valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2633
+			$primary_registrant = $valid_TXN instanceof EE_Transaction
2634
+				? $valid_TXN->primary_registration()
2635
+				: null;
2636
+			// let's start by retrieving the cart for this TXN
2637
+			$cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2638
+			if ($cart instanceof EE_Cart) {
2639
+				// verify that the current cart has tickets
2640
+				$tickets = $cart->get_tickets();
2641
+				if (empty($tickets)) {
2642
+					$invalid_TXN = true;
2643
+				}
2644
+			} else {
2645
+				$invalid_TXN = true;
2646
+			}
2647
+			$valid_TXN_SID = $primary_registrant instanceof EE_Registration
2648
+				? $primary_registrant->session_ID()
2649
+				: null;
2650
+			// validate current Session ID and compare against valid TXN session ID
2651
+			if (
2652
+				$invalid_TXN // if this is already true, then skip other checks
2653
+				|| EE_Session::instance()->id() === null
2654
+				|| (
2655
+					// WARNING !!!
2656
+					// this could be PayPal sending back duplicate requests (ya they do that)
2657
+					// or it **could** mean someone is simply registering AGAIN after having just done so
2658
+					// so now we need to determine if this current TXN looks valid or not
2659
+					// and whether this reg step has even been started ?
2660
+					EE_Session::instance()->id() === $valid_TXN_SID
2661
+					// really? you're half way through this reg step, but you never started it ?
2662
+					&& $this->checkout->transaction->reg_step_completed($this->slug()) === false
2663
+				)
2664
+			) {
2665
+				$invalid_TXN = true;
2666
+			}
2667
+			if ($invalid_TXN) {
2668
+				// is the valid TXN completed ?
2669
+				if ($valid_TXN instanceof EE_Transaction) {
2670
+					// has this step even been started ?
2671
+					$reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2672
+					if ($reg_step_completed !== false && $reg_step_completed !== true) {
2673
+						// so it **looks** like this is a double request from PayPal
2674
+						// so let's try to pick up where we left off
2675
+						$this->checkout->transaction = $valid_TXN;
2676
+						$this->checkout->refresh_all_entities(true);
2677
+						return;
2678
+					}
2679
+				}
2680
+				// you appear to be lost?
2681
+				$this->_redirect_wayward_request($primary_registrant);
2682
+			}
2683
+		}
2684
+	}
2685
+
2686
+
2687
+	/**
2688
+	 * _redirect_wayward_request
2689
+	 *
2690
+	 * @access private
2691
+	 * @param \EE_Registration|null $primary_registrant
2692
+	 * @return bool
2693
+	 * @throws EE_Error
2694
+	 * @throws InvalidArgumentException
2695
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2696
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2697
+	 */
2698
+	private function _redirect_wayward_request(EE_Registration $primary_registrant)
2699
+	{
2700
+		if (! $primary_registrant instanceof EE_Registration) {
2701
+			// try redirecting based on the current TXN
2702
+			$primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2703
+				? $this->checkout->transaction->primary_registration()
2704
+				: null;
2705
+		}
2706
+		if (! $primary_registrant instanceof EE_Registration) {
2707
+			EE_Error::add_error(
2708
+				sprintf(
2709
+					esc_html__(
2710
+						'Invalid information was received from the Off-Site Payment Processor and your Transaction details could not be retrieved from the database.%1$sPlease try again or contact %2$s for assistance.',
2711
+						'event_espresso'
2712
+					),
2713
+					'<br/>',
2714
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2715
+				),
2716
+				__FILE__,
2717
+				__FUNCTION__,
2718
+				__LINE__
2719
+			);
2720
+			return false;
2721
+		}
2722
+		// make sure transaction is not locked
2723
+		$this->checkout->transaction->unlock();
2724
+		wp_safe_redirect(
2725
+			add_query_arg(
2726
+				array(
2727
+					'e_reg_url_link' => $primary_registrant->reg_url_link(),
2728
+				),
2729
+				$this->checkout->thank_you_page_url
2730
+			)
2731
+		);
2732
+		exit();
2733
+	}
2734
+
2735
+
2736
+	/**
2737
+	 * _process_off_site_payment
2738
+	 *
2739
+	 * @access private
2740
+	 * @param \EE_Offsite_Gateway $gateway
2741
+	 * @return EE_Payment
2742
+	 * @throws EE_Error
2743
+	 * @throws InvalidArgumentException
2744
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2745
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2746
+	 */
2747
+	private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2748
+	{
2749
+		try {
2750
+			$request_data = \EE_Registry::instance()->REQ->params();
2751
+			// if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2752
+			$this->set_handle_IPN_in_this_request(
2753
+				$gateway->handle_IPN_in_this_request($request_data, false)
2754
+			);
2755
+			if ($this->handle_IPN_in_this_request()) {
2756
+				// get payment details and process results
2757
+				/** @type EE_Payment_Processor $payment_processor */
2758
+				$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2759
+				$payment           = $payment_processor->process_ipn(
2760
+					$request_data,
2761
+					$this->checkout->transaction,
2762
+					$this->checkout->payment_method,
2763
+					true,
2764
+					false
2765
+				);
2766
+				//$payment_source = 'process_ipn';
2767
+			} else {
2768
+				$payment = $this->checkout->transaction->last_payment();
2769
+				//$payment_source = 'last_payment';
2770
+			}
2771
+		} catch (Exception $e) {
2772
+			// let's just eat the exception and try to move on using any previously set payment info
2773
+			$payment = $this->checkout->transaction->last_payment();
2774
+			//$payment_source = 'last_payment after Exception';
2775
+			// but if we STILL don't have a payment object
2776
+			if (! $payment instanceof EE_Payment) {
2777
+				// then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2778
+				$this->_handle_payment_processor_exception($e);
2779
+			}
2780
+		}
2781
+		// DEBUG LOG
2782
+		//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2783
+		//	array(
2784
+		//		'process_ipn_payment' => $payment,
2785
+		//		'payment_source'      => $payment_source,
2786
+		//	)
2787
+		//);
2788
+		return $payment;
2789
+	}
2790
+
2791
+
2792
+	/**
2793
+	 * _process_cancelled_payments
2794
+	 * just makes sure that the payment status gets updated correctly
2795
+	 * so tha tan error isn't generated during payment validation
2796
+	 *
2797
+	 * @access private
2798
+	 * @param EE_Payment $payment
2799
+	 * @return EE_Payment | FALSE
2800
+	 * @throws \EE_Error
2801
+	 */
2802
+	private function _process_cancelled_payments($payment = null)
2803
+	{
2804
+		if (
2805
+			$payment instanceof EE_Payment
2806
+			&& isset($_REQUEST['ee_cancel_payment'])
2807
+			&& $payment->status() === EEM_Payment::status_id_failed
2808
+		) {
2809
+			$payment->set_status(EEM_Payment::status_id_cancelled);
2810
+		}
2811
+		return $payment;
2812
+	}
2813
+
2814
+
2815
+	/**
2816
+	 *    get_transaction_details_for_gateways
2817
+	 *
2818
+	 * @access    public
2819
+	 * @return int
2820
+	 * @throws EE_Error
2821
+	 * @throws InvalidArgumentException
2822
+	 * @throws ReflectionException
2823
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2824
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2825
+	 */
2826
+	public function get_transaction_details_for_gateways()
2827
+	{
2828
+		$txn_details = array();
2829
+		// ya gotta make a choice man
2830
+		if (empty($this->checkout->selected_method_of_payment)) {
2831
+			$txn_details = array(
2832
+				'error' => esc_html__('Please select a method of payment before proceeding.', 'event_espresso'),
2833
+			);
2834
+		}
2835
+		// get EE_Payment_Method object
2836
+		if (
2837
+			empty($txn_details)
2838
+			&&
2839
+			! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2840
+		) {
2841
+			$txn_details = array(
2842
+				'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2843
+				'error'                      => esc_html__(
2844
+					'A valid Payment Method could not be determined.',
2845
+					'event_espresso'
2846
+				),
2847
+			);
2848
+		}
2849
+		if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2850
+			$return_url  = $this->_get_return_url($this->checkout->payment_method);
2851
+			$txn_details = array(
2852
+				'TXN_ID'         => $this->checkout->transaction->ID(),
2853
+				'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2854
+				'TXN_total'      => $this->checkout->transaction->total(),
2855
+				'TXN_paid'       => $this->checkout->transaction->paid(),
2856
+				'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2857
+				'STS_ID'         => $this->checkout->transaction->status_ID(),
2858
+				'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2859
+				'payment_amount' => $this->checkout->amount_owing,
2860
+				'return_url'     => $return_url,
2861
+				'cancel_url'     => add_query_arg(array('ee_cancel_payment' => true), $return_url),
2862
+				'notify_url'     => EE_Config::instance()->core->txn_page_url(
2863
+					array(
2864
+						'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2865
+						'ee_payment_method' => $this->checkout->payment_method->slug(),
2866
+					)
2867
+				),
2868
+			);
2869
+		}
2870
+		echo wp_json_encode($txn_details);
2871
+		exit();
2872
+	}
2873
+
2874
+
2875
+	/**
2876
+	 *    __sleep
2877
+	 * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2878
+	 * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2879
+	 * reg form, because if needed, it will be regenerated anyways
2880
+	 *
2881
+	 * @return array
2882
+	 */
2883
+	public function __sleep()
2884
+	{
2885
+		// remove the reg form and the checkout
2886
+		return array_diff(array_keys(get_object_vars($this)), array('reg_form', 'checkout', 'line_item_display'));
2887
+	}
2888 2888
 }
Please login to merge, or discard this patch.
admin_pages/transactions/Transactions_Admin_Page.core.php 2 patches
Indentation   +2433 added lines, -2433 removed lines patch added patch discarded remove patch
@@ -16,2437 +16,2437 @@
 block discarded – undo
16 16
 class Transactions_Admin_Page extends EE_Admin_Page
17 17
 {
18 18
 
19
-    /**
20
-     * @var EE_Transaction
21
-     */
22
-    private $_transaction;
23
-
24
-    /**
25
-     * @var EE_Session
26
-     */
27
-    private $_session;
28
-
29
-    /**
30
-     * @var array $_txn_status
31
-     */
32
-    private static $_txn_status;
33
-
34
-    /**
35
-     * @var array $_pay_status
36
-     */
37
-    private static $_pay_status;
38
-
39
-    /**
40
-     * @var array $_existing_reg_payment_REG_IDs
41
-     */
42
-    protected $_existing_reg_payment_REG_IDs = null;
43
-
44
-
45
-    /**
46
-     * @Constructor
47
-     * @access public
48
-     * @param bool $routing
49
-     * @throws EE_Error
50
-     * @throws InvalidArgumentException
51
-     * @throws ReflectionException
52
-     * @throws InvalidDataTypeException
53
-     * @throws InvalidInterfaceException
54
-     */
55
-    public function __construct($routing = true)
56
-    {
57
-        parent::__construct($routing);
58
-    }
59
-
60
-
61
-    /**
62
-     *    _init_page_props
63
-     *
64
-     * @return void
65
-     */
66
-    protected function _init_page_props()
67
-    {
68
-        $this->page_slug        = TXN_PG_SLUG;
69
-        $this->page_label       = esc_html__('Transactions', 'event_espresso');
70
-        $this->_admin_base_url  = TXN_ADMIN_URL;
71
-        $this->_admin_base_path = TXN_ADMIN;
72
-    }
73
-
74
-
75
-    /**
76
-     *    _ajax_hooks
77
-     *
78
-     * @return void
79
-     */
80
-    protected function _ajax_hooks()
81
-    {
82
-        add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
83
-        add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
84
-        add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
85
-    }
86
-
87
-
88
-    /**
89
-     *    _define_page_props
90
-     *
91
-     * @return void
92
-     */
93
-    protected function _define_page_props()
94
-    {
95
-        $this->_admin_page_title = $this->page_label;
96
-        $this->_labels           = array(
97
-            'buttons' => array(
98
-                'add'    => esc_html__('Add New Transaction', 'event_espresso'),
99
-                'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
100
-                'delete' => esc_html__('Delete Transaction', 'event_espresso'),
101
-            ),
102
-        );
103
-    }
104
-
105
-
106
-    /**
107
-     *        grab url requests and route them
108
-     *
109
-     * @access private
110
-     * @return void
111
-     * @throws EE_Error
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     */
116
-    public function _set_page_routes()
117
-    {
118
-
119
-        $this->_set_transaction_status_array();
120
-
121
-        $txn_id = ! empty($this->_req_data['TXN_ID'])
122
-                  && ! is_array($this->_req_data['TXN_ID'])
123
-            ? $this->_req_data['TXN_ID']
124
-            : 0;
125
-
126
-        $this->_page_routes = array(
127
-
128
-            'default' => array(
129
-                'func'       => '_transactions_overview_list_table',
130
-                'capability' => 'ee_read_transactions',
131
-            ),
132
-
133
-            'view_transaction' => array(
134
-                'func'       => '_transaction_details',
135
-                'capability' => 'ee_read_transaction',
136
-                'obj_id'     => $txn_id,
137
-            ),
138
-
139
-            'send_payment_reminder' => array(
140
-                'func'       => '_send_payment_reminder',
141
-                'noheader'   => true,
142
-                'capability' => 'ee_send_message',
143
-            ),
144
-
145
-            'espresso_apply_payment' => array(
146
-                'func'       => 'apply_payments_or_refunds',
147
-                'noheader'   => true,
148
-                'capability' => 'ee_edit_payments',
149
-            ),
150
-
151
-            'espresso_apply_refund' => array(
152
-                'func'       => 'apply_payments_or_refunds',
153
-                'noheader'   => true,
154
-                'capability' => 'ee_edit_payments',
155
-            ),
156
-
157
-            'espresso_delete_payment' => array(
158
-                'func'       => 'delete_payment',
159
-                'noheader'   => true,
160
-                'capability' => 'ee_delete_payments',
161
-            ),
162
-
163
-        );
164
-    }
165
-
166
-
167
-    protected function _set_page_config()
168
-    {
169
-        $this->_page_config = array(
170
-            'default'          => array(
171
-                'nav'           => array(
172
-                    'label' => esc_html__('Overview', 'event_espresso'),
173
-                    'order' => 10,
174
-                ),
175
-                'list_table'    => 'EE_Admin_Transactions_List_Table',
176
-                'help_tabs'     => array(
177
-                    'transactions_overview_help_tab'                       => array(
178
-                        'title'    => esc_html__('Transactions Overview', 'event_espresso'),
179
-                        'filename' => 'transactions_overview',
180
-                    ),
181
-                    'transactions_overview_table_column_headings_help_tab' => array(
182
-                        'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
183
-                        'filename' => 'transactions_overview_table_column_headings',
184
-                    ),
185
-                    'transactions_overview_views_filters_help_tab'         => array(
186
-                        'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
187
-                        'filename' => 'transactions_overview_views_filters_search',
188
-                    ),
189
-                ),
190
-                'help_tour'     => array('Transactions_Overview_Help_Tour'),
191
-                /**
192
-                 * commented out because currently we are not displaying tips for transaction list table status but this
193
-                 * may change in a later iteration so want to keep the code for then.
194
-                 */
195
-                //'qtips' => array( 'Transactions_List_Table_Tips' ),
196
-                'require_nonce' => false,
197
-            ),
198
-            'view_transaction' => array(
199
-                'nav'       => array(
200
-                    'label'      => esc_html__('View Transaction', 'event_espresso'),
201
-                    'order'      => 5,
202
-                    'url'        => isset($this->_req_data['TXN_ID'])
203
-                        ? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']), $this->_current_page_view_url)
204
-                        : $this->_admin_base_url,
205
-                    'persistent' => false,
206
-                ),
207
-                'help_tabs' => array(
208
-                    'transactions_view_transaction_help_tab'                                              => array(
209
-                        'title'    => esc_html__('View Transaction', 'event_espresso'),
210
-                        'filename' => 'transactions_view_transaction',
211
-                    ),
212
-                    'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
213
-                        'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
214
-                        'filename' => 'transactions_view_transaction_transaction_details_table',
215
-                    ),
216
-                    'transactions_view_transaction_attendees_registered_help_tab'                         => array(
217
-                        'title'    => esc_html__('Attendees Registered', 'event_espresso'),
218
-                        'filename' => 'transactions_view_transaction_attendees_registered',
219
-                    ),
220
-                    'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
221
-                        'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
222
-                        'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
223
-                    ),
224
-                ),
225
-                'qtips'     => array('Transaction_Details_Tips'),
226
-                'help_tour' => array('Transaction_Details_Help_Tour'),
227
-                'metaboxes' => array('_transaction_details_metaboxes'),
228
-
229
-                'require_nonce' => false,
230
-            ),
231
-        );
232
-    }
233
-
234
-
235
-    /**
236
-     * The below methods aren't used by this class currently
237
-     */
238
-    protected function _add_screen_options()
239
-    {
240
-        //noop
241
-    }
242
-
243
-    protected function _add_feature_pointers()
244
-    {
245
-        //noop
246
-    }
247
-
248
-    public function admin_init()
249
-    {
250
-        // IF a registration was JUST added via the admin...
251
-        if (isset(
252
-            $this->_req_data['redirect_from'],
253
-            $this->_req_data['EVT_ID'],
254
-            $this->_req_data['event_name']
255
-        )) {
256
-            // then set a cookie so that we can block any attempts to use
257
-            // the back button as a way to enter another registration.
258
-            setcookie(
259
-                'ee_registration_added',
260
-                $this->_req_data['EVT_ID'], time() + WEEK_IN_SECONDS, '/'
261
-            );
262
-            // and update the global
263
-            $_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
264
-        }
265
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
266
-            'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267
-            'event_espresso'
268
-        );
269
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
270
-            'An error occurred! Please refresh the page and try again.',
271
-            'event_espresso'
272
-        );
273
-        EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
274
-        EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
275
-        EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
276
-        EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__(
277
-            'This transaction has been overpaid ! Payments Total',
278
-            'event_espresso'
279
-        );
280
-    }
281
-
282
-    public function admin_notices()
283
-    {
284
-        //noop
285
-    }
286
-
287
-    public function admin_footer_scripts()
288
-    {
289
-        //noop
290
-    }
291
-
292
-
293
-    /**
294
-     * _set_transaction_status_array
295
-     * sets list of transaction statuses
296
-     *
297
-     * @access private
298
-     * @return void
299
-     * @throws EE_Error
300
-     * @throws InvalidArgumentException
301
-     * @throws InvalidDataTypeException
302
-     * @throws InvalidInterfaceException
303
-     */
304
-    private function _set_transaction_status_array()
305
-    {
306
-        self::$_txn_status = EEM_Transaction::instance()->status_array(true);
307
-    }
308
-
309
-
310
-    /**
311
-     * get_transaction_status_array
312
-     * return the transaction status array for wp_list_table
313
-     *
314
-     * @access public
315
-     * @return array
316
-     */
317
-    public function get_transaction_status_array()
318
-    {
319
-        return self::$_txn_status;
320
-    }
321
-
322
-
323
-    /**
324
-     *    get list of payment statuses
325
-     *
326
-     * @access private
327
-     * @return void
328
-     * @throws EE_Error
329
-     * @throws InvalidArgumentException
330
-     * @throws InvalidDataTypeException
331
-     * @throws InvalidInterfaceException
332
-     */
333
-    private function _get_payment_status_array()
334
-    {
335
-        self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
336
-        $this->_template_args['payment_status'] = self::$_pay_status;
337
-
338
-    }
339
-
340
-
341
-    /**
342
-     *    _add_screen_options_default
343
-     *
344
-     * @access protected
345
-     * @return void
346
-     * @throws InvalidArgumentException
347
-     * @throws InvalidDataTypeException
348
-     * @throws InvalidInterfaceException
349
-     */
350
-    protected function _add_screen_options_default()
351
-    {
352
-        $this->_per_page_screen_option();
353
-    }
354
-
355
-
356
-    /**
357
-     * load_scripts_styles
358
-     *
359
-     * @access public
360
-     * @return void
361
-     */
362
-    public function load_scripts_styles()
363
-    {
364
-        //enqueue style
365
-        wp_register_style(
366
-            'espresso_txn',
367
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
368
-            array(),
369
-            EVENT_ESPRESSO_VERSION
370
-        );
371
-        wp_enqueue_style('espresso_txn');
372
-        //scripts
373
-        wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
374
-            'ee_admin_js',
375
-            'ee-datepicker',
376
-            'jquery-ui-datepicker',
377
-            'jquery-ui-draggable',
378
-            'ee-dialog',
379
-            'ee-accounting',
380
-            'ee-serialize-full-array',
381
-        ), EVENT_ESPRESSO_VERSION, true);
382
-        wp_enqueue_script('espresso_txn');
383
-    }
384
-
385
-
386
-    /**
387
-     *    load_scripts_styles_view_transaction
388
-     *
389
-     * @access public
390
-     * @return void
391
-     */
392
-    public function load_scripts_styles_view_transaction()
393
-    {
394
-        //styles
395
-        wp_enqueue_style('espresso-ui-theme');
396
-    }
397
-
398
-
399
-    /**
400
-     *    load_scripts_styles_default
401
-     *
402
-     * @access public
403
-     * @return void
404
-     */
405
-    public function load_scripts_styles_default()
406
-    {
407
-        //styles
408
-        wp_enqueue_style('espresso-ui-theme');
409
-    }
410
-
411
-
412
-    /**
413
-     *    _set_list_table_views_default
414
-     *
415
-     * @access protected
416
-     * @return void
417
-     */
418
-    protected function _set_list_table_views_default()
419
-    {
420
-        $this->_views = array(
421
-            'all'       => array(
422
-                'slug'  => 'all',
423
-                'label' => esc_html__('View All Transactions', 'event_espresso'),
424
-                'count' => 0,
425
-            ),
426
-            'abandoned' => array(
427
-                'slug'  => 'abandoned',
428
-                'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
429
-                'count' => 0,
430
-            ),
431
-            'failed'    => array(
432
-                'slug'  => 'failed',
433
-                'label' => esc_html__('Failed Transactions', 'event_espresso'),
434
-                'count' => 0,
435
-            ),
436
-        );
437
-    }
438
-
439
-
440
-    /**
441
-     * _set_transaction_object
442
-     * This sets the _transaction property for the transaction details screen
443
-     *
444
-     * @access private
445
-     * @return void
446
-     * @throws EE_Error
447
-     * @throws InvalidArgumentException
448
-     * @throws RuntimeException
449
-     * @throws InvalidDataTypeException
450
-     * @throws InvalidInterfaceException
451
-     * @throws ReflectionException
452
-     */
453
-    private function _set_transaction_object()
454
-    {
455
-        if ($this->_transaction instanceof EE_Transaction) {
456
-            return;
457
-        } //get out we've already set the object
458
-
459
-        $TXN_ID = ! empty($this->_req_data['TXN_ID'])
460
-            ? absint($this->_req_data['TXN_ID'])
461
-            : false;
462
-
463
-        //get transaction object
464
-        $this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
465
-        $this->_session     = $this->_transaction instanceof EE_Transaction
466
-            ? $this->_transaction->get('TXN_session_data')
467
-            : null;
468
-        $this->_transaction->verify_abandoned_transaction_status();
469
-
470
-        if (! $this->_transaction instanceof EE_Transaction) {
471
-            $error_msg = sprintf(
472
-                esc_html__(
473
-                    'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
474
-                    'event_espresso'
475
-                ),
476
-                $TXN_ID
477
-            );
478
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
479
-        }
480
-    }
481
-
482
-
483
-    /**
484
-     *    _transaction_legend_items
485
-     *
486
-     * @access protected
487
-     * @return array
488
-     * @throws EE_Error
489
-     * @throws InvalidArgumentException
490
-     * @throws ReflectionException
491
-     * @throws InvalidDataTypeException
492
-     * @throws InvalidInterfaceException
493
-     */
494
-    protected function _transaction_legend_items()
495
-    {
496
-        EE_Registry::instance()->load_helper('MSG_Template');
497
-        $items = array();
498
-
499
-        if (EE_Registry::instance()->CAP->current_user_can(
500
-            'ee_read_global_messages',
501
-            'view_filtered_messages'
502
-        )) {
503
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
504
-            if (is_array($related_for_icon)
505
-                && isset($related_for_icon['css_class'], $related_for_icon['label'])
506
-            ) {
507
-                $items['view_related_messages'] = array(
508
-                    'class' => $related_for_icon['css_class'],
509
-                    'desc'  => $related_for_icon['label'],
510
-                );
511
-            }
512
-        }
513
-
514
-        $items = apply_filters(
515
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
516
-            array_merge(
517
-                $items,
518
-                array(
519
-                    'view_details'          => array(
520
-                        'class' => 'dashicons dashicons-cart',
521
-                        'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
522
-                    ),
523
-                    'view_invoice'          => array(
524
-                        'class' => 'dashicons dashicons-media-spreadsheet',
525
-                        'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
526
-                    ),
527
-                    'view_receipt'          => array(
528
-                        'class' => 'dashicons dashicons-media-default',
529
-                        'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
530
-                    ),
531
-                    'view_registration'     => array(
532
-                        'class' => 'dashicons dashicons-clipboard',
533
-                        'desc'  => esc_html__('View Registration Details', 'event_espresso'),
534
-                    ),
535
-                    'payment_overview_link' => array(
536
-                        'class' => 'dashicons dashicons-money',
537
-                        'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
538
-                    ),
539
-                )
540
-            )
541
-        );
542
-
543
-        if (EE_Registry::instance()->CAP->current_user_can(
544
-            'ee_send_message',
545
-            'espresso_transactions_send_payment_reminder'
546
-        )) {
547
-            if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
548
-                $items['send_payment_reminder'] = array(
549
-                    'class' => 'dashicons dashicons-email-alt',
550
-                    'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
551
-                );
552
-            } else {
553
-                $items['blank*'] = array(
554
-                    'class' => '',
555
-                    'desc'  => '',
556
-                );
557
-            }
558
-        } else {
559
-            $items['blank*'] = array(
560
-                'class' => '',
561
-                'desc'  => '',
562
-            );
563
-        }
564
-        $more_items = apply_filters(
565
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
566
-            array(
567
-                'overpaid'   => array(
568
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
569
-                    'desc'  => EEH_Template::pretty_status(
570
-                        EEM_Transaction::overpaid_status_code,
571
-                        false,
572
-                        'sentence'
573
-                    ),
574
-                ),
575
-                'complete'   => array(
576
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
577
-                    'desc'  => EEH_Template::pretty_status(
578
-                        EEM_Transaction::complete_status_code,
579
-                        false,
580
-                        'sentence'
581
-                    ),
582
-                ),
583
-                'incomplete' => array(
584
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
585
-                    'desc'  => EEH_Template::pretty_status(
586
-                        EEM_Transaction::incomplete_status_code,
587
-                        false,
588
-                        'sentence'
589
-                    ),
590
-                ),
591
-                'abandoned'  => array(
592
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
593
-                    'desc'  => EEH_Template::pretty_status(
594
-                        EEM_Transaction::abandoned_status_code,
595
-                        false,
596
-                        'sentence'
597
-                    ),
598
-                ),
599
-                'failed'     => array(
600
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
601
-                    'desc'  => EEH_Template::pretty_status(
602
-                        EEM_Transaction::failed_status_code,
603
-                        false,
604
-                        'sentence'
605
-                    ),
606
-                ),
607
-            )
608
-        );
609
-
610
-        return array_merge($items, $more_items);
611
-    }
612
-
613
-
614
-    /**
615
-     *    _transactions_overview_list_table
616
-     *
617
-     * @access protected
618
-     * @return void
619
-     * @throws DomainException
620
-     * @throws EE_Error
621
-     * @throws InvalidArgumentException
622
-     * @throws InvalidDataTypeException
623
-     * @throws InvalidInterfaceException
624
-     * @throws ReflectionException
625
-     */
626
-    protected function _transactions_overview_list_table()
627
-    {
628
-        $this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
629
-        $event = isset($this->_req_data['EVT_ID'])
630
-            ? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'])
631
-            : null;
632
-        $this->_template_args['admin_page_header'] = $event instanceof EE_Event
633
-            ? sprintf(
634
-                esc_html__(
635
-                    '%sViewing Transactions for the Event: %s%s',
636
-                    'event_espresso'
637
-                ),
638
-                '<h3>',
639
-                '<a href="'
640
-                . EE_Admin_Page::add_query_args_and_nonce(
641
-                    array('action' => 'edit', 'post' => $event->ID()),
642
-                    EVENTS_ADMIN_URL
643
-                )
644
-                . '" title="'
645
-                . esc_attr__(
646
-                    'Click to Edit event',
647
-                    'event_espresso'
648
-                )
649
-                . '">' . $event->get('EVT_name') . '</a>',
650
-                '</h3>'
651
-            )
652
-            : '';
653
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
654
-        $this->display_admin_list_table_page_with_no_sidebar();
655
-    }
656
-
657
-
658
-    /**
659
-     *    _transaction_details
660
-     * generates HTML for the View Transaction Details Admin page
661
-     *
662
-     * @access protected
663
-     * @return void
664
-     * @throws DomainException
665
-     * @throws EE_Error
666
-     * @throws InvalidArgumentException
667
-     * @throws InvalidDataTypeException
668
-     * @throws InvalidInterfaceException
669
-     * @throws RuntimeException
670
-     * @throws ReflectionException
671
-     */
672
-    protected function _transaction_details()
673
-    {
674
-        do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
675
-
676
-        $this->_set_transaction_status_array();
677
-
678
-        $this->_template_args                      = array();
679
-        $this->_template_args['transactions_page'] = $this->_wp_page_slug;
680
-
681
-        $this->_set_transaction_object();
682
-
683
-        $primary_registration = $this->_transaction->primary_registration();
684
-        $attendee = $primary_registration instanceof EE_Registration
685
-            ? $primary_registration->attendee()
686
-            : null;
687
-
688
-        $this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
689
-        $this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
690
-
691
-        $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
692
-        $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
693
-
694
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
695
-        $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
696
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
697
-
698
-        $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
699
-        $this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
700
-
701
-        $amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
702
-        $this->_template_args['amount_due'] = EEH_Template::format_currency(
703
-            $amount_due,
704
-            true
705
-        );
706
-        if (EE_Registry::instance()->CFG->currency->sign_b4) {
707
-            $this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign
708
-                                                  . $this->_template_args['amount_due'];
709
-        } else {
710
-            $this->_template_args['amount_due'] .= EE_Registry::instance()->CFG->currency->sign;
711
-        }
712
-        $this->_template_args['amount_due_class'] = '';
713
-
714
-        if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
715
-            // paid in full
716
-            $this->_template_args['amount_due'] = false;
717
-        } elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
718
-            // overpaid
719
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
720
-        } elseif ($this->_transaction->get('TXN_total') > 0
721
-                  && $this->_transaction->get('TXN_paid') > 0
722
-        ) {
723
-            // monies owing
724
-            $this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
725
-        } elseif ($this->_transaction->get('TXN_total') > 0
726
-                  && $this->_transaction->get('TXN_paid') == 0
727
-        ) {
728
-            // no payments made yet
729
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
730
-        } elseif ($this->_transaction->get('TXN_total') == 0) {
731
-            // free event
732
-            $this->_template_args['amount_due'] = false;
733
-        }
734
-
735
-        $payment_method = $this->_transaction->payment_method();
736
-
737
-        $this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
738
-            ? $payment_method->admin_name()
739
-            : esc_html__('Unknown', 'event_espresso');
740
-
741
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
742
-        // link back to overview
743
-        $this->_template_args['txn_overview_url'] = ! empty($_SERVER['HTTP_REFERER'])
744
-            ? $_SERVER['HTTP_REFERER']
745
-            : TXN_ADMIN_URL;
746
-
747
-
748
-        // next link
749
-        $next_txn                                 = $this->_transaction->next(
750
-            null,
751
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
752
-            'TXN_ID'
753
-        );
754
-        $this->_template_args['next_transaction'] = $next_txn
755
-            ? $this->_next_link(
756
-                EE_Admin_Page::add_query_args_and_nonce(
757
-                    array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
758
-                    TXN_ADMIN_URL
759
-                ),
760
-                'dashicons dashicons-arrow-right ee-icon-size-22'
761
-            )
762
-            : '';
763
-        // previous link
764
-        $previous_txn                                 = $this->_transaction->previous(
765
-            null,
766
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
767
-            'TXN_ID'
768
-        );
769
-        $this->_template_args['previous_transaction'] = $previous_txn
770
-            ? $this->_previous_link(
771
-                EE_Admin_Page::add_query_args_and_nonce(
772
-                    array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
773
-                    TXN_ADMIN_URL
774
-                ),
775
-                'dashicons dashicons-arrow-left ee-icon-size-22'
776
-            )
777
-            : '';
778
-
779
-        // were we just redirected here after adding a new registration ???
780
-        if (isset(
781
-            $this->_req_data['redirect_from'],
782
-            $this->_req_data['EVT_ID'],
783
-            $this->_req_data['event_name']
784
-        )) {
785
-            if (EE_Registry::instance()->CAP->current_user_can(
786
-                'ee_edit_registrations',
787
-                'espresso_registrations_new_registration',
788
-                $this->_req_data['EVT_ID']
789
-            )) {
790
-                $this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
791
-                $this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
792
-                    array(
793
-                        'page'     => 'espresso_registrations',
794
-                        'action'   => 'new_registration',
795
-                        'return'   => 'default',
796
-                        'TXN_ID'   => $this->_transaction->ID(),
797
-                        'event_id' => $this->_req_data['EVT_ID'],
798
-                    ),
799
-                    REG_ADMIN_URL
800
-                );
801
-                $this->_admin_page_title .= '">';
802
-
803
-                $this->_admin_page_title .= sprintf(
804
-                    esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
805
-                    htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
806
-                );
807
-                $this->_admin_page_title .= '</a>';
808
-            }
809
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
810
-        }
811
-        // grab messages at the last second
812
-        $this->_template_args['notices'] = EE_Error::get_notices();
813
-        // path to template
814
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
815
-        $this->_template_args['admin_page_header'] = EEH_Template::display_template(
816
-            $template_path,
817
-            $this->_template_args,
818
-            true
819
-        );
820
-
821
-        // the details template wrapper
822
-        $this->display_admin_page_with_sidebar();
823
-
824
-    }
825
-
826
-
827
-    /**
828
-     *        _transaction_details_metaboxes
829
-     *
830
-     * @access protected
831
-     * @return void
832
-     * @throws EE_Error
833
-     * @throws InvalidArgumentException
834
-     * @throws InvalidDataTypeException
835
-     * @throws InvalidInterfaceException
836
-     * @throws RuntimeException
837
-     * @throws ReflectionException
838
-     */
839
-    protected function _transaction_details_metaboxes()
840
-    {
841
-
842
-        $this->_set_transaction_object();
843
-
844
-        add_meta_box(
845
-            'edit-txn-details-mbox',
846
-            esc_html__('Transaction Details', 'event_espresso'),
847
-            array($this, 'txn_details_meta_box'),
848
-            $this->_wp_page_slug,
849
-            'normal',
850
-            'high'
851
-        );
852
-        add_meta_box(
853
-            'edit-txn-attendees-mbox',
854
-            esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
855
-            array($this, 'txn_attendees_meta_box'),
856
-            $this->_wp_page_slug,
857
-            'normal',
858
-            'high',
859
-            array('TXN_ID' => $this->_transaction->ID())
860
-        );
861
-        add_meta_box(
862
-            'edit-txn-registrant-mbox',
863
-            esc_html__('Primary Contact', 'event_espresso'),
864
-            array($this, 'txn_registrant_side_meta_box'),
865
-            $this->_wp_page_slug,
866
-            'side',
867
-            'high'
868
-        );
869
-        add_meta_box(
870
-            'edit-txn-billing-info-mbox',
871
-            esc_html__('Billing Information', 'event_espresso'),
872
-            array($this, 'txn_billing_info_side_meta_box'),
873
-            $this->_wp_page_slug,
874
-            'side',
875
-            'high'
876
-        );
877
-    }
878
-
879
-
880
-    /**
881
-     * Callback for transaction actions metabox.
882
-     *
883
-     * @param EE_Transaction|null $transaction
884
-     * @throws DomainException
885
-     * @throws EE_Error
886
-     * @throws InvalidArgumentException
887
-     * @throws InvalidDataTypeException
888
-     * @throws InvalidInterfaceException
889
-     * @throws ReflectionException
890
-     * @throws RuntimeException
891
-     */
892
-    public function getActionButtons(EE_Transaction $transaction = null)
893
-    {
894
-        $content = '';
895
-        $actions = array();
896
-        if (! $transaction instanceof EE_Transaction) {
897
-            return $content;
898
-        }
899
-        /** @var EE_Registration $primary_registration */
900
-        $primary_registration = $transaction->primary_registration();
901
-        $attendee = $primary_registration instanceof EE_Registration
902
-            ? $primary_registration->attendee()
903
-            : null;
904
-
905
-        if ($attendee instanceof EE_Attendee
906
-            && EE_Registry::instance()->CAP->current_user_can(
907
-                'ee_send_message',
908
-                'espresso_transactions_send_payment_reminder'
909
-            )
910
-        ) {
911
-            $actions['payment_reminder'] =
912
-                EEH_MSG_Template::is_mt_active('payment_reminder')
913
-                && $this->_transaction->get('STS_ID') !== EEM_Transaction::complete_status_code
914
-                && $this->_transaction->get('STS_ID') !== EEM_Transaction::overpaid_status_code
915
-                    ? EEH_Template::get_button_or_link(
916
-                        EE_Admin_Page::add_query_args_and_nonce(
917
-                            array(
918
-                                'action'      => 'send_payment_reminder',
919
-                                'TXN_ID'      => $this->_transaction->ID(),
920
-                                'redirect_to' => 'view_transaction',
921
-                            ),
922
-                            TXN_ADMIN_URL
923
-                        ),
924
-                        esc_html__(' Send Payment Reminder', 'event_espresso'),
925
-                        'button secondary-button',
926
-                        'dashicons dashicons-email-alt'
927
-                    )
928
-                    : '';
929
-        }
930
-
931
-        if ($primary_registration instanceof EE_Registration
932
-            && EEH_MSG_Template::is_mt_active('receipt')
933
-        ) {
934
-            $actions['receipt'] = EEH_Template::get_button_or_link(
935
-                $primary_registration->receipt_url(),
936
-                esc_html__('View Receipt', 'event_espresso'),
937
-                'button secondary-button',
938
-                'dashicons dashicons-media-default'
939
-            );
940
-        }
941
-
942
-        if ($primary_registration instanceof EE_Registration
943
-            && EEH_MSG_Template::is_mt_active('invoice')
944
-        ) {
945
-            $actions['invoice'] = EEH_Template::get_button_or_link(
946
-                $primary_registration->invoice_url(),
947
-                esc_html__('View Invoice', 'event_espresso'),
948
-                'button secondary-button',
949
-                'dashicons dashicons-media-spreadsheet'
950
-            );
951
-        }
952
-        $actions = array_filter(
953
-            apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
954
-        );
955
-        if ($actions) {
956
-            $content = '<ul>';
957
-            $content .= '<li>' . implode('</li><li>', $actions) . '</li>';
958
-            $content .= '</uL>';
959
-        }
960
-        return $content;
961
-    }
962
-
963
-
964
-    /**
965
-     * txn_details_meta_box
966
-     * generates HTML for the Transaction main meta box
967
-     *
968
-     * @return void
969
-     * @throws DomainException
970
-     * @throws EE_Error
971
-     * @throws InvalidArgumentException
972
-     * @throws InvalidDataTypeException
973
-     * @throws InvalidInterfaceException
974
-     * @throws RuntimeException
975
-     * @throws ReflectionException
976
-     */
977
-    public function txn_details_meta_box()
978
-    {
979
-        $this->_set_transaction_object();
980
-        $this->_template_args['TXN_ID']   = $this->_transaction->ID();
981
-        $this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration
982
-            ? $this->_transaction->primary_registration()->attendee()
983
-            : null;
984
-        $this->_template_args['can_edit_payments'] = EE_Registry::instance()->CAP->current_user_can(
985
-            'ee_edit_payments',
986
-            'apply_payment_or_refund_from_registration_details'
987
-        );
988
-        $this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
989
-            'ee_delete_payments',
990
-            'delete_payment_from_registration_details'
991
-        );
992
-
993
-        //get line table
994
-        EEH_Autoloader::register_line_item_display_autoloaders();
995
-        $Line_Item_Display                       = new EE_Line_Item_Display(
996
-            'admin_table',
997
-            'EE_Admin_Table_Line_Item_Display_Strategy'
998
-        );
999
-        $this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1000
-            $this->_transaction->total_line_item()
1001
-        );
1002
-        $this->_template_args['REG_code']        = $this->_transaction->get_first_related('Registration')
1003
-                                                                      ->get('REG_code');
1004
-
1005
-        // process taxes
1006
-        $taxes                         = $this->_transaction->get_many_related(
1007
-            'Line_Item',
1008
-            array(array('LIN_type' => EEM_Line_Item::type_tax))
1009
-        );
1010
-        $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1011
-
1012
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1013
-            $this->_transaction->get('TXN_total'),
1014
-            false,
1015
-            false
1016
-        );
1017
-        $this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
1018
-        $this->_template_args['TXN_status']      = $this->_transaction->get('STS_ID');
1019
-
1020
-        // process payment details
1021
-        $payments = $this->_transaction->get_many_related('Payment');
1022
-        if (! empty($payments)) {
1023
-            $this->_template_args['payments']              = $payments;
1024
-            $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1025
-        } else {
1026
-            $this->_template_args['payments']              = false;
1027
-            $this->_template_args['existing_reg_payments'] = array();
1028
-        }
1029
-
1030
-        $this->_template_args['edit_payment_url']   = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
1031
-        $this->_template_args['delete_payment_url'] = add_query_arg(
1032
-            array('action' => 'espresso_delete_payment'),
1033
-            TXN_ADMIN_URL
1034
-        );
1035
-
1036
-        if (isset($txn_details['invoice_number'])) {
1037
-            $this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1038
-            $this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1039
-                'Invoice Number',
1040
-                'event_espresso'
1041
-            );
1042
-        }
1043
-
1044
-        $this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction
1045
-            ->get_first_related('Registration')
1046
-            ->get('REG_session');
1047
-        $this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1048
-            'Registration Session',
1049
-            'event_espresso'
1050
-        );
1051
-
1052
-        $this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address'])
1053
-            ? $this->_session['ip_address']
1054
-            : '';
1055
-        $this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1056
-            'Transaction placed from IP',
1057
-            'event_espresso'
1058
-        );
1059
-
1060
-        $this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent'])
1061
-            ? $this->_session['user_agent']
1062
-            : '';
1063
-        $this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1064
-            'Registrant User Agent',
1065
-            'event_espresso'
1066
-        );
1067
-
1068
-        $reg_steps = '<ul>';
1069
-        foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1070
-            if ($reg_step_status === true) {
1071
-                $reg_steps .= '<li style="color:#70cc50">'
1072
-                              . sprintf(
1073
-                                  esc_html__('%1$s : Completed', 'event_espresso'),
1074
-                                  ucwords(str_replace('_', ' ', $reg_step))
1075
-                              )
1076
-                              . '</li>';
1077
-            } elseif (is_numeric($reg_step_status) && $reg_step_status !== false) {
1078
-                $reg_steps .= '<li style="color:#2EA2CC">'
1079
-                              . sprintf(
1080
-                                  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1081
-                                  ucwords(str_replace('_', ' ', $reg_step)),
1082
-                                  date(
1083
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1084
-                                      ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1085
-                                  )
1086
-                              )
1087
-                              . '</li>';
1088
-            } else {
1089
-                $reg_steps .= '<li style="color:#E76700">'
1090
-                              . sprintf(
1091
-                                  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1092
-                                  ucwords(str_replace('_', ' ', $reg_step))
1093
-                              )
1094
-                              . '</li>';
1095
-            }
1096
-        }
1097
-        $reg_steps                                                 .= '</ul>';
1098
-        $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1099
-        $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1100
-            'Registration Step Progress',
1101
-            'event_espresso'
1102
-        );
1103
-
1104
-
1105
-        $this->_get_registrations_to_apply_payment_to();
1106
-        $this->_get_payment_methods($payments);
1107
-        $this->_get_payment_status_array();
1108
-        $this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
1109
-
1110
-        $this->_template_args['transaction_form_url']    = add_query_arg(array(
1111
-            'action'  => 'edit_transaction',
1112
-            'process' => 'transaction',
1113
-        ), TXN_ADMIN_URL);
1114
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(array(
1115
-            'page'   => 'espresso_transactions',
1116
-            'action' => 'espresso_apply_payment',
1117
-        ), WP_AJAX_URL);
1118
-        $this->_template_args['delete_payment_form_url'] = add_query_arg(array(
1119
-            'page'   => 'espresso_transactions',
1120
-            'action' => 'espresso_delete_payment',
1121
-        ), WP_AJAX_URL);
1122
-
1123
-        $this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1124
-
1125
-        // 'espresso_delete_payment_nonce'
1126
-
1127
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1128
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1129
-    }
1130
-
1131
-
1132
-    /**
1133
-     * _get_registration_payment_IDs
1134
-     *    generates an array of Payment IDs and their corresponding Registration IDs
1135
-     *
1136
-     * @access protected
1137
-     * @param EE_Payment[] $payments
1138
-     * @return array
1139
-     * @throws EE_Error
1140
-     * @throws InvalidArgumentException
1141
-     * @throws InvalidDataTypeException
1142
-     * @throws InvalidInterfaceException
1143
-     * @throws ReflectionException
1144
-     */
1145
-    protected function _get_registration_payment_IDs($payments = array())
1146
-    {
1147
-        $existing_reg_payments = array();
1148
-        // get all reg payments for these payments
1149
-        $reg_payments = EEM_Registration_Payment::instance()->get_all(array(
1150
-            array(
1151
-                'PAY_ID' => array(
1152
-                    'IN',
1153
-                    array_keys($payments),
1154
-                ),
1155
-            ),
1156
-        ));
1157
-        if (! empty($reg_payments)) {
1158
-            foreach ($payments as $payment) {
1159
-                if (! $payment instanceof EE_Payment) {
1160
-                    continue;
1161
-                } elseif (! isset($existing_reg_payments[$payment->ID()])) {
1162
-                    $existing_reg_payments[$payment->ID()] = array();
1163
-                }
1164
-                foreach ($reg_payments as $reg_payment) {
1165
-                    if ($reg_payment instanceof EE_Registration_Payment
1166
-                        && $reg_payment->payment_ID() === $payment->ID()
1167
-                    ) {
1168
-                        $existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
1169
-                    }
1170
-                }
1171
-            }
1172
-        }
1173
-
1174
-        return $existing_reg_payments;
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * _get_registrations_to_apply_payment_to
1180
-     *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1181
-     * which allows the admin to only apply the payment to the specific registrations
1182
-     *
1183
-     * @access protected
1184
-     * @return void
1185
-     * @throws \EE_Error
1186
-     */
1187
-    protected function _get_registrations_to_apply_payment_to()
1188
-    {
1189
-        // we want any registration with an active status (ie: not deleted or cancelled)
1190
-        $query_params                      = array(
1191
-            array(
1192
-                'STS_ID' => array(
1193
-                    'IN',
1194
-                    array(
1195
-                        EEM_Registration::status_id_approved,
1196
-                        EEM_Registration::status_id_pending_payment,
1197
-                        EEM_Registration::status_id_not_approved,
1198
-                    ),
1199
-                ),
1200
-            ),
1201
-        );
1202
-        $registrations_to_apply_payment_to = EEH_HTML::br()
1203
-                                             . EEH_HTML::div(
1204
-                                                 '',
1205
-                                                 'txn-admin-apply-payment-to-registrations-dv',
1206
-                                                 '',
1207
-                                                 'clear: both; margin: 1.5em 0 0; display: none;'
1208
-                                             );
1209
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1210
-        $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1211
-        $registrations_to_apply_payment_to .= EEH_HTML::thead(
1212
-            EEH_HTML::tr(
1213
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1214
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1215
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1216
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1217
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1218
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1219
-                EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1220
-            )
1221
-        );
1222
-        $registrations_to_apply_payment_to .= EEH_HTML::tbody();
1223
-        // get registrations for TXN
1224
-        $registrations = $this->_transaction->registrations($query_params);
1225
-        $existing_reg_payments = $this->_template_args['existing_reg_payments'];
1226
-        foreach ($registrations as $registration) {
1227
-            if ($registration instanceof EE_Registration) {
1228
-                $attendee_name                     = $registration->attendee() instanceof EE_Attendee
1229
-                    ? $registration->attendee()->full_name()
1230
-                    : esc_html__('Unknown Attendee', 'event_espresso');
1231
-                $owing                             = $registration->final_price() - $registration->paid();
1232
-                $taxable                           = $registration->ticket()->taxable()
1233
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1234
-                    : '';
1235
-                $checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1236
-                    ? ' checked="checked"'
1237
-                    : '';
1238
-                $disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1239
-                $registrations_to_apply_payment_to .= EEH_HTML::tr(
1240
-                    EEH_HTML::td($registration->ID()) .
1241
-                    EEH_HTML::td($attendee_name) .
1242
-                    EEH_HTML::td(
1243
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1244
-                    ) .
1245
-                    EEH_HTML::td($registration->event_name()) .
1246
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1247
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1248
-                    EEH_HTML::td(
1249
-                        '<input type="checkbox" value="' . $registration->ID()
1250
-                        . '" name="txn_admin_payment[registrations]"'
1251
-                        . $checked . $disabled . '>',
1252
-                        '',
1253
-                        'jst-cntr'
1254
-                    ),
1255
-                    'apply-payment-registration-row-' . $registration->ID()
1256
-                );
1257
-            }
1258
-        }
1259
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1260
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1261
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1262
-        $registrations_to_apply_payment_to                         .= EEH_HTML::p(
1263
-            esc_html__(
1264
-                'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1265
-                'event_espresso'
1266
-            ),
1267
-            '',
1268
-            'clear description'
1269
-        );
1270
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1271
-        $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * _get_reg_status_selection
1277
-     *
1278
-     * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1279
-     *         instead of events.
1280
-     * @access protected
1281
-     * @return void
1282
-     * @throws EE_Error
1283
-     */
1284
-    protected function _get_reg_status_selection()
1285
-    {
1286
-        //first get all possible statuses
1287
-        $statuses = EEM_Registration::reg_status_array(array(), true);
1288
-        //let's add a "don't change" option.
1289
-        $status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1290
-        $status_array                                        = array_merge($status_array, $statuses);
1291
-        $this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1292
-            'txn_reg_status_change[reg_status]',
1293
-            $status_array,
1294
-            'NAN',
1295
-            'id="txn-admin-payment-reg-status-inp"',
1296
-            'txn-reg-status-change-reg-status'
1297
-        );
1298
-        $this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1299
-            'delete_txn_reg_status_change[reg_status]',
1300
-            $status_array,
1301
-            'NAN',
1302
-            'delete-txn-admin-payment-reg-status-inp',
1303
-            'delete-txn-reg-status-change-reg-status'
1304
-        );
1305
-    }
1306
-
1307
-
1308
-    /**
1309
-     *    _get_payment_methods
1310
-     * Gets all the payment methods available generally, or the ones that are already
1311
-     * selected on these payments (in case their payment methods are no longer active).
1312
-     * Has the side-effect of updating the template args' payment_methods item
1313
-     *
1314
-     * @access private
1315
-     * @param EE_Payment[] to show on this page
1316
-     * @return void
1317
-     * @throws EE_Error
1318
-     * @throws InvalidArgumentException
1319
-     * @throws InvalidDataTypeException
1320
-     * @throws InvalidInterfaceException
1321
-     * @throws ReflectionException
1322
-     */
1323
-    private function _get_payment_methods($payments = array())
1324
-    {
1325
-        $payment_methods_of_payments = array();
1326
-        foreach ($payments as $payment) {
1327
-            if ($payment instanceof EE_Payment) {
1328
-                $payment_methods_of_payments[] = $payment->get('PMD_ID');
1329
-            }
1330
-        }
1331
-        if ($payment_methods_of_payments) {
1332
-            $query_args = array(
1333
-                array(
1334
-                    'OR*payment_method_for_payment' => array(
1335
-                        'PMD_ID'    => array('IN', $payment_methods_of_payments),
1336
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1337
-                    ),
1338
-                ),
1339
-            );
1340
-        } else {
1341
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1342
-        }
1343
-        $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1344
-    }
1345
-
1346
-
1347
-    /**
1348
-     * txn_attendees_meta_box
1349
-     *    generates HTML for the Attendees Transaction main meta box
1350
-     *
1351
-     * @access public
1352
-     * @param WP_Post $post
1353
-     * @param array   $metabox
1354
-     * @return void
1355
-     * @throws DomainException
1356
-     * @throws EE_Error
1357
-     */
1358
-    public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1359
-    {
1360
-
1361
-        /** @noinspection NonSecureExtractUsageInspection */
1362
-        extract($metabox['args']);
1363
-        $this->_template_args['post']            = $post;
1364
-        $this->_template_args['event_attendees'] = array();
1365
-        // process items in cart
1366
-        $line_items = $this->_transaction->get_many_related(
1367
-            'Line_Item',
1368
-            array(array('LIN_type' => 'line-item'))
1369
-        );
1370
-        if (! empty($line_items)) {
1371
-            foreach ($line_items as $item) {
1372
-                if ($item instanceof EE_Line_Item) {
1373
-                    switch ($item->OBJ_type()) {
1374
-                        case 'Event':
1375
-                            break;
1376
-                        case 'Ticket':
1377
-                            $ticket = $item->ticket();
1378
-                            //right now we're only handling tickets here.
1379
-                            //Cause its expected that only tickets will have attendees right?
1380
-                            if (! $ticket instanceof EE_Ticket) {
1381
-                                continue;
1382
-                            }
1383
-                            try {
1384
-                                $event_name = $ticket->get_event_name();
1385
-                            } catch (Exception $e) {
1386
-                                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1387
-                                $event_name = esc_html__('Unknown Event', 'event_espresso');
1388
-                            }
1389
-                            $event_name   .= ' - ' . $item->get('LIN_name');
1390
-                            $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1391
-                            // now get all of the registrations for this transaction that use this ticket
1392
-                            $registrations = $ticket->get_many_related(
1393
-                                'Registration',
1394
-                                array(array('TXN_ID' => $this->_transaction->ID()))
1395
-                            );
1396
-                            foreach ($registrations as $registration) {
1397
-                                if (! $registration instanceof EE_Registration) {
1398
-                                    continue;
1399
-                                }
1400
-                                $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
1401
-                                    = $registration->status_ID();
1402
-                                $this->_template_args['event_attendees'][$registration->ID()]['att_num']
1403
-                                    = $registration->count();
1404
-                                $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name']
1405
-                                    = $event_name;
1406
-                                $this->_template_args['event_attendees'][$registration->ID()]['ticket_price']
1407
-                                    = $ticket_price;
1408
-                                // attendee info
1409
-                                $attendee = $registration->get_first_related('Attendee');
1410
-                                if ($attendee instanceof EE_Attendee) {
1411
-                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']
1412
-                                        = $attendee->ID();
1413
-                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee']
1414
-                                        = $attendee->full_name();
1415
-                                    $this->_template_args['event_attendees'][$registration->ID()]['email']
1416
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1417
-                                          . esc_html__(
1418
-                                              ' Event',
1419
-                                              'event_espresso'
1420
-                                          )
1421
-                                          . '">' . $attendee->email() . '</a>';
1422
-                                    $this->_template_args['event_attendees'][$registration->ID()]['address']
1423
-                                        = EEH_Address::format($attendee, 'inline', false, false);
1424
-                                } else {
1425
-                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1426
-                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1427
-                                    $this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1428
-                                    $this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1429
-                                }
1430
-                            }
1431
-                            break;
1432
-
1433
-                    }
1434
-                }
1435
-            }
1436
-
1437
-            $this->_template_args['transaction_form_url'] = add_query_arg(
1438
-                array(
1439
-                    'action'  => 'edit_transaction',
1440
-                    'process' => 'attendees',
1441
-                ),
1442
-                TXN_ADMIN_URL
1443
-            );
1444
-            echo EEH_Template::display_template(
1445
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1446
-                $this->_template_args,
1447
-                true
1448
-            );
1449
-
1450
-        } else {
1451
-            echo sprintf(
1452
-                esc_html__(
1453
-                    '%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1454
-                    'event_espresso'
1455
-                ),
1456
-                '<p class="important-notice">',
1457
-                '</p>'
1458
-            );
1459
-        }
1460
-    }
1461
-
1462
-
1463
-    /**
1464
-     * txn_registrant_side_meta_box
1465
-     * generates HTML for the Edit Transaction side meta box
1466
-     *
1467
-     * @access public
1468
-     * @return void
1469
-     * @throws DomainException
1470
-     * @throws EE_Error
1471
-     * @throws InvalidArgumentException
1472
-     * @throws InvalidDataTypeException
1473
-     * @throws InvalidInterfaceException
1474
-     * @throws ReflectionException
1475
-     */
1476
-    public function txn_registrant_side_meta_box()
1477
-    {
1478
-        $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1479
-            ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1480
-            : null;
1481
-        if (! $primary_att instanceof EE_Attendee) {
1482
-            $this->_template_args['no_attendee_message'] = esc_html__(
1483
-                'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1484
-                'event_espresso'
1485
-            );
1486
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1487
-        }
1488
-        $this->_template_args['ATT_ID']            = $primary_att->ID();
1489
-        $this->_template_args['prime_reg_fname']   = $primary_att->fname();
1490
-        $this->_template_args['prime_reg_lname']   = $primary_att->lname();
1491
-        $this->_template_args['prime_reg_email']   = $primary_att->email();
1492
-        $this->_template_args['prime_reg_phone']   = $primary_att->phone();
1493
-        $this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(array(
1494
-            'action' => 'edit_attendee',
1495
-            'post'   => $primary_att->ID(),
1496
-        ), REG_ADMIN_URL);
1497
-        // get formatted address for registrant
1498
-        $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1499
-        echo EEH_Template::display_template(
1500
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1501
-            $this->_template_args,
1502
-            true
1503
-        );
1504
-    }
1505
-
1506
-
1507
-    /**
1508
-     * txn_billing_info_side_meta_box
1509
-     *    generates HTML for the Edit Transaction side meta box
1510
-     *
1511
-     * @access public
1512
-     * @return void
1513
-     * @throws DomainException
1514
-     * @throws EE_Error
1515
-     */
1516
-    public function txn_billing_info_side_meta_box()
1517
-    {
1518
-
1519
-        $this->_template_args['billing_form']     = $this->_transaction->billing_info();
1520
-        $this->_template_args['billing_form_url'] = add_query_arg(
1521
-            array('action' => 'edit_transaction', 'process' => 'billing'),
1522
-            TXN_ADMIN_URL
1523
-        );
1524
-
1525
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1526
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1527
-    }
1528
-
1529
-
1530
-    /**
1531
-     * apply_payments_or_refunds
1532
-     *    registers a payment or refund made towards a transaction
1533
-     *
1534
-     * @access public
1535
-     * @return void
1536
-     * @throws EE_Error
1537
-     * @throws InvalidArgumentException
1538
-     * @throws ReflectionException
1539
-     * @throws RuntimeException
1540
-     * @throws InvalidDataTypeException
1541
-     * @throws InvalidInterfaceException
1542
-     */
1543
-    public function apply_payments_or_refunds()
1544
-    {
1545
-        $json_response_data = array('return_data' => false);
1546
-        $valid_data         = $this->_validate_payment_request_data();
1547
-        $has_access = EE_Registry::instance()->CAP->current_user_can(
1548
-            'ee_edit_payments',
1549
-            'apply_payment_or_refund_from_registration_details'
1550
-        );
1551
-        if (! empty($valid_data) && $has_access) {
1552
-            $PAY_ID = $valid_data['PAY_ID'];
1553
-            //save  the new payment
1554
-            $payment = $this->_create_payment_from_request_data($valid_data);
1555
-            // get the TXN for this payment
1556
-            $transaction = $payment->transaction();
1557
-            // verify transaction
1558
-            if ($transaction instanceof EE_Transaction) {
1559
-                // calculate_total_payments_and_update_status
1560
-                $this->_process_transaction_payments($transaction);
1561
-                $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1562
-                $this->_remove_existing_registration_payments($payment, $PAY_ID);
1563
-                // apply payment to registrations (if applicable)
1564
-                if (! empty($REG_IDs)) {
1565
-                    $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1566
-                    $this->_maybe_send_notifications();
1567
-                    // now process status changes for the same registrations
1568
-                    $this->_process_registration_status_change($transaction, $REG_IDs);
1569
-                }
1570
-                $this->_maybe_send_notifications($payment);
1571
-                //prepare to render page
1572
-                $json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1573
-                do_action(
1574
-                    'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1575
-                    $transaction,
1576
-                    $payment
1577
-                );
1578
-            } else {
1579
-                EE_Error::add_error(
1580
-                    esc_html__(
1581
-                        'A valid Transaction for this payment could not be retrieved.',
1582
-                        'event_espresso'
1583
-                    ),
1584
-                    __FILE__,
1585
-                    __FUNCTION__,
1586
-                    __LINE__
1587
-                );
1588
-            }
1589
-        } else {
1590
-            if ($has_access) {
1591
-                EE_Error::add_error(
1592
-                    esc_html__(
1593
-                        'The payment form data could not be processed. Please try again.',
1594
-                        'event_espresso'
1595
-                    ),
1596
-                    __FILE__,
1597
-                    __FUNCTION__,
1598
-                    __LINE__
1599
-                );
1600
-            } else {
1601
-                EE_Error::add_error(
1602
-                    esc_html__(
1603
-                        'You do not have access to apply payments or refunds to a registration.',
1604
-                        'event_espresso'
1605
-                    ),
1606
-                    __FILE__,
1607
-                    __FUNCTION__,
1608
-                    __LINE__
1609
-                );
1610
-            }
1611
-        }
1612
-        $notices              = EE_Error::get_notices(
1613
-            false,
1614
-            false,
1615
-            false
1616
-        );
1617
-        $this->_template_args = array(
1618
-            'data'    => $json_response_data,
1619
-            'error'   => $notices['errors'],
1620
-            'success' => $notices['success'],
1621
-        );
1622
-        $this->_return_json();
1623
-    }
1624
-
1625
-
1626
-    /**
1627
-     * _validate_payment_request_data
1628
-     *
1629
-     * @return array
1630
-     * @throws EE_Error
1631
-     */
1632
-    protected function _validate_payment_request_data()
1633
-    {
1634
-        if (! isset($this->_req_data['txn_admin_payment'])) {
1635
-            return false;
1636
-        }
1637
-        $payment_form = $this->_generate_payment_form_section();
1638
-        try {
1639
-            if ($payment_form->was_submitted()) {
1640
-                $payment_form->receive_form_submission();
1641
-                if (! $payment_form->is_valid()) {
1642
-                    $submission_error_messages = array();
1643
-                    foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1644
-                        if ($validation_error instanceof EE_Validation_Error) {
1645
-                            $submission_error_messages[] = sprintf(
1646
-                                _x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1647
-                                $validation_error->get_form_section()->html_label_text(),
1648
-                                $validation_error->getMessage()
1649
-                            );
1650
-                        }
1651
-                    }
1652
-                    EE_Error::add_error(
1653
-                        implode('<br />', $submission_error_messages),
1654
-                        __FILE__,
1655
-                        __FUNCTION__,
1656
-                        __LINE__
1657
-                    );
1658
-
1659
-                    return array();
1660
-                }
1661
-            }
1662
-        } catch (EE_Error $e) {
1663
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1664
-
1665
-            return array();
1666
-        }
1667
-
1668
-        return $payment_form->valid_data();
1669
-    }
1670
-
1671
-
1672
-    /**
1673
-     * _generate_payment_form_section
1674
-     *
1675
-     * @return EE_Form_Section_Proper
1676
-     * @throws EE_Error
1677
-     */
1678
-    protected function _generate_payment_form_section()
1679
-    {
1680
-        return new EE_Form_Section_Proper(
1681
-            array(
1682
-                'name'        => 'txn_admin_payment',
1683
-                'subsections' => array(
1684
-                    'PAY_ID'          => new EE_Text_Input(
1685
-                        array(
1686
-                            'default'               => 0,
1687
-                            'required'              => false,
1688
-                            'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1689
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1690
-                        )
1691
-                    ),
1692
-                    'TXN_ID'          => new EE_Text_Input(
1693
-                        array(
1694
-                            'default'               => 0,
1695
-                            'required'              => true,
1696
-                            'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1697
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1698
-                        )
1699
-                    ),
1700
-                    'type'            => new EE_Text_Input(
1701
-                        array(
1702
-                            'default'               => 1,
1703
-                            'required'              => true,
1704
-                            'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1705
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1706
-                        )
1707
-                    ),
1708
-                    'amount'          => new EE_Text_Input(
1709
-                        array(
1710
-                            'default'               => 0,
1711
-                            'required'              => true,
1712
-                            'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1713
-                            'validation_strategies' => array(new EE_Float_Normalization()),
1714
-                        )
1715
-                    ),
1716
-                    'status'          => new EE_Text_Input(
1717
-                        array(
1718
-                            'default'         => EEM_Payment::status_id_approved,
1719
-                            'required'        => true,
1720
-                            'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1721
-                        )
1722
-                    ),
1723
-                    'PMD_ID'          => new EE_Text_Input(
1724
-                        array(
1725
-                            'default'               => 2,
1726
-                            'required'              => true,
1727
-                            'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1728
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1729
-                        )
1730
-                    ),
1731
-                    'date'            => new EE_Text_Input(
1732
-                        array(
1733
-                            'default'         => time(),
1734
-                            'required'        => true,
1735
-                            'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1736
-                        )
1737
-                    ),
1738
-                    'txn_id_chq_nmbr' => new EE_Text_Input(
1739
-                        array(
1740
-                            'default'               => '',
1741
-                            'required'              => false,
1742
-                            'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1743
-                            'validation_strategies' => array(
1744
-                                new EE_Max_Length_Validation_Strategy(
1745
-                                    esc_html__('Input too long', 'event_espresso'),
1746
-                                    100
1747
-                                ),
1748
-                            ),
1749
-                        )
1750
-                    ),
1751
-                    'po_number'       => new EE_Text_Input(
1752
-                        array(
1753
-                            'default'               => '',
1754
-                            'required'              => false,
1755
-                            'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1756
-                            'validation_strategies' => array(
1757
-                                new EE_Max_Length_Validation_Strategy(
1758
-                                    esc_html__('Input too long', 'event_espresso'),
1759
-                                    100
1760
-                                ),
1761
-                            ),
1762
-                        )
1763
-                    ),
1764
-                    'accounting'      => new EE_Text_Input(
1765
-                        array(
1766
-                            'default'               => '',
1767
-                            'required'              => false,
1768
-                            'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1769
-                            'validation_strategies' => array(
1770
-                                new EE_Max_Length_Validation_Strategy(
1771
-                                    esc_html__('Input too long', 'event_espresso'),
1772
-                                    100
1773
-                                ),
1774
-                            ),
1775
-                        )
1776
-                    ),
1777
-                ),
1778
-            )
1779
-        );
1780
-    }
1781
-
1782
-
1783
-    /**
1784
-     * _create_payment_from_request_data
1785
-     *
1786
-     * @param array $valid_data
1787
-     * @return EE_Payment
1788
-     * @throws EE_Error
1789
-     */
1790
-    protected function _create_payment_from_request_data($valid_data)
1791
-    {
1792
-        $PAY_ID = $valid_data['PAY_ID'];
1793
-        // get payment amount
1794
-        $amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1795
-        // payments have a type value of 1 and refunds have a type value of -1
1796
-        // so multiplying amount by type will give a positive value for payments, and negative values for refunds
1797
-        $amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1798
-        // for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1799
-        $date    = $valid_data['date']
1800
-            ? preg_replace('/\s+/', ' ', $valid_data['date'])
1801
-            : date('Y-m-d g:i a', current_time('timestamp'));
1802
-        $payment = EE_Payment::new_instance(
1803
-            array(
1804
-                'TXN_ID'              => $valid_data['TXN_ID'],
1805
-                'STS_ID'              => $valid_data['status'],
1806
-                'PAY_timestamp'       => $date,
1807
-                'PAY_source'          => EEM_Payment_Method::scope_admin,
1808
-                'PMD_ID'              => $valid_data['PMD_ID'],
1809
-                'PAY_amount'          => $amount,
1810
-                'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1811
-                'PAY_po_number'       => $valid_data['po_number'],
1812
-                'PAY_extra_accntng'   => $valid_data['accounting'],
1813
-                'PAY_details'         => $valid_data,
1814
-                'PAY_ID'              => $PAY_ID,
1815
-            ),
1816
-            '',
1817
-            array('Y-m-d', 'g:i a')
1818
-        );
1819
-
1820
-        if (! $payment->save()) {
1821
-            EE_Error::add_error(
1822
-                sprintf(
1823
-                    esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1824
-                    $payment->ID()
1825
-                ),
1826
-                __FILE__, __FUNCTION__, __LINE__
1827
-            );
1828
-        }
1829
-
1830
-        return $payment;
1831
-    }
1832
-
1833
-
1834
-    /**
1835
-     * _process_transaction_payments
1836
-     *
1837
-     * @param \EE_Transaction $transaction
1838
-     * @return void
1839
-     * @throws EE_Error
1840
-     * @throws InvalidArgumentException
1841
-     * @throws ReflectionException
1842
-     * @throws InvalidDataTypeException
1843
-     * @throws InvalidInterfaceException
1844
-     */
1845
-    protected function _process_transaction_payments(EE_Transaction $transaction)
1846
-    {
1847
-        /** @type EE_Transaction_Payments $transaction_payments */
1848
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1849
-        //update the transaction with this payment
1850
-        if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1851
-            EE_Error::add_success(esc_html__(
1852
-                'The payment has been processed successfully.', 'event_espresso'),
1853
-                __FILE__,
1854
-                __FUNCTION__,
1855
-                __LINE__
1856
-            );
1857
-        } else {
1858
-            EE_Error::add_error(
1859
-                esc_html__(
1860
-                    'The payment was processed successfully but the amount paid for the transaction was not updated.',
1861
-                    'event_espresso'
1862
-                )
1863
-                ,
1864
-                __FILE__,
1865
-                __FUNCTION__,
1866
-                __LINE__
1867
-            );
1868
-        }
1869
-    }
1870
-
1871
-
1872
-    /**
1873
-     * _get_REG_IDs_to_apply_payment_to
1874
-     * returns a list of registration IDs that the payment will apply to
1875
-     *
1876
-     * @param \EE_Payment $payment
1877
-     * @return array
1878
-     * @throws EE_Error
1879
-     */
1880
-    protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1881
-    {
1882
-        $REG_IDs = array();
1883
-        // grab array of IDs for specific registrations to apply changes to
1884
-        if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1885
-            $REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1886
-        }
1887
-        //nothing specified ? then get all reg IDs
1888
-        if (empty($REG_IDs)) {
1889
-            $registrations = $payment->transaction()->registrations();
1890
-            $REG_IDs       = ! empty($registrations)
1891
-                ? array_keys($registrations)
1892
-                : $this->_get_existing_reg_payment_REG_IDs($payment);
1893
-        }
1894
-
1895
-        // ensure that REG_IDs are integers and NOT strings
1896
-        return array_map('intval', $REG_IDs);
1897
-    }
1898
-
1899
-
1900
-    /**
1901
-     * @return array
1902
-     */
1903
-    public function existing_reg_payment_REG_IDs()
1904
-    {
1905
-        return $this->_existing_reg_payment_REG_IDs;
1906
-    }
1907
-
1908
-
1909
-    /**
1910
-     * @param array $existing_reg_payment_REG_IDs
1911
-     */
1912
-    public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1913
-    {
1914
-        $this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1915
-    }
1916
-
1917
-
1918
-    /**
1919
-     * _get_existing_reg_payment_REG_IDs
1920
-     * returns a list of registration IDs that the payment is currently related to
1921
-     * as recorded in the database
1922
-     *
1923
-     * @param \EE_Payment $payment
1924
-     * @return array
1925
-     * @throws EE_Error
1926
-     */
1927
-    protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1928
-    {
1929
-        if ($this->existing_reg_payment_REG_IDs() === null) {
1930
-            // let's get any existing reg payment records for this payment
1931
-            $existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1932
-            // but we only want the REG IDs, so grab the array keys
1933
-            $existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
1934
-                ? array_keys($existing_reg_payment_REG_IDs)
1935
-                : array();
1936
-            $this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1937
-        }
1938
-
1939
-        return $this->existing_reg_payment_REG_IDs();
1940
-    }
1941
-
1942
-
1943
-    /**
1944
-     * _remove_existing_registration_payments
1945
-     * this calculates the difference between existing relations
1946
-     * to the supplied payment and the new list registration IDs,
1947
-     * removes any related registrations that no longer apply,
1948
-     * and then updates the registration paid fields
1949
-     *
1950
-     * @param \EE_Payment $payment
1951
-     * @param int         $PAY_ID
1952
-     * @return bool;
1953
-     * @throws EE_Error
1954
-     * @throws InvalidArgumentException
1955
-     * @throws ReflectionException
1956
-     * @throws InvalidDataTypeException
1957
-     * @throws InvalidInterfaceException
1958
-     */
1959
-    protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1960
-    {
1961
-        // newly created payments will have nothing recorded for $PAY_ID
1962
-        if ($PAY_ID == 0) {
1963
-            return false;
1964
-        }
1965
-        $existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1966
-        if (empty($existing_reg_payment_REG_IDs)) {
1967
-            return false;
1968
-        }
1969
-        /** @type EE_Transaction_Payments $transaction_payments */
1970
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1971
-
1972
-        return $transaction_payments->delete_registration_payments_and_update_registrations(
1973
-            $payment,
1974
-            array(
1975
-                array(
1976
-                    'PAY_ID' => $payment->ID(),
1977
-                    'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
1978
-                ),
1979
-            )
1980
-        );
1981
-    }
1982
-
1983
-
1984
-    /**
1985
-     * _update_registration_payments
1986
-     * this applies the payments to the selected registrations
1987
-     * but only if they have not already been paid for
1988
-     *
1989
-     * @param  EE_Transaction $transaction
1990
-     * @param \EE_Payment     $payment
1991
-     * @param array           $REG_IDs
1992
-     * @return void
1993
-     * @throws EE_Error
1994
-     * @throws InvalidArgumentException
1995
-     * @throws ReflectionException
1996
-     * @throws RuntimeException
1997
-     * @throws InvalidDataTypeException
1998
-     * @throws InvalidInterfaceException
1999
-     */
2000
-    protected function _update_registration_payments(
2001
-        EE_Transaction $transaction,
2002
-        EE_Payment $payment,
2003
-        $REG_IDs = array()
2004
-    ) {
2005
-        // we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2006
-        // so let's do that using our set of REG_IDs from the form
2007
-        $registration_query_where_params = array(
2008
-            'REG_ID' => array('IN', $REG_IDs),
2009
-        );
2010
-        // but add in some conditions regarding payment,
2011
-        // so that we don't apply payments to registrations that are free or have already been paid for
2012
-        // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2013
-        if (! $payment->is_a_refund()) {
2014
-            $registration_query_where_params['REG_final_price']  = array('!=', 0);
2015
-            $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2016
-        }
2017
-        $registrations = $transaction->registrations(array($registration_query_where_params));
2018
-        if (! empty($registrations)) {
2019
-            /** @type EE_Payment_Processor $payment_processor */
2020
-            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2021
-            $payment_processor->process_registration_payments($transaction, $payment, $registrations);
2022
-        }
2023
-    }
2024
-
2025
-
2026
-    /**
2027
-     * _process_registration_status_change
2028
-     * This processes requested registration status changes for all the registrations
2029
-     * on a given transaction and (optionally) sends out notifications for the changes.
2030
-     *
2031
-     * @param  EE_Transaction $transaction
2032
-     * @param array           $REG_IDs
2033
-     * @return bool
2034
-     * @throws EE_Error
2035
-     * @throws InvalidArgumentException
2036
-     * @throws ReflectionException
2037
-     * @throws InvalidDataTypeException
2038
-     * @throws InvalidInterfaceException
2039
-     */
2040
-    protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2041
-    {
2042
-        // first if there is no change in status then we get out.
2043
-        if (
2044
-            ! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2045
-            || $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2046
-        ) {
2047
-            //no error message, no change requested, just nothing to do man.
2048
-            return false;
2049
-        }
2050
-        /** @type EE_Transaction_Processor $transaction_processor */
2051
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2052
-
2053
-        // made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2054
-        return $transaction_processor->manually_update_registration_statuses(
2055
-            $transaction,
2056
-            sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
2057
-            array(array('REG_ID' => array('IN', $REG_IDs)))
2058
-        );
2059
-    }
2060
-
2061
-
2062
-    /**
2063
-     * _build_payment_json_response
2064
-     *
2065
-     * @access public
2066
-     * @param \EE_Payment $payment
2067
-     * @param array       $REG_IDs
2068
-     * @param bool | null $delete_txn_reg_status_change
2069
-     * @return array
2070
-     * @throws EE_Error
2071
-     * @throws InvalidArgumentException
2072
-     * @throws InvalidDataTypeException
2073
-     * @throws InvalidInterfaceException
2074
-     * @throws ReflectionException
2075
-     */
2076
-    protected function _build_payment_json_response(
2077
-        EE_Payment $payment,
2078
-        $REG_IDs = array(),
2079
-        $delete_txn_reg_status_change = null
2080
-    ) {
2081
-        // was the payment deleted ?
2082
-        if (is_bool($delete_txn_reg_status_change)) {
2083
-            return array(
2084
-                'PAY_ID'                       => $payment->ID(),
2085
-                'amount'                       => $payment->amount(),
2086
-                'total_paid'                   => $payment->transaction()->paid(),
2087
-                'txn_status'                   => $payment->transaction()->status_ID(),
2088
-                'pay_status'                   => $payment->STS_ID(),
2089
-                'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2090
-                'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2091
-            );
2092
-        } else {
2093
-            $this->_get_payment_status_array();
2094
-
2095
-            return array(
2096
-                'amount'           => $payment->amount(),
2097
-                'total_paid'       => $payment->transaction()->paid(),
2098
-                'txn_status'       => $payment->transaction()->status_ID(),
2099
-                'pay_status'       => $payment->STS_ID(),
2100
-                'PAY_ID'           => $payment->ID(),
2101
-                'STS_ID'           => $payment->STS_ID(),
2102
-                'status'           => self::$_pay_status[$payment->STS_ID()],
2103
-                'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2104
-                'method'           => strtoupper($payment->source()),
2105
-                'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2106
-                'gateway'          => $payment->payment_method()
2107
-                    ? $payment->payment_method()->admin_name()
2108
-                    : esc_html__("Unknown", 'event_espresso'),
2109
-                'gateway_response' => $payment->gateway_response(),
2110
-                'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2111
-                'po_number'        => $payment->po_number(),
2112
-                'extra_accntng'    => $payment->extra_accntng(),
2113
-                'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2114
-            );
2115
-        }
2116
-    }
2117
-
2118
-
2119
-    /**
2120
-     * delete_payment
2121
-     *    delete a payment or refund made towards a transaction
2122
-     *
2123
-     * @access public
2124
-     * @return void
2125
-     * @throws EE_Error
2126
-     * @throws InvalidArgumentException
2127
-     * @throws ReflectionException
2128
-     * @throws InvalidDataTypeException
2129
-     * @throws InvalidInterfaceException
2130
-     */
2131
-    public function delete_payment()
2132
-    {
2133
-        $json_response_data = array('return_data' => false);
2134
-        $PAY_ID             = isset($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2135
-            ? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2136
-            : 0;
2137
-        $can_delete = EE_Registry::instance()->CAP->current_user_can(
2138
-            'ee_delete_payments',
2139
-            'delete_payment_from_registration_details'
2140
-        );
2141
-        if ($PAY_ID && $can_delete) {
2142
-            $delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change'])
2143
-                ? $this->_req_data['delete_txn_reg_status_change']
2144
-                : false;
2145
-            $payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2146
-            if ($payment instanceof EE_Payment) {
2147
-                $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2148
-                /** @type EE_Transaction_Payments $transaction_payments */
2149
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2150
-                if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2151
-                    $json_response_data['return_data'] = $this->_build_payment_json_response(
2152
-                        $payment,
2153
-                        $REG_IDs,
2154
-                        $delete_txn_reg_status_change
2155
-                    );
2156
-                    if ($delete_txn_reg_status_change) {
2157
-                        $this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
2158
-                        //MAKE sure we also add the delete_txn_req_status_change to the
2159
-                        //$_REQUEST global because that's how messages will be looking for it.
2160
-                        $_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
2161
-                        $this->_maybe_send_notifications();
2162
-                        $this->_process_registration_status_change($payment->transaction(), $REG_IDs);
2163
-                    }
2164
-                }
2165
-            } else {
2166
-                EE_Error::add_error(
2167
-                    esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2168
-                    __FILE__, __FUNCTION__, __LINE__
2169
-                );
2170
-            }
2171
-        } else {
2172
-            if ($can_delete) {
2173
-                EE_Error::add_error(
2174
-                    esc_html__(
2175
-                        'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2176
-                        'event_espresso'
2177
-                    ),
2178
-                    __FILE__, __FUNCTION__, __LINE__
2179
-                );
2180
-            } else {
2181
-                EE_Error::add_error(
2182
-                    esc_html__(
2183
-                        'You do not have access to delete a payment.',
2184
-                        'event_espresso'
2185
-                    ),
2186
-                    __FILE__,
2187
-                    __FUNCTION__,
2188
-                    __LINE__
2189
-                );
2190
-            }
2191
-        }
2192
-        $notices              = EE_Error::get_notices(false, false, false);
2193
-        $this->_template_args = array(
2194
-            'data'      => $json_response_data,
2195
-            'success'   => $notices['success'],
2196
-            'error'     => $notices['errors'],
2197
-            'attention' => $notices['attention'],
2198
-        );
2199
-        $this->_return_json();
2200
-    }
2201
-
2202
-
2203
-    /**
2204
-     * _registration_payment_data_array
2205
-     * adds info for 'owing' and 'paid' for each registration to the json response
2206
-     *
2207
-     * @access protected
2208
-     * @param array $REG_IDs
2209
-     * @return array
2210
-     * @throws EE_Error
2211
-     * @throws InvalidArgumentException
2212
-     * @throws InvalidDataTypeException
2213
-     * @throws InvalidInterfaceException
2214
-     * @throws ReflectionException
2215
-     */
2216
-    protected function _registration_payment_data_array($REG_IDs)
2217
-    {
2218
-        $registration_payment_data = array();
2219
-        //if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2220
-        if (! empty($REG_IDs)) {
2221
-            $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2222
-            foreach ($registrations as $registration) {
2223
-                if ($registration instanceof EE_Registration) {
2224
-                    $registration_payment_data[$registration->ID()] = array(
2225
-                        'paid'  => $registration->pretty_paid(),
2226
-                        'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2227
-                    );
2228
-                }
2229
-            }
2230
-        }
2231
-
2232
-        return $registration_payment_data;
2233
-    }
2234
-
2235
-
2236
-    /**
2237
-     * _maybe_send_notifications
2238
-     * determines whether or not the admin has indicated that notifications should be sent.
2239
-     * If so, will toggle a filter switch for delivering registration notices.
2240
-     * If passed an EE_Payment object, then it will trigger payment notifications instead.
2241
-     *
2242
-     * @access protected
2243
-     * @param \EE_Payment | null $payment
2244
-     */
2245
-    protected function _maybe_send_notifications($payment = null)
2246
-    {
2247
-        switch ($payment instanceof EE_Payment) {
2248
-            // payment notifications
2249
-            case true :
2250
-                if (
2251
-                    isset(
2252
-                        $this->_req_data['txn_payments'],
2253
-                        $this->_req_data['txn_payments']['send_notifications']
2254
-                    ) &&
2255
-                    filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2256
-                ) {
2257
-                    $this->_process_payment_notification($payment);
2258
-                }
2259
-                break;
2260
-            // registration notifications
2261
-            case false :
2262
-                if (
2263
-                    isset(
2264
-                        $this->_req_data['txn_reg_status_change'],
2265
-                        $this->_req_data['txn_reg_status_change']['send_notifications']
2266
-                    ) &&
2267
-                    filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2268
-                ) {
2269
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2270
-                }
2271
-                break;
2272
-        }
2273
-    }
2274
-
2275
-
2276
-    /**
2277
-     * _send_payment_reminder
2278
-     *    generates HTML for the View Transaction Details Admin page
2279
-     *
2280
-     * @access protected
2281
-     * @return void
2282
-     * @throws EE_Error
2283
-     * @throws InvalidArgumentException
2284
-     * @throws InvalidDataTypeException
2285
-     * @throws InvalidInterfaceException
2286
-     */
2287
-    protected function _send_payment_reminder()
2288
-    {
2289
-        $TXN_ID      = ! empty($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : false;
2290
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2291
-        $query_args  = isset($this->_req_data['redirect_to']) ? array(
2292
-            'action' => $this->_req_data['redirect_to'],
2293
-            'TXN_ID' => $this->_req_data['TXN_ID'],
2294
-        ) : array();
2295
-        do_action(
2296
-            'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2297
-            $transaction
2298
-        );
2299
-        $this->_redirect_after_action(
2300
-            false,
2301
-            esc_html__('payment reminder', 'event_espresso'),
2302
-            esc_html__('sent', 'event_espresso'),
2303
-            $query_args,
2304
-            true
2305
-        );
2306
-    }
2307
-
2308
-
2309
-    /**
2310
-     *  get_transactions
2311
-     *    get transactions for given parameters (used by list table)
2312
-     *
2313
-     * @param  int     $perpage how many transactions displayed per page
2314
-     * @param  boolean $count   return the count or objects
2315
-     * @param string   $view
2316
-     * @return mixed int = count || array of transaction objects
2317
-     * @throws EE_Error
2318
-     * @throws InvalidArgumentException
2319
-     * @throws InvalidDataTypeException
2320
-     * @throws InvalidInterfaceException
2321
-     */
2322
-    public function get_transactions($perpage, $count = false, $view = '')
2323
-    {
2324
-
2325
-        $TXN = EEM_Transaction::instance();
2326
-
2327
-        $start_date = isset($this->_req_data['txn-filter-start-date'])
2328
-            ? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
2329
-            : date(
2330
-                'm/d/Y',
2331
-                strtotime('-10 year')
2332
-            );
2333
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
2334
-            ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2335
-            : date('m/d/Y');
2336
-
2337
-        //make sure our timestamps start and end right at the boundaries for each day
2338
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2339
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2340
-
2341
-
2342
-        //convert to timestamps
2343
-        $start_date = strtotime($start_date);
2344
-        $end_date   = strtotime($end_date);
2345
-
2346
-        //makes sure start date is the lowest value and vice versa
2347
-        $start_date = min($start_date, $end_date);
2348
-        $end_date   = max($start_date, $end_date);
2349
-
2350
-        //convert to correct format for query
2351
-        $start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2352
-            'TXN_timestamp',
2353
-            date('Y-m-d H:i:s', $start_date),
2354
-            'Y-m-d H:i:s'
2355
-        );
2356
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2357
-            'TXN_timestamp',
2358
-            date('Y-m-d H:i:s', $end_date),
2359
-            'Y-m-d H:i:s'
2360
-        );
2361
-
2362
-
2363
-        //set orderby
2364
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
2365
-
2366
-        switch ($this->_req_data['orderby']) {
2367
-            case 'TXN_ID':
2368
-                $orderby = 'TXN_ID';
2369
-                break;
2370
-            case 'ATT_fname':
2371
-                $orderby = 'Registration.Attendee.ATT_fname';
2372
-                break;
2373
-            case 'event_name':
2374
-                $orderby = 'Registration.Event.EVT_name';
2375
-                break;
2376
-            default: //'TXN_timestamp'
2377
-                $orderby = 'TXN_timestamp';
2378
-        }
2379
-
2380
-        $sort         = ! empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2381
-        $current_page = ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
2382
-        $per_page     = ! empty($perpage) ? $perpage : 10;
2383
-        $per_page     = ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
2384
-
2385
-        $offset = ($current_page - 1) * $per_page;
2386
-        $limit  = array($offset, $per_page);
2387
-
2388
-        $_where = array(
2389
-            'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
2390
-            'Registration.REG_count' => 1,
2391
-        );
2392
-
2393
-        if (isset($this->_req_data['EVT_ID'])) {
2394
-            $_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
2395
-        }
2396
-
2397
-        if (isset($this->_req_data['s'])) {
2398
-            $search_string = '%' . $this->_req_data['s'] . '%';
2399
-            $_where['OR']  = array(
2400
-                'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2401
-                'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
2402
-                'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
2403
-                'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
2404
-                'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
2405
-                'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
2406
-                'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
2407
-                'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
2408
-                'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
2409
-                'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
2410
-                'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
2411
-                'Registration.REG_final_price'        => array('LIKE', $search_string),
2412
-                'Registration.REG_code'               => array('LIKE', $search_string),
2413
-                'Registration.REG_count'              => array('LIKE', $search_string),
2414
-                'Registration.REG_group_size'         => array('LIKE', $search_string),
2415
-                'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
2416
-                'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
2417
-                'Payment.PAY_source'                  => array('LIKE', $search_string),
2418
-                'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
2419
-                'TXN_session_data'                    => array('LIKE', $search_string),
2420
-                'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string),
2421
-            );
2422
-        }
2423
-
2424
-        //failed transactions
2425
-        $failed    = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2426
-                     || ($count && $view === 'failed');
2427
-        $abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2428
-                     || ($count && $view === 'abandoned');
2429
-
2430
-        if ($failed) {
2431
-            $_where['STS_ID'] = EEM_Transaction::failed_status_code;
2432
-        } else if ($abandoned) {
2433
-            $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2434
-        } else {
2435
-            $_where['STS_ID']  = array('!=', EEM_Transaction::failed_status_code);
2436
-            $_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
2437
-        }
2438
-
2439
-        $query_params = array(
2440
-            $_where,
2441
-            'order_by'                 => array($orderby => $sort),
2442
-            'limit'                    => $limit,
2443
-            'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2444
-        );
2445
-
2446
-        $transactions = $count
2447
-            ? $TXN->count(array($_where), 'TXN_ID', true)
2448
-            : $TXN->get_all($query_params);
2449
-
2450
-        return $transactions;
2451
-    }
19
+	/**
20
+	 * @var EE_Transaction
21
+	 */
22
+	private $_transaction;
23
+
24
+	/**
25
+	 * @var EE_Session
26
+	 */
27
+	private $_session;
28
+
29
+	/**
30
+	 * @var array $_txn_status
31
+	 */
32
+	private static $_txn_status;
33
+
34
+	/**
35
+	 * @var array $_pay_status
36
+	 */
37
+	private static $_pay_status;
38
+
39
+	/**
40
+	 * @var array $_existing_reg_payment_REG_IDs
41
+	 */
42
+	protected $_existing_reg_payment_REG_IDs = null;
43
+
44
+
45
+	/**
46
+	 * @Constructor
47
+	 * @access public
48
+	 * @param bool $routing
49
+	 * @throws EE_Error
50
+	 * @throws InvalidArgumentException
51
+	 * @throws ReflectionException
52
+	 * @throws InvalidDataTypeException
53
+	 * @throws InvalidInterfaceException
54
+	 */
55
+	public function __construct($routing = true)
56
+	{
57
+		parent::__construct($routing);
58
+	}
59
+
60
+
61
+	/**
62
+	 *    _init_page_props
63
+	 *
64
+	 * @return void
65
+	 */
66
+	protected function _init_page_props()
67
+	{
68
+		$this->page_slug        = TXN_PG_SLUG;
69
+		$this->page_label       = esc_html__('Transactions', 'event_espresso');
70
+		$this->_admin_base_url  = TXN_ADMIN_URL;
71
+		$this->_admin_base_path = TXN_ADMIN;
72
+	}
73
+
74
+
75
+	/**
76
+	 *    _ajax_hooks
77
+	 *
78
+	 * @return void
79
+	 */
80
+	protected function _ajax_hooks()
81
+	{
82
+		add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
83
+		add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
84
+		add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
85
+	}
86
+
87
+
88
+	/**
89
+	 *    _define_page_props
90
+	 *
91
+	 * @return void
92
+	 */
93
+	protected function _define_page_props()
94
+	{
95
+		$this->_admin_page_title = $this->page_label;
96
+		$this->_labels           = array(
97
+			'buttons' => array(
98
+				'add'    => esc_html__('Add New Transaction', 'event_espresso'),
99
+				'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
100
+				'delete' => esc_html__('Delete Transaction', 'event_espresso'),
101
+			),
102
+		);
103
+	}
104
+
105
+
106
+	/**
107
+	 *        grab url requests and route them
108
+	 *
109
+	 * @access private
110
+	 * @return void
111
+	 * @throws EE_Error
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 */
116
+	public function _set_page_routes()
117
+	{
118
+
119
+		$this->_set_transaction_status_array();
120
+
121
+		$txn_id = ! empty($this->_req_data['TXN_ID'])
122
+				  && ! is_array($this->_req_data['TXN_ID'])
123
+			? $this->_req_data['TXN_ID']
124
+			: 0;
125
+
126
+		$this->_page_routes = array(
127
+
128
+			'default' => array(
129
+				'func'       => '_transactions_overview_list_table',
130
+				'capability' => 'ee_read_transactions',
131
+			),
132
+
133
+			'view_transaction' => array(
134
+				'func'       => '_transaction_details',
135
+				'capability' => 'ee_read_transaction',
136
+				'obj_id'     => $txn_id,
137
+			),
138
+
139
+			'send_payment_reminder' => array(
140
+				'func'       => '_send_payment_reminder',
141
+				'noheader'   => true,
142
+				'capability' => 'ee_send_message',
143
+			),
144
+
145
+			'espresso_apply_payment' => array(
146
+				'func'       => 'apply_payments_or_refunds',
147
+				'noheader'   => true,
148
+				'capability' => 'ee_edit_payments',
149
+			),
150
+
151
+			'espresso_apply_refund' => array(
152
+				'func'       => 'apply_payments_or_refunds',
153
+				'noheader'   => true,
154
+				'capability' => 'ee_edit_payments',
155
+			),
156
+
157
+			'espresso_delete_payment' => array(
158
+				'func'       => 'delete_payment',
159
+				'noheader'   => true,
160
+				'capability' => 'ee_delete_payments',
161
+			),
162
+
163
+		);
164
+	}
165
+
166
+
167
+	protected function _set_page_config()
168
+	{
169
+		$this->_page_config = array(
170
+			'default'          => array(
171
+				'nav'           => array(
172
+					'label' => esc_html__('Overview', 'event_espresso'),
173
+					'order' => 10,
174
+				),
175
+				'list_table'    => 'EE_Admin_Transactions_List_Table',
176
+				'help_tabs'     => array(
177
+					'transactions_overview_help_tab'                       => array(
178
+						'title'    => esc_html__('Transactions Overview', 'event_espresso'),
179
+						'filename' => 'transactions_overview',
180
+					),
181
+					'transactions_overview_table_column_headings_help_tab' => array(
182
+						'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
183
+						'filename' => 'transactions_overview_table_column_headings',
184
+					),
185
+					'transactions_overview_views_filters_help_tab'         => array(
186
+						'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
187
+						'filename' => 'transactions_overview_views_filters_search',
188
+					),
189
+				),
190
+				'help_tour'     => array('Transactions_Overview_Help_Tour'),
191
+				/**
192
+				 * commented out because currently we are not displaying tips for transaction list table status but this
193
+				 * may change in a later iteration so want to keep the code for then.
194
+				 */
195
+				//'qtips' => array( 'Transactions_List_Table_Tips' ),
196
+				'require_nonce' => false,
197
+			),
198
+			'view_transaction' => array(
199
+				'nav'       => array(
200
+					'label'      => esc_html__('View Transaction', 'event_espresso'),
201
+					'order'      => 5,
202
+					'url'        => isset($this->_req_data['TXN_ID'])
203
+						? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']), $this->_current_page_view_url)
204
+						: $this->_admin_base_url,
205
+					'persistent' => false,
206
+				),
207
+				'help_tabs' => array(
208
+					'transactions_view_transaction_help_tab'                                              => array(
209
+						'title'    => esc_html__('View Transaction', 'event_espresso'),
210
+						'filename' => 'transactions_view_transaction',
211
+					),
212
+					'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
213
+						'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
214
+						'filename' => 'transactions_view_transaction_transaction_details_table',
215
+					),
216
+					'transactions_view_transaction_attendees_registered_help_tab'                         => array(
217
+						'title'    => esc_html__('Attendees Registered', 'event_espresso'),
218
+						'filename' => 'transactions_view_transaction_attendees_registered',
219
+					),
220
+					'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
221
+						'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
222
+						'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
223
+					),
224
+				),
225
+				'qtips'     => array('Transaction_Details_Tips'),
226
+				'help_tour' => array('Transaction_Details_Help_Tour'),
227
+				'metaboxes' => array('_transaction_details_metaboxes'),
228
+
229
+				'require_nonce' => false,
230
+			),
231
+		);
232
+	}
233
+
234
+
235
+	/**
236
+	 * The below methods aren't used by this class currently
237
+	 */
238
+	protected function _add_screen_options()
239
+	{
240
+		//noop
241
+	}
242
+
243
+	protected function _add_feature_pointers()
244
+	{
245
+		//noop
246
+	}
247
+
248
+	public function admin_init()
249
+	{
250
+		// IF a registration was JUST added via the admin...
251
+		if (isset(
252
+			$this->_req_data['redirect_from'],
253
+			$this->_req_data['EVT_ID'],
254
+			$this->_req_data['event_name']
255
+		)) {
256
+			// then set a cookie so that we can block any attempts to use
257
+			// the back button as a way to enter another registration.
258
+			setcookie(
259
+				'ee_registration_added',
260
+				$this->_req_data['EVT_ID'], time() + WEEK_IN_SECONDS, '/'
261
+			);
262
+			// and update the global
263
+			$_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
264
+		}
265
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
266
+			'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267
+			'event_espresso'
268
+		);
269
+		EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
270
+			'An error occurred! Please refresh the page and try again.',
271
+			'event_espresso'
272
+		);
273
+		EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
274
+		EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
275
+		EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
276
+		EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__(
277
+			'This transaction has been overpaid ! Payments Total',
278
+			'event_espresso'
279
+		);
280
+	}
281
+
282
+	public function admin_notices()
283
+	{
284
+		//noop
285
+	}
286
+
287
+	public function admin_footer_scripts()
288
+	{
289
+		//noop
290
+	}
291
+
292
+
293
+	/**
294
+	 * _set_transaction_status_array
295
+	 * sets list of transaction statuses
296
+	 *
297
+	 * @access private
298
+	 * @return void
299
+	 * @throws EE_Error
300
+	 * @throws InvalidArgumentException
301
+	 * @throws InvalidDataTypeException
302
+	 * @throws InvalidInterfaceException
303
+	 */
304
+	private function _set_transaction_status_array()
305
+	{
306
+		self::$_txn_status = EEM_Transaction::instance()->status_array(true);
307
+	}
308
+
309
+
310
+	/**
311
+	 * get_transaction_status_array
312
+	 * return the transaction status array for wp_list_table
313
+	 *
314
+	 * @access public
315
+	 * @return array
316
+	 */
317
+	public function get_transaction_status_array()
318
+	{
319
+		return self::$_txn_status;
320
+	}
321
+
322
+
323
+	/**
324
+	 *    get list of payment statuses
325
+	 *
326
+	 * @access private
327
+	 * @return void
328
+	 * @throws EE_Error
329
+	 * @throws InvalidArgumentException
330
+	 * @throws InvalidDataTypeException
331
+	 * @throws InvalidInterfaceException
332
+	 */
333
+	private function _get_payment_status_array()
334
+	{
335
+		self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
336
+		$this->_template_args['payment_status'] = self::$_pay_status;
337
+
338
+	}
339
+
340
+
341
+	/**
342
+	 *    _add_screen_options_default
343
+	 *
344
+	 * @access protected
345
+	 * @return void
346
+	 * @throws InvalidArgumentException
347
+	 * @throws InvalidDataTypeException
348
+	 * @throws InvalidInterfaceException
349
+	 */
350
+	protected function _add_screen_options_default()
351
+	{
352
+		$this->_per_page_screen_option();
353
+	}
354
+
355
+
356
+	/**
357
+	 * load_scripts_styles
358
+	 *
359
+	 * @access public
360
+	 * @return void
361
+	 */
362
+	public function load_scripts_styles()
363
+	{
364
+		//enqueue style
365
+		wp_register_style(
366
+			'espresso_txn',
367
+			TXN_ASSETS_URL . 'espresso_transactions_admin.css',
368
+			array(),
369
+			EVENT_ESPRESSO_VERSION
370
+		);
371
+		wp_enqueue_style('espresso_txn');
372
+		//scripts
373
+		wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
374
+			'ee_admin_js',
375
+			'ee-datepicker',
376
+			'jquery-ui-datepicker',
377
+			'jquery-ui-draggable',
378
+			'ee-dialog',
379
+			'ee-accounting',
380
+			'ee-serialize-full-array',
381
+		), EVENT_ESPRESSO_VERSION, true);
382
+		wp_enqueue_script('espresso_txn');
383
+	}
384
+
385
+
386
+	/**
387
+	 *    load_scripts_styles_view_transaction
388
+	 *
389
+	 * @access public
390
+	 * @return void
391
+	 */
392
+	public function load_scripts_styles_view_transaction()
393
+	{
394
+		//styles
395
+		wp_enqueue_style('espresso-ui-theme');
396
+	}
397
+
398
+
399
+	/**
400
+	 *    load_scripts_styles_default
401
+	 *
402
+	 * @access public
403
+	 * @return void
404
+	 */
405
+	public function load_scripts_styles_default()
406
+	{
407
+		//styles
408
+		wp_enqueue_style('espresso-ui-theme');
409
+	}
410
+
411
+
412
+	/**
413
+	 *    _set_list_table_views_default
414
+	 *
415
+	 * @access protected
416
+	 * @return void
417
+	 */
418
+	protected function _set_list_table_views_default()
419
+	{
420
+		$this->_views = array(
421
+			'all'       => array(
422
+				'slug'  => 'all',
423
+				'label' => esc_html__('View All Transactions', 'event_espresso'),
424
+				'count' => 0,
425
+			),
426
+			'abandoned' => array(
427
+				'slug'  => 'abandoned',
428
+				'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
429
+				'count' => 0,
430
+			),
431
+			'failed'    => array(
432
+				'slug'  => 'failed',
433
+				'label' => esc_html__('Failed Transactions', 'event_espresso'),
434
+				'count' => 0,
435
+			),
436
+		);
437
+	}
438
+
439
+
440
+	/**
441
+	 * _set_transaction_object
442
+	 * This sets the _transaction property for the transaction details screen
443
+	 *
444
+	 * @access private
445
+	 * @return void
446
+	 * @throws EE_Error
447
+	 * @throws InvalidArgumentException
448
+	 * @throws RuntimeException
449
+	 * @throws InvalidDataTypeException
450
+	 * @throws InvalidInterfaceException
451
+	 * @throws ReflectionException
452
+	 */
453
+	private function _set_transaction_object()
454
+	{
455
+		if ($this->_transaction instanceof EE_Transaction) {
456
+			return;
457
+		} //get out we've already set the object
458
+
459
+		$TXN_ID = ! empty($this->_req_data['TXN_ID'])
460
+			? absint($this->_req_data['TXN_ID'])
461
+			: false;
462
+
463
+		//get transaction object
464
+		$this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
465
+		$this->_session     = $this->_transaction instanceof EE_Transaction
466
+			? $this->_transaction->get('TXN_session_data')
467
+			: null;
468
+		$this->_transaction->verify_abandoned_transaction_status();
469
+
470
+		if (! $this->_transaction instanceof EE_Transaction) {
471
+			$error_msg = sprintf(
472
+				esc_html__(
473
+					'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
474
+					'event_espresso'
475
+				),
476
+				$TXN_ID
477
+			);
478
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
479
+		}
480
+	}
481
+
482
+
483
+	/**
484
+	 *    _transaction_legend_items
485
+	 *
486
+	 * @access protected
487
+	 * @return array
488
+	 * @throws EE_Error
489
+	 * @throws InvalidArgumentException
490
+	 * @throws ReflectionException
491
+	 * @throws InvalidDataTypeException
492
+	 * @throws InvalidInterfaceException
493
+	 */
494
+	protected function _transaction_legend_items()
495
+	{
496
+		EE_Registry::instance()->load_helper('MSG_Template');
497
+		$items = array();
498
+
499
+		if (EE_Registry::instance()->CAP->current_user_can(
500
+			'ee_read_global_messages',
501
+			'view_filtered_messages'
502
+		)) {
503
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
504
+			if (is_array($related_for_icon)
505
+				&& isset($related_for_icon['css_class'], $related_for_icon['label'])
506
+			) {
507
+				$items['view_related_messages'] = array(
508
+					'class' => $related_for_icon['css_class'],
509
+					'desc'  => $related_for_icon['label'],
510
+				);
511
+			}
512
+		}
513
+
514
+		$items = apply_filters(
515
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
516
+			array_merge(
517
+				$items,
518
+				array(
519
+					'view_details'          => array(
520
+						'class' => 'dashicons dashicons-cart',
521
+						'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
522
+					),
523
+					'view_invoice'          => array(
524
+						'class' => 'dashicons dashicons-media-spreadsheet',
525
+						'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
526
+					),
527
+					'view_receipt'          => array(
528
+						'class' => 'dashicons dashicons-media-default',
529
+						'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
530
+					),
531
+					'view_registration'     => array(
532
+						'class' => 'dashicons dashicons-clipboard',
533
+						'desc'  => esc_html__('View Registration Details', 'event_espresso'),
534
+					),
535
+					'payment_overview_link' => array(
536
+						'class' => 'dashicons dashicons-money',
537
+						'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
538
+					),
539
+				)
540
+			)
541
+		);
542
+
543
+		if (EE_Registry::instance()->CAP->current_user_can(
544
+			'ee_send_message',
545
+			'espresso_transactions_send_payment_reminder'
546
+		)) {
547
+			if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
548
+				$items['send_payment_reminder'] = array(
549
+					'class' => 'dashicons dashicons-email-alt',
550
+					'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
551
+				);
552
+			} else {
553
+				$items['blank*'] = array(
554
+					'class' => '',
555
+					'desc'  => '',
556
+				);
557
+			}
558
+		} else {
559
+			$items['blank*'] = array(
560
+				'class' => '',
561
+				'desc'  => '',
562
+			);
563
+		}
564
+		$more_items = apply_filters(
565
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
566
+			array(
567
+				'overpaid'   => array(
568
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
569
+					'desc'  => EEH_Template::pretty_status(
570
+						EEM_Transaction::overpaid_status_code,
571
+						false,
572
+						'sentence'
573
+					),
574
+				),
575
+				'complete'   => array(
576
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
577
+					'desc'  => EEH_Template::pretty_status(
578
+						EEM_Transaction::complete_status_code,
579
+						false,
580
+						'sentence'
581
+					),
582
+				),
583
+				'incomplete' => array(
584
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
585
+					'desc'  => EEH_Template::pretty_status(
586
+						EEM_Transaction::incomplete_status_code,
587
+						false,
588
+						'sentence'
589
+					),
590
+				),
591
+				'abandoned'  => array(
592
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
593
+					'desc'  => EEH_Template::pretty_status(
594
+						EEM_Transaction::abandoned_status_code,
595
+						false,
596
+						'sentence'
597
+					),
598
+				),
599
+				'failed'     => array(
600
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
601
+					'desc'  => EEH_Template::pretty_status(
602
+						EEM_Transaction::failed_status_code,
603
+						false,
604
+						'sentence'
605
+					),
606
+				),
607
+			)
608
+		);
609
+
610
+		return array_merge($items, $more_items);
611
+	}
612
+
613
+
614
+	/**
615
+	 *    _transactions_overview_list_table
616
+	 *
617
+	 * @access protected
618
+	 * @return void
619
+	 * @throws DomainException
620
+	 * @throws EE_Error
621
+	 * @throws InvalidArgumentException
622
+	 * @throws InvalidDataTypeException
623
+	 * @throws InvalidInterfaceException
624
+	 * @throws ReflectionException
625
+	 */
626
+	protected function _transactions_overview_list_table()
627
+	{
628
+		$this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
629
+		$event = isset($this->_req_data['EVT_ID'])
630
+			? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'])
631
+			: null;
632
+		$this->_template_args['admin_page_header'] = $event instanceof EE_Event
633
+			? sprintf(
634
+				esc_html__(
635
+					'%sViewing Transactions for the Event: %s%s',
636
+					'event_espresso'
637
+				),
638
+				'<h3>',
639
+				'<a href="'
640
+				. EE_Admin_Page::add_query_args_and_nonce(
641
+					array('action' => 'edit', 'post' => $event->ID()),
642
+					EVENTS_ADMIN_URL
643
+				)
644
+				. '" title="'
645
+				. esc_attr__(
646
+					'Click to Edit event',
647
+					'event_espresso'
648
+				)
649
+				. '">' . $event->get('EVT_name') . '</a>',
650
+				'</h3>'
651
+			)
652
+			: '';
653
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
654
+		$this->display_admin_list_table_page_with_no_sidebar();
655
+	}
656
+
657
+
658
+	/**
659
+	 *    _transaction_details
660
+	 * generates HTML for the View Transaction Details Admin page
661
+	 *
662
+	 * @access protected
663
+	 * @return void
664
+	 * @throws DomainException
665
+	 * @throws EE_Error
666
+	 * @throws InvalidArgumentException
667
+	 * @throws InvalidDataTypeException
668
+	 * @throws InvalidInterfaceException
669
+	 * @throws RuntimeException
670
+	 * @throws ReflectionException
671
+	 */
672
+	protected function _transaction_details()
673
+	{
674
+		do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
675
+
676
+		$this->_set_transaction_status_array();
677
+
678
+		$this->_template_args                      = array();
679
+		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
680
+
681
+		$this->_set_transaction_object();
682
+
683
+		$primary_registration = $this->_transaction->primary_registration();
684
+		$attendee = $primary_registration instanceof EE_Registration
685
+			? $primary_registration->attendee()
686
+			: null;
687
+
688
+		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
689
+		$this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
690
+
691
+		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
692
+		$this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
693
+
694
+		$this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
695
+		$this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
696
+		$this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
697
+
698
+		$this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
699
+		$this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
700
+
701
+		$amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
702
+		$this->_template_args['amount_due'] = EEH_Template::format_currency(
703
+			$amount_due,
704
+			true
705
+		);
706
+		if (EE_Registry::instance()->CFG->currency->sign_b4) {
707
+			$this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign
708
+												  . $this->_template_args['amount_due'];
709
+		} else {
710
+			$this->_template_args['amount_due'] .= EE_Registry::instance()->CFG->currency->sign;
711
+		}
712
+		$this->_template_args['amount_due_class'] = '';
713
+
714
+		if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
715
+			// paid in full
716
+			$this->_template_args['amount_due'] = false;
717
+		} elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
718
+			// overpaid
719
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
720
+		} elseif ($this->_transaction->get('TXN_total') > 0
721
+				  && $this->_transaction->get('TXN_paid') > 0
722
+		) {
723
+			// monies owing
724
+			$this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
725
+		} elseif ($this->_transaction->get('TXN_total') > 0
726
+				  && $this->_transaction->get('TXN_paid') == 0
727
+		) {
728
+			// no payments made yet
729
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
730
+		} elseif ($this->_transaction->get('TXN_total') == 0) {
731
+			// free event
732
+			$this->_template_args['amount_due'] = false;
733
+		}
734
+
735
+		$payment_method = $this->_transaction->payment_method();
736
+
737
+		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
738
+			? $payment_method->admin_name()
739
+			: esc_html__('Unknown', 'event_espresso');
740
+
741
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
742
+		// link back to overview
743
+		$this->_template_args['txn_overview_url'] = ! empty($_SERVER['HTTP_REFERER'])
744
+			? $_SERVER['HTTP_REFERER']
745
+			: TXN_ADMIN_URL;
746
+
747
+
748
+		// next link
749
+		$next_txn                                 = $this->_transaction->next(
750
+			null,
751
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
752
+			'TXN_ID'
753
+		);
754
+		$this->_template_args['next_transaction'] = $next_txn
755
+			? $this->_next_link(
756
+				EE_Admin_Page::add_query_args_and_nonce(
757
+					array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
758
+					TXN_ADMIN_URL
759
+				),
760
+				'dashicons dashicons-arrow-right ee-icon-size-22'
761
+			)
762
+			: '';
763
+		// previous link
764
+		$previous_txn                                 = $this->_transaction->previous(
765
+			null,
766
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
767
+			'TXN_ID'
768
+		);
769
+		$this->_template_args['previous_transaction'] = $previous_txn
770
+			? $this->_previous_link(
771
+				EE_Admin_Page::add_query_args_and_nonce(
772
+					array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
773
+					TXN_ADMIN_URL
774
+				),
775
+				'dashicons dashicons-arrow-left ee-icon-size-22'
776
+			)
777
+			: '';
778
+
779
+		// were we just redirected here after adding a new registration ???
780
+		if (isset(
781
+			$this->_req_data['redirect_from'],
782
+			$this->_req_data['EVT_ID'],
783
+			$this->_req_data['event_name']
784
+		)) {
785
+			if (EE_Registry::instance()->CAP->current_user_can(
786
+				'ee_edit_registrations',
787
+				'espresso_registrations_new_registration',
788
+				$this->_req_data['EVT_ID']
789
+			)) {
790
+				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
791
+				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
792
+					array(
793
+						'page'     => 'espresso_registrations',
794
+						'action'   => 'new_registration',
795
+						'return'   => 'default',
796
+						'TXN_ID'   => $this->_transaction->ID(),
797
+						'event_id' => $this->_req_data['EVT_ID'],
798
+					),
799
+					REG_ADMIN_URL
800
+				);
801
+				$this->_admin_page_title .= '">';
802
+
803
+				$this->_admin_page_title .= sprintf(
804
+					esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
805
+					htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
806
+				);
807
+				$this->_admin_page_title .= '</a>';
808
+			}
809
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
810
+		}
811
+		// grab messages at the last second
812
+		$this->_template_args['notices'] = EE_Error::get_notices();
813
+		// path to template
814
+		$template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
815
+		$this->_template_args['admin_page_header'] = EEH_Template::display_template(
816
+			$template_path,
817
+			$this->_template_args,
818
+			true
819
+		);
820
+
821
+		// the details template wrapper
822
+		$this->display_admin_page_with_sidebar();
823
+
824
+	}
825
+
826
+
827
+	/**
828
+	 *        _transaction_details_metaboxes
829
+	 *
830
+	 * @access protected
831
+	 * @return void
832
+	 * @throws EE_Error
833
+	 * @throws InvalidArgumentException
834
+	 * @throws InvalidDataTypeException
835
+	 * @throws InvalidInterfaceException
836
+	 * @throws RuntimeException
837
+	 * @throws ReflectionException
838
+	 */
839
+	protected function _transaction_details_metaboxes()
840
+	{
841
+
842
+		$this->_set_transaction_object();
843
+
844
+		add_meta_box(
845
+			'edit-txn-details-mbox',
846
+			esc_html__('Transaction Details', 'event_espresso'),
847
+			array($this, 'txn_details_meta_box'),
848
+			$this->_wp_page_slug,
849
+			'normal',
850
+			'high'
851
+		);
852
+		add_meta_box(
853
+			'edit-txn-attendees-mbox',
854
+			esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
855
+			array($this, 'txn_attendees_meta_box'),
856
+			$this->_wp_page_slug,
857
+			'normal',
858
+			'high',
859
+			array('TXN_ID' => $this->_transaction->ID())
860
+		);
861
+		add_meta_box(
862
+			'edit-txn-registrant-mbox',
863
+			esc_html__('Primary Contact', 'event_espresso'),
864
+			array($this, 'txn_registrant_side_meta_box'),
865
+			$this->_wp_page_slug,
866
+			'side',
867
+			'high'
868
+		);
869
+		add_meta_box(
870
+			'edit-txn-billing-info-mbox',
871
+			esc_html__('Billing Information', 'event_espresso'),
872
+			array($this, 'txn_billing_info_side_meta_box'),
873
+			$this->_wp_page_slug,
874
+			'side',
875
+			'high'
876
+		);
877
+	}
878
+
879
+
880
+	/**
881
+	 * Callback for transaction actions metabox.
882
+	 *
883
+	 * @param EE_Transaction|null $transaction
884
+	 * @throws DomainException
885
+	 * @throws EE_Error
886
+	 * @throws InvalidArgumentException
887
+	 * @throws InvalidDataTypeException
888
+	 * @throws InvalidInterfaceException
889
+	 * @throws ReflectionException
890
+	 * @throws RuntimeException
891
+	 */
892
+	public function getActionButtons(EE_Transaction $transaction = null)
893
+	{
894
+		$content = '';
895
+		$actions = array();
896
+		if (! $transaction instanceof EE_Transaction) {
897
+			return $content;
898
+		}
899
+		/** @var EE_Registration $primary_registration */
900
+		$primary_registration = $transaction->primary_registration();
901
+		$attendee = $primary_registration instanceof EE_Registration
902
+			? $primary_registration->attendee()
903
+			: null;
904
+
905
+		if ($attendee instanceof EE_Attendee
906
+			&& EE_Registry::instance()->CAP->current_user_can(
907
+				'ee_send_message',
908
+				'espresso_transactions_send_payment_reminder'
909
+			)
910
+		) {
911
+			$actions['payment_reminder'] =
912
+				EEH_MSG_Template::is_mt_active('payment_reminder')
913
+				&& $this->_transaction->get('STS_ID') !== EEM_Transaction::complete_status_code
914
+				&& $this->_transaction->get('STS_ID') !== EEM_Transaction::overpaid_status_code
915
+					? EEH_Template::get_button_or_link(
916
+						EE_Admin_Page::add_query_args_and_nonce(
917
+							array(
918
+								'action'      => 'send_payment_reminder',
919
+								'TXN_ID'      => $this->_transaction->ID(),
920
+								'redirect_to' => 'view_transaction',
921
+							),
922
+							TXN_ADMIN_URL
923
+						),
924
+						esc_html__(' Send Payment Reminder', 'event_espresso'),
925
+						'button secondary-button',
926
+						'dashicons dashicons-email-alt'
927
+					)
928
+					: '';
929
+		}
930
+
931
+		if ($primary_registration instanceof EE_Registration
932
+			&& EEH_MSG_Template::is_mt_active('receipt')
933
+		) {
934
+			$actions['receipt'] = EEH_Template::get_button_or_link(
935
+				$primary_registration->receipt_url(),
936
+				esc_html__('View Receipt', 'event_espresso'),
937
+				'button secondary-button',
938
+				'dashicons dashicons-media-default'
939
+			);
940
+		}
941
+
942
+		if ($primary_registration instanceof EE_Registration
943
+			&& EEH_MSG_Template::is_mt_active('invoice')
944
+		) {
945
+			$actions['invoice'] = EEH_Template::get_button_or_link(
946
+				$primary_registration->invoice_url(),
947
+				esc_html__('View Invoice', 'event_espresso'),
948
+				'button secondary-button',
949
+				'dashicons dashicons-media-spreadsheet'
950
+			);
951
+		}
952
+		$actions = array_filter(
953
+			apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
954
+		);
955
+		if ($actions) {
956
+			$content = '<ul>';
957
+			$content .= '<li>' . implode('</li><li>', $actions) . '</li>';
958
+			$content .= '</uL>';
959
+		}
960
+		return $content;
961
+	}
962
+
963
+
964
+	/**
965
+	 * txn_details_meta_box
966
+	 * generates HTML for the Transaction main meta box
967
+	 *
968
+	 * @return void
969
+	 * @throws DomainException
970
+	 * @throws EE_Error
971
+	 * @throws InvalidArgumentException
972
+	 * @throws InvalidDataTypeException
973
+	 * @throws InvalidInterfaceException
974
+	 * @throws RuntimeException
975
+	 * @throws ReflectionException
976
+	 */
977
+	public function txn_details_meta_box()
978
+	{
979
+		$this->_set_transaction_object();
980
+		$this->_template_args['TXN_ID']   = $this->_transaction->ID();
981
+		$this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration
982
+			? $this->_transaction->primary_registration()->attendee()
983
+			: null;
984
+		$this->_template_args['can_edit_payments'] = EE_Registry::instance()->CAP->current_user_can(
985
+			'ee_edit_payments',
986
+			'apply_payment_or_refund_from_registration_details'
987
+		);
988
+		$this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
989
+			'ee_delete_payments',
990
+			'delete_payment_from_registration_details'
991
+		);
992
+
993
+		//get line table
994
+		EEH_Autoloader::register_line_item_display_autoloaders();
995
+		$Line_Item_Display                       = new EE_Line_Item_Display(
996
+			'admin_table',
997
+			'EE_Admin_Table_Line_Item_Display_Strategy'
998
+		);
999
+		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1000
+			$this->_transaction->total_line_item()
1001
+		);
1002
+		$this->_template_args['REG_code']        = $this->_transaction->get_first_related('Registration')
1003
+																	  ->get('REG_code');
1004
+
1005
+		// process taxes
1006
+		$taxes                         = $this->_transaction->get_many_related(
1007
+			'Line_Item',
1008
+			array(array('LIN_type' => EEM_Line_Item::type_tax))
1009
+		);
1010
+		$this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1011
+
1012
+		$this->_template_args['grand_total']     = EEH_Template::format_currency(
1013
+			$this->_transaction->get('TXN_total'),
1014
+			false,
1015
+			false
1016
+		);
1017
+		$this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
1018
+		$this->_template_args['TXN_status']      = $this->_transaction->get('STS_ID');
1019
+
1020
+		// process payment details
1021
+		$payments = $this->_transaction->get_many_related('Payment');
1022
+		if (! empty($payments)) {
1023
+			$this->_template_args['payments']              = $payments;
1024
+			$this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1025
+		} else {
1026
+			$this->_template_args['payments']              = false;
1027
+			$this->_template_args['existing_reg_payments'] = array();
1028
+		}
1029
+
1030
+		$this->_template_args['edit_payment_url']   = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
1031
+		$this->_template_args['delete_payment_url'] = add_query_arg(
1032
+			array('action' => 'espresso_delete_payment'),
1033
+			TXN_ADMIN_URL
1034
+		);
1035
+
1036
+		if (isset($txn_details['invoice_number'])) {
1037
+			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1038
+			$this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1039
+				'Invoice Number',
1040
+				'event_espresso'
1041
+			);
1042
+		}
1043
+
1044
+		$this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction
1045
+			->get_first_related('Registration')
1046
+			->get('REG_session');
1047
+		$this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1048
+			'Registration Session',
1049
+			'event_espresso'
1050
+		);
1051
+
1052
+		$this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address'])
1053
+			? $this->_session['ip_address']
1054
+			: '';
1055
+		$this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1056
+			'Transaction placed from IP',
1057
+			'event_espresso'
1058
+		);
1059
+
1060
+		$this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent'])
1061
+			? $this->_session['user_agent']
1062
+			: '';
1063
+		$this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1064
+			'Registrant User Agent',
1065
+			'event_espresso'
1066
+		);
1067
+
1068
+		$reg_steps = '<ul>';
1069
+		foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1070
+			if ($reg_step_status === true) {
1071
+				$reg_steps .= '<li style="color:#70cc50">'
1072
+							  . sprintf(
1073
+								  esc_html__('%1$s : Completed', 'event_espresso'),
1074
+								  ucwords(str_replace('_', ' ', $reg_step))
1075
+							  )
1076
+							  . '</li>';
1077
+			} elseif (is_numeric($reg_step_status) && $reg_step_status !== false) {
1078
+				$reg_steps .= '<li style="color:#2EA2CC">'
1079
+							  . sprintf(
1080
+								  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1081
+								  ucwords(str_replace('_', ' ', $reg_step)),
1082
+								  date(
1083
+									  get_option('date_format') . ' ' . get_option('time_format'),
1084
+									  ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1085
+								  )
1086
+							  )
1087
+							  . '</li>';
1088
+			} else {
1089
+				$reg_steps .= '<li style="color:#E76700">'
1090
+							  . sprintf(
1091
+								  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1092
+								  ucwords(str_replace('_', ' ', $reg_step))
1093
+							  )
1094
+							  . '</li>';
1095
+			}
1096
+		}
1097
+		$reg_steps                                                 .= '</ul>';
1098
+		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1099
+		$this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1100
+			'Registration Step Progress',
1101
+			'event_espresso'
1102
+		);
1103
+
1104
+
1105
+		$this->_get_registrations_to_apply_payment_to();
1106
+		$this->_get_payment_methods($payments);
1107
+		$this->_get_payment_status_array();
1108
+		$this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
1109
+
1110
+		$this->_template_args['transaction_form_url']    = add_query_arg(array(
1111
+			'action'  => 'edit_transaction',
1112
+			'process' => 'transaction',
1113
+		), TXN_ADMIN_URL);
1114
+		$this->_template_args['apply_payment_form_url']  = add_query_arg(array(
1115
+			'page'   => 'espresso_transactions',
1116
+			'action' => 'espresso_apply_payment',
1117
+		), WP_AJAX_URL);
1118
+		$this->_template_args['delete_payment_form_url'] = add_query_arg(array(
1119
+			'page'   => 'espresso_transactions',
1120
+			'action' => 'espresso_delete_payment',
1121
+		), WP_AJAX_URL);
1122
+
1123
+		$this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1124
+
1125
+		// 'espresso_delete_payment_nonce'
1126
+
1127
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1128
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1129
+	}
1130
+
1131
+
1132
+	/**
1133
+	 * _get_registration_payment_IDs
1134
+	 *    generates an array of Payment IDs and their corresponding Registration IDs
1135
+	 *
1136
+	 * @access protected
1137
+	 * @param EE_Payment[] $payments
1138
+	 * @return array
1139
+	 * @throws EE_Error
1140
+	 * @throws InvalidArgumentException
1141
+	 * @throws InvalidDataTypeException
1142
+	 * @throws InvalidInterfaceException
1143
+	 * @throws ReflectionException
1144
+	 */
1145
+	protected function _get_registration_payment_IDs($payments = array())
1146
+	{
1147
+		$existing_reg_payments = array();
1148
+		// get all reg payments for these payments
1149
+		$reg_payments = EEM_Registration_Payment::instance()->get_all(array(
1150
+			array(
1151
+				'PAY_ID' => array(
1152
+					'IN',
1153
+					array_keys($payments),
1154
+				),
1155
+			),
1156
+		));
1157
+		if (! empty($reg_payments)) {
1158
+			foreach ($payments as $payment) {
1159
+				if (! $payment instanceof EE_Payment) {
1160
+					continue;
1161
+				} elseif (! isset($existing_reg_payments[$payment->ID()])) {
1162
+					$existing_reg_payments[$payment->ID()] = array();
1163
+				}
1164
+				foreach ($reg_payments as $reg_payment) {
1165
+					if ($reg_payment instanceof EE_Registration_Payment
1166
+						&& $reg_payment->payment_ID() === $payment->ID()
1167
+					) {
1168
+						$existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
1169
+					}
1170
+				}
1171
+			}
1172
+		}
1173
+
1174
+		return $existing_reg_payments;
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * _get_registrations_to_apply_payment_to
1180
+	 *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1181
+	 * which allows the admin to only apply the payment to the specific registrations
1182
+	 *
1183
+	 * @access protected
1184
+	 * @return void
1185
+	 * @throws \EE_Error
1186
+	 */
1187
+	protected function _get_registrations_to_apply_payment_to()
1188
+	{
1189
+		// we want any registration with an active status (ie: not deleted or cancelled)
1190
+		$query_params                      = array(
1191
+			array(
1192
+				'STS_ID' => array(
1193
+					'IN',
1194
+					array(
1195
+						EEM_Registration::status_id_approved,
1196
+						EEM_Registration::status_id_pending_payment,
1197
+						EEM_Registration::status_id_not_approved,
1198
+					),
1199
+				),
1200
+			),
1201
+		);
1202
+		$registrations_to_apply_payment_to = EEH_HTML::br()
1203
+											 . EEH_HTML::div(
1204
+												 '',
1205
+												 'txn-admin-apply-payment-to-registrations-dv',
1206
+												 '',
1207
+												 'clear: both; margin: 1.5em 0 0; display: none;'
1208
+											 );
1209
+		$registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1210
+		$registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1211
+		$registrations_to_apply_payment_to .= EEH_HTML::thead(
1212
+			EEH_HTML::tr(
1213
+				EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1214
+				EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1215
+				EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1216
+				EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1217
+				EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1218
+				EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1219
+				EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1220
+			)
1221
+		);
1222
+		$registrations_to_apply_payment_to .= EEH_HTML::tbody();
1223
+		// get registrations for TXN
1224
+		$registrations = $this->_transaction->registrations($query_params);
1225
+		$existing_reg_payments = $this->_template_args['existing_reg_payments'];
1226
+		foreach ($registrations as $registration) {
1227
+			if ($registration instanceof EE_Registration) {
1228
+				$attendee_name                     = $registration->attendee() instanceof EE_Attendee
1229
+					? $registration->attendee()->full_name()
1230
+					: esc_html__('Unknown Attendee', 'event_espresso');
1231
+				$owing                             = $registration->final_price() - $registration->paid();
1232
+				$taxable                           = $registration->ticket()->taxable()
1233
+					? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1234
+					: '';
1235
+				$checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1236
+					? ' checked="checked"'
1237
+					: '';
1238
+				$disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1239
+				$registrations_to_apply_payment_to .= EEH_HTML::tr(
1240
+					EEH_HTML::td($registration->ID()) .
1241
+					EEH_HTML::td($attendee_name) .
1242
+					EEH_HTML::td(
1243
+						$registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1244
+					) .
1245
+					EEH_HTML::td($registration->event_name()) .
1246
+					EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1247
+					EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1248
+					EEH_HTML::td(
1249
+						'<input type="checkbox" value="' . $registration->ID()
1250
+						. '" name="txn_admin_payment[registrations]"'
1251
+						. $checked . $disabled . '>',
1252
+						'',
1253
+						'jst-cntr'
1254
+					),
1255
+					'apply-payment-registration-row-' . $registration->ID()
1256
+				);
1257
+			}
1258
+		}
1259
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1260
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1261
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1262
+		$registrations_to_apply_payment_to                         .= EEH_HTML::p(
1263
+			esc_html__(
1264
+				'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1265
+				'event_espresso'
1266
+			),
1267
+			'',
1268
+			'clear description'
1269
+		);
1270
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1271
+		$this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * _get_reg_status_selection
1277
+	 *
1278
+	 * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1279
+	 *         instead of events.
1280
+	 * @access protected
1281
+	 * @return void
1282
+	 * @throws EE_Error
1283
+	 */
1284
+	protected function _get_reg_status_selection()
1285
+	{
1286
+		//first get all possible statuses
1287
+		$statuses = EEM_Registration::reg_status_array(array(), true);
1288
+		//let's add a "don't change" option.
1289
+		$status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1290
+		$status_array                                        = array_merge($status_array, $statuses);
1291
+		$this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1292
+			'txn_reg_status_change[reg_status]',
1293
+			$status_array,
1294
+			'NAN',
1295
+			'id="txn-admin-payment-reg-status-inp"',
1296
+			'txn-reg-status-change-reg-status'
1297
+		);
1298
+		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1299
+			'delete_txn_reg_status_change[reg_status]',
1300
+			$status_array,
1301
+			'NAN',
1302
+			'delete-txn-admin-payment-reg-status-inp',
1303
+			'delete-txn-reg-status-change-reg-status'
1304
+		);
1305
+	}
1306
+
1307
+
1308
+	/**
1309
+	 *    _get_payment_methods
1310
+	 * Gets all the payment methods available generally, or the ones that are already
1311
+	 * selected on these payments (in case their payment methods are no longer active).
1312
+	 * Has the side-effect of updating the template args' payment_methods item
1313
+	 *
1314
+	 * @access private
1315
+	 * @param EE_Payment[] to show on this page
1316
+	 * @return void
1317
+	 * @throws EE_Error
1318
+	 * @throws InvalidArgumentException
1319
+	 * @throws InvalidDataTypeException
1320
+	 * @throws InvalidInterfaceException
1321
+	 * @throws ReflectionException
1322
+	 */
1323
+	private function _get_payment_methods($payments = array())
1324
+	{
1325
+		$payment_methods_of_payments = array();
1326
+		foreach ($payments as $payment) {
1327
+			if ($payment instanceof EE_Payment) {
1328
+				$payment_methods_of_payments[] = $payment->get('PMD_ID');
1329
+			}
1330
+		}
1331
+		if ($payment_methods_of_payments) {
1332
+			$query_args = array(
1333
+				array(
1334
+					'OR*payment_method_for_payment' => array(
1335
+						'PMD_ID'    => array('IN', $payment_methods_of_payments),
1336
+						'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1337
+					),
1338
+				),
1339
+			);
1340
+		} else {
1341
+			$query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1342
+		}
1343
+		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1344
+	}
1345
+
1346
+
1347
+	/**
1348
+	 * txn_attendees_meta_box
1349
+	 *    generates HTML for the Attendees Transaction main meta box
1350
+	 *
1351
+	 * @access public
1352
+	 * @param WP_Post $post
1353
+	 * @param array   $metabox
1354
+	 * @return void
1355
+	 * @throws DomainException
1356
+	 * @throws EE_Error
1357
+	 */
1358
+	public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1359
+	{
1360
+
1361
+		/** @noinspection NonSecureExtractUsageInspection */
1362
+		extract($metabox['args']);
1363
+		$this->_template_args['post']            = $post;
1364
+		$this->_template_args['event_attendees'] = array();
1365
+		// process items in cart
1366
+		$line_items = $this->_transaction->get_many_related(
1367
+			'Line_Item',
1368
+			array(array('LIN_type' => 'line-item'))
1369
+		);
1370
+		if (! empty($line_items)) {
1371
+			foreach ($line_items as $item) {
1372
+				if ($item instanceof EE_Line_Item) {
1373
+					switch ($item->OBJ_type()) {
1374
+						case 'Event':
1375
+							break;
1376
+						case 'Ticket':
1377
+							$ticket = $item->ticket();
1378
+							//right now we're only handling tickets here.
1379
+							//Cause its expected that only tickets will have attendees right?
1380
+							if (! $ticket instanceof EE_Ticket) {
1381
+								continue;
1382
+							}
1383
+							try {
1384
+								$event_name = $ticket->get_event_name();
1385
+							} catch (Exception $e) {
1386
+								EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1387
+								$event_name = esc_html__('Unknown Event', 'event_espresso');
1388
+							}
1389
+							$event_name   .= ' - ' . $item->get('LIN_name');
1390
+							$ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1391
+							// now get all of the registrations for this transaction that use this ticket
1392
+							$registrations = $ticket->get_many_related(
1393
+								'Registration',
1394
+								array(array('TXN_ID' => $this->_transaction->ID()))
1395
+							);
1396
+							foreach ($registrations as $registration) {
1397
+								if (! $registration instanceof EE_Registration) {
1398
+									continue;
1399
+								}
1400
+								$this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
1401
+									= $registration->status_ID();
1402
+								$this->_template_args['event_attendees'][$registration->ID()]['att_num']
1403
+									= $registration->count();
1404
+								$this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name']
1405
+									= $event_name;
1406
+								$this->_template_args['event_attendees'][$registration->ID()]['ticket_price']
1407
+									= $ticket_price;
1408
+								// attendee info
1409
+								$attendee = $registration->get_first_related('Attendee');
1410
+								if ($attendee instanceof EE_Attendee) {
1411
+									$this->_template_args['event_attendees'][$registration->ID()]['att_id']
1412
+										= $attendee->ID();
1413
+									$this->_template_args['event_attendees'][$registration->ID()]['attendee']
1414
+										= $attendee->full_name();
1415
+									$this->_template_args['event_attendees'][$registration->ID()]['email']
1416
+										= '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1417
+										  . esc_html__(
1418
+											  ' Event',
1419
+											  'event_espresso'
1420
+										  )
1421
+										  . '">' . $attendee->email() . '</a>';
1422
+									$this->_template_args['event_attendees'][$registration->ID()]['address']
1423
+										= EEH_Address::format($attendee, 'inline', false, false);
1424
+								} else {
1425
+									$this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1426
+									$this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1427
+									$this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1428
+									$this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1429
+								}
1430
+							}
1431
+							break;
1432
+
1433
+					}
1434
+				}
1435
+			}
1436
+
1437
+			$this->_template_args['transaction_form_url'] = add_query_arg(
1438
+				array(
1439
+					'action'  => 'edit_transaction',
1440
+					'process' => 'attendees',
1441
+				),
1442
+				TXN_ADMIN_URL
1443
+			);
1444
+			echo EEH_Template::display_template(
1445
+				TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1446
+				$this->_template_args,
1447
+				true
1448
+			);
1449
+
1450
+		} else {
1451
+			echo sprintf(
1452
+				esc_html__(
1453
+					'%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1454
+					'event_espresso'
1455
+				),
1456
+				'<p class="important-notice">',
1457
+				'</p>'
1458
+			);
1459
+		}
1460
+	}
1461
+
1462
+
1463
+	/**
1464
+	 * txn_registrant_side_meta_box
1465
+	 * generates HTML for the Edit Transaction side meta box
1466
+	 *
1467
+	 * @access public
1468
+	 * @return void
1469
+	 * @throws DomainException
1470
+	 * @throws EE_Error
1471
+	 * @throws InvalidArgumentException
1472
+	 * @throws InvalidDataTypeException
1473
+	 * @throws InvalidInterfaceException
1474
+	 * @throws ReflectionException
1475
+	 */
1476
+	public function txn_registrant_side_meta_box()
1477
+	{
1478
+		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1479
+			? $this->_transaction->primary_registration()->get_first_related('Attendee')
1480
+			: null;
1481
+		if (! $primary_att instanceof EE_Attendee) {
1482
+			$this->_template_args['no_attendee_message'] = esc_html__(
1483
+				'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1484
+				'event_espresso'
1485
+			);
1486
+			$primary_att                                 = EEM_Attendee::instance()->create_default_object();
1487
+		}
1488
+		$this->_template_args['ATT_ID']            = $primary_att->ID();
1489
+		$this->_template_args['prime_reg_fname']   = $primary_att->fname();
1490
+		$this->_template_args['prime_reg_lname']   = $primary_att->lname();
1491
+		$this->_template_args['prime_reg_email']   = $primary_att->email();
1492
+		$this->_template_args['prime_reg_phone']   = $primary_att->phone();
1493
+		$this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(array(
1494
+			'action' => 'edit_attendee',
1495
+			'post'   => $primary_att->ID(),
1496
+		), REG_ADMIN_URL);
1497
+		// get formatted address for registrant
1498
+		$this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1499
+		echo EEH_Template::display_template(
1500
+			TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1501
+			$this->_template_args,
1502
+			true
1503
+		);
1504
+	}
1505
+
1506
+
1507
+	/**
1508
+	 * txn_billing_info_side_meta_box
1509
+	 *    generates HTML for the Edit Transaction side meta box
1510
+	 *
1511
+	 * @access public
1512
+	 * @return void
1513
+	 * @throws DomainException
1514
+	 * @throws EE_Error
1515
+	 */
1516
+	public function txn_billing_info_side_meta_box()
1517
+	{
1518
+
1519
+		$this->_template_args['billing_form']     = $this->_transaction->billing_info();
1520
+		$this->_template_args['billing_form_url'] = add_query_arg(
1521
+			array('action' => 'edit_transaction', 'process' => 'billing'),
1522
+			TXN_ADMIN_URL
1523
+		);
1524
+
1525
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1526
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1527
+	}
1528
+
1529
+
1530
+	/**
1531
+	 * apply_payments_or_refunds
1532
+	 *    registers a payment or refund made towards a transaction
1533
+	 *
1534
+	 * @access public
1535
+	 * @return void
1536
+	 * @throws EE_Error
1537
+	 * @throws InvalidArgumentException
1538
+	 * @throws ReflectionException
1539
+	 * @throws RuntimeException
1540
+	 * @throws InvalidDataTypeException
1541
+	 * @throws InvalidInterfaceException
1542
+	 */
1543
+	public function apply_payments_or_refunds()
1544
+	{
1545
+		$json_response_data = array('return_data' => false);
1546
+		$valid_data         = $this->_validate_payment_request_data();
1547
+		$has_access = EE_Registry::instance()->CAP->current_user_can(
1548
+			'ee_edit_payments',
1549
+			'apply_payment_or_refund_from_registration_details'
1550
+		);
1551
+		if (! empty($valid_data) && $has_access) {
1552
+			$PAY_ID = $valid_data['PAY_ID'];
1553
+			//save  the new payment
1554
+			$payment = $this->_create_payment_from_request_data($valid_data);
1555
+			// get the TXN for this payment
1556
+			$transaction = $payment->transaction();
1557
+			// verify transaction
1558
+			if ($transaction instanceof EE_Transaction) {
1559
+				// calculate_total_payments_and_update_status
1560
+				$this->_process_transaction_payments($transaction);
1561
+				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1562
+				$this->_remove_existing_registration_payments($payment, $PAY_ID);
1563
+				// apply payment to registrations (if applicable)
1564
+				if (! empty($REG_IDs)) {
1565
+					$this->_update_registration_payments($transaction, $payment, $REG_IDs);
1566
+					$this->_maybe_send_notifications();
1567
+					// now process status changes for the same registrations
1568
+					$this->_process_registration_status_change($transaction, $REG_IDs);
1569
+				}
1570
+				$this->_maybe_send_notifications($payment);
1571
+				//prepare to render page
1572
+				$json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1573
+				do_action(
1574
+					'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1575
+					$transaction,
1576
+					$payment
1577
+				);
1578
+			} else {
1579
+				EE_Error::add_error(
1580
+					esc_html__(
1581
+						'A valid Transaction for this payment could not be retrieved.',
1582
+						'event_espresso'
1583
+					),
1584
+					__FILE__,
1585
+					__FUNCTION__,
1586
+					__LINE__
1587
+				);
1588
+			}
1589
+		} else {
1590
+			if ($has_access) {
1591
+				EE_Error::add_error(
1592
+					esc_html__(
1593
+						'The payment form data could not be processed. Please try again.',
1594
+						'event_espresso'
1595
+					),
1596
+					__FILE__,
1597
+					__FUNCTION__,
1598
+					__LINE__
1599
+				);
1600
+			} else {
1601
+				EE_Error::add_error(
1602
+					esc_html__(
1603
+						'You do not have access to apply payments or refunds to a registration.',
1604
+						'event_espresso'
1605
+					),
1606
+					__FILE__,
1607
+					__FUNCTION__,
1608
+					__LINE__
1609
+				);
1610
+			}
1611
+		}
1612
+		$notices              = EE_Error::get_notices(
1613
+			false,
1614
+			false,
1615
+			false
1616
+		);
1617
+		$this->_template_args = array(
1618
+			'data'    => $json_response_data,
1619
+			'error'   => $notices['errors'],
1620
+			'success' => $notices['success'],
1621
+		);
1622
+		$this->_return_json();
1623
+	}
1624
+
1625
+
1626
+	/**
1627
+	 * _validate_payment_request_data
1628
+	 *
1629
+	 * @return array
1630
+	 * @throws EE_Error
1631
+	 */
1632
+	protected function _validate_payment_request_data()
1633
+	{
1634
+		if (! isset($this->_req_data['txn_admin_payment'])) {
1635
+			return false;
1636
+		}
1637
+		$payment_form = $this->_generate_payment_form_section();
1638
+		try {
1639
+			if ($payment_form->was_submitted()) {
1640
+				$payment_form->receive_form_submission();
1641
+				if (! $payment_form->is_valid()) {
1642
+					$submission_error_messages = array();
1643
+					foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1644
+						if ($validation_error instanceof EE_Validation_Error) {
1645
+							$submission_error_messages[] = sprintf(
1646
+								_x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1647
+								$validation_error->get_form_section()->html_label_text(),
1648
+								$validation_error->getMessage()
1649
+							);
1650
+						}
1651
+					}
1652
+					EE_Error::add_error(
1653
+						implode('<br />', $submission_error_messages),
1654
+						__FILE__,
1655
+						__FUNCTION__,
1656
+						__LINE__
1657
+					);
1658
+
1659
+					return array();
1660
+				}
1661
+			}
1662
+		} catch (EE_Error $e) {
1663
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1664
+
1665
+			return array();
1666
+		}
1667
+
1668
+		return $payment_form->valid_data();
1669
+	}
1670
+
1671
+
1672
+	/**
1673
+	 * _generate_payment_form_section
1674
+	 *
1675
+	 * @return EE_Form_Section_Proper
1676
+	 * @throws EE_Error
1677
+	 */
1678
+	protected function _generate_payment_form_section()
1679
+	{
1680
+		return new EE_Form_Section_Proper(
1681
+			array(
1682
+				'name'        => 'txn_admin_payment',
1683
+				'subsections' => array(
1684
+					'PAY_ID'          => new EE_Text_Input(
1685
+						array(
1686
+							'default'               => 0,
1687
+							'required'              => false,
1688
+							'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1689
+							'validation_strategies' => array(new EE_Int_Normalization()),
1690
+						)
1691
+					),
1692
+					'TXN_ID'          => new EE_Text_Input(
1693
+						array(
1694
+							'default'               => 0,
1695
+							'required'              => true,
1696
+							'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1697
+							'validation_strategies' => array(new EE_Int_Normalization()),
1698
+						)
1699
+					),
1700
+					'type'            => new EE_Text_Input(
1701
+						array(
1702
+							'default'               => 1,
1703
+							'required'              => true,
1704
+							'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1705
+							'validation_strategies' => array(new EE_Int_Normalization()),
1706
+						)
1707
+					),
1708
+					'amount'          => new EE_Text_Input(
1709
+						array(
1710
+							'default'               => 0,
1711
+							'required'              => true,
1712
+							'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1713
+							'validation_strategies' => array(new EE_Float_Normalization()),
1714
+						)
1715
+					),
1716
+					'status'          => new EE_Text_Input(
1717
+						array(
1718
+							'default'         => EEM_Payment::status_id_approved,
1719
+							'required'        => true,
1720
+							'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1721
+						)
1722
+					),
1723
+					'PMD_ID'          => new EE_Text_Input(
1724
+						array(
1725
+							'default'               => 2,
1726
+							'required'              => true,
1727
+							'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1728
+							'validation_strategies' => array(new EE_Int_Normalization()),
1729
+						)
1730
+					),
1731
+					'date'            => new EE_Text_Input(
1732
+						array(
1733
+							'default'         => time(),
1734
+							'required'        => true,
1735
+							'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1736
+						)
1737
+					),
1738
+					'txn_id_chq_nmbr' => new EE_Text_Input(
1739
+						array(
1740
+							'default'               => '',
1741
+							'required'              => false,
1742
+							'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1743
+							'validation_strategies' => array(
1744
+								new EE_Max_Length_Validation_Strategy(
1745
+									esc_html__('Input too long', 'event_espresso'),
1746
+									100
1747
+								),
1748
+							),
1749
+						)
1750
+					),
1751
+					'po_number'       => new EE_Text_Input(
1752
+						array(
1753
+							'default'               => '',
1754
+							'required'              => false,
1755
+							'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1756
+							'validation_strategies' => array(
1757
+								new EE_Max_Length_Validation_Strategy(
1758
+									esc_html__('Input too long', 'event_espresso'),
1759
+									100
1760
+								),
1761
+							),
1762
+						)
1763
+					),
1764
+					'accounting'      => new EE_Text_Input(
1765
+						array(
1766
+							'default'               => '',
1767
+							'required'              => false,
1768
+							'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1769
+							'validation_strategies' => array(
1770
+								new EE_Max_Length_Validation_Strategy(
1771
+									esc_html__('Input too long', 'event_espresso'),
1772
+									100
1773
+								),
1774
+							),
1775
+						)
1776
+					),
1777
+				),
1778
+			)
1779
+		);
1780
+	}
1781
+
1782
+
1783
+	/**
1784
+	 * _create_payment_from_request_data
1785
+	 *
1786
+	 * @param array $valid_data
1787
+	 * @return EE_Payment
1788
+	 * @throws EE_Error
1789
+	 */
1790
+	protected function _create_payment_from_request_data($valid_data)
1791
+	{
1792
+		$PAY_ID = $valid_data['PAY_ID'];
1793
+		// get payment amount
1794
+		$amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1795
+		// payments have a type value of 1 and refunds have a type value of -1
1796
+		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1797
+		$amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1798
+		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1799
+		$date    = $valid_data['date']
1800
+			? preg_replace('/\s+/', ' ', $valid_data['date'])
1801
+			: date('Y-m-d g:i a', current_time('timestamp'));
1802
+		$payment = EE_Payment::new_instance(
1803
+			array(
1804
+				'TXN_ID'              => $valid_data['TXN_ID'],
1805
+				'STS_ID'              => $valid_data['status'],
1806
+				'PAY_timestamp'       => $date,
1807
+				'PAY_source'          => EEM_Payment_Method::scope_admin,
1808
+				'PMD_ID'              => $valid_data['PMD_ID'],
1809
+				'PAY_amount'          => $amount,
1810
+				'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1811
+				'PAY_po_number'       => $valid_data['po_number'],
1812
+				'PAY_extra_accntng'   => $valid_data['accounting'],
1813
+				'PAY_details'         => $valid_data,
1814
+				'PAY_ID'              => $PAY_ID,
1815
+			),
1816
+			'',
1817
+			array('Y-m-d', 'g:i a')
1818
+		);
1819
+
1820
+		if (! $payment->save()) {
1821
+			EE_Error::add_error(
1822
+				sprintf(
1823
+					esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1824
+					$payment->ID()
1825
+				),
1826
+				__FILE__, __FUNCTION__, __LINE__
1827
+			);
1828
+		}
1829
+
1830
+		return $payment;
1831
+	}
1832
+
1833
+
1834
+	/**
1835
+	 * _process_transaction_payments
1836
+	 *
1837
+	 * @param \EE_Transaction $transaction
1838
+	 * @return void
1839
+	 * @throws EE_Error
1840
+	 * @throws InvalidArgumentException
1841
+	 * @throws ReflectionException
1842
+	 * @throws InvalidDataTypeException
1843
+	 * @throws InvalidInterfaceException
1844
+	 */
1845
+	protected function _process_transaction_payments(EE_Transaction $transaction)
1846
+	{
1847
+		/** @type EE_Transaction_Payments $transaction_payments */
1848
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1849
+		//update the transaction with this payment
1850
+		if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1851
+			EE_Error::add_success(esc_html__(
1852
+				'The payment has been processed successfully.', 'event_espresso'),
1853
+				__FILE__,
1854
+				__FUNCTION__,
1855
+				__LINE__
1856
+			);
1857
+		} else {
1858
+			EE_Error::add_error(
1859
+				esc_html__(
1860
+					'The payment was processed successfully but the amount paid for the transaction was not updated.',
1861
+					'event_espresso'
1862
+				)
1863
+				,
1864
+				__FILE__,
1865
+				__FUNCTION__,
1866
+				__LINE__
1867
+			);
1868
+		}
1869
+	}
1870
+
1871
+
1872
+	/**
1873
+	 * _get_REG_IDs_to_apply_payment_to
1874
+	 * returns a list of registration IDs that the payment will apply to
1875
+	 *
1876
+	 * @param \EE_Payment $payment
1877
+	 * @return array
1878
+	 * @throws EE_Error
1879
+	 */
1880
+	protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1881
+	{
1882
+		$REG_IDs = array();
1883
+		// grab array of IDs for specific registrations to apply changes to
1884
+		if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1885
+			$REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1886
+		}
1887
+		//nothing specified ? then get all reg IDs
1888
+		if (empty($REG_IDs)) {
1889
+			$registrations = $payment->transaction()->registrations();
1890
+			$REG_IDs       = ! empty($registrations)
1891
+				? array_keys($registrations)
1892
+				: $this->_get_existing_reg_payment_REG_IDs($payment);
1893
+		}
1894
+
1895
+		// ensure that REG_IDs are integers and NOT strings
1896
+		return array_map('intval', $REG_IDs);
1897
+	}
1898
+
1899
+
1900
+	/**
1901
+	 * @return array
1902
+	 */
1903
+	public function existing_reg_payment_REG_IDs()
1904
+	{
1905
+		return $this->_existing_reg_payment_REG_IDs;
1906
+	}
1907
+
1908
+
1909
+	/**
1910
+	 * @param array $existing_reg_payment_REG_IDs
1911
+	 */
1912
+	public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1913
+	{
1914
+		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1915
+	}
1916
+
1917
+
1918
+	/**
1919
+	 * _get_existing_reg_payment_REG_IDs
1920
+	 * returns a list of registration IDs that the payment is currently related to
1921
+	 * as recorded in the database
1922
+	 *
1923
+	 * @param \EE_Payment $payment
1924
+	 * @return array
1925
+	 * @throws EE_Error
1926
+	 */
1927
+	protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1928
+	{
1929
+		if ($this->existing_reg_payment_REG_IDs() === null) {
1930
+			// let's get any existing reg payment records for this payment
1931
+			$existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1932
+			// but we only want the REG IDs, so grab the array keys
1933
+			$existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
1934
+				? array_keys($existing_reg_payment_REG_IDs)
1935
+				: array();
1936
+			$this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1937
+		}
1938
+
1939
+		return $this->existing_reg_payment_REG_IDs();
1940
+	}
1941
+
1942
+
1943
+	/**
1944
+	 * _remove_existing_registration_payments
1945
+	 * this calculates the difference between existing relations
1946
+	 * to the supplied payment and the new list registration IDs,
1947
+	 * removes any related registrations that no longer apply,
1948
+	 * and then updates the registration paid fields
1949
+	 *
1950
+	 * @param \EE_Payment $payment
1951
+	 * @param int         $PAY_ID
1952
+	 * @return bool;
1953
+	 * @throws EE_Error
1954
+	 * @throws InvalidArgumentException
1955
+	 * @throws ReflectionException
1956
+	 * @throws InvalidDataTypeException
1957
+	 * @throws InvalidInterfaceException
1958
+	 */
1959
+	protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1960
+	{
1961
+		// newly created payments will have nothing recorded for $PAY_ID
1962
+		if ($PAY_ID == 0) {
1963
+			return false;
1964
+		}
1965
+		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1966
+		if (empty($existing_reg_payment_REG_IDs)) {
1967
+			return false;
1968
+		}
1969
+		/** @type EE_Transaction_Payments $transaction_payments */
1970
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1971
+
1972
+		return $transaction_payments->delete_registration_payments_and_update_registrations(
1973
+			$payment,
1974
+			array(
1975
+				array(
1976
+					'PAY_ID' => $payment->ID(),
1977
+					'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
1978
+				),
1979
+			)
1980
+		);
1981
+	}
1982
+
1983
+
1984
+	/**
1985
+	 * _update_registration_payments
1986
+	 * this applies the payments to the selected registrations
1987
+	 * but only if they have not already been paid for
1988
+	 *
1989
+	 * @param  EE_Transaction $transaction
1990
+	 * @param \EE_Payment     $payment
1991
+	 * @param array           $REG_IDs
1992
+	 * @return void
1993
+	 * @throws EE_Error
1994
+	 * @throws InvalidArgumentException
1995
+	 * @throws ReflectionException
1996
+	 * @throws RuntimeException
1997
+	 * @throws InvalidDataTypeException
1998
+	 * @throws InvalidInterfaceException
1999
+	 */
2000
+	protected function _update_registration_payments(
2001
+		EE_Transaction $transaction,
2002
+		EE_Payment $payment,
2003
+		$REG_IDs = array()
2004
+	) {
2005
+		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2006
+		// so let's do that using our set of REG_IDs from the form
2007
+		$registration_query_where_params = array(
2008
+			'REG_ID' => array('IN', $REG_IDs),
2009
+		);
2010
+		// but add in some conditions regarding payment,
2011
+		// so that we don't apply payments to registrations that are free or have already been paid for
2012
+		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2013
+		if (! $payment->is_a_refund()) {
2014
+			$registration_query_where_params['REG_final_price']  = array('!=', 0);
2015
+			$registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2016
+		}
2017
+		$registrations = $transaction->registrations(array($registration_query_where_params));
2018
+		if (! empty($registrations)) {
2019
+			/** @type EE_Payment_Processor $payment_processor */
2020
+			$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2021
+			$payment_processor->process_registration_payments($transaction, $payment, $registrations);
2022
+		}
2023
+	}
2024
+
2025
+
2026
+	/**
2027
+	 * _process_registration_status_change
2028
+	 * This processes requested registration status changes for all the registrations
2029
+	 * on a given transaction and (optionally) sends out notifications for the changes.
2030
+	 *
2031
+	 * @param  EE_Transaction $transaction
2032
+	 * @param array           $REG_IDs
2033
+	 * @return bool
2034
+	 * @throws EE_Error
2035
+	 * @throws InvalidArgumentException
2036
+	 * @throws ReflectionException
2037
+	 * @throws InvalidDataTypeException
2038
+	 * @throws InvalidInterfaceException
2039
+	 */
2040
+	protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2041
+	{
2042
+		// first if there is no change in status then we get out.
2043
+		if (
2044
+			! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2045
+			|| $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2046
+		) {
2047
+			//no error message, no change requested, just nothing to do man.
2048
+			return false;
2049
+		}
2050
+		/** @type EE_Transaction_Processor $transaction_processor */
2051
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2052
+
2053
+		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2054
+		return $transaction_processor->manually_update_registration_statuses(
2055
+			$transaction,
2056
+			sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
2057
+			array(array('REG_ID' => array('IN', $REG_IDs)))
2058
+		);
2059
+	}
2060
+
2061
+
2062
+	/**
2063
+	 * _build_payment_json_response
2064
+	 *
2065
+	 * @access public
2066
+	 * @param \EE_Payment $payment
2067
+	 * @param array       $REG_IDs
2068
+	 * @param bool | null $delete_txn_reg_status_change
2069
+	 * @return array
2070
+	 * @throws EE_Error
2071
+	 * @throws InvalidArgumentException
2072
+	 * @throws InvalidDataTypeException
2073
+	 * @throws InvalidInterfaceException
2074
+	 * @throws ReflectionException
2075
+	 */
2076
+	protected function _build_payment_json_response(
2077
+		EE_Payment $payment,
2078
+		$REG_IDs = array(),
2079
+		$delete_txn_reg_status_change = null
2080
+	) {
2081
+		// was the payment deleted ?
2082
+		if (is_bool($delete_txn_reg_status_change)) {
2083
+			return array(
2084
+				'PAY_ID'                       => $payment->ID(),
2085
+				'amount'                       => $payment->amount(),
2086
+				'total_paid'                   => $payment->transaction()->paid(),
2087
+				'txn_status'                   => $payment->transaction()->status_ID(),
2088
+				'pay_status'                   => $payment->STS_ID(),
2089
+				'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2090
+				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2091
+			);
2092
+		} else {
2093
+			$this->_get_payment_status_array();
2094
+
2095
+			return array(
2096
+				'amount'           => $payment->amount(),
2097
+				'total_paid'       => $payment->transaction()->paid(),
2098
+				'txn_status'       => $payment->transaction()->status_ID(),
2099
+				'pay_status'       => $payment->STS_ID(),
2100
+				'PAY_ID'           => $payment->ID(),
2101
+				'STS_ID'           => $payment->STS_ID(),
2102
+				'status'           => self::$_pay_status[$payment->STS_ID()],
2103
+				'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2104
+				'method'           => strtoupper($payment->source()),
2105
+				'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2106
+				'gateway'          => $payment->payment_method()
2107
+					? $payment->payment_method()->admin_name()
2108
+					: esc_html__("Unknown", 'event_espresso'),
2109
+				'gateway_response' => $payment->gateway_response(),
2110
+				'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2111
+				'po_number'        => $payment->po_number(),
2112
+				'extra_accntng'    => $payment->extra_accntng(),
2113
+				'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2114
+			);
2115
+		}
2116
+	}
2117
+
2118
+
2119
+	/**
2120
+	 * delete_payment
2121
+	 *    delete a payment or refund made towards a transaction
2122
+	 *
2123
+	 * @access public
2124
+	 * @return void
2125
+	 * @throws EE_Error
2126
+	 * @throws InvalidArgumentException
2127
+	 * @throws ReflectionException
2128
+	 * @throws InvalidDataTypeException
2129
+	 * @throws InvalidInterfaceException
2130
+	 */
2131
+	public function delete_payment()
2132
+	{
2133
+		$json_response_data = array('return_data' => false);
2134
+		$PAY_ID             = isset($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2135
+			? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2136
+			: 0;
2137
+		$can_delete = EE_Registry::instance()->CAP->current_user_can(
2138
+			'ee_delete_payments',
2139
+			'delete_payment_from_registration_details'
2140
+		);
2141
+		if ($PAY_ID && $can_delete) {
2142
+			$delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change'])
2143
+				? $this->_req_data['delete_txn_reg_status_change']
2144
+				: false;
2145
+			$payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2146
+			if ($payment instanceof EE_Payment) {
2147
+				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2148
+				/** @type EE_Transaction_Payments $transaction_payments */
2149
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2150
+				if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2151
+					$json_response_data['return_data'] = $this->_build_payment_json_response(
2152
+						$payment,
2153
+						$REG_IDs,
2154
+						$delete_txn_reg_status_change
2155
+					);
2156
+					if ($delete_txn_reg_status_change) {
2157
+						$this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
2158
+						//MAKE sure we also add the delete_txn_req_status_change to the
2159
+						//$_REQUEST global because that's how messages will be looking for it.
2160
+						$_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
2161
+						$this->_maybe_send_notifications();
2162
+						$this->_process_registration_status_change($payment->transaction(), $REG_IDs);
2163
+					}
2164
+				}
2165
+			} else {
2166
+				EE_Error::add_error(
2167
+					esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2168
+					__FILE__, __FUNCTION__, __LINE__
2169
+				);
2170
+			}
2171
+		} else {
2172
+			if ($can_delete) {
2173
+				EE_Error::add_error(
2174
+					esc_html__(
2175
+						'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2176
+						'event_espresso'
2177
+					),
2178
+					__FILE__, __FUNCTION__, __LINE__
2179
+				);
2180
+			} else {
2181
+				EE_Error::add_error(
2182
+					esc_html__(
2183
+						'You do not have access to delete a payment.',
2184
+						'event_espresso'
2185
+					),
2186
+					__FILE__,
2187
+					__FUNCTION__,
2188
+					__LINE__
2189
+				);
2190
+			}
2191
+		}
2192
+		$notices              = EE_Error::get_notices(false, false, false);
2193
+		$this->_template_args = array(
2194
+			'data'      => $json_response_data,
2195
+			'success'   => $notices['success'],
2196
+			'error'     => $notices['errors'],
2197
+			'attention' => $notices['attention'],
2198
+		);
2199
+		$this->_return_json();
2200
+	}
2201
+
2202
+
2203
+	/**
2204
+	 * _registration_payment_data_array
2205
+	 * adds info for 'owing' and 'paid' for each registration to the json response
2206
+	 *
2207
+	 * @access protected
2208
+	 * @param array $REG_IDs
2209
+	 * @return array
2210
+	 * @throws EE_Error
2211
+	 * @throws InvalidArgumentException
2212
+	 * @throws InvalidDataTypeException
2213
+	 * @throws InvalidInterfaceException
2214
+	 * @throws ReflectionException
2215
+	 */
2216
+	protected function _registration_payment_data_array($REG_IDs)
2217
+	{
2218
+		$registration_payment_data = array();
2219
+		//if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2220
+		if (! empty($REG_IDs)) {
2221
+			$registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2222
+			foreach ($registrations as $registration) {
2223
+				if ($registration instanceof EE_Registration) {
2224
+					$registration_payment_data[$registration->ID()] = array(
2225
+						'paid'  => $registration->pretty_paid(),
2226
+						'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2227
+					);
2228
+				}
2229
+			}
2230
+		}
2231
+
2232
+		return $registration_payment_data;
2233
+	}
2234
+
2235
+
2236
+	/**
2237
+	 * _maybe_send_notifications
2238
+	 * determines whether or not the admin has indicated that notifications should be sent.
2239
+	 * If so, will toggle a filter switch for delivering registration notices.
2240
+	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
2241
+	 *
2242
+	 * @access protected
2243
+	 * @param \EE_Payment | null $payment
2244
+	 */
2245
+	protected function _maybe_send_notifications($payment = null)
2246
+	{
2247
+		switch ($payment instanceof EE_Payment) {
2248
+			// payment notifications
2249
+			case true :
2250
+				if (
2251
+					isset(
2252
+						$this->_req_data['txn_payments'],
2253
+						$this->_req_data['txn_payments']['send_notifications']
2254
+					) &&
2255
+					filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2256
+				) {
2257
+					$this->_process_payment_notification($payment);
2258
+				}
2259
+				break;
2260
+			// registration notifications
2261
+			case false :
2262
+				if (
2263
+					isset(
2264
+						$this->_req_data['txn_reg_status_change'],
2265
+						$this->_req_data['txn_reg_status_change']['send_notifications']
2266
+					) &&
2267
+					filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2268
+				) {
2269
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2270
+				}
2271
+				break;
2272
+		}
2273
+	}
2274
+
2275
+
2276
+	/**
2277
+	 * _send_payment_reminder
2278
+	 *    generates HTML for the View Transaction Details Admin page
2279
+	 *
2280
+	 * @access protected
2281
+	 * @return void
2282
+	 * @throws EE_Error
2283
+	 * @throws InvalidArgumentException
2284
+	 * @throws InvalidDataTypeException
2285
+	 * @throws InvalidInterfaceException
2286
+	 */
2287
+	protected function _send_payment_reminder()
2288
+	{
2289
+		$TXN_ID      = ! empty($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : false;
2290
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2291
+		$query_args  = isset($this->_req_data['redirect_to']) ? array(
2292
+			'action' => $this->_req_data['redirect_to'],
2293
+			'TXN_ID' => $this->_req_data['TXN_ID'],
2294
+		) : array();
2295
+		do_action(
2296
+			'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2297
+			$transaction
2298
+		);
2299
+		$this->_redirect_after_action(
2300
+			false,
2301
+			esc_html__('payment reminder', 'event_espresso'),
2302
+			esc_html__('sent', 'event_espresso'),
2303
+			$query_args,
2304
+			true
2305
+		);
2306
+	}
2307
+
2308
+
2309
+	/**
2310
+	 *  get_transactions
2311
+	 *    get transactions for given parameters (used by list table)
2312
+	 *
2313
+	 * @param  int     $perpage how many transactions displayed per page
2314
+	 * @param  boolean $count   return the count or objects
2315
+	 * @param string   $view
2316
+	 * @return mixed int = count || array of transaction objects
2317
+	 * @throws EE_Error
2318
+	 * @throws InvalidArgumentException
2319
+	 * @throws InvalidDataTypeException
2320
+	 * @throws InvalidInterfaceException
2321
+	 */
2322
+	public function get_transactions($perpage, $count = false, $view = '')
2323
+	{
2324
+
2325
+		$TXN = EEM_Transaction::instance();
2326
+
2327
+		$start_date = isset($this->_req_data['txn-filter-start-date'])
2328
+			? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
2329
+			: date(
2330
+				'm/d/Y',
2331
+				strtotime('-10 year')
2332
+			);
2333
+		$end_date   = isset($this->_req_data['txn-filter-end-date'])
2334
+			? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2335
+			: date('m/d/Y');
2336
+
2337
+		//make sure our timestamps start and end right at the boundaries for each day
2338
+		$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2339
+		$end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2340
+
2341
+
2342
+		//convert to timestamps
2343
+		$start_date = strtotime($start_date);
2344
+		$end_date   = strtotime($end_date);
2345
+
2346
+		//makes sure start date is the lowest value and vice versa
2347
+		$start_date = min($start_date, $end_date);
2348
+		$end_date   = max($start_date, $end_date);
2349
+
2350
+		//convert to correct format for query
2351
+		$start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2352
+			'TXN_timestamp',
2353
+			date('Y-m-d H:i:s', $start_date),
2354
+			'Y-m-d H:i:s'
2355
+		);
2356
+		$end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2357
+			'TXN_timestamp',
2358
+			date('Y-m-d H:i:s', $end_date),
2359
+			'Y-m-d H:i:s'
2360
+		);
2361
+
2362
+
2363
+		//set orderby
2364
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
2365
+
2366
+		switch ($this->_req_data['orderby']) {
2367
+			case 'TXN_ID':
2368
+				$orderby = 'TXN_ID';
2369
+				break;
2370
+			case 'ATT_fname':
2371
+				$orderby = 'Registration.Attendee.ATT_fname';
2372
+				break;
2373
+			case 'event_name':
2374
+				$orderby = 'Registration.Event.EVT_name';
2375
+				break;
2376
+			default: //'TXN_timestamp'
2377
+				$orderby = 'TXN_timestamp';
2378
+		}
2379
+
2380
+		$sort         = ! empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2381
+		$current_page = ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
2382
+		$per_page     = ! empty($perpage) ? $perpage : 10;
2383
+		$per_page     = ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
2384
+
2385
+		$offset = ($current_page - 1) * $per_page;
2386
+		$limit  = array($offset, $per_page);
2387
+
2388
+		$_where = array(
2389
+			'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
2390
+			'Registration.REG_count' => 1,
2391
+		);
2392
+
2393
+		if (isset($this->_req_data['EVT_ID'])) {
2394
+			$_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
2395
+		}
2396
+
2397
+		if (isset($this->_req_data['s'])) {
2398
+			$search_string = '%' . $this->_req_data['s'] . '%';
2399
+			$_where['OR']  = array(
2400
+				'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2401
+				'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
2402
+				'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
2403
+				'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
2404
+				'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
2405
+				'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
2406
+				'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
2407
+				'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
2408
+				'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
2409
+				'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
2410
+				'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
2411
+				'Registration.REG_final_price'        => array('LIKE', $search_string),
2412
+				'Registration.REG_code'               => array('LIKE', $search_string),
2413
+				'Registration.REG_count'              => array('LIKE', $search_string),
2414
+				'Registration.REG_group_size'         => array('LIKE', $search_string),
2415
+				'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
2416
+				'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
2417
+				'Payment.PAY_source'                  => array('LIKE', $search_string),
2418
+				'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
2419
+				'TXN_session_data'                    => array('LIKE', $search_string),
2420
+				'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string),
2421
+			);
2422
+		}
2423
+
2424
+		//failed transactions
2425
+		$failed    = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2426
+					 || ($count && $view === 'failed');
2427
+		$abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2428
+					 || ($count && $view === 'abandoned');
2429
+
2430
+		if ($failed) {
2431
+			$_where['STS_ID'] = EEM_Transaction::failed_status_code;
2432
+		} else if ($abandoned) {
2433
+			$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2434
+		} else {
2435
+			$_where['STS_ID']  = array('!=', EEM_Transaction::failed_status_code);
2436
+			$_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
2437
+		}
2438
+
2439
+		$query_params = array(
2440
+			$_where,
2441
+			'order_by'                 => array($orderby => $sort),
2442
+			'limit'                    => $limit,
2443
+			'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2444
+		);
2445
+
2446
+		$transactions = $count
2447
+			? $TXN->count(array($_where), 'TXN_ID', true)
2448
+			: $TXN->get_all($query_params);
2449
+
2450
+		return $transactions;
2451
+	}
2452 2452
 }
Please login to merge, or discard this patch.
Spacing   +81 added lines, -81 removed lines patch added patch discarded remove patch
@@ -266,7 +266,7 @@  discard block
 block discarded – undo
266 266
             'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267 267
             'event_espresso'
268 268
         );
269
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
269
+        EE_Registry::$i18n_js_strings['error_occurred'] = esc_html__(
270 270
             'An error occurred! Please refresh the page and try again.',
271 271
             'event_espresso'
272 272
         );
@@ -364,13 +364,13 @@  discard block
 block discarded – undo
364 364
         //enqueue style
365 365
         wp_register_style(
366 366
             'espresso_txn',
367
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
367
+            TXN_ASSETS_URL.'espresso_transactions_admin.css',
368 368
             array(),
369 369
             EVENT_ESPRESSO_VERSION
370 370
         );
371 371
         wp_enqueue_style('espresso_txn');
372 372
         //scripts
373
-        wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
373
+        wp_register_script('espresso_txn', TXN_ASSETS_URL.'espresso_transactions_admin.js', array(
374 374
             'ee_admin_js',
375 375
             'ee-datepicker',
376 376
             'jquery-ui-datepicker',
@@ -467,7 +467,7 @@  discard block
 block discarded – undo
467 467
             : null;
468 468
         $this->_transaction->verify_abandoned_transaction_status();
469 469
 
470
-        if (! $this->_transaction instanceof EE_Transaction) {
470
+        if ( ! $this->_transaction instanceof EE_Transaction) {
471 471
             $error_msg = sprintf(
472 472
                 esc_html__(
473 473
                     'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
@@ -565,7 +565,7 @@  discard block
 block discarded – undo
565 565
             'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
566 566
             array(
567 567
                 'overpaid'   => array(
568
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
568
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::overpaid_status_code,
569 569
                     'desc'  => EEH_Template::pretty_status(
570 570
                         EEM_Transaction::overpaid_status_code,
571 571
                         false,
@@ -573,7 +573,7 @@  discard block
 block discarded – undo
573 573
                     ),
574 574
                 ),
575 575
                 'complete'   => array(
576
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
576
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::complete_status_code,
577 577
                     'desc'  => EEH_Template::pretty_status(
578 578
                         EEM_Transaction::complete_status_code,
579 579
                         false,
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
                     ),
582 582
                 ),
583 583
                 'incomplete' => array(
584
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
584
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::incomplete_status_code,
585 585
                     'desc'  => EEH_Template::pretty_status(
586 586
                         EEM_Transaction::incomplete_status_code,
587 587
                         false,
@@ -589,7 +589,7 @@  discard block
 block discarded – undo
589 589
                     ),
590 590
                 ),
591 591
                 'abandoned'  => array(
592
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
592
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::abandoned_status_code,
593 593
                     'desc'  => EEH_Template::pretty_status(
594 594
                         EEM_Transaction::abandoned_status_code,
595 595
                         false,
@@ -597,7 +597,7 @@  discard block
 block discarded – undo
597 597
                     ),
598 598
                 ),
599 599
                 'failed'     => array(
600
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
600
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::failed_status_code,
601 601
                     'desc'  => EEH_Template::pretty_status(
602 602
                         EEM_Transaction::failed_status_code,
603 603
                         false,
@@ -646,11 +646,11 @@  discard block
 block discarded – undo
646 646
                     'Click to Edit event',
647 647
                     'event_espresso'
648 648
                 )
649
-                . '">' . $event->get('EVT_name') . '</a>',
649
+                . '">'.$event->get('EVT_name').'</a>',
650 650
                 '</h3>'
651 651
             )
652 652
             : '';
653
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
653
+        $this->_template_args['after_list_table'] = $this->_display_legend($this->_transaction_legend_items());
654 654
         $this->display_admin_list_table_page_with_no_sidebar();
655 655
     }
656 656
 
@@ -693,7 +693,7 @@  discard block
 block discarded – undo
693 693
 
694 694
         $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
695 695
         $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
696
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
696
+        $this->_template_args['txn_status']['class'] = 'status-'.$this->_transaction->get('STS_ID');
697 697
 
698 698
         $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
699 699
         $this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
@@ -746,7 +746,7 @@  discard block
 block discarded – undo
746 746
 
747 747
 
748 748
         // next link
749
-        $next_txn                                 = $this->_transaction->next(
749
+        $next_txn = $this->_transaction->next(
750 750
             null,
751 751
             array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
752 752
             'TXN_ID'
@@ -761,7 +761,7 @@  discard block
 block discarded – undo
761 761
             )
762 762
             : '';
763 763
         // previous link
764
-        $previous_txn                                 = $this->_transaction->previous(
764
+        $previous_txn = $this->_transaction->previous(
765 765
             null,
766 766
             array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
767 767
             'TXN_ID'
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
         // grab messages at the last second
812 812
         $this->_template_args['notices'] = EE_Error::get_notices();
813 813
         // path to template
814
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
814
+        $template_path                             = TXN_TEMPLATE_PATH.'txn_admin_details_header.template.php';
815 815
         $this->_template_args['admin_page_header'] = EEH_Template::display_template(
816 816
             $template_path,
817 817
             $this->_template_args,
@@ -893,7 +893,7 @@  discard block
 block discarded – undo
893 893
     {
894 894
         $content = '';
895 895
         $actions = array();
896
-        if (! $transaction instanceof EE_Transaction) {
896
+        if ( ! $transaction instanceof EE_Transaction) {
897 897
             return $content;
898 898
         }
899 899
         /** @var EE_Registration $primary_registration */
@@ -954,7 +954,7 @@  discard block
 block discarded – undo
954 954
         );
955 955
         if ($actions) {
956 956
             $content = '<ul>';
957
-            $content .= '<li>' . implode('</li><li>', $actions) . '</li>';
957
+            $content .= '<li>'.implode('</li><li>', $actions).'</li>';
958 958
             $content .= '</uL>';
959 959
         }
960 960
         return $content;
@@ -992,7 +992,7 @@  discard block
 block discarded – undo
992 992
 
993 993
         //get line table
994 994
         EEH_Autoloader::register_line_item_display_autoloaders();
995
-        $Line_Item_Display                       = new EE_Line_Item_Display(
995
+        $Line_Item_Display = new EE_Line_Item_Display(
996 996
             'admin_table',
997 997
             'EE_Admin_Table_Line_Item_Display_Strategy'
998 998
         );
@@ -1003,13 +1003,13 @@  discard block
 block discarded – undo
1003 1003
                                                                       ->get('REG_code');
1004 1004
 
1005 1005
         // process taxes
1006
-        $taxes                         = $this->_transaction->get_many_related(
1006
+        $taxes = $this->_transaction->get_many_related(
1007 1007
             'Line_Item',
1008 1008
             array(array('LIN_type' => EEM_Line_Item::type_tax))
1009 1009
         );
1010 1010
         $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1011 1011
 
1012
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1012
+        $this->_template_args['grand_total'] = EEH_Template::format_currency(
1013 1013
             $this->_transaction->get('TXN_total'),
1014 1014
             false,
1015 1015
             false
@@ -1019,7 +1019,7 @@  discard block
 block discarded – undo
1019 1019
 
1020 1020
         // process payment details
1021 1021
         $payments = $this->_transaction->get_many_related('Payment');
1022
-        if (! empty($payments)) {
1022
+        if ( ! empty($payments)) {
1023 1023
             $this->_template_args['payments']              = $payments;
1024 1024
             $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1025 1025
         } else {
@@ -1080,7 +1080,7 @@  discard block
 block discarded – undo
1080 1080
                                   esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1081 1081
                                   ucwords(str_replace('_', ' ', $reg_step)),
1082 1082
                                   date(
1083
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1083
+                                      get_option('date_format').' '.get_option('time_format'),
1084 1084
                                       ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1085 1085
                                   )
1086 1086
                               )
@@ -1094,7 +1094,7 @@  discard block
 block discarded – undo
1094 1094
                               . '</li>';
1095 1095
             }
1096 1096
         }
1097
-        $reg_steps                                                 .= '</ul>';
1097
+        $reg_steps .= '</ul>';
1098 1098
         $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1099 1099
         $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1100 1100
             'Registration Step Progress',
@@ -1107,11 +1107,11 @@  discard block
 block discarded – undo
1107 1107
         $this->_get_payment_status_array();
1108 1108
         $this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
1109 1109
 
1110
-        $this->_template_args['transaction_form_url']    = add_query_arg(array(
1110
+        $this->_template_args['transaction_form_url'] = add_query_arg(array(
1111 1111
             'action'  => 'edit_transaction',
1112 1112
             'process' => 'transaction',
1113 1113
         ), TXN_ADMIN_URL);
1114
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(array(
1114
+        $this->_template_args['apply_payment_form_url'] = add_query_arg(array(
1115 1115
             'page'   => 'espresso_transactions',
1116 1116
             'action' => 'espresso_apply_payment',
1117 1117
         ), WP_AJAX_URL);
@@ -1124,7 +1124,7 @@  discard block
 block discarded – undo
1124 1124
 
1125 1125
         // 'espresso_delete_payment_nonce'
1126 1126
 
1127
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1127
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_txn_details.template.php';
1128 1128
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
1129 1129
     }
1130 1130
 
@@ -1154,11 +1154,11 @@  discard block
 block discarded – undo
1154 1154
                 ),
1155 1155
             ),
1156 1156
         ));
1157
-        if (! empty($reg_payments)) {
1157
+        if ( ! empty($reg_payments)) {
1158 1158
             foreach ($payments as $payment) {
1159
-                if (! $payment instanceof EE_Payment) {
1159
+                if ( ! $payment instanceof EE_Payment) {
1160 1160
                     continue;
1161
-                } elseif (! isset($existing_reg_payments[$payment->ID()])) {
1161
+                } elseif ( ! isset($existing_reg_payments[$payment->ID()])) {
1162 1162
                     $existing_reg_payments[$payment->ID()] = array();
1163 1163
                 }
1164 1164
                 foreach ($reg_payments as $reg_payment) {
@@ -1187,7 +1187,7 @@  discard block
 block discarded – undo
1187 1187
     protected function _get_registrations_to_apply_payment_to()
1188 1188
     {
1189 1189
         // we want any registration with an active status (ie: not deleted or cancelled)
1190
-        $query_params                      = array(
1190
+        $query_params = array(
1191 1191
             array(
1192 1192
                 'STS_ID' => array(
1193 1193
                     'IN',
@@ -1206,16 +1206,16 @@  discard block
 block discarded – undo
1206 1206
                                                  '',
1207 1207
                                                  'clear: both; margin: 1.5em 0 0; display: none;'
1208 1208
                                              );
1209
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1209
+        $registrations_to_apply_payment_to .= EEH_HTML::br().EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1210 1210
         $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1211 1211
         $registrations_to_apply_payment_to .= EEH_HTML::thead(
1212 1212
             EEH_HTML::tr(
1213
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1214
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1215
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1216
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1217
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1218
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1213
+                EEH_HTML::th(esc_html__('ID', 'event_espresso')).
1214
+                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')).
1215
+                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')).
1216
+                EEH_HTML::th(esc_html__('Event', 'event_espresso')).
1217
+                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr').
1218
+                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr').
1219 1219
                 EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1220 1220
             )
1221 1221
         );
@@ -1230,29 +1230,29 @@  discard block
 block discarded – undo
1230 1230
                     : esc_html__('Unknown Attendee', 'event_espresso');
1231 1231
                 $owing                             = $registration->final_price() - $registration->paid();
1232 1232
                 $taxable                           = $registration->ticket()->taxable()
1233
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1233
+                    ? ' <span class="smaller-text lt-grey-text"> '.esc_html__('+ tax', 'event_espresso').'</span>'
1234 1234
                     : '';
1235 1235
                 $checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1236 1236
                     ? ' checked="checked"'
1237 1237
                     : '';
1238
-                $disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1238
+                $disabled = $registration->final_price() > 0 ? '' : ' disabled';
1239 1239
                 $registrations_to_apply_payment_to .= EEH_HTML::tr(
1240
-                    EEH_HTML::td($registration->ID()) .
1241
-                    EEH_HTML::td($attendee_name) .
1240
+                    EEH_HTML::td($registration->ID()).
1241
+                    EEH_HTML::td($attendee_name).
1242 1242
                     EEH_HTML::td(
1243
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1244
-                    ) .
1245
-                    EEH_HTML::td($registration->event_name()) .
1246
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1247
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1243
+                        $registration->ticket()->name().' : '.$registration->ticket()->pretty_price().$taxable
1244
+                    ).
1245
+                    EEH_HTML::td($registration->event_name()).
1246
+                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr').
1247
+                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr').
1248 1248
                     EEH_HTML::td(
1249
-                        '<input type="checkbox" value="' . $registration->ID()
1249
+                        '<input type="checkbox" value="'.$registration->ID()
1250 1250
                         . '" name="txn_admin_payment[registrations]"'
1251
-                        . $checked . $disabled . '>',
1251
+                        . $checked.$disabled.'>',
1252 1252
                         '',
1253 1253
                         'jst-cntr'
1254 1254
                     ),
1255
-                    'apply-payment-registration-row-' . $registration->ID()
1255
+                    'apply-payment-registration-row-'.$registration->ID()
1256 1256
                 );
1257 1257
             }
1258 1258
         }
@@ -1267,7 +1267,7 @@  discard block
 block discarded – undo
1267 1267
             '',
1268 1268
             'clear description'
1269 1269
         );
1270
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1270
+        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1271 1271
         $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1272 1272
     }
1273 1273
 
@@ -1333,12 +1333,12 @@  discard block
 block discarded – undo
1333 1333
                 array(
1334 1334
                     'OR*payment_method_for_payment' => array(
1335 1335
                         'PMD_ID'    => array('IN', $payment_methods_of_payments),
1336
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1336
+                        'PMD_scope' => array('LIKE', '%'.EEM_Payment_Method::scope_admin.'%'),
1337 1337
                     ),
1338 1338
                 ),
1339 1339
             );
1340 1340
         } else {
1341
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1341
+            $query_args = array(array('PMD_scope' => array('LIKE', '%'.EEM_Payment_Method::scope_admin.'%')));
1342 1342
         }
1343 1343
         $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1344 1344
     }
@@ -1367,7 +1367,7 @@  discard block
 block discarded – undo
1367 1367
             'Line_Item',
1368 1368
             array(array('LIN_type' => 'line-item'))
1369 1369
         );
1370
-        if (! empty($line_items)) {
1370
+        if ( ! empty($line_items)) {
1371 1371
             foreach ($line_items as $item) {
1372 1372
                 if ($item instanceof EE_Line_Item) {
1373 1373
                     switch ($item->OBJ_type()) {
@@ -1377,7 +1377,7 @@  discard block
 block discarded – undo
1377 1377
                             $ticket = $item->ticket();
1378 1378
                             //right now we're only handling tickets here.
1379 1379
                             //Cause its expected that only tickets will have attendees right?
1380
-                            if (! $ticket instanceof EE_Ticket) {
1380
+                            if ( ! $ticket instanceof EE_Ticket) {
1381 1381
                                 continue;
1382 1382
                             }
1383 1383
                             try {
@@ -1386,7 +1386,7 @@  discard block
 block discarded – undo
1386 1386
                                 EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1387 1387
                                 $event_name = esc_html__('Unknown Event', 'event_espresso');
1388 1388
                             }
1389
-                            $event_name   .= ' - ' . $item->get('LIN_name');
1389
+                            $event_name   .= ' - '.$item->get('LIN_name');
1390 1390
                             $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1391 1391
                             // now get all of the registrations for this transaction that use this ticket
1392 1392
                             $registrations = $ticket->get_many_related(
@@ -1394,7 +1394,7 @@  discard block
 block discarded – undo
1394 1394
                                 array(array('TXN_ID' => $this->_transaction->ID()))
1395 1395
                             );
1396 1396
                             foreach ($registrations as $registration) {
1397
-                                if (! $registration instanceof EE_Registration) {
1397
+                                if ( ! $registration instanceof EE_Registration) {
1398 1398
                                     continue;
1399 1399
                                 }
1400 1400
                                 $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
@@ -1413,12 +1413,12 @@  discard block
 block discarded – undo
1413 1413
                                     $this->_template_args['event_attendees'][$registration->ID()]['attendee']
1414 1414
                                         = $attendee->full_name();
1415 1415
                                     $this->_template_args['event_attendees'][$registration->ID()]['email']
1416
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1416
+                                        = '<a href="mailto:'.$attendee->email().'?subject='.$event_name
1417 1417
                                           . esc_html__(
1418 1418
                                               ' Event',
1419 1419
                                               'event_espresso'
1420 1420
                                           )
1421
-                                          . '">' . $attendee->email() . '</a>';
1421
+                                          . '">'.$attendee->email().'</a>';
1422 1422
                                     $this->_template_args['event_attendees'][$registration->ID()]['address']
1423 1423
                                         = EEH_Address::format($attendee, 'inline', false, false);
1424 1424
                                 } else {
@@ -1442,7 +1442,7 @@  discard block
 block discarded – undo
1442 1442
                 TXN_ADMIN_URL
1443 1443
             );
1444 1444
             echo EEH_Template::display_template(
1445
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1445
+                TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_attendees.template.php',
1446 1446
                 $this->_template_args,
1447 1447
                 true
1448 1448
             );
@@ -1478,12 +1478,12 @@  discard block
 block discarded – undo
1478 1478
         $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1479 1479
             ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1480 1480
             : null;
1481
-        if (! $primary_att instanceof EE_Attendee) {
1481
+        if ( ! $primary_att instanceof EE_Attendee) {
1482 1482
             $this->_template_args['no_attendee_message'] = esc_html__(
1483 1483
                 'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1484 1484
                 'event_espresso'
1485 1485
             );
1486
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1486
+            $primary_att = EEM_Attendee::instance()->create_default_object();
1487 1487
         }
1488 1488
         $this->_template_args['ATT_ID']            = $primary_att->ID();
1489 1489
         $this->_template_args['prime_reg_fname']   = $primary_att->fname();
@@ -1497,7 +1497,7 @@  discard block
 block discarded – undo
1497 1497
         // get formatted address for registrant
1498 1498
         $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1499 1499
         echo EEH_Template::display_template(
1500
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1500
+            TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_registrant.template.php',
1501 1501
             $this->_template_args,
1502 1502
             true
1503 1503
         );
@@ -1522,8 +1522,8 @@  discard block
 block discarded – undo
1522 1522
             TXN_ADMIN_URL
1523 1523
         );
1524 1524
 
1525
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1526
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1525
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_billing_info.template.php';
1526
+        echo EEH_Template::display_template($template_path, $this->_template_args, true); /**/
1527 1527
     }
1528 1528
 
1529 1529
 
@@ -1548,7 +1548,7 @@  discard block
 block discarded – undo
1548 1548
             'ee_edit_payments',
1549 1549
             'apply_payment_or_refund_from_registration_details'
1550 1550
         );
1551
-        if (! empty($valid_data) && $has_access) {
1551
+        if ( ! empty($valid_data) && $has_access) {
1552 1552
             $PAY_ID = $valid_data['PAY_ID'];
1553 1553
             //save  the new payment
1554 1554
             $payment = $this->_create_payment_from_request_data($valid_data);
@@ -1561,7 +1561,7 @@  discard block
 block discarded – undo
1561 1561
                 $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1562 1562
                 $this->_remove_existing_registration_payments($payment, $PAY_ID);
1563 1563
                 // apply payment to registrations (if applicable)
1564
-                if (! empty($REG_IDs)) {
1564
+                if ( ! empty($REG_IDs)) {
1565 1565
                     $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1566 1566
                     $this->_maybe_send_notifications();
1567 1567
                     // now process status changes for the same registrations
@@ -1609,7 +1609,7 @@  discard block
 block discarded – undo
1609 1609
                 );
1610 1610
             }
1611 1611
         }
1612
-        $notices              = EE_Error::get_notices(
1612
+        $notices = EE_Error::get_notices(
1613 1613
             false,
1614 1614
             false,
1615 1615
             false
@@ -1631,14 +1631,14 @@  discard block
 block discarded – undo
1631 1631
      */
1632 1632
     protected function _validate_payment_request_data()
1633 1633
     {
1634
-        if (! isset($this->_req_data['txn_admin_payment'])) {
1634
+        if ( ! isset($this->_req_data['txn_admin_payment'])) {
1635 1635
             return false;
1636 1636
         }
1637 1637
         $payment_form = $this->_generate_payment_form_section();
1638 1638
         try {
1639 1639
             if ($payment_form->was_submitted()) {
1640 1640
                 $payment_form->receive_form_submission();
1641
-                if (! $payment_form->is_valid()) {
1641
+                if ( ! $payment_form->is_valid()) {
1642 1642
                     $submission_error_messages = array();
1643 1643
                     foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1644 1644
                         if ($validation_error instanceof EE_Validation_Error) {
@@ -1817,7 +1817,7 @@  discard block
 block discarded – undo
1817 1817
             array('Y-m-d', 'g:i a')
1818 1818
         );
1819 1819
 
1820
-        if (! $payment->save()) {
1820
+        if ( ! $payment->save()) {
1821 1821
             EE_Error::add_error(
1822 1822
                 sprintf(
1823 1823
                     esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
@@ -1882,7 +1882,7 @@  discard block
 block discarded – undo
1882 1882
         $REG_IDs = array();
1883 1883
         // grab array of IDs for specific registrations to apply changes to
1884 1884
         if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1885
-            $REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1885
+            $REG_IDs = (array) $this->_req_data['txn_admin_payment']['registrations'];
1886 1886
         }
1887 1887
         //nothing specified ? then get all reg IDs
1888 1888
         if (empty($REG_IDs)) {
@@ -2010,12 +2010,12 @@  discard block
 block discarded – undo
2010 2010
         // but add in some conditions regarding payment,
2011 2011
         // so that we don't apply payments to registrations that are free or have already been paid for
2012 2012
         // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2013
-        if (! $payment->is_a_refund()) {
2013
+        if ( ! $payment->is_a_refund()) {
2014 2014
             $registration_query_where_params['REG_final_price']  = array('!=', 0);
2015 2015
             $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2016 2016
         }
2017 2017
         $registrations = $transaction->registrations(array($registration_query_where_params));
2018
-        if (! empty($registrations)) {
2018
+        if ( ! empty($registrations)) {
2019 2019
             /** @type EE_Payment_Processor $payment_processor */
2020 2020
             $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2021 2021
             $payment_processor->process_registration_payments($transaction, $payment, $registrations);
@@ -2217,7 +2217,7 @@  discard block
 block discarded – undo
2217 2217
     {
2218 2218
         $registration_payment_data = array();
2219 2219
         //if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2220
-        if (! empty($REG_IDs)) {
2220
+        if ( ! empty($REG_IDs)) {
2221 2221
             $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2222 2222
             foreach ($registrations as $registration) {
2223 2223
                 if ($registration instanceof EE_Registration) {
@@ -2330,13 +2330,13 @@  discard block
 block discarded – undo
2330 2330
                 'm/d/Y',
2331 2331
                 strtotime('-10 year')
2332 2332
             );
2333
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
2333
+        $end_date = isset($this->_req_data['txn-filter-end-date'])
2334 2334
             ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2335 2335
             : date('m/d/Y');
2336 2336
 
2337 2337
         //make sure our timestamps start and end right at the boundaries for each day
2338
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2339
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2338
+        $start_date = date('Y-m-d', strtotime($start_date)).' 00:00:00';
2339
+        $end_date   = date('Y-m-d', strtotime($end_date)).' 23:59:59';
2340 2340
 
2341 2341
 
2342 2342
         //convert to timestamps
@@ -2353,7 +2353,7 @@  discard block
 block discarded – undo
2353 2353
             date('Y-m-d H:i:s', $start_date),
2354 2354
             'Y-m-d H:i:s'
2355 2355
         );
2356
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2356
+        $end_date = EEM_Transaction::instance()->convert_datetime_for_query(
2357 2357
             'TXN_timestamp',
2358 2358
             date('Y-m-d H:i:s', $end_date),
2359 2359
             'Y-m-d H:i:s'
@@ -2395,7 +2395,7 @@  discard block
 block discarded – undo
2395 2395
         }
2396 2396
 
2397 2397
         if (isset($this->_req_data['s'])) {
2398
-            $search_string = '%' . $this->_req_data['s'] . '%';
2398
+            $search_string = '%'.$this->_req_data['s'].'%';
2399 2399
             $_where['OR']  = array(
2400 2400
                 'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2401 2401
                 'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
@@ -2422,9 +2422,9 @@  discard block
 block discarded – undo
2422 2422
         }
2423 2423
 
2424 2424
         //failed transactions
2425
-        $failed    = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2425
+        $failed    = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2426 2426
                      || ($count && $view === 'failed');
2427
-        $abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2427
+        $abandoned = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2428 2428
                      || ($count && $view === 'abandoned');
2429 2429
 
2430 2430
         if ($failed) {
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +79 added lines, -79 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 
64 64
 } else {
65
-    define('EE_MIN_PHP_VER_REQUIRED', '5.4.0');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
-        /**
68
-         * espresso_minimum_php_version_error
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
65
+	define('EE_MIN_PHP_VER_REQUIRED', '5.4.0');
66
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
+		/**
68
+		 * espresso_minimum_php_version_error
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.9.59.rc.049');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.9.59.rc.049');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
Please login to merge, or discard this patch.
core/EE_Registry.core.php 1 patch
Indentation   +1603 added lines, -1603 removed lines patch added patch discarded remove patch
@@ -27,1609 +27,1609 @@
 block discarded – undo
27 27
 class EE_Registry implements ResettableInterface
28 28
 {
29 29
 
30
-    /**
31
-     * @var EE_Registry $_instance
32
-     */
33
-    private static $_instance;
34
-
35
-    /**
36
-     * @var EE_Dependency_Map $_dependency_map
37
-     */
38
-    protected $_dependency_map;
39
-
40
-    /**
41
-     * @var Mirror
42
-     */
43
-    private $mirror;
44
-
45
-    /**
46
-     * @var ClassInterfaceCache $class_cache
47
-     */
48
-    private $class_cache;
49
-
50
-    /**
51
-     * @var array $_class_abbreviations
52
-     */
53
-    protected $_class_abbreviations = array();
54
-
55
-    /**
56
-     * @var CommandBusInterface $BUS
57
-     */
58
-    public $BUS;
59
-
60
-    /**
61
-     * @var EE_Cart $CART
62
-     */
63
-    public $CART;
64
-
65
-    /**
66
-     * @var EE_Config $CFG
67
-     */
68
-    public $CFG;
69
-
70
-    /**
71
-     * @var EE_Network_Config $NET_CFG
72
-     */
73
-    public $NET_CFG;
74
-
75
-    /**
76
-     * StdClass object for storing library classes in
77
-     *
78
-     * @var StdClass $LIB
79
-     */
80
-    public $LIB;
81
-
82
-    /**
83
-     * @var EE_Request_Handler $REQ
84
-     */
85
-    public $REQ;
86
-
87
-    /**
88
-     * @var EE_Session $SSN
89
-     */
90
-    public $SSN;
91
-
92
-    /**
93
-     * @since 4.5.0
94
-     * @var EE_Capabilities $CAP
95
-     */
96
-    public $CAP;
97
-
98
-    /**
99
-     * @since 4.9.0
100
-     * @var EE_Message_Resource_Manager $MRM
101
-     */
102
-    public $MRM;
103
-
104
-
105
-    /**
106
-     * @var Registry $AssetsRegistry
107
-     */
108
-    public $AssetsRegistry;
109
-
110
-    /**
111
-     * StdClass object for holding addons which have registered themselves to work with EE core
112
-     *
113
-     * @var EE_Addon[] $addons
114
-     */
115
-    public $addons;
116
-
117
-    /**
118
-     * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
119
-     *
120
-     * @var EEM_Base[] $models
121
-     */
122
-    public $models = array();
123
-
124
-    /**
125
-     * @var EED_Module[] $modules
126
-     */
127
-    public $modules;
128
-
129
-    /**
130
-     * @var EES_Shortcode[] $shortcodes
131
-     */
132
-    public $shortcodes;
133
-
134
-    /**
135
-     * @var WP_Widget[] $widgets
136
-     */
137
-    public $widgets;
138
-
139
-    /**
140
-     * this is an array of all implemented model names (i.e. not the parent abstract models, or models
141
-     * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
142
-     * Keys are model "short names" (eg "Event") as used in model relations, and values are
143
-     * classnames (eg "EEM_Event")
144
-     *
145
-     * @var array $non_abstract_db_models
146
-     */
147
-    public $non_abstract_db_models = array();
148
-
149
-
150
-    /**
151
-     * internationalization for JS strings
152
-     *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
153
-     *    in js file:  var translatedString = eei18n.string_key;
154
-     *
155
-     * @var array $i18n_js_strings
156
-     */
157
-    public static $i18n_js_strings = array();
158
-
159
-
160
-    /**
161
-     * $main_file - path to espresso.php
162
-     *
163
-     * @var array $main_file
164
-     */
165
-    public $main_file;
166
-
167
-    /**
168
-     * array of ReflectionClass objects where the key is the class name
169
-     *
170
-     * @deprecated $VID:$
171
-     * @var ReflectionClass[] $_reflectors
172
-     */
173
-    public $_reflectors;
174
-
175
-    /**
176
-     * boolean flag to indicate whether or not to load/save dependencies from/to the cache
177
-     *
178
-     * @var boolean $_cache_on
179
-     */
180
-    protected $_cache_on = true;
181
-
182
-
183
-    /**
184
-     * @singleton method used to instantiate class object
185
-     * @param EE_Dependency_Map|null   $dependency_map
186
-     * @param Mirror|null              $mirror
187
-     * @param ClassInterfaceCache|null $class_cache
188
-     * @return EE_Registry instance
189
-     */
190
-    public static function instance(
191
-        EE_Dependency_Map $dependency_map = null,
192
-        Mirror $mirror = null,
193
-        ClassInterfaceCache $class_cache = null
194
-    ) {
195
-        // check if class object is instantiated
196
-        if (
197
-            ! self::$_instance instanceof EE_Registry
198
-            && $dependency_map instanceof EE_Dependency_Map
199
-            && $mirror instanceof Mirror
200
-            && $class_cache instanceof ClassInterfaceCache
201
-        ) {
202
-            self::$_instance = new self($dependency_map, $mirror, $class_cache);
203
-        }
204
-        return self::$_instance;
205
-    }
206
-
207
-
208
-    /**
209
-     * protected constructor to prevent direct creation
210
-     *
211
-     * @Constructor
212
-     * @param  EE_Dependency_Map  $dependency_map
213
-     * @param Mirror              $mirror
214
-     * @param ClassInterfaceCache $class_cache
215
-     */
216
-    protected function __construct(EE_Dependency_Map $dependency_map, Mirror $mirror, ClassInterfaceCache $class_cache)
217
-    {
218
-        $this->_dependency_map = $dependency_map;
219
-        $this->mirror = $mirror;
220
-        $this->class_cache = $class_cache;
221
-        // $registry_container = new RegistryContainer();
222
-        $this->LIB = new RegistryContainer();
223
-        $this->addons = new RegistryContainer();
224
-        $this->modules = new RegistryContainer();
225
-        $this->shortcodes = new RegistryContainer();
226
-        $this->widgets = new RegistryContainer();
227
-        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
228
-    }
229
-
230
-
231
-
232
-    /**
233
-     * initialize
234
-     *
235
-     * @throws EE_Error
236
-     * @throws ReflectionException
237
-     */
238
-    public function initialize()
239
-    {
240
-        $this->_class_abbreviations = apply_filters(
241
-            'FHEE__EE_Registry____construct___class_abbreviations',
242
-            array(
243
-                'EE_Config'                                       => 'CFG',
244
-                'EE_Session'                                      => 'SSN',
245
-                'EE_Capabilities'                                 => 'CAP',
246
-                'EE_Cart'                                         => 'CART',
247
-                'EE_Network_Config'                               => 'NET_CFG',
248
-                'EE_Request_Handler'                              => 'REQ',
249
-                'EE_Message_Resource_Manager'                     => 'MRM',
250
-                'EventEspresso\core\services\commands\CommandBus' => 'BUS',
251
-                'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
252
-            )
253
-        );
254
-        $this->load_core('Base', array(), true);
255
-        // add our request and response objects to the cache
256
-        $request_loader = $this->_dependency_map->class_loader(
257
-            'EventEspresso\core\services\request\Request'
258
-        );
259
-        $this->_set_cached_class(
260
-            $request_loader(),
261
-            'EventEspresso\core\services\request\Request'
262
-        );
263
-        $response_loader = $this->_dependency_map->class_loader(
264
-            'EventEspresso\core\services\request\Response'
265
-        );
266
-        $this->_set_cached_class(
267
-            $response_loader(),
268
-            'EventEspresso\core\services\request\Response'
269
-        );
270
-        add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
271
-    }
272
-
273
-
274
-
275
-    /**
276
-     * @return void
277
-     */
278
-    public function init()
279
-    {
280
-        // Get current page protocol
281
-        $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
282
-        // Output admin-ajax.php URL with same protocol as current page
283
-        self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
284
-        self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
285
-    }
286
-
287
-
288
-
289
-    /**
290
-     * localize_i18n_js_strings
291
-     *
292
-     * @return string
293
-     */
294
-    public static function localize_i18n_js_strings()
295
-    {
296
-        $i18n_js_strings = (array)self::$i18n_js_strings;
297
-        foreach ($i18n_js_strings as $key => $value) {
298
-            if (is_scalar($value)) {
299
-                $i18n_js_strings[$key] = html_entity_decode((string)$value, ENT_QUOTES, 'UTF-8');
300
-            }
301
-        }
302
-        return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
303
-    }
304
-
305
-
306
-
307
-    /**
308
-     * @param mixed string | EED_Module $module
309
-     * @throws EE_Error
310
-     * @throws ReflectionException
311
-     */
312
-    public function add_module($module)
313
-    {
314
-        if ($module instanceof EED_Module) {
315
-            $module_class = get_class($module);
316
-            $this->modules->{$module_class} = $module;
317
-        } else {
318
-            if ( ! class_exists('EE_Module_Request_Router', false)) {
319
-                $this->load_core('Module_Request_Router');
320
-            }
321
-            EE_Module_Request_Router::module_factory($module);
322
-        }
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * @param string $module_name
329
-     * @return mixed EED_Module | NULL
330
-     */
331
-    public function get_module($module_name = '')
332
-    {
333
-        return isset($this->modules->{$module_name})
334
-            ? $this->modules->{$module_name}
335
-            : null;
336
-    }
337
-
338
-
339
-
340
-    /**
341
-     * loads core classes - must be singletons
342
-     *
343
-     * @param string $class_name - simple class name ie: session
344
-     * @param mixed  $arguments
345
-     * @param bool   $load_only
346
-     * @return mixed
347
-     * @throws EE_Error
348
-     * @throws ReflectionException
349
-     */
350
-    public function load_core($class_name, $arguments = array(), $load_only = false)
351
-    {
352
-        $core_paths = apply_filters(
353
-            'FHEE__EE_Registry__load_core__core_paths',
354
-            array(
355
-                EE_CORE,
356
-                EE_ADMIN,
357
-                EE_CPTS,
358
-                EE_CORE . 'data_migration_scripts' . DS,
359
-                EE_CORE . 'capabilities' . DS,
360
-                EE_CORE . 'request_stack' . DS,
361
-                EE_CORE . 'middleware' . DS,
362
-            )
363
-        );
364
-        // retrieve instantiated class
365
-        return $this->_load(
366
-            $core_paths,
367
-            'EE_',
368
-            $class_name,
369
-            'core',
370
-            $arguments,
371
-            false,
372
-            true,
373
-            $load_only
374
-        );
375
-    }
376
-
377
-
378
-
379
-    /**
380
-     * loads service classes
381
-     *
382
-     * @param string $class_name - simple class name ie: session
383
-     * @param mixed  $arguments
384
-     * @param bool   $load_only
385
-     * @return mixed
386
-     * @throws EE_Error
387
-     * @throws ReflectionException
388
-     */
389
-    public function load_service($class_name, $arguments = array(), $load_only = false)
390
-    {
391
-        $service_paths = apply_filters(
392
-            'FHEE__EE_Registry__load_service__service_paths',
393
-            array(
394
-                EE_CORE . 'services' . DS,
395
-            )
396
-        );
397
-        // retrieve instantiated class
398
-        return $this->_load(
399
-            $service_paths,
400
-            'EE_',
401
-            $class_name,
402
-            'class',
403
-            $arguments,
404
-            false,
405
-            true,
406
-            $load_only
407
-        );
408
-    }
409
-
410
-
411
-
412
-    /**
413
-     * loads data_migration_scripts
414
-     *
415
-     * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
416
-     * @param mixed  $arguments
417
-     * @return EE_Data_Migration_Script_Base|mixed
418
-     * @throws EE_Error
419
-     * @throws ReflectionException
420
-     */
421
-    public function load_dms($class_name, $arguments = array())
422
-    {
423
-        // retrieve instantiated class
424
-        return $this->_load(
425
-            EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
426
-            'EE_DMS_',
427
-            $class_name,
428
-            'dms',
429
-            $arguments,
430
-            false,
431
-            false
432
-        );
433
-    }
434
-
435
-
436
-
437
-    /**
438
-     * loads object creating classes - must be singletons
439
-     *
440
-     * @param string $class_name - simple class name ie: attendee
441
-     * @param mixed  $arguments  - an array of arguments to pass to the class
442
-     * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
443
-     *                           instantiate
444
-     * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
445
-     *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
446
-     * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
447
-     *                           (default)
448
-     * @return EE_Base_Class | bool
449
-     * @throws EE_Error
450
-     * @throws ReflectionException
451
-     */
452
-    public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
453
-    {
454
-        $paths = apply_filters(
455
-            'FHEE__EE_Registry__load_class__paths', array(
456
-            EE_CORE,
457
-            EE_CLASSES,
458
-            EE_BUSINESS,
459
-        )
460
-        );
461
-        // retrieve instantiated class
462
-        return $this->_load(
463
-            $paths,
464
-            'EE_',
465
-            $class_name,
466
-            'class',
467
-            $arguments,
468
-            $from_db,
469
-            $cache,
470
-            $load_only
471
-        );
472
-    }
473
-
474
-
475
-
476
-    /**
477
-     * loads helper classes - must be singletons
478
-     *
479
-     * @param string $class_name - simple class name ie: price
480
-     * @param mixed  $arguments
481
-     * @param bool   $load_only
482
-     * @return EEH_Base | bool
483
-     * @throws EE_Error
484
-     * @throws ReflectionException
485
-     */
486
-    public function load_helper($class_name, $arguments = array(), $load_only = true)
487
-    {
488
-        // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
489
-        $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
490
-        // retrieve instantiated class
491
-        return $this->_load(
492
-            $helper_paths,
493
-            'EEH_',
494
-            $class_name,
495
-            'helper',
496
-            $arguments,
497
-            false,
498
-            true,
499
-            $load_only
500
-        );
501
-    }
502
-
503
-
504
-
505
-    /**
506
-     * loads core classes - must be singletons
507
-     *
508
-     * @param string $class_name - simple class name ie: session
509
-     * @param mixed  $arguments
510
-     * @param bool   $load_only
511
-     * @param bool   $cache      whether to cache the object or not.
512
-     * @return mixed
513
-     * @throws EE_Error
514
-     * @throws ReflectionException
515
-     */
516
-    public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
517
-    {
518
-        $paths = array(
519
-            EE_LIBRARIES,
520
-            EE_LIBRARIES . 'messages' . DS,
521
-            EE_LIBRARIES . 'shortcodes' . DS,
522
-            EE_LIBRARIES . 'qtips' . DS,
523
-            EE_LIBRARIES . 'payment_methods' . DS,
524
-        );
525
-        // retrieve instantiated class
526
-        return $this->_load(
527
-            $paths,
528
-            'EE_',
529
-            $class_name,
530
-            'lib',
531
-            $arguments,
532
-            false,
533
-            $cache,
534
-            $load_only
535
-        );
536
-    }
537
-
538
-
539
-
540
-    /**
541
-     * loads model classes - must be singletons
542
-     *
543
-     * @param string $class_name - simple class name ie: price
544
-     * @param mixed  $arguments
545
-     * @param bool   $load_only
546
-     * @return EEM_Base | bool
547
-     * @throws EE_Error
548
-     * @throws ReflectionException
549
-     */
550
-    public function load_model($class_name, $arguments = array(), $load_only = false)
551
-    {
552
-        $paths = apply_filters(
553
-            'FHEE__EE_Registry__load_model__paths', array(
554
-            EE_MODELS,
555
-            EE_CORE,
556
-        )
557
-        );
558
-        // retrieve instantiated class
559
-        return $this->_load(
560
-            $paths,
561
-            'EEM_',
562
-            $class_name,
563
-            'model',
564
-            $arguments,
565
-            false,
566
-            true,
567
-            $load_only
568
-        );
569
-    }
570
-
571
-
572
-
573
-    /**
574
-     * loads model classes - must be singletons
575
-     *
576
-     * @param string $class_name - simple class name ie: price
577
-     * @param mixed  $arguments
578
-     * @param bool   $load_only
579
-     * @return mixed | bool
580
-     * @throws EE_Error
581
-     * @throws ReflectionException
582
-     */
583
-    public function load_model_class($class_name, $arguments = array(), $load_only = true)
584
-    {
585
-        $paths = array(
586
-            EE_MODELS . 'fields' . DS,
587
-            EE_MODELS . 'helpers' . DS,
588
-            EE_MODELS . 'relations' . DS,
589
-            EE_MODELS . 'strategies' . DS,
590
-        );
591
-        // retrieve instantiated class
592
-        return $this->_load(
593
-            $paths,
594
-            'EE_',
595
-            $class_name,
596
-            '',
597
-            $arguments,
598
-            false,
599
-            true,
600
-            $load_only
601
-        );
602
-    }
603
-
604
-
605
-
606
-    /**
607
-     * Determines if $model_name is the name of an actual EE model.
608
-     *
609
-     * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
610
-     * @return boolean
611
-     */
612
-    public function is_model_name($model_name)
613
-    {
614
-        return isset($this->models[$model_name]);
615
-    }
616
-
617
-
618
-
619
-    /**
620
-     * generic class loader
621
-     *
622
-     * @param string $path_to_file - directory path to file location, not including filename
623
-     * @param string $file_name    - file name  ie:  my_file.php, including extension
624
-     * @param string $type         - file type - core? class? helper? model?
625
-     * @param mixed  $arguments
626
-     * @param bool   $load_only
627
-     * @return mixed
628
-     * @throws EE_Error
629
-     * @throws ReflectionException
630
-     */
631
-    public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
632
-    {
633
-        // retrieve instantiated class
634
-        return $this->_load(
635
-            $path_to_file,
636
-            '',
637
-            $file_name,
638
-            $type,
639
-            $arguments,
640
-            false,
641
-            true,
642
-            $load_only
643
-        );
644
-    }
645
-
646
-
647
-
648
-    /**
649
-     * @param string $path_to_file - directory path to file location, not including filename
650
-     * @param string $class_name   - full class name  ie:  My_Class
651
-     * @param string $type         - file type - core? class? helper? model?
652
-     * @param mixed  $arguments
653
-     * @param bool   $load_only
654
-     * @return bool|EE_Addon|object
655
-     * @throws EE_Error
656
-     * @throws ReflectionException
657
-     */
658
-    public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
659
-    {
660
-        // retrieve instantiated class
661
-        return $this->_load(
662
-            $path_to_file,
663
-            'addon',
664
-            $class_name,
665
-            $type,
666
-            $arguments,
667
-            false,
668
-            true,
669
-            $load_only
670
-        );
671
-    }
672
-
673
-
674
-    /**
675
-     * instantiates, caches, and automatically resolves dependencies
676
-     * for classes that use a Fully Qualified Class Name.
677
-     * if the class is not capable of being loaded using PSR-4 autoloading,
678
-     * then you need to use one of the existing load_*() methods
679
-     * which can resolve the classname and filepath from the passed arguments
680
-     *
681
-     * @param bool|string $class_name   Fully Qualified Class Name
682
-     * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
683
-     * @param bool        $cache        whether to cache the instantiated object for reuse
684
-     * @param bool        $from_db      some classes are instantiated from the db
685
-     *                                  and thus call a different method to instantiate
686
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
687
-     * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
688
-     * @return bool|null|mixed          null = failure to load or instantiate class object.
689
-     *                                  object = class loaded and instantiated successfully.
690
-     *                                  bool = fail or success when $load_only is true
691
-     * @throws InvalidInterfaceException
692
-     * @throws InvalidDataTypeException
693
-     * @throws InvalidClassException
694
-     * @throws EE_Error
695
-     * @throws ReflectionException
696
-     */
697
-    public function create(
698
-        $class_name = false,
699
-        $arguments = array(),
700
-        $cache = false,
701
-        $from_db = false,
702
-        $load_only = false,
703
-        $addon = false
704
-    ) {
705
-        $class_name = ltrim($class_name, '\\');
706
-        $class_name = $this->class_cache->getFqnForAlias($class_name);
707
-        $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
708
-        // if a non-FQCN was passed, then verifyClassExists() might return an object
709
-        // or it could return null if the class just could not be found anywhere
710
-        if ($class_exists instanceof $class_name || $class_exists === null){
711
-            // either way, return the results
712
-            return $class_exists;
713
-        }
714
-        $class_name = $class_exists;
715
-        // if we're only loading the class and it already exists, then let's just return true immediately
716
-        if ($load_only) {
717
-            return true;
718
-        }
719
-        $addon = $addon
720
-            ? 'addon'
721
-            : '';
722
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
723
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
724
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
725
-        if ($this->_cache_on && $cache && ! $load_only) {
726
-            // return object if it's already cached
727
-            $cached_class = $this->_get_cached_class($class_name, $addon);
728
-            if ($cached_class !== null) {
729
-                return $cached_class;
730
-            }
731
-        }
732
-        // obtain the loader method from the dependency map
733
-        $loader = $this->_dependency_map->class_loader($class_name);
734
-        // instantiate the requested object
735
-        if ($loader instanceof Closure) {
736
-            $class_obj = $loader($arguments);
737
-        } else if ($loader && method_exists($this, $loader)) {
738
-            $class_obj = $this->{$loader}($class_name, $arguments);
739
-        } else {
740
-            $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
741
-        }
742
-        if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
743
-            // save it for later... kinda like gum  { : $
744
-            $this->_set_cached_class($class_obj, $class_name, $addon, $from_db);
745
-        }
746
-        $this->_cache_on = true;
747
-        return $class_obj;
748
-    }
749
-
750
-
751
-
752
-    /**
753
-     * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
754
-     *
755
-     * @param string $class_name
756
-     * @param array  $arguments
757
-     * @param int    $attempt
758
-     * @return mixed
759
-     */
760
-    private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) {
761
-        if (is_object($class_name) || class_exists($class_name)) {
762
-            return $class_name;
763
-        }
764
-        switch ($attempt) {
765
-            case 1:
766
-                // if it's a FQCN then maybe the class is registered with a preceding \
767
-                $class_name = strpos($class_name, '\\') !== false
768
-                    ? '\\' . ltrim($class_name, '\\')
769
-                    : $class_name;
770
-                break;
771
-            case 2:
772
-                //
773
-                $loader = $this->_dependency_map->class_loader($class_name);
774
-                if ($loader && method_exists($this, $loader)) {
775
-                    return $this->{$loader}($class_name, $arguments);
776
-                }
777
-                break;
778
-            case 3:
779
-            default;
780
-                return null;
781
-        }
782
-        $attempt++;
783
-        return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
784
-    }
785
-
786
-
787
-
788
-    /**
789
-     * instantiates, caches, and injects dependencies for classes
790
-     *
791
-     * @param array       $file_paths   an array of paths to folders to look in
792
-     * @param string      $class_prefix EE  or EEM or... ???
793
-     * @param bool|string $class_name   $class name
794
-     * @param string      $type         file type - core? class? helper? model?
795
-     * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
796
-     * @param bool        $from_db      some classes are instantiated from the db
797
-     *                                  and thus call a different method to instantiate
798
-     * @param bool        $cache        whether to cache the instantiated object for reuse
799
-     * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
800
-     * @return bool|null|object null = failure to load or instantiate class object.
801
-     *                                  object = class loaded and instantiated successfully.
802
-     *                                  bool = fail or success when $load_only is true
803
-     * @throws EE_Error
804
-     * @throws ReflectionException
805
-     * @throws InvalidInterfaceException
806
-     * @throws InvalidDataTypeException
807
-     * @throws InvalidClassException
808
-     */
809
-    protected function _load(
810
-        $file_paths = array(),
811
-        $class_prefix = 'EE_',
812
-        $class_name = false,
813
-        $type = 'class',
814
-        $arguments = array(),
815
-        $from_db = false,
816
-        $cache = true,
817
-        $load_only = false
818
-    ) {
819
-        $class_name = ltrim($class_name, '\\');
820
-        // strip php file extension
821
-        $class_name = str_replace('.php', '', trim($class_name));
822
-        // does the class have a prefix ?
823
-        if (! empty($class_prefix) && $class_prefix !== 'addon') {
824
-            // make sure $class_prefix is uppercase
825
-            $class_prefix = strtoupper(trim($class_prefix));
826
-            // add class prefix ONCE!!!
827
-            $class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
828
-        }
829
-        $class_name = $this->class_cache->getFqnForAlias($class_name);
830
-        $class_exists = class_exists($class_name, false);
831
-        // if we're only loading the class and it already exists, then let's just return true immediately
832
-        if ($load_only && $class_exists) {
833
-            return true;
834
-        }
835
-        // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
836
-        // $cache is controlled by individual calls to separate Registry loader methods like load_class()
837
-        // $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
838
-        if ($this->_cache_on && $cache && ! $load_only) {
839
-            // return object if it's already cached
840
-            $cached_class = $this->_get_cached_class($class_name, $class_prefix);
841
-            if ($cached_class !== null) {
842
-                return $cached_class;
843
-            }
844
-        }
845
-        // if the class doesn't already exist.. then we need to try and find the file and load it
846
-        if (! $class_exists) {
847
-            // get full path to file
848
-            $path = $this->_resolve_path($class_name, $type, $file_paths);
849
-            // load the file
850
-            $loaded = $this->_require_file($path, $class_name, $type, $file_paths);
851
-            // if loading failed, or we are only loading a file but NOT instantiating an object
852
-            if (! $loaded || $load_only) {
853
-                // return boolean if only loading, or null if an object was expected
854
-                return $load_only
855
-                    ? $loaded
856
-                    : null;
857
-            }
858
-        }
859
-        // instantiate the requested object
860
-        $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
861
-        if ($this->_cache_on && $cache) {
862
-            // save it for later... kinda like gum  { : $
863
-            $this->_set_cached_class($class_obj, $class_name, $class_prefix, $from_db);
864
-        }
865
-        $this->_cache_on = true;
866
-        return $class_obj;
867
-    }
868
-
869
-
870
-
871
-    /**
872
-     * @param string $class_name
873
-     * @param string $default have to specify something, but not anything that will conflict
874
-     * @return mixed|string
875
-     */
876
-    protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
877
-    {
878
-        return isset($this->_class_abbreviations[$class_name])
879
-            ? $this->_class_abbreviations[$class_name]
880
-            : $default;
881
-    }
882
-
883
-    /**
884
-     * attempts to find a cached version of the requested class
885
-     * by looking in the following places:
886
-     *        $this->{$class_abbreviation}            ie:    $this->CART
887
-     *        $this->{$class_name}                        ie:    $this->Some_Class
888
-     *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
889
-     *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
890
-     *
891
-     * @param string $class_name
892
-     * @param string $class_prefix
893
-     * @return mixed
894
-     */
895
-    protected function _get_cached_class($class_name, $class_prefix = '')
896
-    {
897
-        if ($class_name === 'EE_Registry') {
898
-            return $this;
899
-        }
900
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
901
-        $class_name = str_replace('\\', '_', $class_name);
902
-        // check if class has already been loaded, and return it if it has been
903
-        if (isset($this->{$class_abbreviation})) {
904
-            return $this->{$class_abbreviation};
905
-        }
906
-        if (isset ($this->{$class_name})) {
907
-            return $this->{$class_name};
908
-        }
909
-        if (isset ($this->LIB->{$class_name})) {
910
-            return $this->LIB->{$class_name};
911
-        }
912
-        if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
913
-            return $this->addons->{$class_name};
914
-        }
915
-        return null;
916
-    }
917
-
918
-
919
-
920
-    /**
921
-     * removes a cached version of the requested class
922
-     *
923
-     * @param string  $class_name
924
-     * @param boolean $addon
925
-     * @return boolean
926
-     */
927
-    public function clear_cached_class($class_name, $addon = false)
928
-    {
929
-        $class_abbreviation = $this->get_class_abbreviation($class_name);
930
-        $class_name = str_replace('\\', '_', $class_name);
931
-        // check if class has already been loaded, and return it if it has been
932
-        if (isset($this->{$class_abbreviation})) {
933
-            $this->{$class_abbreviation} = null;
934
-            return true;
935
-        }
936
-        if (isset($this->{$class_name})) {
937
-            $this->{$class_name} = null;
938
-            return true;
939
-        }
940
-        if (isset($this->LIB->{$class_name})) {
941
-            unset($this->LIB->{$class_name});
942
-            return true;
943
-        }
944
-        if ($addon && isset($this->addons->{$class_name})) {
945
-            unset($this->addons->{$class_name});
946
-            return true;
947
-        }
948
-        return false;
949
-    }
950
-
951
-
952
-
953
-    /**
954
-     * attempts to find a full valid filepath for the requested class.
955
-     * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
956
-     * then returns that path if the target file has been found and is readable
957
-     *
958
-     * @param string $class_name
959
-     * @param string $type
960
-     * @param array  $file_paths
961
-     * @return string | bool
962
-     */
963
-    protected function _resolve_path($class_name, $type = '', $file_paths = array())
964
-    {
965
-        // make sure $file_paths is an array
966
-        $file_paths = is_array($file_paths)
967
-            ? $file_paths
968
-            : array($file_paths);
969
-        // cycle thru paths
970
-        foreach ($file_paths as $key => $file_path) {
971
-            // convert all separators to proper DS, if no filepath, then use EE_CLASSES
972
-            $file_path = $file_path
973
-                ? str_replace(array('/', '\\'), DS, $file_path)
974
-                : EE_CLASSES;
975
-            // prep file type
976
-            $type = ! empty($type)
977
-                ? trim($type, '.') . '.'
978
-                : '';
979
-            // build full file path
980
-            $file_paths[$key] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
981
-            //does the file exist and can be read ?
982
-            if (is_readable($file_paths[$key])) {
983
-                return $file_paths[$key];
984
-            }
985
-        }
986
-        return false;
987
-    }
988
-
989
-
990
-
991
-    /**
992
-     * basically just performs a require_once()
993
-     * but with some error handling
994
-     *
995
-     * @param  string $path
996
-     * @param  string $class_name
997
-     * @param  string $type
998
-     * @param  array  $file_paths
999
-     * @return bool
1000
-     * @throws EE_Error
1001
-     * @throws ReflectionException
1002
-     */
1003
-    protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1004
-    {
1005
-        $this->resolve_legacy_class_parent($class_name);
1006
-        // don't give up! you gotta...
1007
-        try {
1008
-            //does the file exist and can it be read ?
1009
-            if (! $path) {
1010
-                // just in case the file has already been autoloaded,
1011
-                // but discrepancies in the naming schema are preventing it from
1012
-                // being loaded via one of the EE_Registry::load_*() methods,
1013
-                // then let's try one last hail mary before throwing an exception
1014
-                // and call class_exists() again, but with autoloading turned ON
1015
-                if(class_exists($class_name)) {
1016
-                    return true;
1017
-                }
1018
-                // so sorry, can't find the file
1019
-                throw new EE_Error (
1020
-                    sprintf(
1021
-                        esc_html__(
1022
-                            'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s',
1023
-                            'event_espresso'
1024
-                        ),
1025
-                        trim($type, '.'),
1026
-                        $class_name,
1027
-                        '<br />' . implode(',<br />', $file_paths)
1028
-                    )
1029
-                );
1030
-            }
1031
-            // get the file
1032
-            require_once($path);
1033
-            // if the class isn't already declared somewhere
1034
-            if (class_exists($class_name, false) === false) {
1035
-                // so sorry, not a class
1036
-                throw new EE_Error(
1037
-                    sprintf(
1038
-                        esc_html__('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
1039
-                        $type,
1040
-                        $path,
1041
-                        $class_name
1042
-                    )
1043
-                );
1044
-            }
1045
-        } catch (EE_Error $e) {
1046
-            $e->get_error();
1047
-            return false;
1048
-        }
1049
-        return true;
1050
-    }
1051
-
1052
-
1053
-
1054
-    /**
1055
-     * Some of our legacy classes that extended a parent class would simply use a require() statement
1056
-     * before their class declaration in order to ensure that the parent class was loaded.
1057
-     * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1058
-     * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1059
-     *
1060
-     * @param string $class_name
1061
-     */
1062
-    protected function resolve_legacy_class_parent($class_name = '')
1063
-    {
1064
-        try {
1065
-            $legacy_parent_class_map = array(
1066
-                'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php'
1067
-            );
1068
-            if(isset($legacy_parent_class_map[$class_name])) {
1069
-                require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[$class_name];
1070
-            }
1071
-        } catch (Exception $exception) {
1072
-        }
1073
-    }
1074
-
1075
-
1076
-    /**
1077
-     * _create_object
1078
-     * Attempts to instantiate the requested class via any of the
1079
-     * commonly used instantiation methods employed throughout EE.
1080
-     * The priority for instantiation is as follows:
1081
-     *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1082
-     *        - model objects via their 'new_instance_from_db' method
1083
-     *        - model objects via their 'new_instance' method
1084
-     *        - "singleton" classes" via their 'instance' method
1085
-     *    - standard instantiable classes via their __constructor
1086
-     * Prior to instantiation, if the classname exists in the dependency_map,
1087
-     * then the constructor for the requested class will be examined to determine
1088
-     * if any dependencies exist, and if they can be injected.
1089
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1090
-     *
1091
-     * @param string $class_name
1092
-     * @param array  $arguments
1093
-     * @param string $type
1094
-     * @param bool   $from_db
1095
-     * @return null|object
1096
-     * @throws EE_Error
1097
-     * @throws ReflectionException
1098
-     * @throws InvalidDataTypeException
1099
-     */
1100
-    protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1101
-    {
1102
-        // create reflection
1103
-        $reflector = $this->mirror->getReflectionClass($class_name);
1104
-        // make sure arguments are an array
1105
-        $arguments = is_array($arguments)
1106
-            ? $arguments
1107
-            : array($arguments);
1108
-        // and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1109
-        // else wrap it in an additional array so that it doesn't get split into multiple parameters
1110
-        $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1111
-            ? $arguments
1112
-            : array($arguments);
1113
-        // attempt to inject dependencies ?
1114
-        if ($this->_dependency_map->has($class_name)) {
1115
-            $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1116
-        }
1117
-        // instantiate the class if possible
1118
-        if ($reflector->isAbstract()) {
1119
-            // nothing to instantiate, loading file was enough
1120
-            // does not throw an exception so $instantiation_mode is unused
1121
-            // $instantiation_mode = "1) no constructor abstract class";
1122
-            return true;
1123
-        }
1124
-        if (
1125
-            empty($arguments)
1126
-            && $this->mirror->getConstructorFromReflection($reflector) === null
1127
-            && $reflector->isInstantiable()
1128
-        ) {
1129
-            // no constructor = static methods only... nothing to instantiate, loading file was enough
1130
-            // $instantiation_mode = "2) no constructor but instantiable";
1131
-            return $reflector->newInstance();
1132
-        }
1133
-        if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1134
-            // $instantiation_mode = "3) new_instance_from_db()";
1135
-            return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1136
-        }
1137
-        if (method_exists($class_name, 'new_instance')) {
1138
-            // $instantiation_mode = "4) new_instance()";
1139
-            return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1140
-        }
1141
-        if (method_exists($class_name, 'instance')) {
1142
-            // $instantiation_mode = "5) instance()";
1143
-            return call_user_func_array(array($class_name, 'instance'), $arguments);
1144
-        }
1145
-        if ($reflector->isInstantiable()) {
1146
-            // $instantiation_mode = "6) constructor";
1147
-            return $reflector->newInstanceArgs($arguments);
1148
-        }
1149
-        // heh ? something's not right !
1150
-        throw new EE_Error(
1151
-            sprintf(
1152
-                __('The %s file %s could not be instantiated.', 'event_espresso'),
1153
-                $type,
1154
-                $class_name
1155
-            )
1156
-        );
1157
-    }
1158
-
1159
-
1160
-
1161
-    /**
1162
-     * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1163
-     * @param array $array
1164
-     * @return bool
1165
-     */
1166
-    protected function _array_is_numerically_and_sequentially_indexed(array $array)
1167
-    {
1168
-        return ! empty($array)
1169
-            ? array_keys($array) === range(0, count($array) - 1)
1170
-            : true;
1171
-    }
1172
-
1173
-
1174
-    /**
1175
-     * _resolve_dependencies
1176
-     * examines the constructor for the requested class to determine
1177
-     * if any dependencies exist, and if they can be injected.
1178
-     * If so, then those classes will be added to the array of arguments passed to the constructor
1179
-     * PLZ NOTE: this is achieved by type hinting the constructor params
1180
-     * For example:
1181
-     *        if attempting to load a class "Foo" with the following constructor:
1182
-     *        __construct( Bar $bar_class, Fighter $grohl_class )
1183
-     *        then $bar_class and $grohl_class will be added to the $arguments array,
1184
-     *        but only IF they are NOT already present in the incoming arguments array,
1185
-     *        and the correct classes can be loaded
1186
-     *
1187
-     * @param ReflectionClass $reflector
1188
-     * @param string          $class_name
1189
-     * @param array           $arguments
1190
-     * @return array
1191
-     * @throws EE_Error
1192
-     * @throws InvalidArgumentException
1193
-     * @throws InvalidDataTypeException
1194
-     * @throws InvalidInterfaceException
1195
-     * @throws ReflectionException
1196
-     * @throws InvalidClassException
1197
-     */
1198
-    protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1199
-    {
1200
-        // let's examine the constructor
1201
-        $constructor = $this->mirror->getConstructorFromReflection($reflector);
1202
-        // whu? huh? nothing?
1203
-        if (! $constructor) {
1204
-            return $arguments;
1205
-        }
1206
-        // get constructor parameters
1207
-        $params = $this->mirror->getParametersFromReflection($reflector);
1208
-        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1209
-        $argument_keys = array_keys($arguments);
1210
-        // now loop thru all of the constructors expected parameters
1211
-        foreach ($params as $index => $param) {
1212
-            // is this a dependency for a specific class ?
1213
-            $param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1214
-            // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1215
-            $param_class = $this->class_cache->isAlias($param_class, $class_name)
1216
-                ? $this->class_cache->getFqnForAlias($param_class, $class_name)
1217
-                : $param_class;
1218
-            if (
1219
-                // param is not even a class
1220
-                $param_class === null
1221
-                // and something already exists in the incoming arguments for this param
1222
-                && array_key_exists($index, $argument_keys)
1223
-                && array_key_exists($argument_keys[$index], $arguments)
1224
-            ) {
1225
-                // so let's skip this argument and move on to the next
1226
-                continue;
1227
-            }
1228
-            if (
1229
-                // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1230
-                $param_class !== null
1231
-                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1232
-                && $arguments[$argument_keys[$index]] instanceof $param_class
1233
-            ) {
1234
-                // skip this argument and move on to the next
1235
-                continue;
1236
-            }
1237
-            if (
1238
-                // parameter is type hinted as a class, and should be injected
1239
-                $param_class !== null
1240
-                && $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1241
-            ) {
1242
-                $arguments = $this->_resolve_dependency(
1243
-                    $class_name,
1244
-                    $param_class,
1245
-                    $arguments,
1246
-                    $index,
1247
-                    $argument_keys
1248
-                );
1249
-            } else {
1250
-                try {
1251
-                    $arguments[$index] = $this->mirror->getParameterDefaultValue(
1252
-                        $param,
1253
-                        $class_name,
1254
-                        $index
1255
-                    );
1256
-                } catch (ReflectionException $e) {
1257
-                    throw new ReflectionException(
1258
-                        sprintf(
1259
-                            esc_html__('%1$s for parameter "$%2$s on classname "%3$s"', 'event_espresso'),
1260
-                            $e->getMessage(),
1261
-                            $param->getName(),
1262
-                            $class_name
1263
-                        )
1264
-                    );
1265
-                }
1266
-            }
1267
-        }
1268
-        return $arguments;
1269
-    }
1270
-
1271
-
1272
-
1273
-    /**
1274
-     * @param string $class_name
1275
-     * @param string $param_class
1276
-     * @param array  $arguments
1277
-     * @param mixed  $index
1278
-     * @param array  $argument_keys
1279
-     * @return array
1280
-     * @throws EE_Error
1281
-     * @throws ReflectionException
1282
-     * @throws InvalidArgumentException
1283
-     * @throws InvalidInterfaceException
1284
-     * @throws InvalidDataTypeException
1285
-     */
1286
-    protected function _resolve_dependency($class_name, $param_class, $arguments, $index, array $argument_keys)
1287
-    {
1288
-        $dependency = null;
1289
-        // should dependency be loaded from cache ?
1290
-        $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1291
-            $class_name,
1292
-            $param_class
1293
-        );
1294
-        $cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1295
-        // we might have a dependency...
1296
-        // let's MAYBE try and find it in our cache if that's what's been requested
1297
-        $cached_class = $cache_on
1298
-            ? $this->_get_cached_class($param_class)
1299
-            : null;
1300
-        // and grab it if it exists
1301
-        if ($cached_class instanceof $param_class) {
1302
-            $dependency = $cached_class;
1303
-        } else if ($param_class !== $class_name) {
1304
-            // obtain the loader method from the dependency map
1305
-            $loader = $this->_dependency_map->class_loader($param_class);
1306
-            // is loader a custom closure ?
1307
-            if ($loader instanceof Closure) {
1308
-                $dependency = $loader($arguments);
1309
-            } else {
1310
-                // set the cache on property for the recursive loading call
1311
-                $this->_cache_on = $cache_on;
1312
-                // if not, then let's try and load it via the registry
1313
-                if ($loader && method_exists($this, $loader)) {
1314
-                    $dependency = $this->{$loader}($param_class);
1315
-                } else {
1316
-                    $dependency = LoaderFactory::getLoader()->load(
1317
-                        $param_class,
1318
-                        array(),
1319
-                        $cache_on
1320
-                    );
1321
-                }
1322
-            }
1323
-        }
1324
-        // did we successfully find the correct dependency ?
1325
-        if ($dependency instanceof $param_class) {
1326
-            // then let's inject it into the incoming array of arguments at the correct location
1327
-            $arguments[$index] = $dependency;
1328
-        }
1329
-        return $arguments;
1330
-    }
1331
-
1332
-
1333
-
1334
-    /**
1335
-     * _set_cached_class
1336
-     * attempts to cache the instantiated class locally
1337
-     * in one of the following places, in the following order:
1338
-     *        $this->{class_abbreviation}   ie:    $this->CART
1339
-     *        $this->{$class_name}          ie:    $this->Some_Class
1340
-     *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1341
-     *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1342
-     *
1343
-     * @param object $class_obj
1344
-     * @param string $class_name
1345
-     * @param string $class_prefix
1346
-     * @param bool   $from_db
1347
-     * @return void
1348
-     */
1349
-    protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1350
-    {
1351
-        if ($class_name === 'EE_Registry' || empty($class_obj)) {
1352
-            return;
1353
-        }
1354
-        // return newly instantiated class
1355
-        $class_abbreviation = $this->get_class_abbreviation($class_name, '');
1356
-        if ($class_abbreviation) {
1357
-            $this->{$class_abbreviation} = $class_obj;
1358
-            return;
1359
-        }
1360
-        $class_name = str_replace('\\', '_', $class_name);
1361
-        if (property_exists($this, $class_name)) {
1362
-            $this->{$class_name} = $class_obj;
1363
-            return;
1364
-        }
1365
-        if ($class_prefix === 'addon') {
1366
-            $this->addons->{$class_name} = $class_obj;
1367
-            return;
1368
-        }
1369
-        if (! $from_db) {
1370
-            $this->LIB->{$class_name} = $class_obj;
1371
-        }
1372
-    }
1373
-
1374
-
1375
-
1376
-    /**
1377
-     * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1378
-     *
1379
-     * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1380
-     *                          in the EE_Dependency_Map::$_class_loaders array,
1381
-     *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1382
-     * @param array  $arguments
1383
-     * @return object
1384
-     */
1385
-    public static function factory($classname, $arguments = array())
1386
-    {
1387
-        $loader = self::instance()->_dependency_map->class_loader($classname);
1388
-        if ($loader instanceof Closure) {
1389
-            return $loader($arguments);
1390
-        }
1391
-        if (method_exists(self::instance(), $loader)) {
1392
-            return self::instance()->{$loader}($classname, $arguments);
1393
-        }
1394
-        return null;
1395
-    }
1396
-
1397
-
1398
-
1399
-    /**
1400
-     * Gets the addon by its class name
1401
-     *
1402
-     * @param string $class_name
1403
-     * @return EE_Addon
1404
-     */
1405
-    public function getAddon($class_name)
1406
-    {
1407
-        $class_name = str_replace('\\', '_', $class_name);
1408
-        return $this->addons->{$class_name};
1409
-    }
1410
-
1411
-
1412
-    /**
1413
-     * removes the addon from the internal cache
1414
-     *
1415
-     * @param string $class_name
1416
-     * @return void
1417
-     */
1418
-    public function removeAddon($class_name)
1419
-    {
1420
-        $class_name = str_replace('\\', '_', $class_name);
1421
-        unset($this->addons->{$class_name});
1422
-    }
1423
-
1424
-
1425
-
1426
-    /**
1427
-     * Gets the addon by its name/slug (not classname. For that, just
1428
-     * use the get_addon() method above
1429
-     *
1430
-     * @param string $name
1431
-     * @return EE_Addon
1432
-     */
1433
-    public function get_addon_by_name($name)
1434
-    {
1435
-        foreach ($this->addons as $addon) {
1436
-            if ($addon->name() === $name) {
1437
-                return $addon;
1438
-            }
1439
-        }
1440
-        return null;
1441
-    }
1442
-
1443
-
1444
-
1445
-    /**
1446
-     * Gets an array of all the registered addons, where the keys are their names.
1447
-     * (ie, what each returns for their name() function)
1448
-     * They're already available on EE_Registry::instance()->addons as properties,
1449
-     * where each property's name is the addon's classname,
1450
-     * So if you just want to get the addon by classname,
1451
-     * OR use the get_addon() method above.
1452
-     * PLEASE  NOTE:
1453
-     * addons with Fully Qualified Class Names
1454
-     * have had the namespace separators converted to underscores,
1455
-     * so a classname like Fully\Qualified\ClassName
1456
-     * would have been converted to Fully_Qualified_ClassName
1457
-     *
1458
-     * @return EE_Addon[] where the KEYS are the addon's name()
1459
-     */
1460
-    public function get_addons_by_name()
1461
-    {
1462
-        $addons = array();
1463
-        foreach ($this->addons as $addon) {
1464
-            $addons[$addon->name()] = $addon;
1465
-        }
1466
-        return $addons;
1467
-    }
1468
-
1469
-
1470
-    /**
1471
-     * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1472
-     * a stale copy of it around
1473
-     *
1474
-     * @param string $model_name
1475
-     * @return \EEM_Base
1476
-     * @throws \EE_Error
1477
-     */
1478
-    public function reset_model($model_name)
1479
-    {
1480
-        $model_class_name = strpos($model_name, 'EEM_') !== 0
1481
-            ? "EEM_{$model_name}"
1482
-            : $model_name;
1483
-        if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1484
-            return null;
1485
-        }
1486
-        //get that model reset it and make sure we nuke the old reference to it
1487
-        if ($this->LIB->{$model_class_name} instanceof $model_class_name
1488
-            && is_callable(
1489
-                array($model_class_name, 'reset')
1490
-            )) {
1491
-            $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1492
-        } else {
1493
-            throw new EE_Error(sprintf(esc_html__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1494
-        }
1495
-        return $this->LIB->{$model_class_name};
1496
-    }
1497
-
1498
-
1499
-
1500
-    /**
1501
-     * Resets the registry.
1502
-     * The criteria for what gets reset is based on what can be shared between sites on the same request when
1503
-     * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1504
-     * - $_dependency_map
1505
-     * - $_class_abbreviations
1506
-     * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1507
-     * - $REQ:  Still on the same request so no need to change.
1508
-     * - $CAP: There is no site specific state in the EE_Capability class.
1509
-     * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1510
-     * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1511
-     * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1512
-     *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1513
-     *             switch or on the restore.
1514
-     * - $modules
1515
-     * - $shortcodes
1516
-     * - $widgets
1517
-     *
1518
-     * @param boolean $hard             [deprecated]
1519
-     * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1520
-     *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1521
-     *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1522
-     * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1523
-     *                                  client
1524
-     *                                  code instead can just change the model context to a different blog id if
1525
-     *                                  necessary
1526
-     * @return EE_Registry
1527
-     * @throws EE_Error
1528
-     * @throws ReflectionException
1529
-     */
1530
-    public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1531
-    {
1532
-        $instance = self::instance();
1533
-        $instance->_cache_on = true;
1534
-        // reset some "special" classes
1535
-        EEH_Activation::reset();
1536
-        $hard = apply_filters( 'FHEE__EE_Registry__reset__hard', $hard);
1537
-        $instance->CFG = EE_Config::reset($hard, $reinstantiate);
1538
-        $instance->CART = null;
1539
-        $instance->MRM = null;
1540
-        $instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1541
-        //messages reset
1542
-        EED_Messages::reset();
1543
-        //handle of objects cached on LIB
1544
-        foreach (array('LIB', 'modules') as $cache) {
1545
-            foreach ($instance->{$cache} as $class_name => $class) {
1546
-                if (self::_reset_and_unset_object($class, $reset_models)) {
1547
-                    unset($instance->{$cache}->{$class_name});
1548
-                }
1549
-            }
1550
-        }
1551
-        return $instance;
1552
-    }
1553
-
1554
-
1555
-
1556
-    /**
1557
-     * if passed object implements ResettableInterface, then call it's reset() method
1558
-     * if passed object implements InterminableInterface, then return false,
1559
-     * to indicate that it should NOT be cleared from the Registry cache
1560
-     *
1561
-     * @param      $object
1562
-     * @param bool $reset_models
1563
-     * @return bool returns true if cached object should be unset
1564
-     */
1565
-    private static function _reset_and_unset_object($object, $reset_models)
1566
-    {
1567
-        if (! is_object($object)) {
1568
-            // don't unset anything that's not an object
1569
-            return false;
1570
-        }
1571
-        if ($object instanceof EED_Module) {
1572
-            $object::reset();
1573
-            // don't unset modules
1574
-            return false;
1575
-        }
1576
-        if ($object instanceof ResettableInterface) {
1577
-            if ($object instanceof EEM_Base) {
1578
-                if ($reset_models) {
1579
-                    $object->reset();
1580
-                    return true;
1581
-                }
1582
-                return false;
1583
-            }
1584
-            $object->reset();
1585
-            return true;
1586
-        }
1587
-        if (! $object instanceof InterminableInterface) {
1588
-            return true;
1589
-        }
1590
-        return false;
1591
-    }
1592
-
1593
-
1594
-
1595
-    /**
1596
-     * Gets all the custom post type models defined
1597
-     *
1598
-     * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1599
-     */
1600
-    public function cpt_models()
1601
-    {
1602
-        $cpt_models = array();
1603
-        foreach ($this->non_abstract_db_models as $short_name => $classname) {
1604
-            if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1605
-                $cpt_models[$short_name] = $classname;
1606
-            }
1607
-        }
1608
-        return $cpt_models;
1609
-    }
1610
-
1611
-
1612
-
1613
-    /**
1614
-     * @return \EE_Config
1615
-     */
1616
-    public static function CFG()
1617
-    {
1618
-        return self::instance()->CFG;
1619
-    }
1620
-
1621
-
1622
-    /**
1623
-     * @deprecated $VID:$
1624
-     * @param string $class_name
1625
-     * @return ReflectionClass
1626
-     * @throws ReflectionException
1627
-     * @throws InvalidDataTypeException
1628
-     */
1629
-    public function get_ReflectionClass($class_name)
1630
-    {
1631
-        return $this->mirror->getReflectionClass($class_name);
1632
-    }
30
+	/**
31
+	 * @var EE_Registry $_instance
32
+	 */
33
+	private static $_instance;
34
+
35
+	/**
36
+	 * @var EE_Dependency_Map $_dependency_map
37
+	 */
38
+	protected $_dependency_map;
39
+
40
+	/**
41
+	 * @var Mirror
42
+	 */
43
+	private $mirror;
44
+
45
+	/**
46
+	 * @var ClassInterfaceCache $class_cache
47
+	 */
48
+	private $class_cache;
49
+
50
+	/**
51
+	 * @var array $_class_abbreviations
52
+	 */
53
+	protected $_class_abbreviations = array();
54
+
55
+	/**
56
+	 * @var CommandBusInterface $BUS
57
+	 */
58
+	public $BUS;
59
+
60
+	/**
61
+	 * @var EE_Cart $CART
62
+	 */
63
+	public $CART;
64
+
65
+	/**
66
+	 * @var EE_Config $CFG
67
+	 */
68
+	public $CFG;
69
+
70
+	/**
71
+	 * @var EE_Network_Config $NET_CFG
72
+	 */
73
+	public $NET_CFG;
74
+
75
+	/**
76
+	 * StdClass object for storing library classes in
77
+	 *
78
+	 * @var StdClass $LIB
79
+	 */
80
+	public $LIB;
81
+
82
+	/**
83
+	 * @var EE_Request_Handler $REQ
84
+	 */
85
+	public $REQ;
86
+
87
+	/**
88
+	 * @var EE_Session $SSN
89
+	 */
90
+	public $SSN;
91
+
92
+	/**
93
+	 * @since 4.5.0
94
+	 * @var EE_Capabilities $CAP
95
+	 */
96
+	public $CAP;
97
+
98
+	/**
99
+	 * @since 4.9.0
100
+	 * @var EE_Message_Resource_Manager $MRM
101
+	 */
102
+	public $MRM;
103
+
104
+
105
+	/**
106
+	 * @var Registry $AssetsRegistry
107
+	 */
108
+	public $AssetsRegistry;
109
+
110
+	/**
111
+	 * StdClass object for holding addons which have registered themselves to work with EE core
112
+	 *
113
+	 * @var EE_Addon[] $addons
114
+	 */
115
+	public $addons;
116
+
117
+	/**
118
+	 * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event')
119
+	 *
120
+	 * @var EEM_Base[] $models
121
+	 */
122
+	public $models = array();
123
+
124
+	/**
125
+	 * @var EED_Module[] $modules
126
+	 */
127
+	public $modules;
128
+
129
+	/**
130
+	 * @var EES_Shortcode[] $shortcodes
131
+	 */
132
+	public $shortcodes;
133
+
134
+	/**
135
+	 * @var WP_Widget[] $widgets
136
+	 */
137
+	public $widgets;
138
+
139
+	/**
140
+	 * this is an array of all implemented model names (i.e. not the parent abstract models, or models
141
+	 * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)).
142
+	 * Keys are model "short names" (eg "Event") as used in model relations, and values are
143
+	 * classnames (eg "EEM_Event")
144
+	 *
145
+	 * @var array $non_abstract_db_models
146
+	 */
147
+	public $non_abstract_db_models = array();
148
+
149
+
150
+	/**
151
+	 * internationalization for JS strings
152
+	 *    usage:   EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' );
153
+	 *    in js file:  var translatedString = eei18n.string_key;
154
+	 *
155
+	 * @var array $i18n_js_strings
156
+	 */
157
+	public static $i18n_js_strings = array();
158
+
159
+
160
+	/**
161
+	 * $main_file - path to espresso.php
162
+	 *
163
+	 * @var array $main_file
164
+	 */
165
+	public $main_file;
166
+
167
+	/**
168
+	 * array of ReflectionClass objects where the key is the class name
169
+	 *
170
+	 * @deprecated $VID:$
171
+	 * @var ReflectionClass[] $_reflectors
172
+	 */
173
+	public $_reflectors;
174
+
175
+	/**
176
+	 * boolean flag to indicate whether or not to load/save dependencies from/to the cache
177
+	 *
178
+	 * @var boolean $_cache_on
179
+	 */
180
+	protected $_cache_on = true;
181
+
182
+
183
+	/**
184
+	 * @singleton method used to instantiate class object
185
+	 * @param EE_Dependency_Map|null   $dependency_map
186
+	 * @param Mirror|null              $mirror
187
+	 * @param ClassInterfaceCache|null $class_cache
188
+	 * @return EE_Registry instance
189
+	 */
190
+	public static function instance(
191
+		EE_Dependency_Map $dependency_map = null,
192
+		Mirror $mirror = null,
193
+		ClassInterfaceCache $class_cache = null
194
+	) {
195
+		// check if class object is instantiated
196
+		if (
197
+			! self::$_instance instanceof EE_Registry
198
+			&& $dependency_map instanceof EE_Dependency_Map
199
+			&& $mirror instanceof Mirror
200
+			&& $class_cache instanceof ClassInterfaceCache
201
+		) {
202
+			self::$_instance = new self($dependency_map, $mirror, $class_cache);
203
+		}
204
+		return self::$_instance;
205
+	}
206
+
207
+
208
+	/**
209
+	 * protected constructor to prevent direct creation
210
+	 *
211
+	 * @Constructor
212
+	 * @param  EE_Dependency_Map  $dependency_map
213
+	 * @param Mirror              $mirror
214
+	 * @param ClassInterfaceCache $class_cache
215
+	 */
216
+	protected function __construct(EE_Dependency_Map $dependency_map, Mirror $mirror, ClassInterfaceCache $class_cache)
217
+	{
218
+		$this->_dependency_map = $dependency_map;
219
+		$this->mirror = $mirror;
220
+		$this->class_cache = $class_cache;
221
+		// $registry_container = new RegistryContainer();
222
+		$this->LIB = new RegistryContainer();
223
+		$this->addons = new RegistryContainer();
224
+		$this->modules = new RegistryContainer();
225
+		$this->shortcodes = new RegistryContainer();
226
+		$this->widgets = new RegistryContainer();
227
+		add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
228
+	}
229
+
230
+
231
+
232
+	/**
233
+	 * initialize
234
+	 *
235
+	 * @throws EE_Error
236
+	 * @throws ReflectionException
237
+	 */
238
+	public function initialize()
239
+	{
240
+		$this->_class_abbreviations = apply_filters(
241
+			'FHEE__EE_Registry____construct___class_abbreviations',
242
+			array(
243
+				'EE_Config'                                       => 'CFG',
244
+				'EE_Session'                                      => 'SSN',
245
+				'EE_Capabilities'                                 => 'CAP',
246
+				'EE_Cart'                                         => 'CART',
247
+				'EE_Network_Config'                               => 'NET_CFG',
248
+				'EE_Request_Handler'                              => 'REQ',
249
+				'EE_Message_Resource_Manager'                     => 'MRM',
250
+				'EventEspresso\core\services\commands\CommandBus' => 'BUS',
251
+				'EventEspresso\core\services\assets\Registry'     => 'AssetsRegistry',
252
+			)
253
+		);
254
+		$this->load_core('Base', array(), true);
255
+		// add our request and response objects to the cache
256
+		$request_loader = $this->_dependency_map->class_loader(
257
+			'EventEspresso\core\services\request\Request'
258
+		);
259
+		$this->_set_cached_class(
260
+			$request_loader(),
261
+			'EventEspresso\core\services\request\Request'
262
+		);
263
+		$response_loader = $this->_dependency_map->class_loader(
264
+			'EventEspresso\core\services\request\Response'
265
+		);
266
+		$this->_set_cached_class(
267
+			$response_loader(),
268
+			'EventEspresso\core\services\request\Response'
269
+		);
270
+		add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init'));
271
+	}
272
+
273
+
274
+
275
+	/**
276
+	 * @return void
277
+	 */
278
+	public function init()
279
+	{
280
+		// Get current page protocol
281
+		$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
282
+		// Output admin-ajax.php URL with same protocol as current page
283
+		self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol);
284
+		self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false;
285
+	}
286
+
287
+
288
+
289
+	/**
290
+	 * localize_i18n_js_strings
291
+	 *
292
+	 * @return string
293
+	 */
294
+	public static function localize_i18n_js_strings()
295
+	{
296
+		$i18n_js_strings = (array)self::$i18n_js_strings;
297
+		foreach ($i18n_js_strings as $key => $value) {
298
+			if (is_scalar($value)) {
299
+				$i18n_js_strings[$key] = html_entity_decode((string)$value, ENT_QUOTES, 'UTF-8');
300
+			}
301
+		}
302
+		return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */';
303
+	}
304
+
305
+
306
+
307
+	/**
308
+	 * @param mixed string | EED_Module $module
309
+	 * @throws EE_Error
310
+	 * @throws ReflectionException
311
+	 */
312
+	public function add_module($module)
313
+	{
314
+		if ($module instanceof EED_Module) {
315
+			$module_class = get_class($module);
316
+			$this->modules->{$module_class} = $module;
317
+		} else {
318
+			if ( ! class_exists('EE_Module_Request_Router', false)) {
319
+				$this->load_core('Module_Request_Router');
320
+			}
321
+			EE_Module_Request_Router::module_factory($module);
322
+		}
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * @param string $module_name
329
+	 * @return mixed EED_Module | NULL
330
+	 */
331
+	public function get_module($module_name = '')
332
+	{
333
+		return isset($this->modules->{$module_name})
334
+			? $this->modules->{$module_name}
335
+			: null;
336
+	}
337
+
338
+
339
+
340
+	/**
341
+	 * loads core classes - must be singletons
342
+	 *
343
+	 * @param string $class_name - simple class name ie: session
344
+	 * @param mixed  $arguments
345
+	 * @param bool   $load_only
346
+	 * @return mixed
347
+	 * @throws EE_Error
348
+	 * @throws ReflectionException
349
+	 */
350
+	public function load_core($class_name, $arguments = array(), $load_only = false)
351
+	{
352
+		$core_paths = apply_filters(
353
+			'FHEE__EE_Registry__load_core__core_paths',
354
+			array(
355
+				EE_CORE,
356
+				EE_ADMIN,
357
+				EE_CPTS,
358
+				EE_CORE . 'data_migration_scripts' . DS,
359
+				EE_CORE . 'capabilities' . DS,
360
+				EE_CORE . 'request_stack' . DS,
361
+				EE_CORE . 'middleware' . DS,
362
+			)
363
+		);
364
+		// retrieve instantiated class
365
+		return $this->_load(
366
+			$core_paths,
367
+			'EE_',
368
+			$class_name,
369
+			'core',
370
+			$arguments,
371
+			false,
372
+			true,
373
+			$load_only
374
+		);
375
+	}
376
+
377
+
378
+
379
+	/**
380
+	 * loads service classes
381
+	 *
382
+	 * @param string $class_name - simple class name ie: session
383
+	 * @param mixed  $arguments
384
+	 * @param bool   $load_only
385
+	 * @return mixed
386
+	 * @throws EE_Error
387
+	 * @throws ReflectionException
388
+	 */
389
+	public function load_service($class_name, $arguments = array(), $load_only = false)
390
+	{
391
+		$service_paths = apply_filters(
392
+			'FHEE__EE_Registry__load_service__service_paths',
393
+			array(
394
+				EE_CORE . 'services' . DS,
395
+			)
396
+		);
397
+		// retrieve instantiated class
398
+		return $this->_load(
399
+			$service_paths,
400
+			'EE_',
401
+			$class_name,
402
+			'class',
403
+			$arguments,
404
+			false,
405
+			true,
406
+			$load_only
407
+		);
408
+	}
409
+
410
+
411
+
412
+	/**
413
+	 * loads data_migration_scripts
414
+	 *
415
+	 * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0
416
+	 * @param mixed  $arguments
417
+	 * @return EE_Data_Migration_Script_Base|mixed
418
+	 * @throws EE_Error
419
+	 * @throws ReflectionException
420
+	 */
421
+	public function load_dms($class_name, $arguments = array())
422
+	{
423
+		// retrieve instantiated class
424
+		return $this->_load(
425
+			EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(),
426
+			'EE_DMS_',
427
+			$class_name,
428
+			'dms',
429
+			$arguments,
430
+			false,
431
+			false
432
+		);
433
+	}
434
+
435
+
436
+
437
+	/**
438
+	 * loads object creating classes - must be singletons
439
+	 *
440
+	 * @param string $class_name - simple class name ie: attendee
441
+	 * @param mixed  $arguments  - an array of arguments to pass to the class
442
+	 * @param bool   $from_db    - some classes are instantiated from the db and thus call a different method to
443
+	 *                           instantiate
444
+	 * @param bool   $cache      if you don't want the class to be stored in the internal cache (non-persistent) then
445
+	 *                           set this to FALSE (ie. when instantiating model objects from client in a loop)
446
+	 * @param bool   $load_only  whether or not to just load the file and NOT instantiate, or load AND instantiate
447
+	 *                           (default)
448
+	 * @return EE_Base_Class | bool
449
+	 * @throws EE_Error
450
+	 * @throws ReflectionException
451
+	 */
452
+	public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false)
453
+	{
454
+		$paths = apply_filters(
455
+			'FHEE__EE_Registry__load_class__paths', array(
456
+			EE_CORE,
457
+			EE_CLASSES,
458
+			EE_BUSINESS,
459
+		)
460
+		);
461
+		// retrieve instantiated class
462
+		return $this->_load(
463
+			$paths,
464
+			'EE_',
465
+			$class_name,
466
+			'class',
467
+			$arguments,
468
+			$from_db,
469
+			$cache,
470
+			$load_only
471
+		);
472
+	}
473
+
474
+
475
+
476
+	/**
477
+	 * loads helper classes - must be singletons
478
+	 *
479
+	 * @param string $class_name - simple class name ie: price
480
+	 * @param mixed  $arguments
481
+	 * @param bool   $load_only
482
+	 * @return EEH_Base | bool
483
+	 * @throws EE_Error
484
+	 * @throws ReflectionException
485
+	 */
486
+	public function load_helper($class_name, $arguments = array(), $load_only = true)
487
+	{
488
+		// todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed
489
+		$helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS));
490
+		// retrieve instantiated class
491
+		return $this->_load(
492
+			$helper_paths,
493
+			'EEH_',
494
+			$class_name,
495
+			'helper',
496
+			$arguments,
497
+			false,
498
+			true,
499
+			$load_only
500
+		);
501
+	}
502
+
503
+
504
+
505
+	/**
506
+	 * loads core classes - must be singletons
507
+	 *
508
+	 * @param string $class_name - simple class name ie: session
509
+	 * @param mixed  $arguments
510
+	 * @param bool   $load_only
511
+	 * @param bool   $cache      whether to cache the object or not.
512
+	 * @return mixed
513
+	 * @throws EE_Error
514
+	 * @throws ReflectionException
515
+	 */
516
+	public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true)
517
+	{
518
+		$paths = array(
519
+			EE_LIBRARIES,
520
+			EE_LIBRARIES . 'messages' . DS,
521
+			EE_LIBRARIES . 'shortcodes' . DS,
522
+			EE_LIBRARIES . 'qtips' . DS,
523
+			EE_LIBRARIES . 'payment_methods' . DS,
524
+		);
525
+		// retrieve instantiated class
526
+		return $this->_load(
527
+			$paths,
528
+			'EE_',
529
+			$class_name,
530
+			'lib',
531
+			$arguments,
532
+			false,
533
+			$cache,
534
+			$load_only
535
+		);
536
+	}
537
+
538
+
539
+
540
+	/**
541
+	 * loads model classes - must be singletons
542
+	 *
543
+	 * @param string $class_name - simple class name ie: price
544
+	 * @param mixed  $arguments
545
+	 * @param bool   $load_only
546
+	 * @return EEM_Base | bool
547
+	 * @throws EE_Error
548
+	 * @throws ReflectionException
549
+	 */
550
+	public function load_model($class_name, $arguments = array(), $load_only = false)
551
+	{
552
+		$paths = apply_filters(
553
+			'FHEE__EE_Registry__load_model__paths', array(
554
+			EE_MODELS,
555
+			EE_CORE,
556
+		)
557
+		);
558
+		// retrieve instantiated class
559
+		return $this->_load(
560
+			$paths,
561
+			'EEM_',
562
+			$class_name,
563
+			'model',
564
+			$arguments,
565
+			false,
566
+			true,
567
+			$load_only
568
+		);
569
+	}
570
+
571
+
572
+
573
+	/**
574
+	 * loads model classes - must be singletons
575
+	 *
576
+	 * @param string $class_name - simple class name ie: price
577
+	 * @param mixed  $arguments
578
+	 * @param bool   $load_only
579
+	 * @return mixed | bool
580
+	 * @throws EE_Error
581
+	 * @throws ReflectionException
582
+	 */
583
+	public function load_model_class($class_name, $arguments = array(), $load_only = true)
584
+	{
585
+		$paths = array(
586
+			EE_MODELS . 'fields' . DS,
587
+			EE_MODELS . 'helpers' . DS,
588
+			EE_MODELS . 'relations' . DS,
589
+			EE_MODELS . 'strategies' . DS,
590
+		);
591
+		// retrieve instantiated class
592
+		return $this->_load(
593
+			$paths,
594
+			'EE_',
595
+			$class_name,
596
+			'',
597
+			$arguments,
598
+			false,
599
+			true,
600
+			$load_only
601
+		);
602
+	}
603
+
604
+
605
+
606
+	/**
607
+	 * Determines if $model_name is the name of an actual EE model.
608
+	 *
609
+	 * @param string $model_name like Event, Attendee, Question_Group_Question, etc.
610
+	 * @return boolean
611
+	 */
612
+	public function is_model_name($model_name)
613
+	{
614
+		return isset($this->models[$model_name]);
615
+	}
616
+
617
+
618
+
619
+	/**
620
+	 * generic class loader
621
+	 *
622
+	 * @param string $path_to_file - directory path to file location, not including filename
623
+	 * @param string $file_name    - file name  ie:  my_file.php, including extension
624
+	 * @param string $type         - file type - core? class? helper? model?
625
+	 * @param mixed  $arguments
626
+	 * @param bool   $load_only
627
+	 * @return mixed
628
+	 * @throws EE_Error
629
+	 * @throws ReflectionException
630
+	 */
631
+	public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true)
632
+	{
633
+		// retrieve instantiated class
634
+		return $this->_load(
635
+			$path_to_file,
636
+			'',
637
+			$file_name,
638
+			$type,
639
+			$arguments,
640
+			false,
641
+			true,
642
+			$load_only
643
+		);
644
+	}
645
+
646
+
647
+
648
+	/**
649
+	 * @param string $path_to_file - directory path to file location, not including filename
650
+	 * @param string $class_name   - full class name  ie:  My_Class
651
+	 * @param string $type         - file type - core? class? helper? model?
652
+	 * @param mixed  $arguments
653
+	 * @param bool   $load_only
654
+	 * @return bool|EE_Addon|object
655
+	 * @throws EE_Error
656
+	 * @throws ReflectionException
657
+	 */
658
+	public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false)
659
+	{
660
+		// retrieve instantiated class
661
+		return $this->_load(
662
+			$path_to_file,
663
+			'addon',
664
+			$class_name,
665
+			$type,
666
+			$arguments,
667
+			false,
668
+			true,
669
+			$load_only
670
+		);
671
+	}
672
+
673
+
674
+	/**
675
+	 * instantiates, caches, and automatically resolves dependencies
676
+	 * for classes that use a Fully Qualified Class Name.
677
+	 * if the class is not capable of being loaded using PSR-4 autoloading,
678
+	 * then you need to use one of the existing load_*() methods
679
+	 * which can resolve the classname and filepath from the passed arguments
680
+	 *
681
+	 * @param bool|string $class_name   Fully Qualified Class Name
682
+	 * @param array       $arguments    an argument, or array of arguments to pass to the class upon instantiation
683
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
684
+	 * @param bool        $from_db      some classes are instantiated from the db
685
+	 *                                  and thus call a different method to instantiate
686
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
687
+	 * @param bool|string $addon        if true, will cache the object in the EE_Registry->$addons array
688
+	 * @return bool|null|mixed          null = failure to load or instantiate class object.
689
+	 *                                  object = class loaded and instantiated successfully.
690
+	 *                                  bool = fail or success when $load_only is true
691
+	 * @throws InvalidInterfaceException
692
+	 * @throws InvalidDataTypeException
693
+	 * @throws InvalidClassException
694
+	 * @throws EE_Error
695
+	 * @throws ReflectionException
696
+	 */
697
+	public function create(
698
+		$class_name = false,
699
+		$arguments = array(),
700
+		$cache = false,
701
+		$from_db = false,
702
+		$load_only = false,
703
+		$addon = false
704
+	) {
705
+		$class_name = ltrim($class_name, '\\');
706
+		$class_name = $this->class_cache->getFqnForAlias($class_name);
707
+		$class_exists = $this->loadOrVerifyClassExists($class_name, $arguments);
708
+		// if a non-FQCN was passed, then verifyClassExists() might return an object
709
+		// or it could return null if the class just could not be found anywhere
710
+		if ($class_exists instanceof $class_name || $class_exists === null){
711
+			// either way, return the results
712
+			return $class_exists;
713
+		}
714
+		$class_name = $class_exists;
715
+		// if we're only loading the class and it already exists, then let's just return true immediately
716
+		if ($load_only) {
717
+			return true;
718
+		}
719
+		$addon = $addon
720
+			? 'addon'
721
+			: '';
722
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
723
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
724
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
725
+		if ($this->_cache_on && $cache && ! $load_only) {
726
+			// return object if it's already cached
727
+			$cached_class = $this->_get_cached_class($class_name, $addon);
728
+			if ($cached_class !== null) {
729
+				return $cached_class;
730
+			}
731
+		}
732
+		// obtain the loader method from the dependency map
733
+		$loader = $this->_dependency_map->class_loader($class_name);
734
+		// instantiate the requested object
735
+		if ($loader instanceof Closure) {
736
+			$class_obj = $loader($arguments);
737
+		} else if ($loader && method_exists($this, $loader)) {
738
+			$class_obj = $this->{$loader}($class_name, $arguments);
739
+		} else {
740
+			$class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db);
741
+		}
742
+		if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) {
743
+			// save it for later... kinda like gum  { : $
744
+			$this->_set_cached_class($class_obj, $class_name, $addon, $from_db);
745
+		}
746
+		$this->_cache_on = true;
747
+		return $class_obj;
748
+	}
749
+
750
+
751
+
752
+	/**
753
+	 * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs
754
+	 *
755
+	 * @param string $class_name
756
+	 * @param array  $arguments
757
+	 * @param int    $attempt
758
+	 * @return mixed
759
+	 */
760
+	private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) {
761
+		if (is_object($class_name) || class_exists($class_name)) {
762
+			return $class_name;
763
+		}
764
+		switch ($attempt) {
765
+			case 1:
766
+				// if it's a FQCN then maybe the class is registered with a preceding \
767
+				$class_name = strpos($class_name, '\\') !== false
768
+					? '\\' . ltrim($class_name, '\\')
769
+					: $class_name;
770
+				break;
771
+			case 2:
772
+				//
773
+				$loader = $this->_dependency_map->class_loader($class_name);
774
+				if ($loader && method_exists($this, $loader)) {
775
+					return $this->{$loader}($class_name, $arguments);
776
+				}
777
+				break;
778
+			case 3:
779
+			default;
780
+				return null;
781
+		}
782
+		$attempt++;
783
+		return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt);
784
+	}
785
+
786
+
787
+
788
+	/**
789
+	 * instantiates, caches, and injects dependencies for classes
790
+	 *
791
+	 * @param array       $file_paths   an array of paths to folders to look in
792
+	 * @param string      $class_prefix EE  or EEM or... ???
793
+	 * @param bool|string $class_name   $class name
794
+	 * @param string      $type         file type - core? class? helper? model?
795
+	 * @param mixed       $arguments    an argument or array of arguments to pass to the class upon instantiation
796
+	 * @param bool        $from_db      some classes are instantiated from the db
797
+	 *                                  and thus call a different method to instantiate
798
+	 * @param bool        $cache        whether to cache the instantiated object for reuse
799
+	 * @param bool        $load_only    if true, will only load the file, but will NOT instantiate an object
800
+	 * @return bool|null|object null = failure to load or instantiate class object.
801
+	 *                                  object = class loaded and instantiated successfully.
802
+	 *                                  bool = fail or success when $load_only is true
803
+	 * @throws EE_Error
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidInterfaceException
806
+	 * @throws InvalidDataTypeException
807
+	 * @throws InvalidClassException
808
+	 */
809
+	protected function _load(
810
+		$file_paths = array(),
811
+		$class_prefix = 'EE_',
812
+		$class_name = false,
813
+		$type = 'class',
814
+		$arguments = array(),
815
+		$from_db = false,
816
+		$cache = true,
817
+		$load_only = false
818
+	) {
819
+		$class_name = ltrim($class_name, '\\');
820
+		// strip php file extension
821
+		$class_name = str_replace('.php', '', trim($class_name));
822
+		// does the class have a prefix ?
823
+		if (! empty($class_prefix) && $class_prefix !== 'addon') {
824
+			// make sure $class_prefix is uppercase
825
+			$class_prefix = strtoupper(trim($class_prefix));
826
+			// add class prefix ONCE!!!
827
+			$class_name = $class_prefix . str_replace($class_prefix, '', $class_name);
828
+		}
829
+		$class_name = $this->class_cache->getFqnForAlias($class_name);
830
+		$class_exists = class_exists($class_name, false);
831
+		// if we're only loading the class and it already exists, then let's just return true immediately
832
+		if ($load_only && $class_exists) {
833
+			return true;
834
+		}
835
+		// $this->_cache_on is toggled during the recursive loading that can occur with dependency injection
836
+		// $cache is controlled by individual calls to separate Registry loader methods like load_class()
837
+		// $load_only is also controlled by individual calls to separate Registry loader methods like load_file()
838
+		if ($this->_cache_on && $cache && ! $load_only) {
839
+			// return object if it's already cached
840
+			$cached_class = $this->_get_cached_class($class_name, $class_prefix);
841
+			if ($cached_class !== null) {
842
+				return $cached_class;
843
+			}
844
+		}
845
+		// if the class doesn't already exist.. then we need to try and find the file and load it
846
+		if (! $class_exists) {
847
+			// get full path to file
848
+			$path = $this->_resolve_path($class_name, $type, $file_paths);
849
+			// load the file
850
+			$loaded = $this->_require_file($path, $class_name, $type, $file_paths);
851
+			// if loading failed, or we are only loading a file but NOT instantiating an object
852
+			if (! $loaded || $load_only) {
853
+				// return boolean if only loading, or null if an object was expected
854
+				return $load_only
855
+					? $loaded
856
+					: null;
857
+			}
858
+		}
859
+		// instantiate the requested object
860
+		$class_obj = $this->_create_object($class_name, $arguments, $type, $from_db);
861
+		if ($this->_cache_on && $cache) {
862
+			// save it for later... kinda like gum  { : $
863
+			$this->_set_cached_class($class_obj, $class_name, $class_prefix, $from_db);
864
+		}
865
+		$this->_cache_on = true;
866
+		return $class_obj;
867
+	}
868
+
869
+
870
+
871
+	/**
872
+	 * @param string $class_name
873
+	 * @param string $default have to specify something, but not anything that will conflict
874
+	 * @return mixed|string
875
+	 */
876
+	protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS')
877
+	{
878
+		return isset($this->_class_abbreviations[$class_name])
879
+			? $this->_class_abbreviations[$class_name]
880
+			: $default;
881
+	}
882
+
883
+	/**
884
+	 * attempts to find a cached version of the requested class
885
+	 * by looking in the following places:
886
+	 *        $this->{$class_abbreviation}            ie:    $this->CART
887
+	 *        $this->{$class_name}                        ie:    $this->Some_Class
888
+	 *        $this->LIB->{$class_name}                ie:    $this->LIB->Some_Class
889
+	 *        $this->addon->{$class_name}    ie:    $this->addon->Some_Addon_Class
890
+	 *
891
+	 * @param string $class_name
892
+	 * @param string $class_prefix
893
+	 * @return mixed
894
+	 */
895
+	protected function _get_cached_class($class_name, $class_prefix = '')
896
+	{
897
+		if ($class_name === 'EE_Registry') {
898
+			return $this;
899
+		}
900
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
901
+		$class_name = str_replace('\\', '_', $class_name);
902
+		// check if class has already been loaded, and return it if it has been
903
+		if (isset($this->{$class_abbreviation})) {
904
+			return $this->{$class_abbreviation};
905
+		}
906
+		if (isset ($this->{$class_name})) {
907
+			return $this->{$class_name};
908
+		}
909
+		if (isset ($this->LIB->{$class_name})) {
910
+			return $this->LIB->{$class_name};
911
+		}
912
+		if ($class_prefix === 'addon' && isset ($this->addons->{$class_name})) {
913
+			return $this->addons->{$class_name};
914
+		}
915
+		return null;
916
+	}
917
+
918
+
919
+
920
+	/**
921
+	 * removes a cached version of the requested class
922
+	 *
923
+	 * @param string  $class_name
924
+	 * @param boolean $addon
925
+	 * @return boolean
926
+	 */
927
+	public function clear_cached_class($class_name, $addon = false)
928
+	{
929
+		$class_abbreviation = $this->get_class_abbreviation($class_name);
930
+		$class_name = str_replace('\\', '_', $class_name);
931
+		// check if class has already been loaded, and return it if it has been
932
+		if (isset($this->{$class_abbreviation})) {
933
+			$this->{$class_abbreviation} = null;
934
+			return true;
935
+		}
936
+		if (isset($this->{$class_name})) {
937
+			$this->{$class_name} = null;
938
+			return true;
939
+		}
940
+		if (isset($this->LIB->{$class_name})) {
941
+			unset($this->LIB->{$class_name});
942
+			return true;
943
+		}
944
+		if ($addon && isset($this->addons->{$class_name})) {
945
+			unset($this->addons->{$class_name});
946
+			return true;
947
+		}
948
+		return false;
949
+	}
950
+
951
+
952
+
953
+	/**
954
+	 * attempts to find a full valid filepath for the requested class.
955
+	 * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php"
956
+	 * then returns that path if the target file has been found and is readable
957
+	 *
958
+	 * @param string $class_name
959
+	 * @param string $type
960
+	 * @param array  $file_paths
961
+	 * @return string | bool
962
+	 */
963
+	protected function _resolve_path($class_name, $type = '', $file_paths = array())
964
+	{
965
+		// make sure $file_paths is an array
966
+		$file_paths = is_array($file_paths)
967
+			? $file_paths
968
+			: array($file_paths);
969
+		// cycle thru paths
970
+		foreach ($file_paths as $key => $file_path) {
971
+			// convert all separators to proper DS, if no filepath, then use EE_CLASSES
972
+			$file_path = $file_path
973
+				? str_replace(array('/', '\\'), DS, $file_path)
974
+				: EE_CLASSES;
975
+			// prep file type
976
+			$type = ! empty($type)
977
+				? trim($type, '.') . '.'
978
+				: '';
979
+			// build full file path
980
+			$file_paths[$key] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php';
981
+			//does the file exist and can be read ?
982
+			if (is_readable($file_paths[$key])) {
983
+				return $file_paths[$key];
984
+			}
985
+		}
986
+		return false;
987
+	}
988
+
989
+
990
+
991
+	/**
992
+	 * basically just performs a require_once()
993
+	 * but with some error handling
994
+	 *
995
+	 * @param  string $path
996
+	 * @param  string $class_name
997
+	 * @param  string $type
998
+	 * @param  array  $file_paths
999
+	 * @return bool
1000
+	 * @throws EE_Error
1001
+	 * @throws ReflectionException
1002
+	 */
1003
+	protected function _require_file($path, $class_name, $type = '', $file_paths = array())
1004
+	{
1005
+		$this->resolve_legacy_class_parent($class_name);
1006
+		// don't give up! you gotta...
1007
+		try {
1008
+			//does the file exist and can it be read ?
1009
+			if (! $path) {
1010
+				// just in case the file has already been autoloaded,
1011
+				// but discrepancies in the naming schema are preventing it from
1012
+				// being loaded via one of the EE_Registry::load_*() methods,
1013
+				// then let's try one last hail mary before throwing an exception
1014
+				// and call class_exists() again, but with autoloading turned ON
1015
+				if(class_exists($class_name)) {
1016
+					return true;
1017
+				}
1018
+				// so sorry, can't find the file
1019
+				throw new EE_Error (
1020
+					sprintf(
1021
+						esc_html__(
1022
+							'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s',
1023
+							'event_espresso'
1024
+						),
1025
+						trim($type, '.'),
1026
+						$class_name,
1027
+						'<br />' . implode(',<br />', $file_paths)
1028
+					)
1029
+				);
1030
+			}
1031
+			// get the file
1032
+			require_once($path);
1033
+			// if the class isn't already declared somewhere
1034
+			if (class_exists($class_name, false) === false) {
1035
+				// so sorry, not a class
1036
+				throw new EE_Error(
1037
+					sprintf(
1038
+						esc_html__('The %s file %s does not appear to contain the %s Class.', 'event_espresso'),
1039
+						$type,
1040
+						$path,
1041
+						$class_name
1042
+					)
1043
+				);
1044
+			}
1045
+		} catch (EE_Error $e) {
1046
+			$e->get_error();
1047
+			return false;
1048
+		}
1049
+		return true;
1050
+	}
1051
+
1052
+
1053
+
1054
+	/**
1055
+	 * Some of our legacy classes that extended a parent class would simply use a require() statement
1056
+	 * before their class declaration in order to ensure that the parent class was loaded.
1057
+	 * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class,
1058
+	 * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist.
1059
+	 *
1060
+	 * @param string $class_name
1061
+	 */
1062
+	protected function resolve_legacy_class_parent($class_name = '')
1063
+	{
1064
+		try {
1065
+			$legacy_parent_class_map = array(
1066
+				'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php'
1067
+			);
1068
+			if(isset($legacy_parent_class_map[$class_name])) {
1069
+				require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[$class_name];
1070
+			}
1071
+		} catch (Exception $exception) {
1072
+		}
1073
+	}
1074
+
1075
+
1076
+	/**
1077
+	 * _create_object
1078
+	 * Attempts to instantiate the requested class via any of the
1079
+	 * commonly used instantiation methods employed throughout EE.
1080
+	 * The priority for instantiation is as follows:
1081
+	 *        - abstract classes or any class flagged as "load only" (no instantiation occurs)
1082
+	 *        - model objects via their 'new_instance_from_db' method
1083
+	 *        - model objects via their 'new_instance' method
1084
+	 *        - "singleton" classes" via their 'instance' method
1085
+	 *    - standard instantiable classes via their __constructor
1086
+	 * Prior to instantiation, if the classname exists in the dependency_map,
1087
+	 * then the constructor for the requested class will be examined to determine
1088
+	 * if any dependencies exist, and if they can be injected.
1089
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1090
+	 *
1091
+	 * @param string $class_name
1092
+	 * @param array  $arguments
1093
+	 * @param string $type
1094
+	 * @param bool   $from_db
1095
+	 * @return null|object
1096
+	 * @throws EE_Error
1097
+	 * @throws ReflectionException
1098
+	 * @throws InvalidDataTypeException
1099
+	 */
1100
+	protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false)
1101
+	{
1102
+		// create reflection
1103
+		$reflector = $this->mirror->getReflectionClass($class_name);
1104
+		// make sure arguments are an array
1105
+		$arguments = is_array($arguments)
1106
+			? $arguments
1107
+			: array($arguments);
1108
+		// and if arguments array is numerically and sequentially indexed, then we want it to remain as is,
1109
+		// else wrap it in an additional array so that it doesn't get split into multiple parameters
1110
+		$arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments)
1111
+			? $arguments
1112
+			: array($arguments);
1113
+		// attempt to inject dependencies ?
1114
+		if ($this->_dependency_map->has($class_name)) {
1115
+			$arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments);
1116
+		}
1117
+		// instantiate the class if possible
1118
+		if ($reflector->isAbstract()) {
1119
+			// nothing to instantiate, loading file was enough
1120
+			// does not throw an exception so $instantiation_mode is unused
1121
+			// $instantiation_mode = "1) no constructor abstract class";
1122
+			return true;
1123
+		}
1124
+		if (
1125
+			empty($arguments)
1126
+			&& $this->mirror->getConstructorFromReflection($reflector) === null
1127
+			&& $reflector->isInstantiable()
1128
+		) {
1129
+			// no constructor = static methods only... nothing to instantiate, loading file was enough
1130
+			// $instantiation_mode = "2) no constructor but instantiable";
1131
+			return $reflector->newInstance();
1132
+		}
1133
+		if ($from_db && method_exists($class_name, 'new_instance_from_db')) {
1134
+			// $instantiation_mode = "3) new_instance_from_db()";
1135
+			return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments);
1136
+		}
1137
+		if (method_exists($class_name, 'new_instance')) {
1138
+			// $instantiation_mode = "4) new_instance()";
1139
+			return call_user_func_array(array($class_name, 'new_instance'), $arguments);
1140
+		}
1141
+		if (method_exists($class_name, 'instance')) {
1142
+			// $instantiation_mode = "5) instance()";
1143
+			return call_user_func_array(array($class_name, 'instance'), $arguments);
1144
+		}
1145
+		if ($reflector->isInstantiable()) {
1146
+			// $instantiation_mode = "6) constructor";
1147
+			return $reflector->newInstanceArgs($arguments);
1148
+		}
1149
+		// heh ? something's not right !
1150
+		throw new EE_Error(
1151
+			sprintf(
1152
+				__('The %s file %s could not be instantiated.', 'event_espresso'),
1153
+				$type,
1154
+				$class_name
1155
+			)
1156
+		);
1157
+	}
1158
+
1159
+
1160
+
1161
+	/**
1162
+	 * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
1163
+	 * @param array $array
1164
+	 * @return bool
1165
+	 */
1166
+	protected function _array_is_numerically_and_sequentially_indexed(array $array)
1167
+	{
1168
+		return ! empty($array)
1169
+			? array_keys($array) === range(0, count($array) - 1)
1170
+			: true;
1171
+	}
1172
+
1173
+
1174
+	/**
1175
+	 * _resolve_dependencies
1176
+	 * examines the constructor for the requested class to determine
1177
+	 * if any dependencies exist, and if they can be injected.
1178
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
1179
+	 * PLZ NOTE: this is achieved by type hinting the constructor params
1180
+	 * For example:
1181
+	 *        if attempting to load a class "Foo" with the following constructor:
1182
+	 *        __construct( Bar $bar_class, Fighter $grohl_class )
1183
+	 *        then $bar_class and $grohl_class will be added to the $arguments array,
1184
+	 *        but only IF they are NOT already present in the incoming arguments array,
1185
+	 *        and the correct classes can be loaded
1186
+	 *
1187
+	 * @param ReflectionClass $reflector
1188
+	 * @param string          $class_name
1189
+	 * @param array           $arguments
1190
+	 * @return array
1191
+	 * @throws EE_Error
1192
+	 * @throws InvalidArgumentException
1193
+	 * @throws InvalidDataTypeException
1194
+	 * @throws InvalidInterfaceException
1195
+	 * @throws ReflectionException
1196
+	 * @throws InvalidClassException
1197
+	 */
1198
+	protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array())
1199
+	{
1200
+		// let's examine the constructor
1201
+		$constructor = $this->mirror->getConstructorFromReflection($reflector);
1202
+		// whu? huh? nothing?
1203
+		if (! $constructor) {
1204
+			return $arguments;
1205
+		}
1206
+		// get constructor parameters
1207
+		$params = $this->mirror->getParametersFromReflection($reflector);
1208
+		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
1209
+		$argument_keys = array_keys($arguments);
1210
+		// now loop thru all of the constructors expected parameters
1211
+		foreach ($params as $index => $param) {
1212
+			// is this a dependency for a specific class ?
1213
+			$param_class = $this->mirror->getParameterClassName($param, $class_name, $index);
1214
+			// BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime)
1215
+			$param_class = $this->class_cache->isAlias($param_class, $class_name)
1216
+				? $this->class_cache->getFqnForAlias($param_class, $class_name)
1217
+				: $param_class;
1218
+			if (
1219
+				// param is not even a class
1220
+				$param_class === null
1221
+				// and something already exists in the incoming arguments for this param
1222
+				&& array_key_exists($index, $argument_keys)
1223
+				&& array_key_exists($argument_keys[$index], $arguments)
1224
+			) {
1225
+				// so let's skip this argument and move on to the next
1226
+				continue;
1227
+			}
1228
+			if (
1229
+				// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
1230
+				$param_class !== null
1231
+				&& isset($argument_keys[$index], $arguments[$argument_keys[$index]])
1232
+				&& $arguments[$argument_keys[$index]] instanceof $param_class
1233
+			) {
1234
+				// skip this argument and move on to the next
1235
+				continue;
1236
+			}
1237
+			if (
1238
+				// parameter is type hinted as a class, and should be injected
1239
+				$param_class !== null
1240
+				&& $this->_dependency_map->has_dependency_for_class($class_name, $param_class)
1241
+			) {
1242
+				$arguments = $this->_resolve_dependency(
1243
+					$class_name,
1244
+					$param_class,
1245
+					$arguments,
1246
+					$index,
1247
+					$argument_keys
1248
+				);
1249
+			} else {
1250
+				try {
1251
+					$arguments[$index] = $this->mirror->getParameterDefaultValue(
1252
+						$param,
1253
+						$class_name,
1254
+						$index
1255
+					);
1256
+				} catch (ReflectionException $e) {
1257
+					throw new ReflectionException(
1258
+						sprintf(
1259
+							esc_html__('%1$s for parameter "$%2$s on classname "%3$s"', 'event_espresso'),
1260
+							$e->getMessage(),
1261
+							$param->getName(),
1262
+							$class_name
1263
+						)
1264
+					);
1265
+				}
1266
+			}
1267
+		}
1268
+		return $arguments;
1269
+	}
1270
+
1271
+
1272
+
1273
+	/**
1274
+	 * @param string $class_name
1275
+	 * @param string $param_class
1276
+	 * @param array  $arguments
1277
+	 * @param mixed  $index
1278
+	 * @param array  $argument_keys
1279
+	 * @return array
1280
+	 * @throws EE_Error
1281
+	 * @throws ReflectionException
1282
+	 * @throws InvalidArgumentException
1283
+	 * @throws InvalidInterfaceException
1284
+	 * @throws InvalidDataTypeException
1285
+	 */
1286
+	protected function _resolve_dependency($class_name, $param_class, $arguments, $index, array $argument_keys)
1287
+	{
1288
+		$dependency = null;
1289
+		// should dependency be loaded from cache ?
1290
+		$cache_on = $this->_dependency_map->loading_strategy_for_class_dependency(
1291
+			$class_name,
1292
+			$param_class
1293
+		);
1294
+		$cache_on = $cache_on !== EE_Dependency_Map::load_new_object;
1295
+		// we might have a dependency...
1296
+		// let's MAYBE try and find it in our cache if that's what's been requested
1297
+		$cached_class = $cache_on
1298
+			? $this->_get_cached_class($param_class)
1299
+			: null;
1300
+		// and grab it if it exists
1301
+		if ($cached_class instanceof $param_class) {
1302
+			$dependency = $cached_class;
1303
+		} else if ($param_class !== $class_name) {
1304
+			// obtain the loader method from the dependency map
1305
+			$loader = $this->_dependency_map->class_loader($param_class);
1306
+			// is loader a custom closure ?
1307
+			if ($loader instanceof Closure) {
1308
+				$dependency = $loader($arguments);
1309
+			} else {
1310
+				// set the cache on property for the recursive loading call
1311
+				$this->_cache_on = $cache_on;
1312
+				// if not, then let's try and load it via the registry
1313
+				if ($loader && method_exists($this, $loader)) {
1314
+					$dependency = $this->{$loader}($param_class);
1315
+				} else {
1316
+					$dependency = LoaderFactory::getLoader()->load(
1317
+						$param_class,
1318
+						array(),
1319
+						$cache_on
1320
+					);
1321
+				}
1322
+			}
1323
+		}
1324
+		// did we successfully find the correct dependency ?
1325
+		if ($dependency instanceof $param_class) {
1326
+			// then let's inject it into the incoming array of arguments at the correct location
1327
+			$arguments[$index] = $dependency;
1328
+		}
1329
+		return $arguments;
1330
+	}
1331
+
1332
+
1333
+
1334
+	/**
1335
+	 * _set_cached_class
1336
+	 * attempts to cache the instantiated class locally
1337
+	 * in one of the following places, in the following order:
1338
+	 *        $this->{class_abbreviation}   ie:    $this->CART
1339
+	 *        $this->{$class_name}          ie:    $this->Some_Class
1340
+	 *        $this->addon->{$$class_name}    ie:    $this->addon->Some_Addon_Class
1341
+	 *        $this->LIB->{$class_name}     ie:    $this->LIB->Some_Class
1342
+	 *
1343
+	 * @param object $class_obj
1344
+	 * @param string $class_name
1345
+	 * @param string $class_prefix
1346
+	 * @param bool   $from_db
1347
+	 * @return void
1348
+	 */
1349
+	protected function _set_cached_class($class_obj, $class_name, $class_prefix = '', $from_db = false)
1350
+	{
1351
+		if ($class_name === 'EE_Registry' || empty($class_obj)) {
1352
+			return;
1353
+		}
1354
+		// return newly instantiated class
1355
+		$class_abbreviation = $this->get_class_abbreviation($class_name, '');
1356
+		if ($class_abbreviation) {
1357
+			$this->{$class_abbreviation} = $class_obj;
1358
+			return;
1359
+		}
1360
+		$class_name = str_replace('\\', '_', $class_name);
1361
+		if (property_exists($this, $class_name)) {
1362
+			$this->{$class_name} = $class_obj;
1363
+			return;
1364
+		}
1365
+		if ($class_prefix === 'addon') {
1366
+			$this->addons->{$class_name} = $class_obj;
1367
+			return;
1368
+		}
1369
+		if (! $from_db) {
1370
+			$this->LIB->{$class_name} = $class_obj;
1371
+		}
1372
+	}
1373
+
1374
+
1375
+
1376
+	/**
1377
+	 * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array
1378
+	 *
1379
+	 * @param string $classname PLEASE NOTE: the class name needs to match what's registered
1380
+	 *                          in the EE_Dependency_Map::$_class_loaders array,
1381
+	 *                          including the class prefix, ie: "EE_", "EEM_", "EEH_", etc
1382
+	 * @param array  $arguments
1383
+	 * @return object
1384
+	 */
1385
+	public static function factory($classname, $arguments = array())
1386
+	{
1387
+		$loader = self::instance()->_dependency_map->class_loader($classname);
1388
+		if ($loader instanceof Closure) {
1389
+			return $loader($arguments);
1390
+		}
1391
+		if (method_exists(self::instance(), $loader)) {
1392
+			return self::instance()->{$loader}($classname, $arguments);
1393
+		}
1394
+		return null;
1395
+	}
1396
+
1397
+
1398
+
1399
+	/**
1400
+	 * Gets the addon by its class name
1401
+	 *
1402
+	 * @param string $class_name
1403
+	 * @return EE_Addon
1404
+	 */
1405
+	public function getAddon($class_name)
1406
+	{
1407
+		$class_name = str_replace('\\', '_', $class_name);
1408
+		return $this->addons->{$class_name};
1409
+	}
1410
+
1411
+
1412
+	/**
1413
+	 * removes the addon from the internal cache
1414
+	 *
1415
+	 * @param string $class_name
1416
+	 * @return void
1417
+	 */
1418
+	public function removeAddon($class_name)
1419
+	{
1420
+		$class_name = str_replace('\\', '_', $class_name);
1421
+		unset($this->addons->{$class_name});
1422
+	}
1423
+
1424
+
1425
+
1426
+	/**
1427
+	 * Gets the addon by its name/slug (not classname. For that, just
1428
+	 * use the get_addon() method above
1429
+	 *
1430
+	 * @param string $name
1431
+	 * @return EE_Addon
1432
+	 */
1433
+	public function get_addon_by_name($name)
1434
+	{
1435
+		foreach ($this->addons as $addon) {
1436
+			if ($addon->name() === $name) {
1437
+				return $addon;
1438
+			}
1439
+		}
1440
+		return null;
1441
+	}
1442
+
1443
+
1444
+
1445
+	/**
1446
+	 * Gets an array of all the registered addons, where the keys are their names.
1447
+	 * (ie, what each returns for their name() function)
1448
+	 * They're already available on EE_Registry::instance()->addons as properties,
1449
+	 * where each property's name is the addon's classname,
1450
+	 * So if you just want to get the addon by classname,
1451
+	 * OR use the get_addon() method above.
1452
+	 * PLEASE  NOTE:
1453
+	 * addons with Fully Qualified Class Names
1454
+	 * have had the namespace separators converted to underscores,
1455
+	 * so a classname like Fully\Qualified\ClassName
1456
+	 * would have been converted to Fully_Qualified_ClassName
1457
+	 *
1458
+	 * @return EE_Addon[] where the KEYS are the addon's name()
1459
+	 */
1460
+	public function get_addons_by_name()
1461
+	{
1462
+		$addons = array();
1463
+		foreach ($this->addons as $addon) {
1464
+			$addons[$addon->name()] = $addon;
1465
+		}
1466
+		return $addons;
1467
+	}
1468
+
1469
+
1470
+	/**
1471
+	 * Resets the specified model's instance AND makes sure EE_Registry doesn't keep
1472
+	 * a stale copy of it around
1473
+	 *
1474
+	 * @param string $model_name
1475
+	 * @return \EEM_Base
1476
+	 * @throws \EE_Error
1477
+	 */
1478
+	public function reset_model($model_name)
1479
+	{
1480
+		$model_class_name = strpos($model_name, 'EEM_') !== 0
1481
+			? "EEM_{$model_name}"
1482
+			: $model_name;
1483
+		if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) {
1484
+			return null;
1485
+		}
1486
+		//get that model reset it and make sure we nuke the old reference to it
1487
+		if ($this->LIB->{$model_class_name} instanceof $model_class_name
1488
+			&& is_callable(
1489
+				array($model_class_name, 'reset')
1490
+			)) {
1491
+			$this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset();
1492
+		} else {
1493
+			throw new EE_Error(sprintf(esc_html__('Model %s does not have a method "reset"', 'event_espresso'), $model_name));
1494
+		}
1495
+		return $this->LIB->{$model_class_name};
1496
+	}
1497
+
1498
+
1499
+
1500
+	/**
1501
+	 * Resets the registry.
1502
+	 * The criteria for what gets reset is based on what can be shared between sites on the same request when
1503
+	 * switch_to_blog is used in a multisite install.  Here is a list of things that are NOT reset.
1504
+	 * - $_dependency_map
1505
+	 * - $_class_abbreviations
1506
+	 * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset.
1507
+	 * - $REQ:  Still on the same request so no need to change.
1508
+	 * - $CAP: There is no site specific state in the EE_Capability class.
1509
+	 * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only
1510
+	 * one Session can be active in a single request.  Resetting could resolve in "headers already sent" errors.
1511
+	 * - $addons:  In multisite, the state of the addons is something controlled via hooks etc in a normal request.  So
1512
+	 *             for now, we won't reset the addons because it could break calls to an add-ons class/methods in the
1513
+	 *             switch or on the restore.
1514
+	 * - $modules
1515
+	 * - $shortcodes
1516
+	 * - $widgets
1517
+	 *
1518
+	 * @param boolean $hard             [deprecated]
1519
+	 * @param boolean $reinstantiate    whether to create new instances of EE_Registry's singletons too,
1520
+	 *                                  or just reset without re-instantiating (handy to set to FALSE if you're not
1521
+	 *                                  sure if you CAN currently reinstantiate the singletons at the moment)
1522
+	 * @param   bool  $reset_models     Defaults to true.  When false, then the models are not reset.  This is so
1523
+	 *                                  client
1524
+	 *                                  code instead can just change the model context to a different blog id if
1525
+	 *                                  necessary
1526
+	 * @return EE_Registry
1527
+	 * @throws EE_Error
1528
+	 * @throws ReflectionException
1529
+	 */
1530
+	public static function reset($hard = false, $reinstantiate = true, $reset_models = true)
1531
+	{
1532
+		$instance = self::instance();
1533
+		$instance->_cache_on = true;
1534
+		// reset some "special" classes
1535
+		EEH_Activation::reset();
1536
+		$hard = apply_filters( 'FHEE__EE_Registry__reset__hard', $hard);
1537
+		$instance->CFG = EE_Config::reset($hard, $reinstantiate);
1538
+		$instance->CART = null;
1539
+		$instance->MRM = null;
1540
+		$instance->AssetsRegistry = $instance->create('EventEspresso\core\services\assets\Registry');
1541
+		//messages reset
1542
+		EED_Messages::reset();
1543
+		//handle of objects cached on LIB
1544
+		foreach (array('LIB', 'modules') as $cache) {
1545
+			foreach ($instance->{$cache} as $class_name => $class) {
1546
+				if (self::_reset_and_unset_object($class, $reset_models)) {
1547
+					unset($instance->{$cache}->{$class_name});
1548
+				}
1549
+			}
1550
+		}
1551
+		return $instance;
1552
+	}
1553
+
1554
+
1555
+
1556
+	/**
1557
+	 * if passed object implements ResettableInterface, then call it's reset() method
1558
+	 * if passed object implements InterminableInterface, then return false,
1559
+	 * to indicate that it should NOT be cleared from the Registry cache
1560
+	 *
1561
+	 * @param      $object
1562
+	 * @param bool $reset_models
1563
+	 * @return bool returns true if cached object should be unset
1564
+	 */
1565
+	private static function _reset_and_unset_object($object, $reset_models)
1566
+	{
1567
+		if (! is_object($object)) {
1568
+			// don't unset anything that's not an object
1569
+			return false;
1570
+		}
1571
+		if ($object instanceof EED_Module) {
1572
+			$object::reset();
1573
+			// don't unset modules
1574
+			return false;
1575
+		}
1576
+		if ($object instanceof ResettableInterface) {
1577
+			if ($object instanceof EEM_Base) {
1578
+				if ($reset_models) {
1579
+					$object->reset();
1580
+					return true;
1581
+				}
1582
+				return false;
1583
+			}
1584
+			$object->reset();
1585
+			return true;
1586
+		}
1587
+		if (! $object instanceof InterminableInterface) {
1588
+			return true;
1589
+		}
1590
+		return false;
1591
+	}
1592
+
1593
+
1594
+
1595
+	/**
1596
+	 * Gets all the custom post type models defined
1597
+	 *
1598
+	 * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event")
1599
+	 */
1600
+	public function cpt_models()
1601
+	{
1602
+		$cpt_models = array();
1603
+		foreach ($this->non_abstract_db_models as $short_name => $classname) {
1604
+			if (is_subclass_of($classname, 'EEM_CPT_Base')) {
1605
+				$cpt_models[$short_name] = $classname;
1606
+			}
1607
+		}
1608
+		return $cpt_models;
1609
+	}
1610
+
1611
+
1612
+
1613
+	/**
1614
+	 * @return \EE_Config
1615
+	 */
1616
+	public static function CFG()
1617
+	{
1618
+		return self::instance()->CFG;
1619
+	}
1620
+
1621
+
1622
+	/**
1623
+	 * @deprecated $VID:$
1624
+	 * @param string $class_name
1625
+	 * @return ReflectionClass
1626
+	 * @throws ReflectionException
1627
+	 * @throws InvalidDataTypeException
1628
+	 */
1629
+	public function get_ReflectionClass($class_name)
1630
+	{
1631
+		return $this->mirror->getReflectionClass($class_name);
1632
+	}
1633 1633
 }
1634 1634
 // End of file EE_Registry.core.php
1635 1635
 // Location: ./core/EE_Registry.core.php
Please login to merge, or discard this patch.
core/EE_Dependency_Map.core.php 2 patches
Indentation   +821 added lines, -821 removed lines patch added patch discarded remove patch
@@ -8,7 +8,7 @@  discard block
 block discarded – undo
8 8
 use EventEspresso\core\services\request\ResponseInterface;
9 9
 
10 10
 if (! defined('EVENT_ESPRESSO_VERSION')) {
11
-    exit('No direct script access allowed');
11
+	exit('No direct script access allowed');
12 12
 }
13 13
 
14 14
 
@@ -25,826 +25,826 @@  discard block
 block discarded – undo
25 25
 class EE_Dependency_Map
26 26
 {
27 27
 
28
-    /**
29
-     * This means that the requested class dependency is not present in the dependency map
30
-     */
31
-    const not_registered = 0;
32
-
33
-    /**
34
-     * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
35
-     */
36
-    const load_new_object = 1;
37
-
38
-    /**
39
-     * This instructs class loaders to return a previously instantiated and cached object for the requested class.
40
-     * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
41
-     */
42
-    const load_from_cache = 2;
43
-
44
-    /**
45
-     * When registering a dependency,
46
-     * this indicates to keep any existing dependencies that already exist,
47
-     * and simply discard any new dependencies declared in the incoming data
48
-     */
49
-    const KEEP_EXISTING_DEPENDENCIES = 0;
50
-
51
-    /**
52
-     * When registering a dependency,
53
-     * this indicates to overwrite any existing dependencies that already exist using the incoming data
54
-     */
55
-    const OVERWRITE_DEPENDENCIES = 1;
56
-
57
-
58
-
59
-    /**
60
-     * @type EE_Dependency_Map $_instance
61
-     */
62
-    protected static $_instance;
63
-
64
-    /**
65
-     * @var ClassInterfaceCache $class_cache
66
-     */
67
-    private $class_cache;
68
-
69
-    /**
70
-     * @type RequestInterface $request
71
-     */
72
-    protected $request;
73
-
74
-    /**
75
-     * @type LegacyRequestInterface $legacy_request
76
-     */
77
-    protected $legacy_request;
78
-
79
-    /**
80
-     * @type ResponseInterface $response
81
-     */
82
-    protected $response;
83
-
84
-    /**
85
-     * @type LoaderInterface $loader
86
-     */
87
-    protected $loader;
88
-
89
-    /**
90
-     * @type array $_dependency_map
91
-     */
92
-    protected $_dependency_map = array();
93
-
94
-    /**
95
-     * @type array $_class_loaders
96
-     */
97
-    protected $_class_loaders = array();
98
-
99
-
100
-    /**
101
-     * EE_Dependency_Map constructor.
102
-     *
103
-     * @param ClassInterfaceCache $class_cache
104
-     */
105
-    protected function __construct(ClassInterfaceCache $class_cache)
106
-    {
107
-        $this->class_cache = $class_cache;
108
-        do_action('EE_Dependency_Map____construct', $this);
109
-    }
110
-
111
-
112
-    /**
113
-     * @return void
114
-     */
115
-    public function initialize()
116
-    {
117
-        $this->_register_core_dependencies();
118
-        $this->_register_core_class_loaders();
119
-        $this->_register_core_aliases();
120
-    }
121
-
122
-
123
-    /**
124
-     * @singleton method used to instantiate class object
125
-     * @param ClassInterfaceCache|null $class_cache
126
-     * @return EE_Dependency_Map
127
-     */
128
-    public static function instance(ClassInterfaceCache $class_cache = null) {
129
-        // check if class object is instantiated, and instantiated properly
130
-        if (
131
-            ! self::$_instance instanceof EE_Dependency_Map
132
-            && $class_cache instanceof ClassInterfaceCache
133
-        ) {
134
-            self::$_instance = new EE_Dependency_Map($class_cache);
135
-        }
136
-        return self::$_instance;
137
-    }
138
-
139
-
140
-    /**
141
-     * @param RequestInterface $request
142
-     */
143
-    public function setRequest(RequestInterface $request)
144
-    {
145
-        $this->request = $request;
146
-    }
147
-
148
-
149
-    /**
150
-     * @param LegacyRequestInterface $legacy_request
151
-     */
152
-    public function setLegacyRequest(LegacyRequestInterface $legacy_request)
153
-    {
154
-        $this->legacy_request = $legacy_request;
155
-    }
156
-
157
-
158
-    /**
159
-     * @param ResponseInterface $response
160
-     */
161
-    public function setResponse(ResponseInterface $response)
162
-    {
163
-        $this->response = $response;
164
-    }
165
-
166
-
167
-
168
-    /**
169
-     * @param LoaderInterface $loader
170
-     */
171
-    public function setLoader(LoaderInterface $loader)
172
-    {
173
-        $this->loader = $loader;
174
-    }
175
-
176
-
177
-
178
-    /**
179
-     * @param string $class
180
-     * @param array  $dependencies
181
-     * @param int    $overwrite
182
-     * @return bool
183
-     */
184
-    public static function register_dependencies(
185
-        $class,
186
-        array $dependencies,
187
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
188
-    ) {
189
-        return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
190
-    }
191
-
192
-
193
-
194
-    /**
195
-     * Assigns an array of class names and corresponding load sources (new or cached)
196
-     * to the class specified by the first parameter.
197
-     * IMPORTANT !!!
198
-     * The order of elements in the incoming $dependencies array MUST match
199
-     * the order of the constructor parameters for the class in question.
200
-     * This is especially important when overriding any existing dependencies that are registered.
201
-     * the third parameter controls whether any duplicate dependencies are overwritten or not.
202
-     *
203
-     * @param string $class
204
-     * @param array  $dependencies
205
-     * @param int    $overwrite
206
-     * @return bool
207
-     */
208
-    public function registerDependencies(
209
-        $class,
210
-        array $dependencies,
211
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
212
-    ) {
213
-        $class = trim($class, '\\');
214
-        $registered = false;
215
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
216
-            self::$_instance->_dependency_map[ $class ] = array();
217
-        }
218
-        // we need to make sure that any aliases used when registering a dependency
219
-        // get resolved to the correct class name
220
-        foreach ($dependencies as $dependency => $load_source) {
221
-            $alias = self::$_instance->get_alias($dependency);
222
-            if (
223
-                $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
224
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
225
-            ) {
226
-                unset($dependencies[$dependency]);
227
-                $dependencies[$alias] = $load_source;
228
-                $registered = true;
229
-            }
230
-        }
231
-        // now add our two lists of dependencies together.
232
-        // using Union (+=) favours the arrays in precedence from left to right,
233
-        // so $dependencies is NOT overwritten because it is listed first
234
-        // ie: with A = B + C, entries in B take precedence over duplicate entries in C
235
-        // Union is way faster than array_merge() but should be used with caution...
236
-        // especially with numerically indexed arrays
237
-        $dependencies += self::$_instance->_dependency_map[ $class ];
238
-        // now we need to ensure that the resulting dependencies
239
-        // array only has the entries that are required for the class
240
-        // so first count how many dependencies were originally registered for the class
241
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
242
-        // if that count is non-zero (meaning dependencies were already registered)
243
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
244
-            // then truncate the  final array to match that count
245
-            ? array_slice($dependencies, 0, $dependency_count)
246
-            // otherwise just take the incoming array because nothing previously existed
247
-            : $dependencies;
248
-        return $registered;
249
-    }
250
-
251
-
252
-
253
-    /**
254
-     * @param string $class_name
255
-     * @param string $loader
256
-     * @return bool
257
-     * @throws DomainException
258
-     */
259
-    public static function register_class_loader($class_name, $loader = 'load_core')
260
-    {
261
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
262
-            throw new DomainException(
263
-                esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
264
-            );
265
-        }
266
-        // check that loader is callable or method starts with "load_" and exists in EE_Registry
267
-        if (
268
-            ! is_callable($loader)
269
-            && (
270
-                strpos($loader, 'load_') !== 0
271
-                || ! method_exists('EE_Registry', $loader)
272
-            )
273
-        ) {
274
-            throw new DomainException(
275
-                sprintf(
276
-                    esc_html__(
277
-                        '"%1$s" is not a valid loader method on EE_Registry.',
278
-                        'event_espresso'
279
-                    ),
280
-                    $loader
281
-                )
282
-            );
283
-        }
284
-        $class_name = self::$_instance->get_alias($class_name);
285
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
286
-            self::$_instance->_class_loaders[$class_name] = $loader;
287
-            return true;
288
-        }
289
-        return false;
290
-    }
291
-
292
-
293
-
294
-    /**
295
-     * @return array
296
-     */
297
-    public function dependency_map()
298
-    {
299
-        return $this->_dependency_map;
300
-    }
301
-
302
-
303
-
304
-    /**
305
-     * returns TRUE if dependency map contains a listing for the provided class name
306
-     *
307
-     * @param string $class_name
308
-     * @return boolean
309
-     */
310
-    public function has($class_name = '')
311
-    {
312
-        // all legacy models have the same dependencies
313
-        if (strpos($class_name, 'EEM_') === 0) {
314
-            $class_name = 'LEGACY_MODELS';
315
-        }
316
-        return isset($this->_dependency_map[$class_name]) ? true : false;
317
-    }
318
-
319
-
320
-
321
-    /**
322
-     * returns TRUE if dependency map contains a listing for the provided class name AND dependency
323
-     *
324
-     * @param string $class_name
325
-     * @param string $dependency
326
-     * @return bool
327
-     */
328
-    public function has_dependency_for_class($class_name = '', $dependency = '')
329
-    {
330
-        // all legacy models have the same dependencies
331
-        if (strpos($class_name, 'EEM_') === 0) {
332
-            $class_name = 'LEGACY_MODELS';
333
-        }
334
-        $dependency = $this->get_alias($dependency);
335
-        return isset($this->_dependency_map[$class_name][$dependency])
336
-            ? true
337
-            : false;
338
-    }
339
-
340
-
341
-
342
-    /**
343
-     * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
344
-     *
345
-     * @param string $class_name
346
-     * @param string $dependency
347
-     * @return int
348
-     */
349
-    public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
350
-    {
351
-        // all legacy models have the same dependencies
352
-        if (strpos($class_name, 'EEM_') === 0) {
353
-            $class_name = 'LEGACY_MODELS';
354
-        }
355
-        $dependency = $this->get_alias($dependency);
356
-        return $this->has_dependency_for_class($class_name, $dependency)
357
-            ? $this->_dependency_map[$class_name][$dependency]
358
-            : EE_Dependency_Map::not_registered;
359
-    }
360
-
361
-
362
-
363
-    /**
364
-     * @param string $class_name
365
-     * @return string | Closure
366
-     */
367
-    public function class_loader($class_name)
368
-    {
369
-        // all legacy models use load_model()
370
-        if(strpos($class_name, 'EEM_') === 0){
371
-            return 'load_model';
372
-        }
373
-        $class_name = $this->get_alias($class_name);
374
-        return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
375
-    }
376
-
377
-
378
-
379
-    /**
380
-     * @return array
381
-     */
382
-    public function class_loaders()
383
-    {
384
-        return $this->_class_loaders;
385
-    }
386
-
387
-
388
-
389
-    /**
390
-     * adds an alias for a classname
391
-     *
392
-     * @param string $fqcn      the class name that should be used (concrete class to replace interface)
393
-     * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
394
-     * @param string $for_class the class that has the dependency (is type hinting for the interface)
395
-     */
396
-    public function add_alias($fqcn, $alias, $for_class = '')
397
-    {
398
-        $this->class_cache->addAlias($alias, $fqcn, $for_class);
399
-    }
400
-
401
-
402
-
403
-    /**
404
-     * PLZ NOTE: a better name for this method would be is_alias()
405
-     * because it returns TRUE if the provided fully qualified name IS an alias
406
-     *
407
-     * @param string $fqn
408
-     * @param string $for_class
409
-     * @return bool
410
-     */
411
-    public function has_alias($fqn = '', $for_class = '')
412
-    {
413
-        return $this->class_cache->isAlias($fqn, $for_class);
414
-    }
415
-
416
-
417
-
418
-    /**
419
-     * PLZ NOTE: a better name for this method would be get_fqn_for_alias()
420
-     * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias
421
-     * functions recursively, so that multiple aliases can be used to drill down to a FQN
422
-     *  for example:
423
-     *      if the following two entries were added to the _aliases array:
424
-     *          array(
425
-     *              'interface_alias'           => 'some\namespace\interface'
426
-     *              'some\namespace\interface'  => 'some\namespace\classname'
427
-     *          )
428
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
429
-     *      to load an instance of 'some\namespace\classname'
430
-     *
431
-     * @param string $alias
432
-     * @param string $for_class
433
-     * @return string
434
-     */
435
-    public function get_alias($alias = '', $for_class = '')
436
-    {
437
-        return (string) $this->class_cache->getFqnForAlias($alias, $for_class);
438
-    }
439
-
440
-
441
-
442
-    /**
443
-     * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
444
-     * if one exists, or whether a new object should be generated every time the requested class is loaded.
445
-     * This is done by using the following class constants:
446
-     *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
447
-     *        EE_Dependency_Map::load_new_object - generates a new object every time
448
-     */
449
-    protected function _register_core_dependencies()
450
-    {
451
-        $this->_dependency_map = array(
452
-            'EE_Request_Handler'                                                                                          => array(
453
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
454
-            ),
455
-            'EE_System'                                                                                                   => array(
456
-                'EE_Registry'                                 => EE_Dependency_Map::load_from_cache,
457
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
458
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
459
-                'EE_Maintenance_Mode'                         => EE_Dependency_Map::load_from_cache,
460
-            ),
461
-            'EE_Session'                                                                                                  => array(
462
-                'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
463
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
464
-                'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
465
-                'EE_Encryption'                                            => EE_Dependency_Map::load_from_cache,
466
-            ),
467
-            'EE_Cart'                                                                                                     => array(
468
-                'EE_Session' => EE_Dependency_Map::load_from_cache,
469
-            ),
470
-            'EE_Front_Controller'                                                                                         => array(
471
-                'EE_Registry'              => EE_Dependency_Map::load_from_cache,
472
-                'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
473
-                'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
474
-            ),
475
-            'EE_Messenger_Collection_Loader'                                                                              => array(
476
-                'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
477
-            ),
478
-            'EE_Message_Type_Collection_Loader'                                                                           => array(
479
-                'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
480
-            ),
481
-            'EE_Message_Resource_Manager'                                                                                 => array(
482
-                'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
483
-                'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
484
-                'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
485
-            ),
486
-            'EE_Message_Factory'                                                                                          => array(
487
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
488
-            ),
489
-            'EE_messages'                                                                                                 => array(
490
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
491
-            ),
492
-            'EE_Messages_Generator'                                                                                       => array(
493
-                'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
494
-                'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
495
-                'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
496
-                'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
497
-            ),
498
-            'EE_Messages_Processor'                                                                                       => array(
499
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
500
-            ),
501
-            'EE_Messages_Queue'                                                                                           => array(
502
-                'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
503
-            ),
504
-            'EE_Messages_Template_Defaults'                                                                               => array(
505
-                'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
506
-                'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
507
-            ),
508
-            'EE_Message_To_Generate_From_Request'                                                                         => array(
509
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
510
-                'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
511
-            ),
512
-            'EventEspresso\core\services\commands\CommandBus'                                                             => array(
513
-                'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
514
-            ),
515
-            'EventEspresso\services\commands\CommandHandler'                                                              => array(
516
-                'EE_Registry'         => EE_Dependency_Map::load_from_cache,
517
-                'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
518
-            ),
519
-            'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
520
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
521
-            ),
522
-            'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
523
-                'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
524
-                'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
525
-            ),
526
-            'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
527
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
528
-            ),
529
-            'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
530
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
531
-            ),
532
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
533
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
534
-            ),
535
-            'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
536
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
537
-            ),
538
-            'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
539
-                'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
540
-            ),
541
-            'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
542
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
543
-            ),
544
-            'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
545
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
546
-            ),
547
-            'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
548
-                'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
549
-            ),
550
-            'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
551
-                'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
552
-            ),
553
-            'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
554
-                'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
555
-            ),
556
-            'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
557
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
558
-            ),
559
-            'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
560
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
561
-            ),
562
-            'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
563
-                'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
564
-            ),
565
-            'EventEspresso\core\services\database\TableManager'                                                           => array(
566
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
567
-            ),
568
-            'EE_Data_Migration_Class_Base'                                                                                => array(
569
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
570
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
571
-            ),
572
-            'EE_DMS_Core_4_1_0'                                                                                           => array(
573
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
574
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
575
-            ),
576
-            'EE_DMS_Core_4_2_0'                                                                                           => array(
577
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
578
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
579
-            ),
580
-            'EE_DMS_Core_4_3_0'                                                                                           => array(
581
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
582
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
583
-            ),
584
-            'EE_DMS_Core_4_4_0'                                                                                           => array(
585
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
586
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
587
-            ),
588
-            'EE_DMS_Core_4_5_0'                                                                                           => array(
589
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
590
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
591
-            ),
592
-            'EE_DMS_Core_4_6_0'                                                                                           => array(
593
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
594
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
595
-            ),
596
-            'EE_DMS_Core_4_7_0'                                                                                           => array(
597
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
598
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
599
-            ),
600
-            'EE_DMS_Core_4_8_0'                                                                                           => array(
601
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
602
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
603
-            ),
604
-            'EE_DMS_Core_4_9_0'                                                                                           => array(
605
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
606
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
607
-            ),
608
-            'EventEspresso\core\services\assets\Registry'                                                                 => array(
609
-                'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
610
-                'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
611
-                'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache
612
-            ),
613
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
614
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
615
-            ),
616
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
617
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
618
-            ),
619
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
620
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
621
-            ),
622
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
623
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
624
-            ),
625
-            'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
626
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
627
-            ),
628
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
629
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
630
-            ),
631
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
632
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
633
-            ),
634
-            'EventEspresso\core\services\cache\BasicCacheManager'                        => array(
635
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
636
-            ),
637
-            'EventEspresso\core\services\cache\PostRelatedCacheManager'                  => array(
638
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
639
-            ),
640
-            'EventEspresso\core\domain\services\validation\email\EmailValidationService' => array(
641
-                'EE_Registration_Config'                                  => EE_Dependency_Map::load_from_cache,
642
-                'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
643
-            ),
644
-            'EventEspresso\core\domain\values\EmailAddress'                              => array(
645
-                null,
646
-                'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
647
-            ),
648
-            'EventEspresso\core\services\orm\ModelFieldFactory' => array(
649
-                'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
650
-            ),
651
-            'LEGACY_MODELS'                                                   => array(
652
-                null,
653
-                'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
654
-            ),
655
-            'EE_Module_Request_Router' => array(
656
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
657
-            ),
658
-            'EE_Registration_Processor' => array(
659
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
660
-            ),
661
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' => array(
662
-                null,
663
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
664
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
665
-            ),
666
-            'EE_Admin_Transactions_List_Table' => array(
667
-                null,
668
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
669
-            ),
670
-        );
671
-    }
672
-
673
-
674
-    /**
675
-     * Registers how core classes are loaded.
676
-     * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
677
-     *        'EE_Request_Handler' => 'load_core'
678
-     *        'EE_Messages_Queue'  => 'load_lib'
679
-     *        'EEH_Debug_Tools'    => 'load_helper'
680
-     * or, if greater control is required, by providing a custom closure. For example:
681
-     *        'Some_Class' => function () {
682
-     *            return new Some_Class();
683
-     *        },
684
-     * This is required for instantiating dependencies
685
-     * where an interface has been type hinted in a class constructor. For example:
686
-     *        'Required_Interface' => function () {
687
-     *            return new A_Class_That_Implements_Required_Interface();
688
-     *        },
689
-     *
690
-     */
691
-    protected function _register_core_class_loaders()
692
-    {
693
-        //for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
694
-        //be used in a closure.
695
-        $request = &$this->request;
696
-        $response = &$this->response;
697
-        $legacy_request = &$this->legacy_request;
698
-        // $loader = &$this->loader;
699
-        $this->_class_loaders = array(
700
-            //load_core
701
-            'EE_Capabilities'          => 'load_core',
702
-            'EE_Encryption'            => 'load_core',
703
-            'EE_Front_Controller'      => 'load_core',
704
-            'EE_Module_Request_Router' => 'load_core',
705
-            'EE_Registry'              => 'load_core',
706
-            'EE_Request'               => function () use (&$legacy_request) {
707
-                return $legacy_request;
708
-            },
709
-            'EventEspresso\core\services\request\Request' => function () use (&$request) {
710
-                return $request;
711
-            },
712
-            'EventEspresso\core\services\request\Response' => function () use (&$response) {
713
-                return $response;
714
-            },
715
-            'EE_Request_Handler'       => 'load_core',
716
-            'EE_Session'               => 'load_core',
717
-            'EE_Cron_Tasks'            => 'load_core',
718
-            'EE_System'                => 'load_core',
719
-            'EE_Maintenance_Mode'      => 'load_core',
720
-            'EE_Register_CPTs'         => 'load_core',
721
-            'EE_Admin'                 => 'load_core',
722
-            //load_lib
723
-            'EE_Message_Resource_Manager'          => 'load_lib',
724
-            'EE_Message_Type_Collection'           => 'load_lib',
725
-            'EE_Message_Type_Collection_Loader'    => 'load_lib',
726
-            'EE_Messenger_Collection'              => 'load_lib',
727
-            'EE_Messenger_Collection_Loader'       => 'load_lib',
728
-            'EE_Messages_Processor'                => 'load_lib',
729
-            'EE_Message_Repository'                => 'load_lib',
730
-            'EE_Messages_Queue'                    => 'load_lib',
731
-            'EE_Messages_Data_Handler_Collection'  => 'load_lib',
732
-            'EE_Message_Template_Group_Collection' => 'load_lib',
733
-            'EE_Payment_Method_Manager'            => 'load_lib',
734
-            'EE_Messages_Generator'                => function () {
735
-                return EE_Registry::instance()->load_lib(
736
-                    'Messages_Generator',
737
-                    array(),
738
-                    false,
739
-                    false
740
-                );
741
-            },
742
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
743
-                return EE_Registry::instance()->load_lib(
744
-                    'Messages_Template_Defaults',
745
-                    $arguments,
746
-                    false,
747
-                    false
748
-                );
749
-            },
750
-            //load_model
751
-            // 'EEM_Attendee'                         => 'load_model',
752
-            // 'EEM_Message_Template_Group'           => 'load_model',
753
-            // 'EEM_Message_Template'                 => 'load_model',
754
-            //load_helper
755
-            'EEH_Parse_Shortcodes'                 => function () {
756
-                if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
757
-                    return new EEH_Parse_Shortcodes();
758
-                }
759
-                return null;
760
-            },
761
-            'EE_Template_Config'                   => function () {
762
-                return EE_Config::instance()->template_settings;
763
-            },
764
-            'EE_Currency_Config'                   => function () {
765
-                return EE_Config::instance()->currency;
766
-            },
767
-            'EE_Registration_Config'                   => function () {
768
-                return EE_Config::instance()->registration;
769
-            },
770
-            'EventEspresso\core\services\loaders\Loader' => function () {
771
-                return LoaderFactory::getLoader();
772
-            },
773
-            'EE_Base' => 'load_core',
774
-        );
775
-    }
776
-
777
-
778
-
779
-
780
-    /**
781
-     * can be used for supplying alternate names for classes,
782
-     * or for connecting interface names to instantiable classes
783
-     */
784
-    protected function _register_core_aliases()
785
-    {
786
-        $aliases = array(
787
-            'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
788
-            'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
789
-            'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
790
-            'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
791
-            'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
792
-            'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
793
-            'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
794
-            'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
795
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
796
-            'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
797
-            'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
798
-            'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
799
-            'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
800
-            'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
801
-            'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
802
-            'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
803
-            'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
804
-            'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
805
-            'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
806
-            'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
807
-            'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
808
-            'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
809
-            'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
810
-            'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
811
-            'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
812
-            'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
813
-            'CommandFactoryInterface'                                                     => 'EventEspresso\core\services\commands\CommandFactoryInterface',
814
-            'EventEspresso\core\services\commands\CommandFactoryInterface'                => 'EventEspresso\core\services\commands\CommandFactory',
815
-            'EventEspresso\core\domain\services\session\SessionIdentifierInterface'       => 'EE_Session',
816
-            'EmailValidatorInterface'                                                     => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
817
-            'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
818
-            'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
819
-            'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
820
-            'NoticesContainerInterface'                                           => 'EventEspresso\core\services\notices\NoticesContainerInterface',
821
-            'EventEspresso\core\services\notices\NoticesContainerInterface'       => 'EventEspresso\core\services\notices\NoticesContainer',
822
-            'EventEspresso\core\services\request\RequestInterface'                => 'EventEspresso\core\services\request\Request',
823
-            'EventEspresso\core\services\request\ResponseInterface'               => 'EventEspresso\core\services\request\Response',
824
-            'EventEspresso\core\domain\DomainInterface'                           => 'EventEspresso\core\domain\Domain',
825
-        );
826
-        foreach ($aliases as $alias => $fqn) {
827
-            $this->class_cache->addAlias($fqn, $alias);
828
-        }
829
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
830
-            $this->class_cache->addAlias(
831
-                'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
832
-                'EventEspresso\core\services\notices\NoticeConverterInterface'
833
-            );
834
-        }
835
-    }
836
-
837
-
838
-
839
-    /**
840
-     * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
841
-     * request Primarily used by unit tests.
842
-     */
843
-    public function reset()
844
-    {
845
-        $this->_register_core_class_loaders();
846
-        $this->_register_core_dependencies();
847
-    }
28
+	/**
29
+	 * This means that the requested class dependency is not present in the dependency map
30
+	 */
31
+	const not_registered = 0;
32
+
33
+	/**
34
+	 * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
35
+	 */
36
+	const load_new_object = 1;
37
+
38
+	/**
39
+	 * This instructs class loaders to return a previously instantiated and cached object for the requested class.
40
+	 * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
41
+	 */
42
+	const load_from_cache = 2;
43
+
44
+	/**
45
+	 * When registering a dependency,
46
+	 * this indicates to keep any existing dependencies that already exist,
47
+	 * and simply discard any new dependencies declared in the incoming data
48
+	 */
49
+	const KEEP_EXISTING_DEPENDENCIES = 0;
50
+
51
+	/**
52
+	 * When registering a dependency,
53
+	 * this indicates to overwrite any existing dependencies that already exist using the incoming data
54
+	 */
55
+	const OVERWRITE_DEPENDENCIES = 1;
56
+
57
+
58
+
59
+	/**
60
+	 * @type EE_Dependency_Map $_instance
61
+	 */
62
+	protected static $_instance;
63
+
64
+	/**
65
+	 * @var ClassInterfaceCache $class_cache
66
+	 */
67
+	private $class_cache;
68
+
69
+	/**
70
+	 * @type RequestInterface $request
71
+	 */
72
+	protected $request;
73
+
74
+	/**
75
+	 * @type LegacyRequestInterface $legacy_request
76
+	 */
77
+	protected $legacy_request;
78
+
79
+	/**
80
+	 * @type ResponseInterface $response
81
+	 */
82
+	protected $response;
83
+
84
+	/**
85
+	 * @type LoaderInterface $loader
86
+	 */
87
+	protected $loader;
88
+
89
+	/**
90
+	 * @type array $_dependency_map
91
+	 */
92
+	protected $_dependency_map = array();
93
+
94
+	/**
95
+	 * @type array $_class_loaders
96
+	 */
97
+	protected $_class_loaders = array();
98
+
99
+
100
+	/**
101
+	 * EE_Dependency_Map constructor.
102
+	 *
103
+	 * @param ClassInterfaceCache $class_cache
104
+	 */
105
+	protected function __construct(ClassInterfaceCache $class_cache)
106
+	{
107
+		$this->class_cache = $class_cache;
108
+		do_action('EE_Dependency_Map____construct', $this);
109
+	}
110
+
111
+
112
+	/**
113
+	 * @return void
114
+	 */
115
+	public function initialize()
116
+	{
117
+		$this->_register_core_dependencies();
118
+		$this->_register_core_class_loaders();
119
+		$this->_register_core_aliases();
120
+	}
121
+
122
+
123
+	/**
124
+	 * @singleton method used to instantiate class object
125
+	 * @param ClassInterfaceCache|null $class_cache
126
+	 * @return EE_Dependency_Map
127
+	 */
128
+	public static function instance(ClassInterfaceCache $class_cache = null) {
129
+		// check if class object is instantiated, and instantiated properly
130
+		if (
131
+			! self::$_instance instanceof EE_Dependency_Map
132
+			&& $class_cache instanceof ClassInterfaceCache
133
+		) {
134
+			self::$_instance = new EE_Dependency_Map($class_cache);
135
+		}
136
+		return self::$_instance;
137
+	}
138
+
139
+
140
+	/**
141
+	 * @param RequestInterface $request
142
+	 */
143
+	public function setRequest(RequestInterface $request)
144
+	{
145
+		$this->request = $request;
146
+	}
147
+
148
+
149
+	/**
150
+	 * @param LegacyRequestInterface $legacy_request
151
+	 */
152
+	public function setLegacyRequest(LegacyRequestInterface $legacy_request)
153
+	{
154
+		$this->legacy_request = $legacy_request;
155
+	}
156
+
157
+
158
+	/**
159
+	 * @param ResponseInterface $response
160
+	 */
161
+	public function setResponse(ResponseInterface $response)
162
+	{
163
+		$this->response = $response;
164
+	}
165
+
166
+
167
+
168
+	/**
169
+	 * @param LoaderInterface $loader
170
+	 */
171
+	public function setLoader(LoaderInterface $loader)
172
+	{
173
+		$this->loader = $loader;
174
+	}
175
+
176
+
177
+
178
+	/**
179
+	 * @param string $class
180
+	 * @param array  $dependencies
181
+	 * @param int    $overwrite
182
+	 * @return bool
183
+	 */
184
+	public static function register_dependencies(
185
+		$class,
186
+		array $dependencies,
187
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
188
+	) {
189
+		return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
190
+	}
191
+
192
+
193
+
194
+	/**
195
+	 * Assigns an array of class names and corresponding load sources (new or cached)
196
+	 * to the class specified by the first parameter.
197
+	 * IMPORTANT !!!
198
+	 * The order of elements in the incoming $dependencies array MUST match
199
+	 * the order of the constructor parameters for the class in question.
200
+	 * This is especially important when overriding any existing dependencies that are registered.
201
+	 * the third parameter controls whether any duplicate dependencies are overwritten or not.
202
+	 *
203
+	 * @param string $class
204
+	 * @param array  $dependencies
205
+	 * @param int    $overwrite
206
+	 * @return bool
207
+	 */
208
+	public function registerDependencies(
209
+		$class,
210
+		array $dependencies,
211
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
212
+	) {
213
+		$class = trim($class, '\\');
214
+		$registered = false;
215
+		if (empty(self::$_instance->_dependency_map[ $class ])) {
216
+			self::$_instance->_dependency_map[ $class ] = array();
217
+		}
218
+		// we need to make sure that any aliases used when registering a dependency
219
+		// get resolved to the correct class name
220
+		foreach ($dependencies as $dependency => $load_source) {
221
+			$alias = self::$_instance->get_alias($dependency);
222
+			if (
223
+				$overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
224
+				|| ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
225
+			) {
226
+				unset($dependencies[$dependency]);
227
+				$dependencies[$alias] = $load_source;
228
+				$registered = true;
229
+			}
230
+		}
231
+		// now add our two lists of dependencies together.
232
+		// using Union (+=) favours the arrays in precedence from left to right,
233
+		// so $dependencies is NOT overwritten because it is listed first
234
+		// ie: with A = B + C, entries in B take precedence over duplicate entries in C
235
+		// Union is way faster than array_merge() but should be used with caution...
236
+		// especially with numerically indexed arrays
237
+		$dependencies += self::$_instance->_dependency_map[ $class ];
238
+		// now we need to ensure that the resulting dependencies
239
+		// array only has the entries that are required for the class
240
+		// so first count how many dependencies were originally registered for the class
241
+		$dependency_count = count(self::$_instance->_dependency_map[ $class ]);
242
+		// if that count is non-zero (meaning dependencies were already registered)
243
+		self::$_instance->_dependency_map[ $class ] = $dependency_count
244
+			// then truncate the  final array to match that count
245
+			? array_slice($dependencies, 0, $dependency_count)
246
+			// otherwise just take the incoming array because nothing previously existed
247
+			: $dependencies;
248
+		return $registered;
249
+	}
250
+
251
+
252
+
253
+	/**
254
+	 * @param string $class_name
255
+	 * @param string $loader
256
+	 * @return bool
257
+	 * @throws DomainException
258
+	 */
259
+	public static function register_class_loader($class_name, $loader = 'load_core')
260
+	{
261
+		if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
262
+			throw new DomainException(
263
+				esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
264
+			);
265
+		}
266
+		// check that loader is callable or method starts with "load_" and exists in EE_Registry
267
+		if (
268
+			! is_callable($loader)
269
+			&& (
270
+				strpos($loader, 'load_') !== 0
271
+				|| ! method_exists('EE_Registry', $loader)
272
+			)
273
+		) {
274
+			throw new DomainException(
275
+				sprintf(
276
+					esc_html__(
277
+						'"%1$s" is not a valid loader method on EE_Registry.',
278
+						'event_espresso'
279
+					),
280
+					$loader
281
+				)
282
+			);
283
+		}
284
+		$class_name = self::$_instance->get_alias($class_name);
285
+		if (! isset(self::$_instance->_class_loaders[$class_name])) {
286
+			self::$_instance->_class_loaders[$class_name] = $loader;
287
+			return true;
288
+		}
289
+		return false;
290
+	}
291
+
292
+
293
+
294
+	/**
295
+	 * @return array
296
+	 */
297
+	public function dependency_map()
298
+	{
299
+		return $this->_dependency_map;
300
+	}
301
+
302
+
303
+
304
+	/**
305
+	 * returns TRUE if dependency map contains a listing for the provided class name
306
+	 *
307
+	 * @param string $class_name
308
+	 * @return boolean
309
+	 */
310
+	public function has($class_name = '')
311
+	{
312
+		// all legacy models have the same dependencies
313
+		if (strpos($class_name, 'EEM_') === 0) {
314
+			$class_name = 'LEGACY_MODELS';
315
+		}
316
+		return isset($this->_dependency_map[$class_name]) ? true : false;
317
+	}
318
+
319
+
320
+
321
+	/**
322
+	 * returns TRUE if dependency map contains a listing for the provided class name AND dependency
323
+	 *
324
+	 * @param string $class_name
325
+	 * @param string $dependency
326
+	 * @return bool
327
+	 */
328
+	public function has_dependency_for_class($class_name = '', $dependency = '')
329
+	{
330
+		// all legacy models have the same dependencies
331
+		if (strpos($class_name, 'EEM_') === 0) {
332
+			$class_name = 'LEGACY_MODELS';
333
+		}
334
+		$dependency = $this->get_alias($dependency);
335
+		return isset($this->_dependency_map[$class_name][$dependency])
336
+			? true
337
+			: false;
338
+	}
339
+
340
+
341
+
342
+	/**
343
+	 * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
344
+	 *
345
+	 * @param string $class_name
346
+	 * @param string $dependency
347
+	 * @return int
348
+	 */
349
+	public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
350
+	{
351
+		// all legacy models have the same dependencies
352
+		if (strpos($class_name, 'EEM_') === 0) {
353
+			$class_name = 'LEGACY_MODELS';
354
+		}
355
+		$dependency = $this->get_alias($dependency);
356
+		return $this->has_dependency_for_class($class_name, $dependency)
357
+			? $this->_dependency_map[$class_name][$dependency]
358
+			: EE_Dependency_Map::not_registered;
359
+	}
360
+
361
+
362
+
363
+	/**
364
+	 * @param string $class_name
365
+	 * @return string | Closure
366
+	 */
367
+	public function class_loader($class_name)
368
+	{
369
+		// all legacy models use load_model()
370
+		if(strpos($class_name, 'EEM_') === 0){
371
+			return 'load_model';
372
+		}
373
+		$class_name = $this->get_alias($class_name);
374
+		return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
375
+	}
376
+
377
+
378
+
379
+	/**
380
+	 * @return array
381
+	 */
382
+	public function class_loaders()
383
+	{
384
+		return $this->_class_loaders;
385
+	}
386
+
387
+
388
+
389
+	/**
390
+	 * adds an alias for a classname
391
+	 *
392
+	 * @param string $fqcn      the class name that should be used (concrete class to replace interface)
393
+	 * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
394
+	 * @param string $for_class the class that has the dependency (is type hinting for the interface)
395
+	 */
396
+	public function add_alias($fqcn, $alias, $for_class = '')
397
+	{
398
+		$this->class_cache->addAlias($alias, $fqcn, $for_class);
399
+	}
400
+
401
+
402
+
403
+	/**
404
+	 * PLZ NOTE: a better name for this method would be is_alias()
405
+	 * because it returns TRUE if the provided fully qualified name IS an alias
406
+	 *
407
+	 * @param string $fqn
408
+	 * @param string $for_class
409
+	 * @return bool
410
+	 */
411
+	public function has_alias($fqn = '', $for_class = '')
412
+	{
413
+		return $this->class_cache->isAlias($fqn, $for_class);
414
+	}
415
+
416
+
417
+
418
+	/**
419
+	 * PLZ NOTE: a better name for this method would be get_fqn_for_alias()
420
+	 * because it returns a FQN for provided alias if one exists, otherwise returns the original $alias
421
+	 * functions recursively, so that multiple aliases can be used to drill down to a FQN
422
+	 *  for example:
423
+	 *      if the following two entries were added to the _aliases array:
424
+	 *          array(
425
+	 *              'interface_alias'           => 'some\namespace\interface'
426
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
427
+	 *          )
428
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
429
+	 *      to load an instance of 'some\namespace\classname'
430
+	 *
431
+	 * @param string $alias
432
+	 * @param string $for_class
433
+	 * @return string
434
+	 */
435
+	public function get_alias($alias = '', $for_class = '')
436
+	{
437
+		return (string) $this->class_cache->getFqnForAlias($alias, $for_class);
438
+	}
439
+
440
+
441
+
442
+	/**
443
+	 * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
444
+	 * if one exists, or whether a new object should be generated every time the requested class is loaded.
445
+	 * This is done by using the following class constants:
446
+	 *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
447
+	 *        EE_Dependency_Map::load_new_object - generates a new object every time
448
+	 */
449
+	protected function _register_core_dependencies()
450
+	{
451
+		$this->_dependency_map = array(
452
+			'EE_Request_Handler'                                                                                          => array(
453
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
454
+			),
455
+			'EE_System'                                                                                                   => array(
456
+				'EE_Registry'                                 => EE_Dependency_Map::load_from_cache,
457
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
458
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
459
+				'EE_Maintenance_Mode'                         => EE_Dependency_Map::load_from_cache,
460
+			),
461
+			'EE_Session'                                                                                                  => array(
462
+				'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
463
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
464
+				'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
465
+				'EE_Encryption'                                            => EE_Dependency_Map::load_from_cache,
466
+			),
467
+			'EE_Cart'                                                                                                     => array(
468
+				'EE_Session' => EE_Dependency_Map::load_from_cache,
469
+			),
470
+			'EE_Front_Controller'                                                                                         => array(
471
+				'EE_Registry'              => EE_Dependency_Map::load_from_cache,
472
+				'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
473
+				'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
474
+			),
475
+			'EE_Messenger_Collection_Loader'                                                                              => array(
476
+				'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
477
+			),
478
+			'EE_Message_Type_Collection_Loader'                                                                           => array(
479
+				'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
480
+			),
481
+			'EE_Message_Resource_Manager'                                                                                 => array(
482
+				'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
483
+				'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
484
+				'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
485
+			),
486
+			'EE_Message_Factory'                                                                                          => array(
487
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
488
+			),
489
+			'EE_messages'                                                                                                 => array(
490
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
491
+			),
492
+			'EE_Messages_Generator'                                                                                       => array(
493
+				'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
494
+				'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
495
+				'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
496
+				'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
497
+			),
498
+			'EE_Messages_Processor'                                                                                       => array(
499
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
500
+			),
501
+			'EE_Messages_Queue'                                                                                           => array(
502
+				'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
503
+			),
504
+			'EE_Messages_Template_Defaults'                                                                               => array(
505
+				'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
506
+				'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
507
+			),
508
+			'EE_Message_To_Generate_From_Request'                                                                         => array(
509
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
510
+				'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
511
+			),
512
+			'EventEspresso\core\services\commands\CommandBus'                                                             => array(
513
+				'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
514
+			),
515
+			'EventEspresso\services\commands\CommandHandler'                                                              => array(
516
+				'EE_Registry'         => EE_Dependency_Map::load_from_cache,
517
+				'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
518
+			),
519
+			'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
520
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
521
+			),
522
+			'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
523
+				'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
524
+				'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
525
+			),
526
+			'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
527
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
528
+			),
529
+			'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
530
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
531
+			),
532
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
533
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
534
+			),
535
+			'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
536
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
537
+			),
538
+			'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
539
+				'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
540
+			),
541
+			'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
542
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
543
+			),
544
+			'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
545
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
546
+			),
547
+			'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
548
+				'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
549
+			),
550
+			'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
551
+				'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
552
+			),
553
+			'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
554
+				'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
555
+			),
556
+			'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
557
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
558
+			),
559
+			'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
560
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
561
+			),
562
+			'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
563
+				'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
564
+			),
565
+			'EventEspresso\core\services\database\TableManager'                                                           => array(
566
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
567
+			),
568
+			'EE_Data_Migration_Class_Base'                                                                                => array(
569
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
570
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
571
+			),
572
+			'EE_DMS_Core_4_1_0'                                                                                           => array(
573
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
574
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
575
+			),
576
+			'EE_DMS_Core_4_2_0'                                                                                           => array(
577
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
578
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
579
+			),
580
+			'EE_DMS_Core_4_3_0'                                                                                           => array(
581
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
582
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
583
+			),
584
+			'EE_DMS_Core_4_4_0'                                                                                           => array(
585
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
586
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
587
+			),
588
+			'EE_DMS_Core_4_5_0'                                                                                           => array(
589
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
590
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
591
+			),
592
+			'EE_DMS_Core_4_6_0'                                                                                           => array(
593
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
594
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
595
+			),
596
+			'EE_DMS_Core_4_7_0'                                                                                           => array(
597
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
598
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
599
+			),
600
+			'EE_DMS_Core_4_8_0'                                                                                           => array(
601
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
602
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
603
+			),
604
+			'EE_DMS_Core_4_9_0'                                                                                           => array(
605
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
606
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
607
+			),
608
+			'EventEspresso\core\services\assets\Registry'                                                                 => array(
609
+				'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
610
+				'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
611
+				'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache
612
+			),
613
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
614
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
615
+			),
616
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
617
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
618
+			),
619
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
620
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
621
+			),
622
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
623
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
624
+			),
625
+			'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
626
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
627
+			),
628
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
629
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
630
+			),
631
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
632
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
633
+			),
634
+			'EventEspresso\core\services\cache\BasicCacheManager'                        => array(
635
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
636
+			),
637
+			'EventEspresso\core\services\cache\PostRelatedCacheManager'                  => array(
638
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
639
+			),
640
+			'EventEspresso\core\domain\services\validation\email\EmailValidationService' => array(
641
+				'EE_Registration_Config'                                  => EE_Dependency_Map::load_from_cache,
642
+				'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
643
+			),
644
+			'EventEspresso\core\domain\values\EmailAddress'                              => array(
645
+				null,
646
+				'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
647
+			),
648
+			'EventEspresso\core\services\orm\ModelFieldFactory' => array(
649
+				'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
650
+			),
651
+			'LEGACY_MODELS'                                                   => array(
652
+				null,
653
+				'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
654
+			),
655
+			'EE_Module_Request_Router' => array(
656
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
657
+			),
658
+			'EE_Registration_Processor' => array(
659
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
660
+			),
661
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' => array(
662
+				null,
663
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
664
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
665
+			),
666
+			'EE_Admin_Transactions_List_Table' => array(
667
+				null,
668
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
669
+			),
670
+		);
671
+	}
672
+
673
+
674
+	/**
675
+	 * Registers how core classes are loaded.
676
+	 * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
677
+	 *        'EE_Request_Handler' => 'load_core'
678
+	 *        'EE_Messages_Queue'  => 'load_lib'
679
+	 *        'EEH_Debug_Tools'    => 'load_helper'
680
+	 * or, if greater control is required, by providing a custom closure. For example:
681
+	 *        'Some_Class' => function () {
682
+	 *            return new Some_Class();
683
+	 *        },
684
+	 * This is required for instantiating dependencies
685
+	 * where an interface has been type hinted in a class constructor. For example:
686
+	 *        'Required_Interface' => function () {
687
+	 *            return new A_Class_That_Implements_Required_Interface();
688
+	 *        },
689
+	 *
690
+	 */
691
+	protected function _register_core_class_loaders()
692
+	{
693
+		//for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
694
+		//be used in a closure.
695
+		$request = &$this->request;
696
+		$response = &$this->response;
697
+		$legacy_request = &$this->legacy_request;
698
+		// $loader = &$this->loader;
699
+		$this->_class_loaders = array(
700
+			//load_core
701
+			'EE_Capabilities'          => 'load_core',
702
+			'EE_Encryption'            => 'load_core',
703
+			'EE_Front_Controller'      => 'load_core',
704
+			'EE_Module_Request_Router' => 'load_core',
705
+			'EE_Registry'              => 'load_core',
706
+			'EE_Request'               => function () use (&$legacy_request) {
707
+				return $legacy_request;
708
+			},
709
+			'EventEspresso\core\services\request\Request' => function () use (&$request) {
710
+				return $request;
711
+			},
712
+			'EventEspresso\core\services\request\Response' => function () use (&$response) {
713
+				return $response;
714
+			},
715
+			'EE_Request_Handler'       => 'load_core',
716
+			'EE_Session'               => 'load_core',
717
+			'EE_Cron_Tasks'            => 'load_core',
718
+			'EE_System'                => 'load_core',
719
+			'EE_Maintenance_Mode'      => 'load_core',
720
+			'EE_Register_CPTs'         => 'load_core',
721
+			'EE_Admin'                 => 'load_core',
722
+			//load_lib
723
+			'EE_Message_Resource_Manager'          => 'load_lib',
724
+			'EE_Message_Type_Collection'           => 'load_lib',
725
+			'EE_Message_Type_Collection_Loader'    => 'load_lib',
726
+			'EE_Messenger_Collection'              => 'load_lib',
727
+			'EE_Messenger_Collection_Loader'       => 'load_lib',
728
+			'EE_Messages_Processor'                => 'load_lib',
729
+			'EE_Message_Repository'                => 'load_lib',
730
+			'EE_Messages_Queue'                    => 'load_lib',
731
+			'EE_Messages_Data_Handler_Collection'  => 'load_lib',
732
+			'EE_Message_Template_Group_Collection' => 'load_lib',
733
+			'EE_Payment_Method_Manager'            => 'load_lib',
734
+			'EE_Messages_Generator'                => function () {
735
+				return EE_Registry::instance()->load_lib(
736
+					'Messages_Generator',
737
+					array(),
738
+					false,
739
+					false
740
+				);
741
+			},
742
+			'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
743
+				return EE_Registry::instance()->load_lib(
744
+					'Messages_Template_Defaults',
745
+					$arguments,
746
+					false,
747
+					false
748
+				);
749
+			},
750
+			//load_model
751
+			// 'EEM_Attendee'                         => 'load_model',
752
+			// 'EEM_Message_Template_Group'           => 'load_model',
753
+			// 'EEM_Message_Template'                 => 'load_model',
754
+			//load_helper
755
+			'EEH_Parse_Shortcodes'                 => function () {
756
+				if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
757
+					return new EEH_Parse_Shortcodes();
758
+				}
759
+				return null;
760
+			},
761
+			'EE_Template_Config'                   => function () {
762
+				return EE_Config::instance()->template_settings;
763
+			},
764
+			'EE_Currency_Config'                   => function () {
765
+				return EE_Config::instance()->currency;
766
+			},
767
+			'EE_Registration_Config'                   => function () {
768
+				return EE_Config::instance()->registration;
769
+			},
770
+			'EventEspresso\core\services\loaders\Loader' => function () {
771
+				return LoaderFactory::getLoader();
772
+			},
773
+			'EE_Base' => 'load_core',
774
+		);
775
+	}
776
+
777
+
778
+
779
+
780
+	/**
781
+	 * can be used for supplying alternate names for classes,
782
+	 * or for connecting interface names to instantiable classes
783
+	 */
784
+	protected function _register_core_aliases()
785
+	{
786
+		$aliases = array(
787
+			'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
788
+			'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
789
+			'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
790
+			'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
791
+			'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
792
+			'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
793
+			'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
794
+			'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
795
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
796
+			'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
797
+			'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
798
+			'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
799
+			'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
800
+			'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
801
+			'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
802
+			'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
803
+			'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
804
+			'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
805
+			'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
806
+			'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
807
+			'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
808
+			'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
809
+			'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
810
+			'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
811
+			'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
812
+			'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
813
+			'CommandFactoryInterface'                                                     => 'EventEspresso\core\services\commands\CommandFactoryInterface',
814
+			'EventEspresso\core\services\commands\CommandFactoryInterface'                => 'EventEspresso\core\services\commands\CommandFactory',
815
+			'EventEspresso\core\domain\services\session\SessionIdentifierInterface'       => 'EE_Session',
816
+			'EmailValidatorInterface'                                                     => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
817
+			'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
818
+			'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
819
+			'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
820
+			'NoticesContainerInterface'                                           => 'EventEspresso\core\services\notices\NoticesContainerInterface',
821
+			'EventEspresso\core\services\notices\NoticesContainerInterface'       => 'EventEspresso\core\services\notices\NoticesContainer',
822
+			'EventEspresso\core\services\request\RequestInterface'                => 'EventEspresso\core\services\request\Request',
823
+			'EventEspresso\core\services\request\ResponseInterface'               => 'EventEspresso\core\services\request\Response',
824
+			'EventEspresso\core\domain\DomainInterface'                           => 'EventEspresso\core\domain\Domain',
825
+		);
826
+		foreach ($aliases as $alias => $fqn) {
827
+			$this->class_cache->addAlias($fqn, $alias);
828
+		}
829
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
830
+			$this->class_cache->addAlias(
831
+				'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
832
+				'EventEspresso\core\services\notices\NoticeConverterInterface'
833
+			);
834
+		}
835
+	}
836
+
837
+
838
+
839
+	/**
840
+	 * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
841
+	 * request Primarily used by unit tests.
842
+	 */
843
+	public function reset()
844
+	{
845
+		$this->_register_core_class_loaders();
846
+		$this->_register_core_dependencies();
847
+	}
848 848
 
849 849
 
850 850
 }
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@  discard block
 block discarded – undo
7 7
 use EventEspresso\core\services\request\RequestInterface;
8 8
 use EventEspresso\core\services\request\ResponseInterface;
9 9
 
10
-if (! defined('EVENT_ESPRESSO_VERSION')) {
10
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
11 11
     exit('No direct script access allowed');
12 12
 }
13 13
 
@@ -212,8 +212,8 @@  discard block
 block discarded – undo
212 212
     ) {
213 213
         $class = trim($class, '\\');
214 214
         $registered = false;
215
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
216
-            self::$_instance->_dependency_map[ $class ] = array();
215
+        if (empty(self::$_instance->_dependency_map[$class])) {
216
+            self::$_instance->_dependency_map[$class] = array();
217 217
         }
218 218
         // we need to make sure that any aliases used when registering a dependency
219 219
         // get resolved to the correct class name
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
             $alias = self::$_instance->get_alias($dependency);
222 222
             if (
223 223
                 $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
224
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
224
+                || ! isset(self::$_instance->_dependency_map[$class][$alias])
225 225
             ) {
226 226
                 unset($dependencies[$dependency]);
227 227
                 $dependencies[$alias] = $load_source;
@@ -234,13 +234,13 @@  discard block
 block discarded – undo
234 234
         // ie: with A = B + C, entries in B take precedence over duplicate entries in C
235 235
         // Union is way faster than array_merge() but should be used with caution...
236 236
         // especially with numerically indexed arrays
237
-        $dependencies += self::$_instance->_dependency_map[ $class ];
237
+        $dependencies += self::$_instance->_dependency_map[$class];
238 238
         // now we need to ensure that the resulting dependencies
239 239
         // array only has the entries that are required for the class
240 240
         // so first count how many dependencies were originally registered for the class
241
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
241
+        $dependency_count = count(self::$_instance->_dependency_map[$class]);
242 242
         // if that count is non-zero (meaning dependencies were already registered)
243
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
243
+        self::$_instance->_dependency_map[$class] = $dependency_count
244 244
             // then truncate the  final array to match that count
245 245
             ? array_slice($dependencies, 0, $dependency_count)
246 246
             // otherwise just take the incoming array because nothing previously existed
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
      */
259 259
     public static function register_class_loader($class_name, $loader = 'load_core')
260 260
     {
261
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
261
+        if ( ! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
262 262
             throw new DomainException(
263 263
                 esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
264 264
             );
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
             );
283 283
         }
284 284
         $class_name = self::$_instance->get_alias($class_name);
285
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
285
+        if ( ! isset(self::$_instance->_class_loaders[$class_name])) {
286 286
             self::$_instance->_class_loaders[$class_name] = $loader;
287 287
             return true;
288 288
         }
@@ -367,7 +367,7 @@  discard block
 block discarded – undo
367 367
     public function class_loader($class_name)
368 368
     {
369 369
         // all legacy models use load_model()
370
-        if(strpos($class_name, 'EEM_') === 0){
370
+        if (strpos($class_name, 'EEM_') === 0) {
371 371
             return 'load_model';
372 372
         }
373 373
         $class_name = $this->get_alias($class_name);
@@ -703,13 +703,13 @@  discard block
 block discarded – undo
703 703
             'EE_Front_Controller'      => 'load_core',
704 704
             'EE_Module_Request_Router' => 'load_core',
705 705
             'EE_Registry'              => 'load_core',
706
-            'EE_Request'               => function () use (&$legacy_request) {
706
+            'EE_Request'               => function() use (&$legacy_request) {
707 707
                 return $legacy_request;
708 708
             },
709
-            'EventEspresso\core\services\request\Request' => function () use (&$request) {
709
+            'EventEspresso\core\services\request\Request' => function() use (&$request) {
710 710
                 return $request;
711 711
             },
712
-            'EventEspresso\core\services\request\Response' => function () use (&$response) {
712
+            'EventEspresso\core\services\request\Response' => function() use (&$response) {
713 713
                 return $response;
714 714
             },
715 715
             'EE_Request_Handler'       => 'load_core',
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
             'EE_Messages_Data_Handler_Collection'  => 'load_lib',
732 732
             'EE_Message_Template_Group_Collection' => 'load_lib',
733 733
             'EE_Payment_Method_Manager'            => 'load_lib',
734
-            'EE_Messages_Generator'                => function () {
734
+            'EE_Messages_Generator'                => function() {
735 735
                 return EE_Registry::instance()->load_lib(
736 736
                     'Messages_Generator',
737 737
                     array(),
@@ -739,7 +739,7 @@  discard block
 block discarded – undo
739 739
                     false
740 740
                 );
741 741
             },
742
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
742
+            'EE_Messages_Template_Defaults'        => function($arguments = array()) {
743 743
                 return EE_Registry::instance()->load_lib(
744 744
                     'Messages_Template_Defaults',
745 745
                     $arguments,
@@ -752,22 +752,22 @@  discard block
 block discarded – undo
752 752
             // 'EEM_Message_Template_Group'           => 'load_model',
753 753
             // 'EEM_Message_Template'                 => 'load_model',
754 754
             //load_helper
755
-            'EEH_Parse_Shortcodes'                 => function () {
755
+            'EEH_Parse_Shortcodes'                 => function() {
756 756
                 if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
757 757
                     return new EEH_Parse_Shortcodes();
758 758
                 }
759 759
                 return null;
760 760
             },
761
-            'EE_Template_Config'                   => function () {
761
+            'EE_Template_Config'                   => function() {
762 762
                 return EE_Config::instance()->template_settings;
763 763
             },
764
-            'EE_Currency_Config'                   => function () {
764
+            'EE_Currency_Config'                   => function() {
765 765
                 return EE_Config::instance()->currency;
766 766
             },
767
-            'EE_Registration_Config'                   => function () {
767
+            'EE_Registration_Config'                   => function() {
768 768
                 return EE_Config::instance()->registration;
769 769
             },
770
-            'EventEspresso\core\services\loaders\Loader' => function () {
770
+            'EventEspresso\core\services\loaders\Loader' => function() {
771 771
                 return LoaderFactory::getLoader();
772 772
             },
773 773
             'EE_Base' => 'load_core',
@@ -826,7 +826,7 @@  discard block
 block discarded – undo
826 826
         foreach ($aliases as $alias => $fqn) {
827 827
             $this->class_cache->addAlias($fqn, $alias);
828 828
         }
829
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
829
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
830 830
             $this->class_cache->addAlias(
831 831
                 'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices',
832 832
                 'EventEspresso\core\services\notices\NoticeConverterInterface'
Please login to merge, or discard this patch.