Completed
Branch BUG/11126/attendee-mover-tax (6b5324)
by
unknown
94:01 queued 81:15
created
core/helpers/EEH_Form_Fields.helper.php 1 patch
Spacing   +377 added lines, -377 removed lines patch added patch discarded remove patch
@@ -69,10 +69,10 @@  discard block
 block discarded – undo
69 69
 	 * 	@return string
70 70
 	 * 	@todo: at some point we can break this down into other static methods to abstract it a bit better.
71 71
 	 */
72
-	static public function get_form_fields( $input_vars = array(), $id = FALSE ) {
72
+	static public function get_form_fields($input_vars = array(), $id = FALSE) {
73 73
 		
74
-		if ( empty($input_vars) ) {
75
-			EE_Error::add_error( __('missing required variables for the form field generator', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
74
+		if (empty($input_vars)) {
75
+			EE_Error::add_error(__('missing required variables for the form field generator', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
76 76
 			return FALSE;
77 77
 		}
78 78
 
@@ -98,25 +98,25 @@  discard block
 block discarded – undo
98 98
 				'append_content' => ''
99 99
 				);
100 100
 
101
-			$input_value = wp_parse_args( $input_value, $defaults );
101
+			$input_value = wp_parse_args($input_value, $defaults);
102 102
 
103 103
 			// required fields get a *
104 104
 			$required = isset($input_value['required']) && $input_value['required'] ? ' <span>*</span>: ' : ': ';
105 105
 			// and the css class "required"
106
-			$css_class = isset( $input_value['css_class'] ) ? $input_value['css_class'] : '';
107
-			$styles = $input_value['required'] ? 'required ' . $css_class : $css_class;
106
+			$css_class = isset($input_value['css_class']) ? $input_value['css_class'] : '';
107
+			$styles = $input_value['required'] ? 'required '.$css_class : $css_class;
108 108
 
109
-			$field_id = ($id) ? $id . '-' . $input_key : $input_key;
110
-			$tabindex = !empty($input_value['tabindex']) ? ' tabindex="' . $input_value['tabindex'] . '"' : '';
109
+			$field_id = ($id) ? $id.'-'.$input_key : $input_key;
110
+			$tabindex = ! empty($input_value['tabindex']) ? ' tabindex="'.$input_value['tabindex'].'"' : '';
111 111
 
112 112
 			//rows or cols?
113
-			$rows = isset($input_value['rows'] ) ? $input_value['rows'] : '10';
114
-			$cols = isset($input_value['cols'] ) ? $input_value['cols'] : '80';
113
+			$rows = isset($input_value['rows']) ? $input_value['rows'] : '10';
114
+			$cols = isset($input_value['cols']) ? $input_value['cols'] : '80';
115 115
 
116 116
 			//any content?
117 117
 			$append_content = $input_value['append_content'];
118 118
 
119
-			$output .= (!$close) ? '<ul>' : '';
119
+			$output .= ( ! $close) ? '<ul>' : '';
120 120
 			$output .= '<li>';
121 121
 
122 122
 			// what type of input are we dealing with ?
@@ -124,15 +124,15 @@  discard block
 block discarded – undo
124 124
 
125 125
 				// text inputs
126 126
 				case 'text' :
127
-					$output .= "\n\t\t\t" . '<label for="' . $field_id . '">' . $input_value['label'] . $required . '</label>';
128
-					$output .= "\n\t\t\t" . '<input id="' . $field_id . '" class="' . $styles . '" type="text" value="' . esc_textarea($input_value['value']) . '" name="' . $input_value['name'] . '"' . $tabindex . '>';
127
+					$output .= "\n\t\t\t".'<label for="'.$field_id.'">'.$input_value['label'].$required.'</label>';
128
+					$output .= "\n\t\t\t".'<input id="'.$field_id.'" class="'.$styles.'" type="text" value="'.esc_textarea($input_value['value']).'" name="'.$input_value['name'].'"'.$tabindex.'>';
129 129
 					break;
130 130
 
131 131
 				// dropdowns
132 132
 				case 'select' :
133 133
 
134
-					$output .= "\n\t\t\t" . '<label for="' . $field_id . '">' . $input_value['label'] . $required . '</label>';
135
-					$output .= "\n\t\t\t" . '<select id="' . $field_id . '" class="' . $styles . '" name="' . $input_value['name'] . '"' . $tabindex . '>';
134
+					$output .= "\n\t\t\t".'<label for="'.$field_id.'">'.$input_value['label'].$required.'</label>';
135
+					$output .= "\n\t\t\t".'<select id="'.$field_id.'" class="'.$styles.'" name="'.$input_value['name'].'"'.$tabindex.'>';
136 136
 
137 137
 					if (is_array($input_value['options'])) {
138 138
 						$options = $input_value['options'];
@@ -141,30 +141,30 @@  discard block
 block discarded – undo
141 141
 					}
142 142
 
143 143
 					foreach ($options as $key => $value) {
144
-						$selected = isset( $input_value['value'] ) && $input_value['value'] == $key ? 'selected=selected' : '';
144
+						$selected = isset($input_value['value']) && $input_value['value'] == $key ? 'selected=selected' : '';
145 145
 						//$key = str_replace( ' ', '_', sanitize_key( $value ));
146
-						$output .= "\n\t\t\t\t" . '<option '. $selected . ' value="' . $key . '">' . $value . '</option>';
146
+						$output .= "\n\t\t\t\t".'<option '.$selected.' value="'.$key.'">'.$value.'</option>';
147 147
 					}
148
-					$output .= "\n\t\t\t" . '</select>';
148
+					$output .= "\n\t\t\t".'</select>';
149 149
 
150 150
 					break;
151 151
 
152 152
 				case 'textarea' :
153 153
 
154
-					$output .= "\n\t\t\t" . '<label for="' . $field_id . '">' . $input_value['label'] . $required . '</label>';
155
-					$output .= "\n\t\t\t" . '<textarea id="' . $field_id . '" class="' . $styles . '" rows="'.$rows.'" cols="'.$cols.'" name="' . $input_value['name'] . '"' . $tabindex . '>' . esc_textarea($input_value['value']) . '</textarea>';
154
+					$output .= "\n\t\t\t".'<label for="'.$field_id.'">'.$input_value['label'].$required.'</label>';
155
+					$output .= "\n\t\t\t".'<textarea id="'.$field_id.'" class="'.$styles.'" rows="'.$rows.'" cols="'.$cols.'" name="'.$input_value['name'].'"'.$tabindex.'>'.esc_textarea($input_value['value']).'</textarea>';
156 156
 					break;
157 157
 
158 158
 				case 'hidden' :
159 159
 					$close = false;
160 160
 					$output .= "</li></ul>";
161
-					$output .= "\n\t\t\t" . '<input id="' . $field_id . '" type="hidden" name="' . $input_value['name'] . '" value="' . $input_value['value'] . '">';
161
+					$output .= "\n\t\t\t".'<input id="'.$field_id.'" type="hidden" name="'.$input_value['name'].'" value="'.$input_value['value'].'">';
162 162
 					break;
163 163
 
164 164
 				case 'checkbox' :
165
-					$checked = ( $input_value['value'] == 1 ) ? 'checked="checked"' : '';
166
-					$output .= "\n\t\t\t" . '<label for="' . $field_id . '">' . $input_value['label'] . $required . '</label>';
167
-					$output .= "\n\t\t\t" . '<input id="' . $field_id. '" type="checkbox" name="' . $input_value['name'] . '" value="1"' . $checked . $tabindex . ' />';
165
+					$checked = ($input_value['value'] == 1) ? 'checked="checked"' : '';
166
+					$output .= "\n\t\t\t".'<label for="'.$field_id.'">'.$input_value['label'].$required.'</label>';
167
+					$output .= "\n\t\t\t".'<input id="'.$field_id.'" type="checkbox" name="'.$input_value['name'].'" value="1"'.$checked.$tabindex.' />';
168 168
 					break;
169 169
 
170 170
 				case 'wp_editor' :
@@ -177,19 +177,19 @@  discard block
 block discarded – undo
177 177
 					);
178 178
 					$output .= '</li>';
179 179
 					$output .= '</ul>';
180
-					$output .= '<h4>' . $input_value['label'] . '</h4>';
181
-					if ( $append_content ) {
180
+					$output .= '<h4>'.$input_value['label'].'</h4>';
181
+					if ($append_content) {
182 182
 						$output .= $append_content;
183 183
 					}
184 184
 					ob_start();
185
-					wp_editor( $input_value['value'], $field_id, $editor_settings);
185
+					wp_editor($input_value['value'], $field_id, $editor_settings);
186 186
 					$editor = ob_get_contents();
187 187
 					ob_end_clean();
188 188
 					$output .= $editor;
189 189
 					break;
190 190
 
191 191
 				}
192
-				if ( $append_content && $input_value['input'] !== 'wp_editor' ) {
192
+				if ($append_content && $input_value['input'] !== 'wp_editor') {
193 193
 					$output .= $append_content;
194 194
 				}
195 195
 				$output .= ($close) ? '</li>' : '';
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
 		$form_fields = array();
231 231
 		$fields = (array) $fields;
232 232
 
233
-		foreach ( $fields as $field_name => $field_atts ) {
233
+		foreach ($fields as $field_name => $field_atts) {
234 234
 			//defaults:
235 235
 			$defaults = array(
236 236
 				'label' => '',
@@ -248,67 +248,67 @@  discard block
 block discarded – undo
248 248
 				'wpeditor_args' => array()
249 249
 				);
250 250
 			// merge defaults with passed arguments
251
-			$_fields = wp_parse_args( $field_atts, $defaults);
252
-			extract( $_fields );
251
+			$_fields = wp_parse_args($field_atts, $defaults);
252
+			extract($_fields);
253 253
 			// generate label
254
-			$label = empty($label) ? '' : '<label for="' . $id . '">' . $label . '</label>';
254
+			$label = empty($label) ? '' : '<label for="'.$id.'">'.$label.'</label>';
255 255
 			// generate field name
256
-			$f_name = !empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
256
+			$f_name = ! empty($unique_id) ? $field_name.'['.$unique_id.']' : $field_name;
257 257
 
258 258
 			//tabindex
259
-			$tabindex_str = !empty( $tabindex ) ? ' tabindex="' . $tabindex . '"' : '';
259
+			$tabindex_str = ! empty($tabindex) ? ' tabindex="'.$tabindex.'"' : '';
260 260
 
261 261
 			//we determine what we're building based on the type
262
-			switch ( $type ) {
262
+			switch ($type) {
263 263
 
264 264
 				case 'textarea' :
265
-						$fld = '<textarea id="' . $id . '" class="' . $class . '" rows="' . $dimensions[1] . '" cols="' . $dimensions[0] . '" name="' . $f_name . '"' . $tabindex_str . '>' . $value . '</textarea>';
265
+						$fld = '<textarea id="'.$id.'" class="'.$class.'" rows="'.$dimensions[1].'" cols="'.$dimensions[0].'" name="'.$f_name.'"'.$tabindex_str.'>'.$value.'</textarea>';
266 266
 						$fld .= $extra_desc;
267 267
 					break;
268 268
 
269 269
 				case 'checkbox' :
270 270
 						$c_input = '';
271
-						if ( is_array($value) ) {
272
-							foreach ( $value as $key => $val ) {
273
-								$c_id = $field_name . '_' . $value;
274
-								$c_class = isset($classes[$key]) ? ' class="' . $classes[$key] . '" ' : '';
275
-								$c_label = isset($labels[$key]) ? '<label for="' . $c_id . '">' . $labels[$key] . '</label>' : '';
276
-								$checked = !empty($default) && $default == $val ? ' checked="checked" ' : '';
277
-								$c_input .= '<input name="' . $f_name . '[]" type="checkbox" id="' . $c_id . '"' . $c_class . 'value="' . $val . '"' . $checked . $tabindex_str . ' />' . "\n" . $c_label;
271
+						if (is_array($value)) {
272
+							foreach ($value as $key => $val) {
273
+								$c_id = $field_name.'_'.$value;
274
+								$c_class = isset($classes[$key]) ? ' class="'.$classes[$key].'" ' : '';
275
+								$c_label = isset($labels[$key]) ? '<label for="'.$c_id.'">'.$labels[$key].'</label>' : '';
276
+								$checked = ! empty($default) && $default == $val ? ' checked="checked" ' : '';
277
+								$c_input .= '<input name="'.$f_name.'[]" type="checkbox" id="'.$c_id.'"'.$c_class.'value="'.$val.'"'.$checked.$tabindex_str.' />'."\n".$c_label;
278 278
 							}
279 279
 							$fld = $c_input;
280 280
 						} else {
281
-							$checked = !empty($default) && $default == $val ? 'checked="checked" ' : '';
282
-							$fld = '<input name="'. $f_name . '" type="checkbox" id="' . $id . '" class="' . $class . '" value="' . $value . '"' . $checked . $tabindex_str . ' />' . "\n";
281
+							$checked = ! empty($default) && $default == $val ? 'checked="checked" ' : '';
282
+							$fld = '<input name="'.$f_name.'" type="checkbox" id="'.$id.'" class="'.$class.'" value="'.$value.'"'.$checked.$tabindex_str.' />'."\n";
283 283
 						}
284 284
 					break;
285 285
 
286 286
 				case 'radio' :
287 287
 						$c_input = '';
288
-						if ( is_array($value) ) {
289
-							foreach ( $value as $key => $val ) {
290
-								$c_id = $field_name . '_' . $value;
291
-								$c_class = isset($classes[$key]) ? 'class="' . $classes[$key] . '" ' : '';
292
-								$c_label = isset($labels[$key]) ? '<label for="' . $c_id . '">' . $labels[$key] . '</label>' : '';
293
-								$checked = !empty($default) && $default == $val ? ' checked="checked" ' : '';
294
-								$c_input .= '<input name="' . $f_name . '" type="checkbox" id="' . $c_id . '"' . $c_class . 'value="' . $val . '"' . $checked . $tabindex_str . ' />' . "\n" . $c_label;
288
+						if (is_array($value)) {
289
+							foreach ($value as $key => $val) {
290
+								$c_id = $field_name.'_'.$value;
291
+								$c_class = isset($classes[$key]) ? 'class="'.$classes[$key].'" ' : '';
292
+								$c_label = isset($labels[$key]) ? '<label for="'.$c_id.'">'.$labels[$key].'</label>' : '';
293
+								$checked = ! empty($default) && $default == $val ? ' checked="checked" ' : '';
294
+								$c_input .= '<input name="'.$f_name.'" type="checkbox" id="'.$c_id.'"'.$c_class.'value="'.$val.'"'.$checked.$tabindex_str.' />'."\n".$c_label;
295 295
 							}
296 296
 							$fld = $c_input;
297 297
 						} else {
298
-							$checked = !empty($default) && $default == $val ? 'checked="checked" ' : '';
299
-							$fld = '<input name="'. $f_name . '" type="checkbox" id="' . $id . '" class="' . $class . '" value="' . $value . '"' . $checked . $tabindex_str . ' />' . "\n";
298
+							$checked = ! empty($default) && $default == $val ? 'checked="checked" ' : '';
299
+							$fld = '<input name="'.$f_name.'" type="checkbox" id="'.$id.'" class="'.$class.'" value="'.$value.'"'.$checked.$tabindex_str.' />'."\n";
300 300
 						}
301 301
 					break;
302 302
 
303 303
 				case 'hidden' :
304
-						$fld = '<input name="' . $f_name . '" type="hidden" id="' . $id . '" class="' . $class . '" value="' . $value . '" />' . "\n";
304
+						$fld = '<input name="'.$f_name.'" type="hidden" id="'.$id.'" class="'.$class.'" value="'.$value.'" />'."\n";
305 305
 					break;
306 306
 
307 307
 				case 'select' :
308
-						$fld = '<select name="' . $f_name . '" class="' . $class . '" id="' . $id . '"' . $tabindex_str . '>' . "\n";
309
-						foreach ( $value as $key => $val ) {
310
-							$checked = !empty($default) && $default == $val ? ' selected="selected"' : '';
311
-							$fld .= "\t" . '<option value="' . $val . '"' . $checked . '>' . $labels[$key] . '</option>' . "\n";
308
+						$fld = '<select name="'.$f_name.'" class="'.$class.'" id="'.$id.'"'.$tabindex_str.'>'."\n";
309
+						foreach ($value as $key => $val) {
310
+							$checked = ! empty($default) && $default == $val ? ' selected="selected"' : '';
311
+							$fld .= "\t".'<option value="'.$val.'"'.$checked.'>'.$labels[$key].'</option>'."\n";
312 312
 						}
313 313
 						$fld .= '</select>';
314 314
 					break;
@@ -320,21 +320,21 @@  discard block
 block discarded – undo
320 320
 							'editor_class' => $class,
321 321
 							'tabindex' => $tabindex
322 322
 							);
323
-						$editor_settings = array_merge( $wpeditor_args, $editor_settings );
323
+						$editor_settings = array_merge($wpeditor_args, $editor_settings);
324 324
 						ob_start();
325
-						wp_editor( $value, $id, $editor_settings );
325
+						wp_editor($value, $id, $editor_settings);
326 326
 						$editor = ob_get_contents();
327 327
 						ob_end_clean();
328 328
 						$fld = $editor;
329 329
 					break;
330 330
 
331 331
 				default : //'text fields'
332
-						$fld = '<input name="' . $f_name . '" type="text" id="' . $id . '" class="' . $class . '" value="' . $value . '"' . $tabindex_str . ' />' . "\n";
332
+						$fld = '<input name="'.$f_name.'" type="text" id="'.$id.'" class="'.$class.'" value="'.$value.'"'.$tabindex_str.' />'."\n";
333 333
 						$fld .= $extra_desc;
334 334
 
335 335
 			}
336 336
 
337
-			$form_fields[ $field_name ] = array( 'label' => $label, 'field' => $fld );
337
+			$form_fields[$field_name] = array('label' => $label, 'field' => $fld);
338 338
 		}
339 339
 
340 340
 		return $form_fields;
@@ -363,19 +363,19 @@  discard block
 block discarded – undo
363 363
 	 */
364 364
 	static public function select_input($name, $values, $default = '', $parameters = '', $class = '', $autosize = true) {
365 365
 		//if $values was submitted in the wrong format, convert it over
366
-		if(!empty($values) && (!array_key_exists(0,$values) || !is_array($values[0]))){
367
-			$converted_values=array();
368
-			foreach($values as $id=>$text){
369
-				$converted_values[]=array('id'=>$id,'text'=>$text);
366
+		if ( ! empty($values) && ( ! array_key_exists(0, $values) || ! is_array($values[0]))) {
367
+			$converted_values = array();
368
+			foreach ($values as $id=>$text) {
369
+				$converted_values[] = array('id'=>$id, 'text'=>$text);
370 370
 			}
371
-			$values=$converted_values;
371
+			$values = $converted_values;
372 372
 		}
373 373
 
374
-		$field = '<select id="' . EEH_Formatter::ee_tep_output_string($name) . '" name="' . EEH_Formatter::ee_tep_output_string($name) . '"';
374
+		$field = '<select id="'.EEH_Formatter::ee_tep_output_string($name).'" name="'.EEH_Formatter::ee_tep_output_string($name).'"';
375 375
 		//Debug
376 376
 		//EEH_Debug_Tools::printr( $values, '$values  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
377
-		if ( EEH_Formatter::ee_tep_not_null($parameters))
378
-			$field .= ' ' . $parameters;
377
+		if (EEH_Formatter::ee_tep_not_null($parameters))
378
+			$field .= ' '.$parameters;
379 379
 		if ($autosize) {
380 380
 			$size = 'med';
381 381
 			for ($ii = 0, $ni = sizeof($values); $ii < $ni; $ii++) {
@@ -388,21 +388,21 @@  discard block
 block discarded – undo
388 388
 			$size = '';
389 389
 		}
390 390
 
391
-		$field .= ' class="' . $class . ' ' . $size . '">';
391
+		$field .= ' class="'.$class.' '.$size.'">';
392 392
 
393 393
 		if (empty($default) && isset($GLOBALS[$name]))
394 394
 			$default = stripslashes($GLOBALS[$name]);
395 395
 
396 396
 
397 397
 		for ($i = 0, $n = sizeof($values); $i < $n; $i++) {
398
-			$field .= '<option value="' . $values[$i]['id'] . '"';
398
+			$field .= '<option value="'.$values[$i]['id'].'"';
399 399
 			if ($default == $values[$i]['id']) {
400 400
 				$field .= ' selected = "selected"';
401 401
 			}
402
-			if ( isset( $values[$i]['class'] ) ) {
403
-				$field .= ' class="' . $values[$i]['class'] . '"';
402
+			if (isset($values[$i]['class'])) {
403
+				$field .= ' class="'.$values[$i]['class'].'"';
404 404
 			}
405
-			$field .= '>' . $values[$i]['text'] . '</option>';
405
+			$field .= '>'.$values[$i]['text'].'</option>';
406 406
 		}
407 407
 		$field .= '</select>';
408 408
 
@@ -420,38 +420,38 @@  discard block
 block discarded – undo
420 420
 	 * @param string $question_groups
421 421
 	 * @return string HTML
422 422
 	 */
423
-	static function generate_question_groups_html( $question_groups = array(), $group_wrapper = 'fieldset' ) {
423
+	static function generate_question_groups_html($question_groups = array(), $group_wrapper = 'fieldset') {
424 424
 
425 425
 		$html = '';
426
-		$before_question_group_questions = apply_filters( 'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '' );
427
-		$after_question_group_questions = apply_filters( 'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '' );
426
+		$before_question_group_questions = apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
427
+		$after_question_group_questions = apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
428 428
 
429
-		if ( ! empty( $question_groups )) {
429
+		if ( ! empty($question_groups)) {
430 430
 			//EEH_Debug_Tools::printr( $question_groups, '$question_groups  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
431 431
 			// loop thru question groups
432
-			foreach ( $question_groups as $QSG ) {
432
+			foreach ($question_groups as $QSG) {
433 433
 				// check that questions exist
434
-				if ( ! empty( $QSG['QSG_questions'] )) {
434
+				if ( ! empty($QSG['QSG_questions'])) {
435 435
 					// use fieldsets
436
-					$html .= "\n\t" . '<' . $group_wrapper . ' class="espresso-question-group-wrap" id="' . $QSG['QSG_identifier'] . '">';
436
+					$html .= "\n\t".'<'.$group_wrapper.' class="espresso-question-group-wrap" id="'.$QSG['QSG_identifier'].'">';
437 437
 					// group_name
438
-					$html .= $QSG['QSG_show_group_name'] ? "\n\t\t" . '<h5 class="espresso-question-group-title-h5 section-title">' . self::prep_answer( $QSG['QSG_name'] ) . '</h5>' : '';
438
+					$html .= $QSG['QSG_show_group_name'] ? "\n\t\t".'<h5 class="espresso-question-group-title-h5 section-title">'.self::prep_answer($QSG['QSG_name']).'</h5>' : '';
439 439
 					// group_desc
440
-					$html .= $QSG['QSG_show_group_desc'] && ! empty( $QSG['QSG_desc'] ) ? '<div class="espresso-question-group-desc-pg">' . self::prep_answer( $QSG['QSG_desc'] ) . '</div>' : '';
440
+					$html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc']) ? '<div class="espresso-question-group-desc-pg">'.self::prep_answer($QSG['QSG_desc']).'</div>' : '';
441 441
 
442 442
 					$html .= $before_question_group_questions;
443 443
 					// loop thru questions
444
-					foreach ( $QSG['QSG_questions'] as $question ) {
444
+					foreach ($QSG['QSG_questions'] as $question) {
445 445
 //						EEH_Debug_Tools::printr( $question, '$question  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
446 446
 						$QFI = new EE_Question_Form_Input(
447 447
 							$question['qst_obj'],
448 448
 							$question['ans_obj'],
449 449
 							$question
450 450
 						);
451
-						$html .= self::generate_form_input( $QFI );
451
+						$html .= self::generate_form_input($QFI);
452 452
 					}
453 453
 					$html .= $after_question_group_questions;
454
-					$html .= "\n\t" . '</' . $group_wrapper . '>';
454
+					$html .= "\n\t".'</'.$group_wrapper.'>';
455 455
 				}
456 456
 			}
457 457
 		}
@@ -471,11 +471,11 @@  discard block
 block discarded – undo
471 471
 	 * @param string       $group_wrapper
472 472
 	 * @return string HTML
473 473
 	 */
474
-	static function generate_question_groups_html2( $question_groups = array(), $q_meta = array(), 	$from_admin = FALSE, $group_wrapper = 'fieldset' ) {
474
+	static function generate_question_groups_html2($question_groups = array(), $q_meta = array(), $from_admin = FALSE, $group_wrapper = 'fieldset') {
475 475
 
476 476
 		$html = '';
477
-		$before_question_group_questions = apply_filters( 'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '' );
478
-		$after_question_group_questions = apply_filters( 'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '' );
477
+		$before_question_group_questions = apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
478
+		$after_question_group_questions = apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
479 479
 
480 480
 		$default_q_meta = array(
481 481
 				'att_nmbr' => 1,
@@ -484,55 +484,55 @@  discard block
 block discarded – undo
484 484
 				'input_id' => '',
485 485
 				'input_class' => ''
486 486
 		);
487
-		$q_meta = array_merge( $default_q_meta, $q_meta );
487
+		$q_meta = array_merge($default_q_meta, $q_meta);
488 488
 		//EEH_Debug_Tools::printr( $q_meta, '$q_meta  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
489 489
 
490
-		if ( ! empty( $question_groups )) {
490
+		if ( ! empty($question_groups)) {
491 491
 //			EEH_Debug_Tools::printr( $question_groups, '$question_groups  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
492 492
 			// loop thru question groups
493
-			foreach ( $question_groups as $QSG ) {
494
-				if ( $QSG instanceof EE_Question_Group ) {
493
+			foreach ($question_groups as $QSG) {
494
+				if ($QSG instanceof EE_Question_Group) {
495 495
 					// check that questions exist
496 496
 
497
-					$where = array( 'QST_deleted' => 0 );
498
-					if ( ! $from_admin ) {
497
+					$where = array('QST_deleted' => 0);
498
+					if ( ! $from_admin) {
499 499
 						$where['QST_admin_only'] = 0;
500 500
 					}
501
-					$questions = $QSG->questions( array( $where, 'order_by' => array( 'Question_Group_Question.QGQ_order' => 'ASC' )));
502
-					if ( ! empty( $questions )) {
501
+					$questions = $QSG->questions(array($where, 'order_by' => array('Question_Group_Question.QGQ_order' => 'ASC')));
502
+					if ( ! empty($questions)) {
503 503
 						// use fieldsets
504
-						$html .= "\n\t" . '<' . $group_wrapper . ' class="espresso-question-group-wrap" id="' . $QSG->get( 'QSG_identifier' ) . '">';
504
+						$html .= "\n\t".'<'.$group_wrapper.' class="espresso-question-group-wrap" id="'.$QSG->get('QSG_identifier').'">';
505 505
 						// group_name
506
-						if ( $QSG->show_group_name() ) {
507
-							$html .=  "\n\t\t" . '<h5 class="espresso-question-group-title-h5 section-title">' . $QSG->get_pretty( 'QSG_name' ) . '</h5>';
506
+						if ($QSG->show_group_name()) {
507
+							$html .= "\n\t\t".'<h5 class="espresso-question-group-title-h5 section-title">'.$QSG->get_pretty('QSG_name').'</h5>';
508 508
 						}
509 509
 						// group_desc
510
-						if ( $QSG->show_group_desc() ) {
511
-							$html .=  '<div class="espresso-question-group-desc-pg">' . $QSG->get_pretty( 'QSG_desc'  ) . '</div>';
510
+						if ($QSG->show_group_desc()) {
511
+							$html .= '<div class="espresso-question-group-desc-pg">'.$QSG->get_pretty('QSG_desc').'</div>';
512 512
 						}
513 513
 
514 514
 						$html .= $before_question_group_questions;
515 515
 						// loop thru questions
516
-						foreach ( $questions as $QST ) {
516
+						foreach ($questions as $QST) {
517 517
 							$qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
518 518
 
519 519
 							$answer = NULL;
520 520
 
521
-							if (  isset( $_GET['qstn'] ) && isset( $q_meta['input_id'] ) && isset( $q_meta['att_nmbr'] )) {
521
+							if (isset($_GET['qstn']) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
522 522
 								// check for answer in $_GET in case we are reprocessing a form after an error
523
-								if ( isset( $_GET['qstn'][ $q_meta['input_id'] ][ $qstn_id ] )) {
524
-									$answer = is_array( $_GET['qstn'][ $q_meta['input_id'] ][ $qstn_id ] ) ? $_GET['qstn'][ $q_meta['input_id'] ][ $qstn_id ] : sanitize_text_field( $_GET['qstn'][ $q_meta['input_id'] ][ $qstn_id ] );
523
+								if (isset($_GET['qstn'][$q_meta['input_id']][$qstn_id])) {
524
+									$answer = is_array($_GET['qstn'][$q_meta['input_id']][$qstn_id]) ? $_GET['qstn'][$q_meta['input_id']][$qstn_id] : sanitize_text_field($_GET['qstn'][$q_meta['input_id']][$qstn_id]);
525 525
 								}
526
-							} else if ( isset( $q_meta['attendee'] ) && $q_meta['attendee'] ) {
526
+							} else if (isset($q_meta['attendee']) && $q_meta['attendee']) {
527 527
 								//attendee data from the session
528
-								$answer = isset( $q_meta['attendee'][ $qstn_id ] ) ? $q_meta['attendee'][ $qstn_id ] : NULL;
528
+								$answer = isset($q_meta['attendee'][$qstn_id]) ? $q_meta['attendee'][$qstn_id] : NULL;
529 529
 							}
530 530
 
531 531
 
532 532
 
533 533
 							$QFI = new EE_Question_Form_Input(
534 534
 									$QST,
535
-									EE_Answer::new_instance ( array(
535
+									EE_Answer::new_instance(array(
536 536
 											'ANS_ID'=> 0,
537 537
 											'QST_ID'=> 0,
538 538
 											'REG_ID'=> 0,
@@ -541,10 +541,10 @@  discard block
 block discarded – undo
541 541
 									$q_meta
542 542
 							);
543 543
 							//EEH_Debug_Tools::printr( $QFI, '$QFI  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
544
-							$html .= self::generate_form_input( $QFI );
544
+							$html .= self::generate_form_input($QFI);
545 545
 						}
546 546
 						$html .= $after_question_group_questions;
547
-						$html .= "\n\t" . '</' . $group_wrapper . '>';
547
+						$html .= "\n\t".'</'.$group_wrapper.'>';
548 548
 					}
549 549
 				}
550 550
 			}
@@ -564,63 +564,63 @@  discard block
 block discarded – undo
564 564
 	 * @param EE_Question_Form_Input $QFI
565 565
 	 * @return string HTML
566 566
 	 */
567
-	static function generate_form_input( EE_Question_Form_Input $QFI ) {
568
-		if ( isset( $QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin() ) {
567
+	static function generate_form_input(EE_Question_Form_Input $QFI) {
568
+		if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
569 569
 			return '';
570 570
 		}
571 571
 
572
-		$QFI = self::_load_system_dropdowns( $QFI );
573
-		$QFI = self::_load_specialized_dropdowns( $QFI );
572
+		$QFI = self::_load_system_dropdowns($QFI);
573
+		$QFI = self::_load_specialized_dropdowns($QFI);
574 574
 
575 575
 		//we also need to verify
576 576
 
577 577
 		$display_text = $QFI->get('QST_display_text');
578 578
 		$input_name = $QFI->get('QST_input_name');
579
-		$answer = EE_Registry::instance()->REQ->is_set( $input_name ) ? EE_Registry::instance()->REQ->get( $input_name ) : $QFI->get('ANS_value');
579
+		$answer = EE_Registry::instance()->REQ->is_set($input_name) ? EE_Registry::instance()->REQ->get($input_name) : $QFI->get('ANS_value');
580 580
 		$input_id = $QFI->get('QST_input_id');
581 581
 		$input_class = $QFI->get('QST_input_class');
582 582
 //		$disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
583 583
 		$disabled = $QFI->get('QST_disabled') ? TRUE : FALSE;
584
-		$required_label = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>' );
584
+		$required_label = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
585 585
 		$QST_required = $QFI->get('QST_required');
586
-		$required = $QST_required ? array( 'label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required ) : array();
587
-		$use_html_entities = $QFI->get_meta( 'htmlentities' );
588
-		$required_text = $QFI->get('QST_required_text') != '' ? $QFI->get('QST_required_text') : __( 'This field is required', 'event_espresso' );
589
-		$required_text = $QST_required ? "\n\t\t\t" . '<div class="required-text hidden">' . self::prep_answer( $required_text, $use_html_entities ) . '</div>' : '';
586
+		$required = $QST_required ? array('label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required) : array();
587
+		$use_html_entities = $QFI->get_meta('htmlentities');
588
+		$required_text = $QFI->get('QST_required_text') != '' ? $QFI->get('QST_required_text') : __('This field is required', 'event_espresso');
589
+		$required_text = $QST_required ? "\n\t\t\t".'<div class="required-text hidden">'.self::prep_answer($required_text, $use_html_entities).'</div>' : '';
590 590
 		$label_class = 'espresso-form-input-lbl';
591
-		$QST_options = $QFI->options(true,$answer);
592
-		$options = is_array( $QST_options ) ? self::prep_answer_options( $QST_options ) : array();
591
+		$QST_options = $QFI->options(true, $answer);
592
+		$options = is_array($QST_options) ? self::prep_answer_options($QST_options) : array();
593 593
 		$system_ID = $QFI->get('QST_system');
594
-		$label_b4 = $QFI->get_meta( 'label_b4' );
595
-		$use_desc_4_label = $QFI->get_meta( 'use_desc_4_label' );
594
+		$label_b4 = $QFI->get_meta('label_b4');
595
+		$use_desc_4_label = $QFI->get_meta('use_desc_4_label');
596 596
 
597 597
 
598
-		switch ( $QFI->get('QST_type') ){
598
+		switch ($QFI->get('QST_type')) {
599 599
 
600 600
 			case 'TEXTAREA' :
601
-					return EEH_Form_Fields::textarea( $display_text, $answer, $input_name, $input_id, $input_class, array(), $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities );
601
+					return EEH_Form_Fields::textarea($display_text, $answer, $input_name, $input_id, $input_class, array(), $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities);
602 602
 				break;
603 603
 
604 604
 			case 'DROPDOWN' :
605
-					return EEH_Form_Fields::select( $display_text, $answer, $options, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities, TRUE );
605
+					return EEH_Form_Fields::select($display_text, $answer, $options, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities, TRUE);
606 606
 				break;
607 607
 
608 608
 
609 609
 			case 'RADIO_BTN' :
610
-					return EEH_Form_Fields::radio( $display_text, $answer, $options, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities, $label_b4, $use_desc_4_label );
610
+					return EEH_Form_Fields::radio($display_text, $answer, $options, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities, $label_b4, $use_desc_4_label);
611 611
 				break;
612 612
 
613 613
 			case 'CHECKBOX' :
614
-					return EEH_Form_Fields::checkbox( $display_text, $answer, $options, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $label_b4, $system_ID, $use_html_entities );
614
+					return EEH_Form_Fields::checkbox($display_text, $answer, $options, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $label_b4, $system_ID, $use_html_entities);
615 615
 				break;
616 616
 
617 617
 			case 'DATE' :
618
-					return EEH_Form_Fields::datepicker( $display_text, $answer, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities );
618
+					return EEH_Form_Fields::datepicker($display_text, $answer, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities);
619 619
 				break;
620 620
 
621 621
 			case 'TEXT' :
622 622
 			default:
623
-					return EEH_Form_Fields::text( $display_text, $answer, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities );
623
+					return EEH_Form_Fields::text($display_text, $answer, $input_name, $input_id, $input_class, $required, $required_text, $label_class, $disabled, $system_ID, $use_html_entities);
624 624
 				break;
625 625
 
626 626
 		}
@@ -646,31 +646,31 @@  discard block
 block discarded – undo
646 646
 	 * @param string $disabled 		disabled="disabled" or null
647 647
 	 * @return string HTML
648 648
 	 */
649
-	static function text( $question = FALSE, $answer = NULL, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE ) {
649
+	static function text($question = FALSE, $answer = NULL, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE) {
650 650
 		// need these
651
-		if ( ! $question || ! $name ) {
651
+		if ( ! $question || ! $name) {
652 652
 			return NULL;
653 653
 		}
654 654
 		// prep the answer
655
-		$answer = is_array( $answer ) ? '' : self::prep_answer( $answer, $use_html_entities );
655
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
656 656
 		// prep the required array
657
-		$required = self::prep_required( $required );
657
+		$required = self::prep_required($required);
658 658
 		// set disabled tag
659
-		$disabled = $answer === NULL || ! $disabled  ? '' : ' disabled="disabled"';
659
+		$disabled = $answer === NULL || ! $disabled ? '' : ' disabled="disabled"';
660 660
 		// ya gots ta have style man!!!
661 661
 		$txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
662
-		$class = empty( $class ) ? $txt_class : $class;
663
-		$class .= ! empty( $system_ID ) ? ' ' . $system_ID : '';
664
-		$extra = apply_filters( 'FHEE__EEH_Form_Fields__additional_form_field_attributes', '' );
662
+		$class = empty($class) ? $txt_class : $class;
663
+		$class .= ! empty($system_ID) ? ' '.$system_ID : '';
664
+		$extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
665 665
 
666
-		$label_html = $required_text . "\n\t\t\t" . '<label for="' . $name . '" class="' . $label_class . '">' . self::prep_question( $question ) . $required['label'] . '</label><br/>';
666
+		$label_html = $required_text."\n\t\t\t".'<label for="'.$name.'" class="'.$label_class.'">'.self::prep_question($question).$required['label'].'</label><br/>';
667 667
 		// filter label but ensure required text comes before it
668
-		$label_html = apply_filters( 'FHEE__EEH_Form_Fields__label_html', $label_html, $required_text );
668
+		$label_html = apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text);
669 669
 
670
-		$input_html = "\n\t\t\t" . '<input type="text" name="' . $name . '" id="' . $id . '" class="' . $class . ' ' . $required['class'] . '" value="' . esc_attr( $answer ) . '"  title="' . esc_attr( $required['msg'] ) . '" ' . $disabled .' ' . $extra . '/>';
670
+		$input_html = "\n\t\t\t".'<input type="text" name="'.$name.'" id="'.$id.'" class="'.$class.' '.$required['class'].'" value="'.esc_attr($answer).'"  title="'.esc_attr($required['msg']).'" '.$disabled.' '.$extra.'/>';
671 671
 
672
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id );
673
-		return  $label_html . $input_html;
672
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
673
+		return  $label_html.$input_html;
674 674
 
675 675
 	}
676 676
 
@@ -692,35 +692,35 @@  discard block
 block discarded – undo
692 692
 	 * @param string $disabled 		disabled="disabled" or null
693 693
 	 * @return string HTML
694 694
 	 */
695
-	static function textarea( $question = FALSE, $answer = NULL, $name = FALSE, $id = '', $class = '', $dimensions = FALSE, $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE ) {
695
+	static function textarea($question = FALSE, $answer = NULL, $name = FALSE, $id = '', $class = '', $dimensions = FALSE, $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE) {
696 696
 		// need these
697
-		if ( ! $question || ! $name ) {
697
+		if ( ! $question || ! $name) {
698 698
 			return NULL;
699 699
 		}
700 700
 		// prep the answer
701
-		$answer = is_array( $answer ) ? '' : self::prep_answer( $answer, $use_html_entities );
701
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
702 702
 		// prep the required array
703
-		$required = self::prep_required( $required );
703
+		$required = self::prep_required($required);
704 704
 		// make sure $dimensions is an array
705
-		$dimensions = is_array( $dimensions ) ? $dimensions : array();
705
+		$dimensions = is_array($dimensions) ? $dimensions : array();
706 706
 		// and set some defaults
707
-		$dimensions = array_merge( array( 'rows' => 3, 'cols' => 40 ), $dimensions );
707
+		$dimensions = array_merge(array('rows' => 3, 'cols' => 40), $dimensions);
708 708
 		// set disabled tag
709
-		$disabled = $answer === NULL || ! $disabled  ? '' : ' disabled="disabled"';
709
+		$disabled = $answer === NULL || ! $disabled ? '' : ' disabled="disabled"';
710 710
 		// ya gots ta have style man!!!
711 711
 		$txt_class = is_admin() ? 'regular-text' : 'espresso-textarea-inp';
712
-		$class = empty( $class ) ? $txt_class : $class;
713
-		$class .= ! empty( $system_ID ) ? ' ' . $system_ID : '';
714
-		$extra = apply_filters( 'FHEE__EEH_Form_Fields__additional_form_field_attributes', '' );
712
+		$class = empty($class) ? $txt_class : $class;
713
+		$class .= ! empty($system_ID) ? ' '.$system_ID : '';
714
+		$extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
715 715
 
716
-		$label_html = $required_text . "\n\t\t\t" . '<label for="' . $name . '" class="' . $label_class . '">' . self::prep_question( $question ) . $required['label'] . '</label><br/>';
716
+		$label_html = $required_text."\n\t\t\t".'<label for="'.$name.'" class="'.$label_class.'">'.self::prep_question($question).$required['label'].'</label><br/>';
717 717
 		// filter label but ensure required text comes before it
718
-		$label_html = apply_filters( 'FHEE__EEH_Form_Fields__label_html', $label_html, $required_text );
718
+		$label_html = apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text);
719 719
 
720
-		$input_html = "\n\t\t\t" . '<textarea name="' . $name . '" id="' . $id . '" class="' . $class . ' ' . $required['class'] . '" rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  title="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>' . $answer . '</textarea>';
720
+		$input_html = "\n\t\t\t".'<textarea name="'.$name.'" id="'.$id.'" class="'.$class.' '.$required['class'].'" rows="'.$dimensions['rows'].'" cols="'.$dimensions['cols'].'"  title="'.$required['msg'].'" '.$disabled.' '.$extra.'>'.$answer.'</textarea>';
721 721
 
722
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id );
723
-		return  $label_html . $input_html;
722
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
723
+		return  $label_html.$input_html;
724 724
 
725 725
 	}
726 726
 
@@ -743,47 +743,47 @@  discard block
 block discarded – undo
743 743
 	 * @param string $disabled 		disabled="disabled" or null
744 744
 	 * @return string HTML
745 745
 	 */
746
-	static function select( $question = FALSE, $answer = NULL, $options = FALSE, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE, $add_please_select_option = FALSE ) {
746
+	static function select($question = FALSE, $answer = NULL, $options = FALSE, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE, $add_please_select_option = FALSE) {
747 747
 
748 748
 		// need these
749
-		if ( ! $question || ! $name || ! $options || empty( $options ) || ! is_array( $options )) {
749
+		if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
750 750
 			return NULL;
751 751
 		}
752 752
 		// prep the answer
753
-		$answer = is_array( $answer ) ? self::prep_answer( array_shift( $answer ), $use_html_entities) : self::prep_answer( $answer, $use_html_entities );
753
+		$answer = is_array($answer) ? self::prep_answer(array_shift($answer), $use_html_entities) : self::prep_answer($answer, $use_html_entities);
754 754
 		// prep the required array
755
-		$required = self::prep_required( $required );
755
+		$required = self::prep_required($required);
756 756
 		// set disabled tag
757
-		$disabled = $answer === NULL || ! $disabled  ? '' : ' disabled="disabled"';
757
+		$disabled = $answer === NULL || ! $disabled ? '' : ' disabled="disabled"';
758 758
 		// ya gots ta have style man!!!
759 759
 		$txt_class = is_admin() ? 'wide' : 'espresso-select-inp';
760
-		$class = empty( $class ) ? $txt_class : $class;
761
-		$class .= ! empty( $system_ID ) ? ' ' . $system_ID : '';
762
-		$extra = apply_filters( 'FHEE__EEH_Form_Fields__additional_form_field_attributes', '' );
760
+		$class = empty($class) ? $txt_class : $class;
761
+		$class .= ! empty($system_ID) ? ' '.$system_ID : '';
762
+		$extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
763 763
 
764
-		$label_html = $required_text . "\n\t\t\t" . '<label for="' . $name . '" class="' . $label_class . '">' . self::prep_question( $question ) . $required['label'] . '</label><br/>';
764
+		$label_html = $required_text."\n\t\t\t".'<label for="'.$name.'" class="'.$label_class.'">'.self::prep_question($question).$required['label'].'</label><br/>';
765 765
 		// filter label but ensure required text comes before it
766
-		$label_html = apply_filters( 'FHEE__EEH_Form_Fields__label_html', $label_html, $required_text );
766
+		$label_html = apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text);
767 767
 
768
-		$input_html = "\n\t\t\t" . '<select name="' . $name . '" id="' . $id . '" class="' . $class . ' ' . $required['class'] . '" title="' . esc_attr( $required['msg'] ) . '"' . $disabled . ' ' . $extra . '>';
768
+		$input_html = "\n\t\t\t".'<select name="'.$name.'" id="'.$id.'" class="'.$class.' '.$required['class'].'" title="'.esc_attr($required['msg']).'"'.$disabled.' '.$extra.'>';
769 769
 		// recursively count array elements, to determine total number of options
770
-		$only_option = count( $options, 1 ) == 1 ? TRUE : FALSE;
771
-		if ( ! $only_option ) {
770
+		$only_option = count($options, 1) == 1 ? TRUE : FALSE;
771
+		if ( ! $only_option) {
772 772
 			// if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
773 773
 			$selected = $answer === NULL ? ' selected="selected"' : '';
774
-			$input_html .= $add_please_select_option ? "\n\t\t\t\t" . '<option value=""' . $selected . '>' . __(' - please select - ', 'event_espresso') . '</option>' : '';
774
+			$input_html .= $add_please_select_option ? "\n\t\t\t\t".'<option value=""'.$selected.'>'.__(' - please select - ', 'event_espresso').'</option>' : '';
775 775
 		}
776
-		foreach ( $options as $key => $value ) {
776
+		foreach ($options as $key => $value) {
777 777
 			// if value is an array, then create option groups, else create regular ol' options
778
-			$input_html .= is_array( $value ) ? self::_generate_select_option_group( $key, $value, $answer, $use_html_entities ) : self::_generate_select_option( $value->value(), $value->desc(), $answer, $only_option, $use_html_entities );
778
+			$input_html .= is_array($value) ? self::_generate_select_option_group($key, $value, $answer, $use_html_entities) : self::_generate_select_option($value->value(), $value->desc(), $answer, $only_option, $use_html_entities);
779 779
 		}
780 780
 
781
-		$input_html .= "\n\t\t\t" . '</select>';
781
+		$input_html .= "\n\t\t\t".'</select>';
782 782
 
783
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__select__before_end_wrapper', $input_html, $question, $answer, $name, $id, $class, $system_ID );
783
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__select__before_end_wrapper', $input_html, $question, $answer, $name, $id, $class, $system_ID);
784 784
 
785
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id );
786
-		return  $label_html . $input_html;
785
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
786
+		return  $label_html.$input_html;
787 787
 
788 788
 	}
789 789
 
@@ -801,12 +801,12 @@  discard block
 block discarded – undo
801 801
 	 * @param boolean $use_html_entities
802 802
 	 * @return string
803 803
 	 */
804
-	private static function _generate_select_option_group( $opt_group, $QSOs, $answer, $use_html_entities = true ){
805
-		$html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value( $opt_group ) . '">';
806
-		foreach ( $QSOs as $QSO ) {
807
-			$html .= self::_generate_select_option( $QSO->value(), $QSO->desc(), $answer, false, $use_html_entities );
804
+	private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true) {
805
+		$html = "\n\t\t\t\t".'<optgroup label="'.self::prep_option_value($opt_group).'">';
806
+		foreach ($QSOs as $QSO) {
807
+			$html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
808 808
 		}
809
-		$html .= "\n\t\t\t\t" . '</optgroup>';
809
+		$html .= "\n\t\t\t\t".'</optgroup>';
810 810
 		return $html;
811 811
 	}
812 812
 
@@ -821,12 +821,12 @@  discard block
 block discarded – undo
821 821
 	 * @param boolean $use_html_entities
822 822
 	 * @return string
823 823
 	 */
824
-	private static function _generate_select_option( $key, $value, $answer, $only_option = FALSE, $use_html_entities = true ){
825
-		$key = self::prep_answer( $key, $use_html_entities );
826
-		$value = self::prep_answer( $value, $use_html_entities );
827
-		$value = ! empty( $value ) ? $value : $key;
828
-		$selected = ( $answer == $key || $only_option ) ? ' selected="selected"' : '';
829
-		return "\n\t\t\t\t" . '<option value="' . self::prep_option_value( $key ) . '"' . $selected . '> ' . $value . '&nbsp;&nbsp;&nbsp;</option>';
824
+	private static function _generate_select_option($key, $value, $answer, $only_option = FALSE, $use_html_entities = true) {
825
+		$key = self::prep_answer($key, $use_html_entities);
826
+		$value = self::prep_answer($value, $use_html_entities);
827
+		$value = ! empty($value) ? $value : $key;
828
+		$selected = ($answer == $key || $only_option) ? ' selected="selected"' : '';
829
+		return "\n\t\t\t\t".'<option value="'.self::prep_option_value($key).'"'.$selected.'> '.$value.'&nbsp;&nbsp;&nbsp;</option>';
830 830
 	}
831 831
 
832 832
 
@@ -850,56 +850,56 @@  discard block
 block discarded – undo
850 850
 	 * @param bool        $use_desc_4_label
851 851
 	 * @return string HTML
852 852
 	 */
853
-	static function radio( $question = FALSE, $answer = NULL, $options = FALSE, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE, $label_b4 = FALSE, $use_desc_4_label = FALSE ) {
853
+	static function radio($question = FALSE, $answer = NULL, $options = FALSE, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE, $label_b4 = FALSE, $use_desc_4_label = FALSE) {
854 854
 		// need these
855
-		if ( ! $question || ! $name || ! $options || empty( $options ) || ! is_array( $options )) {
855
+		if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
856 856
 			return NULL;
857 857
 		}
858 858
 		// prep the answer
859
-		$answer = is_array( $answer ) ? '' : self::prep_answer( $answer, $use_html_entities );
859
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
860 860
 		// prep the required array
861
-		$required = self::prep_required( $required );
861
+		$required = self::prep_required($required);
862 862
 		// set disabled tag
863
-		$disabled = $answer === NULL || ! $disabled  ? '' : ' disabled="disabled"';
863
+		$disabled = $answer === NULL || ! $disabled ? '' : ' disabled="disabled"';
864 864
 		// ya gots ta have style man!!!
865 865
 		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
866
-		$class = ! empty( $class ) ? $class : 'espresso-radio-btn-inp';
867
-		$extra = apply_filters( 'FHEE__EEH_Form_Fields__additional_form_field_attributes', '' );
866
+		$class = ! empty($class) ? $class : 'espresso-radio-btn-inp';
867
+		$extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
868 868
 
869
-		$label_html = $required_text . "\n\t\t\t" . '<label class="' . $label_class . '">' . self::prep_question( $question ) . $required['label'] . '</label> ';
869
+		$label_html = $required_text."\n\t\t\t".'<label class="'.$label_class.'">'.self::prep_question($question).$required['label'].'</label> ';
870 870
 		// filter label but ensure required text comes before it
871
-		$label_html = apply_filters( 'FHEE__EEH_Form_Fields__label_html', $label_html, $required_text );
871
+		$label_html = apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text);
872 872
 
873
-		$input_html = "\n\t\t\t" . '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $label_class . ' ' . $class . '-ul">';
873
+		$input_html = "\n\t\t\t".'<ul id="'.$id.'-ul" class="espresso-radio-btn-options-ul '.$label_class.' '.$class.'-ul">';
874 874
 
875
-		$class .= ! empty( $system_ID ) ? ' ' . $system_ID : '';
876
-		$class .= ! empty( $required['class'] ) ? ' ' . $required['class'] : '';
875
+		$class .= ! empty($system_ID) ? ' '.$system_ID : '';
876
+		$class .= ! empty($required['class']) ? ' '.$required['class'] : '';
877 877
 
878
-		foreach ( $options as $OPT ) {
879
-			if ( $OPT instanceof EE_Question_Option ) {
880
-				$value = self::prep_option_value( $OPT->value() );
878
+		foreach ($options as $OPT) {
879
+			if ($OPT instanceof EE_Question_Option) {
880
+				$value = self::prep_option_value($OPT->value());
881 881
 				$label = $use_desc_4_label ? $OPT->desc() : $OPT->value();
882
-				$size = $use_desc_4_label ? self::get_label_size_class( $OPT->value() . ' ' . $OPT->desc() ) : self::get_label_size_class( $OPT->value() );
883
-				$desc = $OPT->desc();//no self::prep_answer
884
-				$answer = is_numeric( $value ) && empty( $answer ) ? 0 : $answer;
885
-				$checked = (string)$value == (string)$answer ? ' checked="checked"' : '';
886
-				$opt = '-' . sanitize_key( $value );
887
-
888
-				$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
889
-				$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
890
-				$input_html .= $label_b4  ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>' : '';
891
-				$input_html .= "\n\t\t\t\t\t\t" . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" title="' . esc_attr( $required['msg'] ) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
892
-				$input_html .= ! $label_b4  ? "\n\t\t\t\t\t\t" . '<span class="espresso-radio-btn-desc">' . $label . '</span>' : '';
893
-				$input_html .= "\n\t\t\t\t\t" . '</label>';
894
-				$input_html .= $use_desc_4_label ? '' : '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
895
-				$input_html .= "\n\t\t\t\t" . '</li>';
882
+				$size = $use_desc_4_label ? self::get_label_size_class($OPT->value().' '.$OPT->desc()) : self::get_label_size_class($OPT->value());
883
+				$desc = $OPT->desc(); //no self::prep_answer
884
+				$answer = is_numeric($value) && empty($answer) ? 0 : $answer;
885
+				$checked = (string) $value == (string) $answer ? ' checked="checked"' : '';
886
+				$opt = '-'.sanitize_key($value);
887
+
888
+				$input_html .= "\n\t\t\t\t".'<li'.$size.'>';
889
+				$input_html .= "\n\t\t\t\t\t".'<label class="'.$radio_class.' espresso-radio-btn-lbl">';
890
+				$input_html .= $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$label.'</span>' : '';
891
+				$input_html .= "\n\t\t\t\t\t\t".'<input type="radio" name="'.$name.'" id="'.$id.$opt.'" class="'.$class.'" value="'.$value.'" title="'.esc_attr($required['msg']).'" '.$disabled.$checked.' '.$extra.'/>';
892
+				$input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t".'<span class="espresso-radio-btn-desc">'.$label.'</span>' : '';
893
+				$input_html .= "\n\t\t\t\t\t".'</label>';
894
+				$input_html .= $use_desc_4_label ? '' : '<span class="espresso-radio-btn-option-desc small-text grey-text">'.$desc.'</span>';
895
+				$input_html .= "\n\t\t\t\t".'</li>';
896 896
 			}
897 897
 		}
898 898
 
899
-		$input_html .= "\n\t\t\t" . '</ul>';
899
+		$input_html .= "\n\t\t\t".'</ul>';
900 900
 
901
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id );
902
-		return  $label_html . $input_html;
901
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
902
+		return  $label_html.$input_html;
903 903
 
904 904
 	}
905 905
 
@@ -922,65 +922,65 @@  discard block
 block discarded – undo
922 922
 	 * @param string $disabled 		disabled="disabled" or null
923 923
 	 * @return string HTML
924 924
 	 */
925
-	static function checkbox( $question = FALSE, $answer = NULL, $options = FALSE, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $label_b4 = FALSE, $system_ID = FALSE, $use_html_entities = TRUE ) {
925
+	static function checkbox($question = FALSE, $answer = NULL, $options = FALSE, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $label_b4 = FALSE, $system_ID = FALSE, $use_html_entities = TRUE) {
926 926
 		// need these
927
-		if ( ! $question || ! $name || ! $options || empty( $options ) || ! is_array( $options )) {
927
+		if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
928 928
 			return NULL;
929 929
 		}
930
-		$answer = maybe_unserialize( $answer );
930
+		$answer = maybe_unserialize($answer);
931 931
 
932 932
 		// prep the answer(s)
933
-		$answer = is_array( $answer ) ? $answer : array( sanitize_key( $answer ) => $answer );
933
+		$answer = is_array($answer) ? $answer : array(sanitize_key($answer) => $answer);
934 934
 
935
-		foreach ( $answer as $key => $value ) {
936
-			$key = self::prep_option_value( $key );
937
-			$answer[$key] = self::prep_answer( $value, $use_html_entities );
935
+		foreach ($answer as $key => $value) {
936
+			$key = self::prep_option_value($key);
937
+			$answer[$key] = self::prep_answer($value, $use_html_entities);
938 938
 		}
939 939
 
940 940
 		// prep the required array
941
-		$required = self::prep_required( $required );
941
+		$required = self::prep_required($required);
942 942
 		// set disabled tag
943
-		$disabled = $answer === NULL || ! $disabled  ? '' : ' disabled="disabled"';
943
+		$disabled = $answer === NULL || ! $disabled ? '' : ' disabled="disabled"';
944 944
 		// ya gots ta have style man!!!
945 945
 		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
946
-		$class = empty( $class ) ? 'espresso-radio-btn-inp' : $class;
947
-		$extra = apply_filters( 'FHEE__EEH_Form_Fields__additional_form_field_attributes', '' );
946
+		$class = empty($class) ? 'espresso-radio-btn-inp' : $class;
947
+		$extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
948 948
 
949
-		$label_html = $required_text . "\n\t\t\t" . '<label class="' . $label_class . '">' . self::prep_question( $question ) . $required['label'] . '</label> ';
949
+		$label_html = $required_text."\n\t\t\t".'<label class="'.$label_class.'">'.self::prep_question($question).$required['label'].'</label> ';
950 950
 		// filter label but ensure required text comes before it
951
-		$label_html = apply_filters( 'FHEE__EEH_Form_Fields__label_html', $label_html, $required_text );
952
-
953
-		$input_html = "\n\t\t\t" . '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $label_class . ' ' . $class . '-ul">';
954
-
955
-		$class .= ! empty( $system_ID ) ? ' ' . $system_ID : '';
956
-		$class .= ! empty( $required['class'] ) ? ' ' . $required['class'] : '';
957
-
958
-		foreach ( $options as $OPT ) {
959
-			$value = $OPT->value();//self::prep_option_value( $OPT->value() );
960
-			$size = self::get_label_size_class(  $OPT->value() . ' ' . $OPT->desc() );
961
-			$text = self::prep_answer( $OPT->value() );
962
-			$desc = $OPT->desc() ;
963
-			$opt = '-' . sanitize_key( $value );
964
-
965
-			$checked = is_array( $answer ) && in_array( $text, $answer ) ? ' checked="checked"' : '';
966
-
967
-			$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
968
-			$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
969
-			$input_html .= $label_b4  ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>' : '';
970
-			$input_html .= "\n\t\t\t\t\t\t" . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" title="' . esc_attr( $required['msg'] ) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
971
-			$input_html .= ! $label_b4  ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>' : '';
972
- 			$input_html .= "\n\t\t\t\t\t" . '</label>';
973
-			if ( ! empty( $desc ) && $desc != $text ) {
974
-	 			$input_html .= "\n\t\t\t\t\t" . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">' . $desc . '</div>';
951
+		$label_html = apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text);
952
+
953
+		$input_html = "\n\t\t\t".'<ul id="'.$id.'-ul" class="espresso-checkbox-options-ul '.$label_class.' '.$class.'-ul">';
954
+
955
+		$class .= ! empty($system_ID) ? ' '.$system_ID : '';
956
+		$class .= ! empty($required['class']) ? ' '.$required['class'] : '';
957
+
958
+		foreach ($options as $OPT) {
959
+			$value = $OPT->value(); //self::prep_option_value( $OPT->value() );
960
+			$size = self::get_label_size_class($OPT->value().' '.$OPT->desc());
961
+			$text = self::prep_answer($OPT->value());
962
+			$desc = $OPT->desc();
963
+			$opt = '-'.sanitize_key($value);
964
+
965
+			$checked = is_array($answer) && in_array($text, $answer) ? ' checked="checked"' : '';
966
+
967
+			$input_html .= "\n\t\t\t\t".'<li'.$size.'>';
968
+			$input_html .= "\n\t\t\t\t\t".'<label class="'.$radio_class.' espresso-checkbox-lbl">';
969
+			$input_html .= $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$text.'</span>' : '';
970
+			$input_html .= "\n\t\t\t\t\t\t".'<input type="checkbox" name="'.$name.'['.$OPT->ID().']" id="'.$id.$opt.'" class="'.$class.'" value="'.$value.'" title="'.esc_attr($required['msg']).'" '.$disabled.$checked.' '.$extra.'/>';
971
+			$input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$text.'</span>' : '';
972
+ 			$input_html .= "\n\t\t\t\t\t".'</label>';
973
+			if ( ! empty($desc) && $desc != $text) {
974
+	 			$input_html .= "\n\t\t\t\t\t".' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'.$desc.'</div>';
975 975
 			}
976
-			$input_html .= "\n\t\t\t\t" . '</li>';
976
+			$input_html .= "\n\t\t\t\t".'</li>';
977 977
 
978 978
 		}
979 979
 
980
-		$input_html .= "\n\t\t\t" . '</ul>';
980
+		$input_html .= "\n\t\t\t".'</ul>';
981 981
 
982
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id );
983
-		return  $label_html . $input_html;
982
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
983
+		return  $label_html.$input_html;
984 984
 
985 985
 	}
986 986
 
@@ -1002,36 +1002,36 @@  discard block
 block discarded – undo
1002 1002
 	 * @param string $disabled 		disabled="disabled" or null
1003 1003
 	 * @return string HTML
1004 1004
 	 */
1005
-	static function datepicker( $question = FALSE, $answer = NULL, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE ) {
1005
+	static function datepicker($question = FALSE, $answer = NULL, $name = FALSE, $id = '', $class = '', $required = FALSE, $required_text = '', $label_class = '', $disabled = FALSE, $system_ID = FALSE, $use_html_entities = TRUE) {
1006 1006
 		// need these
1007
-		if ( ! $question || ! $name ) {
1007
+		if ( ! $question || ! $name) {
1008 1008
 			return NULL;
1009 1009
 		}
1010 1010
 		// prep the answer
1011
-		$answer = is_array( $answer ) ? '' : self::prep_answer( $answer, $use_html_entities );
1011
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1012 1012
 		// prep the required array
1013
-		$required = self::prep_required( $required );
1013
+		$required = self::prep_required($required);
1014 1014
 		// set disabled tag
1015
-		$disabled = $answer === NULL || ! $disabled  ? '' : ' disabled="disabled"';
1015
+		$disabled = $answer === NULL || ! $disabled ? '' : ' disabled="disabled"';
1016 1016
 		// ya gots ta have style man!!!
1017 1017
 		$txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1018
-		$class = empty( $class ) ? $txt_class : $class;
1019
-		$class .= ! empty( $system_ID ) ? ' ' . $system_ID : '';
1020
-		$extra = apply_filters( 'FHEE__EEH_Form_Fields__additional_form_field_attributes', '' );
1018
+		$class = empty($class) ? $txt_class : $class;
1019
+		$class .= ! empty($system_ID) ? ' '.$system_ID : '';
1020
+		$extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1021 1021
 
1022
-		$label_html = $required_text . "\n\t\t\t" . '<label for="' . $name . '" class="' . $label_class . '">' . self::prep_question( $question ) . $required['label'] . '</label><br/>';
1022
+		$label_html = $required_text."\n\t\t\t".'<label for="'.$name.'" class="'.$label_class.'">'.self::prep_question($question).$required['label'].'</label><br/>';
1023 1023
 		// filter label but ensure required text comes before it
1024
-		$label_html = apply_filters( 'FHEE__EEH_Form_Fields__label_html', $label_html, $required_text );
1024
+		$label_html = apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text);
1025 1025
 
1026
-		$input_html = "\n\t\t\t" . '<input type="text" name="' . $name . '" id="' . $id . '" class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  title="' . esc_attr( $required['msg'] ) . '" ' . $disabled . ' ' . $extra . '/>';
1026
+		$input_html = "\n\t\t\t".'<input type="text" name="'.$name.'" id="'.$id.'" class="'.$class.' '.$required['class'].' datepicker" value="'.$answer.'"  title="'.esc_attr($required['msg']).'" '.$disabled.' '.$extra.'/>';
1027 1027
 
1028 1028
 		// enqueue scripts
1029
-		wp_register_style( 'espresso-ui-theme', EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css', array(), EVENT_ESPRESSO_VERSION );
1030
-		wp_enqueue_style( 'espresso-ui-theme');
1031
-		wp_enqueue_script( 'jquery-ui-datepicker' );
1029
+		wp_register_style('espresso-ui-theme', EE_GLOBAL_ASSETS_URL.'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css', array(), EVENT_ESPRESSO_VERSION);
1030
+		wp_enqueue_style('espresso-ui-theme');
1031
+		wp_enqueue_script('jquery-ui-datepicker');
1032 1032
 
1033
-		$input_html =  apply_filters( 'FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id );
1034
-		return  $label_html . $input_html;
1033
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1034
+		return  $label_html.$input_html;
1035 1035
 
1036 1036
 	}
1037 1037
 
@@ -1043,7 +1043,7 @@  discard block
 block discarded – undo
1043 1043
 	 * 	@access public
1044 1044
 	 * 	@return 	string
1045 1045
 	 */
1046
-	public static function remove_label_keep_required_msg( $label_html, $required_text ) {
1046
+	public static function remove_label_keep_required_msg($label_html, $required_text) {
1047 1047
 		return $required_text;
1048 1048
 	}
1049 1049
 
@@ -1057,9 +1057,9 @@  discard block
 block discarded – undo
1057 1057
 	 * @param string $value
1058 1058
 	 * @return string HTML
1059 1059
 	 */
1060
-	static function hidden_input( $name, $value, $id = '' ){
1061
-		$id = ! empty( $id ) ? $id : $name;
1062
-		return '<input id="' . $id . '" type="hidden" name="'.$name.'" value="' .  $value . '"/>';
1060
+	static function hidden_input($name, $value, $id = '') {
1061
+		$id = ! empty($id) ? $id : $name;
1062
+		return '<input id="'.$id.'" type="hidden" name="'.$name.'" value="'.$value.'"/>';
1063 1063
 	}
1064 1064
 
1065 1065
 
@@ -1071,7 +1071,7 @@  discard block
 block discarded – undo
1071 1071
 	 * @param string $question
1072 1072
 	 * @return string
1073 1073
 	 */
1074
-	static function prep_question( $question ){
1074
+	static function prep_question($question) {
1075 1075
 		return $question;
1076 1076
 //		$link = '';
1077 1077
 //		// does this label have a help link attached ?
@@ -1094,13 +1094,13 @@  discard block
 block discarded – undo
1094 1094
 	 * @param mixed $answer
1095 1095
 	 * @return string
1096 1096
 	 */
1097
-	static function prep_answer( $answer, $use_html_entities = TRUE ){
1097
+	static function prep_answer($answer, $use_html_entities = TRUE) {
1098 1098
 		//make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired, we want "0".
1099
-		if ( is_bool( $answer ) ) {
1099
+		if (is_bool($answer)) {
1100 1100
 			$answer = $answer ? 1 : 0;
1101 1101
 		}
1102
-		$answer = trim( stripslashes( str_replace( '&#039;', "'", $answer )));
1103
-		return $use_html_entities ? htmlentities( $answer, ENT_QUOTES, 'UTF-8' ) : $answer;
1102
+		$answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1103
+		return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1104 1104
 	}
1105 1105
 
1106 1106
 
@@ -1110,18 +1110,18 @@  discard block
 block discarded – undo
1110 1110
 	 * 	@param array $QSOs  array of EE_Question_Option objects
1111 1111
 	 * 	@return array
1112 1112
 	 */
1113
-	public static function prep_answer_options( $QSOs = array() ){
1113
+	public static function prep_answer_options($QSOs = array()) {
1114 1114
 		$prepped_answer_options = array();
1115
-		if ( is_array( $QSOs ) && ! empty( $QSOs )) {
1116
-			foreach( $QSOs as $key => $QSO ) {
1117
-				if ( ! $QSO instanceof EE_Question_Option ) {
1118
-					$QSO = EE_Question_Option::new_instance( array(
1119
-						'QSO_value' => is_array( $QSO ) && isset( $QSO['id'] ) ? (string)$QSO['id'] : (string)$key,
1120
-						'QSO_desc' => is_array( $QSO ) && isset( $QSO['text'] ) ? (string)$QSO['text'] : (string)$QSO
1115
+		if (is_array($QSOs) && ! empty($QSOs)) {
1116
+			foreach ($QSOs as $key => $QSO) {
1117
+				if ( ! $QSO instanceof EE_Question_Option) {
1118
+					$QSO = EE_Question_Option::new_instance(array(
1119
+						'QSO_value' => is_array($QSO) && isset($QSO['id']) ? (string) $QSO['id'] : (string) $key,
1120
+						'QSO_desc' => is_array($QSO) && isset($QSO['text']) ? (string) $QSO['text'] : (string) $QSO
1121 1121
 					));
1122 1122
 				}
1123
-				if ( $QSO->opt_group() ) {
1124
-					$prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1123
+				if ($QSO->opt_group()) {
1124
+					$prepped_answer_options[$QSO->opt_group()][] = $QSO;
1125 1125
 				} else {
1126 1126
 					$prepped_answer_options[] = $QSO;
1127 1127
 				}
@@ -1137,8 +1137,8 @@  discard block
 block discarded – undo
1137 1137
 	 * @param string $option_value
1138 1138
 	 * @return string
1139 1139
 	 */
1140
-	static function prep_option_value( $option_value ){
1141
-		return esc_attr( trim( stripslashes( $option_value ) ) );
1140
+	static function prep_option_value($option_value) {
1141
+		return esc_attr(trim(stripslashes($option_value)));
1142 1142
 	}
1143 1143
 
1144 1144
 
@@ -1149,11 +1149,11 @@  discard block
 block discarded – undo
1149 1149
 	 * @param string|array 	$required
1150 1150
 	 * @return array
1151 1151
 	 */
1152
-	static function prep_required( $required = array() ){
1152
+	static function prep_required($required = array()) {
1153 1153
 		// make sure required is an array
1154
-		$required = is_array( $required ) ? $required : array();
1154
+		$required = is_array($required) ? $required : array();
1155 1155
 		// and set some defaults
1156
-		$required = array_merge( array( 'label' => '', 'class' => '', 'msg' => '' ), $required );
1156
+		$required = array_merge(array('label' => '', 'class' => '', 'msg' => ''), $required);
1157 1157
 		return $required;
1158 1158
 	}
1159 1159
 
@@ -1164,30 +1164,30 @@  discard block
 block discarded – undo
1164 1164
 	 * @param string 	$value
1165 1165
 	 * @return string
1166 1166
 	 */
1167
-	static function get_label_size_class( $value = FALSE ){
1168
-			if ( $value === FALSE || $value == '' ) {
1167
+	static function get_label_size_class($value = FALSE) {
1168
+			if ($value === FALSE || $value == '') {
1169 1169
 				return ' class="medium-lbl"';
1170 1170
 			}
1171 1171
 			// determine length of option value
1172
-			$val_size = strlen( $value );
1173
-			switch( $val_size ){
1172
+			$val_size = strlen($value);
1173
+			switch ($val_size) {
1174 1174
 				case $val_size < 3 :
1175
-					$size =  ' class="nano-lbl"';
1175
+					$size = ' class="nano-lbl"';
1176 1176
 					break;
1177 1177
 				case $val_size < 6 :
1178
-					$size =  ' class="micro-lbl"';
1178
+					$size = ' class="micro-lbl"';
1179 1179
 					break;
1180 1180
 				case $val_size < 12 :
1181
-					$size =  ' class="tiny-lbl"';
1181
+					$size = ' class="tiny-lbl"';
1182 1182
 					break;
1183 1183
 				case $val_size < 25 :
1184
-					$size =  ' class="small-lbl"';
1184
+					$size = ' class="small-lbl"';
1185 1185
 					break;
1186 1186
 				case $val_size > 100 :
1187
-					$size =  ' class="big-lbl"';
1187
+					$size = ' class="big-lbl"';
1188 1188
 					break;
1189 1189
 				default:
1190
-					$size =  ' class="medium-lbl"';
1190
+					$size = ' class="medium-lbl"';
1191 1191
 					break;
1192 1192
 			}
1193 1193
 		return $size;
@@ -1201,20 +1201,20 @@  discard block
 block discarded – undo
1201 1201
 	 * @param array 	$QFI
1202 1202
 	 * @return array
1203 1203
 	 */
1204
-	private static function _load_system_dropdowns( $QFI ){
1204
+	private static function _load_system_dropdowns($QFI) {
1205 1205
 		$QST_system = $QFI->get('QST_system');
1206
-		switch ( $QST_system ) {
1206
+		switch ($QST_system) {
1207 1207
 			case 'state' :
1208
-				$QFI = self::generate_state_dropdown( $QFI );
1208
+				$QFI = self::generate_state_dropdown($QFI);
1209 1209
 				break;
1210 1210
 			case 'country' :
1211
-				$QFI = self::generate_country_dropdown( $QFI );
1211
+				$QFI = self::generate_country_dropdown($QFI);
1212 1212
 				break;
1213 1213
 			case 'admin-state' :
1214
-				$QFI = self::generate_state_dropdown( $QFI, TRUE );
1214
+				$QFI = self::generate_state_dropdown($QFI, TRUE);
1215 1215
 				break;
1216 1216
 			case 'admin-country' :
1217
-				$QFI = self::generate_country_dropdown( $QFI, TRUE );
1217
+				$QFI = self::generate_country_dropdown($QFI, TRUE);
1218 1218
 				break;
1219 1219
 		}
1220 1220
 		return $QFI;
@@ -1231,13 +1231,13 @@  discard block
 block discarded – undo
1231 1231
 	 *
1232 1232
 	 * @return EE_Question_Form_Input
1233 1233
 	 */
1234
-	protected static function _load_specialized_dropdowns( $QFI ) {
1235
-		switch( $QFI->get( 'QST_type' ) ) {
1234
+	protected static function _load_specialized_dropdowns($QFI) {
1235
+		switch ($QFI->get('QST_type')) {
1236 1236
 			case 'STATE' :
1237
-				$QFI = self::generate_state_dropdown( $QFI );
1237
+				$QFI = self::generate_state_dropdown($QFI);
1238 1238
 				break;
1239 1239
 			case 'COUNTRY' :
1240
-				$QFI = self::generate_country_dropdown( $QFI );
1240
+				$QFI = self::generate_country_dropdown($QFI);
1241 1241
 				break;
1242 1242
 		}
1243 1243
 		return $QFI;
@@ -1251,23 +1251,23 @@  discard block
 block discarded – undo
1251 1251
 	 * @param bool  $get_all
1252 1252
 	 * @return array
1253 1253
 	 */
1254
-	public static function generate_state_dropdown( $QST, $get_all = FALSE ){
1254
+	public static function generate_state_dropdown($QST, $get_all = FALSE) {
1255 1255
 		$states = $get_all ? EEM_State::instance()->get_all_states() : EEM_State::instance()->get_all_states_of_active_countries();
1256
-		if ( $states && count( $states ) != count( $QST->options() )) {
1257
-			$QST->set( 'QST_type', 'DROPDOWN' );
1256
+		if ($states && count($states) != count($QST->options())) {
1257
+			$QST->set('QST_type', 'DROPDOWN');
1258 1258
 			// if multiple countries, we'll create option groups within the dropdown
1259
-			foreach ( $states as $state ) {
1260
-				if ( $state instanceof EE_State ) {
1261
-					$QSO = EE_Question_Option::new_instance ( array (
1259
+			foreach ($states as $state) {
1260
+				if ($state instanceof EE_State) {
1261
+					$QSO = EE_Question_Option::new_instance(array(
1262 1262
 						'QSO_value' => $state->ID(),
1263 1263
 						'QSO_desc' => $state->name(),
1264
-						'QST_ID' => $QST->get( 'QST_ID' ),
1264
+						'QST_ID' => $QST->get('QST_ID'),
1265 1265
 						'QSO_deleted' => FALSE
1266 1266
 					));
1267 1267
 					// set option group
1268
-					$QSO->set_opt_group( $state->country()->name() );
1268
+					$QSO->set_opt_group($state->country()->name());
1269 1269
 					// add option to question
1270
-					$QST->add_temp_option( $QSO );
1270
+					$QST->add_temp_option($QSO);
1271 1271
 				}
1272 1272
 			}
1273 1273
 		}
@@ -1283,20 +1283,20 @@  discard block
 block discarded – undo
1283 1283
 	 * @internal param array $question
1284 1284
 	 * @return array
1285 1285
 	 */
1286
-	public static function generate_country_dropdown( $QST, $get_all = FALSE ){
1286
+	public static function generate_country_dropdown($QST, $get_all = FALSE) {
1287 1287
 		$countries = $get_all ? EEM_Country::instance()->get_all_countries() : EEM_Country::instance()->get_all_active_countries();
1288
-		if ( $countries && count( $countries ) != count( $QST->options() ) ) {
1289
-			$QST->set( 'QST_type', 'DROPDOWN' );
1288
+		if ($countries && count($countries) != count($QST->options())) {
1289
+			$QST->set('QST_type', 'DROPDOWN');
1290 1290
 			// now add countries
1291
-			foreach ( $countries as $country ) {
1292
-				if ( $country instanceof EE_Country ) {
1293
-					$QSO = EE_Question_Option::new_instance ( array (
1291
+			foreach ($countries as $country) {
1292
+				if ($country instanceof EE_Country) {
1293
+					$QSO = EE_Question_Option::new_instance(array(
1294 1294
 						'QSO_value' => $country->ID(),
1295 1295
 						'QSO_desc' => $country->name(),
1296
-						'QST_ID' => $QST->get( 'QST_ID' ),
1296
+						'QST_ID' => $QST->get('QST_ID'),
1297 1297
 						'QSO_deleted' => FALSE
1298 1298
 					));
1299
-					$QST->add_temp_option( $QSO );
1299
+					$QST->add_temp_option($QSO);
1300 1300
 				}
1301 1301
 			}
1302 1302
 		}
@@ -1313,11 +1313,11 @@  discard block
 block discarded – undo
1313 1313
 	 */
1314 1314
 	public static function two_digit_months_dropdown_options() {
1315 1315
 		$options = array();
1316
-		for ( $x = 1; $x <= 12; $x++ ) {
1317
-			$mm = str_pad( $x, 2, '0', STR_PAD_LEFT );
1318
-			$options[ (string)$mm ] = (string)$mm;
1316
+		for ($x = 1; $x <= 12; $x++) {
1317
+			$mm = str_pad($x, 2, '0', STR_PAD_LEFT);
1318
+			$options[(string) $mm] = (string) $mm;
1319 1319
 		}
1320
-		return EEH_Form_Fields::prep_answer_options( $options );
1320
+		return EEH_Form_Fields::prep_answer_options($options);
1321 1321
 	}
1322 1322
 
1323 1323
 
@@ -1332,11 +1332,11 @@  discard block
 block discarded – undo
1332 1332
 		$options = array();
1333 1333
 		$current_year = date('y');
1334 1334
 		$next_decade = $current_year + 10;
1335
-		for ( $x = $current_year; $x <= $next_decade; $x++ ) {
1336
-			$yy = str_pad( $x, 2, '0', STR_PAD_LEFT );
1337
-			$options[ (string)$yy ] = (string)$yy;
1335
+		for ($x = $current_year; $x <= $next_decade; $x++) {
1336
+			$yy = str_pad($x, 2, '0', STR_PAD_LEFT);
1337
+			$options[(string) $yy] = (string) $yy;
1338 1338
 		}
1339
-		return EEH_Form_Fields::prep_answer_options( $options );
1339
+		return EEH_Form_Fields::prep_answer_options($options);
1340 1340
 	}
1341 1341
 
1342 1342
 
@@ -1350,17 +1350,17 @@  discard block
 block discarded – undo
1350 1350
 	 * @param  integer $evt_category Event Category ID if the Event Category filter is selected
1351 1351
 	 * @return string                html
1352 1352
 	 */
1353
-	public static function generate_registration_months_dropdown( $cur_date = '', $status = '', $evt_category = 0 ) {
1353
+	public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0) {
1354 1354
 		$_where = array();
1355
-		if ( !empty( $status ) ) {
1355
+		if ( ! empty($status)) {
1356 1356
 			$_where['STS_ID'] = $status;
1357 1357
 		}
1358 1358
 
1359
-		if ( $evt_category > 0 ) {
1359
+		if ($evt_category > 0) {
1360 1360
 			$_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1361 1361
 		}
1362 1362
 
1363
-		$regdtts = EEM_Registration::instance()->get_reg_months_and_years( $_where );
1363
+		$regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1364 1364
 
1365 1365
 		//setup vals for select input helper
1366 1366
 		$options = array(
@@ -1370,15 +1370,15 @@  discard block
 block discarded – undo
1370 1370
 				)
1371 1371
 			);
1372 1372
 
1373
-		foreach ( $regdtts as $regdtt ) {
1374
-			$date = $regdtt->reg_month. ' ' . $regdtt->reg_year;
1373
+		foreach ($regdtts as $regdtt) {
1374
+			$date = $regdtt->reg_month.' '.$regdtt->reg_year;
1375 1375
 			$options[] = array(
1376 1376
 				'text' => $date,
1377 1377
 				'id' => $date
1378 1378
 				);
1379 1379
 		}
1380 1380
 
1381
-		return self::select_input('month_range', $options, $cur_date, '', 'wide' );
1381
+		return self::select_input('month_range', $options, $cur_date, '', 'wide');
1382 1382
 	}
1383 1383
 
1384 1384
 
@@ -1392,18 +1392,18 @@  discard block
 block discarded – undo
1392 1392
 	 * @param  string $evt_active_status "upcoming", "expired", "active", or "inactive"
1393 1393
 	 * @return string                    html
1394 1394
 	 */
1395
-	public static function generate_event_months_dropdown( $cur_date = '', $status = NULL, $evt_category = NULL, $evt_active_status = NULL ) {
1395
+	public static function generate_event_months_dropdown($cur_date = '', $status = NULL, $evt_category = NULL, $evt_active_status = NULL) {
1396 1396
 		//determine what post_status our condition will have for the query.
1397
-		switch ( $status ) {
1397
+		switch ($status) {
1398 1398
 			case 'month' :
1399 1399
 			case 'today' :
1400 1400
 			case NULL :
1401 1401
 			case 'all' :
1402
-				$where['Event.status'] = array( 'NOT IN', array('trash') );
1402
+				$where['Event.status'] = array('NOT IN', array('trash'));
1403 1403
 				break;
1404 1404
 
1405 1405
 			case 'draft' :
1406
-				$where['Event.status'] = array( 'IN', array('draft', 'auto-draft') );
1406
+				$where['Event.status'] = array('IN', array('draft', 'auto-draft'));
1407 1407
 
1408 1408
 			default :
1409 1409
 				$where['Event.status'] = $status;
@@ -1412,7 +1412,7 @@  discard block
 block discarded – undo
1412 1412
 		//categories?
1413 1413
 
1414 1414
 
1415
-		if ( !empty ( $evt_category ) ) {
1415
+		if ( ! empty ($evt_category)) {
1416 1416
 			$where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1417 1417
 			$where['Event.Term_Taxonomy.term_id'] = $evt_category;
1418 1418
 		}
@@ -1420,7 +1420,7 @@  discard block
 block discarded – undo
1420 1420
 
1421 1421
 //		$where['DTT_is_primary'] = 1;
1422 1422
 
1423
-		$DTTS = EE_Registry::instance()->load_model('Datetime')->get_dtt_months_and_years($where, $evt_active_status );
1423
+		$DTTS = EE_Registry::instance()->load_model('Datetime')->get_dtt_months_and_years($where, $evt_active_status);
1424 1424
 
1425 1425
 		//let's setup vals for select input helper
1426 1426
 		$options = array(
@@ -1435,9 +1435,9 @@  discard block
 block discarded – undo
1435 1435
 		//translate month and date
1436 1436
 		global $wp_locale;
1437 1437
 
1438
-		foreach ( $DTTS as $DTT ) {
1439
-			$localized_date = $wp_locale->get_month( $DTT->dtt_month_num ) . ' ' . $DTT->dtt_year;
1440
-			$id = $DTT->dtt_month . ' ' . $DTT->dtt_year;
1438
+		foreach ($DTTS as $DTT) {
1439
+			$localized_date = $wp_locale->get_month($DTT->dtt_month_num).' '.$DTT->dtt_year;
1440
+			$id = $DTT->dtt_month.' '.$DTT->dtt_year;
1441 1441
 			$options[] = array(
1442 1442
 				'text' => $localized_date,
1443 1443
 				'id' => $id
@@ -1445,7 +1445,7 @@  discard block
 block discarded – undo
1445 1445
 		}
1446 1446
 
1447 1447
 
1448
-		return self::select_input( 'month_range', $options, $cur_date, '', 'wide' );
1448
+		return self::select_input('month_range', $options, $cur_date, '', 'wide');
1449 1449
 	}
1450 1450
 
1451 1451
 
@@ -1456,7 +1456,7 @@  discard block
 block discarded – undo
1456 1456
 	 * @param  integer $current_cat currently selected category
1457 1457
 	 * @return string               html for dropdown
1458 1458
 	 */
1459
-	public static function generate_event_category_dropdown( $current_cat = -1 ) {
1459
+	public static function generate_event_category_dropdown($current_cat = -1) {
1460 1460
 		$categories = EEM_Term::instance()->get_all_ee_categories(TRUE);
1461 1461
 		$options = array(
1462 1462
 			'0' => array(
@@ -1466,14 +1466,14 @@  discard block
 block discarded – undo
1466 1466
 			);
1467 1467
 
1468 1468
 		//setup categories for dropdown
1469
-		foreach ( $categories as $category ) {
1469
+		foreach ($categories as $category) {
1470 1470
 			$options[] = array(
1471 1471
 				'text' => $category->get('name'),
1472 1472
 				'id' => $category->ID()
1473 1473
 				);
1474 1474
 		}
1475 1475
 
1476
-		return self::select_input( 'EVT_CAT', $options, $current_cat );
1476
+		return self::select_input('EVT_CAT', $options, $current_cat);
1477 1477
 	}
1478 1478
 
1479 1479
 
@@ -1492,20 +1492,20 @@  discard block
 block discarded – undo
1492 1492
 	 * @param    string   $extra_attributes - any extra attributes that need to be attached to the form input
1493 1493
 	 * @return    void
1494 1494
 	 */
1495
-	public static function submit_button( $url = '', $ID = '', $class = '', $text = '', $nonce_action = '', $input_only = FALSE, $extra_attributes = '' ) {
1495
+	public static function submit_button($url = '', $ID = '', $class = '', $text = '', $nonce_action = '', $input_only = FALSE, $extra_attributes = '') {
1496 1496
 		$btn = '';
1497
-		if ( empty( $url ) || empty( $ID )) {
1497
+		if (empty($url) || empty($ID)) {
1498 1498
 			return $btn;
1499 1499
 		}
1500
-		$text = ! empty( $text ) ? $text : __('Submit', 'event_espresso' );
1501
-		$btn .= '<input id="' . $ID . '-btn" class="' . $class . '" type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
1502
-		if ( ! $input_only ) {
1503
-			$btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
1504
-			$btn_frm .= ! empty( $nonce_action ) ? wp_nonce_field( $nonce_action, $nonce_action . '_nonce', TRUE, FALSE ) : '';
1500
+		$text = ! empty($text) ? $text : __('Submit', 'event_espresso');
1501
+		$btn .= '<input id="'.$ID.'-btn" class="'.$class.'" type="submit" value="'.$text.'" '.$extra_attributes.'/>';
1502
+		if ( ! $input_only) {
1503
+			$btn_frm = '<form id="'.$ID.'-frm" method="POST" action="'.$url.'">';
1504
+			$btn_frm .= ! empty($nonce_action) ? wp_nonce_field($nonce_action, $nonce_action.'_nonce', TRUE, FALSE) : '';
1505 1505
 			$btn_frm .= $btn;
1506 1506
 			$btn_frm .= '</form>';
1507 1507
 			$btn = $btn_frm;
1508
-			unset ( $btn_frm );
1508
+			unset ($btn_frm);
1509 1509
 		}
1510 1510
 		return $btn;
1511 1511
 	}
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 2 patches
Indentation   +2723 added lines, -2723 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 do_action('AHEE_log', __FILE__, ' FILE LOADED', '');
5 5
 
@@ -25,2728 +25,2728 @@  discard block
 block discarded – undo
25 25
 abstract class EE_Base_Class
26 26
 {
27 27
 
28
-    /**
29
-     * This is an array of the original properties and values provided during construction
30
-     * of this model object. (keys are model field names, values are their values).
31
-     * This list is important to remember so that when we are merging data from the db, we know
32
-     * which values to override and which to not override.
33
-     *
34
-     * @var array
35
-     */
36
-    protected $_props_n_values_provided_in_constructor;
37
-
38
-    /**
39
-     * Timezone
40
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
41
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
42
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
43
-     * access to it.
44
-     *
45
-     * @var string
46
-     */
47
-    protected $_timezone;
48
-
49
-
50
-
51
-    /**
52
-     * date format
53
-     * pattern or format for displaying dates
54
-     *
55
-     * @var string $_dt_frmt
56
-     */
57
-    protected $_dt_frmt;
58
-
59
-
60
-
61
-    /**
62
-     * time format
63
-     * pattern or format for displaying time
64
-     *
65
-     * @var string $_tm_frmt
66
-     */
67
-    protected $_tm_frmt;
68
-
69
-
70
-
71
-    /**
72
-     * This property is for holding a cached array of object properties indexed by property name as the key.
73
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
74
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
75
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
76
-     *
77
-     * @var array
78
-     */
79
-    protected $_cached_properties = array();
80
-
81
-    /**
82
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
83
-     * single
84
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
85
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
86
-     * all others have an array)
87
-     *
88
-     * @var array
89
-     */
90
-    protected $_model_relations = array();
91
-
92
-    /**
93
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
94
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
95
-     *
96
-     * @var array
97
-     */
98
-    protected $_fields = array();
99
-
100
-    /**
101
-     * @var boolean indicating whether or not this model object is intended to ever be saved
102
-     * For example, we might create model objects intended to only be used for the duration
103
-     * of this request and to be thrown away, and if they were accidentally saved
104
-     * it would be a bug.
105
-     */
106
-    protected $_allow_persist = true;
107
-
108
-    /**
109
-     * @var boolean indicating whether or not this model object's properties have changed since construction
110
-     */
111
-    protected $_has_changes = false;
112
-
113
-    /**
114
-     * @var EEM_Base
115
-     */
116
-    protected $_model;
117
-
118
-
119
-
120
-    /**
121
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
122
-     * play nice
123
-     *
124
-     * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
125
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
126
-     *                                                         TXN_amount, QST_name, etc) and values are their values
127
-     * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
128
-     *                                                         corresponding db model or not.
129
-     * @param string  $timezone                                indicate what timezone you want any datetime fields to
130
-     *                                                         be in when instantiating a EE_Base_Class object.
131
-     * @param array   $date_formats                            An array of date formats to set on construct where first
132
-     *                                                         value is the date_format and second value is the time
133
-     *                                                         format.
134
-     * @throws EE_Error
135
-     */
136
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
137
-    {
138
-        $className = get_class($this);
139
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
140
-        $model = $this->get_model();
141
-        $model_fields = $model->field_settings(false);
142
-        // ensure $fieldValues is an array
143
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
144
-        // EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
145
-        // verify client code has not passed any invalid field names
146
-        foreach ($fieldValues as $field_name => $field_value) {
147
-            if ( ! isset($model_fields[$field_name])) {
148
-                throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
149
-                    "event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
150
-            }
151
-        }
152
-        // EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
153
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
154
-        if ( ! empty($date_formats) && is_array($date_formats)) {
155
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
156
-        } else {
157
-            //set default formats for date and time
158
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
159
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
160
-        }
161
-        //if db model is instantiating
162
-        if ($bydb) {
163
-            //client code has indicated these field values are from the database
164
-            foreach ($model_fields as $fieldName => $field) {
165
-                $this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
166
-            }
167
-        } else {
168
-            //we're constructing a brand
169
-            //new instance of the model object. Generally, this means we'll need to do more field validation
170
-            foreach ($model_fields as $fieldName => $field) {
171
-                $this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
172
-            }
173
-        }
174
-        //remember what values were passed to this constructor
175
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
176
-        //remember in entity mapper
177
-        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
178
-            $model->add_to_entity_map($this);
179
-        }
180
-        //setup all the relations
181
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
182
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
183
-                $this->_model_relations[$relation_name] = null;
184
-            } else {
185
-                $this->_model_relations[$relation_name] = array();
186
-            }
187
-        }
188
-        /**
189
-         * Action done at the end of each model object construction
190
-         *
191
-         * @param EE_Base_Class $this the model object just created
192
-         */
193
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
194
-    }
195
-
196
-
197
-
198
-    /**
199
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
200
-     *
201
-     * @return boolean
202
-     */
203
-    public function allow_persist()
204
-    {
205
-        return $this->_allow_persist;
206
-    }
207
-
208
-
209
-
210
-    /**
211
-     * Sets whether or not this model object should be allowed to be saved to the DB.
212
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
213
-     * you got new information that somehow made you change your mind.
214
-     *
215
-     * @param boolean $allow_persist
216
-     * @return boolean
217
-     */
218
-    public function set_allow_persist($allow_persist)
219
-    {
220
-        return $this->_allow_persist = $allow_persist;
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     * Gets the field's original value when this object was constructed during this request.
227
-     * This can be helpful when determining if a model object has changed or not
228
-     *
229
-     * @param string $field_name
230
-     * @return mixed|null
231
-     * @throws \EE_Error
232
-     */
233
-    public function get_original($field_name)
234
-    {
235
-        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
236
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
237
-        ) {
238
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
239
-        } else {
240
-            return null;
241
-        }
242
-    }
243
-
244
-
245
-
246
-    /**
247
-     * @param EE_Base_Class $obj
248
-     * @return string
249
-     */
250
-    public function get_class($obj)
251
-    {
252
-        return get_class($obj);
253
-    }
254
-
255
-
256
-
257
-    /**
258
-     * Overrides parent because parent expects old models.
259
-     * This also doesn't do any validation, and won't work for serialized arrays
260
-     *
261
-     * @param    string $field_name
262
-     * @param    mixed  $field_value
263
-     * @param bool      $use_default
264
-     * @throws \EE_Error
265
-     */
266
-    public function set($field_name, $field_value, $use_default = false)
267
-    {
268
-        // if not using default and nothing has changed, and object has already been setup (has ID),
269
-        // then don't do anything
270
-        if (
271
-            ! $use_default
272
-            && $this->_fields[$field_name] === $field_value
273
-            && $this->ID()
274
-        ) {
275
-            return;
276
-        }
277
-        $model = $this->get_model();
278
-        $this->_has_changes = true;
279
-        $field_obj = $model->field_settings_for($field_name);
280
-        if ($field_obj instanceof EE_Model_Field_Base) {
281
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
282
-            if ($field_obj instanceof EE_Datetime_Field) {
283
-                $field_obj->set_timezone($this->_timezone);
284
-                $field_obj->set_date_format($this->_dt_frmt);
285
-                $field_obj->set_time_format($this->_tm_frmt);
286
-            }
287
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
288
-            //should the value be null?
289
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
290
-                $this->_fields[$field_name] = $field_obj->get_default_value();
291
-                /**
292
-                 * To save having to refactor all the models, if a default value is used for a
293
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
294
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
295
-                 * object.
296
-                 *
297
-                 * @since 4.6.10+
298
-                 */
299
-                if (
300
-                    $field_obj instanceof EE_Datetime_Field
301
-                    && $this->_fields[$field_name] !== null
302
-                    && ! $this->_fields[$field_name] instanceof DateTime
303
-                ) {
304
-                    empty($this->_fields[$field_name])
305
-                        ? $this->set($field_name, time())
306
-                        : $this->set($field_name, $this->_fields[$field_name]);
307
-                }
308
-            } else {
309
-                $this->_fields[$field_name] = $holder_of_value;
310
-            }
311
-            //if we're not in the constructor...
312
-            //now check if what we set was a primary key
313
-            if (
314
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
315
-                $this->_props_n_values_provided_in_constructor
316
-                && $field_value
317
-                && $field_name === $model->primary_key_name()
318
-            ) {
319
-                //if so, we want all this object's fields to be filled either with
320
-                //what we've explicitly set on this model
321
-                //or what we have in the db
322
-                // echo "setting primary key!";
323
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
324
-                $obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
325
-                foreach ($fields_on_model as $field_obj) {
326
-                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
327
-                         && $field_obj->get_name() !== $field_name
328
-                    ) {
329
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
330
-                    }
331
-                }
332
-                //oh this model object has an ID? well make sure its in the entity mapper
333
-                $model->add_to_entity_map($this);
334
-            }
335
-            //let's unset any cache for this field_name from the $_cached_properties property.
336
-            $this->_clear_cached_property($field_name);
337
-        } else {
338
-            throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
339
-                "event_espresso"), $field_name));
340
-        }
341
-    }
342
-
343
-
344
-
345
-    /**
346
-     * This sets the field value on the db column if it exists for the given $column_name or
347
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
348
-     *
349
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
350
-     * @param string $field_name  Must be the exact column name.
351
-     * @param mixed  $field_value The value to set.
352
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
353
-     * @throws \EE_Error
354
-     */
355
-    public function set_field_or_extra_meta($field_name, $field_value)
356
-    {
357
-        if ($this->get_model()->has_field($field_name)) {
358
-            $this->set($field_name, $field_value);
359
-            return true;
360
-        } else {
361
-            //ensure this object is saved first so that extra meta can be properly related.
362
-            $this->save();
363
-            return $this->update_extra_meta($field_name, $field_value);
364
-        }
365
-    }
366
-
367
-
368
-
369
-    /**
370
-     * This retrieves the value of the db column set on this class or if that's not present
371
-     * it will attempt to retrieve from extra_meta if found.
372
-     * Example Usage:
373
-     * Via EE_Message child class:
374
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
375
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
376
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
377
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
378
-     * value for those extra fields dynamically via the EE_message object.
379
-     *
380
-     * @param  string $field_name expecting the fully qualified field name.
381
-     * @return mixed|null  value for the field if found.  null if not found.
382
-     * @throws \EE_Error
383
-     */
384
-    public function get_field_or_extra_meta($field_name)
385
-    {
386
-        if ($this->get_model()->has_field($field_name)) {
387
-            $column_value = $this->get($field_name);
388
-        } else {
389
-            //This isn't a column in the main table, let's see if it is in the extra meta.
390
-            $column_value = $this->get_extra_meta($field_name, true, null);
391
-        }
392
-        return $column_value;
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
399
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
400
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
401
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
402
-     *
403
-     * @access public
404
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
405
-     * @return void
406
-     * @throws \EE_Error
407
-     */
408
-    public function set_timezone($timezone = '')
409
-    {
410
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
411
-        //make sure we clear all cached properties because they won't be relevant now
412
-        $this->_clear_cached_properties();
413
-        //make sure we update field settings and the date for all EE_Datetime_Fields
414
-        $model_fields = $this->get_model()->field_settings(false);
415
-        foreach ($model_fields as $field_name => $field_obj) {
416
-            if ($field_obj instanceof EE_Datetime_Field) {
417
-                $field_obj->set_timezone($this->_timezone);
418
-                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
419
-                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
420
-                }
421
-            }
422
-        }
423
-    }
424
-
425
-
426
-
427
-    /**
428
-     * This just returns whatever is set for the current timezone.
429
-     *
430
-     * @access public
431
-     * @return string timezone string
432
-     */
433
-    public function get_timezone()
434
-    {
435
-        return $this->_timezone;
436
-    }
437
-
438
-
439
-
440
-    /**
441
-     * This sets the internal date format to what is sent in to be used as the new default for the class
442
-     * internally instead of wp set date format options
443
-     *
444
-     * @since 4.6
445
-     * @param string $format should be a format recognizable by PHP date() functions.
446
-     */
447
-    public function set_date_format($format)
448
-    {
449
-        $this->_dt_frmt = $format;
450
-        //clear cached_properties because they won't be relevant now.
451
-        $this->_clear_cached_properties();
452
-    }
453
-
454
-
455
-
456
-    /**
457
-     * This sets the internal time format string to what is sent in to be used as the new default for the
458
-     * class internally instead of wp set time format options.
459
-     *
460
-     * @since 4.6
461
-     * @param string $format should be a format recognizable by PHP date() functions.
462
-     */
463
-    public function set_time_format($format)
464
-    {
465
-        $this->_tm_frmt = $format;
466
-        //clear cached_properties because they won't be relevant now.
467
-        $this->_clear_cached_properties();
468
-    }
469
-
470
-
471
-
472
-    /**
473
-     * This returns the current internal set format for the date and time formats.
474
-     *
475
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
476
-     *                             where the first value is the date format and the second value is the time format.
477
-     * @return mixed string|array
478
-     */
479
-    public function get_format($full = true)
480
-    {
481
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
482
-    }
483
-
484
-
485
-
486
-    /**
487
-     * cache
488
-     * stores the passed model object on the current model object.
489
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
490
-     *
491
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
492
-     *                                       'Registration' associated with this model object
493
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
494
-     *                                       that could be a payment or a registration)
495
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
496
-     *                                       items which will be stored in an array on this object
497
-     * @throws EE_Error
498
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
499
-     *                  related thing, no array)
500
-     */
501
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
502
-    {
503
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
504
-        if ( ! $object_to_cache instanceof EE_Base_Class) {
505
-            return false;
506
-        }
507
-        // also get "how" the object is related, or throw an error
508
-        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
509
-            throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
510
-                $relationName, get_class($this)));
511
-        }
512
-        // how many things are related ?
513
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
514
-            // if it's a "belongs to" relationship, then there's only one related model object  eg, if this is a registration, there's only 1 attendee for it
515
-            // so for these model objects just set it to be cached
516
-            $this->_model_relations[$relationName] = $object_to_cache;
517
-            $return = true;
518
-        } else {
519
-            // otherwise, this is the "many" side of a one to many relationship, so we'll add the object to the array of related objects for that type.
520
-            // eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
521
-            if ( ! is_array($this->_model_relations[$relationName])) {
522
-                // if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
523
-                $this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
524
-                    ? array($this->_model_relations[$relationName]) : array();
525
-            }
526
-            // first check for a cache_id which is normally empty
527
-            if ( ! empty($cache_id)) {
528
-                // if the cache_id exists, then it means we are purposely trying to cache this with a known key that can then be used to retrieve the object later on
529
-                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
530
-                $return = $cache_id;
531
-            } elseif ($object_to_cache->ID()) {
532
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
533
-                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
534
-                $return = $object_to_cache->ID();
535
-            } else {
536
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
537
-                $this->_model_relations[$relationName][] = $object_to_cache;
538
-                // move the internal pointer to the end of the array
539
-                end($this->_model_relations[$relationName]);
540
-                // and grab the key so that we can return it
541
-                $return = key($this->_model_relations[$relationName]);
542
-            }
543
-        }
544
-        return $return;
545
-    }
546
-
547
-
548
-
549
-    /**
550
-     * For adding an item to the cached_properties property.
551
-     *
552
-     * @access protected
553
-     * @param string      $fieldname the property item the corresponding value is for.
554
-     * @param mixed       $value     The value we are caching.
555
-     * @param string|null $cache_type
556
-     * @return void
557
-     * @throws \EE_Error
558
-     */
559
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
560
-    {
561
-        //first make sure this property exists
562
-        $this->get_model()->field_settings_for($fieldname);
563
-        $cache_type = empty($cache_type) ? 'standard' : $cache_type;
564
-        $this->_cached_properties[$fieldname][$cache_type] = $value;
565
-    }
566
-
567
-
568
-
569
-    /**
570
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
571
-     * This also SETS the cache if we return the actual property!
572
-     *
573
-     * @param string $fieldname        the name of the property we're trying to retrieve
574
-     * @param bool   $pretty
575
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
576
-     *                                 (in cases where the same property may be used for different outputs
577
-     *                                 - i.e. datetime, money etc.)
578
-     *                                 It can also accept certain pre-defined "schema" strings
579
-     *                                 to define how to output the property.
580
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
581
-     * @return mixed                   whatever the value for the property is we're retrieving
582
-     * @throws \EE_Error
583
-     */
584
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
585
-    {
586
-        //verify the field exists
587
-        $model = $this->get_model();
588
-        $model->field_settings_for($fieldname);
589
-        $cache_type = $pretty ? 'pretty' : 'standard';
590
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
591
-        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
592
-            return $this->_cached_properties[$fieldname][$cache_type];
593
-        }
594
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
595
-        $this->_set_cached_property($fieldname, $value, $cache_type);
596
-        return $value;
597
-    }
598
-
599
-
600
-
601
-    /**
602
-     * If the cache didn't fetch the needed item, this fetches it.
603
-     * @param string $fieldname
604
-     * @param bool $pretty
605
-     * @param string $extra_cache_ref
606
-     * @return mixed
607
-     */
608
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
609
-    {
610
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
611
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
612
-        if ($field_obj instanceof EE_Datetime_Field) {
613
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
614
-        }
615
-        if ( ! isset($this->_fields[$fieldname])) {
616
-            $this->_fields[$fieldname] = null;
617
-        }
618
-        $value = $pretty
619
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
620
-            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
621
-        return $value;
622
-    }
623
-
624
-
625
-
626
-    /**
627
-     * set timezone, formats, and output for EE_Datetime_Field objects
628
-     *
629
-     * @param \EE_Datetime_Field $datetime_field
630
-     * @param bool               $pretty
631
-     * @param null $date_or_time
632
-     * @return void
633
-     * @throws \EE_Error
634
-     */
635
-    protected function _prepare_datetime_field(
636
-        EE_Datetime_Field $datetime_field,
637
-        $pretty = false,
638
-        $date_or_time = null
639
-    ) {
640
-        $datetime_field->set_timezone($this->_timezone);
641
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
642
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
643
-        //set the output returned
644
-        switch ($date_or_time) {
645
-            case 'D' :
646
-                $datetime_field->set_date_time_output('date');
647
-                break;
648
-            case 'T' :
649
-                $datetime_field->set_date_time_output('time');
650
-                break;
651
-            default :
652
-                $datetime_field->set_date_time_output();
653
-        }
654
-    }
655
-
656
-
657
-
658
-    /**
659
-     * This just takes care of clearing out the cached_properties
660
-     *
661
-     * @return void
662
-     */
663
-    protected function _clear_cached_properties()
664
-    {
665
-        $this->_cached_properties = array();
666
-    }
667
-
668
-
669
-
670
-    /**
671
-     * This just clears out ONE property if it exists in the cache
672
-     *
673
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
674
-     * @return void
675
-     */
676
-    protected function _clear_cached_property($property_name)
677
-    {
678
-        if (isset($this->_cached_properties[$property_name])) {
679
-            unset($this->_cached_properties[$property_name]);
680
-        }
681
-    }
682
-
683
-
684
-
685
-    /**
686
-     * Ensures that this related thing is a model object.
687
-     *
688
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
689
-     * @param string $model_name   name of the related thing, eg 'Attendee',
690
-     * @return EE_Base_Class
691
-     * @throws \EE_Error
692
-     */
693
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
694
-    {
695
-        $other_model_instance = self::_get_model_instance_with_name(
696
-            self::_get_model_classname($model_name),
697
-            $this->_timezone
698
-        );
699
-        return $other_model_instance->ensure_is_obj($object_or_id);
700
-    }
701
-
702
-
703
-
704
-    /**
705
-     * Forgets the cached model of the given relation Name. So the next time we request it,
706
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
707
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
708
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
709
-     *
710
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
711
-     *                                                     Eg 'Registration'
712
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
713
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
714
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
715
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
716
-     *                                                     this is HasMany or HABTM.
717
-     * @throws EE_Error
718
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
719
-     *                       relation from all
720
-     */
721
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
722
-    {
723
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
724
-        $index_in_cache = '';
725
-        if ( ! $relationship_to_model) {
726
-            throw new EE_Error(
727
-                sprintf(
728
-                    __("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
729
-                    $relationName,
730
-                    get_class($this)
731
-                )
732
-            );
733
-        }
734
-        if ($clear_all) {
735
-            $obj_removed = true;
736
-            $this->_model_relations[$relationName] = null;
737
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
738
-            $obj_removed = $this->_model_relations[$relationName];
739
-            $this->_model_relations[$relationName] = null;
740
-        } else {
741
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
742
-                && $object_to_remove_or_index_into_array->ID()
743
-            ) {
744
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
745
-                if (is_array($this->_model_relations[$relationName])
746
-                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
747
-                ) {
748
-                    $index_found_at = null;
749
-                    //find this object in the array even though it has a different key
750
-                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
751
-                        if (
752
-                            $obj instanceof EE_Base_Class
753
-                            && (
754
-                                $obj == $object_to_remove_or_index_into_array
755
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
756
-                            )
757
-                        ) {
758
-                            $index_found_at = $index;
759
-                            break;
760
-                        }
761
-                    }
762
-                    if ($index_found_at) {
763
-                        $index_in_cache = $index_found_at;
764
-                    } else {
765
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
766
-                        //if it wasn't in it to begin with. So we're done
767
-                        return $object_to_remove_or_index_into_array;
768
-                    }
769
-                }
770
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
771
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
772
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
773
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
774
-                        $index_in_cache = $index;
775
-                    }
776
-                }
777
-            } else {
778
-                $index_in_cache = $object_to_remove_or_index_into_array;
779
-            }
780
-            //supposedly we've found it. But it could just be that the client code
781
-            //provided a bad index/object
782
-            if (
783
-            isset(
784
-                $this->_model_relations[$relationName],
785
-                $this->_model_relations[$relationName][$index_in_cache]
786
-            )
787
-            ) {
788
-                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
789
-                unset($this->_model_relations[$relationName][$index_in_cache]);
790
-            } else {
791
-                //that thing was never cached anyways.
792
-                $obj_removed = null;
793
-            }
794
-        }
795
-        return $obj_removed;
796
-    }
797
-
798
-
799
-
800
-    /**
801
-     * update_cache_after_object_save
802
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
803
-     * obtained after being saved to the db
804
-     *
805
-     * @param string         $relationName       - the type of object that is cached
806
-     * @param \EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
807
-     * @param string         $current_cache_id   - the ID that was used when originally caching the object
808
-     * @return boolean TRUE on success, FALSE on fail
809
-     * @throws \EE_Error
810
-     */
811
-    public function update_cache_after_object_save(
812
-        $relationName,
813
-        EE_Base_Class $newly_saved_object,
814
-        $current_cache_id = ''
815
-    ) {
816
-        // verify that incoming object is of the correct type
817
-        $obj_class = 'EE_' . $relationName;
818
-        if ($newly_saved_object instanceof $obj_class) {
819
-            /* @type EE_Base_Class $newly_saved_object */
820
-            // now get the type of relation
821
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
822
-            // if this is a 1:1 relationship
823
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
824
-                // then just replace the cached object with the newly saved object
825
-                $this->_model_relations[$relationName] = $newly_saved_object;
826
-                return true;
827
-                // or if it's some kind of sordid feral polyamorous relationship...
828
-            } elseif (is_array($this->_model_relations[$relationName])
829
-                      && isset($this->_model_relations[$relationName][$current_cache_id])
830
-            ) {
831
-                // then remove the current cached item
832
-                unset($this->_model_relations[$relationName][$current_cache_id]);
833
-                // and cache the newly saved object using it's new ID
834
-                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
835
-                return true;
836
-            }
837
-        }
838
-        return false;
839
-    }
840
-
841
-
842
-
843
-    /**
844
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
845
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
846
-     *
847
-     * @param string $relationName
848
-     * @return EE_Base_Class
849
-     */
850
-    public function get_one_from_cache($relationName)
851
-    {
852
-        $cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
853
-            : null;
854
-        if (is_array($cached_array_or_object)) {
855
-            return array_shift($cached_array_or_object);
856
-        } else {
857
-            return $cached_array_or_object;
858
-        }
859
-    }
860
-
861
-
862
-
863
-    /**
864
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
865
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
866
-     *
867
-     * @param string $relationName
868
-     * @throws \EE_Error
869
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
870
-     */
871
-    public function get_all_from_cache($relationName)
872
-    {
873
-        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
874
-        // if the result is not an array, but exists, make it an array
875
-        $objects = is_array($objects) ? $objects : array($objects);
876
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
877
-        //basically, if this model object was stored in the session, and these cached model objects
878
-        //already have IDs, let's make sure they're in their model's entity mapper
879
-        //otherwise we will have duplicates next time we call
880
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
881
-        $model = EE_Registry::instance()->load_model($relationName);
882
-        foreach ($objects as $model_object) {
883
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
884
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
885
-                if ($model_object->ID()) {
886
-                    $model->add_to_entity_map($model_object);
887
-                }
888
-            } else {
889
-                throw new EE_Error(
890
-                    sprintf(
891
-                        __(
892
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
893
-                            'event_espresso'
894
-                        ),
895
-                        $relationName,
896
-                        gettype($model_object)
897
-                    )
898
-                );
899
-            }
900
-        }
901
-        return $objects;
902
-    }
903
-
904
-
905
-
906
-    /**
907
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
908
-     * matching the given query conditions.
909
-     *
910
-     * @param null  $field_to_order_by  What field is being used as the reference point.
911
-     * @param int   $limit              How many objects to return.
912
-     * @param array $query_params       Any additional conditions on the query.
913
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
914
-     *                                  you can indicate just the columns you want returned
915
-     * @return array|EE_Base_Class[]
916
-     * @throws \EE_Error
917
-     */
918
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
919
-    {
920
-        $model = $this->get_model();
921
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
922
-            ? $model->get_primary_key_field()->get_name()
923
-            : $field_to_order_by;
924
-        $current_value = ! empty($field) ? $this->get($field) : null;
925
-        if (empty($field) || empty($current_value)) {
926
-            return array();
927
-        }
928
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
929
-    }
930
-
931
-
932
-
933
-    /**
934
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
935
-     * matching the given query conditions.
936
-     *
937
-     * @param null  $field_to_order_by  What field is being used as the reference point.
938
-     * @param int   $limit              How many objects to return.
939
-     * @param array $query_params       Any additional conditions on the query.
940
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
941
-     *                                  you can indicate just the columns you want returned
942
-     * @return array|EE_Base_Class[]
943
-     * @throws \EE_Error
944
-     */
945
-    public function previous_x(
946
-        $field_to_order_by = null,
947
-        $limit = 1,
948
-        $query_params = array(),
949
-        $columns_to_select = null
950
-    ) {
951
-        $model = $this->get_model();
952
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
953
-            ? $model->get_primary_key_field()->get_name()
954
-            : $field_to_order_by;
955
-        $current_value = ! empty($field) ? $this->get($field) : null;
956
-        if (empty($field) || empty($current_value)) {
957
-            return array();
958
-        }
959
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
960
-    }
961
-
962
-
963
-
964
-    /**
965
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
966
-     * matching the given query conditions.
967
-     *
968
-     * @param null  $field_to_order_by  What field is being used as the reference point.
969
-     * @param array $query_params       Any additional conditions on the query.
970
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
971
-     *                                  you can indicate just the columns you want returned
972
-     * @return array|EE_Base_Class
973
-     * @throws \EE_Error
974
-     */
975
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
976
-    {
977
-        $model = $this->get_model();
978
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
979
-            ? $model->get_primary_key_field()->get_name()
980
-            : $field_to_order_by;
981
-        $current_value = ! empty($field) ? $this->get($field) : null;
982
-        if (empty($field) || empty($current_value)) {
983
-            return array();
984
-        }
985
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
986
-    }
987
-
988
-
989
-
990
-    /**
991
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
992
-     * matching the given query conditions.
993
-     *
994
-     * @param null  $field_to_order_by  What field is being used as the reference point.
995
-     * @param array $query_params       Any additional conditions on the query.
996
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
997
-     *                                  you can indicate just the column you want returned
998
-     * @return array|EE_Base_Class
999
-     * @throws \EE_Error
1000
-     */
1001
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1002
-    {
1003
-        $model = $this->get_model();
1004
-        $field = empty($field_to_order_by) && $model->has_primary_key_field()
1005
-            ? $model->get_primary_key_field()->get_name()
1006
-            : $field_to_order_by;
1007
-        $current_value = ! empty($field) ? $this->get($field) : null;
1008
-        if (empty($field) || empty($current_value)) {
1009
-            return array();
1010
-        }
1011
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1012
-    }
1013
-
1014
-
1015
-
1016
-    /**
1017
-     * Overrides parent because parent expects old models.
1018
-     * This also doesn't do any validation, and won't work for serialized arrays
1019
-     *
1020
-     * @param string $field_name
1021
-     * @param mixed  $field_value_from_db
1022
-     * @throws \EE_Error
1023
-     */
1024
-    public function set_from_db($field_name, $field_value_from_db)
1025
-    {
1026
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1027
-        if ($field_obj instanceof EE_Model_Field_Base) {
1028
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1029
-            //eg, a CPT model object could have an entry in the posts table, but no
1030
-            //entry in the meta table. Meaning that all its columns in the meta table
1031
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1032
-            if ($field_value_from_db === null) {
1033
-                if ($field_obj->is_nullable()) {
1034
-                    //if the field allows nulls, then let it be null
1035
-                    $field_value = null;
1036
-                } else {
1037
-                    $field_value = $field_obj->get_default_value();
1038
-                }
1039
-            } else {
1040
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1041
-            }
1042
-            $this->_fields[$field_name] = $field_value;
1043
-            $this->_clear_cached_property($field_name);
1044
-        }
1045
-    }
1046
-
1047
-
1048
-
1049
-    /**
1050
-     * verifies that the specified field is of the correct type
1051
-     *
1052
-     * @param string $field_name
1053
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1054
-     *                                (in cases where the same property may be used for different outputs
1055
-     *                                - i.e. datetime, money etc.)
1056
-     * @return mixed
1057
-     * @throws \EE_Error
1058
-     */
1059
-    public function get($field_name, $extra_cache_ref = null)
1060
-    {
1061
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1062
-    }
1063
-
1064
-
1065
-
1066
-    /**
1067
-     * This method simply returns the RAW unprocessed value for the given property in this class
1068
-     *
1069
-     * @param  string $field_name A valid fieldname
1070
-     * @return mixed              Whatever the raw value stored on the property is.
1071
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1072
-     */
1073
-    public function get_raw($field_name)
1074
-    {
1075
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1076
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1077
-            ? $this->_fields[$field_name]->format('U')
1078
-            : $this->_fields[$field_name];
1079
-    }
1080
-
1081
-
1082
-
1083
-    /**
1084
-     * This is used to return the internal DateTime object used for a field that is a
1085
-     * EE_Datetime_Field.
1086
-     *
1087
-     * @param string $field_name               The field name retrieving the DateTime object.
1088
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1089
-     * @throws \EE_Error
1090
-     *                                         an error is set and false returned.  If the field IS an
1091
-     *                                         EE_Datetime_Field and but the field value is null, then
1092
-     *                                         just null is returned (because that indicates that likely
1093
-     *                                         this field is nullable).
1094
-     */
1095
-    public function get_DateTime_object($field_name)
1096
-    {
1097
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1098
-        if ( ! $field_settings instanceof EE_Datetime_Field) {
1099
-            EE_Error::add_error(
1100
-                sprintf(
1101
-                    __(
1102
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1103
-                        'event_espresso'
1104
-                    ),
1105
-                    $field_name
1106
-                ),
1107
-                __FILE__,
1108
-                __FUNCTION__,
1109
-                __LINE__
1110
-            );
1111
-            return false;
1112
-        }
1113
-        return $this->_fields[$field_name];
1114
-    }
1115
-
1116
-
1117
-
1118
-    /**
1119
-     * To be used in template to immediately echo out the value, and format it for output.
1120
-     * Eg, should call stripslashes and whatnot before echoing
1121
-     *
1122
-     * @param string $field_name      the name of the field as it appears in the DB
1123
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1124
-     *                                (in cases where the same property may be used for different outputs
1125
-     *                                - i.e. datetime, money etc.)
1126
-     * @return void
1127
-     * @throws \EE_Error
1128
-     */
1129
-    public function e($field_name, $extra_cache_ref = null)
1130
-    {
1131
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1132
-    }
1133
-
1134
-
1135
-
1136
-    /**
1137
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1138
-     * can be easily used as the value of form input.
1139
-     *
1140
-     * @param string $field_name
1141
-     * @return void
1142
-     * @throws \EE_Error
1143
-     */
1144
-    public function f($field_name)
1145
-    {
1146
-        $this->e($field_name, 'form_input');
1147
-    }
1148
-
1149
-    /**
1150
-     * Same as `f()` but just returns the value instead of echoing it
1151
-     * @param string $field_name
1152
-     * @return string
1153
-     */
1154
-    public function get_f($field_name)
1155
-    {
1156
-        return (string)$this->get_pretty($field_name,'form_input');
1157
-    }
1158
-
1159
-
1160
-
1161
-    /**
1162
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1163
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1164
-     * to see what options are available.
1165
-     * @param string $field_name
1166
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1167
-     *                                (in cases where the same property may be used for different outputs
1168
-     *                                - i.e. datetime, money etc.)
1169
-     * @return mixed
1170
-     * @throws \EE_Error
1171
-     */
1172
-    public function get_pretty($field_name, $extra_cache_ref = null)
1173
-    {
1174
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1175
-    }
1176
-
1177
-
1178
-
1179
-    /**
1180
-     * This simply returns the datetime for the given field name
1181
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1182
-     * (and the equivalent e_date, e_time, e_datetime).
1183
-     *
1184
-     * @access   protected
1185
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1186
-     * @param string   $dt_frmt      valid datetime format used for date
1187
-     *                               (if '' then we just use the default on the field,
1188
-     *                               if NULL we use the last-used format)
1189
-     * @param string   $tm_frmt      Same as above except this is for time format
1190
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1191
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1192
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1193
-     *                               if field is not a valid dtt field, or void if echoing
1194
-     * @throws \EE_Error
1195
-     */
1196
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1197
-    {
1198
-        // clear cached property
1199
-        $this->_clear_cached_property($field_name);
1200
-        //reset format properties because they are used in get()
1201
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1202
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1203
-        if ($echo) {
1204
-            $this->e($field_name, $date_or_time);
1205
-            return '';
1206
-        }
1207
-        return $this->get($field_name, $date_or_time);
1208
-    }
1209
-
1210
-
1211
-
1212
-    /**
1213
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1214
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1215
-     * other echoes the pretty value for dtt)
1216
-     *
1217
-     * @param  string $field_name name of model object datetime field holding the value
1218
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1219
-     * @return string            datetime value formatted
1220
-     * @throws \EE_Error
1221
-     */
1222
-    public function get_date($field_name, $format = '')
1223
-    {
1224
-        return $this->_get_datetime($field_name, $format, null, 'D');
1225
-    }
1226
-
1227
-
1228
-
1229
-    /**
1230
-     * @param      $field_name
1231
-     * @param string $format
1232
-     * @throws \EE_Error
1233
-     */
1234
-    public function e_date($field_name, $format = '')
1235
-    {
1236
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1237
-    }
1238
-
1239
-
1240
-
1241
-    /**
1242
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1243
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1244
-     * other echoes the pretty value for dtt)
1245
-     *
1246
-     * @param  string $field_name name of model object datetime field holding the value
1247
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1248
-     * @return string             datetime value formatted
1249
-     * @throws \EE_Error
1250
-     */
1251
-    public function get_time($field_name, $format = '')
1252
-    {
1253
-        return $this->_get_datetime($field_name, null, $format, 'T');
1254
-    }
1255
-
1256
-
1257
-
1258
-    /**
1259
-     * @param      $field_name
1260
-     * @param string $format
1261
-     * @throws \EE_Error
1262
-     */
1263
-    public function e_time($field_name, $format = '')
1264
-    {
1265
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1266
-    }
1267
-
1268
-
1269
-
1270
-    /**
1271
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1272
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1273
-     * other echoes the pretty value for dtt)
1274
-     *
1275
-     * @param  string $field_name name of model object datetime field holding the value
1276
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1277
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1278
-     * @return string             datetime value formatted
1279
-     * @throws \EE_Error
1280
-     */
1281
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1282
-    {
1283
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1284
-    }
1285
-
1286
-
1287
-
1288
-    /**
1289
-     * @param string $field_name
1290
-     * @param string $dt_frmt
1291
-     * @param string $tm_frmt
1292
-     * @throws \EE_Error
1293
-     */
1294
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1295
-    {
1296
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1297
-    }
1298
-
1299
-
1300
-
1301
-    /**
1302
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1303
-     *
1304
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1305
-     * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1306
-     *                           on the object will be used.
1307
-     * @return string Date and time string in set locale or false if no field exists for the given
1308
-     * @throws \EE_Error
1309
-     *                           field name.
1310
-     */
1311
-    public function get_i18n_datetime($field_name, $format = '')
1312
-    {
1313
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1314
-        return date_i18n(
1315
-            $format,
1316
-            EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1317
-        );
1318
-    }
1319
-
1320
-
1321
-
1322
-    /**
1323
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1324
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1325
-     * thrown.
1326
-     *
1327
-     * @param  string $field_name The field name being checked
1328
-     * @throws EE_Error
1329
-     * @return EE_Datetime_Field
1330
-     */
1331
-    protected function _get_dtt_field_settings($field_name)
1332
-    {
1333
-        $field = $this->get_model()->field_settings_for($field_name);
1334
-        //check if field is dtt
1335
-        if ($field instanceof EE_Datetime_Field) {
1336
-            return $field;
1337
-        } else {
1338
-            throw new EE_Error(sprintf(__('The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1339
-                'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1340
-        }
1341
-    }
1342
-
1343
-
1344
-
1345
-
1346
-    /**
1347
-     * NOTE ABOUT BELOW:
1348
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1349
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1350
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1351
-     * method and make sure you send the entire datetime value for setting.
1352
-     */
1353
-    /**
1354
-     * sets the time on a datetime property
1355
-     *
1356
-     * @access protected
1357
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1358
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1359
-     * @throws \EE_Error
1360
-     */
1361
-    protected function _set_time_for($time, $fieldname)
1362
-    {
1363
-        $this->_set_date_time('T', $time, $fieldname);
1364
-    }
1365
-
1366
-
1367
-
1368
-    /**
1369
-     * sets the date on a datetime property
1370
-     *
1371
-     * @access protected
1372
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1373
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1374
-     * @throws \EE_Error
1375
-     */
1376
-    protected function _set_date_for($date, $fieldname)
1377
-    {
1378
-        $this->_set_date_time('D', $date, $fieldname);
1379
-    }
1380
-
1381
-
1382
-
1383
-    /**
1384
-     * This takes care of setting a date or time independently on a given model object property. This method also
1385
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1386
-     *
1387
-     * @access protected
1388
-     * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1389
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1390
-     * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1391
-     *                                        EE_Datetime_Field property)
1392
-     * @throws \EE_Error
1393
-     */
1394
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1395
-    {
1396
-        $field = $this->_get_dtt_field_settings($fieldname);
1397
-        $field->set_timezone($this->_timezone);
1398
-        $field->set_date_format($this->_dt_frmt);
1399
-        $field->set_time_format($this->_tm_frmt);
1400
-        switch ($what) {
1401
-            case 'T' :
1402
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1403
-                    $datetime_value,
1404
-                    $this->_fields[$fieldname]
1405
-                );
1406
-                break;
1407
-            case 'D' :
1408
-                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1409
-                    $datetime_value,
1410
-                    $this->_fields[$fieldname]
1411
-                );
1412
-                break;
1413
-            case 'B' :
1414
-                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1415
-                break;
1416
-        }
1417
-        $this->_clear_cached_property($fieldname);
1418
-    }
1419
-
1420
-
1421
-
1422
-    /**
1423
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1424
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1425
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1426
-     * that could lead to some unexpected results!
1427
-     *
1428
-     * @access public
1429
-     * @param string               $field_name This is the name of the field on the object that contains the date/time
1430
-     *                                         value being returned.
1431
-     * @param string               $callback   must match a valid method in this class (defaults to get_datetime)
1432
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1433
-     * @param string               $prepend    You can include something to prepend on the timestamp
1434
-     * @param string               $append     You can include something to append on the timestamp
1435
-     * @throws EE_Error
1436
-     * @return string timestamp
1437
-     */
1438
-    public function display_in_my_timezone(
1439
-        $field_name,
1440
-        $callback = 'get_datetime',
1441
-        $args = null,
1442
-        $prepend = '',
1443
-        $append = ''
1444
-    ) {
1445
-        $timezone = EEH_DTT_Helper::get_timezone();
1446
-        if ($timezone === $this->_timezone) {
1447
-            return '';
1448
-        }
1449
-        $original_timezone = $this->_timezone;
1450
-        $this->set_timezone($timezone);
1451
-        $fn = (array)$field_name;
1452
-        $args = array_merge($fn, (array)$args);
1453
-        if ( ! method_exists($this, $callback)) {
1454
-            throw new EE_Error(
1455
-                sprintf(
1456
-                    __(
1457
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1458
-                        'event_espresso'
1459
-                    ),
1460
-                    $callback
1461
-                )
1462
-            );
1463
-        }
1464
-        $args = (array)$args;
1465
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1466
-        $this->set_timezone($original_timezone);
1467
-        return $return;
1468
-    }
1469
-
1470
-
1471
-
1472
-    /**
1473
-     * Deletes this model object.
1474
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1475
-     * override
1476
-     * `EE_Base_Class::_delete` NOT this class.
1477
-     *
1478
-     * @return boolean | int
1479
-     * @throws \EE_Error
1480
-     */
1481
-    public function delete()
1482
-    {
1483
-        /**
1484
-         * Called just before the `EE_Base_Class::_delete` method call.
1485
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1486
-         * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1487
-         * soft deletes (trash) the object and does not permanently delete it.
1488
-         *
1489
-         * @param EE_Base_Class $model_object about to be 'deleted'
1490
-         */
1491
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1492
-        $result = $this->_delete();
1493
-        /**
1494
-         * Called just after the `EE_Base_Class::_delete` method call.
1495
-         * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1496
-         * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1497
-         * soft deletes (trash) the object and does not permanently delete it.
1498
-         *
1499
-         * @param EE_Base_Class $model_object that was just 'deleted'
1500
-         * @param boolean       $result
1501
-         */
1502
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1503
-        return $result;
1504
-    }
1505
-
1506
-
1507
-
1508
-    /**
1509
-     * Calls the specific delete method for the instantiated class.
1510
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1511
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1512
-     * `EE_Base_Class::delete`
1513
-     *
1514
-     * @return bool|int
1515
-     * @throws \EE_Error
1516
-     */
1517
-    protected function _delete()
1518
-    {
1519
-        return $this->delete_permanently();
1520
-    }
1521
-
1522
-
1523
-
1524
-    /**
1525
-     * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1526
-     * error)
1527
-     *
1528
-     * @return bool | int
1529
-     * @throws \EE_Error
1530
-     */
1531
-    public function delete_permanently()
1532
-    {
1533
-        /**
1534
-         * Called just before HARD deleting a model object
1535
-         *
1536
-         * @param EE_Base_Class $model_object about to be 'deleted'
1537
-         */
1538
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1539
-        $model = $this->get_model();
1540
-        $result = $model->delete_permanently_by_ID($this->ID());
1541
-        $this->refresh_cache_of_related_objects();
1542
-        /**
1543
-         * Called just after HARD deleting a model object
1544
-         *
1545
-         * @param EE_Base_Class $model_object that was just 'deleted'
1546
-         * @param boolean       $result
1547
-         */
1548
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1549
-        return $result;
1550
-    }
1551
-
1552
-
1553
-
1554
-    /**
1555
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1556
-     * related model objects
1557
-     *
1558
-     * @throws \EE_Error
1559
-     */
1560
-    public function refresh_cache_of_related_objects()
1561
-    {
1562
-        $model = $this->get_model();
1563
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1564
-            if ( ! empty($this->_model_relations[$relation_name])) {
1565
-                $related_objects = $this->_model_relations[$relation_name];
1566
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1567
-                    //this relation only stores a single model object, not an array
1568
-                    //but let's make it consistent
1569
-                    $related_objects = array($related_objects);
1570
-                }
1571
-                foreach ($related_objects as $related_object) {
1572
-                    //only refresh their cache if they're in memory
1573
-                    if ($related_object instanceof EE_Base_Class) {
1574
-                        $related_object->clear_cache($model->get_this_model_name(), $this);
1575
-                    }
1576
-                }
1577
-            }
1578
-        }
1579
-    }
1580
-
1581
-
1582
-
1583
-    /**
1584
-     *        Saves this object to the database. An array may be supplied to set some values on this
1585
-     * object just before saving.
1586
-     *
1587
-     * @access public
1588
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1589
-     *                                 if provided during the save() method (often client code will change the fields'
1590
-     *                                 values before calling save)
1591
-     * @throws \EE_Error
1592
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1593
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1594
-     */
1595
-    public function save($set_cols_n_values = array())
1596
-    {
1597
-        $model = $this->get_model();
1598
-        /**
1599
-         * Filters the fields we're about to save on the model object
1600
-         *
1601
-         * @param array         $set_cols_n_values
1602
-         * @param EE_Base_Class $model_object
1603
-         */
1604
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1605
-            $this);
1606
-        //set attributes as provided in $set_cols_n_values
1607
-        foreach ($set_cols_n_values as $column => $value) {
1608
-            $this->set($column, $value);
1609
-        }
1610
-        // no changes ? then don't do anything
1611
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1612
-            return 0;
1613
-        }
1614
-        /**
1615
-         * Saving a model object.
1616
-         * Before we perform a save, this action is fired.
1617
-         *
1618
-         * @param EE_Base_Class $model_object the model object about to be saved.
1619
-         */
1620
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1621
-        if ( ! $this->allow_persist()) {
1622
-            return 0;
1623
-        }
1624
-        //now get current attribute values
1625
-        $save_cols_n_values = $this->_fields;
1626
-        //if the object already has an ID, update it. Otherwise, insert it
1627
-        //also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1628
-        $old_assumption_concerning_value_preparation = $model
1629
-                                                            ->get_assumption_concerning_values_already_prepared_by_model_object();
1630
-        $model->assume_values_already_prepared_by_model_object(true);
1631
-        //does this model have an autoincrement PK?
1632
-        if ($model->has_primary_key_field()) {
1633
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1634
-                //ok check if it's set, if so: update; if not, insert
1635
-                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1636
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1637
-                } else {
1638
-                    unset($save_cols_n_values[$model->primary_key_name()]);
1639
-                    $results = $model->insert($save_cols_n_values);
1640
-                    if ($results) {
1641
-                        //if successful, set the primary key
1642
-                        //but don't use the normal SET method, because it will check if
1643
-                        //an item with the same ID exists in the mapper & db, then
1644
-                        //will find it in the db (because we just added it) and THAT object
1645
-                        //will get added to the mapper before we can add this one!
1646
-                        //but if we just avoid using the SET method, all that headache can be avoided
1647
-                        $pk_field_name = $model->primary_key_name();
1648
-                        $this->_fields[$pk_field_name] = $results;
1649
-                        $this->_clear_cached_property($pk_field_name);
1650
-                        $model->add_to_entity_map($this);
1651
-                        $this->_update_cached_related_model_objs_fks();
1652
-                    }
1653
-                }
1654
-            } else {//PK is NOT auto-increment
1655
-                //so check if one like it already exists in the db
1656
-                if ($model->exists_by_ID($this->ID())) {
1657
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1658
-                        throw new EE_Error(
1659
-                            sprintf(
1660
-                                __('Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1661
-                                    'event_espresso'),
1662
-                                get_class($this),
1663
-                                get_class($model) . '::instance()->add_to_entity_map()',
1664
-                                get_class($model) . '::instance()->get_one_by_ID()',
1665
-                                '<br />'
1666
-                            )
1667
-                        );
1668
-                    }
1669
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1670
-                } else {
1671
-                    $results = $model->insert($save_cols_n_values);
1672
-                    $this->_update_cached_related_model_objs_fks();
1673
-                }
1674
-            }
1675
-        } else {//there is NO primary key
1676
-            $already_in_db = false;
1677
-            foreach ($model->unique_indexes() as $index) {
1678
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1679
-                if ($model->exists(array($uniqueness_where_params))) {
1680
-                    $already_in_db = true;
1681
-                }
1682
-            }
1683
-            if ($already_in_db) {
1684
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1685
-                    $model->get_combined_primary_key_fields());
1686
-                $results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1687
-            } else {
1688
-                $results = $model->insert($save_cols_n_values);
1689
-            }
1690
-        }
1691
-        //restore the old assumption about values being prepared by the model object
1692
-        $model
1693
-             ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1694
-        /**
1695
-         * After saving the model object this action is called
1696
-         *
1697
-         * @param EE_Base_Class $model_object which was just saved
1698
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1699
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1700
-         */
1701
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1702
-        $this->_has_changes = false;
1703
-        return $results;
1704
-    }
1705
-
1706
-
1707
-
1708
-    /**
1709
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1710
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1711
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1712
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1713
-     * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1714
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1715
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1716
-     *
1717
-     * @return void
1718
-     * @throws \EE_Error
1719
-     */
1720
-    protected function _update_cached_related_model_objs_fks()
1721
-    {
1722
-        $model = $this->get_model();
1723
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1724
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1725
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1726
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1727
-                        $model->get_this_model_name()
1728
-                    );
1729
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1730
-                    if ($related_model_obj_in_cache->ID()) {
1731
-                        $related_model_obj_in_cache->save();
1732
-                    }
1733
-                }
1734
-            }
1735
-        }
1736
-    }
1737
-
1738
-
1739
-
1740
-    /**
1741
-     * Saves this model object and its NEW cached relations to the database.
1742
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1743
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1744
-     * because otherwise, there's a potential for infinite looping of saving
1745
-     * Saves the cached related model objects, and ensures the relation between them
1746
-     * and this object and properly setup
1747
-     *
1748
-     * @return int ID of new model object on save; 0 on failure+
1749
-     * @throws \EE_Error
1750
-     */
1751
-    public function save_new_cached_related_model_objs()
1752
-    {
1753
-        //make sure this has been saved
1754
-        if ( ! $this->ID()) {
1755
-            $id = $this->save();
1756
-        } else {
1757
-            $id = $this->ID();
1758
-        }
1759
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1760
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1761
-            if ($this->_model_relations[$relationName]) {
1762
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1763
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1764
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1765
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1766
-                    //but ONLY if it DOES NOT exist in the DB
1767
-                    /* @var $related_model_obj EE_Base_Class */
1768
-                    $related_model_obj = $this->_model_relations[$relationName];
1769
-                    //					if( ! $related_model_obj->ID()){
1770
-                    $this->_add_relation_to($related_model_obj, $relationName);
1771
-                    $related_model_obj->save_new_cached_related_model_objs();
1772
-                    //					}
1773
-                } else {
1774
-                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1775
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
1776
-                        //but ONLY if it DOES NOT exist in the DB
1777
-                        //						if( ! $related_model_obj->ID()){
1778
-                        $this->_add_relation_to($related_model_obj, $relationName);
1779
-                        $related_model_obj->save_new_cached_related_model_objs();
1780
-                        //						}
1781
-                    }
1782
-                }
1783
-            }
1784
-        }
1785
-        return $id;
1786
-    }
1787
-
1788
-
1789
-
1790
-    /**
1791
-     * for getting a model while instantiated.
1792
-     *
1793
-     * @return \EEM_Base | \EEM_CPT_Base
1794
-     */
1795
-    public function get_model()
1796
-    {
1797
-        if( ! $this->_model){
1798
-            $modelName = self::_get_model_classname(get_class($this));
1799
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1800
-        } else {
1801
-            $this->_model->set_timezone($this->_timezone);
1802
-        }
1803
-
1804
-        return $this->_model;
1805
-    }
1806
-
1807
-
1808
-
1809
-    /**
1810
-     * @param $props_n_values
1811
-     * @param $classname
1812
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1813
-     * @throws \EE_Error
1814
-     */
1815
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1816
-    {
1817
-        //TODO: will not work for Term_Relationships because they have no PK!
1818
-        $primary_id_ref = self::_get_primary_key_name($classname);
1819
-        if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1820
-            $id = $props_n_values[$primary_id_ref];
1821
-            return self::_get_model($classname)->get_from_entity_map($id);
1822
-        }
1823
-        return false;
1824
-    }
1825
-
1826
-
1827
-
1828
-    /**
1829
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1830
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1831
-     * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
1832
-     * we return false.
1833
-     *
1834
-     * @param  array  $props_n_values   incoming array of properties and their values
1835
-     * @param  string $classname        the classname of the child class
1836
-     * @param null    $timezone
1837
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
1838
-     *                                  date_format and the second value is the time format
1839
-     * @return mixed (EE_Base_Class|bool)
1840
-     * @throws \EE_Error
1841
-     */
1842
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1843
-    {
1844
-        $existing = null;
1845
-        $model = self::_get_model($classname, $timezone);
1846
-        if ($model->has_primary_key_field()) {
1847
-            $primary_id_ref = self::_get_primary_key_name($classname);
1848
-            if (array_key_exists($primary_id_ref, $props_n_values)
1849
-                && ! empty($props_n_values[$primary_id_ref])
1850
-            ) {
1851
-                $existing = $model->get_one_by_ID(
1852
-                    $props_n_values[$primary_id_ref]
1853
-                );
1854
-            }
1855
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1856
-            //no primary key on this model, but there's still a matching item in the DB
1857
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1858
-                self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1859
-            );
1860
-        }
1861
-        if ($existing) {
1862
-            //set date formats if present before setting values
1863
-            if ( ! empty($date_formats) && is_array($date_formats)) {
1864
-                $existing->set_date_format($date_formats[0]);
1865
-                $existing->set_time_format($date_formats[1]);
1866
-            } else {
1867
-                //set default formats for date and time
1868
-                $existing->set_date_format(get_option('date_format'));
1869
-                $existing->set_time_format(get_option('time_format'));
1870
-            }
1871
-            foreach ($props_n_values as $property => $field_value) {
1872
-                $existing->set($property, $field_value);
1873
-            }
1874
-            return $existing;
1875
-        } else {
1876
-            return false;
1877
-        }
1878
-    }
1879
-
1880
-
1881
-
1882
-    /**
1883
-     * Gets the EEM_*_Model for this class
1884
-     *
1885
-     * @access public now, as this is more convenient
1886
-     * @param      $classname
1887
-     * @param null $timezone
1888
-     * @throws EE_Error
1889
-     * @return EEM_Base
1890
-     */
1891
-    protected static function _get_model($classname, $timezone = null)
1892
-    {
1893
-        //find model for this class
1894
-        if ( ! $classname) {
1895
-            throw new EE_Error(
1896
-                sprintf(
1897
-                    __(
1898
-                        "What were you thinking calling _get_model(%s)?? You need to specify the class name",
1899
-                        "event_espresso"
1900
-                    ),
1901
-                    $classname
1902
-                )
1903
-            );
1904
-        }
1905
-        $modelName = self::_get_model_classname($classname);
1906
-        return self::_get_model_instance_with_name($modelName, $timezone);
1907
-    }
1908
-
1909
-
1910
-
1911
-    /**
1912
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
1913
-     *
1914
-     * @param string $model_classname
1915
-     * @param null   $timezone
1916
-     * @return EEM_Base
1917
-     */
1918
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
1919
-    {
1920
-        $model_classname = str_replace('EEM_', '', $model_classname);
1921
-        $model = EE_Registry::instance()->load_model($model_classname);
1922
-        $model->set_timezone($timezone);
1923
-        return $model;
1924
-    }
1925
-
1926
-
1927
-
1928
-    /**
1929
-     * If a model name is provided (eg Registration), gets the model classname for that model.
1930
-     * Also works if a model class's classname is provided (eg EE_Registration).
1931
-     *
1932
-     * @param null $model_name
1933
-     * @return string like EEM_Attendee
1934
-     */
1935
-    private static function _get_model_classname($model_name = null)
1936
-    {
1937
-        if (strpos($model_name, "EE_") === 0) {
1938
-            $model_classname = str_replace("EE_", "EEM_", $model_name);
1939
-        } else {
1940
-            $model_classname = "EEM_" . $model_name;
1941
-        }
1942
-        return $model_classname;
1943
-    }
1944
-
1945
-
1946
-
1947
-    /**
1948
-     * returns the name of the primary key attribute
1949
-     *
1950
-     * @param null $classname
1951
-     * @throws EE_Error
1952
-     * @return string
1953
-     */
1954
-    protected static function _get_primary_key_name($classname = null)
1955
-    {
1956
-        if ( ! $classname) {
1957
-            throw new EE_Error(
1958
-                sprintf(
1959
-                    __("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
1960
-                    $classname
1961
-                )
1962
-            );
1963
-        }
1964
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
1965
-    }
1966
-
1967
-
1968
-
1969
-    /**
1970
-     * Gets the value of the primary key.
1971
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
1972
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
1973
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
1974
-     *
1975
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
1976
-     * @throws \EE_Error
1977
-     */
1978
-    public function ID()
1979
-    {
1980
-        $model = $this->get_model();
1981
-        //now that we know the name of the variable, use a variable variable to get its value and return its
1982
-        if ($model->has_primary_key_field()) {
1983
-            return $this->_fields[$model->primary_key_name()];
1984
-        } else {
1985
-            return $model->get_index_primary_key_string($this->_fields);
1986
-        }
1987
-    }
1988
-
1989
-
1990
-
1991
-    /**
1992
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
1993
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
1994
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
1995
-     *
1996
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
1997
-     * @param string $relationName                     eg 'Events','Question',etc.
1998
-     *                                                 an attendee to a group, you also want to specify which role they
1999
-     *                                                 will have in that group. So you would use this parameter to
2000
-     *                                                 specify array('role-column-name'=>'role-id')
2001
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2002
-     *                                                 allow you to further constrict the relation to being added.
2003
-     *                                                 However, keep in mind that the columns (keys) given must match a
2004
-     *                                                 column on the JOIN table and currently only the HABTM models
2005
-     *                                                 accept these additional conditions.  Also remember that if an
2006
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2007
-     *                                                 NEW row is created in the join table.
2008
-     * @param null   $cache_id
2009
-     * @throws EE_Error
2010
-     * @return EE_Base_Class the object the relation was added to
2011
-     */
2012
-    public function _add_relation_to(
2013
-        $otherObjectModelObjectOrID,
2014
-        $relationName,
2015
-        $extra_join_model_fields_n_values = array(),
2016
-        $cache_id = null
2017
-    ) {
2018
-        $model = $this->get_model();
2019
-        //if this thing exists in the DB, save the relation to the DB
2020
-        if ($this->ID()) {
2021
-            $otherObject = $model
2022
-                                ->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2023
-                                    $extra_join_model_fields_n_values);
2024
-            //clear cache so future get_many_related and get_first_related() return new results.
2025
-            $this->clear_cache($relationName, $otherObject, true);
2026
-            if ($otherObject instanceof EE_Base_Class) {
2027
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2028
-            }
2029
-        } else {
2030
-            //this thing doesn't exist in the DB,  so just cache it
2031
-            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2032
-                throw new EE_Error(sprintf(
2033
-                    __('Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2034
-                        'event_espresso'),
2035
-                    $otherObjectModelObjectOrID,
2036
-                    get_class($this)
2037
-                ));
2038
-            } else {
2039
-                $otherObject = $otherObjectModelObjectOrID;
2040
-            }
2041
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2042
-        }
2043
-        if ($otherObject instanceof EE_Base_Class) {
2044
-            //fix the reciprocal relation too
2045
-            if ($otherObject->ID()) {
2046
-                //its saved so assumed relations exist in the DB, so we can just
2047
-                //clear the cache so future queries use the updated info in the DB
2048
-                $otherObject->clear_cache($model->get_this_model_name(), null, true);
2049
-            } else {
2050
-                //it's not saved, so it caches relations like this
2051
-                $otherObject->cache($model->get_this_model_name(), $this);
2052
-            }
2053
-        }
2054
-        return $otherObject;
2055
-    }
2056
-
2057
-
2058
-
2059
-    /**
2060
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2061
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2062
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2063
-     * from the cache
2064
-     *
2065
-     * @param mixed  $otherObjectModelObjectOrID
2066
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2067
-     *                to the DB yet
2068
-     * @param string $relationName
2069
-     * @param array  $where_query
2070
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2071
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2072
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2073
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2074
-     *                created in the join table.
2075
-     * @return EE_Base_Class the relation was removed from
2076
-     * @throws \EE_Error
2077
-     */
2078
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2079
-    {
2080
-        if ($this->ID()) {
2081
-            //if this exists in the DB, save the relation change to the DB too
2082
-            $otherObject = $this->get_model()
2083
-                                ->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2084
-                                    $where_query);
2085
-            $this->clear_cache($relationName, $otherObject);
2086
-        } else {
2087
-            //this doesn't exist in the DB, just remove it from the cache
2088
-            $otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2089
-        }
2090
-        if ($otherObject instanceof EE_Base_Class) {
2091
-            $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2092
-        }
2093
-        return $otherObject;
2094
-    }
2095
-
2096
-
2097
-
2098
-    /**
2099
-     * Removes ALL the related things for the $relationName.
2100
-     *
2101
-     * @param string $relationName
2102
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2103
-     * @return EE_Base_Class
2104
-     * @throws \EE_Error
2105
-     */
2106
-    public function _remove_relations($relationName, $where_query_params = array())
2107
-    {
2108
-        if ($this->ID()) {
2109
-            //if this exists in the DB, save the relation change to the DB too
2110
-            $otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2111
-            $this->clear_cache($relationName, null, true);
2112
-        } else {
2113
-            //this doesn't exist in the DB, just remove it from the cache
2114
-            $otherObjects = $this->clear_cache($relationName, null, true);
2115
-        }
2116
-        if (is_array($otherObjects)) {
2117
-            foreach ($otherObjects as $otherObject) {
2118
-                $otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2119
-            }
2120
-        }
2121
-        return $otherObjects;
2122
-    }
2123
-
2124
-
2125
-
2126
-    /**
2127
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2128
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2129
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2130
-     * because we want to get even deleted items etc.
2131
-     *
2132
-     * @param string $relationName key in the model's _model_relations array
2133
-     * @param array  $query_params like EEM_Base::get_all
2134
-     * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2135
-     * @throws \EE_Error
2136
-     *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2137
-     *                             you want IDs
2138
-     */
2139
-    public function get_many_related($relationName, $query_params = array())
2140
-    {
2141
-        if ($this->ID()) {
2142
-            //this exists in the DB, so get the related things from either the cache or the DB
2143
-            //if there are query parameters, forget about caching the related model objects.
2144
-            if ($query_params) {
2145
-                $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2146
-            } else {
2147
-                //did we already cache the result of this query?
2148
-                $cached_results = $this->get_all_from_cache($relationName);
2149
-                if ( ! $cached_results) {
2150
-                    $related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2151
-                    //if no query parameters were passed, then we got all the related model objects
2152
-                    //for that relation. We can cache them then.
2153
-                    foreach ($related_model_objects as $related_model_object) {
2154
-                        $this->cache($relationName, $related_model_object);
2155
-                    }
2156
-                } else {
2157
-                    $related_model_objects = $cached_results;
2158
-                }
2159
-            }
2160
-        } else {
2161
-            //this doesn't exist in the DB, so just get the related things from the cache
2162
-            $related_model_objects = $this->get_all_from_cache($relationName);
2163
-        }
2164
-        return $related_model_objects;
2165
-    }
2166
-
2167
-
2168
-
2169
-    /**
2170
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2171
-     * unless otherwise specified in the $query_params
2172
-     *
2173
-     * @param string $relation_name  model_name like 'Event', or 'Registration'
2174
-     * @param array  $query_params   like EEM_Base::get_all's
2175
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2176
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2177
-     *                               that by the setting $distinct to TRUE;
2178
-     * @return int
2179
-     */
2180
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2181
-    {
2182
-        return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2183
-    }
2184
-
2185
-
2186
-
2187
-    /**
2188
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2189
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2190
-     *
2191
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2192
-     * @param array  $query_params  like EEM_Base::get_all's
2193
-     * @param string $field_to_sum  name of field to count by.
2194
-     *                              By default, uses primary key (which doesn't make much sense, so you should probably
2195
-     *                              change it)
2196
-     * @return int
2197
-     */
2198
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2199
-    {
2200
-        return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2201
-    }
2202
-
2203
-
2204
-
2205
-    /**
2206
-     * Gets the first (ie, one) related model object of the specified type.
2207
-     *
2208
-     * @param string $relationName key in the model's _model_relations array
2209
-     * @param array  $query_params like EEM_Base::get_all
2210
-     * @return EE_Base_Class (not an array, a single object)
2211
-     * @throws \EE_Error
2212
-     */
2213
-    public function get_first_related($relationName, $query_params = array())
2214
-    {
2215
-        $model = $this->get_model();
2216
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2217
-            //if they've provided some query parameters, don't bother trying to cache the result
2218
-            //also make sure we're not caching the result of get_first_related
2219
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2220
-            if ($query_params
2221
-                || ! $model->related_settings_for($relationName)
2222
-                     instanceof
2223
-                     EE_Belongs_To_Relation
2224
-            ) {
2225
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2226
-            } else {
2227
-                //first, check if we've already cached the result of this query
2228
-                $cached_result = $this->get_one_from_cache($relationName);
2229
-                if ( ! $cached_result) {
2230
-                    $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2231
-                    $this->cache($relationName, $related_model_object);
2232
-                } else {
2233
-                    $related_model_object = $cached_result;
2234
-                }
2235
-            }
2236
-        } else {
2237
-            $related_model_object = null;
2238
-            //this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2239
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2240
-                $related_model_object = $model->get_first_related($this, $relationName, $query_params);
2241
-            }
2242
-            //this doesn't exist in the DB and apparently the thing it belongs to doesn't either, just get what's cached on this object
2243
-            if ( ! $related_model_object) {
2244
-                $related_model_object = $this->get_one_from_cache($relationName);
2245
-            }
2246
-        }
2247
-        return $related_model_object;
2248
-    }
2249
-
2250
-
2251
-
2252
-    /**
2253
-     * Does a delete on all related objects of type $relationName and removes
2254
-     * the current model object's relation to them. If they can't be deleted (because
2255
-     * of blocking related model objects) does nothing. If the related model objects are
2256
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2257
-     * If this model object doesn't exist yet in the DB, just removes its related things
2258
-     *
2259
-     * @param string $relationName
2260
-     * @param array  $query_params like EEM_Base::get_all's
2261
-     * @return int how many deleted
2262
-     * @throws \EE_Error
2263
-     */
2264
-    public function delete_related($relationName, $query_params = array())
2265
-    {
2266
-        if ($this->ID()) {
2267
-            $count = $this->get_model()->delete_related($this, $relationName, $query_params);
2268
-        } else {
2269
-            $count = count($this->get_all_from_cache($relationName));
2270
-            $this->clear_cache($relationName, null, true);
2271
-        }
2272
-        return $count;
2273
-    }
2274
-
2275
-
2276
-
2277
-    /**
2278
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2279
-     * the current model object's relation to them. If they can't be deleted (because
2280
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2281
-     * If the related thing isn't a soft-deletable model object, this function is identical
2282
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2283
-     *
2284
-     * @param string $relationName
2285
-     * @param array  $query_params like EEM_Base::get_all's
2286
-     * @return int how many deleted (including those soft deleted)
2287
-     * @throws \EE_Error
2288
-     */
2289
-    public function delete_related_permanently($relationName, $query_params = array())
2290
-    {
2291
-        if ($this->ID()) {
2292
-            $count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2293
-        } else {
2294
-            $count = count($this->get_all_from_cache($relationName));
2295
-        }
2296
-        $this->clear_cache($relationName, null, true);
2297
-        return $count;
2298
-    }
2299
-
2300
-
2301
-
2302
-    /**
2303
-     * is_set
2304
-     * Just a simple utility function children can use for checking if property exists
2305
-     *
2306
-     * @access  public
2307
-     * @param  string $field_name property to check
2308
-     * @return bool                              TRUE if existing,FALSE if not.
2309
-     */
2310
-    public function is_set($field_name)
2311
-    {
2312
-        return isset($this->_fields[$field_name]);
2313
-    }
2314
-
2315
-
2316
-
2317
-    /**
2318
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2319
-     * EE_Error exception if they don't
2320
-     *
2321
-     * @param  mixed (string|array) $properties properties to check
2322
-     * @throws EE_Error
2323
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2324
-     */
2325
-    protected function _property_exists($properties)
2326
-    {
2327
-        foreach ((array)$properties as $property_name) {
2328
-            //first make sure this property exists
2329
-            if ( ! $this->_fields[$property_name]) {
2330
-                throw new EE_Error(
2331
-                    sprintf(
2332
-                        __(
2333
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2334
-                            'event_espresso'
2335
-                        ),
2336
-                        $property_name
2337
-                    )
2338
-                );
2339
-            }
2340
-        }
2341
-        return true;
2342
-    }
2343
-
2344
-
2345
-
2346
-    /**
2347
-     * This simply returns an array of model fields for this object
2348
-     *
2349
-     * @return array
2350
-     * @throws \EE_Error
2351
-     */
2352
-    public function model_field_array()
2353
-    {
2354
-        $fields = $this->get_model()->field_settings(false);
2355
-        $properties = array();
2356
-        //remove prepended underscore
2357
-        foreach ($fields as $field_name => $settings) {
2358
-            $properties[$field_name] = $this->get($field_name);
2359
-        }
2360
-        return $properties;
2361
-    }
2362
-
2363
-
2364
-
2365
-    /**
2366
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2367
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2368
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2369
-     * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2370
-     * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2371
-     * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2372
-     * was called, and an array of the original arguments passed to the function. Whatever their callback function
2373
-     * returns will be returned by this function. Example: in functions.php (or in a plugin):
2374
-     * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2375
-     * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2376
-     * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2377
-     *        return $previousReturnValue.$returnString;
2378
-     * }
2379
-     * require('EE_Answer.class.php');
2380
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2381
-     * echo $answer->my_callback('monkeys',100);
2382
-     * //will output "you called my_callback! and passed args:monkeys,100"
2383
-     *
2384
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2385
-     * @param array  $args       array of original arguments passed to the function
2386
-     * @throws EE_Error
2387
-     * @return mixed whatever the plugin which calls add_filter decides
2388
-     */
2389
-    public function __call($methodName, $args)
2390
-    {
2391
-        $className = get_class($this);
2392
-        $tagName = "FHEE__{$className}__{$methodName}";
2393
-        if ( ! has_filter($tagName)) {
2394
-            throw new EE_Error(
2395
-                sprintf(
2396
-                    __(
2397
-                        "Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2398
-                        "event_espresso"
2399
-                    ),
2400
-                    $methodName,
2401
-                    $className,
2402
-                    $tagName
2403
-                )
2404
-            );
2405
-        }
2406
-        return apply_filters($tagName, null, $this, $args);
2407
-    }
2408
-
2409
-
2410
-
2411
-    /**
2412
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2413
-     * A $previous_value can be specified in case there are many meta rows with the same key
2414
-     *
2415
-     * @param string $meta_key
2416
-     * @param mixed  $meta_value
2417
-     * @param mixed  $previous_value
2418
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2419
-     * @throws \EE_Error
2420
-     * NOTE: if the values haven't changed, returns 0
2421
-     */
2422
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2423
-    {
2424
-        $query_params = array(
2425
-            array(
2426
-                'EXM_key'  => $meta_key,
2427
-                'OBJ_ID'   => $this->ID(),
2428
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2429
-            ),
2430
-        );
2431
-        if ($previous_value !== null) {
2432
-            $query_params[0]['EXM_value'] = $meta_value;
2433
-        }
2434
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2435
-        if ( ! $existing_rows_like_that) {
2436
-            return $this->add_extra_meta($meta_key, $meta_value);
2437
-        }
2438
-        foreach ($existing_rows_like_that as $existing_row) {
2439
-            $existing_row->save(array('EXM_value' => $meta_value));
2440
-        }
2441
-        return count($existing_rows_like_that);
2442
-    }
2443
-
2444
-
2445
-
2446
-    /**
2447
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2448
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2449
-     * extra meta row was entered, false if not
2450
-     *
2451
-     * @param string  $meta_key
2452
-     * @param mixed   $meta_value
2453
-     * @param boolean $unique
2454
-     * @return boolean
2455
-     * @throws \EE_Error
2456
-     */
2457
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2458
-    {
2459
-        if ($unique) {
2460
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2461
-                array(
2462
-                    array(
2463
-                        'EXM_key'  => $meta_key,
2464
-                        'OBJ_ID'   => $this->ID(),
2465
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2466
-                    ),
2467
-                )
2468
-            );
2469
-            if ($existing_extra_meta) {
2470
-                return false;
2471
-            }
2472
-        }
2473
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2474
-            array(
2475
-                'EXM_key'   => $meta_key,
2476
-                'EXM_value' => $meta_value,
2477
-                'OBJ_ID'    => $this->ID(),
2478
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2479
-            )
2480
-        );
2481
-        $new_extra_meta->save();
2482
-        return true;
2483
-    }
2484
-
2485
-
2486
-
2487
-    /**
2488
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2489
-     * is specified, only deletes extra meta records with that value.
2490
-     *
2491
-     * @param string $meta_key
2492
-     * @param mixed  $meta_value
2493
-     * @return int number of extra meta rows deleted
2494
-     * @throws \EE_Error
2495
-     */
2496
-    public function delete_extra_meta($meta_key, $meta_value = null)
2497
-    {
2498
-        $query_params = array(
2499
-            array(
2500
-                'EXM_key'  => $meta_key,
2501
-                'OBJ_ID'   => $this->ID(),
2502
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2503
-            ),
2504
-        );
2505
-        if ($meta_value !== null) {
2506
-            $query_params[0]['EXM_value'] = $meta_value;
2507
-        }
2508
-        return EEM_Extra_Meta::instance()->delete($query_params);
2509
-    }
2510
-
2511
-
2512
-
2513
-    /**
2514
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2515
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2516
-     * You can specify $default is case you haven't found the extra meta
2517
-     *
2518
-     * @param string  $meta_key
2519
-     * @param boolean $single
2520
-     * @param mixed   $default if we don't find anything, what should we return?
2521
-     * @return mixed single value if $single; array if ! $single
2522
-     * @throws \EE_Error
2523
-     */
2524
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2525
-    {
2526
-        if ($single) {
2527
-            $result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2528
-            if ($result instanceof EE_Extra_Meta) {
2529
-                return $result->value();
2530
-            }
2531
-        } else {
2532
-            $results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2533
-            if ($results) {
2534
-                $values = array();
2535
-                foreach ($results as $result) {
2536
-                    if ($result instanceof EE_Extra_Meta) {
2537
-                        $values[$result->ID()] = $result->value();
2538
-                    }
2539
-                }
2540
-                return $values;
2541
-            }
2542
-        }
2543
-        //if nothing discovered yet return default.
2544
-        return apply_filters(
2545
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2546
-            $default,
2547
-            $meta_key,
2548
-            $single,
2549
-            $this
2550
-            );
2551
-    }
2552
-
2553
-
2554
-
2555
-    /**
2556
-     * Returns a simple array of all the extra meta associated with this model object.
2557
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2558
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2559
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2560
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2561
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2562
-     * finally the extra meta's value as each sub-value. (eg
2563
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2564
-     *
2565
-     * @param boolean $one_of_each_key
2566
-     * @return array
2567
-     * @throws \EE_Error
2568
-     */
2569
-    public function all_extra_meta_array($one_of_each_key = true)
2570
-    {
2571
-        $return_array = array();
2572
-        if ($one_of_each_key) {
2573
-            $extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2574
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2575
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2576
-                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2577
-                }
2578
-            }
2579
-        } else {
2580
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2581
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2582
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2583
-                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2584
-                        $return_array[$extra_meta_obj->key()] = array();
2585
-                    }
2586
-                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2587
-                }
2588
-            }
2589
-        }
2590
-        return $return_array;
2591
-    }
2592
-
2593
-
2594
-
2595
-    /**
2596
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2597
-     *
2598
-     * @return string
2599
-     * @throws \EE_Error
2600
-     */
2601
-    public function name()
2602
-    {
2603
-        //find a field that's not a text field
2604
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2605
-        if ($field_we_can_use) {
2606
-            return $this->get($field_we_can_use->get_name());
2607
-        } else {
2608
-            $first_few_properties = $this->model_field_array();
2609
-            $first_few_properties = array_slice($first_few_properties, 0, 3);
2610
-            $name_parts = array();
2611
-            foreach ($first_few_properties as $name => $value) {
2612
-                $name_parts[] = "$name:$value";
2613
-            }
2614
-            return implode(",", $name_parts);
2615
-        }
2616
-    }
2617
-
2618
-
2619
-
2620
-    /**
2621
-     * in_entity_map
2622
-     * Checks if this model object has been proven to already be in the entity map
2623
-     *
2624
-     * @return boolean
2625
-     * @throws \EE_Error
2626
-     */
2627
-    public function in_entity_map()
2628
-    {
2629
-        if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2630
-            //well, if we looked, did we find it in the entity map?
2631
-            return true;
2632
-        } else {
2633
-            return false;
2634
-        }
2635
-    }
2636
-
2637
-
2638
-
2639
-    /**
2640
-     * refresh_from_db
2641
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
2642
-     *
2643
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2644
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2645
-     */
2646
-    public function refresh_from_db()
2647
-    {
2648
-        if ($this->ID() && $this->in_entity_map()) {
2649
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
2650
-        } else {
2651
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2652
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
2653
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2654
-            //absolutely nothing in it for this ID
2655
-            if (WP_DEBUG) {
2656
-                throw new EE_Error(
2657
-                    sprintf(
2658
-                        __('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
2659
-                            'event_espresso'),
2660
-                        $this->ID(),
2661
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2662
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2663
-                    )
2664
-                );
2665
-            }
2666
-        }
2667
-    }
2668
-
2669
-
2670
-
2671
-    /**
2672
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2673
-     * (probably a bad assumption they have made, oh well)
2674
-     *
2675
-     * @return string
2676
-     */
2677
-    public function __toString()
2678
-    {
2679
-        try {
2680
-            return sprintf('%s (%s)', $this->name(), $this->ID());
2681
-        } catch (Exception $e) {
2682
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2683
-            return '';
2684
-        }
2685
-    }
2686
-
2687
-
2688
-
2689
-    /**
2690
-     * Clear related model objects if they're already in the DB, because otherwise when we
2691
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
2692
-     * This means if we have made changes to those related model objects, and want to unserialize
2693
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
2694
-     * Instead, those related model objects should be directly serialized and stored.
2695
-     * Eg, the following won't work:
2696
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2697
-     * $att = $reg->attendee();
2698
-     * $att->set( 'ATT_fname', 'Dirk' );
2699
-     * update_option( 'my_option', serialize( $reg ) );
2700
-     * //END REQUEST
2701
-     * //START NEXT REQUEST
2702
-     * $reg = get_option( 'my_option' );
2703
-     * $reg->attendee()->save();
2704
-     * And would need to be replace with:
2705
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2706
-     * $att = $reg->attendee();
2707
-     * $att->set( 'ATT_fname', 'Dirk' );
2708
-     * update_option( 'my_option', serialize( $reg ) );
2709
-     * //END REQUEST
2710
-     * //START NEXT REQUEST
2711
-     * $att = get_option( 'my_option' );
2712
-     * $att->save();
2713
-     *
2714
-     * @return array
2715
-     * @throws \EE_Error
2716
-     */
2717
-    public function __sleep()
2718
-    {
2719
-        $model = $this->get_model();
2720
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2721
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
2722
-                $classname = 'EE_' . $model->get_this_model_name();
2723
-                if (
2724
-                    $this->get_one_from_cache($relation_name) instanceof $classname
2725
-                    && $this->get_one_from_cache($relation_name)->ID()
2726
-                ) {
2727
-                    $this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2728
-                }
2729
-            }
2730
-        }
2731
-        $this->_props_n_values_provided_in_constructor = array();
2732
-        $properties_to_serialize = get_object_vars($this);
2733
-        //don't serialize the model. It's big and that risks recursion
2734
-        unset($properties_to_serialize['_model']);
2735
-        return array_keys($properties_to_serialize);
2736
-    }
2737
-
2738
-
2739
-
2740
-    /**
2741
-     * restore _props_n_values_provided_in_constructor
2742
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2743
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
2744
-     * At best, you would only be able to detect if state change has occurred during THIS request.
2745
-     */
2746
-    public function __wakeup()
2747
-    {
2748
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
2749
-    }
28
+	/**
29
+	 * This is an array of the original properties and values provided during construction
30
+	 * of this model object. (keys are model field names, values are their values).
31
+	 * This list is important to remember so that when we are merging data from the db, we know
32
+	 * which values to override and which to not override.
33
+	 *
34
+	 * @var array
35
+	 */
36
+	protected $_props_n_values_provided_in_constructor;
37
+
38
+	/**
39
+	 * Timezone
40
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
41
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
42
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
43
+	 * access to it.
44
+	 *
45
+	 * @var string
46
+	 */
47
+	protected $_timezone;
48
+
49
+
50
+
51
+	/**
52
+	 * date format
53
+	 * pattern or format for displaying dates
54
+	 *
55
+	 * @var string $_dt_frmt
56
+	 */
57
+	protected $_dt_frmt;
58
+
59
+
60
+
61
+	/**
62
+	 * time format
63
+	 * pattern or format for displaying time
64
+	 *
65
+	 * @var string $_tm_frmt
66
+	 */
67
+	protected $_tm_frmt;
68
+
69
+
70
+
71
+	/**
72
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
73
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
74
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
75
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
76
+	 *
77
+	 * @var array
78
+	 */
79
+	protected $_cached_properties = array();
80
+
81
+	/**
82
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
83
+	 * single
84
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
85
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
86
+	 * all others have an array)
87
+	 *
88
+	 * @var array
89
+	 */
90
+	protected $_model_relations = array();
91
+
92
+	/**
93
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
94
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
95
+	 *
96
+	 * @var array
97
+	 */
98
+	protected $_fields = array();
99
+
100
+	/**
101
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
102
+	 * For example, we might create model objects intended to only be used for the duration
103
+	 * of this request and to be thrown away, and if they were accidentally saved
104
+	 * it would be a bug.
105
+	 */
106
+	protected $_allow_persist = true;
107
+
108
+	/**
109
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
110
+	 */
111
+	protected $_has_changes = false;
112
+
113
+	/**
114
+	 * @var EEM_Base
115
+	 */
116
+	protected $_model;
117
+
118
+
119
+
120
+	/**
121
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
122
+	 * play nice
123
+	 *
124
+	 * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
125
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
126
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
127
+	 * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
128
+	 *                                                         corresponding db model or not.
129
+	 * @param string  $timezone                                indicate what timezone you want any datetime fields to
130
+	 *                                                         be in when instantiating a EE_Base_Class object.
131
+	 * @param array   $date_formats                            An array of date formats to set on construct where first
132
+	 *                                                         value is the date_format and second value is the time
133
+	 *                                                         format.
134
+	 * @throws EE_Error
135
+	 */
136
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
137
+	{
138
+		$className = get_class($this);
139
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
140
+		$model = $this->get_model();
141
+		$model_fields = $model->field_settings(false);
142
+		// ensure $fieldValues is an array
143
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
144
+		// EEH_Debug_Tools::printr( $fieldValues, '$fieldValues  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
145
+		// verify client code has not passed any invalid field names
146
+		foreach ($fieldValues as $field_name => $field_value) {
147
+			if ( ! isset($model_fields[$field_name])) {
148
+				throw new EE_Error(sprintf(__("Invalid field (%s) passed to constructor of %s. Allowed fields are :%s",
149
+					"event_espresso"), $field_name, get_class($this), implode(", ", array_keys($model_fields))));
150
+			}
151
+		}
152
+		// EEH_Debug_Tools::printr( $model_fields, '$model_fields  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' );
153
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
154
+		if ( ! empty($date_formats) && is_array($date_formats)) {
155
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
156
+		} else {
157
+			//set default formats for date and time
158
+			$this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
159
+			$this->_tm_frmt = (string)get_option('time_format', 'g:i a');
160
+		}
161
+		//if db model is instantiating
162
+		if ($bydb) {
163
+			//client code has indicated these field values are from the database
164
+			foreach ($model_fields as $fieldName => $field) {
165
+				$this->set_from_db($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null);
166
+			}
167
+		} else {
168
+			//we're constructing a brand
169
+			//new instance of the model object. Generally, this means we'll need to do more field validation
170
+			foreach ($model_fields as $fieldName => $field) {
171
+				$this->set($fieldName, isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true);
172
+			}
173
+		}
174
+		//remember what values were passed to this constructor
175
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
176
+		//remember in entity mapper
177
+		if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
178
+			$model->add_to_entity_map($this);
179
+		}
180
+		//setup all the relations
181
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
182
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
183
+				$this->_model_relations[$relation_name] = null;
184
+			} else {
185
+				$this->_model_relations[$relation_name] = array();
186
+			}
187
+		}
188
+		/**
189
+		 * Action done at the end of each model object construction
190
+		 *
191
+		 * @param EE_Base_Class $this the model object just created
192
+		 */
193
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
194
+	}
195
+
196
+
197
+
198
+	/**
199
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
200
+	 *
201
+	 * @return boolean
202
+	 */
203
+	public function allow_persist()
204
+	{
205
+		return $this->_allow_persist;
206
+	}
207
+
208
+
209
+
210
+	/**
211
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
212
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
213
+	 * you got new information that somehow made you change your mind.
214
+	 *
215
+	 * @param boolean $allow_persist
216
+	 * @return boolean
217
+	 */
218
+	public function set_allow_persist($allow_persist)
219
+	{
220
+		return $this->_allow_persist = $allow_persist;
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 * Gets the field's original value when this object was constructed during this request.
227
+	 * This can be helpful when determining if a model object has changed or not
228
+	 *
229
+	 * @param string $field_name
230
+	 * @return mixed|null
231
+	 * @throws \EE_Error
232
+	 */
233
+	public function get_original($field_name)
234
+	{
235
+		if (isset($this->_props_n_values_provided_in_constructor[$field_name])
236
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
237
+		) {
238
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
239
+		} else {
240
+			return null;
241
+		}
242
+	}
243
+
244
+
245
+
246
+	/**
247
+	 * @param EE_Base_Class $obj
248
+	 * @return string
249
+	 */
250
+	public function get_class($obj)
251
+	{
252
+		return get_class($obj);
253
+	}
254
+
255
+
256
+
257
+	/**
258
+	 * Overrides parent because parent expects old models.
259
+	 * This also doesn't do any validation, and won't work for serialized arrays
260
+	 *
261
+	 * @param    string $field_name
262
+	 * @param    mixed  $field_value
263
+	 * @param bool      $use_default
264
+	 * @throws \EE_Error
265
+	 */
266
+	public function set($field_name, $field_value, $use_default = false)
267
+	{
268
+		// if not using default and nothing has changed, and object has already been setup (has ID),
269
+		// then don't do anything
270
+		if (
271
+			! $use_default
272
+			&& $this->_fields[$field_name] === $field_value
273
+			&& $this->ID()
274
+		) {
275
+			return;
276
+		}
277
+		$model = $this->get_model();
278
+		$this->_has_changes = true;
279
+		$field_obj = $model->field_settings_for($field_name);
280
+		if ($field_obj instanceof EE_Model_Field_Base) {
281
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
282
+			if ($field_obj instanceof EE_Datetime_Field) {
283
+				$field_obj->set_timezone($this->_timezone);
284
+				$field_obj->set_date_format($this->_dt_frmt);
285
+				$field_obj->set_time_format($this->_tm_frmt);
286
+			}
287
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
288
+			//should the value be null?
289
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
290
+				$this->_fields[$field_name] = $field_obj->get_default_value();
291
+				/**
292
+				 * To save having to refactor all the models, if a default value is used for a
293
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
294
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
295
+				 * object.
296
+				 *
297
+				 * @since 4.6.10+
298
+				 */
299
+				if (
300
+					$field_obj instanceof EE_Datetime_Field
301
+					&& $this->_fields[$field_name] !== null
302
+					&& ! $this->_fields[$field_name] instanceof DateTime
303
+				) {
304
+					empty($this->_fields[$field_name])
305
+						? $this->set($field_name, time())
306
+						: $this->set($field_name, $this->_fields[$field_name]);
307
+				}
308
+			} else {
309
+				$this->_fields[$field_name] = $holder_of_value;
310
+			}
311
+			//if we're not in the constructor...
312
+			//now check if what we set was a primary key
313
+			if (
314
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
315
+				$this->_props_n_values_provided_in_constructor
316
+				&& $field_value
317
+				&& $field_name === $model->primary_key_name()
318
+			) {
319
+				//if so, we want all this object's fields to be filled either with
320
+				//what we've explicitly set on this model
321
+				//or what we have in the db
322
+				// echo "setting primary key!";
323
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
324
+				$obj_in_db = self::_get_model(get_class($this))->get_one_by_ID($field_value);
325
+				foreach ($fields_on_model as $field_obj) {
326
+					if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
327
+						 && $field_obj->get_name() !== $field_name
328
+					) {
329
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
330
+					}
331
+				}
332
+				//oh this model object has an ID? well make sure its in the entity mapper
333
+				$model->add_to_entity_map($this);
334
+			}
335
+			//let's unset any cache for this field_name from the $_cached_properties property.
336
+			$this->_clear_cached_property($field_name);
337
+		} else {
338
+			throw new EE_Error(sprintf(__("A valid EE_Model_Field_Base could not be found for the given field name: %s",
339
+				"event_espresso"), $field_name));
340
+		}
341
+	}
342
+
343
+
344
+
345
+	/**
346
+	 * This sets the field value on the db column if it exists for the given $column_name or
347
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
348
+	 *
349
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
350
+	 * @param string $field_name  Must be the exact column name.
351
+	 * @param mixed  $field_value The value to set.
352
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
353
+	 * @throws \EE_Error
354
+	 */
355
+	public function set_field_or_extra_meta($field_name, $field_value)
356
+	{
357
+		if ($this->get_model()->has_field($field_name)) {
358
+			$this->set($field_name, $field_value);
359
+			return true;
360
+		} else {
361
+			//ensure this object is saved first so that extra meta can be properly related.
362
+			$this->save();
363
+			return $this->update_extra_meta($field_name, $field_value);
364
+		}
365
+	}
366
+
367
+
368
+
369
+	/**
370
+	 * This retrieves the value of the db column set on this class or if that's not present
371
+	 * it will attempt to retrieve from extra_meta if found.
372
+	 * Example Usage:
373
+	 * Via EE_Message child class:
374
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
375
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
376
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
377
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
378
+	 * value for those extra fields dynamically via the EE_message object.
379
+	 *
380
+	 * @param  string $field_name expecting the fully qualified field name.
381
+	 * @return mixed|null  value for the field if found.  null if not found.
382
+	 * @throws \EE_Error
383
+	 */
384
+	public function get_field_or_extra_meta($field_name)
385
+	{
386
+		if ($this->get_model()->has_field($field_name)) {
387
+			$column_value = $this->get($field_name);
388
+		} else {
389
+			//This isn't a column in the main table, let's see if it is in the extra meta.
390
+			$column_value = $this->get_extra_meta($field_name, true, null);
391
+		}
392
+		return $column_value;
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
399
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
400
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
401
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
402
+	 *
403
+	 * @access public
404
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
405
+	 * @return void
406
+	 * @throws \EE_Error
407
+	 */
408
+	public function set_timezone($timezone = '')
409
+	{
410
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
411
+		//make sure we clear all cached properties because they won't be relevant now
412
+		$this->_clear_cached_properties();
413
+		//make sure we update field settings and the date for all EE_Datetime_Fields
414
+		$model_fields = $this->get_model()->field_settings(false);
415
+		foreach ($model_fields as $field_name => $field_obj) {
416
+			if ($field_obj instanceof EE_Datetime_Field) {
417
+				$field_obj->set_timezone($this->_timezone);
418
+				if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
419
+					$this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
420
+				}
421
+			}
422
+		}
423
+	}
424
+
425
+
426
+
427
+	/**
428
+	 * This just returns whatever is set for the current timezone.
429
+	 *
430
+	 * @access public
431
+	 * @return string timezone string
432
+	 */
433
+	public function get_timezone()
434
+	{
435
+		return $this->_timezone;
436
+	}
437
+
438
+
439
+
440
+	/**
441
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
442
+	 * internally instead of wp set date format options
443
+	 *
444
+	 * @since 4.6
445
+	 * @param string $format should be a format recognizable by PHP date() functions.
446
+	 */
447
+	public function set_date_format($format)
448
+	{
449
+		$this->_dt_frmt = $format;
450
+		//clear cached_properties because they won't be relevant now.
451
+		$this->_clear_cached_properties();
452
+	}
453
+
454
+
455
+
456
+	/**
457
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
458
+	 * class internally instead of wp set time format options.
459
+	 *
460
+	 * @since 4.6
461
+	 * @param string $format should be a format recognizable by PHP date() functions.
462
+	 */
463
+	public function set_time_format($format)
464
+	{
465
+		$this->_tm_frmt = $format;
466
+		//clear cached_properties because they won't be relevant now.
467
+		$this->_clear_cached_properties();
468
+	}
469
+
470
+
471
+
472
+	/**
473
+	 * This returns the current internal set format for the date and time formats.
474
+	 *
475
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
476
+	 *                             where the first value is the date format and the second value is the time format.
477
+	 * @return mixed string|array
478
+	 */
479
+	public function get_format($full = true)
480
+	{
481
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
482
+	}
483
+
484
+
485
+
486
+	/**
487
+	 * cache
488
+	 * stores the passed model object on the current model object.
489
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
490
+	 *
491
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
492
+	 *                                       'Registration' associated with this model object
493
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
494
+	 *                                       that could be a payment or a registration)
495
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
496
+	 *                                       items which will be stored in an array on this object
497
+	 * @throws EE_Error
498
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
499
+	 *                  related thing, no array)
500
+	 */
501
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
502
+	{
503
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
504
+		if ( ! $object_to_cache instanceof EE_Base_Class) {
505
+			return false;
506
+		}
507
+		// also get "how" the object is related, or throw an error
508
+		if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
509
+			throw new EE_Error(sprintf(__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
510
+				$relationName, get_class($this)));
511
+		}
512
+		// how many things are related ?
513
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
514
+			// if it's a "belongs to" relationship, then there's only one related model object  eg, if this is a registration, there's only 1 attendee for it
515
+			// so for these model objects just set it to be cached
516
+			$this->_model_relations[$relationName] = $object_to_cache;
517
+			$return = true;
518
+		} else {
519
+			// otherwise, this is the "many" side of a one to many relationship, so we'll add the object to the array of related objects for that type.
520
+			// eg: if this is an event, there are many registrations for that event, so we cache the registrations in an array
521
+			if ( ! is_array($this->_model_relations[$relationName])) {
522
+				// if for some reason, the cached item is a model object, then stick that in the array, otherwise start with an empty array
523
+				$this->_model_relations[$relationName] = $this->_model_relations[$relationName] instanceof EE_Base_Class
524
+					? array($this->_model_relations[$relationName]) : array();
525
+			}
526
+			// first check for a cache_id which is normally empty
527
+			if ( ! empty($cache_id)) {
528
+				// if the cache_id exists, then it means we are purposely trying to cache this with a known key that can then be used to retrieve the object later on
529
+				$this->_model_relations[$relationName][$cache_id] = $object_to_cache;
530
+				$return = $cache_id;
531
+			} elseif ($object_to_cache->ID()) {
532
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
533
+				$this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
534
+				$return = $object_to_cache->ID();
535
+			} else {
536
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
537
+				$this->_model_relations[$relationName][] = $object_to_cache;
538
+				// move the internal pointer to the end of the array
539
+				end($this->_model_relations[$relationName]);
540
+				// and grab the key so that we can return it
541
+				$return = key($this->_model_relations[$relationName]);
542
+			}
543
+		}
544
+		return $return;
545
+	}
546
+
547
+
548
+
549
+	/**
550
+	 * For adding an item to the cached_properties property.
551
+	 *
552
+	 * @access protected
553
+	 * @param string      $fieldname the property item the corresponding value is for.
554
+	 * @param mixed       $value     The value we are caching.
555
+	 * @param string|null $cache_type
556
+	 * @return void
557
+	 * @throws \EE_Error
558
+	 */
559
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
560
+	{
561
+		//first make sure this property exists
562
+		$this->get_model()->field_settings_for($fieldname);
563
+		$cache_type = empty($cache_type) ? 'standard' : $cache_type;
564
+		$this->_cached_properties[$fieldname][$cache_type] = $value;
565
+	}
566
+
567
+
568
+
569
+	/**
570
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
571
+	 * This also SETS the cache if we return the actual property!
572
+	 *
573
+	 * @param string $fieldname        the name of the property we're trying to retrieve
574
+	 * @param bool   $pretty
575
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
576
+	 *                                 (in cases where the same property may be used for different outputs
577
+	 *                                 - i.e. datetime, money etc.)
578
+	 *                                 It can also accept certain pre-defined "schema" strings
579
+	 *                                 to define how to output the property.
580
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
581
+	 * @return mixed                   whatever the value for the property is we're retrieving
582
+	 * @throws \EE_Error
583
+	 */
584
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
585
+	{
586
+		//verify the field exists
587
+		$model = $this->get_model();
588
+		$model->field_settings_for($fieldname);
589
+		$cache_type = $pretty ? 'pretty' : 'standard';
590
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
591
+		if (isset($this->_cached_properties[$fieldname][$cache_type])) {
592
+			return $this->_cached_properties[$fieldname][$cache_type];
593
+		}
594
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
595
+		$this->_set_cached_property($fieldname, $value, $cache_type);
596
+		return $value;
597
+	}
598
+
599
+
600
+
601
+	/**
602
+	 * If the cache didn't fetch the needed item, this fetches it.
603
+	 * @param string $fieldname
604
+	 * @param bool $pretty
605
+	 * @param string $extra_cache_ref
606
+	 * @return mixed
607
+	 */
608
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
609
+	{
610
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
611
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
612
+		if ($field_obj instanceof EE_Datetime_Field) {
613
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
614
+		}
615
+		if ( ! isset($this->_fields[$fieldname])) {
616
+			$this->_fields[$fieldname] = null;
617
+		}
618
+		$value = $pretty
619
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
620
+			: $field_obj->prepare_for_get($this->_fields[$fieldname]);
621
+		return $value;
622
+	}
623
+
624
+
625
+
626
+	/**
627
+	 * set timezone, formats, and output for EE_Datetime_Field objects
628
+	 *
629
+	 * @param \EE_Datetime_Field $datetime_field
630
+	 * @param bool               $pretty
631
+	 * @param null $date_or_time
632
+	 * @return void
633
+	 * @throws \EE_Error
634
+	 */
635
+	protected function _prepare_datetime_field(
636
+		EE_Datetime_Field $datetime_field,
637
+		$pretty = false,
638
+		$date_or_time = null
639
+	) {
640
+		$datetime_field->set_timezone($this->_timezone);
641
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
642
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
643
+		//set the output returned
644
+		switch ($date_or_time) {
645
+			case 'D' :
646
+				$datetime_field->set_date_time_output('date');
647
+				break;
648
+			case 'T' :
649
+				$datetime_field->set_date_time_output('time');
650
+				break;
651
+			default :
652
+				$datetime_field->set_date_time_output();
653
+		}
654
+	}
655
+
656
+
657
+
658
+	/**
659
+	 * This just takes care of clearing out the cached_properties
660
+	 *
661
+	 * @return void
662
+	 */
663
+	protected function _clear_cached_properties()
664
+	{
665
+		$this->_cached_properties = array();
666
+	}
667
+
668
+
669
+
670
+	/**
671
+	 * This just clears out ONE property if it exists in the cache
672
+	 *
673
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
674
+	 * @return void
675
+	 */
676
+	protected function _clear_cached_property($property_name)
677
+	{
678
+		if (isset($this->_cached_properties[$property_name])) {
679
+			unset($this->_cached_properties[$property_name]);
680
+		}
681
+	}
682
+
683
+
684
+
685
+	/**
686
+	 * Ensures that this related thing is a model object.
687
+	 *
688
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
689
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
690
+	 * @return EE_Base_Class
691
+	 * @throws \EE_Error
692
+	 */
693
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
694
+	{
695
+		$other_model_instance = self::_get_model_instance_with_name(
696
+			self::_get_model_classname($model_name),
697
+			$this->_timezone
698
+		);
699
+		return $other_model_instance->ensure_is_obj($object_or_id);
700
+	}
701
+
702
+
703
+
704
+	/**
705
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
706
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
707
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
708
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
709
+	 *
710
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
711
+	 *                                                     Eg 'Registration'
712
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
713
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
714
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
715
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
716
+	 *                                                     this is HasMany or HABTM.
717
+	 * @throws EE_Error
718
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
719
+	 *                       relation from all
720
+	 */
721
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
722
+	{
723
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
724
+		$index_in_cache = '';
725
+		if ( ! $relationship_to_model) {
726
+			throw new EE_Error(
727
+				sprintf(
728
+					__("There is no relationship to %s on a %s. Cannot clear that cache", 'event_espresso'),
729
+					$relationName,
730
+					get_class($this)
731
+				)
732
+			);
733
+		}
734
+		if ($clear_all) {
735
+			$obj_removed = true;
736
+			$this->_model_relations[$relationName] = null;
737
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
738
+			$obj_removed = $this->_model_relations[$relationName];
739
+			$this->_model_relations[$relationName] = null;
740
+		} else {
741
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
742
+				&& $object_to_remove_or_index_into_array->ID()
743
+			) {
744
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
745
+				if (is_array($this->_model_relations[$relationName])
746
+					&& ! isset($this->_model_relations[$relationName][$index_in_cache])
747
+				) {
748
+					$index_found_at = null;
749
+					//find this object in the array even though it has a different key
750
+					foreach ($this->_model_relations[$relationName] as $index => $obj) {
751
+						if (
752
+							$obj instanceof EE_Base_Class
753
+							&& (
754
+								$obj == $object_to_remove_or_index_into_array
755
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
756
+							)
757
+						) {
758
+							$index_found_at = $index;
759
+							break;
760
+						}
761
+					}
762
+					if ($index_found_at) {
763
+						$index_in_cache = $index_found_at;
764
+					} else {
765
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
766
+						//if it wasn't in it to begin with. So we're done
767
+						return $object_to_remove_or_index_into_array;
768
+					}
769
+				}
770
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
771
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
772
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
773
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
774
+						$index_in_cache = $index;
775
+					}
776
+				}
777
+			} else {
778
+				$index_in_cache = $object_to_remove_or_index_into_array;
779
+			}
780
+			//supposedly we've found it. But it could just be that the client code
781
+			//provided a bad index/object
782
+			if (
783
+			isset(
784
+				$this->_model_relations[$relationName],
785
+				$this->_model_relations[$relationName][$index_in_cache]
786
+			)
787
+			) {
788
+				$obj_removed = $this->_model_relations[$relationName][$index_in_cache];
789
+				unset($this->_model_relations[$relationName][$index_in_cache]);
790
+			} else {
791
+				//that thing was never cached anyways.
792
+				$obj_removed = null;
793
+			}
794
+		}
795
+		return $obj_removed;
796
+	}
797
+
798
+
799
+
800
+	/**
801
+	 * update_cache_after_object_save
802
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
803
+	 * obtained after being saved to the db
804
+	 *
805
+	 * @param string         $relationName       - the type of object that is cached
806
+	 * @param \EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
807
+	 * @param string         $current_cache_id   - the ID that was used when originally caching the object
808
+	 * @return boolean TRUE on success, FALSE on fail
809
+	 * @throws \EE_Error
810
+	 */
811
+	public function update_cache_after_object_save(
812
+		$relationName,
813
+		EE_Base_Class $newly_saved_object,
814
+		$current_cache_id = ''
815
+	) {
816
+		// verify that incoming object is of the correct type
817
+		$obj_class = 'EE_' . $relationName;
818
+		if ($newly_saved_object instanceof $obj_class) {
819
+			/* @type EE_Base_Class $newly_saved_object */
820
+			// now get the type of relation
821
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
822
+			// if this is a 1:1 relationship
823
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
824
+				// then just replace the cached object with the newly saved object
825
+				$this->_model_relations[$relationName] = $newly_saved_object;
826
+				return true;
827
+				// or if it's some kind of sordid feral polyamorous relationship...
828
+			} elseif (is_array($this->_model_relations[$relationName])
829
+					  && isset($this->_model_relations[$relationName][$current_cache_id])
830
+			) {
831
+				// then remove the current cached item
832
+				unset($this->_model_relations[$relationName][$current_cache_id]);
833
+				// and cache the newly saved object using it's new ID
834
+				$this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
835
+				return true;
836
+			}
837
+		}
838
+		return false;
839
+	}
840
+
841
+
842
+
843
+	/**
844
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
845
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
846
+	 *
847
+	 * @param string $relationName
848
+	 * @return EE_Base_Class
849
+	 */
850
+	public function get_one_from_cache($relationName)
851
+	{
852
+		$cached_array_or_object = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName]
853
+			: null;
854
+		if (is_array($cached_array_or_object)) {
855
+			return array_shift($cached_array_or_object);
856
+		} else {
857
+			return $cached_array_or_object;
858
+		}
859
+	}
860
+
861
+
862
+
863
+	/**
864
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
865
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
866
+	 *
867
+	 * @param string $relationName
868
+	 * @throws \EE_Error
869
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
870
+	 */
871
+	public function get_all_from_cache($relationName)
872
+	{
873
+		$objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
874
+		// if the result is not an array, but exists, make it an array
875
+		$objects = is_array($objects) ? $objects : array($objects);
876
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
877
+		//basically, if this model object was stored in the session, and these cached model objects
878
+		//already have IDs, let's make sure they're in their model's entity mapper
879
+		//otherwise we will have duplicates next time we call
880
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
881
+		$model = EE_Registry::instance()->load_model($relationName);
882
+		foreach ($objects as $model_object) {
883
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
884
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
885
+				if ($model_object->ID()) {
886
+					$model->add_to_entity_map($model_object);
887
+				}
888
+			} else {
889
+				throw new EE_Error(
890
+					sprintf(
891
+						__(
892
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
893
+							'event_espresso'
894
+						),
895
+						$relationName,
896
+						gettype($model_object)
897
+					)
898
+				);
899
+			}
900
+		}
901
+		return $objects;
902
+	}
903
+
904
+
905
+
906
+	/**
907
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
908
+	 * matching the given query conditions.
909
+	 *
910
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
911
+	 * @param int   $limit              How many objects to return.
912
+	 * @param array $query_params       Any additional conditions on the query.
913
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
914
+	 *                                  you can indicate just the columns you want returned
915
+	 * @return array|EE_Base_Class[]
916
+	 * @throws \EE_Error
917
+	 */
918
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
919
+	{
920
+		$model = $this->get_model();
921
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
922
+			? $model->get_primary_key_field()->get_name()
923
+			: $field_to_order_by;
924
+		$current_value = ! empty($field) ? $this->get($field) : null;
925
+		if (empty($field) || empty($current_value)) {
926
+			return array();
927
+		}
928
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
929
+	}
930
+
931
+
932
+
933
+	/**
934
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
935
+	 * matching the given query conditions.
936
+	 *
937
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
938
+	 * @param int   $limit              How many objects to return.
939
+	 * @param array $query_params       Any additional conditions on the query.
940
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
941
+	 *                                  you can indicate just the columns you want returned
942
+	 * @return array|EE_Base_Class[]
943
+	 * @throws \EE_Error
944
+	 */
945
+	public function previous_x(
946
+		$field_to_order_by = null,
947
+		$limit = 1,
948
+		$query_params = array(),
949
+		$columns_to_select = null
950
+	) {
951
+		$model = $this->get_model();
952
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
953
+			? $model->get_primary_key_field()->get_name()
954
+			: $field_to_order_by;
955
+		$current_value = ! empty($field) ? $this->get($field) : null;
956
+		if (empty($field) || empty($current_value)) {
957
+			return array();
958
+		}
959
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
960
+	}
961
+
962
+
963
+
964
+	/**
965
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
966
+	 * matching the given query conditions.
967
+	 *
968
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
969
+	 * @param array $query_params       Any additional conditions on the query.
970
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
971
+	 *                                  you can indicate just the columns you want returned
972
+	 * @return array|EE_Base_Class
973
+	 * @throws \EE_Error
974
+	 */
975
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
976
+	{
977
+		$model = $this->get_model();
978
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
979
+			? $model->get_primary_key_field()->get_name()
980
+			: $field_to_order_by;
981
+		$current_value = ! empty($field) ? $this->get($field) : null;
982
+		if (empty($field) || empty($current_value)) {
983
+			return array();
984
+		}
985
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
986
+	}
987
+
988
+
989
+
990
+	/**
991
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
992
+	 * matching the given query conditions.
993
+	 *
994
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
995
+	 * @param array $query_params       Any additional conditions on the query.
996
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
997
+	 *                                  you can indicate just the column you want returned
998
+	 * @return array|EE_Base_Class
999
+	 * @throws \EE_Error
1000
+	 */
1001
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1002
+	{
1003
+		$model = $this->get_model();
1004
+		$field = empty($field_to_order_by) && $model->has_primary_key_field()
1005
+			? $model->get_primary_key_field()->get_name()
1006
+			: $field_to_order_by;
1007
+		$current_value = ! empty($field) ? $this->get($field) : null;
1008
+		if (empty($field) || empty($current_value)) {
1009
+			return array();
1010
+		}
1011
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1012
+	}
1013
+
1014
+
1015
+
1016
+	/**
1017
+	 * Overrides parent because parent expects old models.
1018
+	 * This also doesn't do any validation, and won't work for serialized arrays
1019
+	 *
1020
+	 * @param string $field_name
1021
+	 * @param mixed  $field_value_from_db
1022
+	 * @throws \EE_Error
1023
+	 */
1024
+	public function set_from_db($field_name, $field_value_from_db)
1025
+	{
1026
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1027
+		if ($field_obj instanceof EE_Model_Field_Base) {
1028
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1029
+			//eg, a CPT model object could have an entry in the posts table, but no
1030
+			//entry in the meta table. Meaning that all its columns in the meta table
1031
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1032
+			if ($field_value_from_db === null) {
1033
+				if ($field_obj->is_nullable()) {
1034
+					//if the field allows nulls, then let it be null
1035
+					$field_value = null;
1036
+				} else {
1037
+					$field_value = $field_obj->get_default_value();
1038
+				}
1039
+			} else {
1040
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1041
+			}
1042
+			$this->_fields[$field_name] = $field_value;
1043
+			$this->_clear_cached_property($field_name);
1044
+		}
1045
+	}
1046
+
1047
+
1048
+
1049
+	/**
1050
+	 * verifies that the specified field is of the correct type
1051
+	 *
1052
+	 * @param string $field_name
1053
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1054
+	 *                                (in cases where the same property may be used for different outputs
1055
+	 *                                - i.e. datetime, money etc.)
1056
+	 * @return mixed
1057
+	 * @throws \EE_Error
1058
+	 */
1059
+	public function get($field_name, $extra_cache_ref = null)
1060
+	{
1061
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1062
+	}
1063
+
1064
+
1065
+
1066
+	/**
1067
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1068
+	 *
1069
+	 * @param  string $field_name A valid fieldname
1070
+	 * @return mixed              Whatever the raw value stored on the property is.
1071
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1072
+	 */
1073
+	public function get_raw($field_name)
1074
+	{
1075
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1076
+		return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1077
+			? $this->_fields[$field_name]->format('U')
1078
+			: $this->_fields[$field_name];
1079
+	}
1080
+
1081
+
1082
+
1083
+	/**
1084
+	 * This is used to return the internal DateTime object used for a field that is a
1085
+	 * EE_Datetime_Field.
1086
+	 *
1087
+	 * @param string $field_name               The field name retrieving the DateTime object.
1088
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1089
+	 * @throws \EE_Error
1090
+	 *                                         an error is set and false returned.  If the field IS an
1091
+	 *                                         EE_Datetime_Field and but the field value is null, then
1092
+	 *                                         just null is returned (because that indicates that likely
1093
+	 *                                         this field is nullable).
1094
+	 */
1095
+	public function get_DateTime_object($field_name)
1096
+	{
1097
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1098
+		if ( ! $field_settings instanceof EE_Datetime_Field) {
1099
+			EE_Error::add_error(
1100
+				sprintf(
1101
+					__(
1102
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1103
+						'event_espresso'
1104
+					),
1105
+					$field_name
1106
+				),
1107
+				__FILE__,
1108
+				__FUNCTION__,
1109
+				__LINE__
1110
+			);
1111
+			return false;
1112
+		}
1113
+		return $this->_fields[$field_name];
1114
+	}
1115
+
1116
+
1117
+
1118
+	/**
1119
+	 * To be used in template to immediately echo out the value, and format it for output.
1120
+	 * Eg, should call stripslashes and whatnot before echoing
1121
+	 *
1122
+	 * @param string $field_name      the name of the field as it appears in the DB
1123
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1124
+	 *                                (in cases where the same property may be used for different outputs
1125
+	 *                                - i.e. datetime, money etc.)
1126
+	 * @return void
1127
+	 * @throws \EE_Error
1128
+	 */
1129
+	public function e($field_name, $extra_cache_ref = null)
1130
+	{
1131
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1132
+	}
1133
+
1134
+
1135
+
1136
+	/**
1137
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1138
+	 * can be easily used as the value of form input.
1139
+	 *
1140
+	 * @param string $field_name
1141
+	 * @return void
1142
+	 * @throws \EE_Error
1143
+	 */
1144
+	public function f($field_name)
1145
+	{
1146
+		$this->e($field_name, 'form_input');
1147
+	}
1148
+
1149
+	/**
1150
+	 * Same as `f()` but just returns the value instead of echoing it
1151
+	 * @param string $field_name
1152
+	 * @return string
1153
+	 */
1154
+	public function get_f($field_name)
1155
+	{
1156
+		return (string)$this->get_pretty($field_name,'form_input');
1157
+	}
1158
+
1159
+
1160
+
1161
+	/**
1162
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1163
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1164
+	 * to see what options are available.
1165
+	 * @param string $field_name
1166
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1167
+	 *                                (in cases where the same property may be used for different outputs
1168
+	 *                                - i.e. datetime, money etc.)
1169
+	 * @return mixed
1170
+	 * @throws \EE_Error
1171
+	 */
1172
+	public function get_pretty($field_name, $extra_cache_ref = null)
1173
+	{
1174
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1175
+	}
1176
+
1177
+
1178
+
1179
+	/**
1180
+	 * This simply returns the datetime for the given field name
1181
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1182
+	 * (and the equivalent e_date, e_time, e_datetime).
1183
+	 *
1184
+	 * @access   protected
1185
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1186
+	 * @param string   $dt_frmt      valid datetime format used for date
1187
+	 *                               (if '' then we just use the default on the field,
1188
+	 *                               if NULL we use the last-used format)
1189
+	 * @param string   $tm_frmt      Same as above except this is for time format
1190
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1191
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1192
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1193
+	 *                               if field is not a valid dtt field, or void if echoing
1194
+	 * @throws \EE_Error
1195
+	 */
1196
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1197
+	{
1198
+		// clear cached property
1199
+		$this->_clear_cached_property($field_name);
1200
+		//reset format properties because they are used in get()
1201
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1202
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1203
+		if ($echo) {
1204
+			$this->e($field_name, $date_or_time);
1205
+			return '';
1206
+		}
1207
+		return $this->get($field_name, $date_or_time);
1208
+	}
1209
+
1210
+
1211
+
1212
+	/**
1213
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1214
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1215
+	 * other echoes the pretty value for dtt)
1216
+	 *
1217
+	 * @param  string $field_name name of model object datetime field holding the value
1218
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1219
+	 * @return string            datetime value formatted
1220
+	 * @throws \EE_Error
1221
+	 */
1222
+	public function get_date($field_name, $format = '')
1223
+	{
1224
+		return $this->_get_datetime($field_name, $format, null, 'D');
1225
+	}
1226
+
1227
+
1228
+
1229
+	/**
1230
+	 * @param      $field_name
1231
+	 * @param string $format
1232
+	 * @throws \EE_Error
1233
+	 */
1234
+	public function e_date($field_name, $format = '')
1235
+	{
1236
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1237
+	}
1238
+
1239
+
1240
+
1241
+	/**
1242
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1243
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1244
+	 * other echoes the pretty value for dtt)
1245
+	 *
1246
+	 * @param  string $field_name name of model object datetime field holding the value
1247
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1248
+	 * @return string             datetime value formatted
1249
+	 * @throws \EE_Error
1250
+	 */
1251
+	public function get_time($field_name, $format = '')
1252
+	{
1253
+		return $this->_get_datetime($field_name, null, $format, 'T');
1254
+	}
1255
+
1256
+
1257
+
1258
+	/**
1259
+	 * @param      $field_name
1260
+	 * @param string $format
1261
+	 * @throws \EE_Error
1262
+	 */
1263
+	public function e_time($field_name, $format = '')
1264
+	{
1265
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1266
+	}
1267
+
1268
+
1269
+
1270
+	/**
1271
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1272
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1273
+	 * other echoes the pretty value for dtt)
1274
+	 *
1275
+	 * @param  string $field_name name of model object datetime field holding the value
1276
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1277
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1278
+	 * @return string             datetime value formatted
1279
+	 * @throws \EE_Error
1280
+	 */
1281
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1282
+	{
1283
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1284
+	}
1285
+
1286
+
1287
+
1288
+	/**
1289
+	 * @param string $field_name
1290
+	 * @param string $dt_frmt
1291
+	 * @param string $tm_frmt
1292
+	 * @throws \EE_Error
1293
+	 */
1294
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1295
+	{
1296
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1297
+	}
1298
+
1299
+
1300
+
1301
+	/**
1302
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1303
+	 *
1304
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1305
+	 * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1306
+	 *                           on the object will be used.
1307
+	 * @return string Date and time string in set locale or false if no field exists for the given
1308
+	 * @throws \EE_Error
1309
+	 *                           field name.
1310
+	 */
1311
+	public function get_i18n_datetime($field_name, $format = '')
1312
+	{
1313
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1314
+		return date_i18n(
1315
+			$format,
1316
+			EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
1317
+		);
1318
+	}
1319
+
1320
+
1321
+
1322
+	/**
1323
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1324
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1325
+	 * thrown.
1326
+	 *
1327
+	 * @param  string $field_name The field name being checked
1328
+	 * @throws EE_Error
1329
+	 * @return EE_Datetime_Field
1330
+	 */
1331
+	protected function _get_dtt_field_settings($field_name)
1332
+	{
1333
+		$field = $this->get_model()->field_settings_for($field_name);
1334
+		//check if field is dtt
1335
+		if ($field instanceof EE_Datetime_Field) {
1336
+			return $field;
1337
+		} else {
1338
+			throw new EE_Error(sprintf(__('The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1339
+				'event_espresso'), $field_name, self::_get_model_classname(get_class($this))));
1340
+		}
1341
+	}
1342
+
1343
+
1344
+
1345
+
1346
+	/**
1347
+	 * NOTE ABOUT BELOW:
1348
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1349
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1350
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1351
+	 * method and make sure you send the entire datetime value for setting.
1352
+	 */
1353
+	/**
1354
+	 * sets the time on a datetime property
1355
+	 *
1356
+	 * @access protected
1357
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1358
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1359
+	 * @throws \EE_Error
1360
+	 */
1361
+	protected function _set_time_for($time, $fieldname)
1362
+	{
1363
+		$this->_set_date_time('T', $time, $fieldname);
1364
+	}
1365
+
1366
+
1367
+
1368
+	/**
1369
+	 * sets the date on a datetime property
1370
+	 *
1371
+	 * @access protected
1372
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1373
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1374
+	 * @throws \EE_Error
1375
+	 */
1376
+	protected function _set_date_for($date, $fieldname)
1377
+	{
1378
+		$this->_set_date_time('D', $date, $fieldname);
1379
+	}
1380
+
1381
+
1382
+
1383
+	/**
1384
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1385
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1386
+	 *
1387
+	 * @access protected
1388
+	 * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1389
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1390
+	 * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1391
+	 *                                        EE_Datetime_Field property)
1392
+	 * @throws \EE_Error
1393
+	 */
1394
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1395
+	{
1396
+		$field = $this->_get_dtt_field_settings($fieldname);
1397
+		$field->set_timezone($this->_timezone);
1398
+		$field->set_date_format($this->_dt_frmt);
1399
+		$field->set_time_format($this->_tm_frmt);
1400
+		switch ($what) {
1401
+			case 'T' :
1402
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1403
+					$datetime_value,
1404
+					$this->_fields[$fieldname]
1405
+				);
1406
+				break;
1407
+			case 'D' :
1408
+				$this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1409
+					$datetime_value,
1410
+					$this->_fields[$fieldname]
1411
+				);
1412
+				break;
1413
+			case 'B' :
1414
+				$this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1415
+				break;
1416
+		}
1417
+		$this->_clear_cached_property($fieldname);
1418
+	}
1419
+
1420
+
1421
+
1422
+	/**
1423
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1424
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1425
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1426
+	 * that could lead to some unexpected results!
1427
+	 *
1428
+	 * @access public
1429
+	 * @param string               $field_name This is the name of the field on the object that contains the date/time
1430
+	 *                                         value being returned.
1431
+	 * @param string               $callback   must match a valid method in this class (defaults to get_datetime)
1432
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1433
+	 * @param string               $prepend    You can include something to prepend on the timestamp
1434
+	 * @param string               $append     You can include something to append on the timestamp
1435
+	 * @throws EE_Error
1436
+	 * @return string timestamp
1437
+	 */
1438
+	public function display_in_my_timezone(
1439
+		$field_name,
1440
+		$callback = 'get_datetime',
1441
+		$args = null,
1442
+		$prepend = '',
1443
+		$append = ''
1444
+	) {
1445
+		$timezone = EEH_DTT_Helper::get_timezone();
1446
+		if ($timezone === $this->_timezone) {
1447
+			return '';
1448
+		}
1449
+		$original_timezone = $this->_timezone;
1450
+		$this->set_timezone($timezone);
1451
+		$fn = (array)$field_name;
1452
+		$args = array_merge($fn, (array)$args);
1453
+		if ( ! method_exists($this, $callback)) {
1454
+			throw new EE_Error(
1455
+				sprintf(
1456
+					__(
1457
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1458
+						'event_espresso'
1459
+					),
1460
+					$callback
1461
+				)
1462
+			);
1463
+		}
1464
+		$args = (array)$args;
1465
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1466
+		$this->set_timezone($original_timezone);
1467
+		return $return;
1468
+	}
1469
+
1470
+
1471
+
1472
+	/**
1473
+	 * Deletes this model object.
1474
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1475
+	 * override
1476
+	 * `EE_Base_Class::_delete` NOT this class.
1477
+	 *
1478
+	 * @return boolean | int
1479
+	 * @throws \EE_Error
1480
+	 */
1481
+	public function delete()
1482
+	{
1483
+		/**
1484
+		 * Called just before the `EE_Base_Class::_delete` method call.
1485
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1486
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example, `EE_Soft_Delete_Base_Class::_delete`
1487
+		 * soft deletes (trash) the object and does not permanently delete it.
1488
+		 *
1489
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1490
+		 */
1491
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1492
+		$result = $this->_delete();
1493
+		/**
1494
+		 * Called just after the `EE_Base_Class::_delete` method call.
1495
+		 * Note: `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1496
+		 * should be aware that `_delete` may not always result in a permanent delete.  For example `EE_Soft_Base_Class::_delete`
1497
+		 * soft deletes (trash) the object and does not permanently delete it.
1498
+		 *
1499
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1500
+		 * @param boolean       $result
1501
+		 */
1502
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1503
+		return $result;
1504
+	}
1505
+
1506
+
1507
+
1508
+	/**
1509
+	 * Calls the specific delete method for the instantiated class.
1510
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1511
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1512
+	 * `EE_Base_Class::delete`
1513
+	 *
1514
+	 * @return bool|int
1515
+	 * @throws \EE_Error
1516
+	 */
1517
+	protected function _delete()
1518
+	{
1519
+		return $this->delete_permanently();
1520
+	}
1521
+
1522
+
1523
+
1524
+	/**
1525
+	 * Deletes this model object permanently from db (but keep in mind related models my block the delete and return an
1526
+	 * error)
1527
+	 *
1528
+	 * @return bool | int
1529
+	 * @throws \EE_Error
1530
+	 */
1531
+	public function delete_permanently()
1532
+	{
1533
+		/**
1534
+		 * Called just before HARD deleting a model object
1535
+		 *
1536
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1537
+		 */
1538
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1539
+		$model = $this->get_model();
1540
+		$result = $model->delete_permanently_by_ID($this->ID());
1541
+		$this->refresh_cache_of_related_objects();
1542
+		/**
1543
+		 * Called just after HARD deleting a model object
1544
+		 *
1545
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1546
+		 * @param boolean       $result
1547
+		 */
1548
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1549
+		return $result;
1550
+	}
1551
+
1552
+
1553
+
1554
+	/**
1555
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1556
+	 * related model objects
1557
+	 *
1558
+	 * @throws \EE_Error
1559
+	 */
1560
+	public function refresh_cache_of_related_objects()
1561
+	{
1562
+		$model = $this->get_model();
1563
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1564
+			if ( ! empty($this->_model_relations[$relation_name])) {
1565
+				$related_objects = $this->_model_relations[$relation_name];
1566
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1567
+					//this relation only stores a single model object, not an array
1568
+					//but let's make it consistent
1569
+					$related_objects = array($related_objects);
1570
+				}
1571
+				foreach ($related_objects as $related_object) {
1572
+					//only refresh their cache if they're in memory
1573
+					if ($related_object instanceof EE_Base_Class) {
1574
+						$related_object->clear_cache($model->get_this_model_name(), $this);
1575
+					}
1576
+				}
1577
+			}
1578
+		}
1579
+	}
1580
+
1581
+
1582
+
1583
+	/**
1584
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1585
+	 * object just before saving.
1586
+	 *
1587
+	 * @access public
1588
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1589
+	 *                                 if provided during the save() method (often client code will change the fields'
1590
+	 *                                 values before calling save)
1591
+	 * @throws \EE_Error
1592
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1593
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1594
+	 */
1595
+	public function save($set_cols_n_values = array())
1596
+	{
1597
+		$model = $this->get_model();
1598
+		/**
1599
+		 * Filters the fields we're about to save on the model object
1600
+		 *
1601
+		 * @param array         $set_cols_n_values
1602
+		 * @param EE_Base_Class $model_object
1603
+		 */
1604
+		$set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1605
+			$this);
1606
+		//set attributes as provided in $set_cols_n_values
1607
+		foreach ($set_cols_n_values as $column => $value) {
1608
+			$this->set($column, $value);
1609
+		}
1610
+		// no changes ? then don't do anything
1611
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1612
+			return 0;
1613
+		}
1614
+		/**
1615
+		 * Saving a model object.
1616
+		 * Before we perform a save, this action is fired.
1617
+		 *
1618
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1619
+		 */
1620
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1621
+		if ( ! $this->allow_persist()) {
1622
+			return 0;
1623
+		}
1624
+		//now get current attribute values
1625
+		$save_cols_n_values = $this->_fields;
1626
+		//if the object already has an ID, update it. Otherwise, insert it
1627
+		//also: change the assumption about values passed to the model NOT being prepare dby the model object. They have been
1628
+		$old_assumption_concerning_value_preparation = $model
1629
+															->get_assumption_concerning_values_already_prepared_by_model_object();
1630
+		$model->assume_values_already_prepared_by_model_object(true);
1631
+		//does this model have an autoincrement PK?
1632
+		if ($model->has_primary_key_field()) {
1633
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1634
+				//ok check if it's set, if so: update; if not, insert
1635
+				if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1636
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1637
+				} else {
1638
+					unset($save_cols_n_values[$model->primary_key_name()]);
1639
+					$results = $model->insert($save_cols_n_values);
1640
+					if ($results) {
1641
+						//if successful, set the primary key
1642
+						//but don't use the normal SET method, because it will check if
1643
+						//an item with the same ID exists in the mapper & db, then
1644
+						//will find it in the db (because we just added it) and THAT object
1645
+						//will get added to the mapper before we can add this one!
1646
+						//but if we just avoid using the SET method, all that headache can be avoided
1647
+						$pk_field_name = $model->primary_key_name();
1648
+						$this->_fields[$pk_field_name] = $results;
1649
+						$this->_clear_cached_property($pk_field_name);
1650
+						$model->add_to_entity_map($this);
1651
+						$this->_update_cached_related_model_objs_fks();
1652
+					}
1653
+				}
1654
+			} else {//PK is NOT auto-increment
1655
+				//so check if one like it already exists in the db
1656
+				if ($model->exists_by_ID($this->ID())) {
1657
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1658
+						throw new EE_Error(
1659
+							sprintf(
1660
+								__('Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1661
+									'event_espresso'),
1662
+								get_class($this),
1663
+								get_class($model) . '::instance()->add_to_entity_map()',
1664
+								get_class($model) . '::instance()->get_one_by_ID()',
1665
+								'<br />'
1666
+							)
1667
+						);
1668
+					}
1669
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1670
+				} else {
1671
+					$results = $model->insert($save_cols_n_values);
1672
+					$this->_update_cached_related_model_objs_fks();
1673
+				}
1674
+			}
1675
+		} else {//there is NO primary key
1676
+			$already_in_db = false;
1677
+			foreach ($model->unique_indexes() as $index) {
1678
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1679
+				if ($model->exists(array($uniqueness_where_params))) {
1680
+					$already_in_db = true;
1681
+				}
1682
+			}
1683
+			if ($already_in_db) {
1684
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1685
+					$model->get_combined_primary_key_fields());
1686
+				$results = $model->update($save_cols_n_values, $combined_pk_fields_n_values);
1687
+			} else {
1688
+				$results = $model->insert($save_cols_n_values);
1689
+			}
1690
+		}
1691
+		//restore the old assumption about values being prepared by the model object
1692
+		$model
1693
+			 ->assume_values_already_prepared_by_model_object($old_assumption_concerning_value_preparation);
1694
+		/**
1695
+		 * After saving the model object this action is called
1696
+		 *
1697
+		 * @param EE_Base_Class $model_object which was just saved
1698
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1699
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1700
+		 */
1701
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1702
+		$this->_has_changes = false;
1703
+		return $results;
1704
+	}
1705
+
1706
+
1707
+
1708
+	/**
1709
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1710
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1711
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1712
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1713
+	 * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1714
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1715
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1716
+	 *
1717
+	 * @return void
1718
+	 * @throws \EE_Error
1719
+	 */
1720
+	protected function _update_cached_related_model_objs_fks()
1721
+	{
1722
+		$model = $this->get_model();
1723
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1724
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1725
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1726
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1727
+						$model->get_this_model_name()
1728
+					);
1729
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1730
+					if ($related_model_obj_in_cache->ID()) {
1731
+						$related_model_obj_in_cache->save();
1732
+					}
1733
+				}
1734
+			}
1735
+		}
1736
+	}
1737
+
1738
+
1739
+
1740
+	/**
1741
+	 * Saves this model object and its NEW cached relations to the database.
1742
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1743
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1744
+	 * because otherwise, there's a potential for infinite looping of saving
1745
+	 * Saves the cached related model objects, and ensures the relation between them
1746
+	 * and this object and properly setup
1747
+	 *
1748
+	 * @return int ID of new model object on save; 0 on failure+
1749
+	 * @throws \EE_Error
1750
+	 */
1751
+	public function save_new_cached_related_model_objs()
1752
+	{
1753
+		//make sure this has been saved
1754
+		if ( ! $this->ID()) {
1755
+			$id = $this->save();
1756
+		} else {
1757
+			$id = $this->ID();
1758
+		}
1759
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1760
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1761
+			if ($this->_model_relations[$relationName]) {
1762
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1763
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1764
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1765
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1766
+					//but ONLY if it DOES NOT exist in the DB
1767
+					/* @var $related_model_obj EE_Base_Class */
1768
+					$related_model_obj = $this->_model_relations[$relationName];
1769
+					//					if( ! $related_model_obj->ID()){
1770
+					$this->_add_relation_to($related_model_obj, $relationName);
1771
+					$related_model_obj->save_new_cached_related_model_objs();
1772
+					//					}
1773
+				} else {
1774
+					foreach ($this->_model_relations[$relationName] as $related_model_obj) {
1775
+						//add a relation to that relation type (which saves the appropriate thing in the process)
1776
+						//but ONLY if it DOES NOT exist in the DB
1777
+						//						if( ! $related_model_obj->ID()){
1778
+						$this->_add_relation_to($related_model_obj, $relationName);
1779
+						$related_model_obj->save_new_cached_related_model_objs();
1780
+						//						}
1781
+					}
1782
+				}
1783
+			}
1784
+		}
1785
+		return $id;
1786
+	}
1787
+
1788
+
1789
+
1790
+	/**
1791
+	 * for getting a model while instantiated.
1792
+	 *
1793
+	 * @return \EEM_Base | \EEM_CPT_Base
1794
+	 */
1795
+	public function get_model()
1796
+	{
1797
+		if( ! $this->_model){
1798
+			$modelName = self::_get_model_classname(get_class($this));
1799
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1800
+		} else {
1801
+			$this->_model->set_timezone($this->_timezone);
1802
+		}
1803
+
1804
+		return $this->_model;
1805
+	}
1806
+
1807
+
1808
+
1809
+	/**
1810
+	 * @param $props_n_values
1811
+	 * @param $classname
1812
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
1813
+	 * @throws \EE_Error
1814
+	 */
1815
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
1816
+	{
1817
+		//TODO: will not work for Term_Relationships because they have no PK!
1818
+		$primary_id_ref = self::_get_primary_key_name($classname);
1819
+		if (array_key_exists($primary_id_ref, $props_n_values) && ! empty($props_n_values[$primary_id_ref])) {
1820
+			$id = $props_n_values[$primary_id_ref];
1821
+			return self::_get_model($classname)->get_from_entity_map($id);
1822
+		}
1823
+		return false;
1824
+	}
1825
+
1826
+
1827
+
1828
+	/**
1829
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
1830
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
1831
+	 * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
1832
+	 * we return false.
1833
+	 *
1834
+	 * @param  array  $props_n_values   incoming array of properties and their values
1835
+	 * @param  string $classname        the classname of the child class
1836
+	 * @param null    $timezone
1837
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
1838
+	 *                                  date_format and the second value is the time format
1839
+	 * @return mixed (EE_Base_Class|bool)
1840
+	 * @throws \EE_Error
1841
+	 */
1842
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
1843
+	{
1844
+		$existing = null;
1845
+		$model = self::_get_model($classname, $timezone);
1846
+		if ($model->has_primary_key_field()) {
1847
+			$primary_id_ref = self::_get_primary_key_name($classname);
1848
+			if (array_key_exists($primary_id_ref, $props_n_values)
1849
+				&& ! empty($props_n_values[$primary_id_ref])
1850
+			) {
1851
+				$existing = $model->get_one_by_ID(
1852
+					$props_n_values[$primary_id_ref]
1853
+				);
1854
+			}
1855
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
1856
+			//no primary key on this model, but there's still a matching item in the DB
1857
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
1858
+				self::_get_model($classname, $timezone)->get_index_primary_key_string($props_n_values)
1859
+			);
1860
+		}
1861
+		if ($existing) {
1862
+			//set date formats if present before setting values
1863
+			if ( ! empty($date_formats) && is_array($date_formats)) {
1864
+				$existing->set_date_format($date_formats[0]);
1865
+				$existing->set_time_format($date_formats[1]);
1866
+			} else {
1867
+				//set default formats for date and time
1868
+				$existing->set_date_format(get_option('date_format'));
1869
+				$existing->set_time_format(get_option('time_format'));
1870
+			}
1871
+			foreach ($props_n_values as $property => $field_value) {
1872
+				$existing->set($property, $field_value);
1873
+			}
1874
+			return $existing;
1875
+		} else {
1876
+			return false;
1877
+		}
1878
+	}
1879
+
1880
+
1881
+
1882
+	/**
1883
+	 * Gets the EEM_*_Model for this class
1884
+	 *
1885
+	 * @access public now, as this is more convenient
1886
+	 * @param      $classname
1887
+	 * @param null $timezone
1888
+	 * @throws EE_Error
1889
+	 * @return EEM_Base
1890
+	 */
1891
+	protected static function _get_model($classname, $timezone = null)
1892
+	{
1893
+		//find model for this class
1894
+		if ( ! $classname) {
1895
+			throw new EE_Error(
1896
+				sprintf(
1897
+					__(
1898
+						"What were you thinking calling _get_model(%s)?? You need to specify the class name",
1899
+						"event_espresso"
1900
+					),
1901
+					$classname
1902
+				)
1903
+			);
1904
+		}
1905
+		$modelName = self::_get_model_classname($classname);
1906
+		return self::_get_model_instance_with_name($modelName, $timezone);
1907
+	}
1908
+
1909
+
1910
+
1911
+	/**
1912
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
1913
+	 *
1914
+	 * @param string $model_classname
1915
+	 * @param null   $timezone
1916
+	 * @return EEM_Base
1917
+	 */
1918
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
1919
+	{
1920
+		$model_classname = str_replace('EEM_', '', $model_classname);
1921
+		$model = EE_Registry::instance()->load_model($model_classname);
1922
+		$model->set_timezone($timezone);
1923
+		return $model;
1924
+	}
1925
+
1926
+
1927
+
1928
+	/**
1929
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
1930
+	 * Also works if a model class's classname is provided (eg EE_Registration).
1931
+	 *
1932
+	 * @param null $model_name
1933
+	 * @return string like EEM_Attendee
1934
+	 */
1935
+	private static function _get_model_classname($model_name = null)
1936
+	{
1937
+		if (strpos($model_name, "EE_") === 0) {
1938
+			$model_classname = str_replace("EE_", "EEM_", $model_name);
1939
+		} else {
1940
+			$model_classname = "EEM_" . $model_name;
1941
+		}
1942
+		return $model_classname;
1943
+	}
1944
+
1945
+
1946
+
1947
+	/**
1948
+	 * returns the name of the primary key attribute
1949
+	 *
1950
+	 * @param null $classname
1951
+	 * @throws EE_Error
1952
+	 * @return string
1953
+	 */
1954
+	protected static function _get_primary_key_name($classname = null)
1955
+	{
1956
+		if ( ! $classname) {
1957
+			throw new EE_Error(
1958
+				sprintf(
1959
+					__("What were you thinking calling _get_primary_key_name(%s)", "event_espresso"),
1960
+					$classname
1961
+				)
1962
+			);
1963
+		}
1964
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
1965
+	}
1966
+
1967
+
1968
+
1969
+	/**
1970
+	 * Gets the value of the primary key.
1971
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
1972
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
1973
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
1974
+	 *
1975
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
1976
+	 * @throws \EE_Error
1977
+	 */
1978
+	public function ID()
1979
+	{
1980
+		$model = $this->get_model();
1981
+		//now that we know the name of the variable, use a variable variable to get its value and return its
1982
+		if ($model->has_primary_key_field()) {
1983
+			return $this->_fields[$model->primary_key_name()];
1984
+		} else {
1985
+			return $model->get_index_primary_key_string($this->_fields);
1986
+		}
1987
+	}
1988
+
1989
+
1990
+
1991
+	/**
1992
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
1993
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
1994
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
1995
+	 *
1996
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
1997
+	 * @param string $relationName                     eg 'Events','Question',etc.
1998
+	 *                                                 an attendee to a group, you also want to specify which role they
1999
+	 *                                                 will have in that group. So you would use this parameter to
2000
+	 *                                                 specify array('role-column-name'=>'role-id')
2001
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2002
+	 *                                                 allow you to further constrict the relation to being added.
2003
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2004
+	 *                                                 column on the JOIN table and currently only the HABTM models
2005
+	 *                                                 accept these additional conditions.  Also remember that if an
2006
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2007
+	 *                                                 NEW row is created in the join table.
2008
+	 * @param null   $cache_id
2009
+	 * @throws EE_Error
2010
+	 * @return EE_Base_Class the object the relation was added to
2011
+	 */
2012
+	public function _add_relation_to(
2013
+		$otherObjectModelObjectOrID,
2014
+		$relationName,
2015
+		$extra_join_model_fields_n_values = array(),
2016
+		$cache_id = null
2017
+	) {
2018
+		$model = $this->get_model();
2019
+		//if this thing exists in the DB, save the relation to the DB
2020
+		if ($this->ID()) {
2021
+			$otherObject = $model
2022
+								->add_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2023
+									$extra_join_model_fields_n_values);
2024
+			//clear cache so future get_many_related and get_first_related() return new results.
2025
+			$this->clear_cache($relationName, $otherObject, true);
2026
+			if ($otherObject instanceof EE_Base_Class) {
2027
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2028
+			}
2029
+		} else {
2030
+			//this thing doesn't exist in the DB,  so just cache it
2031
+			if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2032
+				throw new EE_Error(sprintf(
2033
+					__('Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2034
+						'event_espresso'),
2035
+					$otherObjectModelObjectOrID,
2036
+					get_class($this)
2037
+				));
2038
+			} else {
2039
+				$otherObject = $otherObjectModelObjectOrID;
2040
+			}
2041
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2042
+		}
2043
+		if ($otherObject instanceof EE_Base_Class) {
2044
+			//fix the reciprocal relation too
2045
+			if ($otherObject->ID()) {
2046
+				//its saved so assumed relations exist in the DB, so we can just
2047
+				//clear the cache so future queries use the updated info in the DB
2048
+				$otherObject->clear_cache($model->get_this_model_name(), null, true);
2049
+			} else {
2050
+				//it's not saved, so it caches relations like this
2051
+				$otherObject->cache($model->get_this_model_name(), $this);
2052
+			}
2053
+		}
2054
+		return $otherObject;
2055
+	}
2056
+
2057
+
2058
+
2059
+	/**
2060
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2061
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2062
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2063
+	 * from the cache
2064
+	 *
2065
+	 * @param mixed  $otherObjectModelObjectOrID
2066
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2067
+	 *                to the DB yet
2068
+	 * @param string $relationName
2069
+	 * @param array  $where_query
2070
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2071
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2072
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2073
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2074
+	 *                created in the join table.
2075
+	 * @return EE_Base_Class the relation was removed from
2076
+	 * @throws \EE_Error
2077
+	 */
2078
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2079
+	{
2080
+		if ($this->ID()) {
2081
+			//if this exists in the DB, save the relation change to the DB too
2082
+			$otherObject = $this->get_model()
2083
+								->remove_relationship_to($this, $otherObjectModelObjectOrID, $relationName,
2084
+									$where_query);
2085
+			$this->clear_cache($relationName, $otherObject);
2086
+		} else {
2087
+			//this doesn't exist in the DB, just remove it from the cache
2088
+			$otherObject = $this->clear_cache($relationName, $otherObjectModelObjectOrID);
2089
+		}
2090
+		if ($otherObject instanceof EE_Base_Class) {
2091
+			$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2092
+		}
2093
+		return $otherObject;
2094
+	}
2095
+
2096
+
2097
+
2098
+	/**
2099
+	 * Removes ALL the related things for the $relationName.
2100
+	 *
2101
+	 * @param string $relationName
2102
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2103
+	 * @return EE_Base_Class
2104
+	 * @throws \EE_Error
2105
+	 */
2106
+	public function _remove_relations($relationName, $where_query_params = array())
2107
+	{
2108
+		if ($this->ID()) {
2109
+			//if this exists in the DB, save the relation change to the DB too
2110
+			$otherObjects = $this->get_model()->remove_relations($this, $relationName, $where_query_params);
2111
+			$this->clear_cache($relationName, null, true);
2112
+		} else {
2113
+			//this doesn't exist in the DB, just remove it from the cache
2114
+			$otherObjects = $this->clear_cache($relationName, null, true);
2115
+		}
2116
+		if (is_array($otherObjects)) {
2117
+			foreach ($otherObjects as $otherObject) {
2118
+				$otherObject->clear_cache($this->get_model()->get_this_model_name(), $this);
2119
+			}
2120
+		}
2121
+		return $otherObjects;
2122
+	}
2123
+
2124
+
2125
+
2126
+	/**
2127
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2128
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2129
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2130
+	 * because we want to get even deleted items etc.
2131
+	 *
2132
+	 * @param string $relationName key in the model's _model_relations array
2133
+	 * @param array  $query_params like EEM_Base::get_all
2134
+	 * @return EE_Base_Class[] Results not necessarily indexed by IDs, because some results might not have primary keys
2135
+	 * @throws \EE_Error
2136
+	 *                             or might not be saved yet. Consider using EEM_Base::get_IDs() on these results if
2137
+	 *                             you want IDs
2138
+	 */
2139
+	public function get_many_related($relationName, $query_params = array())
2140
+	{
2141
+		if ($this->ID()) {
2142
+			//this exists in the DB, so get the related things from either the cache or the DB
2143
+			//if there are query parameters, forget about caching the related model objects.
2144
+			if ($query_params) {
2145
+				$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2146
+			} else {
2147
+				//did we already cache the result of this query?
2148
+				$cached_results = $this->get_all_from_cache($relationName);
2149
+				if ( ! $cached_results) {
2150
+					$related_model_objects = $this->get_model()->get_all_related($this, $relationName, $query_params);
2151
+					//if no query parameters were passed, then we got all the related model objects
2152
+					//for that relation. We can cache them then.
2153
+					foreach ($related_model_objects as $related_model_object) {
2154
+						$this->cache($relationName, $related_model_object);
2155
+					}
2156
+				} else {
2157
+					$related_model_objects = $cached_results;
2158
+				}
2159
+			}
2160
+		} else {
2161
+			//this doesn't exist in the DB, so just get the related things from the cache
2162
+			$related_model_objects = $this->get_all_from_cache($relationName);
2163
+		}
2164
+		return $related_model_objects;
2165
+	}
2166
+
2167
+
2168
+
2169
+	/**
2170
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2171
+	 * unless otherwise specified in the $query_params
2172
+	 *
2173
+	 * @param string $relation_name  model_name like 'Event', or 'Registration'
2174
+	 * @param array  $query_params   like EEM_Base::get_all's
2175
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2176
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2177
+	 *                               that by the setting $distinct to TRUE;
2178
+	 * @return int
2179
+	 */
2180
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2181
+	{
2182
+		return $this->get_model()->count_related($this, $relation_name, $query_params, $field_to_count, $distinct);
2183
+	}
2184
+
2185
+
2186
+
2187
+	/**
2188
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2189
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2190
+	 *
2191
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2192
+	 * @param array  $query_params  like EEM_Base::get_all's
2193
+	 * @param string $field_to_sum  name of field to count by.
2194
+	 *                              By default, uses primary key (which doesn't make much sense, so you should probably
2195
+	 *                              change it)
2196
+	 * @return int
2197
+	 */
2198
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2199
+	{
2200
+		return $this->get_model()->sum_related($this, $relation_name, $query_params, $field_to_sum);
2201
+	}
2202
+
2203
+
2204
+
2205
+	/**
2206
+	 * Gets the first (ie, one) related model object of the specified type.
2207
+	 *
2208
+	 * @param string $relationName key in the model's _model_relations array
2209
+	 * @param array  $query_params like EEM_Base::get_all
2210
+	 * @return EE_Base_Class (not an array, a single object)
2211
+	 * @throws \EE_Error
2212
+	 */
2213
+	public function get_first_related($relationName, $query_params = array())
2214
+	{
2215
+		$model = $this->get_model();
2216
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2217
+			//if they've provided some query parameters, don't bother trying to cache the result
2218
+			//also make sure we're not caching the result of get_first_related
2219
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2220
+			if ($query_params
2221
+				|| ! $model->related_settings_for($relationName)
2222
+					 instanceof
2223
+					 EE_Belongs_To_Relation
2224
+			) {
2225
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2226
+			} else {
2227
+				//first, check if we've already cached the result of this query
2228
+				$cached_result = $this->get_one_from_cache($relationName);
2229
+				if ( ! $cached_result) {
2230
+					$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2231
+					$this->cache($relationName, $related_model_object);
2232
+				} else {
2233
+					$related_model_object = $cached_result;
2234
+				}
2235
+			}
2236
+		} else {
2237
+			$related_model_object = null;
2238
+			//this doesn't exist in the Db, but maybe the relation is of type belongs to, and so the related thing might
2239
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2240
+				$related_model_object = $model->get_first_related($this, $relationName, $query_params);
2241
+			}
2242
+			//this doesn't exist in the DB and apparently the thing it belongs to doesn't either, just get what's cached on this object
2243
+			if ( ! $related_model_object) {
2244
+				$related_model_object = $this->get_one_from_cache($relationName);
2245
+			}
2246
+		}
2247
+		return $related_model_object;
2248
+	}
2249
+
2250
+
2251
+
2252
+	/**
2253
+	 * Does a delete on all related objects of type $relationName and removes
2254
+	 * the current model object's relation to them. If they can't be deleted (because
2255
+	 * of blocking related model objects) does nothing. If the related model objects are
2256
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2257
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2258
+	 *
2259
+	 * @param string $relationName
2260
+	 * @param array  $query_params like EEM_Base::get_all's
2261
+	 * @return int how many deleted
2262
+	 * @throws \EE_Error
2263
+	 */
2264
+	public function delete_related($relationName, $query_params = array())
2265
+	{
2266
+		if ($this->ID()) {
2267
+			$count = $this->get_model()->delete_related($this, $relationName, $query_params);
2268
+		} else {
2269
+			$count = count($this->get_all_from_cache($relationName));
2270
+			$this->clear_cache($relationName, null, true);
2271
+		}
2272
+		return $count;
2273
+	}
2274
+
2275
+
2276
+
2277
+	/**
2278
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2279
+	 * the current model object's relation to them. If they can't be deleted (because
2280
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2281
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2282
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2283
+	 *
2284
+	 * @param string $relationName
2285
+	 * @param array  $query_params like EEM_Base::get_all's
2286
+	 * @return int how many deleted (including those soft deleted)
2287
+	 * @throws \EE_Error
2288
+	 */
2289
+	public function delete_related_permanently($relationName, $query_params = array())
2290
+	{
2291
+		if ($this->ID()) {
2292
+			$count = $this->get_model()->delete_related_permanently($this, $relationName, $query_params);
2293
+		} else {
2294
+			$count = count($this->get_all_from_cache($relationName));
2295
+		}
2296
+		$this->clear_cache($relationName, null, true);
2297
+		return $count;
2298
+	}
2299
+
2300
+
2301
+
2302
+	/**
2303
+	 * is_set
2304
+	 * Just a simple utility function children can use for checking if property exists
2305
+	 *
2306
+	 * @access  public
2307
+	 * @param  string $field_name property to check
2308
+	 * @return bool                              TRUE if existing,FALSE if not.
2309
+	 */
2310
+	public function is_set($field_name)
2311
+	{
2312
+		return isset($this->_fields[$field_name]);
2313
+	}
2314
+
2315
+
2316
+
2317
+	/**
2318
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2319
+	 * EE_Error exception if they don't
2320
+	 *
2321
+	 * @param  mixed (string|array) $properties properties to check
2322
+	 * @throws EE_Error
2323
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2324
+	 */
2325
+	protected function _property_exists($properties)
2326
+	{
2327
+		foreach ((array)$properties as $property_name) {
2328
+			//first make sure this property exists
2329
+			if ( ! $this->_fields[$property_name]) {
2330
+				throw new EE_Error(
2331
+					sprintf(
2332
+						__(
2333
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2334
+							'event_espresso'
2335
+						),
2336
+						$property_name
2337
+					)
2338
+				);
2339
+			}
2340
+		}
2341
+		return true;
2342
+	}
2343
+
2344
+
2345
+
2346
+	/**
2347
+	 * This simply returns an array of model fields for this object
2348
+	 *
2349
+	 * @return array
2350
+	 * @throws \EE_Error
2351
+	 */
2352
+	public function model_field_array()
2353
+	{
2354
+		$fields = $this->get_model()->field_settings(false);
2355
+		$properties = array();
2356
+		//remove prepended underscore
2357
+		foreach ($fields as $field_name => $settings) {
2358
+			$properties[$field_name] = $this->get($field_name);
2359
+		}
2360
+		return $properties;
2361
+	}
2362
+
2363
+
2364
+
2365
+	/**
2366
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2367
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2368
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments. Instead of
2369
+	 * requiring a plugin to extend the EE_Base_Class (which works fine is there's only 1 plugin, but when will that
2370
+	 * happen?) they can add a hook onto 'filters_hook_espresso__{className}__{methodName}' (eg,
2371
+	 * filters_hook_espresso__EE_Answer__my_great_function) and accepts 2 arguments: the object on which the function
2372
+	 * was called, and an array of the original arguments passed to the function. Whatever their callback function
2373
+	 * returns will be returned by this function. Example: in functions.php (or in a plugin):
2374
+	 * add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3); function
2375
+	 * my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2376
+	 * $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2377
+	 *        return $previousReturnValue.$returnString;
2378
+	 * }
2379
+	 * require('EE_Answer.class.php');
2380
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2381
+	 * echo $answer->my_callback('monkeys',100);
2382
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2383
+	 *
2384
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2385
+	 * @param array  $args       array of original arguments passed to the function
2386
+	 * @throws EE_Error
2387
+	 * @return mixed whatever the plugin which calls add_filter decides
2388
+	 */
2389
+	public function __call($methodName, $args)
2390
+	{
2391
+		$className = get_class($this);
2392
+		$tagName = "FHEE__{$className}__{$methodName}";
2393
+		if ( ! has_filter($tagName)) {
2394
+			throw new EE_Error(
2395
+				sprintf(
2396
+					__(
2397
+						"Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2398
+						"event_espresso"
2399
+					),
2400
+					$methodName,
2401
+					$className,
2402
+					$tagName
2403
+				)
2404
+			);
2405
+		}
2406
+		return apply_filters($tagName, null, $this, $args);
2407
+	}
2408
+
2409
+
2410
+
2411
+	/**
2412
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2413
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2414
+	 *
2415
+	 * @param string $meta_key
2416
+	 * @param mixed  $meta_value
2417
+	 * @param mixed  $previous_value
2418
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2419
+	 * @throws \EE_Error
2420
+	 * NOTE: if the values haven't changed, returns 0
2421
+	 */
2422
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2423
+	{
2424
+		$query_params = array(
2425
+			array(
2426
+				'EXM_key'  => $meta_key,
2427
+				'OBJ_ID'   => $this->ID(),
2428
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2429
+			),
2430
+		);
2431
+		if ($previous_value !== null) {
2432
+			$query_params[0]['EXM_value'] = $meta_value;
2433
+		}
2434
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2435
+		if ( ! $existing_rows_like_that) {
2436
+			return $this->add_extra_meta($meta_key, $meta_value);
2437
+		}
2438
+		foreach ($existing_rows_like_that as $existing_row) {
2439
+			$existing_row->save(array('EXM_value' => $meta_value));
2440
+		}
2441
+		return count($existing_rows_like_that);
2442
+	}
2443
+
2444
+
2445
+
2446
+	/**
2447
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2448
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2449
+	 * extra meta row was entered, false if not
2450
+	 *
2451
+	 * @param string  $meta_key
2452
+	 * @param mixed   $meta_value
2453
+	 * @param boolean $unique
2454
+	 * @return boolean
2455
+	 * @throws \EE_Error
2456
+	 */
2457
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2458
+	{
2459
+		if ($unique) {
2460
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2461
+				array(
2462
+					array(
2463
+						'EXM_key'  => $meta_key,
2464
+						'OBJ_ID'   => $this->ID(),
2465
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2466
+					),
2467
+				)
2468
+			);
2469
+			if ($existing_extra_meta) {
2470
+				return false;
2471
+			}
2472
+		}
2473
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2474
+			array(
2475
+				'EXM_key'   => $meta_key,
2476
+				'EXM_value' => $meta_value,
2477
+				'OBJ_ID'    => $this->ID(),
2478
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2479
+			)
2480
+		);
2481
+		$new_extra_meta->save();
2482
+		return true;
2483
+	}
2484
+
2485
+
2486
+
2487
+	/**
2488
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2489
+	 * is specified, only deletes extra meta records with that value.
2490
+	 *
2491
+	 * @param string $meta_key
2492
+	 * @param mixed  $meta_value
2493
+	 * @return int number of extra meta rows deleted
2494
+	 * @throws \EE_Error
2495
+	 */
2496
+	public function delete_extra_meta($meta_key, $meta_value = null)
2497
+	{
2498
+		$query_params = array(
2499
+			array(
2500
+				'EXM_key'  => $meta_key,
2501
+				'OBJ_ID'   => $this->ID(),
2502
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2503
+			),
2504
+		);
2505
+		if ($meta_value !== null) {
2506
+			$query_params[0]['EXM_value'] = $meta_value;
2507
+		}
2508
+		return EEM_Extra_Meta::instance()->delete($query_params);
2509
+	}
2510
+
2511
+
2512
+
2513
+	/**
2514
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2515
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2516
+	 * You can specify $default is case you haven't found the extra meta
2517
+	 *
2518
+	 * @param string  $meta_key
2519
+	 * @param boolean $single
2520
+	 * @param mixed   $default if we don't find anything, what should we return?
2521
+	 * @return mixed single value if $single; array if ! $single
2522
+	 * @throws \EE_Error
2523
+	 */
2524
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2525
+	{
2526
+		if ($single) {
2527
+			$result = $this->get_first_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2528
+			if ($result instanceof EE_Extra_Meta) {
2529
+				return $result->value();
2530
+			}
2531
+		} else {
2532
+			$results = $this->get_many_related('Extra_Meta', array(array('EXM_key' => $meta_key)));
2533
+			if ($results) {
2534
+				$values = array();
2535
+				foreach ($results as $result) {
2536
+					if ($result instanceof EE_Extra_Meta) {
2537
+						$values[$result->ID()] = $result->value();
2538
+					}
2539
+				}
2540
+				return $values;
2541
+			}
2542
+		}
2543
+		//if nothing discovered yet return default.
2544
+		return apply_filters(
2545
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2546
+			$default,
2547
+			$meta_key,
2548
+			$single,
2549
+			$this
2550
+			);
2551
+	}
2552
+
2553
+
2554
+
2555
+	/**
2556
+	 * Returns a simple array of all the extra meta associated with this model object.
2557
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2558
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2559
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2560
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2561
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2562
+	 * finally the extra meta's value as each sub-value. (eg
2563
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2564
+	 *
2565
+	 * @param boolean $one_of_each_key
2566
+	 * @return array
2567
+	 * @throws \EE_Error
2568
+	 */
2569
+	public function all_extra_meta_array($one_of_each_key = true)
2570
+	{
2571
+		$return_array = array();
2572
+		if ($one_of_each_key) {
2573
+			$extra_meta_objs = $this->get_many_related('Extra_Meta', array('group_by' => 'EXM_key'));
2574
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2575
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2576
+					$return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2577
+				}
2578
+			}
2579
+		} else {
2580
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2581
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2582
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2583
+					if ( ! isset($return_array[$extra_meta_obj->key()])) {
2584
+						$return_array[$extra_meta_obj->key()] = array();
2585
+					}
2586
+					$return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2587
+				}
2588
+			}
2589
+		}
2590
+		return $return_array;
2591
+	}
2592
+
2593
+
2594
+
2595
+	/**
2596
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2597
+	 *
2598
+	 * @return string
2599
+	 * @throws \EE_Error
2600
+	 */
2601
+	public function name()
2602
+	{
2603
+		//find a field that's not a text field
2604
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2605
+		if ($field_we_can_use) {
2606
+			return $this->get($field_we_can_use->get_name());
2607
+		} else {
2608
+			$first_few_properties = $this->model_field_array();
2609
+			$first_few_properties = array_slice($first_few_properties, 0, 3);
2610
+			$name_parts = array();
2611
+			foreach ($first_few_properties as $name => $value) {
2612
+				$name_parts[] = "$name:$value";
2613
+			}
2614
+			return implode(",", $name_parts);
2615
+		}
2616
+	}
2617
+
2618
+
2619
+
2620
+	/**
2621
+	 * in_entity_map
2622
+	 * Checks if this model object has been proven to already be in the entity map
2623
+	 *
2624
+	 * @return boolean
2625
+	 * @throws \EE_Error
2626
+	 */
2627
+	public function in_entity_map()
2628
+	{
2629
+		if ($this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this) {
2630
+			//well, if we looked, did we find it in the entity map?
2631
+			return true;
2632
+		} else {
2633
+			return false;
2634
+		}
2635
+	}
2636
+
2637
+
2638
+
2639
+	/**
2640
+	 * refresh_from_db
2641
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
2642
+	 *
2643
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
2644
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
2645
+	 */
2646
+	public function refresh_from_db()
2647
+	{
2648
+		if ($this->ID() && $this->in_entity_map()) {
2649
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
2650
+		} else {
2651
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
2652
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
2653
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
2654
+			//absolutely nothing in it for this ID
2655
+			if (WP_DEBUG) {
2656
+				throw new EE_Error(
2657
+					sprintf(
2658
+						__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
2659
+							'event_espresso'),
2660
+						$this->ID(),
2661
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2662
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2663
+					)
2664
+				);
2665
+			}
2666
+		}
2667
+	}
2668
+
2669
+
2670
+
2671
+	/**
2672
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
2673
+	 * (probably a bad assumption they have made, oh well)
2674
+	 *
2675
+	 * @return string
2676
+	 */
2677
+	public function __toString()
2678
+	{
2679
+		try {
2680
+			return sprintf('%s (%s)', $this->name(), $this->ID());
2681
+		} catch (Exception $e) {
2682
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
2683
+			return '';
2684
+		}
2685
+	}
2686
+
2687
+
2688
+
2689
+	/**
2690
+	 * Clear related model objects if they're already in the DB, because otherwise when we
2691
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
2692
+	 * This means if we have made changes to those related model objects, and want to unserialize
2693
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
2694
+	 * Instead, those related model objects should be directly serialized and stored.
2695
+	 * Eg, the following won't work:
2696
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2697
+	 * $att = $reg->attendee();
2698
+	 * $att->set( 'ATT_fname', 'Dirk' );
2699
+	 * update_option( 'my_option', serialize( $reg ) );
2700
+	 * //END REQUEST
2701
+	 * //START NEXT REQUEST
2702
+	 * $reg = get_option( 'my_option' );
2703
+	 * $reg->attendee()->save();
2704
+	 * And would need to be replace with:
2705
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
2706
+	 * $att = $reg->attendee();
2707
+	 * $att->set( 'ATT_fname', 'Dirk' );
2708
+	 * update_option( 'my_option', serialize( $reg ) );
2709
+	 * //END REQUEST
2710
+	 * //START NEXT REQUEST
2711
+	 * $att = get_option( 'my_option' );
2712
+	 * $att->save();
2713
+	 *
2714
+	 * @return array
2715
+	 * @throws \EE_Error
2716
+	 */
2717
+	public function __sleep()
2718
+	{
2719
+		$model = $this->get_model();
2720
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2721
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
2722
+				$classname = 'EE_' . $model->get_this_model_name();
2723
+				if (
2724
+					$this->get_one_from_cache($relation_name) instanceof $classname
2725
+					&& $this->get_one_from_cache($relation_name)->ID()
2726
+				) {
2727
+					$this->clear_cache($relation_name, $this->get_one_from_cache($relation_name)->ID());
2728
+				}
2729
+			}
2730
+		}
2731
+		$this->_props_n_values_provided_in_constructor = array();
2732
+		$properties_to_serialize = get_object_vars($this);
2733
+		//don't serialize the model. It's big and that risks recursion
2734
+		unset($properties_to_serialize['_model']);
2735
+		return array_keys($properties_to_serialize);
2736
+	}
2737
+
2738
+
2739
+
2740
+	/**
2741
+	 * restore _props_n_values_provided_in_constructor
2742
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
2743
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
2744
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
2745
+	 */
2746
+	public function __wakeup()
2747
+	{
2748
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
2749
+	}
2750 2750
 
2751 2751
 
2752 2752
 
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -155,8 +155,8 @@  discard block
 block discarded – undo
155 155
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
156 156
         } else {
157 157
             //set default formats for date and time
158
-            $this->_dt_frmt = (string)get_option('date_format', 'Y-m-d');
159
-            $this->_tm_frmt = (string)get_option('time_format', 'g:i a');
158
+            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
159
+            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
160 160
         }
161 161
         //if db model is instantiating
162 162
         if ($bydb) {
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
      */
479 479
     public function get_format($full = true)
480 480
     {
481
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
481
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
482 482
     }
483 483
 
484 484
 
@@ -587,7 +587,7 @@  discard block
 block discarded – undo
587 587
         $model = $this->get_model();
588 588
         $model->field_settings_for($fieldname);
589 589
         $cache_type = $pretty ? 'pretty' : 'standard';
590
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
590
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
591 591
         if (isset($this->_cached_properties[$fieldname][$cache_type])) {
592 592
             return $this->_cached_properties[$fieldname][$cache_type];
593 593
         }
@@ -814,7 +814,7 @@  discard block
 block discarded – undo
814 814
         $current_cache_id = ''
815 815
     ) {
816 816
         // verify that incoming object is of the correct type
817
-        $obj_class = 'EE_' . $relationName;
817
+        $obj_class = 'EE_'.$relationName;
818 818
         if ($newly_saved_object instanceof $obj_class) {
819 819
             /* @type EE_Base_Class $newly_saved_object */
820 820
             // now get the type of relation
@@ -1153,7 +1153,7 @@  discard block
 block discarded – undo
1153 1153
      */
1154 1154
     public function get_f($field_name)
1155 1155
     {
1156
-        return (string)$this->get_pretty($field_name,'form_input');
1156
+        return (string) $this->get_pretty($field_name, 'form_input');
1157 1157
     }
1158 1158
 
1159 1159
 
@@ -1310,7 +1310,7 @@  discard block
 block discarded – undo
1310 1310
      */
1311 1311
     public function get_i18n_datetime($field_name, $format = '')
1312 1312
     {
1313
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1313
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1314 1314
         return date_i18n(
1315 1315
             $format,
1316 1316
             EEH_DTT_Helper::get_timestamp_with_offset($this->get_raw($field_name), $this->_timezone)
@@ -1448,8 +1448,8 @@  discard block
 block discarded – undo
1448 1448
         }
1449 1449
         $original_timezone = $this->_timezone;
1450 1450
         $this->set_timezone($timezone);
1451
-        $fn = (array)$field_name;
1452
-        $args = array_merge($fn, (array)$args);
1451
+        $fn = (array) $field_name;
1452
+        $args = array_merge($fn, (array) $args);
1453 1453
         if ( ! method_exists($this, $callback)) {
1454 1454
             throw new EE_Error(
1455 1455
                 sprintf(
@@ -1461,8 +1461,8 @@  discard block
 block discarded – undo
1461 1461
                 )
1462 1462
             );
1463 1463
         }
1464
-        $args = (array)$args;
1465
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1464
+        $args = (array) $args;
1465
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1466 1466
         $this->set_timezone($original_timezone);
1467 1467
         return $return;
1468 1468
     }
@@ -1601,14 +1601,14 @@  discard block
 block discarded – undo
1601 1601
          * @param array         $set_cols_n_values
1602 1602
          * @param EE_Base_Class $model_object
1603 1603
          */
1604
-        $set_cols_n_values = (array)apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1604
+        $set_cols_n_values = (array) apply_filters('FHEE__EE_Base_Class__save__set_cols_n_values', $set_cols_n_values,
1605 1605
             $this);
1606 1606
         //set attributes as provided in $set_cols_n_values
1607 1607
         foreach ($set_cols_n_values as $column => $value) {
1608 1608
             $this->set($column, $value);
1609 1609
         }
1610 1610
         // no changes ? then don't do anything
1611
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1611
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1612 1612
             return 0;
1613 1613
         }
1614 1614
         /**
@@ -1660,8 +1660,8 @@  discard block
 block discarded – undo
1660 1660
                                 __('Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1661 1661
                                     'event_espresso'),
1662 1662
                                 get_class($this),
1663
-                                get_class($model) . '::instance()->add_to_entity_map()',
1664
-                                get_class($model) . '::instance()->get_one_by_ID()',
1663
+                                get_class($model).'::instance()->add_to_entity_map()',
1664
+                                get_class($model).'::instance()->get_one_by_ID()',
1665 1665
                                 '<br />'
1666 1666
                             )
1667 1667
                         );
@@ -1794,7 +1794,7 @@  discard block
 block discarded – undo
1794 1794
      */
1795 1795
     public function get_model()
1796 1796
     {
1797
-        if( ! $this->_model){
1797
+        if ( ! $this->_model) {
1798 1798
             $modelName = self::_get_model_classname(get_class($this));
1799 1799
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
1800 1800
         } else {
@@ -1937,7 +1937,7 @@  discard block
 block discarded – undo
1937 1937
         if (strpos($model_name, "EE_") === 0) {
1938 1938
             $model_classname = str_replace("EE_", "EEM_", $model_name);
1939 1939
         } else {
1940
-            $model_classname = "EEM_" . $model_name;
1940
+            $model_classname = "EEM_".$model_name;
1941 1941
         }
1942 1942
         return $model_classname;
1943 1943
     }
@@ -2324,7 +2324,7 @@  discard block
 block discarded – undo
2324 2324
      */
2325 2325
     protected function _property_exists($properties)
2326 2326
     {
2327
-        foreach ((array)$properties as $property_name) {
2327
+        foreach ((array) $properties as $property_name) {
2328 2328
             //first make sure this property exists
2329 2329
             if ( ! $this->_fields[$property_name]) {
2330 2330
                 throw new EE_Error(
@@ -2658,8 +2658,8 @@  discard block
 block discarded – undo
2658 2658
                         __('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
2659 2659
                             'event_espresso'),
2660 2660
                         $this->ID(),
2661
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
2662
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
2661
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
2662
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
2663 2663
                     )
2664 2664
                 );
2665 2665
             }
@@ -2719,7 +2719,7 @@  discard block
 block discarded – undo
2719 2719
         $model = $this->get_model();
2720 2720
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
2721 2721
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
2722
-                $classname = 'EE_' . $model->get_this_model_name();
2722
+                $classname = 'EE_'.$model->get_this_model_name();
2723 2723
                 if (
2724 2724
                     $this->get_one_from_cache($relation_name) instanceof $classname
2725 2725
                     && $this->get_one_from_cache($relation_name)->ID()
Please login to merge, or discard this patch.
caffeinated/payment_methods/Paypal_Pro/EEG_Paypal_Pro.gateway.php 2 patches
Indentation   +588 added lines, -588 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if (! defined('EVENT_ESPRESSO_VERSION')) {
3
-    exit('No direct script access allowed');
3
+	exit('No direct script access allowed');
4 4
 }
5 5
 
6 6
 
@@ -25,592 +25,592 @@  discard block
 block discarded – undo
25 25
 class EEG_Paypal_Pro extends EE_Onsite_Gateway
26 26
 {
27 27
 
28
-    /**
29
-     * @var $_paypal_api_username string
30
-     */
31
-    protected $_username = null;
32
-
33
-    /**
34
-     * @var $_password string
35
-     */
36
-    protected $_password = null;
37
-
38
-    /**
39
-     * @var $_signature string
40
-     */
41
-    protected $_signature = null;
42
-
43
-    /**
44
-     * @var $_credit_card_types array with the keys for credit card types accepted on this account
45
-     */
46
-    protected $_credit_card_types    = null;
47
-
48
-    protected $_currencies_supported = array(
49
-        'USD',
50
-        'GBP',
51
-        'CAD',
52
-        'AUD',
53
-        'BRL',
54
-        'CHF',
55
-        'CZK',
56
-        'DKK',
57
-        'EUR',
58
-        'HKD',
59
-        'HUF',
60
-        'ILS',
61
-        'JPY',
62
-        'MXN',
63
-        'MYR',
64
-        'NOK',
65
-        'NZD',
66
-        'PHP',
67
-        'PLN',
68
-        'SEK',
69
-        'SGD',
70
-        'THB',
71
-        'TRY',
72
-        'TWD',
73
-        'RUB',
74
-    );
75
-
76
-
77
-
78
-    /**
79
-     * @param EEI_Payment $payment
80
-     * @param array       $billing_info {
81
-     * @type string $credit_card
82
-     * @type string $credit_card_type
83
-     * @type string $exp_month always 2 characters
84
-     * @type string $exp_year always 4 characters
85
-     * @type string $cvv
86
-     * }
87
-     * @see      parent::do_direct_payment for more info
88
-     * @return EE_Payment|EEI_Payment
89
-     * @throws EE_Error
90
-     */
91
-    public function do_direct_payment($payment, $billing_info = null)
92
-    {
93
-        $transaction = $payment->transaction();
94
-        if (! $transaction instanceof EEI_Transaction) {
95
-            throw new EE_Error(
96
-                esc_html__('No transaction for payment while paying with PayPal Pro.', 'event_espresso')
97
-            );
98
-        }
99
-        $primary_registrant = $transaction->primary_registration();
100
-        if (! $primary_registrant instanceof EEI_Registration) {
101
-            throw new EE_Error(
102
-                esc_html__(
103
-                    'No primary registration on transaction while paying with PayPal Pro.',
104
-                    'event_espresso'
105
-                )
106
-            );
107
-        }
108
-        $attendee = $primary_registrant->attendee();
109
-        if (! $attendee instanceof EEI_Attendee) {
110
-            throw new EE_Error(
111
-                esc_html__(
112
-                    'No attendee on primary registration while paying with PayPal Pro.',
113
-                    'event_espresso'
114
-                )
115
-            );
116
-        }
117
-        $gateway_formatter = $this->_get_gateway_formatter();
118
-        $order_description = substr($gateway_formatter->formatOrderDescription($payment), 0, 127);
119
-        //charge for the full amount. Show itemized list
120
-        if ($this->_can_easily_itemize_transaction_for($payment)) {
121
-            $item_num = 1;
122
-            $total_line_item = $transaction->total_line_item();
123
-            $order_items = array();
124
-            foreach ($total_line_item->get_items() as $line_item) {
125
-                //ignore line items with a quantity of 0
126
-                if ($line_item->quantity() == 0) {
127
-                    continue;
128
-                }
129
-                $item = array(
130
-                    // Item Name.  127 char max.
131
-                    'l_name'                 => substr(
132
-                        $gateway_formatter->formatLineItemName($line_item, $payment),
133
-                        0,
134
-                        127
135
-                    ),
136
-                    // Item description.  127 char max.
137
-                    'l_desc'                 => substr(
138
-                        $gateway_formatter->formatLineItemDesc($line_item, $payment),
139
-                        0,
140
-                        127
141
-                    ),
142
-                    // Cost of individual item.
143
-                    'l_amt'                  => $line_item->unit_price(),
144
-                    // Item Number.  127 char max.
145
-                    'l_number'               => $item_num++,
146
-                    // Item quantity.  Must be any positive integer.
147
-                    'l_qty'                  => $line_item->quantity(),
148
-                    // Item's sales tax amount.
149
-                    'l_taxamt'               => '',
150
-                    // eBay auction number of item.
151
-                    'l_ebayitemnumber'       => '',
152
-                    // eBay transaction ID of purchased item.
153
-                    'l_ebayitemauctiontxnid' => '',
154
-                    // eBay order ID for the item.
155
-                    'l_ebayitemorderid'      => '',
156
-                );
157
-                // add to array of all items
158
-                array_push($order_items, $item);
159
-            }
160
-            $item_amount = $total_line_item->get_items_total();
161
-            $tax_amount = $total_line_item->get_total_tax();
162
-        } else {
163
-            $order_items = array();
164
-            $item_amount = $payment->amount();
165
-            $tax_amount = 0;
166
-            array_push($order_items, array(
167
-                // Item Name.  127 char max.
168
-                'l_name'   => substr(
169
-                    $gateway_formatter->formatPartialPaymentLineItemName($payment),
170
-                    0,
171
-                    127
172
-                ),
173
-                // Item description.  127 char max.
174
-                'l_desc'   => substr(
175
-                    $gateway_formatter->formatPartialPaymentLineItemDesc($payment),
176
-                    0,
177
-                    127
178
-                ),
179
-                // Cost of individual item.
180
-                'l_amt'    => $payment->amount(),
181
-                // Item Number.  127 char max.
182
-                'l_number' => 1,
183
-                // Item quantity.  Must be any positive integer.
184
-                'l_qty'    => 1,
185
-            ));
186
-        }
187
-        // Populate data arrays with order data.
188
-        $DPFields = array(
189
-            // How you want to obtain payment ?
190
-            // Authorization indicates the payment is a basic auth subject to settlement with Auth & Capture.
191
-            // Sale indicates that this is a final sale for which you are requesting payment.  Default is Sale.
192
-            'paymentaction'    => 'Sale',
193
-            // Required.  IP address of the payer's browser.
194
-            'ipaddress'        => $_SERVER['REMOTE_ADDR'],
195
-            // Flag to determine whether you want the results returned by FMF.  1 or 0.  Default is 0.
196
-            'returnfmfdetails' => '1',
197
-        );
198
-        $CCDetails = array(
199
-            // Required. Type of credit card.  Visa, MasterCard, Discover, Amex, Maestro, Solo.
200
-            // If Maestro or Solo, the currency code must be GBP.
201
-            //  In addition, either start date or issue number must be specified.
202
-            'creditcardtype' => $billing_info['credit_card_type'],
203
-            // Required.  Credit card number.  No spaces or punctuation.
204
-            'acct'           => $billing_info['credit_card'],
205
-            // Required.  Credit card expiration date.  Format is MMYYYY
206
-            'expdate'        => $billing_info['exp_month'] . $billing_info['exp_year'],
207
-            // Requirements determined by your PayPal account settings.  Security digits for credit card.
208
-            'cvv2'           => $billing_info['cvv'],
209
-        );
210
-        $PayerInfo = array(
211
-            // Email address of payer.
212
-            'email'       => $billing_info['email'],
213
-            // Unique PayPal customer ID for payer.
214
-            'payerid'     => '',
215
-            // Status of payer.  Values are verified or unverified
216
-            'payerstatus' => '',
217
-            // Payer's business name.
218
-            'business'    => '',
219
-        );
220
-        $PayerName = array(
221
-            // Payer's salutation.  20 char max.
222
-            'salutation' => '',
223
-            // Payer's first name.  25 char max.
224
-            'firstname'  => substr($billing_info['first_name'], 0, 25),
225
-            // Payer's middle name.  25 char max.
226
-            'middlename' => '',
227
-            // Payer's last name.  25 char max.
228
-            'lastname'   => substr($billing_info['last_name'], 0, 25),
229
-            // Payer's suffix.  12 char max.
230
-            'suffix'     => '',
231
-        );
232
-        $BillingAddress = array(
233
-            // Required.  First street address.
234
-            'street'      => $billing_info['address'],
235
-            // Second street address.
236
-            'street2'     => $billing_info['address2'],
237
-            // Required.  Name of City.
238
-            'city'        => $billing_info['city'],
239
-            // Required. Name of State or Province.
240
-            'state'       => substr($billing_info['state'], 0, 40),
241
-            // Required.  Country code.
242
-            'countrycode' => $billing_info['country'],
243
-            // Required.  Postal code of payer.
244
-            'zip'         => $billing_info['zip'],
245
-        );
246
-        //check if the registration info contains the needed fields for paypal pro
247
-        //(see https://developer.paypal.com/docs/classic/api/merchant/DoDirectPayment_API_Operation_NVP/)
248
-        if ($attendee->address() && $attendee->city() && $attendee->country_ID()) {
249
-            $use_registration_address_info = true;
250
-        } else {
251
-            $use_registration_address_info = false;
252
-        }
253
-        //so if the attendee has enough data to fill out PayPal Pro's shipping info, use it.
254
-        // If not, use the billing info again
255
-        $ShippingAddress = array(
256
-            'shiptoname'     => substr($use_registration_address_info
257
-                ? $attendee->full_name()
258
-                : $billing_info['first_name'] . ' ' . $billing_info['last_name'], 0, 32),
259
-            'shiptostreet'   => substr($use_registration_address_info
260
-                ? $attendee->address()
261
-                : $billing_info['address'], 0, 100),
262
-            'shiptostreet2'  => substr($use_registration_address_info
263
-                ? $attendee->address2() : $billing_info['address2'], 0, 100),
264
-            'shiptocity'     => substr($use_registration_address_info
265
-                ? $attendee->city()
266
-                : $billing_info['city'], 0, 40),
267
-            'state'          => substr($use_registration_address_info
268
-                ? $attendee->state_name()
269
-                : $billing_info['state'], 0, 40),
270
-            'shiptocountry'  => $use_registration_address_info
271
-                ? $attendee->country_ID()
272
-                : $billing_info['country'],
273
-            'shiptozip'      => substr($use_registration_address_info
274
-                ? $attendee->zip()
275
-                : $billing_info['zip'], 0, 20),
276
-            'shiptophonenum' => substr($use_registration_address_info
277
-                ? $attendee->phone()
278
-                : $billing_info['phone'], 0, 20),
279
-        );
280
-        $PaymentDetails = array(
281
-            // Required.  Total amount of order, including shipping, handling, and tax.
282
-            'amt'          => $gateway_formatter->formatCurrency($payment->amount()),
283
-            // Required.  Three-letter currency code.  Default is USD.
284
-            'currencycode' => $payment->currency_code(),
285
-            // Required if you include itemized cart details. (L_AMTn, etc.)
286
-            //Subtotal of items not including S&H, or tax.
287
-            'itemamt'      => $gateway_formatter->formatCurrency($item_amount),//
288
-            // Total shipping costs for the order.  If you specify shippingamt, you must also specify itemamt.
289
-            'shippingamt'  => '',
290
-            // Total handling costs for the order.  If you specify handlingamt, you must also specify itemamt.
291
-            'handlingamt'  => '',
292
-            // Required if you specify itemized cart tax details.
293
-            // Sum of tax for all items on the order.  Total sales tax.
294
-            'taxamt'       => $gateway_formatter->formatCurrency($tax_amount),
295
-            // Description of the order the customer is purchasing.  127 char max.
296
-            'desc'         => $order_description,
297
-            // Free-form field for your own use.  256 char max.
298
-            'custom'       => $primary_registrant ? $primary_registrant->ID() : '',
299
-            // Your own invoice or tracking number
300
-            'invnum'       => wp_generate_password(12, false),//$transaction->ID(),
301
-            // URL for receiving Instant Payment Notifications.  This overrides what your profile is set to use.
302
-            'notifyurl'    => '',
303
-            'buttonsource' => 'EventEspresso_SP',//EE will blow up if you change this
304
-        );
305
-        // Wrap all data arrays into a single, "master" array which will be passed into the class function.
306
-        $PayPalRequestData = array(
307
-            'DPFields'        => $DPFields,
308
-            'CCDetails'       => $CCDetails,
309
-            'PayerInfo'       => $PayerInfo,
310
-            'PayerName'       => $PayerName,
311
-            'BillingAddress'  => $BillingAddress,
312
-            'ShippingAddress' => $ShippingAddress,
313
-            'PaymentDetails'  => $PaymentDetails,
314
-            'OrderItems'      => $order_items,
315
-        );
316
-        $this->_log_clean_request($PayPalRequestData, $payment);
317
-        try {
318
-            $PayPalResult = $this->prep_and_curl_request($PayPalRequestData);
319
-            //remove PCI-sensitive data so it doesn't get stored
320
-            $PayPalResult = $this->_log_clean_response($PayPalResult, $payment);
321
-            $message = isset($PayPalResult['L_LONGMESSAGE0']) ? $PayPalResult['L_LONGMESSAGE0'] : $PayPalResult['ACK'];
322
-            if (empty($PayPalResult['RAWRESPONSE'])) {
323
-                $payment->set_status($this->_pay_model->failed_status());
324
-                $payment->set_gateway_response(__('No response received from Paypal Pro', 'event_espresso'));
325
-                $payment->set_details($PayPalResult);
326
-            } else {
327
-                if ($this->_APICallSuccessful($PayPalResult)) {
328
-                    $payment->set_status($this->_pay_model->approved_status());
329
-                } else {
330
-                    $payment->set_status($this->_pay_model->declined_status());
331
-                }
332
-                //make sure we interpret the AMT as a float, not an international string
333
-                // (where periods are thousand separators)
334
-                $payment->set_amount(isset($PayPalResult['AMT']) ? floatval($PayPalResult['AMT']) : 0);
335
-                $payment->set_gateway_response($message);
336
-                $payment->set_txn_id_chq_nmbr(isset($PayPalResult['TRANSACTIONID'])
337
-                    ? $PayPalResult['TRANSACTIONID']
338
-                    : null);
339
-                $primary_registration_code = $primary_registrant instanceof EE_Registration
340
-                    ? $primary_registrant->reg_code()
341
-                    : '';
342
-                $payment->set_extra_accntng($primary_registration_code);
343
-                $payment->set_details($PayPalResult);
344
-            }
345
-        } catch (Exception $e) {
346
-            $payment->set_status($this->_pay_model->failed_status());
347
-            $payment->set_gateway_response($e->getMessage());
348
-        }
349
-        //$payment->set_status( $this->_pay_model->declined_status() );
350
-        //$payment->set_gateway_response( '' );
351
-        return $payment;
352
-    }
353
-
354
-
355
-
356
-    /**
357
-     * CLeans out sensitive CC data and then logs it, and returns the cleaned request
358
-     *
359
-     * @param array       $request
360
-     * @param EEI_Payment $payment
361
-     * @return void
362
-     */
363
-    private function _log_clean_request($request, $payment)
364
-    {
365
-        $cleaned_request_data = $request;
366
-        unset($cleaned_request_data['CCDetails']['acct']);
367
-        unset($cleaned_request_data['CCDetails']['cvv2']);
368
-        unset($cleaned_request_data['CCDetails']['expdate']);
369
-        $this->log(array('Paypal Request' => $cleaned_request_data), $payment);
370
-    }
371
-
372
-
373
-
374
-    /**
375
-     * Cleans the response, logs it, and returns it
376
-     *
377
-     * @param array       $response
378
-     * @param EEI_Payment $payment
379
-     * @return array cleaned
380
-     */
381
-    private function _log_clean_response($response, $payment)
382
-    {
383
-        unset($response['REQUESTDATA']['CREDITCARDTYPE']);
384
-        unset($response['REQUESTDATA']['ACCT']);
385
-        unset($response['REQUESTDATA']['EXPDATE']);
386
-        unset($response['REQUESTDATA']['CVV2']);
387
-        unset($response['RAWREQUEST']);
388
-        $this->log(array('Paypal Response' => $response), $payment);
389
-        return $response;
390
-    }
391
-
392
-
393
-
394
-    /**
395
-     * @param $DataArray
396
-     * @return array
397
-     */
398
-    private function prep_and_curl_request($DataArray)
399
-    {
400
-        // Create empty holders for each portion of the NVP string
401
-        $DPFieldsNVP = '&METHOD=DoDirectPayment&BUTTONSOURCE=AngellEYE_PHP_Class_DDP';
402
-        $CCDetailsNVP = '';
403
-        $PayerInfoNVP = '';
404
-        $PayerNameNVP = '';
405
-        $BillingAddressNVP = '';
406
-        $ShippingAddressNVP = '';
407
-        $PaymentDetailsNVP = '';
408
-        $OrderItemsNVP = '';
409
-        $Secure3DNVP = '';
410
-        // DP Fields
411
-        $DPFields = isset($DataArray['DPFields']) ? $DataArray['DPFields'] : array();
412
-        foreach ($DPFields as $DPFieldsVar => $DPFieldsVal) {
413
-            $DPFieldsNVP .= '&' . strtoupper($DPFieldsVar) . '=' . urlencode($DPFieldsVal);
414
-        }
415
-        // CC Details Fields
416
-        $CCDetails = isset($DataArray['CCDetails']) ? $DataArray['CCDetails'] : array();
417
-        foreach ($CCDetails as $CCDetailsVar => $CCDetailsVal) {
418
-            $CCDetailsNVP .= '&' . strtoupper($CCDetailsVar) . '=' . urlencode($CCDetailsVal);
419
-        }
420
-        // PayerInfo Type Fields
421
-        $PayerInfo = isset($DataArray['PayerInfo']) ? $DataArray['PayerInfo'] : array();
422
-        foreach ($PayerInfo as $PayerInfoVar => $PayerInfoVal) {
423
-            $PayerInfoNVP .= '&' . strtoupper($PayerInfoVar) . '=' . urlencode($PayerInfoVal);
424
-        }
425
-        // Payer Name Fields
426
-        $PayerName = isset($DataArray['PayerName']) ? $DataArray['PayerName'] : array();
427
-        foreach ($PayerName as $PayerNameVar => $PayerNameVal) {
428
-            $PayerNameNVP .= '&' . strtoupper($PayerNameVar) . '=' . urlencode($PayerNameVal);
429
-        }
430
-        // Address Fields (Billing)
431
-        $BillingAddress = isset($DataArray['BillingAddress']) ? $DataArray['BillingAddress'] : array();
432
-        foreach ($BillingAddress as $BillingAddressVar => $BillingAddressVal) {
433
-            $BillingAddressNVP .= '&' . strtoupper($BillingAddressVar) . '=' . urlencode($BillingAddressVal);
434
-        }
435
-        // Payment Details Type Fields
436
-        $PaymentDetails = isset($DataArray['PaymentDetails']) ? $DataArray['PaymentDetails'] : array();
437
-        foreach ($PaymentDetails as $PaymentDetailsVar => $PaymentDetailsVal) {
438
-            $PaymentDetailsNVP .= '&' . strtoupper($PaymentDetailsVar) . '=' . urlencode($PaymentDetailsVal);
439
-        }
440
-        // Payment Details Item Type Fields
441
-        $OrderItems = isset($DataArray['OrderItems']) ? $DataArray['OrderItems'] : array();
442
-        $n = 0;
443
-        foreach ($OrderItems as $OrderItemsVar => $OrderItemsVal) {
444
-            $CurrentItem = $OrderItems[$OrderItemsVar];
445
-            foreach ($CurrentItem as $CurrentItemVar => $CurrentItemVal) {
446
-                $OrderItemsNVP .= '&' . strtoupper($CurrentItemVar) . $n . '=' . urlencode($CurrentItemVal);
447
-            }
448
-            $n++;
449
-        }
450
-        // Ship To Address Fields
451
-        $ShippingAddress = isset($DataArray['ShippingAddress']) ? $DataArray['ShippingAddress'] : array();
452
-        foreach ($ShippingAddress as $ShippingAddressVar => $ShippingAddressVal) {
453
-            $ShippingAddressNVP .= '&' . strtoupper($ShippingAddressVar) . '=' . urlencode($ShippingAddressVal);
454
-        }
455
-        // 3D Secure Fields
456
-        $Secure3D = isset($DataArray['Secure3D']) ? $DataArray['Secure3D'] : array();
457
-        foreach ($Secure3D as $Secure3DVar => $Secure3DVal) {
458
-            $Secure3DNVP .= '&' . strtoupper($Secure3DVar) . '=' . urlencode($Secure3DVal);
459
-        }
460
-        // Now that we have each chunk we need to go ahead and append them all together for our entire NVP string
461
-        $NVPRequest = 'USER='
462
-                      . $this->_username
463
-                      . '&PWD='
464
-                      . $this->_password
465
-                      . '&VERSION=64.0'
466
-                      . '&SIGNATURE='
467
-                      . $this->_signature
468
-                      . $DPFieldsNVP
469
-                      . $CCDetailsNVP
470
-                      . $PayerInfoNVP
471
-                      . $PayerNameNVP
472
-                      . $BillingAddressNVP
473
-                      . $PaymentDetailsNVP
474
-                      . $OrderItemsNVP
475
-                      . $ShippingAddressNVP
476
-                      . $Secure3DNVP;
477
-        $NVPResponse = $this->_CURLRequest($NVPRequest);
478
-        $NVPRequestArray = $this->_NVPToArray($NVPRequest);
479
-        $NVPResponseArray = $this->_NVPToArray($NVPResponse);
480
-        $Errors = $this->_GetErrors($NVPResponseArray);
481
-        $NVPResponseArray['ERRORS'] = $Errors;
482
-        $NVPResponseArray['REQUESTDATA'] = $NVPRequestArray;
483
-        $NVPResponseArray['RAWREQUEST'] = $NVPRequest;
484
-        $NVPResponseArray['RAWRESPONSE'] = $NVPResponse;
485
-        return $NVPResponseArray;
486
-    }
487
-
488
-
489
-
490
-    /**
491
-     * @param $Request
492
-     * @return mixed
493
-     */
494
-    private function _CURLRequest($Request)
495
-    {
496
-        $EndPointURL = $this->_debug_mode ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp';
497
-        $curl = curl_init();
498
-        curl_setopt($curl, CURLOPT_VERBOSE, apply_filters('FHEE__EEG_Paypal_Pro__CurlRequest__CURLOPT_VERBOSE', true));
499
-        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
500
-        curl_setopt($curl, CURLOPT_TIMEOUT, 60);
501
-        curl_setopt($curl, CURLOPT_URL, $EndPointURL);
502
-        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
503
-        curl_setopt($curl, CURLOPT_POSTFIELDS, $Request);
504
-        curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
505
-        //execute the curl POST
506
-        $Response = curl_exec($curl);
507
-        curl_close($curl);
508
-        return $Response;
509
-    }
510
-
511
-
512
-
513
-    /**
514
-     * @param $NVPString
515
-     * @return array
516
-     */
517
-    private function _NVPToArray($NVPString)
518
-    {
519
-        // prepare responses into array
520
-        $proArray = array();
521
-        while (strlen($NVPString)) {
522
-            // name
523
-            $keypos = strpos($NVPString, '=');
524
-            $keyval = substr($NVPString, 0, $keypos);
525
-            // value
526
-            $valuepos = strpos($NVPString, '&') ? strpos($NVPString, '&') : strlen($NVPString);
527
-            $valval = substr($NVPString, $keypos + 1, $valuepos - $keypos - 1);
528
-            // decoding the response
529
-            $proArray[$keyval] = urldecode($valval);
530
-            $NVPString = substr($NVPString, $valuepos + 1, strlen($NVPString));
531
-        }
532
-        return $proArray;
533
-    }
534
-
535
-
536
-
537
-    /**
538
-     * @param array $PayPalResult
539
-     * @return bool
540
-     */
541
-    private function _APICallSuccessful($PayPalResult)
542
-    {
543
-        $approved = false;
544
-        // check main response message from PayPal
545
-        if (isset($PayPalResult['ACK']) && ! empty($PayPalResult['ACK'])) {
546
-            $ack = strtoupper($PayPalResult['ACK']);
547
-            $approved = ($ack == 'SUCCESS' || $ack == 'SUCCESSWITHWARNING' || $ack == 'PARTIALSUCCESS') ? true : false;
548
-        }
549
-        return $approved;
550
-    }
551
-
552
-
553
-
554
-    /**
555
-     * @param $DataArray
556
-     * @return array
557
-     */
558
-    private function _GetErrors($DataArray)
559
-    {
560
-        $Errors = array();
561
-        $n = 0;
562
-        while (isset($DataArray['L_ERRORCODE' . $n . ''])) {
563
-            $LErrorCode = isset($DataArray['L_ERRORCODE' . $n . '']) ? $DataArray['L_ERRORCODE' . $n . ''] : '';
564
-            $LShortMessage = isset($DataArray['L_SHORTMESSAGE' . $n . ''])
565
-                ? $DataArray['L_SHORTMESSAGE' . $n . '']
566
-                : '';
567
-            $LLongMessage = isset($DataArray['L_LONGMESSAGE' . $n . ''])
568
-                ? $DataArray['L_LONGMESSAGE' . $n . '']
569
-                : '';
570
-            $LSeverityCode = isset($DataArray['L_SEVERITYCODE' . $n . ''])
571
-                ? $DataArray['L_SEVERITYCODE' . $n . '']
572
-                : '';
573
-            $CurrentItem = array(
574
-                'L_ERRORCODE'    => $LErrorCode,
575
-                'L_SHORTMESSAGE' => $LShortMessage,
576
-                'L_LONGMESSAGE'  => $LLongMessage,
577
-                'L_SEVERITYCODE' => $LSeverityCode,
578
-            );
579
-            array_push($Errors, $CurrentItem);
580
-            $n++;
581
-        }
582
-        return $Errors;
583
-    }
584
-
585
-
586
-
587
-    /**
588
-     *        nothing to see here...  move along....
589
-     *
590
-     * @access protected
591
-     * @param $Errors
592
-     * @return string
593
-     */
594
-    private function _DisplayErrors($Errors)
595
-    {
596
-        $error = '';
597
-        foreach ($Errors as $ErrorVar => $ErrorVal) {
598
-            $CurrentError = $Errors[$ErrorVar];
599
-            foreach ($CurrentError as $CurrentErrorVar => $CurrentErrorVal) {
600
-                $CurrentVarName = '';
601
-                if ($CurrentErrorVar == 'L_ERRORCODE') {
602
-                    $CurrentVarName = 'Error Code';
603
-                } elseif ($CurrentErrorVar == 'L_SHORTMESSAGE') {
604
-                    $CurrentVarName = 'Short Message';
605
-                } elseif ($CurrentErrorVar == 'L_LONGMESSAGE') {
606
-                    $CurrentVarName = 'Long Message';
607
-                } elseif ($CurrentErrorVar == 'L_SEVERITYCODE') {
608
-                    $CurrentVarName = 'Severity Code';
609
-                }
610
-                $error .= '<br />' . $CurrentVarName . ': ' . $CurrentErrorVal;
611
-            }
612
-        }
613
-        return $error;
614
-    }
28
+	/**
29
+	 * @var $_paypal_api_username string
30
+	 */
31
+	protected $_username = null;
32
+
33
+	/**
34
+	 * @var $_password string
35
+	 */
36
+	protected $_password = null;
37
+
38
+	/**
39
+	 * @var $_signature string
40
+	 */
41
+	protected $_signature = null;
42
+
43
+	/**
44
+	 * @var $_credit_card_types array with the keys for credit card types accepted on this account
45
+	 */
46
+	protected $_credit_card_types    = null;
47
+
48
+	protected $_currencies_supported = array(
49
+		'USD',
50
+		'GBP',
51
+		'CAD',
52
+		'AUD',
53
+		'BRL',
54
+		'CHF',
55
+		'CZK',
56
+		'DKK',
57
+		'EUR',
58
+		'HKD',
59
+		'HUF',
60
+		'ILS',
61
+		'JPY',
62
+		'MXN',
63
+		'MYR',
64
+		'NOK',
65
+		'NZD',
66
+		'PHP',
67
+		'PLN',
68
+		'SEK',
69
+		'SGD',
70
+		'THB',
71
+		'TRY',
72
+		'TWD',
73
+		'RUB',
74
+	);
75
+
76
+
77
+
78
+	/**
79
+	 * @param EEI_Payment $payment
80
+	 * @param array       $billing_info {
81
+	 * @type string $credit_card
82
+	 * @type string $credit_card_type
83
+	 * @type string $exp_month always 2 characters
84
+	 * @type string $exp_year always 4 characters
85
+	 * @type string $cvv
86
+	 * }
87
+	 * @see      parent::do_direct_payment for more info
88
+	 * @return EE_Payment|EEI_Payment
89
+	 * @throws EE_Error
90
+	 */
91
+	public function do_direct_payment($payment, $billing_info = null)
92
+	{
93
+		$transaction = $payment->transaction();
94
+		if (! $transaction instanceof EEI_Transaction) {
95
+			throw new EE_Error(
96
+				esc_html__('No transaction for payment while paying with PayPal Pro.', 'event_espresso')
97
+			);
98
+		}
99
+		$primary_registrant = $transaction->primary_registration();
100
+		if (! $primary_registrant instanceof EEI_Registration) {
101
+			throw new EE_Error(
102
+				esc_html__(
103
+					'No primary registration on transaction while paying with PayPal Pro.',
104
+					'event_espresso'
105
+				)
106
+			);
107
+		}
108
+		$attendee = $primary_registrant->attendee();
109
+		if (! $attendee instanceof EEI_Attendee) {
110
+			throw new EE_Error(
111
+				esc_html__(
112
+					'No attendee on primary registration while paying with PayPal Pro.',
113
+					'event_espresso'
114
+				)
115
+			);
116
+		}
117
+		$gateway_formatter = $this->_get_gateway_formatter();
118
+		$order_description = substr($gateway_formatter->formatOrderDescription($payment), 0, 127);
119
+		//charge for the full amount. Show itemized list
120
+		if ($this->_can_easily_itemize_transaction_for($payment)) {
121
+			$item_num = 1;
122
+			$total_line_item = $transaction->total_line_item();
123
+			$order_items = array();
124
+			foreach ($total_line_item->get_items() as $line_item) {
125
+				//ignore line items with a quantity of 0
126
+				if ($line_item->quantity() == 0) {
127
+					continue;
128
+				}
129
+				$item = array(
130
+					// Item Name.  127 char max.
131
+					'l_name'                 => substr(
132
+						$gateway_formatter->formatLineItemName($line_item, $payment),
133
+						0,
134
+						127
135
+					),
136
+					// Item description.  127 char max.
137
+					'l_desc'                 => substr(
138
+						$gateway_formatter->formatLineItemDesc($line_item, $payment),
139
+						0,
140
+						127
141
+					),
142
+					// Cost of individual item.
143
+					'l_amt'                  => $line_item->unit_price(),
144
+					// Item Number.  127 char max.
145
+					'l_number'               => $item_num++,
146
+					// Item quantity.  Must be any positive integer.
147
+					'l_qty'                  => $line_item->quantity(),
148
+					// Item's sales tax amount.
149
+					'l_taxamt'               => '',
150
+					// eBay auction number of item.
151
+					'l_ebayitemnumber'       => '',
152
+					// eBay transaction ID of purchased item.
153
+					'l_ebayitemauctiontxnid' => '',
154
+					// eBay order ID for the item.
155
+					'l_ebayitemorderid'      => '',
156
+				);
157
+				// add to array of all items
158
+				array_push($order_items, $item);
159
+			}
160
+			$item_amount = $total_line_item->get_items_total();
161
+			$tax_amount = $total_line_item->get_total_tax();
162
+		} else {
163
+			$order_items = array();
164
+			$item_amount = $payment->amount();
165
+			$tax_amount = 0;
166
+			array_push($order_items, array(
167
+				// Item Name.  127 char max.
168
+				'l_name'   => substr(
169
+					$gateway_formatter->formatPartialPaymentLineItemName($payment),
170
+					0,
171
+					127
172
+				),
173
+				// Item description.  127 char max.
174
+				'l_desc'   => substr(
175
+					$gateway_formatter->formatPartialPaymentLineItemDesc($payment),
176
+					0,
177
+					127
178
+				),
179
+				// Cost of individual item.
180
+				'l_amt'    => $payment->amount(),
181
+				// Item Number.  127 char max.
182
+				'l_number' => 1,
183
+				// Item quantity.  Must be any positive integer.
184
+				'l_qty'    => 1,
185
+			));
186
+		}
187
+		// Populate data arrays with order data.
188
+		$DPFields = array(
189
+			// How you want to obtain payment ?
190
+			// Authorization indicates the payment is a basic auth subject to settlement with Auth & Capture.
191
+			// Sale indicates that this is a final sale for which you are requesting payment.  Default is Sale.
192
+			'paymentaction'    => 'Sale',
193
+			// Required.  IP address of the payer's browser.
194
+			'ipaddress'        => $_SERVER['REMOTE_ADDR'],
195
+			// Flag to determine whether you want the results returned by FMF.  1 or 0.  Default is 0.
196
+			'returnfmfdetails' => '1',
197
+		);
198
+		$CCDetails = array(
199
+			// Required. Type of credit card.  Visa, MasterCard, Discover, Amex, Maestro, Solo.
200
+			// If Maestro or Solo, the currency code must be GBP.
201
+			//  In addition, either start date or issue number must be specified.
202
+			'creditcardtype' => $billing_info['credit_card_type'],
203
+			// Required.  Credit card number.  No spaces or punctuation.
204
+			'acct'           => $billing_info['credit_card'],
205
+			// Required.  Credit card expiration date.  Format is MMYYYY
206
+			'expdate'        => $billing_info['exp_month'] . $billing_info['exp_year'],
207
+			// Requirements determined by your PayPal account settings.  Security digits for credit card.
208
+			'cvv2'           => $billing_info['cvv'],
209
+		);
210
+		$PayerInfo = array(
211
+			// Email address of payer.
212
+			'email'       => $billing_info['email'],
213
+			// Unique PayPal customer ID for payer.
214
+			'payerid'     => '',
215
+			// Status of payer.  Values are verified or unverified
216
+			'payerstatus' => '',
217
+			// Payer's business name.
218
+			'business'    => '',
219
+		);
220
+		$PayerName = array(
221
+			// Payer's salutation.  20 char max.
222
+			'salutation' => '',
223
+			// Payer's first name.  25 char max.
224
+			'firstname'  => substr($billing_info['first_name'], 0, 25),
225
+			// Payer's middle name.  25 char max.
226
+			'middlename' => '',
227
+			// Payer's last name.  25 char max.
228
+			'lastname'   => substr($billing_info['last_name'], 0, 25),
229
+			// Payer's suffix.  12 char max.
230
+			'suffix'     => '',
231
+		);
232
+		$BillingAddress = array(
233
+			// Required.  First street address.
234
+			'street'      => $billing_info['address'],
235
+			// Second street address.
236
+			'street2'     => $billing_info['address2'],
237
+			// Required.  Name of City.
238
+			'city'        => $billing_info['city'],
239
+			// Required. Name of State or Province.
240
+			'state'       => substr($billing_info['state'], 0, 40),
241
+			// Required.  Country code.
242
+			'countrycode' => $billing_info['country'],
243
+			// Required.  Postal code of payer.
244
+			'zip'         => $billing_info['zip'],
245
+		);
246
+		//check if the registration info contains the needed fields for paypal pro
247
+		//(see https://developer.paypal.com/docs/classic/api/merchant/DoDirectPayment_API_Operation_NVP/)
248
+		if ($attendee->address() && $attendee->city() && $attendee->country_ID()) {
249
+			$use_registration_address_info = true;
250
+		} else {
251
+			$use_registration_address_info = false;
252
+		}
253
+		//so if the attendee has enough data to fill out PayPal Pro's shipping info, use it.
254
+		// If not, use the billing info again
255
+		$ShippingAddress = array(
256
+			'shiptoname'     => substr($use_registration_address_info
257
+				? $attendee->full_name()
258
+				: $billing_info['first_name'] . ' ' . $billing_info['last_name'], 0, 32),
259
+			'shiptostreet'   => substr($use_registration_address_info
260
+				? $attendee->address()
261
+				: $billing_info['address'], 0, 100),
262
+			'shiptostreet2'  => substr($use_registration_address_info
263
+				? $attendee->address2() : $billing_info['address2'], 0, 100),
264
+			'shiptocity'     => substr($use_registration_address_info
265
+				? $attendee->city()
266
+				: $billing_info['city'], 0, 40),
267
+			'state'          => substr($use_registration_address_info
268
+				? $attendee->state_name()
269
+				: $billing_info['state'], 0, 40),
270
+			'shiptocountry'  => $use_registration_address_info
271
+				? $attendee->country_ID()
272
+				: $billing_info['country'],
273
+			'shiptozip'      => substr($use_registration_address_info
274
+				? $attendee->zip()
275
+				: $billing_info['zip'], 0, 20),
276
+			'shiptophonenum' => substr($use_registration_address_info
277
+				? $attendee->phone()
278
+				: $billing_info['phone'], 0, 20),
279
+		);
280
+		$PaymentDetails = array(
281
+			// Required.  Total amount of order, including shipping, handling, and tax.
282
+			'amt'          => $gateway_formatter->formatCurrency($payment->amount()),
283
+			// Required.  Three-letter currency code.  Default is USD.
284
+			'currencycode' => $payment->currency_code(),
285
+			// Required if you include itemized cart details. (L_AMTn, etc.)
286
+			//Subtotal of items not including S&H, or tax.
287
+			'itemamt'      => $gateway_formatter->formatCurrency($item_amount),//
288
+			// Total shipping costs for the order.  If you specify shippingamt, you must also specify itemamt.
289
+			'shippingamt'  => '',
290
+			// Total handling costs for the order.  If you specify handlingamt, you must also specify itemamt.
291
+			'handlingamt'  => '',
292
+			// Required if you specify itemized cart tax details.
293
+			// Sum of tax for all items on the order.  Total sales tax.
294
+			'taxamt'       => $gateway_formatter->formatCurrency($tax_amount),
295
+			// Description of the order the customer is purchasing.  127 char max.
296
+			'desc'         => $order_description,
297
+			// Free-form field for your own use.  256 char max.
298
+			'custom'       => $primary_registrant ? $primary_registrant->ID() : '',
299
+			// Your own invoice or tracking number
300
+			'invnum'       => wp_generate_password(12, false),//$transaction->ID(),
301
+			// URL for receiving Instant Payment Notifications.  This overrides what your profile is set to use.
302
+			'notifyurl'    => '',
303
+			'buttonsource' => 'EventEspresso_SP',//EE will blow up if you change this
304
+		);
305
+		// Wrap all data arrays into a single, "master" array which will be passed into the class function.
306
+		$PayPalRequestData = array(
307
+			'DPFields'        => $DPFields,
308
+			'CCDetails'       => $CCDetails,
309
+			'PayerInfo'       => $PayerInfo,
310
+			'PayerName'       => $PayerName,
311
+			'BillingAddress'  => $BillingAddress,
312
+			'ShippingAddress' => $ShippingAddress,
313
+			'PaymentDetails'  => $PaymentDetails,
314
+			'OrderItems'      => $order_items,
315
+		);
316
+		$this->_log_clean_request($PayPalRequestData, $payment);
317
+		try {
318
+			$PayPalResult = $this->prep_and_curl_request($PayPalRequestData);
319
+			//remove PCI-sensitive data so it doesn't get stored
320
+			$PayPalResult = $this->_log_clean_response($PayPalResult, $payment);
321
+			$message = isset($PayPalResult['L_LONGMESSAGE0']) ? $PayPalResult['L_LONGMESSAGE0'] : $PayPalResult['ACK'];
322
+			if (empty($PayPalResult['RAWRESPONSE'])) {
323
+				$payment->set_status($this->_pay_model->failed_status());
324
+				$payment->set_gateway_response(__('No response received from Paypal Pro', 'event_espresso'));
325
+				$payment->set_details($PayPalResult);
326
+			} else {
327
+				if ($this->_APICallSuccessful($PayPalResult)) {
328
+					$payment->set_status($this->_pay_model->approved_status());
329
+				} else {
330
+					$payment->set_status($this->_pay_model->declined_status());
331
+				}
332
+				//make sure we interpret the AMT as a float, not an international string
333
+				// (where periods are thousand separators)
334
+				$payment->set_amount(isset($PayPalResult['AMT']) ? floatval($PayPalResult['AMT']) : 0);
335
+				$payment->set_gateway_response($message);
336
+				$payment->set_txn_id_chq_nmbr(isset($PayPalResult['TRANSACTIONID'])
337
+					? $PayPalResult['TRANSACTIONID']
338
+					: null);
339
+				$primary_registration_code = $primary_registrant instanceof EE_Registration
340
+					? $primary_registrant->reg_code()
341
+					: '';
342
+				$payment->set_extra_accntng($primary_registration_code);
343
+				$payment->set_details($PayPalResult);
344
+			}
345
+		} catch (Exception $e) {
346
+			$payment->set_status($this->_pay_model->failed_status());
347
+			$payment->set_gateway_response($e->getMessage());
348
+		}
349
+		//$payment->set_status( $this->_pay_model->declined_status() );
350
+		//$payment->set_gateway_response( '' );
351
+		return $payment;
352
+	}
353
+
354
+
355
+
356
+	/**
357
+	 * CLeans out sensitive CC data and then logs it, and returns the cleaned request
358
+	 *
359
+	 * @param array       $request
360
+	 * @param EEI_Payment $payment
361
+	 * @return void
362
+	 */
363
+	private function _log_clean_request($request, $payment)
364
+	{
365
+		$cleaned_request_data = $request;
366
+		unset($cleaned_request_data['CCDetails']['acct']);
367
+		unset($cleaned_request_data['CCDetails']['cvv2']);
368
+		unset($cleaned_request_data['CCDetails']['expdate']);
369
+		$this->log(array('Paypal Request' => $cleaned_request_data), $payment);
370
+	}
371
+
372
+
373
+
374
+	/**
375
+	 * Cleans the response, logs it, and returns it
376
+	 *
377
+	 * @param array       $response
378
+	 * @param EEI_Payment $payment
379
+	 * @return array cleaned
380
+	 */
381
+	private function _log_clean_response($response, $payment)
382
+	{
383
+		unset($response['REQUESTDATA']['CREDITCARDTYPE']);
384
+		unset($response['REQUESTDATA']['ACCT']);
385
+		unset($response['REQUESTDATA']['EXPDATE']);
386
+		unset($response['REQUESTDATA']['CVV2']);
387
+		unset($response['RAWREQUEST']);
388
+		$this->log(array('Paypal Response' => $response), $payment);
389
+		return $response;
390
+	}
391
+
392
+
393
+
394
+	/**
395
+	 * @param $DataArray
396
+	 * @return array
397
+	 */
398
+	private function prep_and_curl_request($DataArray)
399
+	{
400
+		// Create empty holders for each portion of the NVP string
401
+		$DPFieldsNVP = '&METHOD=DoDirectPayment&BUTTONSOURCE=AngellEYE_PHP_Class_DDP';
402
+		$CCDetailsNVP = '';
403
+		$PayerInfoNVP = '';
404
+		$PayerNameNVP = '';
405
+		$BillingAddressNVP = '';
406
+		$ShippingAddressNVP = '';
407
+		$PaymentDetailsNVP = '';
408
+		$OrderItemsNVP = '';
409
+		$Secure3DNVP = '';
410
+		// DP Fields
411
+		$DPFields = isset($DataArray['DPFields']) ? $DataArray['DPFields'] : array();
412
+		foreach ($DPFields as $DPFieldsVar => $DPFieldsVal) {
413
+			$DPFieldsNVP .= '&' . strtoupper($DPFieldsVar) . '=' . urlencode($DPFieldsVal);
414
+		}
415
+		// CC Details Fields
416
+		$CCDetails = isset($DataArray['CCDetails']) ? $DataArray['CCDetails'] : array();
417
+		foreach ($CCDetails as $CCDetailsVar => $CCDetailsVal) {
418
+			$CCDetailsNVP .= '&' . strtoupper($CCDetailsVar) . '=' . urlencode($CCDetailsVal);
419
+		}
420
+		// PayerInfo Type Fields
421
+		$PayerInfo = isset($DataArray['PayerInfo']) ? $DataArray['PayerInfo'] : array();
422
+		foreach ($PayerInfo as $PayerInfoVar => $PayerInfoVal) {
423
+			$PayerInfoNVP .= '&' . strtoupper($PayerInfoVar) . '=' . urlencode($PayerInfoVal);
424
+		}
425
+		// Payer Name Fields
426
+		$PayerName = isset($DataArray['PayerName']) ? $DataArray['PayerName'] : array();
427
+		foreach ($PayerName as $PayerNameVar => $PayerNameVal) {
428
+			$PayerNameNVP .= '&' . strtoupper($PayerNameVar) . '=' . urlencode($PayerNameVal);
429
+		}
430
+		// Address Fields (Billing)
431
+		$BillingAddress = isset($DataArray['BillingAddress']) ? $DataArray['BillingAddress'] : array();
432
+		foreach ($BillingAddress as $BillingAddressVar => $BillingAddressVal) {
433
+			$BillingAddressNVP .= '&' . strtoupper($BillingAddressVar) . '=' . urlencode($BillingAddressVal);
434
+		}
435
+		// Payment Details Type Fields
436
+		$PaymentDetails = isset($DataArray['PaymentDetails']) ? $DataArray['PaymentDetails'] : array();
437
+		foreach ($PaymentDetails as $PaymentDetailsVar => $PaymentDetailsVal) {
438
+			$PaymentDetailsNVP .= '&' . strtoupper($PaymentDetailsVar) . '=' . urlencode($PaymentDetailsVal);
439
+		}
440
+		// Payment Details Item Type Fields
441
+		$OrderItems = isset($DataArray['OrderItems']) ? $DataArray['OrderItems'] : array();
442
+		$n = 0;
443
+		foreach ($OrderItems as $OrderItemsVar => $OrderItemsVal) {
444
+			$CurrentItem = $OrderItems[$OrderItemsVar];
445
+			foreach ($CurrentItem as $CurrentItemVar => $CurrentItemVal) {
446
+				$OrderItemsNVP .= '&' . strtoupper($CurrentItemVar) . $n . '=' . urlencode($CurrentItemVal);
447
+			}
448
+			$n++;
449
+		}
450
+		// Ship To Address Fields
451
+		$ShippingAddress = isset($DataArray['ShippingAddress']) ? $DataArray['ShippingAddress'] : array();
452
+		foreach ($ShippingAddress as $ShippingAddressVar => $ShippingAddressVal) {
453
+			$ShippingAddressNVP .= '&' . strtoupper($ShippingAddressVar) . '=' . urlencode($ShippingAddressVal);
454
+		}
455
+		// 3D Secure Fields
456
+		$Secure3D = isset($DataArray['Secure3D']) ? $DataArray['Secure3D'] : array();
457
+		foreach ($Secure3D as $Secure3DVar => $Secure3DVal) {
458
+			$Secure3DNVP .= '&' . strtoupper($Secure3DVar) . '=' . urlencode($Secure3DVal);
459
+		}
460
+		// Now that we have each chunk we need to go ahead and append them all together for our entire NVP string
461
+		$NVPRequest = 'USER='
462
+					  . $this->_username
463
+					  . '&PWD='
464
+					  . $this->_password
465
+					  . '&VERSION=64.0'
466
+					  . '&SIGNATURE='
467
+					  . $this->_signature
468
+					  . $DPFieldsNVP
469
+					  . $CCDetailsNVP
470
+					  . $PayerInfoNVP
471
+					  . $PayerNameNVP
472
+					  . $BillingAddressNVP
473
+					  . $PaymentDetailsNVP
474
+					  . $OrderItemsNVP
475
+					  . $ShippingAddressNVP
476
+					  . $Secure3DNVP;
477
+		$NVPResponse = $this->_CURLRequest($NVPRequest);
478
+		$NVPRequestArray = $this->_NVPToArray($NVPRequest);
479
+		$NVPResponseArray = $this->_NVPToArray($NVPResponse);
480
+		$Errors = $this->_GetErrors($NVPResponseArray);
481
+		$NVPResponseArray['ERRORS'] = $Errors;
482
+		$NVPResponseArray['REQUESTDATA'] = $NVPRequestArray;
483
+		$NVPResponseArray['RAWREQUEST'] = $NVPRequest;
484
+		$NVPResponseArray['RAWRESPONSE'] = $NVPResponse;
485
+		return $NVPResponseArray;
486
+	}
487
+
488
+
489
+
490
+	/**
491
+	 * @param $Request
492
+	 * @return mixed
493
+	 */
494
+	private function _CURLRequest($Request)
495
+	{
496
+		$EndPointURL = $this->_debug_mode ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp';
497
+		$curl = curl_init();
498
+		curl_setopt($curl, CURLOPT_VERBOSE, apply_filters('FHEE__EEG_Paypal_Pro__CurlRequest__CURLOPT_VERBOSE', true));
499
+		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
500
+		curl_setopt($curl, CURLOPT_TIMEOUT, 60);
501
+		curl_setopt($curl, CURLOPT_URL, $EndPointURL);
502
+		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
503
+		curl_setopt($curl, CURLOPT_POSTFIELDS, $Request);
504
+		curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
505
+		//execute the curl POST
506
+		$Response = curl_exec($curl);
507
+		curl_close($curl);
508
+		return $Response;
509
+	}
510
+
511
+
512
+
513
+	/**
514
+	 * @param $NVPString
515
+	 * @return array
516
+	 */
517
+	private function _NVPToArray($NVPString)
518
+	{
519
+		// prepare responses into array
520
+		$proArray = array();
521
+		while (strlen($NVPString)) {
522
+			// name
523
+			$keypos = strpos($NVPString, '=');
524
+			$keyval = substr($NVPString, 0, $keypos);
525
+			// value
526
+			$valuepos = strpos($NVPString, '&') ? strpos($NVPString, '&') : strlen($NVPString);
527
+			$valval = substr($NVPString, $keypos + 1, $valuepos - $keypos - 1);
528
+			// decoding the response
529
+			$proArray[$keyval] = urldecode($valval);
530
+			$NVPString = substr($NVPString, $valuepos + 1, strlen($NVPString));
531
+		}
532
+		return $proArray;
533
+	}
534
+
535
+
536
+
537
+	/**
538
+	 * @param array $PayPalResult
539
+	 * @return bool
540
+	 */
541
+	private function _APICallSuccessful($PayPalResult)
542
+	{
543
+		$approved = false;
544
+		// check main response message from PayPal
545
+		if (isset($PayPalResult['ACK']) && ! empty($PayPalResult['ACK'])) {
546
+			$ack = strtoupper($PayPalResult['ACK']);
547
+			$approved = ($ack == 'SUCCESS' || $ack == 'SUCCESSWITHWARNING' || $ack == 'PARTIALSUCCESS') ? true : false;
548
+		}
549
+		return $approved;
550
+	}
551
+
552
+
553
+
554
+	/**
555
+	 * @param $DataArray
556
+	 * @return array
557
+	 */
558
+	private function _GetErrors($DataArray)
559
+	{
560
+		$Errors = array();
561
+		$n = 0;
562
+		while (isset($DataArray['L_ERRORCODE' . $n . ''])) {
563
+			$LErrorCode = isset($DataArray['L_ERRORCODE' . $n . '']) ? $DataArray['L_ERRORCODE' . $n . ''] : '';
564
+			$LShortMessage = isset($DataArray['L_SHORTMESSAGE' . $n . ''])
565
+				? $DataArray['L_SHORTMESSAGE' . $n . '']
566
+				: '';
567
+			$LLongMessage = isset($DataArray['L_LONGMESSAGE' . $n . ''])
568
+				? $DataArray['L_LONGMESSAGE' . $n . '']
569
+				: '';
570
+			$LSeverityCode = isset($DataArray['L_SEVERITYCODE' . $n . ''])
571
+				? $DataArray['L_SEVERITYCODE' . $n . '']
572
+				: '';
573
+			$CurrentItem = array(
574
+				'L_ERRORCODE'    => $LErrorCode,
575
+				'L_SHORTMESSAGE' => $LShortMessage,
576
+				'L_LONGMESSAGE'  => $LLongMessage,
577
+				'L_SEVERITYCODE' => $LSeverityCode,
578
+			);
579
+			array_push($Errors, $CurrentItem);
580
+			$n++;
581
+		}
582
+		return $Errors;
583
+	}
584
+
585
+
586
+
587
+	/**
588
+	 *        nothing to see here...  move along....
589
+	 *
590
+	 * @access protected
591
+	 * @param $Errors
592
+	 * @return string
593
+	 */
594
+	private function _DisplayErrors($Errors)
595
+	{
596
+		$error = '';
597
+		foreach ($Errors as $ErrorVar => $ErrorVal) {
598
+			$CurrentError = $Errors[$ErrorVar];
599
+			foreach ($CurrentError as $CurrentErrorVar => $CurrentErrorVal) {
600
+				$CurrentVarName = '';
601
+				if ($CurrentErrorVar == 'L_ERRORCODE') {
602
+					$CurrentVarName = 'Error Code';
603
+				} elseif ($CurrentErrorVar == 'L_SHORTMESSAGE') {
604
+					$CurrentVarName = 'Short Message';
605
+				} elseif ($CurrentErrorVar == 'L_LONGMESSAGE') {
606
+					$CurrentVarName = 'Long Message';
607
+				} elseif ($CurrentErrorVar == 'L_SEVERITYCODE') {
608
+					$CurrentVarName = 'Severity Code';
609
+				}
610
+				$error .= '<br />' . $CurrentVarName . ': ' . $CurrentErrorVal;
611
+			}
612
+		}
613
+		return $error;
614
+	}
615 615
 }
616 616
 // End of file EEG_Paypal_Pro.gateway.php
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-if (! defined('EVENT_ESPRESSO_VERSION')) {
2
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
3 3
     exit('No direct script access allowed');
4 4
 }
5 5
 
@@ -91,13 +91,13 @@  discard block
 block discarded – undo
91 91
     public function do_direct_payment($payment, $billing_info = null)
92 92
     {
93 93
         $transaction = $payment->transaction();
94
-        if (! $transaction instanceof EEI_Transaction) {
94
+        if ( ! $transaction instanceof EEI_Transaction) {
95 95
             throw new EE_Error(
96 96
                 esc_html__('No transaction for payment while paying with PayPal Pro.', 'event_espresso')
97 97
             );
98 98
         }
99 99
         $primary_registrant = $transaction->primary_registration();
100
-        if (! $primary_registrant instanceof EEI_Registration) {
100
+        if ( ! $primary_registrant instanceof EEI_Registration) {
101 101
             throw new EE_Error(
102 102
                 esc_html__(
103 103
                     'No primary registration on transaction while paying with PayPal Pro.',
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
             );
107 107
         }
108 108
         $attendee = $primary_registrant->attendee();
109
-        if (! $attendee instanceof EEI_Attendee) {
109
+        if ( ! $attendee instanceof EEI_Attendee) {
110 110
             throw new EE_Error(
111 111
                 esc_html__(
112 112
                     'No attendee on primary registration while paying with PayPal Pro.',
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
             // Required.  Credit card number.  No spaces or punctuation.
204 204
             'acct'           => $billing_info['credit_card'],
205 205
             // Required.  Credit card expiration date.  Format is MMYYYY
206
-            'expdate'        => $billing_info['exp_month'] . $billing_info['exp_year'],
206
+            'expdate'        => $billing_info['exp_month'].$billing_info['exp_year'],
207 207
             // Requirements determined by your PayPal account settings.  Security digits for credit card.
208 208
             'cvv2'           => $billing_info['cvv'],
209 209
         );
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
         $ShippingAddress = array(
256 256
             'shiptoname'     => substr($use_registration_address_info
257 257
                 ? $attendee->full_name()
258
-                : $billing_info['first_name'] . ' ' . $billing_info['last_name'], 0, 32),
258
+                : $billing_info['first_name'].' '.$billing_info['last_name'], 0, 32),
259 259
             'shiptostreet'   => substr($use_registration_address_info
260 260
                 ? $attendee->address()
261 261
                 : $billing_info['address'], 0, 100),
@@ -284,7 +284,7 @@  discard block
 block discarded – undo
284 284
             'currencycode' => $payment->currency_code(),
285 285
             // Required if you include itemized cart details. (L_AMTn, etc.)
286 286
             //Subtotal of items not including S&H, or tax.
287
-            'itemamt'      => $gateway_formatter->formatCurrency($item_amount),//
287
+            'itemamt'      => $gateway_formatter->formatCurrency($item_amount), //
288 288
             // Total shipping costs for the order.  If you specify shippingamt, you must also specify itemamt.
289 289
             'shippingamt'  => '',
290 290
             // Total handling costs for the order.  If you specify handlingamt, you must also specify itemamt.
@@ -297,10 +297,10 @@  discard block
 block discarded – undo
297 297
             // Free-form field for your own use.  256 char max.
298 298
             'custom'       => $primary_registrant ? $primary_registrant->ID() : '',
299 299
             // Your own invoice or tracking number
300
-            'invnum'       => wp_generate_password(12, false),//$transaction->ID(),
300
+            'invnum'       => wp_generate_password(12, false), //$transaction->ID(),
301 301
             // URL for receiving Instant Payment Notifications.  This overrides what your profile is set to use.
302 302
             'notifyurl'    => '',
303
-            'buttonsource' => 'EventEspresso_SP',//EE will blow up if you change this
303
+            'buttonsource' => 'EventEspresso_SP', //EE will blow up if you change this
304 304
         );
305 305
         // Wrap all data arrays into a single, "master" array which will be passed into the class function.
306 306
         $PayPalRequestData = array(
@@ -410,32 +410,32 @@  discard block
 block discarded – undo
410 410
         // DP Fields
411 411
         $DPFields = isset($DataArray['DPFields']) ? $DataArray['DPFields'] : array();
412 412
         foreach ($DPFields as $DPFieldsVar => $DPFieldsVal) {
413
-            $DPFieldsNVP .= '&' . strtoupper($DPFieldsVar) . '=' . urlencode($DPFieldsVal);
413
+            $DPFieldsNVP .= '&'.strtoupper($DPFieldsVar).'='.urlencode($DPFieldsVal);
414 414
         }
415 415
         // CC Details Fields
416 416
         $CCDetails = isset($DataArray['CCDetails']) ? $DataArray['CCDetails'] : array();
417 417
         foreach ($CCDetails as $CCDetailsVar => $CCDetailsVal) {
418
-            $CCDetailsNVP .= '&' . strtoupper($CCDetailsVar) . '=' . urlencode($CCDetailsVal);
418
+            $CCDetailsNVP .= '&'.strtoupper($CCDetailsVar).'='.urlencode($CCDetailsVal);
419 419
         }
420 420
         // PayerInfo Type Fields
421 421
         $PayerInfo = isset($DataArray['PayerInfo']) ? $DataArray['PayerInfo'] : array();
422 422
         foreach ($PayerInfo as $PayerInfoVar => $PayerInfoVal) {
423
-            $PayerInfoNVP .= '&' . strtoupper($PayerInfoVar) . '=' . urlencode($PayerInfoVal);
423
+            $PayerInfoNVP .= '&'.strtoupper($PayerInfoVar).'='.urlencode($PayerInfoVal);
424 424
         }
425 425
         // Payer Name Fields
426 426
         $PayerName = isset($DataArray['PayerName']) ? $DataArray['PayerName'] : array();
427 427
         foreach ($PayerName as $PayerNameVar => $PayerNameVal) {
428
-            $PayerNameNVP .= '&' . strtoupper($PayerNameVar) . '=' . urlencode($PayerNameVal);
428
+            $PayerNameNVP .= '&'.strtoupper($PayerNameVar).'='.urlencode($PayerNameVal);
429 429
         }
430 430
         // Address Fields (Billing)
431 431
         $BillingAddress = isset($DataArray['BillingAddress']) ? $DataArray['BillingAddress'] : array();
432 432
         foreach ($BillingAddress as $BillingAddressVar => $BillingAddressVal) {
433
-            $BillingAddressNVP .= '&' . strtoupper($BillingAddressVar) . '=' . urlencode($BillingAddressVal);
433
+            $BillingAddressNVP .= '&'.strtoupper($BillingAddressVar).'='.urlencode($BillingAddressVal);
434 434
         }
435 435
         // Payment Details Type Fields
436 436
         $PaymentDetails = isset($DataArray['PaymentDetails']) ? $DataArray['PaymentDetails'] : array();
437 437
         foreach ($PaymentDetails as $PaymentDetailsVar => $PaymentDetailsVal) {
438
-            $PaymentDetailsNVP .= '&' . strtoupper($PaymentDetailsVar) . '=' . urlencode($PaymentDetailsVal);
438
+            $PaymentDetailsNVP .= '&'.strtoupper($PaymentDetailsVar).'='.urlencode($PaymentDetailsVal);
439 439
         }
440 440
         // Payment Details Item Type Fields
441 441
         $OrderItems = isset($DataArray['OrderItems']) ? $DataArray['OrderItems'] : array();
@@ -443,19 +443,19 @@  discard block
 block discarded – undo
443 443
         foreach ($OrderItems as $OrderItemsVar => $OrderItemsVal) {
444 444
             $CurrentItem = $OrderItems[$OrderItemsVar];
445 445
             foreach ($CurrentItem as $CurrentItemVar => $CurrentItemVal) {
446
-                $OrderItemsNVP .= '&' . strtoupper($CurrentItemVar) . $n . '=' . urlencode($CurrentItemVal);
446
+                $OrderItemsNVP .= '&'.strtoupper($CurrentItemVar).$n.'='.urlencode($CurrentItemVal);
447 447
             }
448 448
             $n++;
449 449
         }
450 450
         // Ship To Address Fields
451 451
         $ShippingAddress = isset($DataArray['ShippingAddress']) ? $DataArray['ShippingAddress'] : array();
452 452
         foreach ($ShippingAddress as $ShippingAddressVar => $ShippingAddressVal) {
453
-            $ShippingAddressNVP .= '&' . strtoupper($ShippingAddressVar) . '=' . urlencode($ShippingAddressVal);
453
+            $ShippingAddressNVP .= '&'.strtoupper($ShippingAddressVar).'='.urlencode($ShippingAddressVal);
454 454
         }
455 455
         // 3D Secure Fields
456 456
         $Secure3D = isset($DataArray['Secure3D']) ? $DataArray['Secure3D'] : array();
457 457
         foreach ($Secure3D as $Secure3DVar => $Secure3DVal) {
458
-            $Secure3DNVP .= '&' . strtoupper($Secure3DVar) . '=' . urlencode($Secure3DVal);
458
+            $Secure3DNVP .= '&'.strtoupper($Secure3DVar).'='.urlencode($Secure3DVal);
459 459
         }
460 460
         // Now that we have each chunk we need to go ahead and append them all together for our entire NVP string
461 461
         $NVPRequest = 'USER='
@@ -559,16 +559,16 @@  discard block
 block discarded – undo
559 559
     {
560 560
         $Errors = array();
561 561
         $n = 0;
562
-        while (isset($DataArray['L_ERRORCODE' . $n . ''])) {
563
-            $LErrorCode = isset($DataArray['L_ERRORCODE' . $n . '']) ? $DataArray['L_ERRORCODE' . $n . ''] : '';
564
-            $LShortMessage = isset($DataArray['L_SHORTMESSAGE' . $n . ''])
565
-                ? $DataArray['L_SHORTMESSAGE' . $n . '']
562
+        while (isset($DataArray['L_ERRORCODE'.$n.''])) {
563
+            $LErrorCode = isset($DataArray['L_ERRORCODE'.$n.'']) ? $DataArray['L_ERRORCODE'.$n.''] : '';
564
+            $LShortMessage = isset($DataArray['L_SHORTMESSAGE'.$n.''])
565
+                ? $DataArray['L_SHORTMESSAGE'.$n.'']
566 566
                 : '';
567
-            $LLongMessage = isset($DataArray['L_LONGMESSAGE' . $n . ''])
568
-                ? $DataArray['L_LONGMESSAGE' . $n . '']
567
+            $LLongMessage = isset($DataArray['L_LONGMESSAGE'.$n.''])
568
+                ? $DataArray['L_LONGMESSAGE'.$n.'']
569 569
                 : '';
570
-            $LSeverityCode = isset($DataArray['L_SEVERITYCODE' . $n . ''])
571
-                ? $DataArray['L_SEVERITYCODE' . $n . '']
570
+            $LSeverityCode = isset($DataArray['L_SEVERITYCODE'.$n.''])
571
+                ? $DataArray['L_SEVERITYCODE'.$n.'']
572 572
                 : '';
573 573
             $CurrentItem = array(
574 574
                 'L_ERRORCODE'    => $LErrorCode,
@@ -607,7 +607,7 @@  discard block
 block discarded – undo
607 607
                 } elseif ($CurrentErrorVar == 'L_SEVERITYCODE') {
608 608
                     $CurrentVarName = 'Severity Code';
609 609
                 }
610
-                $error .= '<br />' . $CurrentVarName . ': ' . $CurrentErrorVal;
610
+                $error .= '<br />'.$CurrentVarName.': '.$CurrentErrorVal;
611 611
             }
612 612
         }
613 613
         return $error;
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/EEG_Paypal_Express.gateway.php 2 patches
Indentation   +671 added lines, -671 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if (! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('NO direct script access allowed');
2
+	exit('NO direct script access allowed');
3 3
 }
4 4
 
5 5
 
@@ -16,680 +16,680 @@  discard block
 block discarded – undo
16 16
  */
17 17
 //Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
18 18
 if (! function_exists('mb_strcut')) {
19
-    /**
20
-     * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
21
-     * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
22
-     * @param $string
23
-     * @param $start
24
-     * @param $length
25
-     * @return bool|string
26
-     */
27
-    function mb_strcut($string, $start, $length = null)
28
-    {
29
-        return mb_substr($string, $start, $length);
30
-    }
19
+	/**
20
+	 * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
21
+	 * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
22
+	 * @param $string
23
+	 * @param $start
24
+	 * @param $length
25
+	 * @return bool|string
26
+	 */
27
+	function mb_strcut($string, $start, $length = null)
28
+	{
29
+		return mb_substr($string, $start, $length);
30
+	}
31 31
 }
32 32
 class EEG_Paypal_Express extends EE_Offsite_Gateway
33 33
 {
34 34
 
35
-    /**
36
-     * Merchant API Username.
37
-     *
38
-     * @var string
39
-     */
40
-    protected $_api_username;
41
-
42
-    /**
43
-     * Merchant API Password.
44
-     *
45
-     * @var string
46
-     */
47
-    protected $_api_password;
48
-
49
-    /**
50
-     * API Signature.
51
-     *
52
-     * @var string
53
-     */
54
-    protected $_api_signature;
55
-
56
-    /**
57
-     * Request Shipping address on PP checkout page.
58
-     *
59
-     * @var string
60
-     */
61
-    protected $_request_shipping_addr;
62
-
63
-    /**
64
-     * Business/personal logo.
65
-     *
66
-     * @var string
67
-     */
68
-    protected $_image_url;
69
-
70
-    /**
71
-     * gateway URL variable
72
-     *
73
-     * @var string
74
-     */
75
-    protected $_base_gateway_url = '';
76
-
77
-
78
-
79
-    /**
80
-     * EEG_Paypal_Express constructor.
81
-     */
82
-    public function __construct()
83
-    {
84
-        $this->_currencies_supported = array(
85
-            'USD',
86
-            'AUD',
87
-            'BRL',
88
-            'CAD',
89
-            'CZK',
90
-            'DKK',
91
-            'EUR',
92
-            'HKD',
93
-            'HUF',
94
-            'ILS',
95
-            'JPY',
96
-            'MYR',
97
-            'MXN',
98
-            'NOK',
99
-            'NZD',
100
-            'PHP',
101
-            'PLN',
102
-            'GBP',
103
-            'RUB',
104
-            'SGD',
105
-            'SEK',
106
-            'CHF',
107
-            'TWD',
108
-            'THB',
109
-            'TRY',
110
-        );
111
-        parent::__construct();
112
-    }
113
-
114
-
115
-
116
-    /**
117
-     * Sets the gateway URL variable based on whether debug mode is enabled or not.
118
-     *
119
-     * @param array $settings_array
120
-     */
121
-    public function set_settings($settings_array)
122
-    {
123
-        parent::set_settings($settings_array);
124
-        // Redirect URL.
125
-        $this->_base_gateway_url = $this->_debug_mode
126
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
127
-            : 'https://api-3t.paypal.com/nvp';
128
-    }
129
-
130
-
131
-
132
-    /**
133
-     * @param EEI_Payment $payment
134
-     * @param array       $billing_info
135
-     * @param string      $return_url
136
-     * @param string      $notify_url
137
-     * @param string      $cancel_url
138
-     * @return \EE_Payment|\EEI_Payment
139
-     * @throws \EE_Error
140
-     */
141
-    public function set_redirection_info(
142
-        $payment,
143
-        $billing_info = array(),
144
-        $return_url = null,
145
-        $notify_url = null,
146
-        $cancel_url = null
147
-    ) {
148
-        if (! $payment instanceof EEI_Payment) {
149
-            $payment->set_gateway_response(
150
-                esc_html__(
151
-                    'Error. No associated payment was found.',
152
-                    'event_espresso'
153
-                )
154
-            );
155
-            $payment->set_status($this->_pay_model->failed_status());
156
-            return $payment;
157
-        }
158
-        $transaction = $payment->transaction();
159
-        if (! $transaction instanceof EEI_Transaction) {
160
-            $payment->set_gateway_response(
161
-                esc_html__(
162
-                    'Could not process this payment because it has no associated transaction.',
163
-                    'event_espresso'
164
-                )
165
-            );
166
-            $payment->set_status($this->_pay_model->failed_status());
167
-            return $payment;
168
-        }
169
-        $gateway_formatter = $this->_get_gateway_formatter();
170
-        $order_description = mb_strcut($gateway_formatter->formatOrderDescription($payment), 0, 127);
171
-        $primary_registration = $transaction->primary_registration();
172
-        $primary_attendee = $primary_registration instanceof EE_Registration
173
-            ? $primary_registration->attendee()
174
-            : false;
175
-        $locale = explode('-', get_bloginfo('language'));
176
-        // Gather request parameters.
177
-        $token_request_dtls = array(
178
-            'METHOD'                         => 'SetExpressCheckout',
179
-            'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
180
-            'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
181
-            'PAYMENTREQUEST_0_DESC'          => $order_description,
182
-            'RETURNURL'                      => $return_url,
183
-            'CANCELURL'                      => $cancel_url,
184
-            'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
185
-            // Buyer does not need to create a PayPal account to check out.
186
-            // This is referred to as PayPal Account Optional.
187
-            'SOLUTIONTYPE'                   => 'Sole',
188
-            //EE will blow up if you change this
189
-            'BUTTONSOURCE'                   => 'EventEspresso_SP',
190
-            // Locale of the pages displayed by PayPal during Express Checkout.
191
-            'LOCALECODE'                     => $locale[1]
192
-        );
193
-        // Show itemized list.
194
-        $itemized_list = $this->itemize_list($payment, $transaction);
195
-        $token_request_dtls = array_merge($token_request_dtls, $itemized_list);
196
-        // Automatically filling out shipping and contact information.
197
-        if ($this->_request_shipping_addr && $primary_attendee instanceof EEI_Attendee) {
198
-            // If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
199
-            $token_request_dtls['NOSHIPPING'] = '2';
200
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET'] = $primary_attendee->address();
201
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET2'] = $primary_attendee->address2();
202
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOCITY'] = $primary_attendee->city();
203
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTATE'] = $primary_attendee->state_abbrev();
204
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
205
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOZIP'] = $primary_attendee->zip();
206
-            $token_request_dtls['PAYMENTREQUEST_0_EMAIL'] = $primary_attendee->email();
207
-            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOPHONENUM'] = $primary_attendee->phone();
208
-        } elseif (! $this->_request_shipping_addr) {
209
-            // Do not request shipping details on the PP Checkout page.
210
-            $token_request_dtls['NOSHIPPING'] = '1';
211
-            $token_request_dtls['REQCONFIRMSHIPPING'] = '0';
212
-        }
213
-        // Used a business/personal logo on the PayPal page.
214
-        if (! empty($this->_image_url)) {
215
-            $token_request_dtls['LOGOIMG'] = $this->_image_url;
216
-        }
217
-        $token_request_dtls = apply_filters(
218
-            'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
219
-            $token_request_dtls,
220
-            $this
221
-        );
222
-        // Request PayPal token.
223
-        $token_request_response = $this->_ppExpress_request($token_request_dtls, 'Payment Token', $payment);
224
-        $token_rstatus = $this->_ppExpress_check_response($token_request_response);
225
-        $response_args = (isset($token_rstatus['args']) && is_array($token_rstatus['args']))
226
-            ? $token_rstatus['args']
227
-            : array();
228
-        if ($token_rstatus['status']) {
229
-            // We got the Token so we may continue with the payment and redirect the client.
230
-            $payment->set_details($response_args);
231
-            $gateway_url = $this->_debug_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
232
-            $payment->set_redirect_url(
233
-                $gateway_url
234
-                . '/checkoutnow?useraction=commit&cmd=_express-checkout&token='
235
-                . $response_args['TOKEN']
236
-            );
237
-        } else {
238
-            if (isset($response_args['L_ERRORCODE'])) {
239
-                $payment->set_gateway_response($response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']);
240
-            } else {
241
-                $payment->set_gateway_response(
242
-                    esc_html__(
243
-                        'Error occurred while trying to setup the Express Checkout.',
244
-                        'event_espresso'
245
-                    )
246
-                );
247
-            }
248
-            $payment->set_details($response_args);
249
-            $payment->set_status($this->_pay_model->failed_status());
250
-        }
251
-        return $payment;
252
-    }
253
-
254
-
255
-
256
-    /**
257
-     * @param array           $update_info {
258
-     * @type string           $gateway_txn_id
259
-     * @type string status an EEMI_Payment status
260
-     *                                     }
261
-     * @param EEI_Transaction $transaction
262
-     * @return EEI_Payment
263
-     */
264
-    public function handle_payment_update($update_info, $transaction)
265
-    {
266
-        $payment = $transaction instanceof EEI_Transaction ? $transaction->last_payment() : null;
267
-        if ($payment instanceof EEI_Payment) {
268
-            $this->log(array('Return from Authorization' => $update_info), $payment);
269
-            $transaction = $payment->transaction();
270
-            if (! $transaction instanceof EEI_Transaction) {
271
-                $payment->set_gateway_response(
272
-                    esc_html__(
273
-                        'Could not process this payment because it has no associated transaction.',
274
-                        'event_espresso'
275
-                    )
276
-                );
277
-                $payment->set_status($this->_pay_model->failed_status());
278
-                return $payment;
279
-            }
280
-            $primary_registrant = $transaction->primary_registration();
281
-            $payment_details = $payment->details();
282
-            // Check if we still have the token.
283
-            if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
284
-                $payment->set_status($this->_pay_model->failed_status());
285
-                return $payment;
286
-            }
287
-            $cdetails_request_dtls = array(
288
-                'METHOD' => 'GetExpressCheckoutDetails',
289
-                'TOKEN'  => $payment_details['TOKEN'],
290
-            );
291
-            // Request Customer Details.
292
-            $cdetails_request_response = $this->_ppExpress_request(
293
-                $cdetails_request_dtls,
294
-                'Customer Details',
295
-                $payment
296
-            );
297
-            $cdetails_rstatus = $this->_ppExpress_check_response($cdetails_request_response);
298
-            $cdata_response_args = (isset($cdetails_rstatus['args']) && is_array($cdetails_rstatus['args']))
299
-                ? $cdetails_rstatus['args']
300
-                : array();
301
-            if ($cdetails_rstatus['status']) {
302
-                // We got the PayerID so now we can Complete the transaction.
303
-                $docheckout_request_dtls = array(
304
-                    'METHOD'                         => 'DoExpressCheckoutPayment',
305
-                    'PAYERID'                        => $cdata_response_args['PAYERID'],
306
-                    'TOKEN'                          => $payment_details['TOKEN'],
307
-                    'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
308
-                    'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
309
-                    'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
310
-                    //EE will blow up if you change this
311
-                    'BUTTONSOURCE'                   => 'EventEspresso_SP',
312
-                );
313
-                 // Include itemized list.
314
-                $itemized_list = $this->itemize_list(
315
-                    $payment,
316
-                    $transaction,
317
-                    $cdata_response_args
318
-                );
319
-                $docheckout_request_dtls = array_merge($docheckout_request_dtls, $itemized_list);
320
-                // Payment Checkout/Capture.
321
-                $docheckout_request_response = $this->_ppExpress_request(
322
-                    $docheckout_request_dtls,
323
-                    'Do Payment',
324
-                    $payment
325
-                );
326
-                $docheckout_rstatus = $this->_ppExpress_check_response($docheckout_request_response);
327
-                $docheckout_response_args = (isset($docheckout_rstatus['args']) && is_array($docheckout_rstatus['args']))
328
-                    ? $docheckout_rstatus['args']
329
-                    : array();
330
-                if ($docheckout_rstatus['status']) {
331
-                    // All is well, payment approved.
332
-                    $primary_registration_code = $primary_registrant instanceof EE_Registration ?
333
-                        $primary_registrant->reg_code()
334
-                        : '';
335
-                    $payment->set_extra_accntng($primary_registration_code);
336
-                    $payment->set_amount(isset($docheckout_response_args['PAYMENTINFO_0_AMT'])
337
-                        ? (float)$docheckout_response_args['PAYMENTINFO_0_AMT']
338
-                        : 0);
339
-                    $payment->set_txn_id_chq_nmbr(isset($docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID'])
340
-                        ? $docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID']
341
-                        : null);
342
-                    $payment->set_details($cdata_response_args);
343
-                    $payment->set_gateway_response(isset($docheckout_response_args['PAYMENTINFO_0_ACK'])
344
-                        ? $docheckout_response_args['PAYMENTINFO_0_ACK']
345
-                        : '');
346
-                    $payment->set_status($this->_pay_model->approved_status());
347
-                } else {
348
-                    if (isset($docheckout_response_args['L_ERRORCODE'])) {
349
-                        $payment->set_gateway_response(
350
-                            $docheckout_response_args['L_ERRORCODE']
351
-                            . '; '
352
-                            . $docheckout_response_args['L_SHORTMESSAGE']
353
-                        );
354
-                    } else {
355
-                        $payment->set_gateway_response(
356
-                            esc_html__(
357
-                                'Error occurred while trying to Capture the funds.',
358
-                                'event_espresso'
359
-                            )
360
-                        );
361
-                    }
362
-                    $payment->set_details($docheckout_response_args);
363
-                    $payment->set_status($this->_pay_model->declined_status());
364
-                }
365
-            } else {
366
-                if (isset($cdata_response_args['L_ERRORCODE'])) {
367
-                    $payment->set_gateway_response(
368
-                        $cdata_response_args['L_ERRORCODE']
369
-                        . '; '
370
-                        . $cdata_response_args['L_SHORTMESSAGE']
371
-                    );
372
-                } else {
373
-                    $payment->set_gateway_response(
374
-                        esc_html__(
375
-                            'Error occurred while trying to get payment Details from PayPal.',
376
-                            'event_espresso'
377
-                        )
378
-                    );
379
-                }
380
-                $payment->set_details($cdata_response_args);
381
-                $payment->set_status($this->_pay_model->failed_status());
382
-            }
383
-        } else {
384
-            $payment->set_gateway_response(
385
-                esc_html__(
386
-                    'Error occurred while trying to process the payment.',
387
-                    'event_espresso'
388
-                )
389
-            );
390
-            $payment->set_status($this->_pay_model->failed_status());
391
-        }
392
-        return $payment;
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     *  Make a list of items that are in the giver transaction.
399
-     *
400
-     * @param EEI_Payment     $payment
401
-     * @param EEI_Transaction $transaction
402
-     * @param array           $request_response_args Data from a previous communication with PP.
403
-     * @return array
404
-     */
405
-    public function itemize_list(EEI_Payment $payment, EEI_Transaction $transaction, $request_response_args = array())
406
-    {
407
-        $itemized_list = array();
408
-        $gateway_formatter = $this->_get_gateway_formatter();
409
-        // If we have data from a previous communication with PP (on this transaction) we may use that for our list...
410
-        if (
411
-            ! empty($request_response_args)
412
-            && array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
413
-            && array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
414
-        ) {
415
-            foreach ($request_response_args as $arg_key => $arg_val) {
416
-                if (
417
-                    strpos($arg_key, 'PAYMENTREQUEST_') !== false
418
-                    && strpos($arg_key, 'NOTIFYURL') === false
419
-                ) {
420
-                    $itemized_list[$arg_key] = $arg_val;
421
-                }
422
-            }
423
-            // If we got only a few Items then something is not right.
424
-            if (count($itemized_list) > 2) {
425
-                return $itemized_list;
426
-            } else {
427
-                if (WP_DEBUG) {
428
-                    throw new EE_Error(
429
-                        sprintf(
430
-                            esc_html__(
431
-                                // @codingStandardsIgnoreStart
432
-                                'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
433
-                                // @codingStandardsIgnoreEnd
434
-                                'event_espresso'
435
-                            ),
436
-                            wp_json_encode($itemized_list)
437
-                        )
438
-                    );
439
-                }
440
-                // Reset the list and log an error, maybe allow to try and generate a new list (below).
441
-                $itemized_list = array();
442
-                $this->log(
443
-                    array(
444
-                        esc_html__(
445
-                            'Could not generate a proper item list with:',
446
-                            'event_espresso'
447
-                        ) => $request_response_args
448
-                    ),
449
-                    $payment
450
-                );
451
-            }
452
-        }
453
-        // ...otherwise we generate a new list for this transaction.
454
-        if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
455
-            $item_num = 0;
456
-            $itemized_sum = 0;
457
-            $total_line_items = $transaction->total_line_item();
458
-            // Go through each item in the list.
459
-            foreach ($total_line_items->get_items() as $line_item) {
460
-                if ($line_item instanceof EE_Line_Item) {
461
-                    // PayPal doesn't like line items with 0.00 amount, so we may skip those.
462
-                    if (EEH_Money::compare_floats($line_item->total(), '0.00', '==')) {
463
-                        continue;
464
-                    }
465
-                    $unit_price = $line_item->unit_price();
466
-                    $line_item_quantity = $line_item->quantity();
467
-                    // This is a discount.
468
-                    if ($line_item->is_percent()) {
469
-                        $unit_price = $line_item->total();
470
-                        $line_item_quantity = 1;
471
-                    }
472
-                    // Item Name.
473
-                    $itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
474
-                        $gateway_formatter->formatLineItemName($line_item, $payment),
475
-                        0,
476
-                        127
477
-                    );
478
-                    // Item description.
479
-                    $itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = mb_strcut(
480
-                        $gateway_formatter->formatLineItemDesc($line_item, $payment),
481
-                        0,
482
-                        127
483
-                    );
484
-                    // Cost of individual item.
485
-                    $itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $gateway_formatter->formatCurrency($unit_price);
486
-                    // Item Number.
487
-                    $itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
488
-                    // Item quantity.
489
-                    $itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = $line_item_quantity;
490
-                    // Digital item is sold.
491
-                    $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
492
-                    $itemized_sum += $line_item->total();
493
-                    ++$item_num;
494
-                }
495
-            }
496
-            // Item's sales S/H and tax amount.
497
-            $itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $total_line_items->get_items_total();
498
-            $itemized_list['PAYMENTREQUEST_0_TAXAMT'] = $total_line_items->get_total_tax();
499
-            $itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
500
-            $itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
501
-            $itemized_sum_diff_from_txn_total = round(
502
-                $transaction->total() - $itemized_sum - $total_line_items->get_total_tax(),
503
-                2
504
-            );
505
-            // If we were not able to recognize some item like promotion, surcharge or cancellation,
506
-            // add the difference as an extra line item.
507
-            if ($this->_money->compare_floats($itemized_sum_diff_from_txn_total, 0, '!=')) {
508
-                // Item Name.
509
-                $itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
510
-                    esc_html__(
511
-                        'Other (promotion/surcharge/cancellation)',
512
-                        'event_espresso'
513
-                    ),
514
-                    0,
515
-                    127
516
-                );
517
-                // Item description.
518
-                $itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = '';
519
-                // Cost of individual item.
520
-                $itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $gateway_formatter->formatCurrency(
521
-                    $itemized_sum_diff_from_txn_total
522
-                );
523
-                // Item Number.
524
-                $itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
525
-                // Item quantity.
526
-                $itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = 1;
527
-                // Digital item is sold.
528
-                $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
529
-                $item_num++;
530
-            }
531
-        } else {
532
-            // Just one Item.
533
-            // Item Name.
534
-            $itemized_list['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
535
-                $gateway_formatter->formatPartialPaymentLineItemName($payment),
536
-                0,
537
-                127
538
-            );
539
-            // Item description.
540
-            $itemized_list['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
541
-                $gateway_formatter->formatPartialPaymentLineItemDesc($payment),
542
-                0,
543
-                127
544
-            );
545
-            // Cost of individual item.
546
-            $itemized_list['L_PAYMENTREQUEST_0_AMT0'] = $gateway_formatter->formatCurrency($payment->amount());
547
-            // Item Number.
548
-            $itemized_list['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
549
-            // Item quantity.
550
-            $itemized_list['L_PAYMENTREQUEST_0_QTY0'] = 1;
551
-            // Digital item is sold.
552
-            $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
553
-            // Item's sales S/H and tax amount.
554
-            $itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $gateway_formatter->formatCurrency($payment->amount());
555
-            $itemized_list['PAYMENTREQUEST_0_TAXAMT'] = '0';
556
-            $itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
557
-            $itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
558
-        }
559
-        return $itemized_list;
560
-    }
561
-
562
-
563
-
564
-    /**
565
-     *  Make the Express checkout request.
566
-     *
567
-     * @param array       $request_params
568
-     * @param string      $request_text
569
-     * @param EEI_Payment $payment
570
-     * @return mixed
571
-     */
572
-    public function _ppExpress_request($request_params, $request_text, $payment)
573
-    {
574
-        $request_dtls = array(
575
-            'VERSION'   => '204.0',
576
-            'USER'      => urlencode($this->_api_username),
577
-            'PWD'       => urlencode($this->_api_password),
578
-            'SIGNATURE' => urlencode($this->_api_signature),
579
-        );
580
-        $dtls = array_merge($request_dtls, $request_params);
581
-        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
582
-        // Request Customer Details.
583
-        $request_response = wp_remote_post(
584
-            $this->_base_gateway_url,
585
-            array(
586
-                'method'      => 'POST',
587
-                'timeout'     => 45,
588
-                'httpversion' => '1.1',
589
-                'cookies'     => array(),
590
-                'headers'     => array(),
591
-                'body'        => http_build_query($dtls),
592
-            )
593
-        );
594
-        // Log the response.
595
-        $this->log(array($request_text . ' Response' => $request_response), $payment);
596
-        return $request_response;
597
-    }
598
-
599
-
600
-
601
-    /**
602
-     *  Check the response status.
603
-     *
604
-     * @param mixed $request_response
605
-     * @return array
606
-     */
607
-    public function _ppExpress_check_response($request_response)
608
-    {
609
-        if (is_wp_error($request_response) || empty($request_response['body'])) {
610
-            // If we got here then there was an error in this request.
611
-            return array('status' => false, 'args' => $request_response);
612
-        }
613
-        $response_args = array();
614
-        parse_str(urldecode($request_response['body']), $response_args);
615
-        if (! isset($response_args['ACK'])) {
616
-            return array('status' => false, 'args' => $request_response);
617
-        }
618
-        if (
619
-            (
620
-                isset($response_args['PAYERID'])
621
-                || isset($response_args['TOKEN'])
622
-                || isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
623
-                || (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
624
-            )
625
-            && in_array($response_args['ACK'], array('Success', 'SuccessWithWarning'), true)
626
-        ) {
627
-            // Response status OK, return response parameters for further processing.
628
-            return array('status' => true, 'args' => $response_args);
629
-        }
630
-        $errors = $this->_get_errors($response_args);
631
-        return array('status' => false, 'args' => $errors);
632
-    }
633
-
634
-
635
-
636
-    /**
637
-     *  Log a "Cleared" request.
638
-     *
639
-     * @param array       $request
640
-     * @param EEI_Payment $payment
641
-     * @param string      $info
642
-     * @return void
643
-     */
644
-    private function _log_clean_request($request, $payment, $info)
645
-    {
646
-        $cleaned_request_data = $request;
647
-        unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
648
-        $this->log(array($info => $cleaned_request_data), $payment);
649
-    }
650
-
651
-
652
-
653
-    /**
654
-     *  Get error from the response data.
655
-     *
656
-     * @param array $data_array
657
-     * @return array
658
-     */
659
-    private function _get_errors($data_array)
660
-    {
661
-        $errors = array();
662
-        $n = 0;
663
-        while (isset($data_array["L_ERRORCODE{$n}"])) {
664
-            $l_error_code = isset($data_array["L_ERRORCODE{$n}"])
665
-                ? $data_array["L_ERRORCODE{$n}"]
666
-                : '';
667
-            $l_severity_code = isset($data_array["L_SEVERITYCODE{$n}"])
668
-                ? $data_array["L_SEVERITYCODE{$n}"]
669
-                : '';
670
-            $l_short_message = isset($data_array["L_SHORTMESSAGE{$n}"])
671
-                ? $data_array["L_SHORTMESSAGE{$n}"]
672
-                : '';
673
-            $l_long_message = isset($data_array["L_LONGMESSAGE{$n}"])
674
-                ? $data_array["L_LONGMESSAGE{$n}"]
675
-                : '';
676
-            if ($n === 0) {
677
-                $errors = array(
678
-                    'L_ERRORCODE'    => $l_error_code,
679
-                    'L_SHORTMESSAGE' => $l_short_message,
680
-                    'L_LONGMESSAGE'  => $l_long_message,
681
-                    'L_SEVERITYCODE' => $l_severity_code,
682
-                );
683
-            } else {
684
-                $errors['L_ERRORCODE'] .= ', ' . $l_error_code;
685
-                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
686
-                $errors['L_LONGMESSAGE'] .= ', ' . $l_long_message;
687
-                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
688
-            }
689
-            $n++;
690
-        }
691
-        return $errors;
692
-    }
35
+	/**
36
+	 * Merchant API Username.
37
+	 *
38
+	 * @var string
39
+	 */
40
+	protected $_api_username;
41
+
42
+	/**
43
+	 * Merchant API Password.
44
+	 *
45
+	 * @var string
46
+	 */
47
+	protected $_api_password;
48
+
49
+	/**
50
+	 * API Signature.
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $_api_signature;
55
+
56
+	/**
57
+	 * Request Shipping address on PP checkout page.
58
+	 *
59
+	 * @var string
60
+	 */
61
+	protected $_request_shipping_addr;
62
+
63
+	/**
64
+	 * Business/personal logo.
65
+	 *
66
+	 * @var string
67
+	 */
68
+	protected $_image_url;
69
+
70
+	/**
71
+	 * gateway URL variable
72
+	 *
73
+	 * @var string
74
+	 */
75
+	protected $_base_gateway_url = '';
76
+
77
+
78
+
79
+	/**
80
+	 * EEG_Paypal_Express constructor.
81
+	 */
82
+	public function __construct()
83
+	{
84
+		$this->_currencies_supported = array(
85
+			'USD',
86
+			'AUD',
87
+			'BRL',
88
+			'CAD',
89
+			'CZK',
90
+			'DKK',
91
+			'EUR',
92
+			'HKD',
93
+			'HUF',
94
+			'ILS',
95
+			'JPY',
96
+			'MYR',
97
+			'MXN',
98
+			'NOK',
99
+			'NZD',
100
+			'PHP',
101
+			'PLN',
102
+			'GBP',
103
+			'RUB',
104
+			'SGD',
105
+			'SEK',
106
+			'CHF',
107
+			'TWD',
108
+			'THB',
109
+			'TRY',
110
+		);
111
+		parent::__construct();
112
+	}
113
+
114
+
115
+
116
+	/**
117
+	 * Sets the gateway URL variable based on whether debug mode is enabled or not.
118
+	 *
119
+	 * @param array $settings_array
120
+	 */
121
+	public function set_settings($settings_array)
122
+	{
123
+		parent::set_settings($settings_array);
124
+		// Redirect URL.
125
+		$this->_base_gateway_url = $this->_debug_mode
126
+			? 'https://api-3t.sandbox.paypal.com/nvp'
127
+			: 'https://api-3t.paypal.com/nvp';
128
+	}
129
+
130
+
131
+
132
+	/**
133
+	 * @param EEI_Payment $payment
134
+	 * @param array       $billing_info
135
+	 * @param string      $return_url
136
+	 * @param string      $notify_url
137
+	 * @param string      $cancel_url
138
+	 * @return \EE_Payment|\EEI_Payment
139
+	 * @throws \EE_Error
140
+	 */
141
+	public function set_redirection_info(
142
+		$payment,
143
+		$billing_info = array(),
144
+		$return_url = null,
145
+		$notify_url = null,
146
+		$cancel_url = null
147
+	) {
148
+		if (! $payment instanceof EEI_Payment) {
149
+			$payment->set_gateway_response(
150
+				esc_html__(
151
+					'Error. No associated payment was found.',
152
+					'event_espresso'
153
+				)
154
+			);
155
+			$payment->set_status($this->_pay_model->failed_status());
156
+			return $payment;
157
+		}
158
+		$transaction = $payment->transaction();
159
+		if (! $transaction instanceof EEI_Transaction) {
160
+			$payment->set_gateway_response(
161
+				esc_html__(
162
+					'Could not process this payment because it has no associated transaction.',
163
+					'event_espresso'
164
+				)
165
+			);
166
+			$payment->set_status($this->_pay_model->failed_status());
167
+			return $payment;
168
+		}
169
+		$gateway_formatter = $this->_get_gateway_formatter();
170
+		$order_description = mb_strcut($gateway_formatter->formatOrderDescription($payment), 0, 127);
171
+		$primary_registration = $transaction->primary_registration();
172
+		$primary_attendee = $primary_registration instanceof EE_Registration
173
+			? $primary_registration->attendee()
174
+			: false;
175
+		$locale = explode('-', get_bloginfo('language'));
176
+		// Gather request parameters.
177
+		$token_request_dtls = array(
178
+			'METHOD'                         => 'SetExpressCheckout',
179
+			'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
180
+			'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
181
+			'PAYMENTREQUEST_0_DESC'          => $order_description,
182
+			'RETURNURL'                      => $return_url,
183
+			'CANCELURL'                      => $cancel_url,
184
+			'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
185
+			// Buyer does not need to create a PayPal account to check out.
186
+			// This is referred to as PayPal Account Optional.
187
+			'SOLUTIONTYPE'                   => 'Sole',
188
+			//EE will blow up if you change this
189
+			'BUTTONSOURCE'                   => 'EventEspresso_SP',
190
+			// Locale of the pages displayed by PayPal during Express Checkout.
191
+			'LOCALECODE'                     => $locale[1]
192
+		);
193
+		// Show itemized list.
194
+		$itemized_list = $this->itemize_list($payment, $transaction);
195
+		$token_request_dtls = array_merge($token_request_dtls, $itemized_list);
196
+		// Automatically filling out shipping and contact information.
197
+		if ($this->_request_shipping_addr && $primary_attendee instanceof EEI_Attendee) {
198
+			// If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
199
+			$token_request_dtls['NOSHIPPING'] = '2';
200
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET'] = $primary_attendee->address();
201
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET2'] = $primary_attendee->address2();
202
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOCITY'] = $primary_attendee->city();
203
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTATE'] = $primary_attendee->state_abbrev();
204
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
205
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOZIP'] = $primary_attendee->zip();
206
+			$token_request_dtls['PAYMENTREQUEST_0_EMAIL'] = $primary_attendee->email();
207
+			$token_request_dtls['PAYMENTREQUEST_0_SHIPTOPHONENUM'] = $primary_attendee->phone();
208
+		} elseif (! $this->_request_shipping_addr) {
209
+			// Do not request shipping details on the PP Checkout page.
210
+			$token_request_dtls['NOSHIPPING'] = '1';
211
+			$token_request_dtls['REQCONFIRMSHIPPING'] = '0';
212
+		}
213
+		// Used a business/personal logo on the PayPal page.
214
+		if (! empty($this->_image_url)) {
215
+			$token_request_dtls['LOGOIMG'] = $this->_image_url;
216
+		}
217
+		$token_request_dtls = apply_filters(
218
+			'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
219
+			$token_request_dtls,
220
+			$this
221
+		);
222
+		// Request PayPal token.
223
+		$token_request_response = $this->_ppExpress_request($token_request_dtls, 'Payment Token', $payment);
224
+		$token_rstatus = $this->_ppExpress_check_response($token_request_response);
225
+		$response_args = (isset($token_rstatus['args']) && is_array($token_rstatus['args']))
226
+			? $token_rstatus['args']
227
+			: array();
228
+		if ($token_rstatus['status']) {
229
+			// We got the Token so we may continue with the payment and redirect the client.
230
+			$payment->set_details($response_args);
231
+			$gateway_url = $this->_debug_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
232
+			$payment->set_redirect_url(
233
+				$gateway_url
234
+				. '/checkoutnow?useraction=commit&cmd=_express-checkout&token='
235
+				. $response_args['TOKEN']
236
+			);
237
+		} else {
238
+			if (isset($response_args['L_ERRORCODE'])) {
239
+				$payment->set_gateway_response($response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']);
240
+			} else {
241
+				$payment->set_gateway_response(
242
+					esc_html__(
243
+						'Error occurred while trying to setup the Express Checkout.',
244
+						'event_espresso'
245
+					)
246
+				);
247
+			}
248
+			$payment->set_details($response_args);
249
+			$payment->set_status($this->_pay_model->failed_status());
250
+		}
251
+		return $payment;
252
+	}
253
+
254
+
255
+
256
+	/**
257
+	 * @param array           $update_info {
258
+	 * @type string           $gateway_txn_id
259
+	 * @type string status an EEMI_Payment status
260
+	 *                                     }
261
+	 * @param EEI_Transaction $transaction
262
+	 * @return EEI_Payment
263
+	 */
264
+	public function handle_payment_update($update_info, $transaction)
265
+	{
266
+		$payment = $transaction instanceof EEI_Transaction ? $transaction->last_payment() : null;
267
+		if ($payment instanceof EEI_Payment) {
268
+			$this->log(array('Return from Authorization' => $update_info), $payment);
269
+			$transaction = $payment->transaction();
270
+			if (! $transaction instanceof EEI_Transaction) {
271
+				$payment->set_gateway_response(
272
+					esc_html__(
273
+						'Could not process this payment because it has no associated transaction.',
274
+						'event_espresso'
275
+					)
276
+				);
277
+				$payment->set_status($this->_pay_model->failed_status());
278
+				return $payment;
279
+			}
280
+			$primary_registrant = $transaction->primary_registration();
281
+			$payment_details = $payment->details();
282
+			// Check if we still have the token.
283
+			if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
284
+				$payment->set_status($this->_pay_model->failed_status());
285
+				return $payment;
286
+			}
287
+			$cdetails_request_dtls = array(
288
+				'METHOD' => 'GetExpressCheckoutDetails',
289
+				'TOKEN'  => $payment_details['TOKEN'],
290
+			);
291
+			// Request Customer Details.
292
+			$cdetails_request_response = $this->_ppExpress_request(
293
+				$cdetails_request_dtls,
294
+				'Customer Details',
295
+				$payment
296
+			);
297
+			$cdetails_rstatus = $this->_ppExpress_check_response($cdetails_request_response);
298
+			$cdata_response_args = (isset($cdetails_rstatus['args']) && is_array($cdetails_rstatus['args']))
299
+				? $cdetails_rstatus['args']
300
+				: array();
301
+			if ($cdetails_rstatus['status']) {
302
+				// We got the PayerID so now we can Complete the transaction.
303
+				$docheckout_request_dtls = array(
304
+					'METHOD'                         => 'DoExpressCheckoutPayment',
305
+					'PAYERID'                        => $cdata_response_args['PAYERID'],
306
+					'TOKEN'                          => $payment_details['TOKEN'],
307
+					'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
308
+					'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
309
+					'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
310
+					//EE will blow up if you change this
311
+					'BUTTONSOURCE'                   => 'EventEspresso_SP',
312
+				);
313
+				 // Include itemized list.
314
+				$itemized_list = $this->itemize_list(
315
+					$payment,
316
+					$transaction,
317
+					$cdata_response_args
318
+				);
319
+				$docheckout_request_dtls = array_merge($docheckout_request_dtls, $itemized_list);
320
+				// Payment Checkout/Capture.
321
+				$docheckout_request_response = $this->_ppExpress_request(
322
+					$docheckout_request_dtls,
323
+					'Do Payment',
324
+					$payment
325
+				);
326
+				$docheckout_rstatus = $this->_ppExpress_check_response($docheckout_request_response);
327
+				$docheckout_response_args = (isset($docheckout_rstatus['args']) && is_array($docheckout_rstatus['args']))
328
+					? $docheckout_rstatus['args']
329
+					: array();
330
+				if ($docheckout_rstatus['status']) {
331
+					// All is well, payment approved.
332
+					$primary_registration_code = $primary_registrant instanceof EE_Registration ?
333
+						$primary_registrant->reg_code()
334
+						: '';
335
+					$payment->set_extra_accntng($primary_registration_code);
336
+					$payment->set_amount(isset($docheckout_response_args['PAYMENTINFO_0_AMT'])
337
+						? (float)$docheckout_response_args['PAYMENTINFO_0_AMT']
338
+						: 0);
339
+					$payment->set_txn_id_chq_nmbr(isset($docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID'])
340
+						? $docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID']
341
+						: null);
342
+					$payment->set_details($cdata_response_args);
343
+					$payment->set_gateway_response(isset($docheckout_response_args['PAYMENTINFO_0_ACK'])
344
+						? $docheckout_response_args['PAYMENTINFO_0_ACK']
345
+						: '');
346
+					$payment->set_status($this->_pay_model->approved_status());
347
+				} else {
348
+					if (isset($docheckout_response_args['L_ERRORCODE'])) {
349
+						$payment->set_gateway_response(
350
+							$docheckout_response_args['L_ERRORCODE']
351
+							. '; '
352
+							. $docheckout_response_args['L_SHORTMESSAGE']
353
+						);
354
+					} else {
355
+						$payment->set_gateway_response(
356
+							esc_html__(
357
+								'Error occurred while trying to Capture the funds.',
358
+								'event_espresso'
359
+							)
360
+						);
361
+					}
362
+					$payment->set_details($docheckout_response_args);
363
+					$payment->set_status($this->_pay_model->declined_status());
364
+				}
365
+			} else {
366
+				if (isset($cdata_response_args['L_ERRORCODE'])) {
367
+					$payment->set_gateway_response(
368
+						$cdata_response_args['L_ERRORCODE']
369
+						. '; '
370
+						. $cdata_response_args['L_SHORTMESSAGE']
371
+					);
372
+				} else {
373
+					$payment->set_gateway_response(
374
+						esc_html__(
375
+							'Error occurred while trying to get payment Details from PayPal.',
376
+							'event_espresso'
377
+						)
378
+					);
379
+				}
380
+				$payment->set_details($cdata_response_args);
381
+				$payment->set_status($this->_pay_model->failed_status());
382
+			}
383
+		} else {
384
+			$payment->set_gateway_response(
385
+				esc_html__(
386
+					'Error occurred while trying to process the payment.',
387
+					'event_espresso'
388
+				)
389
+			);
390
+			$payment->set_status($this->_pay_model->failed_status());
391
+		}
392
+		return $payment;
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 *  Make a list of items that are in the giver transaction.
399
+	 *
400
+	 * @param EEI_Payment     $payment
401
+	 * @param EEI_Transaction $transaction
402
+	 * @param array           $request_response_args Data from a previous communication with PP.
403
+	 * @return array
404
+	 */
405
+	public function itemize_list(EEI_Payment $payment, EEI_Transaction $transaction, $request_response_args = array())
406
+	{
407
+		$itemized_list = array();
408
+		$gateway_formatter = $this->_get_gateway_formatter();
409
+		// If we have data from a previous communication with PP (on this transaction) we may use that for our list...
410
+		if (
411
+			! empty($request_response_args)
412
+			&& array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
413
+			&& array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
414
+		) {
415
+			foreach ($request_response_args as $arg_key => $arg_val) {
416
+				if (
417
+					strpos($arg_key, 'PAYMENTREQUEST_') !== false
418
+					&& strpos($arg_key, 'NOTIFYURL') === false
419
+				) {
420
+					$itemized_list[$arg_key] = $arg_val;
421
+				}
422
+			}
423
+			// If we got only a few Items then something is not right.
424
+			if (count($itemized_list) > 2) {
425
+				return $itemized_list;
426
+			} else {
427
+				if (WP_DEBUG) {
428
+					throw new EE_Error(
429
+						sprintf(
430
+							esc_html__(
431
+								// @codingStandardsIgnoreStart
432
+								'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
433
+								// @codingStandardsIgnoreEnd
434
+								'event_espresso'
435
+							),
436
+							wp_json_encode($itemized_list)
437
+						)
438
+					);
439
+				}
440
+				// Reset the list and log an error, maybe allow to try and generate a new list (below).
441
+				$itemized_list = array();
442
+				$this->log(
443
+					array(
444
+						esc_html__(
445
+							'Could not generate a proper item list with:',
446
+							'event_espresso'
447
+						) => $request_response_args
448
+					),
449
+					$payment
450
+				);
451
+			}
452
+		}
453
+		// ...otherwise we generate a new list for this transaction.
454
+		if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
455
+			$item_num = 0;
456
+			$itemized_sum = 0;
457
+			$total_line_items = $transaction->total_line_item();
458
+			// Go through each item in the list.
459
+			foreach ($total_line_items->get_items() as $line_item) {
460
+				if ($line_item instanceof EE_Line_Item) {
461
+					// PayPal doesn't like line items with 0.00 amount, so we may skip those.
462
+					if (EEH_Money::compare_floats($line_item->total(), '0.00', '==')) {
463
+						continue;
464
+					}
465
+					$unit_price = $line_item->unit_price();
466
+					$line_item_quantity = $line_item->quantity();
467
+					// This is a discount.
468
+					if ($line_item->is_percent()) {
469
+						$unit_price = $line_item->total();
470
+						$line_item_quantity = 1;
471
+					}
472
+					// Item Name.
473
+					$itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
474
+						$gateway_formatter->formatLineItemName($line_item, $payment),
475
+						0,
476
+						127
477
+					);
478
+					// Item description.
479
+					$itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = mb_strcut(
480
+						$gateway_formatter->formatLineItemDesc($line_item, $payment),
481
+						0,
482
+						127
483
+					);
484
+					// Cost of individual item.
485
+					$itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $gateway_formatter->formatCurrency($unit_price);
486
+					// Item Number.
487
+					$itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
488
+					// Item quantity.
489
+					$itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = $line_item_quantity;
490
+					// Digital item is sold.
491
+					$itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
492
+					$itemized_sum += $line_item->total();
493
+					++$item_num;
494
+				}
495
+			}
496
+			// Item's sales S/H and tax amount.
497
+			$itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $total_line_items->get_items_total();
498
+			$itemized_list['PAYMENTREQUEST_0_TAXAMT'] = $total_line_items->get_total_tax();
499
+			$itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
500
+			$itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
501
+			$itemized_sum_diff_from_txn_total = round(
502
+				$transaction->total() - $itemized_sum - $total_line_items->get_total_tax(),
503
+				2
504
+			);
505
+			// If we were not able to recognize some item like promotion, surcharge or cancellation,
506
+			// add the difference as an extra line item.
507
+			if ($this->_money->compare_floats($itemized_sum_diff_from_txn_total, 0, '!=')) {
508
+				// Item Name.
509
+				$itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
510
+					esc_html__(
511
+						'Other (promotion/surcharge/cancellation)',
512
+						'event_espresso'
513
+					),
514
+					0,
515
+					127
516
+				);
517
+				// Item description.
518
+				$itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = '';
519
+				// Cost of individual item.
520
+				$itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $gateway_formatter->formatCurrency(
521
+					$itemized_sum_diff_from_txn_total
522
+				);
523
+				// Item Number.
524
+				$itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
525
+				// Item quantity.
526
+				$itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = 1;
527
+				// Digital item is sold.
528
+				$itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
529
+				$item_num++;
530
+			}
531
+		} else {
532
+			// Just one Item.
533
+			// Item Name.
534
+			$itemized_list['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
535
+				$gateway_formatter->formatPartialPaymentLineItemName($payment),
536
+				0,
537
+				127
538
+			);
539
+			// Item description.
540
+			$itemized_list['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
541
+				$gateway_formatter->formatPartialPaymentLineItemDesc($payment),
542
+				0,
543
+				127
544
+			);
545
+			// Cost of individual item.
546
+			$itemized_list['L_PAYMENTREQUEST_0_AMT0'] = $gateway_formatter->formatCurrency($payment->amount());
547
+			// Item Number.
548
+			$itemized_list['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
549
+			// Item quantity.
550
+			$itemized_list['L_PAYMENTREQUEST_0_QTY0'] = 1;
551
+			// Digital item is sold.
552
+			$itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
553
+			// Item's sales S/H and tax amount.
554
+			$itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $gateway_formatter->formatCurrency($payment->amount());
555
+			$itemized_list['PAYMENTREQUEST_0_TAXAMT'] = '0';
556
+			$itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
557
+			$itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
558
+		}
559
+		return $itemized_list;
560
+	}
561
+
562
+
563
+
564
+	/**
565
+	 *  Make the Express checkout request.
566
+	 *
567
+	 * @param array       $request_params
568
+	 * @param string      $request_text
569
+	 * @param EEI_Payment $payment
570
+	 * @return mixed
571
+	 */
572
+	public function _ppExpress_request($request_params, $request_text, $payment)
573
+	{
574
+		$request_dtls = array(
575
+			'VERSION'   => '204.0',
576
+			'USER'      => urlencode($this->_api_username),
577
+			'PWD'       => urlencode($this->_api_password),
578
+			'SIGNATURE' => urlencode($this->_api_signature),
579
+		);
580
+		$dtls = array_merge($request_dtls, $request_params);
581
+		$this->_log_clean_request($dtls, $payment, $request_text . ' Request');
582
+		// Request Customer Details.
583
+		$request_response = wp_remote_post(
584
+			$this->_base_gateway_url,
585
+			array(
586
+				'method'      => 'POST',
587
+				'timeout'     => 45,
588
+				'httpversion' => '1.1',
589
+				'cookies'     => array(),
590
+				'headers'     => array(),
591
+				'body'        => http_build_query($dtls),
592
+			)
593
+		);
594
+		// Log the response.
595
+		$this->log(array($request_text . ' Response' => $request_response), $payment);
596
+		return $request_response;
597
+	}
598
+
599
+
600
+
601
+	/**
602
+	 *  Check the response status.
603
+	 *
604
+	 * @param mixed $request_response
605
+	 * @return array
606
+	 */
607
+	public function _ppExpress_check_response($request_response)
608
+	{
609
+		if (is_wp_error($request_response) || empty($request_response['body'])) {
610
+			// If we got here then there was an error in this request.
611
+			return array('status' => false, 'args' => $request_response);
612
+		}
613
+		$response_args = array();
614
+		parse_str(urldecode($request_response['body']), $response_args);
615
+		if (! isset($response_args['ACK'])) {
616
+			return array('status' => false, 'args' => $request_response);
617
+		}
618
+		if (
619
+			(
620
+				isset($response_args['PAYERID'])
621
+				|| isset($response_args['TOKEN'])
622
+				|| isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
623
+				|| (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
624
+			)
625
+			&& in_array($response_args['ACK'], array('Success', 'SuccessWithWarning'), true)
626
+		) {
627
+			// Response status OK, return response parameters for further processing.
628
+			return array('status' => true, 'args' => $response_args);
629
+		}
630
+		$errors = $this->_get_errors($response_args);
631
+		return array('status' => false, 'args' => $errors);
632
+	}
633
+
634
+
635
+
636
+	/**
637
+	 *  Log a "Cleared" request.
638
+	 *
639
+	 * @param array       $request
640
+	 * @param EEI_Payment $payment
641
+	 * @param string      $info
642
+	 * @return void
643
+	 */
644
+	private function _log_clean_request($request, $payment, $info)
645
+	{
646
+		$cleaned_request_data = $request;
647
+		unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
648
+		$this->log(array($info => $cleaned_request_data), $payment);
649
+	}
650
+
651
+
652
+
653
+	/**
654
+	 *  Get error from the response data.
655
+	 *
656
+	 * @param array $data_array
657
+	 * @return array
658
+	 */
659
+	private function _get_errors($data_array)
660
+	{
661
+		$errors = array();
662
+		$n = 0;
663
+		while (isset($data_array["L_ERRORCODE{$n}"])) {
664
+			$l_error_code = isset($data_array["L_ERRORCODE{$n}"])
665
+				? $data_array["L_ERRORCODE{$n}"]
666
+				: '';
667
+			$l_severity_code = isset($data_array["L_SEVERITYCODE{$n}"])
668
+				? $data_array["L_SEVERITYCODE{$n}"]
669
+				: '';
670
+			$l_short_message = isset($data_array["L_SHORTMESSAGE{$n}"])
671
+				? $data_array["L_SHORTMESSAGE{$n}"]
672
+				: '';
673
+			$l_long_message = isset($data_array["L_LONGMESSAGE{$n}"])
674
+				? $data_array["L_LONGMESSAGE{$n}"]
675
+				: '';
676
+			if ($n === 0) {
677
+				$errors = array(
678
+					'L_ERRORCODE'    => $l_error_code,
679
+					'L_SHORTMESSAGE' => $l_short_message,
680
+					'L_LONGMESSAGE'  => $l_long_message,
681
+					'L_SEVERITYCODE' => $l_severity_code,
682
+				);
683
+			} else {
684
+				$errors['L_ERRORCODE'] .= ', ' . $l_error_code;
685
+				$errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
686
+				$errors['L_LONGMESSAGE'] .= ', ' . $l_long_message;
687
+				$errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
688
+			}
689
+			$n++;
690
+		}
691
+		return $errors;
692
+	}
693 693
 
694 694
 }
695 695
 // End of file EEG_Paypal_Express.gateway.php
Please login to merge, or discard this patch.
Spacing   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -1,4 +1,4 @@  discard block
 block discarded – undo
1
-<?php if (! defined('EVENT_ESPRESSO_VERSION')) {
1
+<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2 2
     exit('NO direct script access allowed');
3 3
 }
4 4
 
@@ -15,7 +15,7 @@  discard block
 block discarded – undo
15 15
  * ----------------------------------------------
16 16
  */
17 17
 //Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
18
-if (! function_exists('mb_strcut')) {
18
+if ( ! function_exists('mb_strcut')) {
19 19
     /**
20 20
      * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
21 21
      * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
         $notify_url = null,
146 146
         $cancel_url = null
147 147
     ) {
148
-        if (! $payment instanceof EEI_Payment) {
148
+        if ( ! $payment instanceof EEI_Payment) {
149 149
             $payment->set_gateway_response(
150 150
                 esc_html__(
151 151
                     'Error. No associated payment was found.',
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
             return $payment;
157 157
         }
158 158
         $transaction = $payment->transaction();
159
-        if (! $transaction instanceof EEI_Transaction) {
159
+        if ( ! $transaction instanceof EEI_Transaction) {
160 160
             $payment->set_gateway_response(
161 161
                 esc_html__(
162 162
                     'Could not process this payment because it has no associated transaction.',
@@ -205,13 +205,13 @@  discard block
 block discarded – undo
205 205
             $token_request_dtls['PAYMENTREQUEST_0_SHIPTOZIP'] = $primary_attendee->zip();
206 206
             $token_request_dtls['PAYMENTREQUEST_0_EMAIL'] = $primary_attendee->email();
207 207
             $token_request_dtls['PAYMENTREQUEST_0_SHIPTOPHONENUM'] = $primary_attendee->phone();
208
-        } elseif (! $this->_request_shipping_addr) {
208
+        } elseif ( ! $this->_request_shipping_addr) {
209 209
             // Do not request shipping details on the PP Checkout page.
210 210
             $token_request_dtls['NOSHIPPING'] = '1';
211 211
             $token_request_dtls['REQCONFIRMSHIPPING'] = '0';
212 212
         }
213 213
         // Used a business/personal logo on the PayPal page.
214
-        if (! empty($this->_image_url)) {
214
+        if ( ! empty($this->_image_url)) {
215 215
             $token_request_dtls['LOGOIMG'] = $this->_image_url;
216 216
         }
217 217
         $token_request_dtls = apply_filters(
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
             );
237 237
         } else {
238 238
             if (isset($response_args['L_ERRORCODE'])) {
239
-                $payment->set_gateway_response($response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']);
239
+                $payment->set_gateway_response($response_args['L_ERRORCODE'].'; '.$response_args['L_SHORTMESSAGE']);
240 240
             } else {
241 241
                 $payment->set_gateway_response(
242 242
                     esc_html__(
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
         if ($payment instanceof EEI_Payment) {
268 268
             $this->log(array('Return from Authorization' => $update_info), $payment);
269 269
             $transaction = $payment->transaction();
270
-            if (! $transaction instanceof EEI_Transaction) {
270
+            if ( ! $transaction instanceof EEI_Transaction) {
271 271
                 $payment->set_gateway_response(
272 272
                     esc_html__(
273 273
                         'Could not process this payment because it has no associated transaction.',
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
             $primary_registrant = $transaction->primary_registration();
281 281
             $payment_details = $payment->details();
282 282
             // Check if we still have the token.
283
-            if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
283
+            if ( ! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
284 284
                 $payment->set_status($this->_pay_model->failed_status());
285 285
                 return $payment;
286 286
             }
@@ -334,7 +334,7 @@  discard block
 block discarded – undo
334 334
                         : '';
335 335
                     $payment->set_extra_accntng($primary_registration_code);
336 336
                     $payment->set_amount(isset($docheckout_response_args['PAYMENTINFO_0_AMT'])
337
-                        ? (float)$docheckout_response_args['PAYMENTINFO_0_AMT']
337
+                        ? (float) $docheckout_response_args['PAYMENTINFO_0_AMT']
338 338
                         : 0);
339 339
                     $payment->set_txn_id_chq_nmbr(isset($docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID'])
340 340
                         ? $docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID']
@@ -470,25 +470,25 @@  discard block
 block discarded – undo
470 470
                         $line_item_quantity = 1;
471 471
                     }
472 472
                     // Item Name.
473
-                    $itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
473
+                    $itemized_list['L_PAYMENTREQUEST_0_NAME'.$item_num] = mb_strcut(
474 474
                         $gateway_formatter->formatLineItemName($line_item, $payment),
475 475
                         0,
476 476
                         127
477 477
                     );
478 478
                     // Item description.
479
-                    $itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = mb_strcut(
479
+                    $itemized_list['L_PAYMENTREQUEST_0_DESC'.$item_num] = mb_strcut(
480 480
                         $gateway_formatter->formatLineItemDesc($line_item, $payment),
481 481
                         0,
482 482
                         127
483 483
                     );
484 484
                     // Cost of individual item.
485
-                    $itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $gateway_formatter->formatCurrency($unit_price);
485
+                    $itemized_list['L_PAYMENTREQUEST_0_AMT'.$item_num] = $gateway_formatter->formatCurrency($unit_price);
486 486
                     // Item Number.
487
-                    $itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
487
+                    $itemized_list['L_PAYMENTREQUEST_0_NUMBER'.$item_num] = $item_num + 1;
488 488
                     // Item quantity.
489
-                    $itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = $line_item_quantity;
489
+                    $itemized_list['L_PAYMENTREQUEST_0_QTY'.$item_num] = $line_item_quantity;
490 490
                     // Digital item is sold.
491
-                    $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
491
+                    $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY'.$item_num] = 'Physical';
492 492
                     $itemized_sum += $line_item->total();
493 493
                     ++$item_num;
494 494
                 }
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
             // add the difference as an extra line item.
507 507
             if ($this->_money->compare_floats($itemized_sum_diff_from_txn_total, 0, '!=')) {
508 508
                 // Item Name.
509
-                $itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
509
+                $itemized_list['L_PAYMENTREQUEST_0_NAME'.$item_num] = mb_strcut(
510 510
                     esc_html__(
511 511
                         'Other (promotion/surcharge/cancellation)',
512 512
                         'event_espresso'
@@ -515,17 +515,17 @@  discard block
 block discarded – undo
515 515
                     127
516 516
                 );
517 517
                 // Item description.
518
-                $itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = '';
518
+                $itemized_list['L_PAYMENTREQUEST_0_DESC'.$item_num] = '';
519 519
                 // Cost of individual item.
520
-                $itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $gateway_formatter->formatCurrency(
520
+                $itemized_list['L_PAYMENTREQUEST_0_AMT'.$item_num] = $gateway_formatter->formatCurrency(
521 521
                     $itemized_sum_diff_from_txn_total
522 522
                 );
523 523
                 // Item Number.
524
-                $itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
524
+                $itemized_list['L_PAYMENTREQUEST_0_NUMBER'.$item_num] = $item_num + 1;
525 525
                 // Item quantity.
526
-                $itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = 1;
526
+                $itemized_list['L_PAYMENTREQUEST_0_QTY'.$item_num] = 1;
527 527
                 // Digital item is sold.
528
-                $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
528
+                $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY'.$item_num] = 'Physical';
529 529
                 $item_num++;
530 530
             }
531 531
         } else {
@@ -578,7 +578,7 @@  discard block
 block discarded – undo
578 578
             'SIGNATURE' => urlencode($this->_api_signature),
579 579
         );
580 580
         $dtls = array_merge($request_dtls, $request_params);
581
-        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
581
+        $this->_log_clean_request($dtls, $payment, $request_text.' Request');
582 582
         // Request Customer Details.
583 583
         $request_response = wp_remote_post(
584 584
             $this->_base_gateway_url,
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
             )
593 593
         );
594 594
         // Log the response.
595
-        $this->log(array($request_text . ' Response' => $request_response), $payment);
595
+        $this->log(array($request_text.' Response' => $request_response), $payment);
596 596
         return $request_response;
597 597
     }
598 598
 
@@ -612,7 +612,7 @@  discard block
 block discarded – undo
612 612
         }
613 613
         $response_args = array();
614 614
         parse_str(urldecode($request_response['body']), $response_args);
615
-        if (! isset($response_args['ACK'])) {
615
+        if ( ! isset($response_args['ACK'])) {
616 616
             return array('status' => false, 'args' => $request_response);
617 617
         }
618 618
         if (
@@ -681,10 +681,10 @@  discard block
 block discarded – undo
681 681
                     'L_SEVERITYCODE' => $l_severity_code,
682 682
                 );
683 683
             } else {
684
-                $errors['L_ERRORCODE'] .= ', ' . $l_error_code;
685
-                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
686
-                $errors['L_LONGMESSAGE'] .= ', ' . $l_long_message;
687
-                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
684
+                $errors['L_ERRORCODE'] .= ', '.$l_error_code;
685
+                $errors['L_SHORTMESSAGE'] .= ', '.$l_short_message;
686
+                $errors['L_LONGMESSAGE'] .= ', '.$l_long_message;
687
+                $errors['L_SEVERITYCODE'] .= ', '.$l_severity_code;
688 688
             }
689 689
             $n++;
690 690
         }
Please login to merge, or discard this patch.
core/db_models/fields/EE_Text_Field_Base.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -7,49 +7,49 @@
 block discarded – undo
7 7
 abstract class EE_Text_Field_Base extends EE_Model_Field_Base
8 8
 {
9 9
 
10
-    /**
11
-     * Gets the value in the format expected when being set.
12
-     * For display on the front-end, usually you would use prepare_for_pretty_echoing() instead.
13
-     * @param mixed $value_of_field_on_model_object
14
-     * @return mixed|string
15
-     */
16
-    public function prepare_for_get($value_of_field_on_model_object)
17
-    {
18
-        return $value_of_field_on_model_object;
19
-    }
10
+	/**
11
+	 * Gets the value in the format expected when being set.
12
+	 * For display on the front-end, usually you would use prepare_for_pretty_echoing() instead.
13
+	 * @param mixed $value_of_field_on_model_object
14
+	 * @return mixed|string
15
+	 */
16
+	public function prepare_for_get($value_of_field_on_model_object)
17
+	{
18
+		return $value_of_field_on_model_object;
19
+	}
20 20
 
21
-    /**
22
-     * Accepts schema of 'form_input' which formats the string for echoing in form input's value.
23
-     *
24
-     * @param string $value_on_field_to_be_outputted
25
-     * @param string $schema
26
-     * @return string
27
-     */
28
-    public function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null)
29
-    {
30
-        if ($schema === 'form_input') {
31
-            $value_on_field_to_be_outputted = (string)htmlentities(
32
-                $value_on_field_to_be_outputted,
33
-                ENT_QUOTES,
34
-                'UTF-8'
35
-            );
36
-        }
37
-        return parent::prepare_for_pretty_echoing($value_on_field_to_be_outputted);
38
-    }
21
+	/**
22
+	 * Accepts schema of 'form_input' which formats the string for echoing in form input's value.
23
+	 *
24
+	 * @param string $value_on_field_to_be_outputted
25
+	 * @param string $schema
26
+	 * @return string
27
+	 */
28
+	public function prepare_for_pretty_echoing($value_on_field_to_be_outputted, $schema = null)
29
+	{
30
+		if ($schema === 'form_input') {
31
+			$value_on_field_to_be_outputted = (string)htmlentities(
32
+				$value_on_field_to_be_outputted,
33
+				ENT_QUOTES,
34
+				'UTF-8'
35
+			);
36
+		}
37
+		return parent::prepare_for_pretty_echoing($value_on_field_to_be_outputted);
38
+	}
39 39
 
40
-    /**
41
-     * Data received from the user should be exactly as they hope to save it in the DB, with the exception that
42
-     * quotes need to have slashes added to it. This method takes care of removing the slashes added by WP
43
-     * in magic-quotes fashion. We used to call html_entity_decode on the value here,
44
-     * because we called htmlentities when in EE_Text_Field_Base::prepare_for_pretty_echoing, but that's not necessary
45
-     * because web browsers always decode HTML entities in element attributes, like a form element's value attribute.
46
-     * So if we do it again here, we'll be removing HTML entities the user intended to have.)
47
-     *
48
-     * @param string $value_inputted_for_field_on_model_object
49
-     * @return string
50
-     */
51
-    public function prepare_for_set($value_inputted_for_field_on_model_object)
52
-    {
53
-        return stripslashes(parent::prepare_for_set($value_inputted_for_field_on_model_object));
54
-    }
40
+	/**
41
+	 * Data received from the user should be exactly as they hope to save it in the DB, with the exception that
42
+	 * quotes need to have slashes added to it. This method takes care of removing the slashes added by WP
43
+	 * in magic-quotes fashion. We used to call html_entity_decode on the value here,
44
+	 * because we called htmlentities when in EE_Text_Field_Base::prepare_for_pretty_echoing, but that's not necessary
45
+	 * because web browsers always decode HTML entities in element attributes, like a form element's value attribute.
46
+	 * So if we do it again here, we'll be removing HTML entities the user intended to have.)
47
+	 *
48
+	 * @param string $value_inputted_for_field_on_model_object
49
+	 * @return string
50
+	 */
51
+	public function prepare_for_set($value_inputted_for_field_on_model_object)
52
+	{
53
+		return stripslashes(parent::prepare_for_set($value_inputted_for_field_on_model_object));
54
+	}
55 55
 }
56 56
\ No newline at end of file
Please login to merge, or discard this patch.
core/libraries/messages/messenger/EE_Html_messenger.class.php 1 patch
Indentation   +548 added lines, -548 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if (!defined('EVENT_ESPRESSO_VERSION')) {
3
-    exit('NO direct script access allowed');
3
+	exit('NO direct script access allowed');
4 4
 }
5 5
 
6 6
 
@@ -16,552 +16,552 @@  discard block
 block discarded – undo
16 16
 {
17 17
 
18 18
 
19
-    /**
20
-     * The following are the properties that this messenger requires for displaying the html
21
-     */
22
-    /**
23
-     * This is the html body generated by the template via the message type.
24
-     *
25
-     * @var string
26
-     */
27
-    protected $_content;
28
-
29
-
30
-    /**
31
-     * This is for the page title that gets displayed.  (Why use "subject"?  Because the "title" tag in html is
32
-     * equivalent to the "subject" of the page.
33
-     *
34
-     * @var string
35
-     */
36
-    protected $_subject;
37
-
38
-
39
-    /**
40
-     * EE_Html_messenger constructor.
41
-     */
42
-    public function __construct()
43
-    {
44
-        //set properties
45
-        $this->name = 'html';
46
-        $this->description = __('This messenger outputs a message to a browser for display.', 'event_espresso');
47
-        $this->label = array(
48
-            'singular' => __('html', 'event_espresso'),
49
-            'plural' => __('html', 'event_espresso'),
50
-        );
51
-        $this->activate_on_install = true;
52
-        // add the "powered by EE" credit link to the HTML receipt and invoice
53
-        add_filter(
54
-            'FHEE__EE_Html_messenger___send_message__main_body',
55
-            array($this, 'add_powered_by_credit_link_to_receipt_and_invoice'),
56
-            10,
57
-            3
58
-        );
59
-        parent::__construct();
60
-    }
61
-
62
-
63
-    /**
64
-     * HTML Messenger desires execution immediately.
65
-     *
66
-     * @see    parent::send_now() for documentation.
67
-     * @since  4.9.0
68
-     * @return bool
69
-     */
70
-    public function send_now()
71
-    {
72
-        return true;
73
-    }
74
-
75
-
76
-    /**
77
-     * HTML Messenger allows an empty to field.
78
-     *
79
-     * @see    parent::allow_empty_to_field() for documentation
80
-     * @since  4.9.0
81
-     * @return bool
82
-     */
83
-    public function allow_empty_to_field()
84
-    {
85
-        return true;
86
-    }
87
-
88
-
89
-    /**
90
-     * @see abstract declaration in EE_messenger for details.
91
-     */
92
-    protected function _set_admin_pages()
93
-    {
94
-        $this->admin_registered_pages = array('events_edit' => true);
95
-    }
96
-
97
-
98
-    /**
99
-     * @see abstract declaration in EE_messenger for details.
100
-     */
101
-    protected function _set_valid_shortcodes()
102
-    {
103
-        $this->_valid_shortcodes = array();
104
-    }
105
-
106
-
107
-    /**
108
-     * @see abstract declaration in EE_messenger for details.
109
-     */
110
-    protected function _set_validator_config()
111
-    {
112
-        $this->_validator_config = array(
113
-            'subject' => array(
114
-                'shortcodes' => array('organization', 'primary_registration_details', 'email', 'transaction'),
115
-            ),
116
-            'content' => array(
117
-                'shortcodes' => array(
118
-                    'organization',
119
-                    'primary_registration_list',
120
-                    'primary_registration_details',
121
-                    'email',
122
-                    'transaction',
123
-                    'event_list',
124
-                    'payment_list',
125
-                    'venue',
126
-                    'line_item_list',
127
-                    'messenger',
128
-                    'ticket_list',
129
-                ),
130
-            ),
131
-            'event_list' => array(
132
-                'shortcodes' => array(
133
-                    'event',
134
-                    'ticket_list',
135
-                    'venue',
136
-                    'primary_registration_details',
137
-                    'primary_registration_list',
138
-                    'event_author',
139
-                ),
140
-                'required' => array('[EVENT_LIST]'),
141
-            ),
142
-            'ticket_list' => array(
143
-                'shortcodes' => array(
144
-                    'attendee_list',
145
-                    'ticket',
146
-                    'datetime_list',
147
-                    'primary_registration_details',
148
-                    'line_item_list',
149
-                    'venue',
150
-                ),
151
-                'required' => array('[TICKET_LIST]'),
152
-            ),
153
-            'ticket_line_item_no_pms' => array(
154
-                'shortcodes' => array('line_item', 'ticket'),
155
-                'required' => array('[TICKET_LINE_ITEM_LIST]'),
156
-            ),
157
-            'ticket_line_item_pms' => array(
158
-                'shortcodes' => array('line_item', 'ticket', 'line_item_list'),
159
-                'required' => array('[TICKET_LINE_ITEM_LIST]'),
160
-            ),
161
-            'price_modifier_line_item_list' => array(
162
-                'shortcodes' => array('line_item'),
163
-                'required' => array('[PRICE_MODIFIER_LINE_ITEM_LIST]'),
164
-            ),
165
-            'datetime_list' => array(
166
-                'shortcodes' => array('datetime'),
167
-                'required' => array('[DATETIME_LIST]'),
168
-            ),
169
-            'attendee_list' => array(
170
-                'shortcodes' => array('attendee'),
171
-                'required' => array('[ATTENDEE_LIST]'),
172
-            ),
173
-            'tax_line_item_list' => array(
174
-                'shortcodes' => array('line_item'),
175
-                'required' => array('[TAX_LINE_ITEM_LIST]'),
176
-            ),
177
-            'additional_line_item_list' => array(
178
-                'shortcodes' => array('line_item'),
179
-                'required' => array('[ADDITIONAL_LINE_ITEM_LIST]'),
180
-            ),
181
-            'payment_list' => array(
182
-                'shortcodes' => array('payment'),
183
-                'required' => array('[PAYMENT_LIST_*]'),
184
-            ),
185
-        );
186
-    }
187
-
188
-
189
-    /**
190
-     * This is a method called from EE_messages when this messenger is a generating messenger and the sending messenger
191
-     * is a different messenger.  Child messengers can set hooks for the sending messenger to callback on if necessary
192
-     * (i.e. swap out css files or something else).
193
-     *
194
-     * @since 4.5.0
195
-     * @param string $sending_messenger_name the name of the sending messenger so we only set the hooks needed.
196
-     * @return void
197
-     */
198
-    public function do_secondary_messenger_hooks($sending_messenger_name)
199
-    {
200
-        if ($sending_messenger_name = 'pdf') {
201
-            add_filter('EE_messenger__get_variation__variation', array($this, 'add_html_css'), 10, 8);
202
-        }
203
-    }
204
-
205
-
206
-    /**
207
-     * @param                            $variation_path
208
-     * @param \EE_Messages_Template_Pack $template_pack
209
-     * @param                            $messenger_name
210
-     * @param                            $message_type_name
211
-     * @param                            $url
212
-     * @param                            $type
213
-     * @param                            $variation
214
-     * @param                            $skip_filters
215
-     * @return string
216
-     */
217
-    public function add_html_css(
218
-        $variation_path,
219
-        EE_Messages_Template_Pack $template_pack,
220
-        $messenger_name,
221
-        $message_type_name,
222
-        $url,
223
-        $type,
224
-        $variation,
225
-        $skip_filters
226
-    )
227
-    {
228
-        $variation = $template_pack->get_variation(
229
-            $this->name,
230
-            $message_type_name,
231
-            $type,
232
-            $variation,
233
-            $url,
234
-            '.css',
235
-            $skip_filters
236
-        );
237
-        return $variation;
238
-    }
239
-
240
-
241
-    /**
242
-     * Takes care of enqueuing any necessary scripts or styles for the page.  A do_action() so message types using this
243
-     * messenger can add their own js.
244
-     *
245
-     * @return void.
246
-     */
247
-    public function enqueue_scripts_styles()
248
-    {
249
-        parent::enqueue_scripts_styles();
250
-        do_action('AHEE__EE_Html_messenger__enqueue_scripts_styles');
251
-    }
252
-
253
-
254
-    /**
255
-     * _set_template_fields
256
-     * This sets up the fields that a messenger requires for the message to go out.
257
-     *
258
-     * @access  protected
259
-     * @return void
260
-     */
261
-    protected function _set_template_fields()
262
-    {
263
-        // any extra template fields that are NOT used by the messenger
264
-        // but will get used by a messenger field for shortcode replacement
265
-        // get added to the 'extra' key in an associated array
266
-        // indexed by the messenger field they relate to.
267
-        // This is important for the Messages_admin to know what fields to display to the user.
268
-        // Also, notice that the "values" are equal to the field type
269
-        // that messages admin will use to know what kind of field to display.
270
-        // The values ALSO have one index labeled "shortcode".
271
-        // The values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE])
272
-        // is required in order for this extra field to be displayed.
273
-        //  If the required shortcode isn't part of the shortcodes array
274
-        // then the field is not needed and will not be displayed/parsed.
275
-        $this->_template_fields = array(
276
-            'subject' => array(
277
-                'input' => 'text',
278
-                'label' => __('Page Title', 'event_espresso'),
279
-                'type' => 'string',
280
-                'required' => true,
281
-                'validation' => true,
282
-                'css_class' => 'large-text',
283
-                'format' => '%s',
284
-            ),
285
-            'content' => '',
286
-            //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
287
-            'extra' => array(
288
-                'content' => array(
289
-                    'main' => array(
290
-                        'input' => 'wp_editor',
291
-                        'label' => __('Main Content', 'event_espresso'),
292
-                        'type' => 'string',
293
-                        'required' => true,
294
-                        'validation' => true,
295
-                        'format' => '%s',
296
-                        'rows' => '15',
297
-                    ),
298
-                    'event_list' => array(
299
-                        'input' => 'wp_editor',
300
-                        'label' => '[EVENT_LIST]',
301
-                        'type' => 'string',
302
-                        'required' => true,
303
-                        'validation' => true,
304
-                        'format' => '%s',
305
-                        'rows' => '15',
306
-                        'shortcodes_required' => array('[EVENT_LIST]'),
307
-                    ),
308
-                    'ticket_list' => array(
309
-                        'input' => 'textarea',
310
-                        'label' => '[TICKET_LIST]',
311
-                        'type' => 'string',
312
-                        'required' => true,
313
-                        'validation' => true,
314
-                        'format' => '%s',
315
-                        'css_class' => 'large-text',
316
-                        'rows' => '10',
317
-                        'shortcodes_required' => array('[TICKET_LIST]'),
318
-                    ),
319
-                    'ticket_line_item_no_pms' => array(
320
-                        'input' => 'textarea',
321
-                        'label' => '[TICKET_LINE_ITEM_LIST] <br>' . __(
322
-                                'Ticket Line Item List with no Price Modifiers',
323
-                                'event_espresso'
324
-                            ),
325
-                        'type' => 'string',
326
-                        'required' => false,
327
-                        'validation' => true,
328
-                        'format' => '%s',
329
-                        'css_class' => 'large-text',
330
-                        'rows' => '5',
331
-                        'shortcodes_required' => array('[TICKET_LINE_ITEM_LIST]'),
332
-                    ),
333
-                    'ticket_line_item_pms' => array(
334
-                        'input' => 'textarea',
335
-                        'label' => '[TICKET_LINE_ITEM_LIST] <br>' . __(
336
-                                'Ticket Line Item List with Price Modifiers',
337
-                                'event_espresso'
338
-                            ),
339
-                        'type' => 'string',
340
-                        'required' => false,
341
-                        'validation' => true,
342
-                        'format' => '%s',
343
-                        'css_class' => 'large-text',
344
-                        'rows' => '5',
345
-                        'shortcodes_required' => array('[TICKET_LINE_ITEM_LIST]'),
346
-                    ),
347
-                    'price_modifier_line_item_list' => array(
348
-                        'input' => 'textarea',
349
-                        'label' => '[PRICE_MODIFIER_LINE_ITEM_LIST]',
350
-                        'type' => 'string',
351
-                        'required' => false,
352
-                        'validation' => true,
353
-                        'format' => '%s',
354
-                        'css_class' => 'large-text',
355
-                        'rows' => '5',
356
-                        'shortcodes_required' => array('[PRICE_MODIFIER_LINE_ITEM_LIST]'),
357
-                    ),
358
-                    'datetime_list' => array(
359
-                        'input' => 'textarea',
360
-                        'label' => '[DATETIME_LIST]',
361
-                        'type' => 'string',
362
-                        'required' => true,
363
-                        'validation' => true,
364
-                        'format' => '%s',
365
-                        'css_class' => 'large-text',
366
-                        'rows' => '5',
367
-                        'shortcodes_required' => array('[DATETIME_LIST]'),
368
-                    ),
369
-                    'attendee_list' => array(
370
-                        'input' => 'textarea',
371
-                        'label' => '[ATTENDEE_LIST]',
372
-                        'type' => 'string',
373
-                        'required' => true,
374
-                        'validation' => true,
375
-                        'format' => '%s',
376
-                        'css_class' => 'large-text',
377
-                        'rows' => '5',
378
-                        'shortcodes_required' => array('[ATTENDEE_LIST]'),
379
-                    ),
380
-                    'tax_line_item_list' => array(
381
-                        'input' => 'textarea',
382
-                        'label' => '[TAX_LINE_ITEM_LIST]',
383
-                        'type' => 'string',
384
-                        'required' => false,
385
-                        'validation' => true,
386
-                        'format' => '%s',
387
-                        'css_class' => 'large-text',
388
-                        'rows' => '5',
389
-                        'shortcodes_required' => array('[TAX_LINE_ITEM_LIST]'),
390
-                    ),
391
-                    'additional_line_item_list' => array(
392
-                        'input' => 'textarea',
393
-                        'label' => '[ADDITIONAL_LINE_ITEM_LIST]',
394
-                        'type' => 'string',
395
-                        'required' => false,
396
-                        'validation' => true,
397
-                        'format' => '%s',
398
-                        'css_class' => 'large-text',
399
-                        'rows' => '5',
400
-                        'shortcodes_required' => array('[ADDITIONAL_LINE_ITEM_LIST]'),
401
-                    ),
402
-                    'payment_list' => array(
403
-                        'input' => 'textarea',
404
-                        'label' => '[PAYMENT_LIST]',
405
-                        'type' => 'string',
406
-                        'required' => true,
407
-                        'validation' => true,
408
-                        'format' => '%s',
409
-                        'css_class' => 'large-text',
410
-                        'rows' => '5',
411
-                        'shortcodes_required' => array('[PAYMENT_LIST_*]'),
412
-                    ),
413
-                ),
414
-            ),
415
-        );
416
-    }
417
-
418
-
419
-    /**
420
-     * @see   definition of this method in parent
421
-     * @since 4.5.0
422
-     */
423
-    protected function _set_default_message_types()
424
-    {
425
-        $this->_default_message_types = array('receipt', 'invoice');
426
-    }
427
-
428
-
429
-    /**
430
-     * @see   definition of this method in parent
431
-     * @since 4.5.0
432
-     */
433
-    protected function _set_valid_message_types()
434
-    {
435
-        $this->_valid_message_types = array('receipt', 'invoice');
436
-    }
437
-
438
-
439
-    /**
440
-     * Displays the message in the browser.
441
-     *
442
-     * @since 4.5.0
443
-     * @return string.
444
-     */
445
-    protected function _send_message()
446
-    {
447
-        $this->_template_args = array(
448
-            'page_title' => $this->_subject,
449
-            'base_css' => $this->get_variation(
450
-                $this->_tmp_pack,
451
-                $this->_incoming_message_type->name,
452
-                true,
453
-                'base',
454
-                $this->_variation
455
-            ),
456
-            'print_css' => $this->get_variation(
457
-                $this->_tmp_pack,
458
-                $this->_incoming_message_type->name,
459
-                true,
460
-                'print',
461
-                $this->_variation
462
-            ),
463
-            'main_css' => $this->get_variation(
464
-                $this->_tmp_pack,
465
-                $this->_incoming_message_type->name,
466
-                true,
467
-                'main',
468
-                $this->_variation
469
-            ),
470
-            'main_body' => wpautop(
471
-                apply_filters(
472
-                    'FHEE__EE_Html_messenger___send_message__main_body',
473
-                    $this->_content,
474
-                    $this->_content,
475
-                    $this->_incoming_message_type
476
-                )
477
-            )
478
-        );
479
-        $this->_deregister_wp_hooks();
480
-        add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts_styles'));
481
-        echo $this->_get_main_template();
482
-        exit();
483
-    }
484
-
485
-
486
-    /**
487
-     * The purpose of this function is to de register all actions hooked into wp_head and wp_footer so that it doesn't
488
-     * interfere with our templates.  If users want to add any custom styles or scripts they must use the
489
-     * AHEE__EE_Html_messenger__enqueue_scripts_styles hook.
490
-     *
491
-     * @since 4.5.0
492
-     * @return void
493
-     */
494
-    protected function _deregister_wp_hooks()
495
-    {
496
-        remove_all_actions('wp_head');
497
-        remove_all_actions('wp_footer');
498
-        remove_all_actions('wp_print_footer_scripts');
499
-        remove_all_actions('wp_enqueue_scripts');
500
-        global $wp_scripts, $wp_styles;
501
-        $wp_scripts = $wp_styles = array();
502
-        //just add back in wp_enqueue_scripts and wp_print_footer_scripts cause that's all we want to load.
503
-        add_action('wp_footer', 'wp_print_footer_scripts');
504
-        add_action('wp_print_footer_scripts', '_wp_footer_scripts');
505
-        add_action('wp_head', 'wp_enqueue_scripts');
506
-    }
507
-
508
-
509
-    /**
510
-     * Overwrite parent _get_main_template for display_html purposes.
511
-     *
512
-     * @since  4.5.0
513
-     * @param bool $preview
514
-     * @return string
515
-     */
516
-    protected function _get_main_template($preview = false)
517
-    {
518
-        $wrapper_template = $this->_tmp_pack->get_wrapper($this->name, 'main');
519
-        //include message type as a template arg
520
-        $this->_template_args['message_type'] = $this->_incoming_message_type;
521
-        return EEH_Template::display_template($wrapper_template, $this->_template_args, true);
522
-    }
523
-
524
-
525
-    /**
526
-     * @return string
527
-     */
528
-    protected function _preview()
529
-    {
530
-        return $this->_send_message();
531
-    }
532
-
533
-
534
-    protected function _set_admin_settings_fields()
535
-    {
536
-    }
537
-
538
-
539
-    /**
540
-     * add the "powered by EE" credit link to the HTML receipt and invoice
541
-     *
542
-     * @param string $content
543
-     * @param string $content_again
544
-     * @param \EE_message_type $incoming_message_type
545
-     * @return string
546
-     */
547
-    public function add_powered_by_credit_link_to_receipt_and_invoice(
548
-        $content = '',
549
-        $content_again = '',
550
-        EE_message_type $incoming_message_type
551
-    )
552
-    {
553
-        if (
554
-            ($incoming_message_type->name === 'invoice' || $incoming_message_type->name === 'receipt')
555
-            && apply_filters('FHEE_EE_Html_messenger__add_powered_by_credit_link_to_receipt_and_invoice', true)
556
-        ) {
557
-            $content .= \EEH_Template::powered_by_event_espresso(
558
-                    'aln-cntr',
559
-                    '',
560
-                    array('utm_content' => 'messages_system')
561
-                )
562
-                . EEH_HTML::div(EEH_HTML::p('&nbsp;'));
563
-        }
564
-        return $content;
565
-    }
19
+	/**
20
+	 * The following are the properties that this messenger requires for displaying the html
21
+	 */
22
+	/**
23
+	 * This is the html body generated by the template via the message type.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $_content;
28
+
29
+
30
+	/**
31
+	 * This is for the page title that gets displayed.  (Why use "subject"?  Because the "title" tag in html is
32
+	 * equivalent to the "subject" of the page.
33
+	 *
34
+	 * @var string
35
+	 */
36
+	protected $_subject;
37
+
38
+
39
+	/**
40
+	 * EE_Html_messenger constructor.
41
+	 */
42
+	public function __construct()
43
+	{
44
+		//set properties
45
+		$this->name = 'html';
46
+		$this->description = __('This messenger outputs a message to a browser for display.', 'event_espresso');
47
+		$this->label = array(
48
+			'singular' => __('html', 'event_espresso'),
49
+			'plural' => __('html', 'event_espresso'),
50
+		);
51
+		$this->activate_on_install = true;
52
+		// add the "powered by EE" credit link to the HTML receipt and invoice
53
+		add_filter(
54
+			'FHEE__EE_Html_messenger___send_message__main_body',
55
+			array($this, 'add_powered_by_credit_link_to_receipt_and_invoice'),
56
+			10,
57
+			3
58
+		);
59
+		parent::__construct();
60
+	}
61
+
62
+
63
+	/**
64
+	 * HTML Messenger desires execution immediately.
65
+	 *
66
+	 * @see    parent::send_now() for documentation.
67
+	 * @since  4.9.0
68
+	 * @return bool
69
+	 */
70
+	public function send_now()
71
+	{
72
+		return true;
73
+	}
74
+
75
+
76
+	/**
77
+	 * HTML Messenger allows an empty to field.
78
+	 *
79
+	 * @see    parent::allow_empty_to_field() for documentation
80
+	 * @since  4.9.0
81
+	 * @return bool
82
+	 */
83
+	public function allow_empty_to_field()
84
+	{
85
+		return true;
86
+	}
87
+
88
+
89
+	/**
90
+	 * @see abstract declaration in EE_messenger for details.
91
+	 */
92
+	protected function _set_admin_pages()
93
+	{
94
+		$this->admin_registered_pages = array('events_edit' => true);
95
+	}
96
+
97
+
98
+	/**
99
+	 * @see abstract declaration in EE_messenger for details.
100
+	 */
101
+	protected function _set_valid_shortcodes()
102
+	{
103
+		$this->_valid_shortcodes = array();
104
+	}
105
+
106
+
107
+	/**
108
+	 * @see abstract declaration in EE_messenger for details.
109
+	 */
110
+	protected function _set_validator_config()
111
+	{
112
+		$this->_validator_config = array(
113
+			'subject' => array(
114
+				'shortcodes' => array('organization', 'primary_registration_details', 'email', 'transaction'),
115
+			),
116
+			'content' => array(
117
+				'shortcodes' => array(
118
+					'organization',
119
+					'primary_registration_list',
120
+					'primary_registration_details',
121
+					'email',
122
+					'transaction',
123
+					'event_list',
124
+					'payment_list',
125
+					'venue',
126
+					'line_item_list',
127
+					'messenger',
128
+					'ticket_list',
129
+				),
130
+			),
131
+			'event_list' => array(
132
+				'shortcodes' => array(
133
+					'event',
134
+					'ticket_list',
135
+					'venue',
136
+					'primary_registration_details',
137
+					'primary_registration_list',
138
+					'event_author',
139
+				),
140
+				'required' => array('[EVENT_LIST]'),
141
+			),
142
+			'ticket_list' => array(
143
+				'shortcodes' => array(
144
+					'attendee_list',
145
+					'ticket',
146
+					'datetime_list',
147
+					'primary_registration_details',
148
+					'line_item_list',
149
+					'venue',
150
+				),
151
+				'required' => array('[TICKET_LIST]'),
152
+			),
153
+			'ticket_line_item_no_pms' => array(
154
+				'shortcodes' => array('line_item', 'ticket'),
155
+				'required' => array('[TICKET_LINE_ITEM_LIST]'),
156
+			),
157
+			'ticket_line_item_pms' => array(
158
+				'shortcodes' => array('line_item', 'ticket', 'line_item_list'),
159
+				'required' => array('[TICKET_LINE_ITEM_LIST]'),
160
+			),
161
+			'price_modifier_line_item_list' => array(
162
+				'shortcodes' => array('line_item'),
163
+				'required' => array('[PRICE_MODIFIER_LINE_ITEM_LIST]'),
164
+			),
165
+			'datetime_list' => array(
166
+				'shortcodes' => array('datetime'),
167
+				'required' => array('[DATETIME_LIST]'),
168
+			),
169
+			'attendee_list' => array(
170
+				'shortcodes' => array('attendee'),
171
+				'required' => array('[ATTENDEE_LIST]'),
172
+			),
173
+			'tax_line_item_list' => array(
174
+				'shortcodes' => array('line_item'),
175
+				'required' => array('[TAX_LINE_ITEM_LIST]'),
176
+			),
177
+			'additional_line_item_list' => array(
178
+				'shortcodes' => array('line_item'),
179
+				'required' => array('[ADDITIONAL_LINE_ITEM_LIST]'),
180
+			),
181
+			'payment_list' => array(
182
+				'shortcodes' => array('payment'),
183
+				'required' => array('[PAYMENT_LIST_*]'),
184
+			),
185
+		);
186
+	}
187
+
188
+
189
+	/**
190
+	 * This is a method called from EE_messages when this messenger is a generating messenger and the sending messenger
191
+	 * is a different messenger.  Child messengers can set hooks for the sending messenger to callback on if necessary
192
+	 * (i.e. swap out css files or something else).
193
+	 *
194
+	 * @since 4.5.0
195
+	 * @param string $sending_messenger_name the name of the sending messenger so we only set the hooks needed.
196
+	 * @return void
197
+	 */
198
+	public function do_secondary_messenger_hooks($sending_messenger_name)
199
+	{
200
+		if ($sending_messenger_name = 'pdf') {
201
+			add_filter('EE_messenger__get_variation__variation', array($this, 'add_html_css'), 10, 8);
202
+		}
203
+	}
204
+
205
+
206
+	/**
207
+	 * @param                            $variation_path
208
+	 * @param \EE_Messages_Template_Pack $template_pack
209
+	 * @param                            $messenger_name
210
+	 * @param                            $message_type_name
211
+	 * @param                            $url
212
+	 * @param                            $type
213
+	 * @param                            $variation
214
+	 * @param                            $skip_filters
215
+	 * @return string
216
+	 */
217
+	public function add_html_css(
218
+		$variation_path,
219
+		EE_Messages_Template_Pack $template_pack,
220
+		$messenger_name,
221
+		$message_type_name,
222
+		$url,
223
+		$type,
224
+		$variation,
225
+		$skip_filters
226
+	)
227
+	{
228
+		$variation = $template_pack->get_variation(
229
+			$this->name,
230
+			$message_type_name,
231
+			$type,
232
+			$variation,
233
+			$url,
234
+			'.css',
235
+			$skip_filters
236
+		);
237
+		return $variation;
238
+	}
239
+
240
+
241
+	/**
242
+	 * Takes care of enqueuing any necessary scripts or styles for the page.  A do_action() so message types using this
243
+	 * messenger can add their own js.
244
+	 *
245
+	 * @return void.
246
+	 */
247
+	public function enqueue_scripts_styles()
248
+	{
249
+		parent::enqueue_scripts_styles();
250
+		do_action('AHEE__EE_Html_messenger__enqueue_scripts_styles');
251
+	}
252
+
253
+
254
+	/**
255
+	 * _set_template_fields
256
+	 * This sets up the fields that a messenger requires for the message to go out.
257
+	 *
258
+	 * @access  protected
259
+	 * @return void
260
+	 */
261
+	protected function _set_template_fields()
262
+	{
263
+		// any extra template fields that are NOT used by the messenger
264
+		// but will get used by a messenger field for shortcode replacement
265
+		// get added to the 'extra' key in an associated array
266
+		// indexed by the messenger field they relate to.
267
+		// This is important for the Messages_admin to know what fields to display to the user.
268
+		// Also, notice that the "values" are equal to the field type
269
+		// that messages admin will use to know what kind of field to display.
270
+		// The values ALSO have one index labeled "shortcode".
271
+		// The values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE])
272
+		// is required in order for this extra field to be displayed.
273
+		//  If the required shortcode isn't part of the shortcodes array
274
+		// then the field is not needed and will not be displayed/parsed.
275
+		$this->_template_fields = array(
276
+			'subject' => array(
277
+				'input' => 'text',
278
+				'label' => __('Page Title', 'event_espresso'),
279
+				'type' => 'string',
280
+				'required' => true,
281
+				'validation' => true,
282
+				'css_class' => 'large-text',
283
+				'format' => '%s',
284
+			),
285
+			'content' => '',
286
+			//left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
287
+			'extra' => array(
288
+				'content' => array(
289
+					'main' => array(
290
+						'input' => 'wp_editor',
291
+						'label' => __('Main Content', 'event_espresso'),
292
+						'type' => 'string',
293
+						'required' => true,
294
+						'validation' => true,
295
+						'format' => '%s',
296
+						'rows' => '15',
297
+					),
298
+					'event_list' => array(
299
+						'input' => 'wp_editor',
300
+						'label' => '[EVENT_LIST]',
301
+						'type' => 'string',
302
+						'required' => true,
303
+						'validation' => true,
304
+						'format' => '%s',
305
+						'rows' => '15',
306
+						'shortcodes_required' => array('[EVENT_LIST]'),
307
+					),
308
+					'ticket_list' => array(
309
+						'input' => 'textarea',
310
+						'label' => '[TICKET_LIST]',
311
+						'type' => 'string',
312
+						'required' => true,
313
+						'validation' => true,
314
+						'format' => '%s',
315
+						'css_class' => 'large-text',
316
+						'rows' => '10',
317
+						'shortcodes_required' => array('[TICKET_LIST]'),
318
+					),
319
+					'ticket_line_item_no_pms' => array(
320
+						'input' => 'textarea',
321
+						'label' => '[TICKET_LINE_ITEM_LIST] <br>' . __(
322
+								'Ticket Line Item List with no Price Modifiers',
323
+								'event_espresso'
324
+							),
325
+						'type' => 'string',
326
+						'required' => false,
327
+						'validation' => true,
328
+						'format' => '%s',
329
+						'css_class' => 'large-text',
330
+						'rows' => '5',
331
+						'shortcodes_required' => array('[TICKET_LINE_ITEM_LIST]'),
332
+					),
333
+					'ticket_line_item_pms' => array(
334
+						'input' => 'textarea',
335
+						'label' => '[TICKET_LINE_ITEM_LIST] <br>' . __(
336
+								'Ticket Line Item List with Price Modifiers',
337
+								'event_espresso'
338
+							),
339
+						'type' => 'string',
340
+						'required' => false,
341
+						'validation' => true,
342
+						'format' => '%s',
343
+						'css_class' => 'large-text',
344
+						'rows' => '5',
345
+						'shortcodes_required' => array('[TICKET_LINE_ITEM_LIST]'),
346
+					),
347
+					'price_modifier_line_item_list' => array(
348
+						'input' => 'textarea',
349
+						'label' => '[PRICE_MODIFIER_LINE_ITEM_LIST]',
350
+						'type' => 'string',
351
+						'required' => false,
352
+						'validation' => true,
353
+						'format' => '%s',
354
+						'css_class' => 'large-text',
355
+						'rows' => '5',
356
+						'shortcodes_required' => array('[PRICE_MODIFIER_LINE_ITEM_LIST]'),
357
+					),
358
+					'datetime_list' => array(
359
+						'input' => 'textarea',
360
+						'label' => '[DATETIME_LIST]',
361
+						'type' => 'string',
362
+						'required' => true,
363
+						'validation' => true,
364
+						'format' => '%s',
365
+						'css_class' => 'large-text',
366
+						'rows' => '5',
367
+						'shortcodes_required' => array('[DATETIME_LIST]'),
368
+					),
369
+					'attendee_list' => array(
370
+						'input' => 'textarea',
371
+						'label' => '[ATTENDEE_LIST]',
372
+						'type' => 'string',
373
+						'required' => true,
374
+						'validation' => true,
375
+						'format' => '%s',
376
+						'css_class' => 'large-text',
377
+						'rows' => '5',
378
+						'shortcodes_required' => array('[ATTENDEE_LIST]'),
379
+					),
380
+					'tax_line_item_list' => array(
381
+						'input' => 'textarea',
382
+						'label' => '[TAX_LINE_ITEM_LIST]',
383
+						'type' => 'string',
384
+						'required' => false,
385
+						'validation' => true,
386
+						'format' => '%s',
387
+						'css_class' => 'large-text',
388
+						'rows' => '5',
389
+						'shortcodes_required' => array('[TAX_LINE_ITEM_LIST]'),
390
+					),
391
+					'additional_line_item_list' => array(
392
+						'input' => 'textarea',
393
+						'label' => '[ADDITIONAL_LINE_ITEM_LIST]',
394
+						'type' => 'string',
395
+						'required' => false,
396
+						'validation' => true,
397
+						'format' => '%s',
398
+						'css_class' => 'large-text',
399
+						'rows' => '5',
400
+						'shortcodes_required' => array('[ADDITIONAL_LINE_ITEM_LIST]'),
401
+					),
402
+					'payment_list' => array(
403
+						'input' => 'textarea',
404
+						'label' => '[PAYMENT_LIST]',
405
+						'type' => 'string',
406
+						'required' => true,
407
+						'validation' => true,
408
+						'format' => '%s',
409
+						'css_class' => 'large-text',
410
+						'rows' => '5',
411
+						'shortcodes_required' => array('[PAYMENT_LIST_*]'),
412
+					),
413
+				),
414
+			),
415
+		);
416
+	}
417
+
418
+
419
+	/**
420
+	 * @see   definition of this method in parent
421
+	 * @since 4.5.0
422
+	 */
423
+	protected function _set_default_message_types()
424
+	{
425
+		$this->_default_message_types = array('receipt', 'invoice');
426
+	}
427
+
428
+
429
+	/**
430
+	 * @see   definition of this method in parent
431
+	 * @since 4.5.0
432
+	 */
433
+	protected function _set_valid_message_types()
434
+	{
435
+		$this->_valid_message_types = array('receipt', 'invoice');
436
+	}
437
+
438
+
439
+	/**
440
+	 * Displays the message in the browser.
441
+	 *
442
+	 * @since 4.5.0
443
+	 * @return string.
444
+	 */
445
+	protected function _send_message()
446
+	{
447
+		$this->_template_args = array(
448
+			'page_title' => $this->_subject,
449
+			'base_css' => $this->get_variation(
450
+				$this->_tmp_pack,
451
+				$this->_incoming_message_type->name,
452
+				true,
453
+				'base',
454
+				$this->_variation
455
+			),
456
+			'print_css' => $this->get_variation(
457
+				$this->_tmp_pack,
458
+				$this->_incoming_message_type->name,
459
+				true,
460
+				'print',
461
+				$this->_variation
462
+			),
463
+			'main_css' => $this->get_variation(
464
+				$this->_tmp_pack,
465
+				$this->_incoming_message_type->name,
466
+				true,
467
+				'main',
468
+				$this->_variation
469
+			),
470
+			'main_body' => wpautop(
471
+				apply_filters(
472
+					'FHEE__EE_Html_messenger___send_message__main_body',
473
+					$this->_content,
474
+					$this->_content,
475
+					$this->_incoming_message_type
476
+				)
477
+			)
478
+		);
479
+		$this->_deregister_wp_hooks();
480
+		add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts_styles'));
481
+		echo $this->_get_main_template();
482
+		exit();
483
+	}
484
+
485
+
486
+	/**
487
+	 * The purpose of this function is to de register all actions hooked into wp_head and wp_footer so that it doesn't
488
+	 * interfere with our templates.  If users want to add any custom styles or scripts they must use the
489
+	 * AHEE__EE_Html_messenger__enqueue_scripts_styles hook.
490
+	 *
491
+	 * @since 4.5.0
492
+	 * @return void
493
+	 */
494
+	protected function _deregister_wp_hooks()
495
+	{
496
+		remove_all_actions('wp_head');
497
+		remove_all_actions('wp_footer');
498
+		remove_all_actions('wp_print_footer_scripts');
499
+		remove_all_actions('wp_enqueue_scripts');
500
+		global $wp_scripts, $wp_styles;
501
+		$wp_scripts = $wp_styles = array();
502
+		//just add back in wp_enqueue_scripts and wp_print_footer_scripts cause that's all we want to load.
503
+		add_action('wp_footer', 'wp_print_footer_scripts');
504
+		add_action('wp_print_footer_scripts', '_wp_footer_scripts');
505
+		add_action('wp_head', 'wp_enqueue_scripts');
506
+	}
507
+
508
+
509
+	/**
510
+	 * Overwrite parent _get_main_template for display_html purposes.
511
+	 *
512
+	 * @since  4.5.0
513
+	 * @param bool $preview
514
+	 * @return string
515
+	 */
516
+	protected function _get_main_template($preview = false)
517
+	{
518
+		$wrapper_template = $this->_tmp_pack->get_wrapper($this->name, 'main');
519
+		//include message type as a template arg
520
+		$this->_template_args['message_type'] = $this->_incoming_message_type;
521
+		return EEH_Template::display_template($wrapper_template, $this->_template_args, true);
522
+	}
523
+
524
+
525
+	/**
526
+	 * @return string
527
+	 */
528
+	protected function _preview()
529
+	{
530
+		return $this->_send_message();
531
+	}
532
+
533
+
534
+	protected function _set_admin_settings_fields()
535
+	{
536
+	}
537
+
538
+
539
+	/**
540
+	 * add the "powered by EE" credit link to the HTML receipt and invoice
541
+	 *
542
+	 * @param string $content
543
+	 * @param string $content_again
544
+	 * @param \EE_message_type $incoming_message_type
545
+	 * @return string
546
+	 */
547
+	public function add_powered_by_credit_link_to_receipt_and_invoice(
548
+		$content = '',
549
+		$content_again = '',
550
+		EE_message_type $incoming_message_type
551
+	)
552
+	{
553
+		if (
554
+			($incoming_message_type->name === 'invoice' || $incoming_message_type->name === 'receipt')
555
+			&& apply_filters('FHEE_EE_Html_messenger__add_powered_by_credit_link_to_receipt_and_invoice', true)
556
+		) {
557
+			$content .= \EEH_Template::powered_by_event_espresso(
558
+					'aln-cntr',
559
+					'',
560
+					array('utm_content' => 'messages_system')
561
+				)
562
+				. EEH_HTML::div(EEH_HTML::p('&nbsp;'));
563
+		}
564
+		return $content;
565
+	}
566 566
 
567 567
 }
Please login to merge, or discard this patch.
core/libraries/messages/messenger/EE_Email_messenger.class.php 2 patches
Indentation   +637 added lines, -637 removed lines patch added patch discarded remove patch
@@ -8,641 +8,641 @@
 block discarded – undo
8 8
 class EE_Email_messenger extends EE_messenger
9 9
 {
10 10
 
11
-    /**
12
-     * To field for email
13
-     * @var string
14
-     */
15
-    protected $_to = '';
16
-
17
-
18
-    /**
19
-     * CC field for email.
20
-     * @var string
21
-     */
22
-    protected $_cc = '';
23
-
24
-    /**
25
-     * From field for email
26
-     * @var string
27
-     */
28
-    protected $_from = '';
29
-
30
-
31
-    /**
32
-     * Subject field for email
33
-     * @var string
34
-     */
35
-    protected $_subject = '';
36
-
37
-
38
-    /**
39
-     * Content field for email
40
-     * @var string
41
-     */
42
-    protected $_content = '';
43
-
44
-
45
-    /**
46
-     * constructor
47
-     *
48
-     * @access public
49
-     */
50
-    public function __construct()
51
-    {
52
-        //set name and description properties
53
-        $this->name                = 'email';
54
-        $this->description         = sprintf(
55
-            esc_html__(
56
-                'This messenger delivers messages via email using the built-in %s function included with WordPress',
57
-                'event_espresso'
58
-            ),
59
-            '<code>wp_mail</code>'
60
-        );
61
-        $this->label               = array(
62
-            'singular' => esc_html__('email', 'event_espresso'),
63
-            'plural'   => esc_html__('emails', 'event_espresso'),
64
-        );
65
-        $this->activate_on_install = true;
66
-
67
-        //we're using defaults so let's call parent constructor that will take care of setting up all the other
68
-        // properties
69
-        parent::__construct();
70
-    }
71
-
72
-
73
-    /**
74
-     * see abstract declaration in parent class for details.
75
-     */
76
-    protected function _set_admin_pages()
77
-    {
78
-        $this->admin_registered_pages = array(
79
-            'events_edit' => true,
80
-        );
81
-    }
82
-
83
-
84
-    /**
85
-     * see abstract declaration in parent class for details
86
-     */
87
-    protected function _set_valid_shortcodes()
88
-    {
89
-        //remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
90
-        // message type.
91
-        $this->_valid_shortcodes = array(
92
-            'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
93
-            'cc' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
94
-            'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
95
-        );
96
-    }
97
-
98
-
99
-    /**
100
-     * see abstract declaration in parent class for details
101
-     *
102
-     * @access protected
103
-     * @return void
104
-     */
105
-    protected function _set_validator_config()
106
-    {
107
-        $valid_shortcodes = $this->get_valid_shortcodes();
108
-
109
-        $this->_validator_config = array(
110
-            'to'            => array(
111
-                'shortcodes' => $valid_shortcodes['to'],
112
-                'type'       => 'email',
113
-            ),
114
-            'cc' => array(
115
-                'shortcodes' => $valid_shortcodes['to'],
116
-                'type' => 'email',
117
-            ),
118
-            'from'          => array(
119
-                'shortcodes' => $valid_shortcodes['from'],
120
-                'type'       => 'email',
121
-            ),
122
-            'subject'       => array(
123
-                'shortcodes' => array(
124
-                    'organization',
125
-                    'primary_registration_details',
126
-                    'event_author',
127
-                    'primary_registration_details',
128
-                    'recipient_details',
129
-                ),
130
-            ),
131
-            'content'       => array(
132
-                'shortcodes' => array(
133
-                    'event_list',
134
-                    'attendee_list',
135
-                    'ticket_list',
136
-                    'organization',
137
-                    'primary_registration_details',
138
-                    'primary_registration_list',
139
-                    'event_author',
140
-                    'recipient_details',
141
-                    'recipient_list',
142
-                    'transaction',
143
-                    'messenger',
144
-                ),
145
-            ),
146
-            'attendee_list' => array(
147
-                'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
148
-                'required'   => array('[ATTENDEE_LIST]'),
149
-            ),
150
-            'event_list'    => array(
151
-                'shortcodes' => array(
152
-                    'event',
153
-                    'attendee_list',
154
-                    'ticket_list',
155
-                    'venue',
156
-                    'datetime_list',
157
-                    'attendee',
158
-                    'primary_registration_details',
159
-                    'primary_registration_list',
160
-                    'event_author',
161
-                    'recipient_details',
162
-                    'recipient_list',
163
-                ),
164
-                'required'   => array('[EVENT_LIST]'),
165
-            ),
166
-            'ticket_list'   => array(
167
-                'shortcodes' => array(
168
-                    'event_list',
169
-                    'attendee_list',
170
-                    'ticket',
171
-                    'datetime_list',
172
-                    'primary_registration_details',
173
-                    'recipient_details',
174
-                ),
175
-                'required'   => array('[TICKET_LIST]'),
176
-            ),
177
-            'datetime_list' => array(
178
-                'shortcodes' => array('datetime'),
179
-                'required'   => array('[DATETIME_LIST]'),
180
-            ),
181
-        );
182
-    }
183
-
184
-
185
-    /**
186
-     * @see   parent EE_messenger class for docs
187
-     * @since 4.5.0
188
-     */
189
-    public function do_secondary_messenger_hooks($sending_messenger_name)
190
-    {
191
-        if ($sending_messenger_name = 'html') {
192
-            add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
193
-        }
194
-    }
195
-
196
-
197
-    public function add_email_css(
198
-        $variation_path,
199
-        $messenger,
200
-        $message_type,
201
-        $type,
202
-        $variation,
203
-        $file_extension,
204
-        $url,
205
-        EE_Messages_Template_Pack $template_pack
206
-    ) {
207
-        //prevent recursion on this callback.
208
-        remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
209
-        $variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
210
-
211
-        add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
212
-        return $variation;
213
-    }
214
-
215
-
216
-    /**
217
-     * See parent for details
218
-     *
219
-     * @access protected
220
-     * @return void
221
-     */
222
-    protected function _set_test_settings_fields()
223
-    {
224
-        $this->_test_settings_fields = array(
225
-            'to'      => array(
226
-                'input'      => 'text',
227
-                'label'      => esc_html__('Send a test email to', 'event_espresso'),
228
-                'type'       => 'email',
229
-                'required'   => true,
230
-                'validation' => true,
231
-                'css_class'  => 'large-text',
232
-                'format'     => '%s',
233
-                'default'    => get_bloginfo('admin_email'),
234
-            ),
235
-            'subject' => array(
236
-                'input'      => 'hidden',
237
-                'label'      => '',
238
-                'type'       => 'string',
239
-                'required'   => false,
240
-                'validation' => false,
241
-                'format'     => '%s',
242
-                'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
243
-                'default'    => '',
244
-                'css_class'  => '',
245
-            ),
246
-        );
247
-    }
248
-
249
-
250
-    /**
251
-     * _set_template_fields
252
-     * This sets up the fields that a messenger requires for the message to go out.
253
-     *
254
-     * @access  protected
255
-     * @return void
256
-     */
257
-    protected function _set_template_fields()
258
-    {
259
-        // any extra template fields that are NOT used by the messenger but will get used by a messenger field for
260
-        // shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
261
-        // they relate to.  This is important for the Messages_admin to know what fields to display to the user.
262
-        //  Also, notice that the "values" are equal to the field type that messages admin will use to know what
263
-        // kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
264
-        // indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
265
-        // displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
266
-        // will not be displayed/parsed.
267
-        $this->_template_fields = array(
268
-            'to'      => array(
269
-                'input'      => 'text',
270
-                'label'      => esc_html_x(
271
-                    'To',
272
-                    'Label for the "To" field for email addresses',
273
-                    'event_espresso'
274
-                ),
275
-                'type'       => 'string',
276
-                'required'   => true,
277
-                'validation' => true,
278
-                'css_class'  => 'large-text',
279
-                'format'     => '%s',
280
-            ),
281
-            'cc'      => array(
282
-                'input'      => 'text',
283
-                'label'      => esc_html_x(
284
-                    'CC',
285
-                    'Label for the "Carbon Copy" field used for additional email addresses',
286
-                    'event_espresso'
287
-                ),
288
-                'type'       => 'string',
289
-                'required'   => false,
290
-                'validation' => true,
291
-                'css_class'  => 'large-text',
292
-                'format'     => '%s',
293
-            ),
294
-            'from'    => array(
295
-                'input'      => 'text',
296
-                'label'      => esc_html_x(
297
-                    'From',
298
-                    'Label for the "From" field for email addresses.',
299
-                    'event_espresso'
300
-                ),
301
-                'type'       => 'string',
302
-                'required'   => true,
303
-                'validation' => true,
304
-                'css_class'  => 'large-text',
305
-                'format'     => '%s',
306
-            ),
307
-            'subject' => array(
308
-                'input'      => 'text',
309
-                'label'      => esc_html_x(
310
-                    'Subject',
311
-                    'Label for the "Subject" field (short description of contents) for emails.',
312
-                    'event_espresso'
313
-                ),
314
-                'type'       => 'string',
315
-                'required'   => true,
316
-                'validation' => true,
317
-                'css_class'  => 'large-text',
318
-                'format'     => '%s',
319
-            ),
320
-            'content' => '',
321
-            //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
322
-            'extra'   => array(
323
-                'content' => array(
324
-                    'main'          => array(
325
-                        'input'      => 'wp_editor',
326
-                        'label'      => esc_html__('Main Content', 'event_espresso'),
327
-                        'type'       => 'string',
328
-                        'required'   => true,
329
-                        'validation' => true,
330
-                        'format'     => '%s',
331
-                        'rows'       => '15',
332
-                    ),
333
-                    'event_list'    => array(
334
-                        'input'               => 'wp_editor',
335
-                        'label'               => '[EVENT_LIST]',
336
-                        'type'                => 'string',
337
-                        'required'            => true,
338
-                        'validation'          => true,
339
-                        'format'              => '%s',
340
-                        'rows'                => '15',
341
-                        'shortcodes_required' => array('[EVENT_LIST]'),
342
-                    ),
343
-                    'attendee_list' => array(
344
-                        'input'               => 'textarea',
345
-                        'label'               => '[ATTENDEE_LIST]',
346
-                        'type'                => 'string',
347
-                        'required'            => true,
348
-                        'validation'          => true,
349
-                        'format'              => '%s',
350
-                        'css_class'           => 'large-text',
351
-                        'rows'                => '5',
352
-                        'shortcodes_required' => array('[ATTENDEE_LIST]'),
353
-                    ),
354
-                    'ticket_list'   => array(
355
-                        'input'               => 'textarea',
356
-                        'label'               => '[TICKET_LIST]',
357
-                        'type'                => 'string',
358
-                        'required'            => true,
359
-                        'validation'          => true,
360
-                        'format'              => '%s',
361
-                        'css_class'           => 'large-text',
362
-                        'rows'                => '10',
363
-                        'shortcodes_required' => array('[TICKET_LIST]'),
364
-                    ),
365
-                    'datetime_list' => array(
366
-                        'input'               => 'textarea',
367
-                        'label'               => '[DATETIME_LIST]',
368
-                        'type'                => 'string',
369
-                        'required'            => true,
370
-                        'validation'          => true,
371
-                        'format'              => '%s',
372
-                        'css_class'           => 'large-text',
373
-                        'rows'                => '10',
374
-                        'shortcodes_required' => array('[DATETIME_LIST]'),
375
-                    ),
376
-                ),
377
-            ),
378
-        );
379
-    }
380
-
381
-
382
-    /**
383
-     * See definition of this class in parent
384
-     */
385
-    protected function _set_default_message_types()
386
-    {
387
-        $this->_default_message_types = array(
388
-            'payment',
389
-            'payment_refund',
390
-            'registration',
391
-            'not_approved_registration',
392
-            'pending_approval',
393
-        );
394
-    }
395
-
396
-
397
-    /**
398
-     * @see   definition of this class in parent
399
-     * @since 4.5.0
400
-     */
401
-    protected function _set_valid_message_types()
402
-    {
403
-        $this->_valid_message_types = array(
404
-            'payment',
405
-            'registration',
406
-            'not_approved_registration',
407
-            'declined_registration',
408
-            'cancelled_registration',
409
-            'pending_approval',
410
-            'registration_summary',
411
-            'payment_reminder',
412
-            'payment_declined',
413
-            'payment_refund',
414
-        );
415
-    }
416
-
417
-
418
-    /**
419
-     * setting up admin_settings_fields for messenger.
420
-     */
421
-    protected function _set_admin_settings_fields()
422
-    {
423
-    }
424
-
425
-    /**
426
-     * We just deliver the messages don't kill us!!
427
-     *
428
-     * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
429
-     *              present.
430
-     * @throws EE_Error
431
-     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
432
-     */
433
-    protected function _send_message()
434
-    {
435
-        $success = wp_mail(
436
-            $this->_to,
437
-            $this->_subject,
438
-            $this->_body(),
439
-            $this->_headers()
440
-        );
441
-        if (! $success) {
442
-            EE_Error::add_error(
443
-                sprintf(
444
-                    esc_html__(
445
-                        'The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
446
-                        'event_espresso'
447
-                    ),
448
-                    $this->_to,
449
-                    $this->_from,
450
-                    '<br />'
451
-                ),
452
-                __FILE__,
453
-                __FUNCTION__,
454
-                __LINE__
455
-            );
456
-        }
457
-        return $success;
458
-    }
459
-
460
-
461
-    /**
462
-     * see parent for definition
463
-     *
464
-     * @return string html body of the message content and the related css.
465
-     * @throws EE_Error
466
-     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
467
-     */
468
-    protected function _preview()
469
-    {
470
-        return $this->_body(true);
471
-    }
472
-
473
-
474
-    /**
475
-     * Setup headers for email
476
-     *
477
-     * @access protected
478
-     * @return string formatted header for email
479
-     */
480
-    protected function _headers()
481
-    {
482
-        $this->_ensure_has_from_email_address();
483
-        $from    = $this->_from;
484
-        $headers = array(
485
-            'From:' . $from,
486
-            'Reply-To:' . $from,
487
-            'Content-Type:text/html; charset=utf-8',
488
-        );
489
-
490
-        if (! empty($this->_cc)) {
491
-            $headers[] = 'cc: ' . $this->_cc;
492
-        }
493
-
494
-        //but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
495
-        // header.
496
-        add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
497
-        add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
498
-        return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
499
-    }
500
-
501
-
502
-    /**
503
-     * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
504
-     * address for the from address to avoid problems with sending emails.
505
-     */
506
-    protected function _ensure_has_from_email_address()
507
-    {
508
-        if (empty($this->_from)) {
509
-            $this->_from = get_bloginfo('admin_email');
510
-        }
511
-    }
512
-
513
-
514
-    /**
515
-     * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
516
-     * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
517
-     * be empty
518
-     *
519
-     * @since 4.3.1
520
-     * @return array
521
-     */
522
-    private function _parse_from()
523
-    {
524
-        if (strpos($this->_from, '<') !== false) {
525
-            $from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
526
-            $from_name = str_replace('"', '', $from_name);
527
-            $from_name = trim($from_name);
528
-
529
-            $from_email = substr($this->_from, strpos($this->_from, '<') + 1);
530
-            $from_email = str_replace('>', '', $from_email);
531
-            $from_email = trim($from_email);
532
-        } elseif (trim($this->_from) !== '') {
533
-            $from_name  = '';
534
-            $from_email = trim($this->_from);
535
-        } else {
536
-            $from_name = $from_email = '';
537
-        }
538
-        return array($from_name, $from_email);
539
-    }
540
-
541
-
542
-    /**
543
-     * Callback for the wp_mail_from filter.
544
-     *
545
-     * @since 4.3.1
546
-     * @param string $from_email What the original from_email is.
547
-     * @return string
548
-     */
549
-    public function set_from_address($from_email)
550
-    {
551
-        $parsed_from = $this->_parse_from();
552
-        //includes fallback if the parsing failed.
553
-        $from_email = is_array($parsed_from) && ! empty($parsed_from[1])
554
-            ? $parsed_from[1]
555
-            : get_bloginfo('admin_email');
556
-        return $from_email;
557
-    }
558
-
559
-
560
-    /**
561
-     * Callback fro the wp_mail_from_name filter.
562
-     *
563
-     * @since 4.3.1
564
-     * @param string $from_name The original from_name.
565
-     * @return string
566
-     */
567
-    public function set_from_name($from_name)
568
-    {
569
-        $parsed_from = $this->_parse_from();
570
-        if (is_array($parsed_from) && ! empty($parsed_from[0])) {
571
-            $from_name = $parsed_from[0];
572
-        }
573
-
574
-        //if from name is "WordPress" let's sub in the site name instead (more friendly!)
575
-        $from_name = $from_name == 'WordPress' ? get_bloginfo() : $from_name;
576
-
577
-        return $from_name;
578
-    }
579
-
580
-
581
-    /**
582
-     * setup body for email
583
-     *
584
-     * @param bool $preview will determine whether this is preview template or not.
585
-     * @return string formatted body for email.
586
-     * @throws EE_Error
587
-     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
588
-     */
589
-    protected function _body($preview = false)
590
-    {
591
-        //setup template args!
592
-        $this->_template_args = array(
593
-            'subject'   => $this->_subject,
594
-            'from'      => $this->_from,
595
-            'main_body' => wpautop($this->_content),
596
-        );
597
-        $body                 = $this->_get_main_template($preview);
598
-
599
-        /**
600
-         * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
601
-         *
602
-         * @type    bool $preview Indicates whether a preview is being generated or not.
603
-         * @return  bool    true  indicates to use the inliner, false bypasses it.
604
-         */
605
-        if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
606
-            //require CssToInlineStyles library and its dependencies via composer autoloader
607
-            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
608
-
609
-            //now if this isn't a preview, let's setup the body so it has inline styles
610
-            if (! $preview || ($preview && defined('DOING_AJAX'))) {
611
-                $style = file_get_contents(
612
-                    $this->get_variation(
613
-                        $this->_tmp_pack,
614
-                        $this->_incoming_message_type->name,
615
-                        false,
616
-                        'main',
617
-                        $this->_variation
618
-                    ),
619
-                    true
620
-                );
621
-                $CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
622
-                //for some reason the library has a bracket and new line at the beginning.  This takes care of that.
623
-                $body  = ltrim($CSS->convert(true), ">\n");
624
-                //see https://events.codebasehq.com/projects/event-espresso/tickets/8609
625
-                $body  = ltrim($body, "<?");
626
-            }
627
-
628
-        }
629
-        return $body;
630
-    }
631
-
632
-
633
-    /**
634
-     * This just returns any existing test settings that might be saved in the database
635
-     *
636
-     * @access public
637
-     * @return array
638
-     */
639
-    public function get_existing_test_settings()
640
-    {
641
-        $settings = parent::get_existing_test_settings();
642
-        //override subject if present because we always want it to be fresh.
643
-        if (is_array($settings) && ! empty($settings['subject'])) {
644
-            $settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
645
-        }
646
-        return $settings;
647
-    }
11
+	/**
12
+	 * To field for email
13
+	 * @var string
14
+	 */
15
+	protected $_to = '';
16
+
17
+
18
+	/**
19
+	 * CC field for email.
20
+	 * @var string
21
+	 */
22
+	protected $_cc = '';
23
+
24
+	/**
25
+	 * From field for email
26
+	 * @var string
27
+	 */
28
+	protected $_from = '';
29
+
30
+
31
+	/**
32
+	 * Subject field for email
33
+	 * @var string
34
+	 */
35
+	protected $_subject = '';
36
+
37
+
38
+	/**
39
+	 * Content field for email
40
+	 * @var string
41
+	 */
42
+	protected $_content = '';
43
+
44
+
45
+	/**
46
+	 * constructor
47
+	 *
48
+	 * @access public
49
+	 */
50
+	public function __construct()
51
+	{
52
+		//set name and description properties
53
+		$this->name                = 'email';
54
+		$this->description         = sprintf(
55
+			esc_html__(
56
+				'This messenger delivers messages via email using the built-in %s function included with WordPress',
57
+				'event_espresso'
58
+			),
59
+			'<code>wp_mail</code>'
60
+		);
61
+		$this->label               = array(
62
+			'singular' => esc_html__('email', 'event_espresso'),
63
+			'plural'   => esc_html__('emails', 'event_espresso'),
64
+		);
65
+		$this->activate_on_install = true;
66
+
67
+		//we're using defaults so let's call parent constructor that will take care of setting up all the other
68
+		// properties
69
+		parent::__construct();
70
+	}
71
+
72
+
73
+	/**
74
+	 * see abstract declaration in parent class for details.
75
+	 */
76
+	protected function _set_admin_pages()
77
+	{
78
+		$this->admin_registered_pages = array(
79
+			'events_edit' => true,
80
+		);
81
+	}
82
+
83
+
84
+	/**
85
+	 * see abstract declaration in parent class for details
86
+	 */
87
+	protected function _set_valid_shortcodes()
88
+	{
89
+		//remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
90
+		// message type.
91
+		$this->_valid_shortcodes = array(
92
+			'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
93
+			'cc' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
94
+			'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
95
+		);
96
+	}
97
+
98
+
99
+	/**
100
+	 * see abstract declaration in parent class for details
101
+	 *
102
+	 * @access protected
103
+	 * @return void
104
+	 */
105
+	protected function _set_validator_config()
106
+	{
107
+		$valid_shortcodes = $this->get_valid_shortcodes();
108
+
109
+		$this->_validator_config = array(
110
+			'to'            => array(
111
+				'shortcodes' => $valid_shortcodes['to'],
112
+				'type'       => 'email',
113
+			),
114
+			'cc' => array(
115
+				'shortcodes' => $valid_shortcodes['to'],
116
+				'type' => 'email',
117
+			),
118
+			'from'          => array(
119
+				'shortcodes' => $valid_shortcodes['from'],
120
+				'type'       => 'email',
121
+			),
122
+			'subject'       => array(
123
+				'shortcodes' => array(
124
+					'organization',
125
+					'primary_registration_details',
126
+					'event_author',
127
+					'primary_registration_details',
128
+					'recipient_details',
129
+				),
130
+			),
131
+			'content'       => array(
132
+				'shortcodes' => array(
133
+					'event_list',
134
+					'attendee_list',
135
+					'ticket_list',
136
+					'organization',
137
+					'primary_registration_details',
138
+					'primary_registration_list',
139
+					'event_author',
140
+					'recipient_details',
141
+					'recipient_list',
142
+					'transaction',
143
+					'messenger',
144
+				),
145
+			),
146
+			'attendee_list' => array(
147
+				'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
148
+				'required'   => array('[ATTENDEE_LIST]'),
149
+			),
150
+			'event_list'    => array(
151
+				'shortcodes' => array(
152
+					'event',
153
+					'attendee_list',
154
+					'ticket_list',
155
+					'venue',
156
+					'datetime_list',
157
+					'attendee',
158
+					'primary_registration_details',
159
+					'primary_registration_list',
160
+					'event_author',
161
+					'recipient_details',
162
+					'recipient_list',
163
+				),
164
+				'required'   => array('[EVENT_LIST]'),
165
+			),
166
+			'ticket_list'   => array(
167
+				'shortcodes' => array(
168
+					'event_list',
169
+					'attendee_list',
170
+					'ticket',
171
+					'datetime_list',
172
+					'primary_registration_details',
173
+					'recipient_details',
174
+				),
175
+				'required'   => array('[TICKET_LIST]'),
176
+			),
177
+			'datetime_list' => array(
178
+				'shortcodes' => array('datetime'),
179
+				'required'   => array('[DATETIME_LIST]'),
180
+			),
181
+		);
182
+	}
183
+
184
+
185
+	/**
186
+	 * @see   parent EE_messenger class for docs
187
+	 * @since 4.5.0
188
+	 */
189
+	public function do_secondary_messenger_hooks($sending_messenger_name)
190
+	{
191
+		if ($sending_messenger_name = 'html') {
192
+			add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
193
+		}
194
+	}
195
+
196
+
197
+	public function add_email_css(
198
+		$variation_path,
199
+		$messenger,
200
+		$message_type,
201
+		$type,
202
+		$variation,
203
+		$file_extension,
204
+		$url,
205
+		EE_Messages_Template_Pack $template_pack
206
+	) {
207
+		//prevent recursion on this callback.
208
+		remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
209
+		$variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
210
+
211
+		add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
212
+		return $variation;
213
+	}
214
+
215
+
216
+	/**
217
+	 * See parent for details
218
+	 *
219
+	 * @access protected
220
+	 * @return void
221
+	 */
222
+	protected function _set_test_settings_fields()
223
+	{
224
+		$this->_test_settings_fields = array(
225
+			'to'      => array(
226
+				'input'      => 'text',
227
+				'label'      => esc_html__('Send a test email to', 'event_espresso'),
228
+				'type'       => 'email',
229
+				'required'   => true,
230
+				'validation' => true,
231
+				'css_class'  => 'large-text',
232
+				'format'     => '%s',
233
+				'default'    => get_bloginfo('admin_email'),
234
+			),
235
+			'subject' => array(
236
+				'input'      => 'hidden',
237
+				'label'      => '',
238
+				'type'       => 'string',
239
+				'required'   => false,
240
+				'validation' => false,
241
+				'format'     => '%s',
242
+				'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
243
+				'default'    => '',
244
+				'css_class'  => '',
245
+			),
246
+		);
247
+	}
248
+
249
+
250
+	/**
251
+	 * _set_template_fields
252
+	 * This sets up the fields that a messenger requires for the message to go out.
253
+	 *
254
+	 * @access  protected
255
+	 * @return void
256
+	 */
257
+	protected function _set_template_fields()
258
+	{
259
+		// any extra template fields that are NOT used by the messenger but will get used by a messenger field for
260
+		// shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
261
+		// they relate to.  This is important for the Messages_admin to know what fields to display to the user.
262
+		//  Also, notice that the "values" are equal to the field type that messages admin will use to know what
263
+		// kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
264
+		// indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
265
+		// displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
266
+		// will not be displayed/parsed.
267
+		$this->_template_fields = array(
268
+			'to'      => array(
269
+				'input'      => 'text',
270
+				'label'      => esc_html_x(
271
+					'To',
272
+					'Label for the "To" field for email addresses',
273
+					'event_espresso'
274
+				),
275
+				'type'       => 'string',
276
+				'required'   => true,
277
+				'validation' => true,
278
+				'css_class'  => 'large-text',
279
+				'format'     => '%s',
280
+			),
281
+			'cc'      => array(
282
+				'input'      => 'text',
283
+				'label'      => esc_html_x(
284
+					'CC',
285
+					'Label for the "Carbon Copy" field used for additional email addresses',
286
+					'event_espresso'
287
+				),
288
+				'type'       => 'string',
289
+				'required'   => false,
290
+				'validation' => true,
291
+				'css_class'  => 'large-text',
292
+				'format'     => '%s',
293
+			),
294
+			'from'    => array(
295
+				'input'      => 'text',
296
+				'label'      => esc_html_x(
297
+					'From',
298
+					'Label for the "From" field for email addresses.',
299
+					'event_espresso'
300
+				),
301
+				'type'       => 'string',
302
+				'required'   => true,
303
+				'validation' => true,
304
+				'css_class'  => 'large-text',
305
+				'format'     => '%s',
306
+			),
307
+			'subject' => array(
308
+				'input'      => 'text',
309
+				'label'      => esc_html_x(
310
+					'Subject',
311
+					'Label for the "Subject" field (short description of contents) for emails.',
312
+					'event_espresso'
313
+				),
314
+				'type'       => 'string',
315
+				'required'   => true,
316
+				'validation' => true,
317
+				'css_class'  => 'large-text',
318
+				'format'     => '%s',
319
+			),
320
+			'content' => '',
321
+			//left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
322
+			'extra'   => array(
323
+				'content' => array(
324
+					'main'          => array(
325
+						'input'      => 'wp_editor',
326
+						'label'      => esc_html__('Main Content', 'event_espresso'),
327
+						'type'       => 'string',
328
+						'required'   => true,
329
+						'validation' => true,
330
+						'format'     => '%s',
331
+						'rows'       => '15',
332
+					),
333
+					'event_list'    => array(
334
+						'input'               => 'wp_editor',
335
+						'label'               => '[EVENT_LIST]',
336
+						'type'                => 'string',
337
+						'required'            => true,
338
+						'validation'          => true,
339
+						'format'              => '%s',
340
+						'rows'                => '15',
341
+						'shortcodes_required' => array('[EVENT_LIST]'),
342
+					),
343
+					'attendee_list' => array(
344
+						'input'               => 'textarea',
345
+						'label'               => '[ATTENDEE_LIST]',
346
+						'type'                => 'string',
347
+						'required'            => true,
348
+						'validation'          => true,
349
+						'format'              => '%s',
350
+						'css_class'           => 'large-text',
351
+						'rows'                => '5',
352
+						'shortcodes_required' => array('[ATTENDEE_LIST]'),
353
+					),
354
+					'ticket_list'   => array(
355
+						'input'               => 'textarea',
356
+						'label'               => '[TICKET_LIST]',
357
+						'type'                => 'string',
358
+						'required'            => true,
359
+						'validation'          => true,
360
+						'format'              => '%s',
361
+						'css_class'           => 'large-text',
362
+						'rows'                => '10',
363
+						'shortcodes_required' => array('[TICKET_LIST]'),
364
+					),
365
+					'datetime_list' => array(
366
+						'input'               => 'textarea',
367
+						'label'               => '[DATETIME_LIST]',
368
+						'type'                => 'string',
369
+						'required'            => true,
370
+						'validation'          => true,
371
+						'format'              => '%s',
372
+						'css_class'           => 'large-text',
373
+						'rows'                => '10',
374
+						'shortcodes_required' => array('[DATETIME_LIST]'),
375
+					),
376
+				),
377
+			),
378
+		);
379
+	}
380
+
381
+
382
+	/**
383
+	 * See definition of this class in parent
384
+	 */
385
+	protected function _set_default_message_types()
386
+	{
387
+		$this->_default_message_types = array(
388
+			'payment',
389
+			'payment_refund',
390
+			'registration',
391
+			'not_approved_registration',
392
+			'pending_approval',
393
+		);
394
+	}
395
+
396
+
397
+	/**
398
+	 * @see   definition of this class in parent
399
+	 * @since 4.5.0
400
+	 */
401
+	protected function _set_valid_message_types()
402
+	{
403
+		$this->_valid_message_types = array(
404
+			'payment',
405
+			'registration',
406
+			'not_approved_registration',
407
+			'declined_registration',
408
+			'cancelled_registration',
409
+			'pending_approval',
410
+			'registration_summary',
411
+			'payment_reminder',
412
+			'payment_declined',
413
+			'payment_refund',
414
+		);
415
+	}
416
+
417
+
418
+	/**
419
+	 * setting up admin_settings_fields for messenger.
420
+	 */
421
+	protected function _set_admin_settings_fields()
422
+	{
423
+	}
424
+
425
+	/**
426
+	 * We just deliver the messages don't kill us!!
427
+	 *
428
+	 * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
429
+	 *              present.
430
+	 * @throws EE_Error
431
+	 * @throws \TijsVerkoyen\CssToInlineStyles\Exception
432
+	 */
433
+	protected function _send_message()
434
+	{
435
+		$success = wp_mail(
436
+			$this->_to,
437
+			$this->_subject,
438
+			$this->_body(),
439
+			$this->_headers()
440
+		);
441
+		if (! $success) {
442
+			EE_Error::add_error(
443
+				sprintf(
444
+					esc_html__(
445
+						'The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
446
+						'event_espresso'
447
+					),
448
+					$this->_to,
449
+					$this->_from,
450
+					'<br />'
451
+				),
452
+				__FILE__,
453
+				__FUNCTION__,
454
+				__LINE__
455
+			);
456
+		}
457
+		return $success;
458
+	}
459
+
460
+
461
+	/**
462
+	 * see parent for definition
463
+	 *
464
+	 * @return string html body of the message content and the related css.
465
+	 * @throws EE_Error
466
+	 * @throws \TijsVerkoyen\CssToInlineStyles\Exception
467
+	 */
468
+	protected function _preview()
469
+	{
470
+		return $this->_body(true);
471
+	}
472
+
473
+
474
+	/**
475
+	 * Setup headers for email
476
+	 *
477
+	 * @access protected
478
+	 * @return string formatted header for email
479
+	 */
480
+	protected function _headers()
481
+	{
482
+		$this->_ensure_has_from_email_address();
483
+		$from    = $this->_from;
484
+		$headers = array(
485
+			'From:' . $from,
486
+			'Reply-To:' . $from,
487
+			'Content-Type:text/html; charset=utf-8',
488
+		);
489
+
490
+		if (! empty($this->_cc)) {
491
+			$headers[] = 'cc: ' . $this->_cc;
492
+		}
493
+
494
+		//but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
495
+		// header.
496
+		add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
497
+		add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
498
+		return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
499
+	}
500
+
501
+
502
+	/**
503
+	 * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
504
+	 * address for the from address to avoid problems with sending emails.
505
+	 */
506
+	protected function _ensure_has_from_email_address()
507
+	{
508
+		if (empty($this->_from)) {
509
+			$this->_from = get_bloginfo('admin_email');
510
+		}
511
+	}
512
+
513
+
514
+	/**
515
+	 * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
516
+	 * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
517
+	 * be empty
518
+	 *
519
+	 * @since 4.3.1
520
+	 * @return array
521
+	 */
522
+	private function _parse_from()
523
+	{
524
+		if (strpos($this->_from, '<') !== false) {
525
+			$from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
526
+			$from_name = str_replace('"', '', $from_name);
527
+			$from_name = trim($from_name);
528
+
529
+			$from_email = substr($this->_from, strpos($this->_from, '<') + 1);
530
+			$from_email = str_replace('>', '', $from_email);
531
+			$from_email = trim($from_email);
532
+		} elseif (trim($this->_from) !== '') {
533
+			$from_name  = '';
534
+			$from_email = trim($this->_from);
535
+		} else {
536
+			$from_name = $from_email = '';
537
+		}
538
+		return array($from_name, $from_email);
539
+	}
540
+
541
+
542
+	/**
543
+	 * Callback for the wp_mail_from filter.
544
+	 *
545
+	 * @since 4.3.1
546
+	 * @param string $from_email What the original from_email is.
547
+	 * @return string
548
+	 */
549
+	public function set_from_address($from_email)
550
+	{
551
+		$parsed_from = $this->_parse_from();
552
+		//includes fallback if the parsing failed.
553
+		$from_email = is_array($parsed_from) && ! empty($parsed_from[1])
554
+			? $parsed_from[1]
555
+			: get_bloginfo('admin_email');
556
+		return $from_email;
557
+	}
558
+
559
+
560
+	/**
561
+	 * Callback fro the wp_mail_from_name filter.
562
+	 *
563
+	 * @since 4.3.1
564
+	 * @param string $from_name The original from_name.
565
+	 * @return string
566
+	 */
567
+	public function set_from_name($from_name)
568
+	{
569
+		$parsed_from = $this->_parse_from();
570
+		if (is_array($parsed_from) && ! empty($parsed_from[0])) {
571
+			$from_name = $parsed_from[0];
572
+		}
573
+
574
+		//if from name is "WordPress" let's sub in the site name instead (more friendly!)
575
+		$from_name = $from_name == 'WordPress' ? get_bloginfo() : $from_name;
576
+
577
+		return $from_name;
578
+	}
579
+
580
+
581
+	/**
582
+	 * setup body for email
583
+	 *
584
+	 * @param bool $preview will determine whether this is preview template or not.
585
+	 * @return string formatted body for email.
586
+	 * @throws EE_Error
587
+	 * @throws \TijsVerkoyen\CssToInlineStyles\Exception
588
+	 */
589
+	protected function _body($preview = false)
590
+	{
591
+		//setup template args!
592
+		$this->_template_args = array(
593
+			'subject'   => $this->_subject,
594
+			'from'      => $this->_from,
595
+			'main_body' => wpautop($this->_content),
596
+		);
597
+		$body                 = $this->_get_main_template($preview);
598
+
599
+		/**
600
+		 * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
601
+		 *
602
+		 * @type    bool $preview Indicates whether a preview is being generated or not.
603
+		 * @return  bool    true  indicates to use the inliner, false bypasses it.
604
+		 */
605
+		if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
606
+			//require CssToInlineStyles library and its dependencies via composer autoloader
607
+			require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
608
+
609
+			//now if this isn't a preview, let's setup the body so it has inline styles
610
+			if (! $preview || ($preview && defined('DOING_AJAX'))) {
611
+				$style = file_get_contents(
612
+					$this->get_variation(
613
+						$this->_tmp_pack,
614
+						$this->_incoming_message_type->name,
615
+						false,
616
+						'main',
617
+						$this->_variation
618
+					),
619
+					true
620
+				);
621
+				$CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
622
+				//for some reason the library has a bracket and new line at the beginning.  This takes care of that.
623
+				$body  = ltrim($CSS->convert(true), ">\n");
624
+				//see https://events.codebasehq.com/projects/event-espresso/tickets/8609
625
+				$body  = ltrim($body, "<?");
626
+			}
627
+
628
+		}
629
+		return $body;
630
+	}
631
+
632
+
633
+	/**
634
+	 * This just returns any existing test settings that might be saved in the database
635
+	 *
636
+	 * @access public
637
+	 * @return array
638
+	 */
639
+	public function get_existing_test_settings()
640
+	{
641
+		$settings = parent::get_existing_test_settings();
642
+		//override subject if present because we always want it to be fresh.
643
+		if (is_array($settings) && ! empty($settings['subject'])) {
644
+			$settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
645
+		}
646
+		return $settings;
647
+	}
648 648
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -58,7 +58,7 @@  discard block
 block discarded – undo
58 58
             ),
59 59
             '<code>wp_mail</code>'
60 60
         );
61
-        $this->label               = array(
61
+        $this->label = array(
62 62
             'singular' => esc_html__('email', 'event_espresso'),
63 63
             'plural'   => esc_html__('emails', 'event_espresso'),
64 64
         );
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
             $this->_body(),
439 439
             $this->_headers()
440 440
         );
441
-        if (! $success) {
441
+        if ( ! $success) {
442 442
             EE_Error::add_error(
443 443
                 sprintf(
444 444
                     esc_html__(
@@ -482,13 +482,13 @@  discard block
 block discarded – undo
482 482
         $this->_ensure_has_from_email_address();
483 483
         $from    = $this->_from;
484 484
         $headers = array(
485
-            'From:' . $from,
486
-            'Reply-To:' . $from,
485
+            'From:'.$from,
486
+            'Reply-To:'.$from,
487 487
             'Content-Type:text/html; charset=utf-8',
488 488
         );
489 489
 
490
-        if (! empty($this->_cc)) {
491
-            $headers[] = 'cc: ' . $this->_cc;
490
+        if ( ! empty($this->_cc)) {
491
+            $headers[] = 'cc: '.$this->_cc;
492 492
         }
493 493
 
494 494
         //but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
@@ -594,7 +594,7 @@  discard block
 block discarded – undo
594 594
             'from'      => $this->_from,
595 595
             'main_body' => wpautop($this->_content),
596 596
         );
597
-        $body                 = $this->_get_main_template($preview);
597
+        $body = $this->_get_main_template($preview);
598 598
 
599 599
         /**
600 600
          * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
@@ -604,10 +604,10 @@  discard block
 block discarded – undo
604 604
          */
605 605
         if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
606 606
             //require CssToInlineStyles library and its dependencies via composer autoloader
607
-            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
607
+            require_once EE_THIRD_PARTY.'cssinliner/vendor/autoload.php';
608 608
 
609 609
             //now if this isn't a preview, let's setup the body so it has inline styles
610
-            if (! $preview || ($preview && defined('DOING_AJAX'))) {
610
+            if ( ! $preview || ($preview && defined('DOING_AJAX'))) {
611 611
                 $style = file_get_contents(
612 612
                     $this->get_variation(
613 613
                         $this->_tmp_pack,
Please login to merge, or discard this patch.
core/libraries/messages/messenger/EE_Pdf_messenger.class.php 2 patches
Indentation   +339 added lines, -339 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@  discard block
 block discarded – undo
7 7
  * @subpackage messages
8 8
  */
9 9
 if (!defined('EVENT_ESPRESSO_VERSION'))
10
-    exit('NO direct script access allowed');
10
+	exit('NO direct script access allowed');
11 11
 
12 12
 /**
13 13
  *
@@ -24,343 +24,343 @@  discard block
 block discarded – undo
24 24
 {
25 25
 
26 26
 
27
-    /**
28
-     * The following are the properties that this messenger requires for generating pdf
29
-     */
30
-
31
-    /**
32
-     * This is the pdf body generated by the template via the message type.
33
-     *
34
-     * @var string
35
-     */
36
-    protected $_content;
37
-
38
-
39
-    /**
40
-     * This is for the page title that gets displayed.  This will end up being the filename for the generated pdf.
41
-     *
42
-     * @var string
43
-     */
44
-    protected $_subject;
45
-
46
-
47
-    /**
48
-     * @return EE_Pdf_messenger
49
-     */
50
-    public function __construct()
51
-    {
52
-        //set properties
53
-        $this->name = 'pdf';
54
-        $this->description = __('This messenger is used for generating a pdf version of the message.', 'event_espresso');
55
-        $this->label = array(
56
-            'singular' => __('PDF', 'event_espresso'),
57
-            'plural' => __('PDFs', 'event_espresso')
58
-        );
59
-        $this->activate_on_install = TRUE;
60
-
61
-        parent::__construct();
62
-    }
63
-
64
-
65
-    /**
66
-     * PDF Messenger desires execution immediately.
67
-     * @see  parent::send_now() for documentation.
68
-     * @since  4.9.0
69
-     * @return bool
70
-     */
71
-    public function send_now()
72
-    {
73
-        return true;
74
-    }
75
-
76
-
77
-    /**
78
-     * HTML Messenger allows an empty to field.
79
-     * @see parent::allow_empty_to_field() for documentation
80
-     * @since  4.9.0
81
-     * @return bool
82
-     */
83
-    public function allow_empty_to_field()
84
-    {
85
-        return true;
86
-    }
87
-
88
-
89
-    /**
90
-     * @see abstract declaration in EE_messenger for details.
91
-     */
92
-    protected function _set_admin_pages()
93
-    {
94
-        $this->admin_registered_pages = array('events_edit' => false);
95
-    }
96
-
97
-
98
-    /**
99
-     * @see abstract declaration in EE_messenger for details.
100
-     */
101
-    protected function _set_valid_shortcodes()
102
-    {
103
-        $this->_valid_shortcodes = array();
104
-    }
105
-
106
-
107
-    /**
108
-     * @see abstract declaration in EE_messenger for details.
109
-     */
110
-    protected function _set_validator_config()
111
-    {
112
-        $this->_validator_config = array(
113
-            'subject' => array(
114
-                'shortcodes' => array('recipient_details', 'organization', 'event', 'ticket', 'venue', 'primary_registration_details', 'event_author', 'email', 'event_meta', 'recipient_list', 'transaction', 'datetime_list', 'datetime')
115
-            ),
116
-            'content' => array(
117
-                'shortcodes' => array('recipient_details', 'organization', 'event', 'ticket', 'venue', 'primary_registration_details', 'event_author', 'email', 'event_meta', 'recipient_list', 'transaction', 'datetime_list', 'datetime')
118
-            ),
119
-            'attendee_list' => array(
120
-                'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
121
-                'required' => array('[ATTENDEE_LIST]')
122
-            ),
123
-            'event_list' => array(
124
-                'shortcodes' => array('event', 'attendee_list', 'ticket_list', 'venue', 'datetime_list', 'attendee', 'primary_registration_details', 'primary_registration_list', 'event_author', 'recipient_details', 'recipient_list'),
125
-                'required' => array('[EVENT_LIST]')
126
-            ),
127
-            'ticket_list' => array(
128
-                'shortcodes' => array('event_list', 'attendee_list', 'ticket', 'datetime_list', 'primary_registration_details', 'recipient_details'),
129
-                'required' => array('[TICKET_LIST]')
130
-            ),
131
-            'datetime_list' => array(
132
-                'shortcodes' => array('datetime'),
133
-                'required' => array('[DATETIME_LIST]')
134
-            ),
135
-        );
136
-    }
137
-
138
-
139
-    /**
140
-     * Takes care of enqueuing any necessary scripts or styles for the page.  A do_action() so message types using this messenger can add their own js.
141
-     *
142
-     * @return void.
143
-     */
144
-    public function enqueue_scripts_styles()
145
-    {
146
-        parent::enqueue_scripts_styles();
147
-        do_action('AHEE__EE_Pdf_messenger__enqueue_scripts_styles');
148
-    }
149
-
150
-
151
-    /**
152
-     * _set_template_fields
153
-     * This sets up the fields that a messenger requires for the message to go out.
154
-     *
155
-     * @access  protected
156
-     * @return void
157
-     */
158
-    protected function _set_template_fields()
159
-    {
160
-        // any extra template fields that are NOT used by the messenger but will get used by a messenger field for shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field they relate to.  This is important for the Messages_admin to know what fields to display to the user.  Also, notice that the "values" are equal to the field type that messages admin will use to know what kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and will not be displayed/parsed.
161
-        $this->_template_fields = array(
162
-            'subject' => array(
163
-                'input' => 'text',
164
-                'label' => __('Page Title', 'event_espresso'),
165
-                'type' => 'string',
166
-                'required' => TRUE,
167
-                'validation' => TRUE,
168
-                'css_class' => 'large-text',
169
-                'format' => '%s'
170
-            ),
171
-            'content' => '', //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
172
-            'extra' => array(
173
-                'content' => array(
174
-                    'main' => array(
175
-                        'input' => 'wp_editor',
176
-                        'label' => __('Main Content', 'event_espresso'),
177
-                        'type' => 'string',
178
-                        'required' => TRUE,
179
-                        'validation' => TRUE,
180
-                        'format' => '%s',
181
-                        'rows' => '15'
182
-                    ),
183
-                    'event_list' => array(
184
-                        'input' => 'wp_editor',
185
-                        'label' => '[EVENT_LIST]',
186
-                        'type' => 'string',
187
-                        'required' => TRUE,
188
-                        'validation' => TRUE,
189
-                        'format' => '%s',
190
-                        'rows' => '15',
191
-                        'shortcodes_required' => array('[EVENT_LIST]')
192
-                    ),
193
-                    'attendee_list' => array(
194
-                        'input' => 'textarea',
195
-                        'label' => '[ATTENDEE_LIST]',
196
-                        'type' => 'string',
197
-                        'required' => TRUE,
198
-                        'validation' => TRUE,
199
-                        'format' => '%s',
200
-                        'css_class' => 'large-text',
201
-                        'rows' => '5',
202
-                        'shortcodes_required' => array('[ATTENDEE_LIST]')
203
-                    ),
204
-                    'ticket_list' => array(
205
-                        'input' => 'textarea',
206
-                        'label' => '[TICKET_LIST]',
207
-                        'type' => 'string',
208
-                        'required' => TRUE,
209
-                        'validation' => TRUE,
210
-                        'format' => '%s',
211
-                        'css_class' => 'large-text',
212
-                        'rows' => '10',
213
-                        'shortcodes_required' => array('[TICKET_LIST]')
214
-                    ),
215
-                    'datetime_list' => array(
216
-                        'input' => 'textarea',
217
-                        'label' => '[DATETIME_LIST]',
218
-                        'type' => 'string',
219
-                        'required' => TRUE,
220
-                        'validation' => TRUE,
221
-                        'format' => '%s',
222
-                        'css_class' => 'large-text',
223
-                        'rows' => '10',
224
-                        'shortcodes_required' => array('[DATETIME_LIST]')
225
-                    )
226
-                )
227
-            )
228
-        );
229
-    }
230
-
231
-
232
-    /**
233
-     * @see definition of this method in parent
234
-     *
235
-     * @since 4.5.0
236
-     *
237
-     */
238
-    protected function _set_default_message_types()
239
-    {
240
-        //note currently PDF is only a secondary messenger so it never has any associated message types.
241
-        $this->_default_message_types = array();
242
-    }
243
-
244
-
245
-    /**
246
-     * @see definition of this method in parent
247
-     *
248
-     * @since 4.5.0
249
-     */
250
-    protected function _set_valid_message_types()
251
-    {
252
-        $this->_valid_message_types = array();
253
-    }
254
-
255
-
256
-    /**
257
-     * Generates html version of the message content and then sends it to the pdf generator.
258
-     *
259
-     *
260
-     * @since 4.5.0
261
-     *
262
-     * @return string.
263
-     */
264
-    protected function _send_message()
265
-    {
266
-        $this->_template_args = array(
267
-            'page_title' => $this->_subject,
268
-            'base_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'base', $this->_variation),
269
-            'print_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'print', $this->_variation),
270
-            'main_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'main', $this->_variation),
271
-            'extra_css' => EE_LIBRARIES_URL . 'messages/defaults/default/variations/pdf_base_default.css',
272
-            'main_body' => apply_filters('FHEE__EE_Pdf_messenger___send_message__main_body', wpautop($this->_content), $this->_content)
273
-        );
274
-        $this->_deregister_wp_hooks();
275
-        add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts_styles'));
276
-        $content = $this->_get_main_template();
27
+	/**
28
+	 * The following are the properties that this messenger requires for generating pdf
29
+	 */
30
+
31
+	/**
32
+	 * This is the pdf body generated by the template via the message type.
33
+	 *
34
+	 * @var string
35
+	 */
36
+	protected $_content;
37
+
38
+
39
+	/**
40
+	 * This is for the page title that gets displayed.  This will end up being the filename for the generated pdf.
41
+	 *
42
+	 * @var string
43
+	 */
44
+	protected $_subject;
45
+
46
+
47
+	/**
48
+	 * @return EE_Pdf_messenger
49
+	 */
50
+	public function __construct()
51
+	{
52
+		//set properties
53
+		$this->name = 'pdf';
54
+		$this->description = __('This messenger is used for generating a pdf version of the message.', 'event_espresso');
55
+		$this->label = array(
56
+			'singular' => __('PDF', 'event_espresso'),
57
+			'plural' => __('PDFs', 'event_espresso')
58
+		);
59
+		$this->activate_on_install = TRUE;
60
+
61
+		parent::__construct();
62
+	}
63
+
64
+
65
+	/**
66
+	 * PDF Messenger desires execution immediately.
67
+	 * @see  parent::send_now() for documentation.
68
+	 * @since  4.9.0
69
+	 * @return bool
70
+	 */
71
+	public function send_now()
72
+	{
73
+		return true;
74
+	}
75
+
76
+
77
+	/**
78
+	 * HTML Messenger allows an empty to field.
79
+	 * @see parent::allow_empty_to_field() for documentation
80
+	 * @since  4.9.0
81
+	 * @return bool
82
+	 */
83
+	public function allow_empty_to_field()
84
+	{
85
+		return true;
86
+	}
87
+
88
+
89
+	/**
90
+	 * @see abstract declaration in EE_messenger for details.
91
+	 */
92
+	protected function _set_admin_pages()
93
+	{
94
+		$this->admin_registered_pages = array('events_edit' => false);
95
+	}
96
+
97
+
98
+	/**
99
+	 * @see abstract declaration in EE_messenger for details.
100
+	 */
101
+	protected function _set_valid_shortcodes()
102
+	{
103
+		$this->_valid_shortcodes = array();
104
+	}
105
+
106
+
107
+	/**
108
+	 * @see abstract declaration in EE_messenger for details.
109
+	 */
110
+	protected function _set_validator_config()
111
+	{
112
+		$this->_validator_config = array(
113
+			'subject' => array(
114
+				'shortcodes' => array('recipient_details', 'organization', 'event', 'ticket', 'venue', 'primary_registration_details', 'event_author', 'email', 'event_meta', 'recipient_list', 'transaction', 'datetime_list', 'datetime')
115
+			),
116
+			'content' => array(
117
+				'shortcodes' => array('recipient_details', 'organization', 'event', 'ticket', 'venue', 'primary_registration_details', 'event_author', 'email', 'event_meta', 'recipient_list', 'transaction', 'datetime_list', 'datetime')
118
+			),
119
+			'attendee_list' => array(
120
+				'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
121
+				'required' => array('[ATTENDEE_LIST]')
122
+			),
123
+			'event_list' => array(
124
+				'shortcodes' => array('event', 'attendee_list', 'ticket_list', 'venue', 'datetime_list', 'attendee', 'primary_registration_details', 'primary_registration_list', 'event_author', 'recipient_details', 'recipient_list'),
125
+				'required' => array('[EVENT_LIST]')
126
+			),
127
+			'ticket_list' => array(
128
+				'shortcodes' => array('event_list', 'attendee_list', 'ticket', 'datetime_list', 'primary_registration_details', 'recipient_details'),
129
+				'required' => array('[TICKET_LIST]')
130
+			),
131
+			'datetime_list' => array(
132
+				'shortcodes' => array('datetime'),
133
+				'required' => array('[DATETIME_LIST]')
134
+			),
135
+		);
136
+	}
137
+
138
+
139
+	/**
140
+	 * Takes care of enqueuing any necessary scripts or styles for the page.  A do_action() so message types using this messenger can add their own js.
141
+	 *
142
+	 * @return void.
143
+	 */
144
+	public function enqueue_scripts_styles()
145
+	{
146
+		parent::enqueue_scripts_styles();
147
+		do_action('AHEE__EE_Pdf_messenger__enqueue_scripts_styles');
148
+	}
149
+
150
+
151
+	/**
152
+	 * _set_template_fields
153
+	 * This sets up the fields that a messenger requires for the message to go out.
154
+	 *
155
+	 * @access  protected
156
+	 * @return void
157
+	 */
158
+	protected function _set_template_fields()
159
+	{
160
+		// any extra template fields that are NOT used by the messenger but will get used by a messenger field for shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field they relate to.  This is important for the Messages_admin to know what fields to display to the user.  Also, notice that the "values" are equal to the field type that messages admin will use to know what kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and will not be displayed/parsed.
161
+		$this->_template_fields = array(
162
+			'subject' => array(
163
+				'input' => 'text',
164
+				'label' => __('Page Title', 'event_espresso'),
165
+				'type' => 'string',
166
+				'required' => TRUE,
167
+				'validation' => TRUE,
168
+				'css_class' => 'large-text',
169
+				'format' => '%s'
170
+			),
171
+			'content' => '', //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
172
+			'extra' => array(
173
+				'content' => array(
174
+					'main' => array(
175
+						'input' => 'wp_editor',
176
+						'label' => __('Main Content', 'event_espresso'),
177
+						'type' => 'string',
178
+						'required' => TRUE,
179
+						'validation' => TRUE,
180
+						'format' => '%s',
181
+						'rows' => '15'
182
+					),
183
+					'event_list' => array(
184
+						'input' => 'wp_editor',
185
+						'label' => '[EVENT_LIST]',
186
+						'type' => 'string',
187
+						'required' => TRUE,
188
+						'validation' => TRUE,
189
+						'format' => '%s',
190
+						'rows' => '15',
191
+						'shortcodes_required' => array('[EVENT_LIST]')
192
+					),
193
+					'attendee_list' => array(
194
+						'input' => 'textarea',
195
+						'label' => '[ATTENDEE_LIST]',
196
+						'type' => 'string',
197
+						'required' => TRUE,
198
+						'validation' => TRUE,
199
+						'format' => '%s',
200
+						'css_class' => 'large-text',
201
+						'rows' => '5',
202
+						'shortcodes_required' => array('[ATTENDEE_LIST]')
203
+					),
204
+					'ticket_list' => array(
205
+						'input' => 'textarea',
206
+						'label' => '[TICKET_LIST]',
207
+						'type' => 'string',
208
+						'required' => TRUE,
209
+						'validation' => TRUE,
210
+						'format' => '%s',
211
+						'css_class' => 'large-text',
212
+						'rows' => '10',
213
+						'shortcodes_required' => array('[TICKET_LIST]')
214
+					),
215
+					'datetime_list' => array(
216
+						'input' => 'textarea',
217
+						'label' => '[DATETIME_LIST]',
218
+						'type' => 'string',
219
+						'required' => TRUE,
220
+						'validation' => TRUE,
221
+						'format' => '%s',
222
+						'css_class' => 'large-text',
223
+						'rows' => '10',
224
+						'shortcodes_required' => array('[DATETIME_LIST]')
225
+					)
226
+				)
227
+			)
228
+		);
229
+	}
230
+
231
+
232
+	/**
233
+	 * @see definition of this method in parent
234
+	 *
235
+	 * @since 4.5.0
236
+	 *
237
+	 */
238
+	protected function _set_default_message_types()
239
+	{
240
+		//note currently PDF is only a secondary messenger so it never has any associated message types.
241
+		$this->_default_message_types = array();
242
+	}
243
+
244
+
245
+	/**
246
+	 * @see definition of this method in parent
247
+	 *
248
+	 * @since 4.5.0
249
+	 */
250
+	protected function _set_valid_message_types()
251
+	{
252
+		$this->_valid_message_types = array();
253
+	}
254
+
255
+
256
+	/**
257
+	 * Generates html version of the message content and then sends it to the pdf generator.
258
+	 *
259
+	 *
260
+	 * @since 4.5.0
261
+	 *
262
+	 * @return string.
263
+	 */
264
+	protected function _send_message()
265
+	{
266
+		$this->_template_args = array(
267
+			'page_title' => $this->_subject,
268
+			'base_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'base', $this->_variation),
269
+			'print_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'print', $this->_variation),
270
+			'main_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'main', $this->_variation),
271
+			'extra_css' => EE_LIBRARIES_URL . 'messages/defaults/default/variations/pdf_base_default.css',
272
+			'main_body' => apply_filters('FHEE__EE_Pdf_messenger___send_message__main_body', wpautop($this->_content), $this->_content)
273
+		);
274
+		$this->_deregister_wp_hooks();
275
+		add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts_styles'));
276
+		$content = $this->_get_main_template();
277 277
 //		die( $content );
278
-        $this->_do_pdf($content);
279
-        exit(0);
280
-    }
281
-
282
-
283
-    /**
284
-     * The purpose of this function is to de register all actions hooked into wp_head and wp_footer so that it doesn't interfere with our templates.  If users want to add any custom styles or scripts they must use the AHEE__EE_Pdf_messenger__enqueue_scripts_styles hook.
285
-     *
286
-     * @since 4.5.0
287
-     *
288
-     * @return void
289
-     */
290
-    protected function _deregister_wp_hooks()
291
-    {
292
-        remove_all_actions('wp_head');
293
-        remove_all_actions('wp_footer');
294
-        remove_all_actions('wp_print_footer_scripts');
295
-        remove_all_actions('wp_enqueue_scripts');
296
-        global $wp_scripts, $wp_styles;
297
-        $wp_scripts = $wp_styles = array();
298
-
299
-        //just add back in wp_enqueue_scripts and wp_print_footer_scripts cause that's all we want to load.
300
-        add_action('wp_head', 'wp_enqueue_scripts');
301
-        add_action('wp_footer', 'wp_print_footer_scripts');
302
-        add_action('wp_print_footer_scripts', '_wp_footer_scripts');
303
-    }
304
-
305
-
306
-    /**
307
-     * Overwrite parent _get_main_template for pdf purposes.
308
-     *
309
-     * @since  4.5.0
310
-     *
311
-     * @param bool $preview
312
-     * @return string
313
-     */
314
-    protected function _get_main_template($preview = FALSE)
315
-    {
316
-        $wrapper_template = $this->_tmp_pack->get_wrapper('html', 'main');
317
-        //add message type to template_args
318
-        $this->_template_args['message_type'] = $this->_incoming_message_type;
319
-        return EEH_Template::display_template($wrapper_template, $this->_template_args, TRUE);
320
-    }
321
-
322
-
323
-    /**
324
-     * This takes care of loading the dompdf library and generating the actual pdf
325
-     *
326
-     * @param string $content This is the generated html content being converted into a pdf.
327
-     *
328
-     * @return void
329
-     */
330
-    protected function _do_pdf($content = '')
331
-    {
332
-        $invoice_name = $this->_subject;
333
-
334
-        //only load dompdf if nobody else has yet...
335
-        if (!defined('DOMPDF_DIR')) {
336
-            define('DOMPDF_ENABLE_REMOTE', TRUE);
337
-            define('DOMPDF_ENABLE_JAVASCRIPT', FALSE);
338
-            define('DOMPDF_ENABLE_CSS_FLOAT', TRUE);
339
-            require_once(EE_THIRD_PARTY . 'dompdf/dompdf_config.inc.php');
340
-        }
341
-        $dompdf = new DOMPDF();
342
-        if (defined('DOMPDF_DEFAULT_PAPER_SIZE')) {
343
-            $dompdf->set_paper(DOMPDF_DEFAULT_PAPER_SIZE);
344
-        }
345
-        //Remove all spaces between HTML tags
346
-        $content = preg_replace('/>\s+</', '><', $content);
347
-        $dompdf->load_html($content);
348
-        $dompdf->render();
349
-        //forcing the browser to open a download dialog.
350
-        $dompdf->stream($invoice_name . ".pdf", array('Attachment' => TRUE));
351
-    }
352
-
353
-
354
-    /**
355
-     * @return string
356
-     */
357
-    protected function _preview()
358
-    {
359
-        return $this->_send_message();
360
-    }
361
-
362
-
363
-    protected function _set_admin_settings_fields()
364
-    {
365
-    }
278
+		$this->_do_pdf($content);
279
+		exit(0);
280
+	}
281
+
282
+
283
+	/**
284
+	 * The purpose of this function is to de register all actions hooked into wp_head and wp_footer so that it doesn't interfere with our templates.  If users want to add any custom styles or scripts they must use the AHEE__EE_Pdf_messenger__enqueue_scripts_styles hook.
285
+	 *
286
+	 * @since 4.5.0
287
+	 *
288
+	 * @return void
289
+	 */
290
+	protected function _deregister_wp_hooks()
291
+	{
292
+		remove_all_actions('wp_head');
293
+		remove_all_actions('wp_footer');
294
+		remove_all_actions('wp_print_footer_scripts');
295
+		remove_all_actions('wp_enqueue_scripts');
296
+		global $wp_scripts, $wp_styles;
297
+		$wp_scripts = $wp_styles = array();
298
+
299
+		//just add back in wp_enqueue_scripts and wp_print_footer_scripts cause that's all we want to load.
300
+		add_action('wp_head', 'wp_enqueue_scripts');
301
+		add_action('wp_footer', 'wp_print_footer_scripts');
302
+		add_action('wp_print_footer_scripts', '_wp_footer_scripts');
303
+	}
304
+
305
+
306
+	/**
307
+	 * Overwrite parent _get_main_template for pdf purposes.
308
+	 *
309
+	 * @since  4.5.0
310
+	 *
311
+	 * @param bool $preview
312
+	 * @return string
313
+	 */
314
+	protected function _get_main_template($preview = FALSE)
315
+	{
316
+		$wrapper_template = $this->_tmp_pack->get_wrapper('html', 'main');
317
+		//add message type to template_args
318
+		$this->_template_args['message_type'] = $this->_incoming_message_type;
319
+		return EEH_Template::display_template($wrapper_template, $this->_template_args, TRUE);
320
+	}
321
+
322
+
323
+	/**
324
+	 * This takes care of loading the dompdf library and generating the actual pdf
325
+	 *
326
+	 * @param string $content This is the generated html content being converted into a pdf.
327
+	 *
328
+	 * @return void
329
+	 */
330
+	protected function _do_pdf($content = '')
331
+	{
332
+		$invoice_name = $this->_subject;
333
+
334
+		//only load dompdf if nobody else has yet...
335
+		if (!defined('DOMPDF_DIR')) {
336
+			define('DOMPDF_ENABLE_REMOTE', TRUE);
337
+			define('DOMPDF_ENABLE_JAVASCRIPT', FALSE);
338
+			define('DOMPDF_ENABLE_CSS_FLOAT', TRUE);
339
+			require_once(EE_THIRD_PARTY . 'dompdf/dompdf_config.inc.php');
340
+		}
341
+		$dompdf = new DOMPDF();
342
+		if (defined('DOMPDF_DEFAULT_PAPER_SIZE')) {
343
+			$dompdf->set_paper(DOMPDF_DEFAULT_PAPER_SIZE);
344
+		}
345
+		//Remove all spaces between HTML tags
346
+		$content = preg_replace('/>\s+</', '><', $content);
347
+		$dompdf->load_html($content);
348
+		$dompdf->render();
349
+		//forcing the browser to open a download dialog.
350
+		$dompdf->stream($invoice_name . ".pdf", array('Attachment' => TRUE));
351
+	}
352
+
353
+
354
+	/**
355
+	 * @return string
356
+	 */
357
+	protected function _preview()
358
+	{
359
+		return $this->_send_message();
360
+	}
361
+
362
+
363
+	protected function _set_admin_settings_fields()
364
+	{
365
+	}
366 366
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -6,7 +6,7 @@  discard block
 block discarded – undo
6 6
  * @package Event Espresso
7 7
  * @subpackage messages
8 8
  */
9
-if (!defined('EVENT_ESPRESSO_VERSION'))
9
+if ( ! defined('EVENT_ESPRESSO_VERSION'))
10 10
     exit('NO direct script access allowed');
11 11
 
12 12
 /**
@@ -268,7 +268,7 @@  discard block
 block discarded – undo
268 268
             'base_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'base', $this->_variation),
269 269
             'print_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'print', $this->_variation),
270 270
             'main_css' => $this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name, TRUE, 'main', $this->_variation),
271
-            'extra_css' => EE_LIBRARIES_URL . 'messages/defaults/default/variations/pdf_base_default.css',
271
+            'extra_css' => EE_LIBRARIES_URL.'messages/defaults/default/variations/pdf_base_default.css',
272 272
             'main_body' => apply_filters('FHEE__EE_Pdf_messenger___send_message__main_body', wpautop($this->_content), $this->_content)
273 273
         );
274 274
         $this->_deregister_wp_hooks();
@@ -332,11 +332,11 @@  discard block
 block discarded – undo
332 332
         $invoice_name = $this->_subject;
333 333
 
334 334
         //only load dompdf if nobody else has yet...
335
-        if (!defined('DOMPDF_DIR')) {
335
+        if ( ! defined('DOMPDF_DIR')) {
336 336
             define('DOMPDF_ENABLE_REMOTE', TRUE);
337 337
             define('DOMPDF_ENABLE_JAVASCRIPT', FALSE);
338 338
             define('DOMPDF_ENABLE_CSS_FLOAT', TRUE);
339
-            require_once(EE_THIRD_PARTY . 'dompdf/dompdf_config.inc.php');
339
+            require_once(EE_THIRD_PARTY.'dompdf/dompdf_config.inc.php');
340 340
         }
341 341
         $dompdf = new DOMPDF();
342 342
         if (defined('DOMPDF_DEFAULT_PAPER_SIZE')) {
@@ -347,7 +347,7 @@  discard block
 block discarded – undo
347 347
         $dompdf->load_html($content);
348 348
         $dompdf->render();
349 349
         //forcing the browser to open a download dialog.
350
-        $dompdf->stream($invoice_name . ".pdf", array('Attachment' => TRUE));
350
+        $dompdf->stream($invoice_name.".pdf", array('Attachment' => TRUE));
351 351
     }
352 352
 
353 353
 
Please login to merge, or discard this patch.
core/libraries/messages/EE_Messages_Generator.lib.php 1 patch
Indentation   +969 added lines, -969 removed lines patch added patch discarded remove patch
@@ -13,973 +13,973 @@
 block discarded – undo
13 13
 {
14 14
 
15 15
 
16
-    /**
17
-     * @type EE_Messages_Data_Handler_Collection
18
-     */
19
-    protected $_data_handler_collection;
20
-
21
-    /**
22
-     * @type  EE_Message_Template_Group_Collection
23
-     */
24
-    protected $_template_collection;
25
-
26
-    /**
27
-     * This will hold the data handler for the current EE_Message being generated.
28
-     *
29
-     * @type EE_Messages_incoming_data
30
-     */
31
-    protected $_current_data_handler;
32
-
33
-    /**
34
-     * This holds the EE_Messages_Queue that contains the messages to generate.
35
-     *
36
-     * @type EE_Messages_Queue
37
-     */
38
-    protected $_generation_queue;
39
-
40
-    /**
41
-     * This holds the EE_Messages_Queue that will store the generated EE_Message objects.
42
-     *
43
-     * @type EE_Messages_Queue
44
-     */
45
-    protected $_ready_queue;
46
-
47
-    /**
48
-     * This is a container for any error messages that get created through the generation
49
-     * process.
50
-     *
51
-     * @type array
52
-     */
53
-    protected $_error_msg = array();
54
-
55
-    /**
56
-     * Flag used to set when the current EE_Message in the generation queue has been verified.
57
-     *
58
-     * @type bool
59
-     */
60
-    protected $_verified = false;
61
-
62
-    /**
63
-     * This will hold the current messenger object corresponding with the current EE_Message in the generation queue.
64
-     *
65
-     * @type EE_messenger
66
-     */
67
-    protected $_current_messenger;
68
-
69
-    /**
70
-     * This will hold the current message type object corresponding with the current EE_Message in the generation queue.
71
-     *
72
-     * @type EE_message_type
73
-     */
74
-    protected $_current_message_type;
75
-
76
-    /**
77
-     * @type EEH_Parse_Shortcodes
78
-     */
79
-    protected $_shortcode_parser;
80
-
81
-
82
-    /**
83
-     * @param EE_Messages_Queue                     $generation_queue
84
-     * @param \EE_Messages_Queue                    $ready_queue
85
-     * @param \EE_Messages_Data_Handler_Collection  $data_handler_collection
86
-     * @param \EE_Message_Template_Group_Collection $template_collection
87
-     * @param \EEH_Parse_Shortcodes                 $shortcode_parser
88
-     */
89
-    public function __construct(
90
-        EE_Messages_Queue $generation_queue,
91
-        EE_Messages_Queue $ready_queue,
92
-        EE_Messages_Data_Handler_Collection $data_handler_collection,
93
-        EE_Message_Template_Group_Collection $template_collection,
94
-        EEH_Parse_Shortcodes $shortcode_parser
95
-    ) {
96
-        $this->_generation_queue        = $generation_queue;
97
-        $this->_ready_queue             = $ready_queue;
98
-        $this->_data_handler_collection = $data_handler_collection;
99
-        $this->_template_collection     = $template_collection;
100
-        $this->_shortcode_parser        = $shortcode_parser;
101
-    }
102
-
103
-
104
-    /**
105
-     * @return EE_Messages_Queue
106
-     */
107
-    public function generation_queue()
108
-    {
109
-        return $this->_generation_queue;
110
-    }
111
-
112
-
113
-    /**
114
-     *  This iterates through the provided queue and generates the EE_Message objects.
115
-     *  When iterating through the queue, the queued item that served as the base for generating other EE_Message
116
-     *  objects gets removed and the new EE_Message objects get added to a NEW queue.  The NEW queue is then returned
117
-     *  for the caller to decide what to do with it.
118
-     *
119
-     * @param   bool $save Whether to save the EE_Message objects in the new queue or just return.
120
-     * @return EE_Messages_Queue The new queue for holding generated EE_Message objects.
121
-     * @throws EE_Error
122
-     * @throws ReflectionException
123
-     */
124
-    public function generate($save = true)
125
-    {
126
-        //iterate through the messages in the queue, generate, and add to new queue.
127
-        $this->_generation_queue->get_message_repository()->rewind();
128
-        while ($this->_generation_queue->get_message_repository()->valid()) {
129
-            //reset "current" properties
130
-            $this->_reset_current_properties();
131
-
132
-            /** @type EE_Message $msg */
133
-            $msg = $this->_generation_queue->get_message_repository()->current();
134
-
135
-            /**
136
-             * need to get the next object and capture it for setting manually after deletes.  The reason is that when
137
-             * an object is removed from the repo then valid for the next object will fail.
138
-             */
139
-            $this->_generation_queue->get_message_repository()->next();
140
-            $next_msg = $this->_generation_queue->get_message_repository()->current();
141
-            //restore pointer to current item
142
-            $this->_generation_queue->get_message_repository()->set_current($msg);
143
-
144
-            //skip and delete if the current $msg is NOT incomplete (queued for generation)
145
-            if ($msg->STS_ID() !== EEM_Message::status_incomplete) {
146
-                //we keep this item in the db just remove from the repo.
147
-                $this->_generation_queue->get_message_repository()->remove($msg);
148
-                //next item
149
-                $this->_generation_queue->get_message_repository()->set_current($next_msg);
150
-                continue;
151
-            }
152
-
153
-            if ($this->_verify()) {
154
-                //let's get generating!
155
-                $this->_generate();
156
-            }
157
-
158
-            //don't persist debug_only messages if the messages system is not in debug mode.
159
-            if ($msg->STS_ID() === EEM_Message::status_debug_only
160
-                && ! EEM_Message::debug()
161
-            ) {
162
-                do_action(
163
-                    'AHEE__EE_Messages_Generator__generate__before_debug_delete',
164
-                    $msg,
165
-                    $this->_error_msg,
166
-                    $this->_current_messenger,
167
-                    $this->_current_message_type,
168
-                    $this->_current_data_handler
169
-                );
170
-                $this->_generation_queue->get_message_repository()->delete();
171
-                $this->_generation_queue->get_message_repository()->set_current($next_msg);
172
-                continue;
173
-            }
174
-
175
-            //if there are error messages then let's set the status and the error message.
176
-            if ($this->_error_msg) {
177
-                //if the status is already debug only, then let's leave it at that.
178
-                if ($msg->STS_ID() !== EEM_Message::status_debug_only) {
179
-                    $msg->set_STS_ID(EEM_Message::status_failed);
180
-                }
181
-                do_action(
182
-                    'AHEE__EE_Messages_Generator__generate__processing_failed_message',
183
-                    $msg,
184
-                    $this->_error_msg,
185
-                    $this->_current_messenger,
186
-                    $this->_current_message_type,
187
-                    $this->_current_data_handler
188
-                );
189
-                $msg->set_error_message(
190
-                    esc_html__('Message failed to generate for the following reasons: ', 'event_espresso')
191
-                    . "\n"
192
-                    . implode("\n", $this->_error_msg)
193
-                );
194
-                $msg->set_modified(time());
195
-            } else {
196
-                do_action(
197
-                    'AHEE__EE_Messages_Generator__generate__before_successful_generated_message_delete',
198
-                    $msg,
199
-                    $this->_error_msg,
200
-                    $this->_current_messenger,
201
-                    $this->_current_message_type,
202
-                    $this->_current_data_handler
203
-                );
204
-                //remove from db
205
-                $this->_generation_queue->get_message_repository()->delete();
206
-            }
207
-            //next item
208
-            $this->_generation_queue->get_message_repository()->set_current($next_msg);
209
-        }
210
-
211
-        //generation queue is ALWAYS saved to record any errors in the generation process.
212
-        $this->_generation_queue->save();
213
-
214
-        /**
215
-         * save _ready_queue if flag set.
216
-         * Note: The EE_Message objects have values set via the EE_Base_Class::set_field_or_extra_meta() method.  This
217
-         * means if a field was added that is not a valid database column.  The EE_Message was already saved to the db
218
-         * so a EE_Extra_Meta entry could be created and attached to the EE_Message.  In those cases the save flag is
219
-         * irrelevant.
220
-         */
221
-        if ($save) {
222
-            $this->_ready_queue->save();
223
-        }
224
-
225
-        //final reset of properties
226
-        $this->_reset_current_properties();
227
-
228
-        return $this->_ready_queue;
229
-    }
230
-
231
-
232
-    /**
233
-     * This resets all the properties used for holding "current" values corresponding to the current EE_Message object
234
-     * in the generation queue.
235
-     */
236
-    protected function _reset_current_properties()
237
-    {
238
-        $this->_verified = false;
239
-        //make sure any _data value in the current message type is reset
240
-        if ($this->_current_message_type instanceof EE_message_type) {
241
-            $this->_current_message_type->reset_data();
242
-        }
243
-        $this->_current_messenger = $this->_current_message_type = $this->_current_data_handler = null;
244
-    }
245
-
246
-
247
-    /**
248
-     * This proceeds with the actual generation of a message.  By the time this is called, there should already be a
249
-     * $_current_data_handler set and all incoming information should be validated for the current EE_Message in the
250
-     * _generating_queue.
251
-     *
252
-     * @return bool Whether the message was successfully generated or not.
253
-     * @throws EE_Error
254
-     * @throws InvalidArgumentException
255
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
256
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
257
-     */
258
-    protected function _generate()
259
-    {
260
-        //double check verification has run and that everything is ready to work with (saves us having to validate
261
-        // everything again).
262
-        if (! $this->_verified) {
263
-            return false; //get out because we don't have a valid setup to work with.
264
-        }
265
-
266
-
267
-        try {
268
-            $addressees = $this->_current_message_type->get_addressees(
269
-                $this->_current_data_handler,
270
-                $this->_generation_queue->get_message_repository()->current()->context()
271
-            );
272
-        } catch (EE_Error $e) {
273
-            $this->_error_msg[] = $e->getMessage();
274
-            return false;
275
-        }
276
-
277
-
278
-        //if no addressees then get out because there is nothing to generation (possible bad data).
279
-        if (! $this->_valid_addressees($addressees)) {
280
-            do_action(
281
-                'AHEE__EE_Messages_Generator___generate__invalid_addressees',
282
-                $this->_generation_queue->get_message_repository()->current(),
283
-                $addressees,
284
-                $this->_current_messenger,
285
-                $this->_current_message_type,
286
-                $this->_current_data_handler
287
-            );
288
-            $this->_generation_queue->get_message_repository()->current()->set_STS_ID(
289
-                EEM_Message::status_debug_only
290
-            );
291
-            $this->_error_msg[] = esc_html__(
292
-                'This is not a critical error but an informational notice. Unable to generate messages EE_Messages_Addressee objects.  There were no attendees prepared by the data handler. Sometimes this is because messages only get generated for certain registration statuses. For example, the ticket notice message type only goes to approved registrations.',
293
-                'event_espresso'
294
-            );
295
-            return false;
296
-        }
297
-
298
-        $message_template_group = $this->_get_message_template_group();
299
-
300
-        //in the unlikely event there is no EE_Message_Template_Group available, get out!
301
-        if (! $message_template_group instanceof EE_Message_Template_Group) {
302
-            $this->_error_msg[] = esc_html__(
303
-                'Unable to get the Message Templates for the Message being generated.  No message template group accessible.',
304
-                'event_espresso'
305
-            );
306
-            return false;
307
-        }
308
-
309
-        //get formatted templates for using to parse and setup EE_Message objects.
310
-        $templates = $this->_get_templates($message_template_group);
311
-
312
-
313
-        //setup new EE_Message objects (and add to _ready_queue)
314
-        return $this->_assemble_messages($addressees, $templates, $message_template_group);
315
-    }
316
-
317
-
318
-    /**
319
-     * Retrieves the message template group being used for generating messages.
320
-     * Note: this also utilizes the EE_Message_Template_Group_Collection to avoid having to hit the db multiple times.
321
-     *
322
-     * @return EE_Message_Template_Group|null
323
-     * @throws EE_Error
324
-     * @throws InvalidArgumentException
325
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
326
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
327
-     */
328
-    protected function _get_message_template_group()
329
-    {
330
-        //first see if there is a specific message template group requested (current message in the queue has a specific
331
-        //GRP_ID
332
-        $message_template_group = $this->_specific_message_template_group_from_queue();
333
-        if ($message_template_group instanceof EE_Message_Template_Group) {
334
-            return $message_template_group;
335
-        }
336
-
337
-        //get event_ids from the datahandler so we can check to see if there's already a message template group for them
338
-        //in the collection.
339
-        $event_ids              = $this->_get_event_ids_from_current_data_handler();
340
-        $message_template_group = $this->_template_collection->get_by_key(
341
-            $this->_template_collection->getKey(
342
-                $this->_current_messenger->name,
343
-                $this->_current_message_type->name,
344
-                $event_ids
345
-            )
346
-        );
347
-
348
-        //if we have a message template group then no need to hit the database, just return it.
349
-        if ($message_template_group instanceof EE_Message_Template_Group) {
350
-            return $message_template_group;
351
-        }
352
-
353
-        //okay made it here, so let's get the global group first for this messenger and message type to ensure
354
-        //there is no override set.
355
-        $global_message_template_group =
356
-            $this->_get_global_message_template_group_for_current_messenger_and_message_type();
357
-
358
-        if ($global_message_template_group instanceof EE_Message_Template_Group
359
-            && $global_message_template_group->get('MTP_is_override')
360
-        ) {
361
-            return $global_message_template_group;
362
-        }
363
-
364
-        //if we're still here, that means there was no message template group for the events in the collection and
365
-        //the global message template group for the messenger and message type is not set for override.  So next step is
366
-        //to see if there is a common shared custom message template group for this set of events.
367
-        $message_template_group = $this->_get_shared_message_template_for_events($event_ids);
368
-        if ($message_template_group instanceof EE_Message_Template_Group) {
369
-            return $message_template_group;
370
-        }
371
-
372
-        //STILL here?  Okay that means the fallback is to just use the global message template group for this event set.
373
-        //So we'll cache the global group for this event set (so this logic doesn't have to be repeated in this request)
374
-        //and return it.
375
-        if ($global_message_template_group instanceof EE_Message_Template_Group) {
376
-            $this->_template_collection->add(
377
-                $global_message_template_group,
378
-                $event_ids
379
-            );
380
-            return $global_message_template_group;
381
-        }
382
-
383
-        //if we land here that means there's NO active message template group for this set.
384
-        //TODO this will be a good target for some optimization down the road.  Whenever there is no active message
385
-        //template group for a given event set then cache that result so we don't repeat the logic.  However, for now,
386
-        //this should likely bit hit rarely enough that it's not a significant issue.
387
-        return null;
388
-    }
389
-
390
-
391
-    /**
392
-     * This checks the current message in the queue and determines if there is a specific Message Template Group
393
-     * requested for that message.
394
-     *
395
-     * @return EE_Message_Template_Group|null
396
-     * @throws EE_Error
397
-     * @throws InvalidArgumentException
398
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
399
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
400
-     */
401
-    protected function _specific_message_template_group_from_queue()
402
-    {
403
-        //is there a GRP_ID already on the EE_Message object?  If there is, then a specific template has been requested
404
-        //so let's use that.
405
-        $GRP_ID = $this->_generation_queue->get_message_repository()->current()->GRP_ID();
406
-
407
-        if ($GRP_ID) {
408
-            //attempt to retrieve from repo first
409
-            $message_template_group = $this->_template_collection->get_by_ID($GRP_ID);
410
-            if ($message_template_group instanceof EE_Message_Template_Group) {
411
-                return $message_template_group;  //got it!
412
-            }
413
-
414
-            //nope don't have it yet.  Get from DB then add to repo if its not here, then that means the current GRP_ID
415
-            //is not valid, so we'll continue on in the code assuming there's NO GRP_ID.
416
-            $message_template_group = EEM_Message_Template_Group::instance()->get_one_by_ID($GRP_ID);
417
-            if ($message_template_group instanceof EE_Message_Template_Group) {
418
-                $this->_template_collection->add($message_template_group);
419
-                return $message_template_group;
420
-            }
421
-        }
422
-        return null;
423
-    }
424
-
425
-
426
-    /**
427
-     * Returns whether the event ids passed in all share the same message template group for the current message type
428
-     * and messenger.
429
-     *
430
-     * @param array $event_ids
431
-     * @return bool true means they DO share the same message template group, false means they don't.
432
-     * @throws EE_Error
433
-     * @throws InvalidArgumentException
434
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
435
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
436
-     */
437
-    protected function _queue_shares_same_message_template_group_for_events(array $event_ids)
438
-    {
439
-        foreach ($this->_current_data_handler->events as $event) {
440
-            $event_ids[$event['ID']] = $event['ID'];
441
-        }
442
-        $count_of_message_template_groups = EEM_Message_Template_Group::instance()->count(
443
-            array(
444
-                array(
445
-                    'Event.EVT_ID'           => array('IN', $event_ids),
446
-                    'MTP_messenger'    => $this->_current_messenger->name,
447
-                    'MTP_message_type' => $this->_current_message_type->name,
448
-                ),
449
-            ),
450
-            'GRP_ID',
451
-            true
452
-        );
453
-        return $count_of_message_template_groups === 1;
454
-    }
455
-
456
-
457
-    /**
458
-     * This will get the shared message template group for events that are in the current data handler but ONLY if
459
-     * there's a single shared message template group among all the events.  Otherwise it returns null.
460
-     *
461
-     * @param array $event_ids
462
-     * @return EE_Message_Template_Group|null
463
-     * @throws EE_Error
464
-     * @throws InvalidArgumentException
465
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
466
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
467
-     */
468
-    protected function _get_shared_message_template_for_events(array $event_ids)
469
-    {
470
-        $message_template_group = null;
471
-        if ($this->_queue_shares_same_message_template_group_for_events($event_ids)) {
472
-            $message_template_group = EEM_Message_Template_Group::instance()->get_one(
473
-                array(
474
-                    array(
475
-                        'Event.EVT_ID'           => array('IN', $event_ids),
476
-                        'MTP_messenger'    => $this->_current_messenger->name,
477
-                        'MTP_message_type' => $this->_current_message_type->name,
478
-                        'MTP_is_active'    => true,
479
-                    ),
480
-                    'group_by' => 'GRP_ID',
481
-                )
482
-            );
483
-            //store this in the collection if its valid
484
-            if ($message_template_group instanceof EE_Message_Template_Group) {
485
-                $this->_template_collection->add(
486
-                    $message_template_group,
487
-                    $event_ids
488
-                );
489
-            }
490
-        }
491
-        return $message_template_group;
492
-    }
493
-
494
-
495
-    /**
496
-     * Retrieves the global message template group for the current messenger and message type.
497
-     *
498
-     * @return EE_Message_Template_Group|null
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
502
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
503
-     */
504
-    protected function _get_global_message_template_group_for_current_messenger_and_message_type()
505
-    {
506
-        //first check the collection (we use an array with 0 in it to represent global groups).
507
-        $global_message_template_group = $this->_template_collection->get_by_key(
508
-            $this->_template_collection->getKey(
509
-                $this->_current_messenger->name,
510
-                $this->_current_message_type->name,
511
-                array(0)
512
-            )
513
-        );
514
-
515
-        //if we don't have a group lets hit the db.
516
-        if (! $global_message_template_group instanceof EE_Message_Template_Group) {
517
-            $global_message_template_group = EEM_Message_Template_Group::instance()->get_one(
518
-                array(
519
-                    array(
520
-                        'MTP_messenger'    => $this->_current_messenger->name,
521
-                        'MTP_message_type' => $this->_current_message_type->name,
522
-                        'MTP_is_active'    => true,
523
-                        'MTP_is_global'    => true,
524
-                    ),
525
-                )
526
-            );
527
-            //if we have a group, add it to the collection.
528
-            if ($global_message_template_group instanceof EE_Message_Template_Group) {
529
-                $this->_template_collection->add(
530
-                    $global_message_template_group,
531
-                    array(0)
532
-                );
533
-            }
534
-        }
535
-        return $global_message_template_group;
536
-    }
537
-
538
-
539
-    /**
540
-     * Returns an array of event ids for all the events within the current data handler.
541
-     *
542
-     * @return array
543
-     */
544
-    protected function _get_event_ids_from_current_data_handler()
545
-    {
546
-        $event_ids = array();
547
-        foreach ($this->_current_data_handler->events as $event) {
548
-            $event_ids[$event['ID']] = $event['ID'];
549
-        }
550
-        return $event_ids;
551
-    }
552
-
553
-
554
-    /**
555
-     *  Retrieves formatted array of template information for each context specific to the given
556
-     *  EE_Message_Template_Group
557
-     *
558
-     * @param EE_Message_Template_Group $message_template_group
559
-     * @return array The returned array is in this structure:
560
-     *                          array(
561
-     *                          'field_name' => array(
562
-     *                          'context' => 'content'
563
-     *                          )
564
-     *                          )
565
-     * @throws EE_Error
566
-     */
567
-    protected function _get_templates(EE_Message_Template_Group $message_template_group)
568
-    {
569
-        $templates         = array();
570
-        $context_templates = $message_template_group->context_templates();
571
-        foreach ($context_templates as $context => $template_fields) {
572
-            foreach ($template_fields as $template_field => $template_obj) {
573
-                if (! $template_obj instanceof EE_Message_Template) {
574
-                    continue;
575
-                }
576
-                $templates[$template_field][$context] = $template_obj->get('MTP_content');
577
-            }
578
-        }
579
-        return $templates;
580
-    }
581
-
582
-
583
-    /**
584
-     * Assembles new fully generated EE_Message objects and adds to _ready_queue
585
-     *
586
-     * @param array                     $addressees  Array of EE_Messages_Addressee objects indexed by message type
587
-     *                                               context.
588
-     * @param array                     $templates   formatted array of templates used for parsing data.
589
-     * @param EE_Message_Template_Group $message_template_group
590
-     * @return bool true if message generation went a-ok.  false if some sort of exception occurred.  Note: The
591
-     *                                               method will attempt to generate ALL EE_Message objects and add to
592
-     *                                               the _ready_queue.  Successfully generated messages get added to the
593
-     *                                               queue with EEM_Message::status_idle, unsuccessfully generated
594
-     *                                               messages will get added to the queue as EEM_Message::status_failed.
595
-     *                                               Very rarely should "false" be returned from this method.
596
-     * @throws EE_Error
597
-     */
598
-    protected function _assemble_messages($addressees, $templates, EE_Message_Template_Group $message_template_group)
599
-    {
600
-
601
-        //if templates are empty then get out because we can't generate anything.
602
-        if (! $templates) {
603
-            $this->_error_msg[] = esc_html__(
604
-                'Unable to assemble messages because there are no templates retrieved for generating the messages with',
605
-                'event_espresso'
606
-            );
607
-            return false;
608
-        }
609
-
610
-        //We use this as the counter for generated messages because don't forget we may be executing this inside of a
611
-        //generation_queue.  So _ready_queue may have generated EE_Message objects already.
612
-        $generated_count = 0;
613
-        foreach ($addressees as $context => $recipients) {
614
-            foreach ($recipients as $recipient) {
615
-                $message = $this->_setup_message_object($context, $recipient, $templates, $message_template_group);
616
-                if ($message instanceof EE_Message) {
617
-                    $this->_ready_queue->add(
618
-                        $message,
619
-                        array(),
620
-                        $this->_generation_queue->get_message_repository()->is_preview(),
621
-                        $this->_generation_queue->get_message_repository()->is_test_send()
622
-                    );
623
-                    $generated_count++;
624
-                }
625
-
626
-                //if the current MSG being generated is for a test send then we'll only use ONE message in the
627
-                // generation.
628
-                if ($this->_generation_queue->get_message_repository()->is_test_send()) {
629
-                    break 2;
630
-                }
631
-            }
632
-        }
633
-
634
-        //if there are no generated messages then something else fatal went wrong.
635
-        return $generated_count > 0;
636
-    }
637
-
638
-
639
-    /**
640
-     * @param string                    $context   The context for the generated message.
641
-     * @param EE_Messages_Addressee     $recipient
642
-     * @param array                     $templates formatted array of templates used for parsing data.
643
-     * @param EE_Message_Template_Group $message_template_group
644
-     * @return bool|EE_Message
645
-     * @throws EE_Error
646
-     */
647
-    protected function _setup_message_object(
648
-        $context,
649
-        EE_Messages_Addressee $recipient,
650
-        $templates,
651
-        EE_Message_Template_Group $message_template_group
652
-    ) {
653
-        //stuff we already know
654
-        $transaction_id = $recipient->txn instanceof EE_Transaction ? $recipient->txn->ID() : 0;
655
-        $transaction_id = empty($transaction_id) && $this->_current_data_handler->txn instanceof EE_Transaction
656
-            ? $this->_current_data_handler->txn->ID()
657
-            : $transaction_id;
658
-        $message_fields = array(
659
-            'GRP_ID'           => $message_template_group->ID(),
660
-            'TXN_ID'           => $transaction_id,
661
-            'MSG_messenger'    => $this->_current_messenger->name,
662
-            'MSG_message_type' => $this->_current_message_type->name,
663
-            'MSG_context'      => $context,
664
-        );
665
-
666
-        //recipient id and type should be on the EE_Messages_Addressee object but if this is empty, let's try to grab
667
-        // the info from the att_obj found in the EE_Messages_Addressee object.
668
-        if (empty($recipient->recipient_id) || empty($recipient->recipient_type)) {
669
-            $message_fields['MSG_recipient_ID']   = $recipient->att_obj instanceof EE_Attendee
670
-                ? $recipient->att_obj->ID()
671
-                : 0;
672
-            $message_fields['MSG_recipient_type'] = 'Attendee';
673
-        } else {
674
-            $message_fields['MSG_recipient_ID']   = $recipient->recipient_id;
675
-            $message_fields['MSG_recipient_type'] = $recipient->recipient_type;
676
-        }
677
-        $message = EE_Message_Factory::create($message_fields);
678
-
679
-        //grab valid shortcodes for shortcode parser
680
-        $mt_shortcodes = $this->_current_message_type->get_valid_shortcodes();
681
-        $m_shortcodes  = $this->_current_messenger->get_valid_shortcodes();
682
-
683
-        //if the 'to' field is empty or the context is inactive we skip EXCEPT if we're previewing
684
-        if ((
685
-                (
686
-                    empty($templates['to'][$context])
687
-                    && ! $this->_current_messenger->allow_empty_to_field()
688
-                )
689
-                || ! $message_template_group->is_context_active($context)
690
-            )
691
-            && ! $this->_generation_queue->get_message_repository()->is_preview()
692
-        ) {
693
-            //we silently exit here and do NOT record a fail because the message is "turned off" by having no "to"
694
-            //field.
695
-            return false;
696
-        }
697
-        $error_msg = array();
698
-        foreach ($templates as $field => $field_context) {
699
-            $error_msg = array();
700
-            //let's setup the valid shortcodes for the incoming context.
701
-            $valid_shortcodes = $mt_shortcodes[$context];
702
-            //merge in valid shortcodes for the field.
703
-            $shortcodes = isset($m_shortcodes[$field]) ? $m_shortcodes[$field] : $valid_shortcodes;
704
-            if (isset($templates[$field][$context])) {
705
-                //prefix field.
706
-                $column_name = 'MSG_' . $field;
707
-                try {
708
-                    $content = $this->_shortcode_parser->parse_message_template(
709
-                        $templates[$field][$context],
710
-                        $recipient,
711
-                        $shortcodes,
712
-                        $this->_current_message_type,
713
-                        $this->_current_messenger,
714
-                        $message
715
-                    );
716
-                    //the model field removes slashes when setting (usually necessary when the input is from the
717
-                    //request) but this value is from another model and has no slashes. So add them so it matchces
718
-                    //what the field expected (otherwise slashes will have been stripped from this an extra time)
719
-                    $message->set_field_or_extra_meta($column_name, addslashes($content));
720
-                } catch (EE_Error $e) {
721
-                    $error_msg[] = sprintf(
722
-                        esc_html__(
723
-                            'There was a problem generating the content for the field %s: %s',
724
-                            'event_espresso'
725
-                        ),
726
-                        $field,
727
-                        $e->getMessage()
728
-                    );
729
-                    $message->set_STS_ID(EEM_Message::status_failed);
730
-                }
731
-            }
732
-        }
733
-
734
-        if ($message->STS_ID() === EEM_Message::status_failed) {
735
-            $error_msg = esc_html__('There were problems generating this message:', 'event_espresso')
736
-                         . "\n"
737
-                         . implode("\n", $error_msg);
738
-            $message->set_error_message($error_msg);
739
-        } else {
740
-            $message->set_STS_ID(EEM_Message::status_idle);
741
-        }
742
-        return $message;
743
-    }
744
-
745
-
746
-    /**
747
-     * This verifies that the incoming array has a EE_messenger object and a EE_message_type object and sets appropriate
748
-     * error message if either is missing.
749
-     *
750
-     * @return bool true means there were no errors, false means there were errors.
751
-     * @throws EE_Error
752
-     * @throws ReflectionException
753
-     */
754
-    protected function _verify()
755
-    {
756
-        //reset error message to an empty array.
757
-        $this->_error_msg = array();
758
-        $valid            = true;
759
-        $valid            = $valid ? $this->_validate_messenger_and_message_type() : $valid;
760
-        $valid            = $valid ? $this->_validate_and_setup_data() : $valid;
761
-
762
-        //set the verified flag so we know everything has been validated.
763
-        $this->_verified = $valid;
764
-
765
-        return $valid;
766
-    }
767
-
768
-
769
-    /**
770
-     * This accepts an array and validates that it is an array indexed by context with each value being an array of
771
-     * EE_Messages_Addressee objects.
772
-     *
773
-     * @param array $addressees Keys correspond to contexts for the message type and values are EE_Messages_Addressee[]
774
-     * @return bool
775
-     */
776
-    protected function _valid_addressees($addressees)
777
-    {
778
-        if (! $addressees || ! is_array($addressees)) {
779
-            return false;
780
-        }
781
-
782
-        foreach ($addressees as $addressee_array) {
783
-            foreach ($addressee_array as $addressee) {
784
-                if (! $addressee instanceof EE_Messages_Addressee) {
785
-                    return false;
786
-                }
787
-            }
788
-        }
789
-        return true;
790
-    }
791
-
792
-
793
-    /**
794
-     * This validates the messenger, message type, and presences of generation data for the current EE_Message in the
795
-     * queue. This process sets error messages if something is wrong.
796
-     *
797
-     * @return bool   true is if there are no errors.  false is if there is.
798
-     */
799
-    protected function _validate_messenger_and_message_type()
800
-    {
801
-
802
-        //first are there any existing error messages?  If so then return.
803
-        if ($this->_error_msg) {
804
-            return false;
805
-        }
806
-        /** @type EE_Message $message */
807
-        $message = $this->_generation_queue->get_message_repository()->current();
808
-        try {
809
-            $this->_current_messenger = $message->valid_messenger(true)
810
-                ? $message->messenger_object()
811
-                : null;
812
-        } catch (Exception $e) {
813
-            $this->_error_msg[] = $e->getMessage();
814
-        }
815
-        try {
816
-            $this->_current_message_type = $message->valid_message_type(true)
817
-                ? $message->message_type_object()
818
-                : null;
819
-        } catch (Exception $e) {
820
-            $this->_error_msg[] = $e->getMessage();
821
-        }
822
-
823
-        /**
824
-         * Check if there is any generation data, but only if this is not for a preview.
825
-         */
826
-        if (! $this->_generation_queue->get_message_repository()->get_generation_data()
827
-            && (
828
-                ! $this->_generation_queue->get_message_repository()->is_preview()
829
-                && $this->_generation_queue->get_message_repository()->get_data_handler()
830
-                   !== 'EE_Messages_Preview_incoming_data'
831
-            )
832
-        ) {
833
-            $this->_error_msg[] = esc_html__(
834
-                'There is no generation data for this message. Unable to generate.',
835
-                'event_espresso'
836
-            );
837
-        }
838
-
839
-        return empty($this->_error_msg);
840
-    }
841
-
842
-
843
-    /**
844
-     * This method retrieves the expected data handler for the message type and validates the generation data for that
845
-     * data handler.
846
-     *
847
-     * @return bool true means there are no errors.  false means there were errors (and handler did not get setup).
848
-     * @throws EE_Error
849
-     * @throws ReflectionException
850
-     */
851
-    protected function _validate_and_setup_data()
852
-    {
853
-
854
-        //First, are there any existing error messages?  If so, return because if there were errors elsewhere this can't
855
-        //be used anyways.
856
-        if ($this->_error_msg) {
857
-            return false;
858
-        }
859
-
860
-        $generation_data = $this->_generation_queue->get_message_repository()->get_generation_data();
861
-
862
-        /** @type EE_Messages_incoming_data $data_handler_class_name - well not really... just the class name actually*/
863
-        $data_handler_class_name = $this->_generation_queue->get_message_repository()->get_data_handler()
864
-            ? $this->_generation_queue->get_message_repository()->get_data_handler()
865
-            : 'EE_Messages_' . $this->_current_message_type->get_data_handler($generation_data) . '_incoming_data';
866
-
867
-        //If this EE_Message is for a preview, then let's switch out to the preview data handler.
868
-        if ($this->_generation_queue->get_message_repository()->is_preview()) {
869
-            $data_handler_class_name = 'EE_Messages_Preview_incoming_data';
870
-        }
871
-
872
-        //First get the class name for the data handler (and also verifies it exists.
873
-        if (! class_exists($data_handler_class_name)) {
874
-            $this->_error_msg[] = sprintf(
875
-                esc_html__(
876
-                    'The included data handler class name does not match any valid, accessible, "%1$s" classes.  Looking for %2$s.',
877
-                    'event_espresso'
878
-                ),
879
-                'EE_Messages_incoming_data',
880
-                $data_handler_class_name
881
-            );
882
-            return false;
883
-        }
884
-
885
-        //convert generation_data for data_handler_instantiation.
886
-        $generation_data = $data_handler_class_name::convert_data_from_persistent_storage($generation_data);
887
-
888
-        //note, this may set error messages as well.
889
-        $this->_set_data_handler($generation_data, $data_handler_class_name);
890
-
891
-        return empty($this->_error_msg);
892
-    }
893
-
894
-
895
-    /**
896
-     * Sets the $_current_data_handler property that is used for generating the current EE_Message in the queue, and
897
-     * adds it to the _data repository.
898
-     *
899
-     * @param mixed  $generating_data           This is data expected by the instantiated data handler.
900
-     * @param string $data_handler_class_name   This is the reference string indicating what data handler is being
901
-     *                                          instantiated.
902
-     * @return void .
903
-     * @throws EE_Error
904
-     * @throws ReflectionException
905
-     */
906
-    protected function _set_data_handler($generating_data, $data_handler_class_name)
907
-    {
908
-        //valid classname for the data handler.  Now let's setup the key for the data handler repository to see if there
909
-        //is already a ready data handler in the repository.
910
-        $this->_current_data_handler = $this->_data_handler_collection->get_by_key(
911
-            $this->_data_handler_collection->get_key(
912
-                $data_handler_class_name,
913
-                $generating_data
914
-            )
915
-        );
916
-        if (! $this->_current_data_handler instanceof EE_Messages_incoming_data) {
917
-            //no saved data_handler in the repo so let's set one up and add it to the repo.
918
-            try {
919
-                $this->_current_data_handler = new $data_handler_class_name($generating_data);
920
-                $this->_data_handler_collection->add($this->_current_data_handler, $generating_data);
921
-            } catch (EE_Error $e) {
922
-                $this->_error_msg[] = $e->get_error();
923
-            }
924
-        }
925
-    }
926
-
927
-
928
-    /**
929
-     * The queued EE_Message for generation does not save the data used for generation as objects
930
-     * because serialization of those objects could be problematic if the data is saved to the db.
931
-     * So this method calls the static method on the associated data_handler for the given message_type
932
-     * and that preps the data for later instantiation when generating.
933
-     *
934
-     * @param EE_Message_To_Generate $message_to_generate
935
-     * @param bool                   $preview Indicate whether this is being used for a preview or not.
936
-     * @return mixed Prepped data for persisting to the queue.  false is returned if unable to prep data.
937
-     */
938
-    protected function _prepare_data_for_queue(EE_Message_To_Generate $message_to_generate, $preview)
939
-    {
940
-        /** @type EE_Messages_incoming_data $data_handler - well not really... just the class name actually */
941
-        $data_handler = $message_to_generate->get_data_handler_class_name($preview);
942
-        if (! $message_to_generate->valid()) {
943
-            return false; //unable to get the data because the info in the EE_Message_To_Generate class is invalid.
944
-        }
945
-        return $data_handler::convert_data_for_persistent_storage($message_to_generate->data());
946
-    }
947
-
948
-
949
-    /**
950
-     * This sets up a EEM_Message::status_incomplete EE_Message object and adds it to the generation queue.
951
-     *
952
-     * @param EE_Message_To_Generate $message_to_generate
953
-     * @param bool                   $test_send Whether this is just a test send or not.  Typically used for previews.
954
-     * @throws InvalidArgumentException
955
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
956
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
957
-     */
958
-    public function create_and_add_message_to_queue(EE_Message_To_Generate $message_to_generate, $test_send = false)
959
-    {
960
-        //prep data
961
-        $data = $this->_prepare_data_for_queue($message_to_generate, $message_to_generate->preview());
962
-
963
-        $message = $message_to_generate->get_EE_Message();
964
-
965
-        //is there a GRP_ID in the request?
966
-        if ($GRP_ID = EE_Registry::instance()->REQ->get('GRP_ID')) {
967
-            $message->set_GRP_ID($GRP_ID);
968
-        }
969
-
970
-        if ($data === false) {
971
-            $message->set_STS_ID(EEM_Message::status_failed);
972
-            $message->set_error_message(
973
-                esc_html__(
974
-                    'Unable to prepare data for persistence to the database.',
975
-                    'event_espresso'
976
-                )
977
-            );
978
-        } else {
979
-            //make sure that the data handler is cached on the message as well
980
-            $data['data_handler_class_name'] = $message_to_generate->get_data_handler_class_name();
981
-        }
982
-
983
-        $this->_generation_queue->add($message, $data, $message_to_generate->preview(), $test_send);
984
-    }
16
+	/**
17
+	 * @type EE_Messages_Data_Handler_Collection
18
+	 */
19
+	protected $_data_handler_collection;
20
+
21
+	/**
22
+	 * @type  EE_Message_Template_Group_Collection
23
+	 */
24
+	protected $_template_collection;
25
+
26
+	/**
27
+	 * This will hold the data handler for the current EE_Message being generated.
28
+	 *
29
+	 * @type EE_Messages_incoming_data
30
+	 */
31
+	protected $_current_data_handler;
32
+
33
+	/**
34
+	 * This holds the EE_Messages_Queue that contains the messages to generate.
35
+	 *
36
+	 * @type EE_Messages_Queue
37
+	 */
38
+	protected $_generation_queue;
39
+
40
+	/**
41
+	 * This holds the EE_Messages_Queue that will store the generated EE_Message objects.
42
+	 *
43
+	 * @type EE_Messages_Queue
44
+	 */
45
+	protected $_ready_queue;
46
+
47
+	/**
48
+	 * This is a container for any error messages that get created through the generation
49
+	 * process.
50
+	 *
51
+	 * @type array
52
+	 */
53
+	protected $_error_msg = array();
54
+
55
+	/**
56
+	 * Flag used to set when the current EE_Message in the generation queue has been verified.
57
+	 *
58
+	 * @type bool
59
+	 */
60
+	protected $_verified = false;
61
+
62
+	/**
63
+	 * This will hold the current messenger object corresponding with the current EE_Message in the generation queue.
64
+	 *
65
+	 * @type EE_messenger
66
+	 */
67
+	protected $_current_messenger;
68
+
69
+	/**
70
+	 * This will hold the current message type object corresponding with the current EE_Message in the generation queue.
71
+	 *
72
+	 * @type EE_message_type
73
+	 */
74
+	protected $_current_message_type;
75
+
76
+	/**
77
+	 * @type EEH_Parse_Shortcodes
78
+	 */
79
+	protected $_shortcode_parser;
80
+
81
+
82
+	/**
83
+	 * @param EE_Messages_Queue                     $generation_queue
84
+	 * @param \EE_Messages_Queue                    $ready_queue
85
+	 * @param \EE_Messages_Data_Handler_Collection  $data_handler_collection
86
+	 * @param \EE_Message_Template_Group_Collection $template_collection
87
+	 * @param \EEH_Parse_Shortcodes                 $shortcode_parser
88
+	 */
89
+	public function __construct(
90
+		EE_Messages_Queue $generation_queue,
91
+		EE_Messages_Queue $ready_queue,
92
+		EE_Messages_Data_Handler_Collection $data_handler_collection,
93
+		EE_Message_Template_Group_Collection $template_collection,
94
+		EEH_Parse_Shortcodes $shortcode_parser
95
+	) {
96
+		$this->_generation_queue        = $generation_queue;
97
+		$this->_ready_queue             = $ready_queue;
98
+		$this->_data_handler_collection = $data_handler_collection;
99
+		$this->_template_collection     = $template_collection;
100
+		$this->_shortcode_parser        = $shortcode_parser;
101
+	}
102
+
103
+
104
+	/**
105
+	 * @return EE_Messages_Queue
106
+	 */
107
+	public function generation_queue()
108
+	{
109
+		return $this->_generation_queue;
110
+	}
111
+
112
+
113
+	/**
114
+	 *  This iterates through the provided queue and generates the EE_Message objects.
115
+	 *  When iterating through the queue, the queued item that served as the base for generating other EE_Message
116
+	 *  objects gets removed and the new EE_Message objects get added to a NEW queue.  The NEW queue is then returned
117
+	 *  for the caller to decide what to do with it.
118
+	 *
119
+	 * @param   bool $save Whether to save the EE_Message objects in the new queue or just return.
120
+	 * @return EE_Messages_Queue The new queue for holding generated EE_Message objects.
121
+	 * @throws EE_Error
122
+	 * @throws ReflectionException
123
+	 */
124
+	public function generate($save = true)
125
+	{
126
+		//iterate through the messages in the queue, generate, and add to new queue.
127
+		$this->_generation_queue->get_message_repository()->rewind();
128
+		while ($this->_generation_queue->get_message_repository()->valid()) {
129
+			//reset "current" properties
130
+			$this->_reset_current_properties();
131
+
132
+			/** @type EE_Message $msg */
133
+			$msg = $this->_generation_queue->get_message_repository()->current();
134
+
135
+			/**
136
+			 * need to get the next object and capture it for setting manually after deletes.  The reason is that when
137
+			 * an object is removed from the repo then valid for the next object will fail.
138
+			 */
139
+			$this->_generation_queue->get_message_repository()->next();
140
+			$next_msg = $this->_generation_queue->get_message_repository()->current();
141
+			//restore pointer to current item
142
+			$this->_generation_queue->get_message_repository()->set_current($msg);
143
+
144
+			//skip and delete if the current $msg is NOT incomplete (queued for generation)
145
+			if ($msg->STS_ID() !== EEM_Message::status_incomplete) {
146
+				//we keep this item in the db just remove from the repo.
147
+				$this->_generation_queue->get_message_repository()->remove($msg);
148
+				//next item
149
+				$this->_generation_queue->get_message_repository()->set_current($next_msg);
150
+				continue;
151
+			}
152
+
153
+			if ($this->_verify()) {
154
+				//let's get generating!
155
+				$this->_generate();
156
+			}
157
+
158
+			//don't persist debug_only messages if the messages system is not in debug mode.
159
+			if ($msg->STS_ID() === EEM_Message::status_debug_only
160
+				&& ! EEM_Message::debug()
161
+			) {
162
+				do_action(
163
+					'AHEE__EE_Messages_Generator__generate__before_debug_delete',
164
+					$msg,
165
+					$this->_error_msg,
166
+					$this->_current_messenger,
167
+					$this->_current_message_type,
168
+					$this->_current_data_handler
169
+				);
170
+				$this->_generation_queue->get_message_repository()->delete();
171
+				$this->_generation_queue->get_message_repository()->set_current($next_msg);
172
+				continue;
173
+			}
174
+
175
+			//if there are error messages then let's set the status and the error message.
176
+			if ($this->_error_msg) {
177
+				//if the status is already debug only, then let's leave it at that.
178
+				if ($msg->STS_ID() !== EEM_Message::status_debug_only) {
179
+					$msg->set_STS_ID(EEM_Message::status_failed);
180
+				}
181
+				do_action(
182
+					'AHEE__EE_Messages_Generator__generate__processing_failed_message',
183
+					$msg,
184
+					$this->_error_msg,
185
+					$this->_current_messenger,
186
+					$this->_current_message_type,
187
+					$this->_current_data_handler
188
+				);
189
+				$msg->set_error_message(
190
+					esc_html__('Message failed to generate for the following reasons: ', 'event_espresso')
191
+					. "\n"
192
+					. implode("\n", $this->_error_msg)
193
+				);
194
+				$msg->set_modified(time());
195
+			} else {
196
+				do_action(
197
+					'AHEE__EE_Messages_Generator__generate__before_successful_generated_message_delete',
198
+					$msg,
199
+					$this->_error_msg,
200
+					$this->_current_messenger,
201
+					$this->_current_message_type,
202
+					$this->_current_data_handler
203
+				);
204
+				//remove from db
205
+				$this->_generation_queue->get_message_repository()->delete();
206
+			}
207
+			//next item
208
+			$this->_generation_queue->get_message_repository()->set_current($next_msg);
209
+		}
210
+
211
+		//generation queue is ALWAYS saved to record any errors in the generation process.
212
+		$this->_generation_queue->save();
213
+
214
+		/**
215
+		 * save _ready_queue if flag set.
216
+		 * Note: The EE_Message objects have values set via the EE_Base_Class::set_field_or_extra_meta() method.  This
217
+		 * means if a field was added that is not a valid database column.  The EE_Message was already saved to the db
218
+		 * so a EE_Extra_Meta entry could be created and attached to the EE_Message.  In those cases the save flag is
219
+		 * irrelevant.
220
+		 */
221
+		if ($save) {
222
+			$this->_ready_queue->save();
223
+		}
224
+
225
+		//final reset of properties
226
+		$this->_reset_current_properties();
227
+
228
+		return $this->_ready_queue;
229
+	}
230
+
231
+
232
+	/**
233
+	 * This resets all the properties used for holding "current" values corresponding to the current EE_Message object
234
+	 * in the generation queue.
235
+	 */
236
+	protected function _reset_current_properties()
237
+	{
238
+		$this->_verified = false;
239
+		//make sure any _data value in the current message type is reset
240
+		if ($this->_current_message_type instanceof EE_message_type) {
241
+			$this->_current_message_type->reset_data();
242
+		}
243
+		$this->_current_messenger = $this->_current_message_type = $this->_current_data_handler = null;
244
+	}
245
+
246
+
247
+	/**
248
+	 * This proceeds with the actual generation of a message.  By the time this is called, there should already be a
249
+	 * $_current_data_handler set and all incoming information should be validated for the current EE_Message in the
250
+	 * _generating_queue.
251
+	 *
252
+	 * @return bool Whether the message was successfully generated or not.
253
+	 * @throws EE_Error
254
+	 * @throws InvalidArgumentException
255
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
256
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
257
+	 */
258
+	protected function _generate()
259
+	{
260
+		//double check verification has run and that everything is ready to work with (saves us having to validate
261
+		// everything again).
262
+		if (! $this->_verified) {
263
+			return false; //get out because we don't have a valid setup to work with.
264
+		}
265
+
266
+
267
+		try {
268
+			$addressees = $this->_current_message_type->get_addressees(
269
+				$this->_current_data_handler,
270
+				$this->_generation_queue->get_message_repository()->current()->context()
271
+			);
272
+		} catch (EE_Error $e) {
273
+			$this->_error_msg[] = $e->getMessage();
274
+			return false;
275
+		}
276
+
277
+
278
+		//if no addressees then get out because there is nothing to generation (possible bad data).
279
+		if (! $this->_valid_addressees($addressees)) {
280
+			do_action(
281
+				'AHEE__EE_Messages_Generator___generate__invalid_addressees',
282
+				$this->_generation_queue->get_message_repository()->current(),
283
+				$addressees,
284
+				$this->_current_messenger,
285
+				$this->_current_message_type,
286
+				$this->_current_data_handler
287
+			);
288
+			$this->_generation_queue->get_message_repository()->current()->set_STS_ID(
289
+				EEM_Message::status_debug_only
290
+			);
291
+			$this->_error_msg[] = esc_html__(
292
+				'This is not a critical error but an informational notice. Unable to generate messages EE_Messages_Addressee objects.  There were no attendees prepared by the data handler. Sometimes this is because messages only get generated for certain registration statuses. For example, the ticket notice message type only goes to approved registrations.',
293
+				'event_espresso'
294
+			);
295
+			return false;
296
+		}
297
+
298
+		$message_template_group = $this->_get_message_template_group();
299
+
300
+		//in the unlikely event there is no EE_Message_Template_Group available, get out!
301
+		if (! $message_template_group instanceof EE_Message_Template_Group) {
302
+			$this->_error_msg[] = esc_html__(
303
+				'Unable to get the Message Templates for the Message being generated.  No message template group accessible.',
304
+				'event_espresso'
305
+			);
306
+			return false;
307
+		}
308
+
309
+		//get formatted templates for using to parse and setup EE_Message objects.
310
+		$templates = $this->_get_templates($message_template_group);
311
+
312
+
313
+		//setup new EE_Message objects (and add to _ready_queue)
314
+		return $this->_assemble_messages($addressees, $templates, $message_template_group);
315
+	}
316
+
317
+
318
+	/**
319
+	 * Retrieves the message template group being used for generating messages.
320
+	 * Note: this also utilizes the EE_Message_Template_Group_Collection to avoid having to hit the db multiple times.
321
+	 *
322
+	 * @return EE_Message_Template_Group|null
323
+	 * @throws EE_Error
324
+	 * @throws InvalidArgumentException
325
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
326
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
327
+	 */
328
+	protected function _get_message_template_group()
329
+	{
330
+		//first see if there is a specific message template group requested (current message in the queue has a specific
331
+		//GRP_ID
332
+		$message_template_group = $this->_specific_message_template_group_from_queue();
333
+		if ($message_template_group instanceof EE_Message_Template_Group) {
334
+			return $message_template_group;
335
+		}
336
+
337
+		//get event_ids from the datahandler so we can check to see if there's already a message template group for them
338
+		//in the collection.
339
+		$event_ids              = $this->_get_event_ids_from_current_data_handler();
340
+		$message_template_group = $this->_template_collection->get_by_key(
341
+			$this->_template_collection->getKey(
342
+				$this->_current_messenger->name,
343
+				$this->_current_message_type->name,
344
+				$event_ids
345
+			)
346
+		);
347
+
348
+		//if we have a message template group then no need to hit the database, just return it.
349
+		if ($message_template_group instanceof EE_Message_Template_Group) {
350
+			return $message_template_group;
351
+		}
352
+
353
+		//okay made it here, so let's get the global group first for this messenger and message type to ensure
354
+		//there is no override set.
355
+		$global_message_template_group =
356
+			$this->_get_global_message_template_group_for_current_messenger_and_message_type();
357
+
358
+		if ($global_message_template_group instanceof EE_Message_Template_Group
359
+			&& $global_message_template_group->get('MTP_is_override')
360
+		) {
361
+			return $global_message_template_group;
362
+		}
363
+
364
+		//if we're still here, that means there was no message template group for the events in the collection and
365
+		//the global message template group for the messenger and message type is not set for override.  So next step is
366
+		//to see if there is a common shared custom message template group for this set of events.
367
+		$message_template_group = $this->_get_shared_message_template_for_events($event_ids);
368
+		if ($message_template_group instanceof EE_Message_Template_Group) {
369
+			return $message_template_group;
370
+		}
371
+
372
+		//STILL here?  Okay that means the fallback is to just use the global message template group for this event set.
373
+		//So we'll cache the global group for this event set (so this logic doesn't have to be repeated in this request)
374
+		//and return it.
375
+		if ($global_message_template_group instanceof EE_Message_Template_Group) {
376
+			$this->_template_collection->add(
377
+				$global_message_template_group,
378
+				$event_ids
379
+			);
380
+			return $global_message_template_group;
381
+		}
382
+
383
+		//if we land here that means there's NO active message template group for this set.
384
+		//TODO this will be a good target for some optimization down the road.  Whenever there is no active message
385
+		//template group for a given event set then cache that result so we don't repeat the logic.  However, for now,
386
+		//this should likely bit hit rarely enough that it's not a significant issue.
387
+		return null;
388
+	}
389
+
390
+
391
+	/**
392
+	 * This checks the current message in the queue and determines if there is a specific Message Template Group
393
+	 * requested for that message.
394
+	 *
395
+	 * @return EE_Message_Template_Group|null
396
+	 * @throws EE_Error
397
+	 * @throws InvalidArgumentException
398
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
399
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
400
+	 */
401
+	protected function _specific_message_template_group_from_queue()
402
+	{
403
+		//is there a GRP_ID already on the EE_Message object?  If there is, then a specific template has been requested
404
+		//so let's use that.
405
+		$GRP_ID = $this->_generation_queue->get_message_repository()->current()->GRP_ID();
406
+
407
+		if ($GRP_ID) {
408
+			//attempt to retrieve from repo first
409
+			$message_template_group = $this->_template_collection->get_by_ID($GRP_ID);
410
+			if ($message_template_group instanceof EE_Message_Template_Group) {
411
+				return $message_template_group;  //got it!
412
+			}
413
+
414
+			//nope don't have it yet.  Get from DB then add to repo if its not here, then that means the current GRP_ID
415
+			//is not valid, so we'll continue on in the code assuming there's NO GRP_ID.
416
+			$message_template_group = EEM_Message_Template_Group::instance()->get_one_by_ID($GRP_ID);
417
+			if ($message_template_group instanceof EE_Message_Template_Group) {
418
+				$this->_template_collection->add($message_template_group);
419
+				return $message_template_group;
420
+			}
421
+		}
422
+		return null;
423
+	}
424
+
425
+
426
+	/**
427
+	 * Returns whether the event ids passed in all share the same message template group for the current message type
428
+	 * and messenger.
429
+	 *
430
+	 * @param array $event_ids
431
+	 * @return bool true means they DO share the same message template group, false means they don't.
432
+	 * @throws EE_Error
433
+	 * @throws InvalidArgumentException
434
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
435
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
436
+	 */
437
+	protected function _queue_shares_same_message_template_group_for_events(array $event_ids)
438
+	{
439
+		foreach ($this->_current_data_handler->events as $event) {
440
+			$event_ids[$event['ID']] = $event['ID'];
441
+		}
442
+		$count_of_message_template_groups = EEM_Message_Template_Group::instance()->count(
443
+			array(
444
+				array(
445
+					'Event.EVT_ID'           => array('IN', $event_ids),
446
+					'MTP_messenger'    => $this->_current_messenger->name,
447
+					'MTP_message_type' => $this->_current_message_type->name,
448
+				),
449
+			),
450
+			'GRP_ID',
451
+			true
452
+		);
453
+		return $count_of_message_template_groups === 1;
454
+	}
455
+
456
+
457
+	/**
458
+	 * This will get the shared message template group for events that are in the current data handler but ONLY if
459
+	 * there's a single shared message template group among all the events.  Otherwise it returns null.
460
+	 *
461
+	 * @param array $event_ids
462
+	 * @return EE_Message_Template_Group|null
463
+	 * @throws EE_Error
464
+	 * @throws InvalidArgumentException
465
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
466
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
467
+	 */
468
+	protected function _get_shared_message_template_for_events(array $event_ids)
469
+	{
470
+		$message_template_group = null;
471
+		if ($this->_queue_shares_same_message_template_group_for_events($event_ids)) {
472
+			$message_template_group = EEM_Message_Template_Group::instance()->get_one(
473
+				array(
474
+					array(
475
+						'Event.EVT_ID'           => array('IN', $event_ids),
476
+						'MTP_messenger'    => $this->_current_messenger->name,
477
+						'MTP_message_type' => $this->_current_message_type->name,
478
+						'MTP_is_active'    => true,
479
+					),
480
+					'group_by' => 'GRP_ID',
481
+				)
482
+			);
483
+			//store this in the collection if its valid
484
+			if ($message_template_group instanceof EE_Message_Template_Group) {
485
+				$this->_template_collection->add(
486
+					$message_template_group,
487
+					$event_ids
488
+				);
489
+			}
490
+		}
491
+		return $message_template_group;
492
+	}
493
+
494
+
495
+	/**
496
+	 * Retrieves the global message template group for the current messenger and message type.
497
+	 *
498
+	 * @return EE_Message_Template_Group|null
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
502
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
503
+	 */
504
+	protected function _get_global_message_template_group_for_current_messenger_and_message_type()
505
+	{
506
+		//first check the collection (we use an array with 0 in it to represent global groups).
507
+		$global_message_template_group = $this->_template_collection->get_by_key(
508
+			$this->_template_collection->getKey(
509
+				$this->_current_messenger->name,
510
+				$this->_current_message_type->name,
511
+				array(0)
512
+			)
513
+		);
514
+
515
+		//if we don't have a group lets hit the db.
516
+		if (! $global_message_template_group instanceof EE_Message_Template_Group) {
517
+			$global_message_template_group = EEM_Message_Template_Group::instance()->get_one(
518
+				array(
519
+					array(
520
+						'MTP_messenger'    => $this->_current_messenger->name,
521
+						'MTP_message_type' => $this->_current_message_type->name,
522
+						'MTP_is_active'    => true,
523
+						'MTP_is_global'    => true,
524
+					),
525
+				)
526
+			);
527
+			//if we have a group, add it to the collection.
528
+			if ($global_message_template_group instanceof EE_Message_Template_Group) {
529
+				$this->_template_collection->add(
530
+					$global_message_template_group,
531
+					array(0)
532
+				);
533
+			}
534
+		}
535
+		return $global_message_template_group;
536
+	}
537
+
538
+
539
+	/**
540
+	 * Returns an array of event ids for all the events within the current data handler.
541
+	 *
542
+	 * @return array
543
+	 */
544
+	protected function _get_event_ids_from_current_data_handler()
545
+	{
546
+		$event_ids = array();
547
+		foreach ($this->_current_data_handler->events as $event) {
548
+			$event_ids[$event['ID']] = $event['ID'];
549
+		}
550
+		return $event_ids;
551
+	}
552
+
553
+
554
+	/**
555
+	 *  Retrieves formatted array of template information for each context specific to the given
556
+	 *  EE_Message_Template_Group
557
+	 *
558
+	 * @param EE_Message_Template_Group $message_template_group
559
+	 * @return array The returned array is in this structure:
560
+	 *                          array(
561
+	 *                          'field_name' => array(
562
+	 *                          'context' => 'content'
563
+	 *                          )
564
+	 *                          )
565
+	 * @throws EE_Error
566
+	 */
567
+	protected function _get_templates(EE_Message_Template_Group $message_template_group)
568
+	{
569
+		$templates         = array();
570
+		$context_templates = $message_template_group->context_templates();
571
+		foreach ($context_templates as $context => $template_fields) {
572
+			foreach ($template_fields as $template_field => $template_obj) {
573
+				if (! $template_obj instanceof EE_Message_Template) {
574
+					continue;
575
+				}
576
+				$templates[$template_field][$context] = $template_obj->get('MTP_content');
577
+			}
578
+		}
579
+		return $templates;
580
+	}
581
+
582
+
583
+	/**
584
+	 * Assembles new fully generated EE_Message objects and adds to _ready_queue
585
+	 *
586
+	 * @param array                     $addressees  Array of EE_Messages_Addressee objects indexed by message type
587
+	 *                                               context.
588
+	 * @param array                     $templates   formatted array of templates used for parsing data.
589
+	 * @param EE_Message_Template_Group $message_template_group
590
+	 * @return bool true if message generation went a-ok.  false if some sort of exception occurred.  Note: The
591
+	 *                                               method will attempt to generate ALL EE_Message objects and add to
592
+	 *                                               the _ready_queue.  Successfully generated messages get added to the
593
+	 *                                               queue with EEM_Message::status_idle, unsuccessfully generated
594
+	 *                                               messages will get added to the queue as EEM_Message::status_failed.
595
+	 *                                               Very rarely should "false" be returned from this method.
596
+	 * @throws EE_Error
597
+	 */
598
+	protected function _assemble_messages($addressees, $templates, EE_Message_Template_Group $message_template_group)
599
+	{
600
+
601
+		//if templates are empty then get out because we can't generate anything.
602
+		if (! $templates) {
603
+			$this->_error_msg[] = esc_html__(
604
+				'Unable to assemble messages because there are no templates retrieved for generating the messages with',
605
+				'event_espresso'
606
+			);
607
+			return false;
608
+		}
609
+
610
+		//We use this as the counter for generated messages because don't forget we may be executing this inside of a
611
+		//generation_queue.  So _ready_queue may have generated EE_Message objects already.
612
+		$generated_count = 0;
613
+		foreach ($addressees as $context => $recipients) {
614
+			foreach ($recipients as $recipient) {
615
+				$message = $this->_setup_message_object($context, $recipient, $templates, $message_template_group);
616
+				if ($message instanceof EE_Message) {
617
+					$this->_ready_queue->add(
618
+						$message,
619
+						array(),
620
+						$this->_generation_queue->get_message_repository()->is_preview(),
621
+						$this->_generation_queue->get_message_repository()->is_test_send()
622
+					);
623
+					$generated_count++;
624
+				}
625
+
626
+				//if the current MSG being generated is for a test send then we'll only use ONE message in the
627
+				// generation.
628
+				if ($this->_generation_queue->get_message_repository()->is_test_send()) {
629
+					break 2;
630
+				}
631
+			}
632
+		}
633
+
634
+		//if there are no generated messages then something else fatal went wrong.
635
+		return $generated_count > 0;
636
+	}
637
+
638
+
639
+	/**
640
+	 * @param string                    $context   The context for the generated message.
641
+	 * @param EE_Messages_Addressee     $recipient
642
+	 * @param array                     $templates formatted array of templates used for parsing data.
643
+	 * @param EE_Message_Template_Group $message_template_group
644
+	 * @return bool|EE_Message
645
+	 * @throws EE_Error
646
+	 */
647
+	protected function _setup_message_object(
648
+		$context,
649
+		EE_Messages_Addressee $recipient,
650
+		$templates,
651
+		EE_Message_Template_Group $message_template_group
652
+	) {
653
+		//stuff we already know
654
+		$transaction_id = $recipient->txn instanceof EE_Transaction ? $recipient->txn->ID() : 0;
655
+		$transaction_id = empty($transaction_id) && $this->_current_data_handler->txn instanceof EE_Transaction
656
+			? $this->_current_data_handler->txn->ID()
657
+			: $transaction_id;
658
+		$message_fields = array(
659
+			'GRP_ID'           => $message_template_group->ID(),
660
+			'TXN_ID'           => $transaction_id,
661
+			'MSG_messenger'    => $this->_current_messenger->name,
662
+			'MSG_message_type' => $this->_current_message_type->name,
663
+			'MSG_context'      => $context,
664
+		);
665
+
666
+		//recipient id and type should be on the EE_Messages_Addressee object but if this is empty, let's try to grab
667
+		// the info from the att_obj found in the EE_Messages_Addressee object.
668
+		if (empty($recipient->recipient_id) || empty($recipient->recipient_type)) {
669
+			$message_fields['MSG_recipient_ID']   = $recipient->att_obj instanceof EE_Attendee
670
+				? $recipient->att_obj->ID()
671
+				: 0;
672
+			$message_fields['MSG_recipient_type'] = 'Attendee';
673
+		} else {
674
+			$message_fields['MSG_recipient_ID']   = $recipient->recipient_id;
675
+			$message_fields['MSG_recipient_type'] = $recipient->recipient_type;
676
+		}
677
+		$message = EE_Message_Factory::create($message_fields);
678
+
679
+		//grab valid shortcodes for shortcode parser
680
+		$mt_shortcodes = $this->_current_message_type->get_valid_shortcodes();
681
+		$m_shortcodes  = $this->_current_messenger->get_valid_shortcodes();
682
+
683
+		//if the 'to' field is empty or the context is inactive we skip EXCEPT if we're previewing
684
+		if ((
685
+				(
686
+					empty($templates['to'][$context])
687
+					&& ! $this->_current_messenger->allow_empty_to_field()
688
+				)
689
+				|| ! $message_template_group->is_context_active($context)
690
+			)
691
+			&& ! $this->_generation_queue->get_message_repository()->is_preview()
692
+		) {
693
+			//we silently exit here and do NOT record a fail because the message is "turned off" by having no "to"
694
+			//field.
695
+			return false;
696
+		}
697
+		$error_msg = array();
698
+		foreach ($templates as $field => $field_context) {
699
+			$error_msg = array();
700
+			//let's setup the valid shortcodes for the incoming context.
701
+			$valid_shortcodes = $mt_shortcodes[$context];
702
+			//merge in valid shortcodes for the field.
703
+			$shortcodes = isset($m_shortcodes[$field]) ? $m_shortcodes[$field] : $valid_shortcodes;
704
+			if (isset($templates[$field][$context])) {
705
+				//prefix field.
706
+				$column_name = 'MSG_' . $field;
707
+				try {
708
+					$content = $this->_shortcode_parser->parse_message_template(
709
+						$templates[$field][$context],
710
+						$recipient,
711
+						$shortcodes,
712
+						$this->_current_message_type,
713
+						$this->_current_messenger,
714
+						$message
715
+					);
716
+					//the model field removes slashes when setting (usually necessary when the input is from the
717
+					//request) but this value is from another model and has no slashes. So add them so it matchces
718
+					//what the field expected (otherwise slashes will have been stripped from this an extra time)
719
+					$message->set_field_or_extra_meta($column_name, addslashes($content));
720
+				} catch (EE_Error $e) {
721
+					$error_msg[] = sprintf(
722
+						esc_html__(
723
+							'There was a problem generating the content for the field %s: %s',
724
+							'event_espresso'
725
+						),
726
+						$field,
727
+						$e->getMessage()
728
+					);
729
+					$message->set_STS_ID(EEM_Message::status_failed);
730
+				}
731
+			}
732
+		}
733
+
734
+		if ($message->STS_ID() === EEM_Message::status_failed) {
735
+			$error_msg = esc_html__('There were problems generating this message:', 'event_espresso')
736
+						 . "\n"
737
+						 . implode("\n", $error_msg);
738
+			$message->set_error_message($error_msg);
739
+		} else {
740
+			$message->set_STS_ID(EEM_Message::status_idle);
741
+		}
742
+		return $message;
743
+	}
744
+
745
+
746
+	/**
747
+	 * This verifies that the incoming array has a EE_messenger object and a EE_message_type object and sets appropriate
748
+	 * error message if either is missing.
749
+	 *
750
+	 * @return bool true means there were no errors, false means there were errors.
751
+	 * @throws EE_Error
752
+	 * @throws ReflectionException
753
+	 */
754
+	protected function _verify()
755
+	{
756
+		//reset error message to an empty array.
757
+		$this->_error_msg = array();
758
+		$valid            = true;
759
+		$valid            = $valid ? $this->_validate_messenger_and_message_type() : $valid;
760
+		$valid            = $valid ? $this->_validate_and_setup_data() : $valid;
761
+
762
+		//set the verified flag so we know everything has been validated.
763
+		$this->_verified = $valid;
764
+
765
+		return $valid;
766
+	}
767
+
768
+
769
+	/**
770
+	 * This accepts an array and validates that it is an array indexed by context with each value being an array of
771
+	 * EE_Messages_Addressee objects.
772
+	 *
773
+	 * @param array $addressees Keys correspond to contexts for the message type and values are EE_Messages_Addressee[]
774
+	 * @return bool
775
+	 */
776
+	protected function _valid_addressees($addressees)
777
+	{
778
+		if (! $addressees || ! is_array($addressees)) {
779
+			return false;
780
+		}
781
+
782
+		foreach ($addressees as $addressee_array) {
783
+			foreach ($addressee_array as $addressee) {
784
+				if (! $addressee instanceof EE_Messages_Addressee) {
785
+					return false;
786
+				}
787
+			}
788
+		}
789
+		return true;
790
+	}
791
+
792
+
793
+	/**
794
+	 * This validates the messenger, message type, and presences of generation data for the current EE_Message in the
795
+	 * queue. This process sets error messages if something is wrong.
796
+	 *
797
+	 * @return bool   true is if there are no errors.  false is if there is.
798
+	 */
799
+	protected function _validate_messenger_and_message_type()
800
+	{
801
+
802
+		//first are there any existing error messages?  If so then return.
803
+		if ($this->_error_msg) {
804
+			return false;
805
+		}
806
+		/** @type EE_Message $message */
807
+		$message = $this->_generation_queue->get_message_repository()->current();
808
+		try {
809
+			$this->_current_messenger = $message->valid_messenger(true)
810
+				? $message->messenger_object()
811
+				: null;
812
+		} catch (Exception $e) {
813
+			$this->_error_msg[] = $e->getMessage();
814
+		}
815
+		try {
816
+			$this->_current_message_type = $message->valid_message_type(true)
817
+				? $message->message_type_object()
818
+				: null;
819
+		} catch (Exception $e) {
820
+			$this->_error_msg[] = $e->getMessage();
821
+		}
822
+
823
+		/**
824
+		 * Check if there is any generation data, but only if this is not for a preview.
825
+		 */
826
+		if (! $this->_generation_queue->get_message_repository()->get_generation_data()
827
+			&& (
828
+				! $this->_generation_queue->get_message_repository()->is_preview()
829
+				&& $this->_generation_queue->get_message_repository()->get_data_handler()
830
+				   !== 'EE_Messages_Preview_incoming_data'
831
+			)
832
+		) {
833
+			$this->_error_msg[] = esc_html__(
834
+				'There is no generation data for this message. Unable to generate.',
835
+				'event_espresso'
836
+			);
837
+		}
838
+
839
+		return empty($this->_error_msg);
840
+	}
841
+
842
+
843
+	/**
844
+	 * This method retrieves the expected data handler for the message type and validates the generation data for that
845
+	 * data handler.
846
+	 *
847
+	 * @return bool true means there are no errors.  false means there were errors (and handler did not get setup).
848
+	 * @throws EE_Error
849
+	 * @throws ReflectionException
850
+	 */
851
+	protected function _validate_and_setup_data()
852
+	{
853
+
854
+		//First, are there any existing error messages?  If so, return because if there were errors elsewhere this can't
855
+		//be used anyways.
856
+		if ($this->_error_msg) {
857
+			return false;
858
+		}
859
+
860
+		$generation_data = $this->_generation_queue->get_message_repository()->get_generation_data();
861
+
862
+		/** @type EE_Messages_incoming_data $data_handler_class_name - well not really... just the class name actually*/
863
+		$data_handler_class_name = $this->_generation_queue->get_message_repository()->get_data_handler()
864
+			? $this->_generation_queue->get_message_repository()->get_data_handler()
865
+			: 'EE_Messages_' . $this->_current_message_type->get_data_handler($generation_data) . '_incoming_data';
866
+
867
+		//If this EE_Message is for a preview, then let's switch out to the preview data handler.
868
+		if ($this->_generation_queue->get_message_repository()->is_preview()) {
869
+			$data_handler_class_name = 'EE_Messages_Preview_incoming_data';
870
+		}
871
+
872
+		//First get the class name for the data handler (and also verifies it exists.
873
+		if (! class_exists($data_handler_class_name)) {
874
+			$this->_error_msg[] = sprintf(
875
+				esc_html__(
876
+					'The included data handler class name does not match any valid, accessible, "%1$s" classes.  Looking for %2$s.',
877
+					'event_espresso'
878
+				),
879
+				'EE_Messages_incoming_data',
880
+				$data_handler_class_name
881
+			);
882
+			return false;
883
+		}
884
+
885
+		//convert generation_data for data_handler_instantiation.
886
+		$generation_data = $data_handler_class_name::convert_data_from_persistent_storage($generation_data);
887
+
888
+		//note, this may set error messages as well.
889
+		$this->_set_data_handler($generation_data, $data_handler_class_name);
890
+
891
+		return empty($this->_error_msg);
892
+	}
893
+
894
+
895
+	/**
896
+	 * Sets the $_current_data_handler property that is used for generating the current EE_Message in the queue, and
897
+	 * adds it to the _data repository.
898
+	 *
899
+	 * @param mixed  $generating_data           This is data expected by the instantiated data handler.
900
+	 * @param string $data_handler_class_name   This is the reference string indicating what data handler is being
901
+	 *                                          instantiated.
902
+	 * @return void .
903
+	 * @throws EE_Error
904
+	 * @throws ReflectionException
905
+	 */
906
+	protected function _set_data_handler($generating_data, $data_handler_class_name)
907
+	{
908
+		//valid classname for the data handler.  Now let's setup the key for the data handler repository to see if there
909
+		//is already a ready data handler in the repository.
910
+		$this->_current_data_handler = $this->_data_handler_collection->get_by_key(
911
+			$this->_data_handler_collection->get_key(
912
+				$data_handler_class_name,
913
+				$generating_data
914
+			)
915
+		);
916
+		if (! $this->_current_data_handler instanceof EE_Messages_incoming_data) {
917
+			//no saved data_handler in the repo so let's set one up and add it to the repo.
918
+			try {
919
+				$this->_current_data_handler = new $data_handler_class_name($generating_data);
920
+				$this->_data_handler_collection->add($this->_current_data_handler, $generating_data);
921
+			} catch (EE_Error $e) {
922
+				$this->_error_msg[] = $e->get_error();
923
+			}
924
+		}
925
+	}
926
+
927
+
928
+	/**
929
+	 * The queued EE_Message for generation does not save the data used for generation as objects
930
+	 * because serialization of those objects could be problematic if the data is saved to the db.
931
+	 * So this method calls the static method on the associated data_handler for the given message_type
932
+	 * and that preps the data for later instantiation when generating.
933
+	 *
934
+	 * @param EE_Message_To_Generate $message_to_generate
935
+	 * @param bool                   $preview Indicate whether this is being used for a preview or not.
936
+	 * @return mixed Prepped data for persisting to the queue.  false is returned if unable to prep data.
937
+	 */
938
+	protected function _prepare_data_for_queue(EE_Message_To_Generate $message_to_generate, $preview)
939
+	{
940
+		/** @type EE_Messages_incoming_data $data_handler - well not really... just the class name actually */
941
+		$data_handler = $message_to_generate->get_data_handler_class_name($preview);
942
+		if (! $message_to_generate->valid()) {
943
+			return false; //unable to get the data because the info in the EE_Message_To_Generate class is invalid.
944
+		}
945
+		return $data_handler::convert_data_for_persistent_storage($message_to_generate->data());
946
+	}
947
+
948
+
949
+	/**
950
+	 * This sets up a EEM_Message::status_incomplete EE_Message object and adds it to the generation queue.
951
+	 *
952
+	 * @param EE_Message_To_Generate $message_to_generate
953
+	 * @param bool                   $test_send Whether this is just a test send or not.  Typically used for previews.
954
+	 * @throws InvalidArgumentException
955
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
956
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
957
+	 */
958
+	public function create_and_add_message_to_queue(EE_Message_To_Generate $message_to_generate, $test_send = false)
959
+	{
960
+		//prep data
961
+		$data = $this->_prepare_data_for_queue($message_to_generate, $message_to_generate->preview());
962
+
963
+		$message = $message_to_generate->get_EE_Message();
964
+
965
+		//is there a GRP_ID in the request?
966
+		if ($GRP_ID = EE_Registry::instance()->REQ->get('GRP_ID')) {
967
+			$message->set_GRP_ID($GRP_ID);
968
+		}
969
+
970
+		if ($data === false) {
971
+			$message->set_STS_ID(EEM_Message::status_failed);
972
+			$message->set_error_message(
973
+				esc_html__(
974
+					'Unable to prepare data for persistence to the database.',
975
+					'event_espresso'
976
+				)
977
+			);
978
+		} else {
979
+			//make sure that the data handler is cached on the message as well
980
+			$data['data_handler_class_name'] = $message_to_generate->get_data_handler_class_name();
981
+		}
982
+
983
+		$this->_generation_queue->add($message, $data, $message_to_generate->preview(), $test_send);
984
+	}
985 985
 }
Please login to merge, or discard this patch.