Completed
Branch FET/11183/improvements-to-pue-... (232f50)
by
unknown
43:46 queued 26:36
created
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 2 patches
Indentation   +1335 added lines, -1335 removed lines patch added patch discarded remove patch
@@ -17,1343 +17,1343 @@
 block discarded – undo
17 17
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
18 18
 {
19 19
 
20
-    /**
21
-     * @type bool $_print_copy_info
22
-     */
23
-    private $_print_copy_info = false;
24
-
25
-    /**
26
-     * @type array $_attendee_data
27
-     */
28
-    private $_attendee_data = array();
29
-
30
-    /**
31
-     * @type array $_required_questions
32
-     */
33
-    private $_required_questions = array();
34
-
35
-    /**
36
-     * @type array $_registration_answers
37
-     */
38
-    private $_registration_answers = array();
39
-
40
-
41
-    /**
42
-     *    class constructor
43
-     *
44
-     * @access    public
45
-     * @param    EE_Checkout $checkout
46
-     */
47
-    public function __construct(EE_Checkout $checkout)
48
-    {
49
-        $this->_slug     = 'attendee_information';
50
-        $this->_name     = esc_html__('Attendee Information', 'event_espresso');
51
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
52
-        $this->checkout  = $checkout;
53
-        $this->_reset_success_message();
54
-        $this->set_instructions(
55
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
56
-        );
57
-    }
58
-
59
-
60
-    public function translate_js_strings()
61
-    {
62
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
63
-            ' is a required question.',
64
-            'event_espresso'
65
-        );
66
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
67
-            ' is a required question. Please enter a value for at least one of the options.',
68
-            'event_espresso'
69
-        );
70
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
71
-            'Please answer all required questions correctly before proceeding.',
72
-            'event_espresso'
73
-        );
74
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
75
-            esc_html__(
76
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
77
-                'event_espresso'
78
-            ),
79
-            '<br/>'
80
-        );
81
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
82
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
83
-            'event_espresso'
84
-        );
85
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
86
-            'You must enter a valid email address.',
87
-            'event_espresso'
88
-        );
89
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
90
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
91
-            'event_espresso'
92
-        );
93
-    }
94
-
95
-
96
-    public function enqueue_styles_and_scripts()
97
-    {
98
-    }
99
-
100
-
101
-    /**
102
-     * @return boolean
103
-     */
104
-    public function initialize_reg_step()
105
-    {
106
-        return true;
107
-    }
108
-
109
-
110
-    /**
111
-     * @return EE_Form_Section_Proper
112
-     * @throws EE_Error
113
-     * @throws InvalidArgumentException
114
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
115
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
116
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
117
-     */
118
-    public function generate_reg_form()
119
-    {
120
-        $this->_print_copy_info = false;
121
-        $primary_registrant     = null;
122
-        // autoload Line_Item_Display classes
123
-        EEH_Autoloader::register_line_item_display_autoloaders();
124
-        $Line_Item_Display = new EE_Line_Item_Display();
125
-        // calculate taxes
126
-        $Line_Item_Display->display_line_item(
127
-            $this->checkout->cart->get_grand_total(),
128
-            array('set_tax_rate' => true)
129
-        );
130
-        /** @var $subsections EE_Form_Section_Proper[] */
131
-        $subsections   = array(
132
-            'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
133
-        );
134
-        $template_args = array(
135
-            'revisit'       => $this->checkout->revisit,
136
-            'registrations' => array(),
137
-            'ticket_count'  => array(),
138
-        );
139
-        // grab the saved registrations from the transaction
140
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
141
-        if ($registrations) {
142
-            foreach ($registrations as $registration) {
143
-                // can this registration be processed during this visit ?
144
-                if ($registration instanceof EE_Registration
145
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
146
-                ) {
147
-                    $subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
148
-                    if (! $this->checkout->admin_request) {
149
-                        $template_args['registrations'][$registration->reg_url_link()]    = $registration;
150
-                        $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
151
-                            $template_args['ticket_count'][$registration->ticket()->ID()]
152
-                        )
153
-                            ? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
154
-                            : 1;
155
-                        $ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
156
-                            $this->checkout->cart->get_grand_total(),
157
-                            'Ticket',
158
-                            array($registration->ticket()->ID())
159
-                        );
160
-                        $ticket_line_item = is_array($ticket_line_item)
161
-                            ? reset($ticket_line_item)
162
-                            : $ticket_line_item;
163
-                        $template_args['ticket_line_item'][$registration->ticket()->ID()] =
164
-                            $Line_Item_Display->display_line_item($ticket_line_item);
165
-                    }
166
-                    if ($registration->is_primary_registrant()) {
167
-                        $primary_registrant = $registration->reg_url_link();
168
-                    }
169
-                }
170
-            }
171
-            // print_copy_info ?
172
-            if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
173
-                // TODO: add admin option for toggling copy attendee info,
174
-                // then use that value to change $this->_print_copy_info
175
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
176
-                    ? $this->_copy_attendee_info_form()
177
-                    : $this->_auto_copy_attendee_info();
178
-                // generate hidden input
179
-                if (isset($subsections[$primary_registrant])
180
-                    && $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
181
-                ) {
182
-                    $subsections[$primary_registrant]->add_subsections(
183
-                        $copy_options,
184
-                        'primary_registrant',
185
-                        false
186
-                    );
187
-                }
188
-            }
189
-        }
190
-
191
-        return new EE_Form_Section_Proper(
192
-            array(
193
-                'name'            => $this->reg_form_name(),
194
-                'html_id'         => $this->reg_form_name(),
195
-                'subsections'     => $subsections,
196
-                'layout_strategy' => $this->checkout->admin_request ?
197
-                    new EE_Div_Per_Section_Layout() :
198
-                    new EE_Template_Layout(
199
-                        array(
200
-                            'layout_template_file' => $this->_template, // layout_template
201
-                            'template_args'        => $template_args,
202
-                        )
203
-                    ),
204
-            )
205
-        );
206
-    }
207
-
208
-
209
-    /**
210
-     * @param EE_Registration $registration
211
-     * @return EE_Form_Section_Base
212
-     * @throws EE_Error
213
-     * @throws InvalidArgumentException
214
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
215
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
216
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
217
-     */
218
-    private function _registrations_reg_form(EE_Registration $registration)
219
-    {
220
-        static $attendee_nmbr = 1;
221
-        $form_args = array();
222
-        // verify that registration has valid event
223
-        if ($registration->event() instanceof EE_Event) {
224
-            $question_groups = $registration->event()->question_groups(
225
-                apply_filters(
226
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
227
-                    array(
228
-                        array(
229
-                            'Event.EVT_ID'                     => $registration->event()->ID(),
230
-                            'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
231
-                        ),
232
-                        'order_by' => array('QSG_order' => 'ASC'),
233
-                    ),
234
-                    $registration,
235
-                    $this
236
-                )
237
-            );
238
-            if ($question_groups) {
239
-                // array of params to pass to parent constructor
240
-                $form_args = array(
241
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
242
-                    'html_class'      => 'ee-reg-form-attendee-dv',
243
-                    'html_style'      => $this->checkout->admin_request
244
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
245
-                        : '',
246
-                    'subsections'     => array(),
247
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
248
-                        array(
249
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
250
-                            'legend_text'  => sprintf(__('Attendee %d', 'event_espresso'), $attendee_nmbr),
251
-                        )
252
-                    ),
253
-                );
254
-                foreach ($question_groups as $question_group) {
255
-                    if ($question_group instanceof EE_Question_Group) {
256
-                        $form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
257
-                            $registration,
258
-                            $question_group
259
-                        );
260
-                    }
261
-                }
262
-                // add hidden input
263
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
264
-                    $registration
265
-                );
266
-                // if we have question groups for additional attendees, then display the copy options
267
-                $this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
268
-                if ($registration->is_primary_registrant()) {
269
-                    // generate hidden input
270
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
271
-                        $registration
272
-                    );
273
-                }
274
-            }
275
-        }
276
-        $attendee_nmbr++;
277
-        return ! empty($form_args) ? new EE_Form_Section_Proper($form_args) : new EE_Form_Section_HTML();
278
-    }
279
-
280
-
281
-    /**
282
-     * _additional_attendee_reg_info_input
283
-     *
284
-     * @access public
285
-     * @param EE_Registration $registration
286
-     * @param bool            $additional_attendee_reg_info
287
-     * @return    EE_Form_Input_Base
288
-     * @throws \EE_Error
289
-     */
290
-    private function _additional_attendee_reg_info_input(
291
-        EE_Registration $registration,
292
-        $additional_attendee_reg_info = true
293
-    ) {
294
-        // generate hidden input
295
-        return new EE_Hidden_Input(
296
-            array(
297
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
298
-                'default' => $additional_attendee_reg_info,
299
-            )
300
-        );
301
-    }
302
-
303
-
304
-    /**
305
-     * @param EE_Registration   $registration
306
-     * @param EE_Question_Group $question_group
307
-     * @return EE_Form_Section_Proper
308
-     * @throws EE_Error
309
-     * @throws InvalidArgumentException
310
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
311
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
312
-     */
313
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
314
-    {
315
-        // array of params to pass to parent constructor
316
-        $form_args = array(
317
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
318
-            'html_class'      => $this->checkout->admin_request
319
-                ? 'form-table ee-reg-form-qstn-grp-dv'
320
-                : 'ee-reg-form-qstn-grp-dv',
321
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() .  '-' . $registration->ID() . '-lbl',
322
-            'subsections'     => array(
323
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
324
-            ),
325
-            'layout_strategy' => $this->checkout->admin_request
326
-                ? new EE_Admin_Two_Column_Layout()
327
-                : new EE_Div_Per_Section_Layout(),
328
-        );
329
-        // where params
330
-        $query_params = array('QST_deleted' => 0);
331
-        // don't load admin only questions on the frontend
332
-        if (! $this->checkout->admin_request) {
333
-            $query_params['QST_admin_only'] = array('!=', true);
334
-        }
335
-        $questions = $question_group->get_many_related(
336
-            'Question',
337
-            apply_filters(
338
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
339
-                array(
340
-                    $query_params,
341
-                    'order_by' => array(
342
-                        'Question_Group_Question.QGQ_order' => 'ASC',
343
-                    ),
344
-                ),
345
-                $question_group,
346
-                $registration,
347
-                $this
348
-            )
349
-        );
350
-        // filter for additional content before questions
351
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
352
-            apply_filters(
353
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
354
-                '',
355
-                $registration,
356
-                $question_group,
357
-                $this
358
-            )
359
-        );
360
-        // loop thru questions
361
-        foreach ($questions as $question) {
362
-            if ($question instanceof EE_Question) {
363
-                $identifier                            = $question->is_system_question()
364
-                    ? $question->system_ID()
365
-                    : $question->ID();
366
-                $form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
367
-            }
368
-        }
369
-        $form_args['subsections'] = apply_filters(
370
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
371
-            $form_args['subsections'],
372
-            $registration,
373
-            $question_group,
374
-            $this
375
-        );
376
-        // filter for additional content after questions
377
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
378
-            apply_filters(
379
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
380
-                '',
381
-                $registration,
382
-                $question_group,
383
-                $this
384
-            )
385
-        );
20
+	/**
21
+	 * @type bool $_print_copy_info
22
+	 */
23
+	private $_print_copy_info = false;
24
+
25
+	/**
26
+	 * @type array $_attendee_data
27
+	 */
28
+	private $_attendee_data = array();
29
+
30
+	/**
31
+	 * @type array $_required_questions
32
+	 */
33
+	private $_required_questions = array();
34
+
35
+	/**
36
+	 * @type array $_registration_answers
37
+	 */
38
+	private $_registration_answers = array();
39
+
40
+
41
+	/**
42
+	 *    class constructor
43
+	 *
44
+	 * @access    public
45
+	 * @param    EE_Checkout $checkout
46
+	 */
47
+	public function __construct(EE_Checkout $checkout)
48
+	{
49
+		$this->_slug     = 'attendee_information';
50
+		$this->_name     = esc_html__('Attendee Information', 'event_espresso');
51
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
52
+		$this->checkout  = $checkout;
53
+		$this->_reset_success_message();
54
+		$this->set_instructions(
55
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
56
+		);
57
+	}
58
+
59
+
60
+	public function translate_js_strings()
61
+	{
62
+		EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
63
+			' is a required question.',
64
+			'event_espresso'
65
+		);
66
+		EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
67
+			' is a required question. Please enter a value for at least one of the options.',
68
+			'event_espresso'
69
+		);
70
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
71
+			'Please answer all required questions correctly before proceeding.',
72
+			'event_espresso'
73
+		);
74
+		EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
75
+			esc_html__(
76
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
77
+				'event_espresso'
78
+			),
79
+			'<br/>'
80
+		);
81
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
82
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
83
+			'event_espresso'
84
+		);
85
+		EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
86
+			'You must enter a valid email address.',
87
+			'event_espresso'
88
+		);
89
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
90
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
91
+			'event_espresso'
92
+		);
93
+	}
94
+
95
+
96
+	public function enqueue_styles_and_scripts()
97
+	{
98
+	}
99
+
100
+
101
+	/**
102
+	 * @return boolean
103
+	 */
104
+	public function initialize_reg_step()
105
+	{
106
+		return true;
107
+	}
108
+
109
+
110
+	/**
111
+	 * @return EE_Form_Section_Proper
112
+	 * @throws EE_Error
113
+	 * @throws InvalidArgumentException
114
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
115
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
116
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
117
+	 */
118
+	public function generate_reg_form()
119
+	{
120
+		$this->_print_copy_info = false;
121
+		$primary_registrant     = null;
122
+		// autoload Line_Item_Display classes
123
+		EEH_Autoloader::register_line_item_display_autoloaders();
124
+		$Line_Item_Display = new EE_Line_Item_Display();
125
+		// calculate taxes
126
+		$Line_Item_Display->display_line_item(
127
+			$this->checkout->cart->get_grand_total(),
128
+			array('set_tax_rate' => true)
129
+		);
130
+		/** @var $subsections EE_Form_Section_Proper[] */
131
+		$subsections   = array(
132
+			'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
133
+		);
134
+		$template_args = array(
135
+			'revisit'       => $this->checkout->revisit,
136
+			'registrations' => array(),
137
+			'ticket_count'  => array(),
138
+		);
139
+		// grab the saved registrations from the transaction
140
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
141
+		if ($registrations) {
142
+			foreach ($registrations as $registration) {
143
+				// can this registration be processed during this visit ?
144
+				if ($registration instanceof EE_Registration
145
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
146
+				) {
147
+					$subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
148
+					if (! $this->checkout->admin_request) {
149
+						$template_args['registrations'][$registration->reg_url_link()]    = $registration;
150
+						$template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
151
+							$template_args['ticket_count'][$registration->ticket()->ID()]
152
+						)
153
+							? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
154
+							: 1;
155
+						$ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
156
+							$this->checkout->cart->get_grand_total(),
157
+							'Ticket',
158
+							array($registration->ticket()->ID())
159
+						);
160
+						$ticket_line_item = is_array($ticket_line_item)
161
+							? reset($ticket_line_item)
162
+							: $ticket_line_item;
163
+						$template_args['ticket_line_item'][$registration->ticket()->ID()] =
164
+							$Line_Item_Display->display_line_item($ticket_line_item);
165
+					}
166
+					if ($registration->is_primary_registrant()) {
167
+						$primary_registrant = $registration->reg_url_link();
168
+					}
169
+				}
170
+			}
171
+			// print_copy_info ?
172
+			if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
173
+				// TODO: add admin option for toggling copy attendee info,
174
+				// then use that value to change $this->_print_copy_info
175
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
176
+					? $this->_copy_attendee_info_form()
177
+					: $this->_auto_copy_attendee_info();
178
+				// generate hidden input
179
+				if (isset($subsections[$primary_registrant])
180
+					&& $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
181
+				) {
182
+					$subsections[$primary_registrant]->add_subsections(
183
+						$copy_options,
184
+						'primary_registrant',
185
+						false
186
+					);
187
+				}
188
+			}
189
+		}
190
+
191
+		return new EE_Form_Section_Proper(
192
+			array(
193
+				'name'            => $this->reg_form_name(),
194
+				'html_id'         => $this->reg_form_name(),
195
+				'subsections'     => $subsections,
196
+				'layout_strategy' => $this->checkout->admin_request ?
197
+					new EE_Div_Per_Section_Layout() :
198
+					new EE_Template_Layout(
199
+						array(
200
+							'layout_template_file' => $this->_template, // layout_template
201
+							'template_args'        => $template_args,
202
+						)
203
+					),
204
+			)
205
+		);
206
+	}
207
+
208
+
209
+	/**
210
+	 * @param EE_Registration $registration
211
+	 * @return EE_Form_Section_Base
212
+	 * @throws EE_Error
213
+	 * @throws InvalidArgumentException
214
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
215
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
216
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
217
+	 */
218
+	private function _registrations_reg_form(EE_Registration $registration)
219
+	{
220
+		static $attendee_nmbr = 1;
221
+		$form_args = array();
222
+		// verify that registration has valid event
223
+		if ($registration->event() instanceof EE_Event) {
224
+			$question_groups = $registration->event()->question_groups(
225
+				apply_filters(
226
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
227
+					array(
228
+						array(
229
+							'Event.EVT_ID'                     => $registration->event()->ID(),
230
+							'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
231
+						),
232
+						'order_by' => array('QSG_order' => 'ASC'),
233
+					),
234
+					$registration,
235
+					$this
236
+				)
237
+			);
238
+			if ($question_groups) {
239
+				// array of params to pass to parent constructor
240
+				$form_args = array(
241
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
242
+					'html_class'      => 'ee-reg-form-attendee-dv',
243
+					'html_style'      => $this->checkout->admin_request
244
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
245
+						: '',
246
+					'subsections'     => array(),
247
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
248
+						array(
249
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
250
+							'legend_text'  => sprintf(__('Attendee %d', 'event_espresso'), $attendee_nmbr),
251
+						)
252
+					),
253
+				);
254
+				foreach ($question_groups as $question_group) {
255
+					if ($question_group instanceof EE_Question_Group) {
256
+						$form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
257
+							$registration,
258
+							$question_group
259
+						);
260
+					}
261
+				}
262
+				// add hidden input
263
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
264
+					$registration
265
+				);
266
+				// if we have question groups for additional attendees, then display the copy options
267
+				$this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
268
+				if ($registration->is_primary_registrant()) {
269
+					// generate hidden input
270
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
271
+						$registration
272
+					);
273
+				}
274
+			}
275
+		}
276
+		$attendee_nmbr++;
277
+		return ! empty($form_args) ? new EE_Form_Section_Proper($form_args) : new EE_Form_Section_HTML();
278
+	}
279
+
280
+
281
+	/**
282
+	 * _additional_attendee_reg_info_input
283
+	 *
284
+	 * @access public
285
+	 * @param EE_Registration $registration
286
+	 * @param bool            $additional_attendee_reg_info
287
+	 * @return    EE_Form_Input_Base
288
+	 * @throws \EE_Error
289
+	 */
290
+	private function _additional_attendee_reg_info_input(
291
+		EE_Registration $registration,
292
+		$additional_attendee_reg_info = true
293
+	) {
294
+		// generate hidden input
295
+		return new EE_Hidden_Input(
296
+			array(
297
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
298
+				'default' => $additional_attendee_reg_info,
299
+			)
300
+		);
301
+	}
302
+
303
+
304
+	/**
305
+	 * @param EE_Registration   $registration
306
+	 * @param EE_Question_Group $question_group
307
+	 * @return EE_Form_Section_Proper
308
+	 * @throws EE_Error
309
+	 * @throws InvalidArgumentException
310
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
311
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
312
+	 */
313
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
314
+	{
315
+		// array of params to pass to parent constructor
316
+		$form_args = array(
317
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
318
+			'html_class'      => $this->checkout->admin_request
319
+				? 'form-table ee-reg-form-qstn-grp-dv'
320
+				: 'ee-reg-form-qstn-grp-dv',
321
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() .  '-' . $registration->ID() . '-lbl',
322
+			'subsections'     => array(
323
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
324
+			),
325
+			'layout_strategy' => $this->checkout->admin_request
326
+				? new EE_Admin_Two_Column_Layout()
327
+				: new EE_Div_Per_Section_Layout(),
328
+		);
329
+		// where params
330
+		$query_params = array('QST_deleted' => 0);
331
+		// don't load admin only questions on the frontend
332
+		if (! $this->checkout->admin_request) {
333
+			$query_params['QST_admin_only'] = array('!=', true);
334
+		}
335
+		$questions = $question_group->get_many_related(
336
+			'Question',
337
+			apply_filters(
338
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
339
+				array(
340
+					$query_params,
341
+					'order_by' => array(
342
+						'Question_Group_Question.QGQ_order' => 'ASC',
343
+					),
344
+				),
345
+				$question_group,
346
+				$registration,
347
+				$this
348
+			)
349
+		);
350
+		// filter for additional content before questions
351
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
352
+			apply_filters(
353
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
354
+				'',
355
+				$registration,
356
+				$question_group,
357
+				$this
358
+			)
359
+		);
360
+		// loop thru questions
361
+		foreach ($questions as $question) {
362
+			if ($question instanceof EE_Question) {
363
+				$identifier                            = $question->is_system_question()
364
+					? $question->system_ID()
365
+					: $question->ID();
366
+				$form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
367
+			}
368
+		}
369
+		$form_args['subsections'] = apply_filters(
370
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
371
+			$form_args['subsections'],
372
+			$registration,
373
+			$question_group,
374
+			$this
375
+		);
376
+		// filter for additional content after questions
377
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
378
+			apply_filters(
379
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
380
+				'',
381
+				$registration,
382
+				$question_group,
383
+				$this
384
+			)
385
+		);
386 386
 //		d( $form_args );
387
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
388
-        return apply_filters(
389
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
390
-            $question_group_reg_form,
391
-            $registration,
392
-            $question_group,
393
-            $this
394
-        );
395
-    }
396
-
397
-
398
-    /**
399
-     * @access public
400
-     * @param EE_Question_Group $question_group
401
-     * @return    EE_Form_Section_HTML
402
-     */
403
-    private function _question_group_header(EE_Question_Group $question_group)
404
-    {
405
-        $html = '';
406
-        // group_name
407
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
408
-            if ($this->checkout->admin_request) {
409
-                $html .= EEH_HTML::br();
410
-                $html .= EEH_HTML::h3(
411
-                    $question_group->name(),
412
-                    '',
413
-                    'ee-reg-form-qstn-grp-title title',
414
-                    'font-size: 1.3em; padding-left:0;'
415
-                );
416
-            } else {
417
-                $html .= EEH_HTML::h4(
418
-                    $question_group->name(),
419
-                    '',
420
-                    'ee-reg-form-qstn-grp-title section-title'
421
-                );
422
-            }
423
-        }
424
-        // group_desc
425
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
426
-            $html .= EEH_HTML::p(
427
-                $question_group->desc(),
428
-                '',
429
-                $this->checkout->admin_request
430
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
431
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
432
-            );
433
-        }
434
-        return new EE_Form_Section_HTML($html);
435
-    }
436
-
437
-
438
-    /**
439
-     * @access public
440
-     * @return    EE_Form_Section_Proper
441
-     * @throws \EE_Error
442
-     */
443
-    private function _copy_attendee_info_form()
444
-    {
445
-        // array of params to pass to parent constructor
446
-        return new EE_Form_Section_Proper(
447
-            array(
448
-                'subsections'     => $this->_copy_attendee_info_inputs(),
449
-                'layout_strategy' => new EE_Template_Layout(
450
-                    array(
451
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
452
-                                                      . $this->_slug
453
-                                                      . DS
454
-                                                      . 'copy_attendee_info.template.php',
455
-                        'begin_template_file'      => null,
456
-                        'input_template_file'      => null,
457
-                        'subsection_template_file' => null,
458
-                        'end_template_file'        => null,
459
-                    )
460
-                ),
461
-            )
462
-        );
463
-    }
464
-
465
-
466
-    /**
467
-     * _auto_copy_attendee_info
468
-     *
469
-     * @access public
470
-     * @return EE_Form_Section_HTML
471
-     */
472
-    private function _auto_copy_attendee_info()
473
-    {
474
-        return new EE_Form_Section_HTML(
475
-            EEH_Template::locate_template(
476
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
477
-                apply_filters(
478
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
479
-                    array()
480
-                ),
481
-                true,
482
-                true
483
-            )
484
-        );
485
-    }
486
-
487
-
488
-    /**
489
-     * _copy_attendee_info_inputs
490
-     *
491
-     * @access public
492
-     * @return array
493
-     * @throws \EE_Error
494
-     */
495
-    private function _copy_attendee_info_inputs()
496
-    {
497
-        $copy_attendee_info_inputs = array();
498
-        $prev_ticket               = null;
499
-        // grab the saved registrations from the transaction
500
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
501
-        foreach ($registrations as $registration) {
502
-            // for all  attendees other than the primary attendee
503
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
504
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
505
-                if ($registration->ticket()->ID() !== $prev_ticket) {
506
-                    $item_name = $registration->ticket()->name();
507
-                    $item_name .= $registration->ticket()->description() !== ''
508
-                        ? ' - ' . $registration->ticket()->description()
509
-                        : '';
510
-                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
511
-                        new EE_Form_Section_HTML(
512
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
513
-                        );
514
-                    $prev_ticket = $registration->ticket()->ID();
515
-                }
516
-
517
-                $copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
518
-                    new EE_Checkbox_Multi_Input(
519
-                        array(
520
-                            $registration->ID() => sprintf(
521
-                                esc_html__('Attendee #%s', 'event_espresso'),
522
-                                $registration->count()
523
-                            ),
524
-                        ),
525
-                        array(
526
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
527
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
528
-                            'display_html_label_text' => false,
529
-                        )
530
-                    );
531
-            }
532
-        }
533
-        return $copy_attendee_info_inputs;
534
-    }
535
-
536
-
537
-    /**
538
-     * _additional_primary_registrant_inputs
539
-     *
540
-     * @access public
541
-     * @param EE_Registration $registration
542
-     * @return    EE_Form_Input_Base
543
-     * @throws \EE_Error
544
-     */
545
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
546
-    {
547
-        // generate hidden input
548
-        return new EE_Hidden_Input(
549
-            array(
550
-                'html_id' => 'primary_registrant',
551
-                'default' => $registration->reg_url_link(),
552
-            )
553
-        );
554
-    }
555
-
556
-
557
-    /**
558
-     * @access public
559
-     * @param EE_Registration $registration
560
-     * @param EE_Question     $question
561
-     * @return EE_Form_Input_Base
562
-     * @throws EE_Error
563
-     * @throws InvalidArgumentException
564
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
565
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
566
-     */
567
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
568
-    {
569
-
570
-        // if this question was for an attendee detail, then check for that answer
571
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
572
-            $registration,
573
-            $question->system_ID()
574
-        );
575
-        $answer       = $answer_value === null
576
-            ? EEM_Answer::instance()->get_one(
577
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
578
-            )
579
-            : null;
580
-        // if NOT returning to edit an existing registration
581
-        // OR if this question is for an attendee property
582
-        // OR we still don't have an EE_Answer object
583
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
584
-            // create an EE_Answer object for storing everything in
585
-            $answer = EE_Answer::new_instance(array(
586
-                'QST_ID' => $question->ID(),
587
-                'REG_ID' => $registration->ID(),
588
-            ));
589
-        }
590
-        // verify instance
591
-        if ($answer instanceof EE_Answer) {
592
-            if (! empty($answer_value)) {
593
-                $answer->set('ANS_value', $answer_value);
594
-            }
595
-            $answer->cache('Question', $question);
596
-            //remember system ID had a bug where sometimes it could be null
597
-            $answer_cache_id = $question->is_system_question()
598
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
599
-                : $question->ID() . '-' . $registration->reg_url_link();
600
-            $registration->cache('Answer', $answer, $answer_cache_id);
601
-        }
602
-        return $this->_generate_question_input($registration, $question, $answer);
603
-    }
604
-
605
-
606
-    /**
607
-     * @param EE_Registration $registration
608
-     * @param EE_Question     $question
609
-     * @param                 mixed EE_Answer|NULL      $answer
610
-     * @return EE_Form_Input_Base
611
-     * @throws \EE_Error
612
-     */
613
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
614
-    {
615
-        $identifier                             = $question->is_system_question()
616
-            ? $question->system_ID()
617
-            : $question->ID();
618
-        $this->_required_questions[$identifier] = $question->required() ? true : false;
619
-        add_filter(
620
-            'FHEE__EE_Question__generate_form_input__country_options',
621
-            array($this, 'use_cached_countries_for_form_input'),
622
-            10,
623
-            4
624
-        );
625
-        add_filter(
626
-            'FHEE__EE_Question__generate_form_input__state_options',
627
-            array($this, 'use_cached_states_for_form_input'),
628
-            10,
629
-            4
630
-        );
631
-        $input_constructor_args                  = array(
632
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
633
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
634
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
635
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
636
-            'html_label_class' => 'ee-reg-qstn',
637
-        );
638
-        $input_constructor_args['html_label_id'] .= '-lbl';
639
-        if ($answer instanceof EE_Answer && $answer->ID()) {
640
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
641
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
642
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
643
-        }
644
-        $form_input = $question->generate_form_input(
645
-            $registration,
646
-            $answer,
647
-            $input_constructor_args
648
-        );
649
-        remove_filter(
650
-            'FHEE__EE_Question__generate_form_input__country_options',
651
-            array($this, 'use_cached_countries_for_form_input')
652
-        );
653
-        remove_filter(
654
-            'FHEE__EE_Question__generate_form_input__state_options',
655
-            array($this, 'use_cached_states_for_form_input')
656
-        );
657
-        return $form_input;
658
-    }
659
-
660
-
661
-    /**
662
-     * Gets the list of countries for the form input
663
-     *
664
-     * @param array|null       $countries_list
665
-     * @param \EE_Question     $question
666
-     * @param \EE_Registration $registration
667
-     * @param \EE_Answer       $answer
668
-     * @return array 2d keys are country IDs, values are their names
669
-     * @throws EE_Error
670
-     * @throws InvalidArgumentException
671
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
672
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
673
-     */
674
-    public function use_cached_countries_for_form_input(
675
-        $countries_list,
676
-        \EE_Question $question = null,
677
-        \EE_Registration $registration = null,
678
-        \EE_Answer $answer = null
679
-    ) {
680
-        $country_options = array('' => '');
681
-        // get possibly cached list of countries
682
-        $countries = $this->checkout->action === 'process_reg_step'
683
-            ? EEM_Country::instance()->get_all_countries()
684
-            : EEM_Country::instance()->get_all_active_countries();
685
-        if (! empty($countries)) {
686
-            foreach ($countries as $country) {
687
-                if ($country instanceof EE_Country) {
688
-                    $country_options[$country->ID()] = $country->name();
689
-                }
690
-            }
691
-        }
692
-        if ($question instanceof EE_Question
693
-            && $registration instanceof EE_Registration) {
694
-            $answer = EEM_Answer::instance()->get_one(
695
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
696
-            );
697
-        } else {
698
-            $answer = EE_Answer::new_instance();
699
-        }
700
-        $country_options = apply_filters(
701
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
702
-            $country_options,
703
-            $this,
704
-            $registration,
705
-            $question,
706
-            $answer
707
-        );
708
-        return $country_options;
709
-    }
710
-
711
-
712
-    /**
713
-     * Gets the list of states for the form input
714
-     *
715
-     * @param array|null       $states_list
716
-     * @param \EE_Question     $question
717
-     * @param \EE_Registration $registration
718
-     * @param \EE_Answer       $answer
719
-     * @return array 2d keys are state IDs, values are their names
720
-     * @throws EE_Error
721
-     * @throws InvalidArgumentException
722
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
723
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
724
-     */
725
-    public function use_cached_states_for_form_input(
726
-        $states_list,
727
-        \EE_Question $question = null,
728
-        \EE_Registration $registration = null,
729
-        \EE_Answer $answer = null
730
-    ) {
731
-        $state_options = array('' => array('' => ''));
732
-        $states        = $this->checkout->action === 'process_reg_step'
733
-            ? EEM_State::instance()->get_all_states()
734
-            : EEM_State::instance()->get_all_active_states();
735
-        if (! empty($states)) {
736
-            foreach ($states as $state) {
737
-                if ($state instanceof EE_State) {
738
-                    $state_options[$state->country()->name()][$state->ID()] = $state->name();
739
-                }
740
-            }
741
-        }
742
-        $state_options = apply_filters(
743
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
744
-            $state_options,
745
-            $this,
746
-            $registration,
747
-            $question,
748
-            $answer
749
-        );
750
-        return $state_options;
751
-    }
752
-
753
-
754
-
755
-
756
-
757
-
758
-    /********************************************************************************************************/
759
-    /****************************************  PROCESS REG STEP  ****************************************/
760
-    /********************************************************************************************************/
761
-    /**
762
-     * @return bool
763
-     * @throws EE_Error
764
-     * @throws InvalidArgumentException
765
-     * @throws ReflectionException
766
-     * @throws RuntimeException
767
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
768
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
769
-     */
770
-    public function process_reg_step()
771
-    {
772
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
773
-        // grab validated data from form
774
-        $valid_data = $this->checkout->current_step->valid_data();
775
-        // EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
776
-        // EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
777
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
778
-        if (empty($valid_data)) {
779
-            EE_Error::add_error(
780
-                esc_html__('No valid question responses were received.', 'event_espresso'),
781
-                __FILE__,
782
-                __FUNCTION__,
783
-                __LINE__
784
-            );
785
-            return false;
786
-        }
787
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
788
-            EE_Error::add_error(
789
-                esc_html__(
790
-                    'A valid transaction could not be initiated for processing your registrations.',
791
-                    'event_espresso'
792
-                ),
793
-                __FILE__,
794
-                __FUNCTION__,
795
-                __LINE__
796
-            );
797
-            return false;
798
-        }
799
-        // get cached registrations
800
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
801
-        // verify we got the goods
802
-        if (empty($registrations)) {
803
-            //combine the old translated string with a new one, in order to not break translations
804
-            $error_message = esc_html__( 'Your form data could not be applied to any valid registrations.', 'event_espresso' )
805
-                             . sprintf(
806
-                                 esc_html__('%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.', 'event_espresso'),
807
-                                 '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
808
-                                 '</a>',
809
-                                 '<br />'
810
-                             );
811
-            EE_Error::add_error(
812
-                $error_message,
813
-                __FILE__,
814
-                __FUNCTION__,
815
-                __LINE__
816
-            );
817
-            return false;
818
-        }
819
-        // extract attendee info from form data and save to model objects
820
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
821
-        // if first pass thru SPCO,
822
-        // then let's check processed registrations against the total number of tickets in the cart
823
-        if ($registrations_processed === false) {
824
-            // but return immediately if the previous step exited early due to errors
825
-            return false;
826
-        } elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
827
-            // generate a correctly translated string for all possible singular/plural combinations
828
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
829
-                $error_msg = sprintf(
830
-                    esc_html__(
831
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
832
-                        'event_espresso'
833
-                    ),
834
-                    $this->checkout->total_ticket_count,
835
-                    $registrations_processed
836
-                );
837
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
838
-                $error_msg = sprintf(
839
-                    esc_html__(
840
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
841
-                        'event_espresso'
842
-                    ),
843
-                    $this->checkout->total_ticket_count,
844
-                    $registrations_processed
845
-                );
846
-            } else {
847
-                $error_msg = sprintf(
848
-                    esc_html__(
849
-                        'There was a total of %1$d tickets in the Event Queue, but %2$ds registrations were processed',
850
-                        'event_espresso'
851
-                    ),
852
-                    $this->checkout->total_ticket_count,
853
-                    $registrations_processed
854
-                );
855
-            }
856
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
857
-            return false;
858
-        }
859
-        // mark this reg step as completed
860
-        $this->set_completed();
861
-        $this->_set_success_message(
862
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
863
-        );
864
-        //do action in case a plugin wants to do something with the data submitted in step 1.
865
-        //passes EE_Single_Page_Checkout, and it's posted data
866
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
867
-        return true;
868
-    }
869
-
870
-
871
-    /**
872
-     *    _process_registrations
873
-     *
874
-     * @param EE_Registration[] $registrations
875
-     * @param array             $valid_data
876
-     * @return bool|int
877
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
878
-     * @throws EE_Error
879
-     * @throws InvalidArgumentException
880
-     * @throws ReflectionException
881
-     * @throws RuntimeException
882
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
883
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
884
-     */
885
-    private function _process_registrations($registrations = array(), $valid_data = array())
886
-    {
887
-        // load resources and set some defaults
888
-        EE_Registry::instance()->load_model('Attendee');
889
-        // holder for primary registrant attendee object
890
-        $this->checkout->primary_attendee_obj = null;
891
-        // array for tracking reg form data for the primary registrant
892
-        $primary_registrant = array(
893
-            'line_item_id' => null,
894
-        );
895
-        $copy_primary       = false;
896
-        // reg form sections that do not contain inputs
897
-        $non_input_form_sections = array(
898
-            'primary_registrant',
899
-            'additional_attendee_reg_info',
900
-            'spco_copy_attendee_chk',
901
-        );
902
-        // attendee counter
903
-        $att_nmbr = 0;
904
-        // grab the saved registrations from the transaction
905
-        foreach ($registrations as $registration) {
906
-            // verify EE_Registration object
907
-            if (! $registration instanceof EE_Registration) {
908
-                EE_Error::add_error(
909
-                    esc_html__(
910
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
911
-                        'event_espresso'
912
-                    ),
913
-                    __FILE__,
914
-                    __FUNCTION__,
915
-                    __LINE__
916
-                );
917
-                return false;
918
-            }
919
-            /** @var string $reg_url_link */
920
-            $reg_url_link = $registration->reg_url_link();
921
-            // reg_url_link exists ?
922
-            if (! empty($reg_url_link)) {
923
-                // should this registration be processed during this visit ?
924
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
925
-                    // if NOT revisiting, then let's save the registration now,
926
-                    // so that we have a REG_ID to use when generating other objects
927
-                    if (! $this->checkout->revisit) {
928
-                        $registration->save();
929
-                    }
930
-                    /**
931
-                     * This allows plugins to trigger a fail on processing of a
932
-                     * registration for any conditions they may have for it to pass.
933
-                     *
934
-                     * @var bool   if true is returned by the plugin then the
935
-                     *            registration processing is halted.
936
-                     */
937
-                    if (apply_filters(
938
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
939
-                        false,
940
-                        $att_nmbr,
941
-                        $registration,
942
-                        $registrations,
943
-                        $valid_data,
944
-                        $this
945
-                    )) {
946
-                        return false;
947
-                    }
948
-
949
-                    // Houston, we have a registration!
950
-                    $att_nmbr++;
951
-                    $this->_attendee_data[$reg_url_link] = array();
952
-                    // grab any existing related answer objects
953
-                    $this->_registration_answers = $registration->answers();
954
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
955
-                    if (isset($valid_data[$reg_url_link])) {
956
-                        // do we need to copy basic info from primary attendee ?
957
-                        $copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
958
-                                        && absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0
959
-                            ? true
960
-                            : false;
961
-                        // filter form input data for this registration
962
-                        $valid_data[$reg_url_link] = (array)apply_filters(
963
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
964
-                            $valid_data[$reg_url_link]
965
-                        );
966
-                        if (isset($valid_data['primary_attendee'])) {
967
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
968
-                                ? $valid_data['primary_attendee']
969
-                                : false;
970
-                            unset($valid_data['primary_attendee']);
971
-                        }
972
-                        // now loop through our array of valid post data && process attendee reg forms
973
-                        foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
974
-                            if (! in_array($form_section, $non_input_form_sections)) {
975
-                                foreach ($form_inputs as $form_input => $input_value) {
976
-                                    // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
977
-                                    // check for critical inputs
978
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
979
-                                        $form_input,
980
-                                        $input_value
981
-                                    )
982
-                                    ) {
983
-                                        return false;
984
-                                    }
985
-                                    // store a bit of data about the primary attendee
986
-                                    if ($att_nmbr === 1
987
-                                        && ! empty($input_value)
988
-                                        && $reg_url_link === $primary_registrant['line_item_id']
989
-                                    ) {
990
-                                        $primary_registrant[$form_input] = $input_value;
991
-                                    } elseif ($copy_primary
992
-                                        && $input_value === null
993
-                                        && isset($primary_registrant[$form_input])
994
-                                    ) {
995
-                                        $input_value = $primary_registrant[$form_input];
996
-                                    }
997
-                                    // now attempt to save the input data
998
-                                    if (! $this->_save_registration_form_input(
999
-                                        $registration,
1000
-                                        $form_input,
1001
-                                        $input_value
1002
-                                    )
1003
-                                    ) {
1004
-                                        EE_Error::add_error(
1005
-                                            sprintf(
1006
-                                                esc_html__(
1007
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1008
-                                                    'event_espresso'
1009
-                                                ),
1010
-                                                $form_input,
1011
-                                                $input_value
1012
-                                            ),
1013
-                                            __FILE__,
1014
-                                            __FUNCTION__,
1015
-                                            __LINE__
1016
-                                        );
1017
-                                        return false;
1018
-                                    }
1019
-                                }
1020
-                            }
1021
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1022
-                    }
1023
-                    //EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1024
-                    // this registration does not require additional attendee information ?
1025
-                    if ($copy_primary
1026
-                        && $att_nmbr > 1
1027
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1028
-                    ) {
1029
-                        // just copy the primary registrant
1030
-                        $attendee = $this->checkout->primary_attendee_obj;
1031
-                    } else {
1032
-                        // ensure critical details are set for additional attendees
1033
-                        $this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1034
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1035
-                                $this->_attendee_data[$reg_url_link]
1036
-                            )
1037
-                            : $this->_attendee_data[$reg_url_link];
1038
-                        // execute create attendee command (which may return an existing attendee)
1039
-                        $attendee = EE_Registry::instance()->BUS->execute(
1040
-                            new CreateAttendeeCommand(
1041
-                                $this->_attendee_data[$reg_url_link],
1042
-                                $registration
1043
-                            )
1044
-                        );
1045
-                        // who's #1 ?
1046
-                        if ($att_nmbr === 1) {
1047
-                            $this->checkout->primary_attendee_obj = $attendee;
1048
-                        }
1049
-                    }
1050
-                    // EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1051
-                    // add relation to registration, set attendee ID, and cache attendee
1052
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1053
-                    // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1054
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1055
-                        EE_Error::add_error(
1056
-                            sprintf(
1057
-                                esc_html__(
1058
-                                    'Registration %s has an invalid or missing Attendee object.',
1059
-                                    'event_espresso'
1060
-                                ),
1061
-                                $reg_url_link
1062
-                            ),
1063
-                            __FILE__,
1064
-                            __FUNCTION__,
1065
-                            __LINE__
1066
-                        );
1067
-                        return false;
1068
-                    }
1069
-                    /** @type EE_Registration_Processor $registration_processor */
1070
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1071
-                    // at this point, we should have enough details about the registrant to consider the registration
1072
-                    // NOT incomplete
1073
-                    $registration_processor->toggle_incomplete_registration_status_to_default(
1074
-                        $registration,
1075
-                        false,
1076
-                        new Context(
1077
-                            'spco_reg_step_attendee_information_process_registrations',
1078
-                            esc_html__(
1079
-                                'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1080
-                                'event_espresso'
1081
-                            )
1082
-                        )
1083
-                    );
1084
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1085
-                    // abandoned
1086
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1087
-                    // if we've gotten this far, then let's save what we have
1088
-                    $registration->save();
1089
-                    // add relation between TXN and registration
1090
-                    $this->_associate_registration_with_transaction($registration);
1091
-                }
1092
-            } else {
1093
-                EE_Error::add_error(
1094
-                    esc_html__(
1095
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1096
-                        'event_espresso'
1097
-                    ),
1098
-                    __FILE__,
1099
-                    __FUNCTION__,
1100
-                    __LINE__
1101
-                );
1102
-                // remove malformed data
1103
-                unset($valid_data[$reg_url_link]);
1104
-                return false;
1105
-            }
1106
-
1107
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1108
-        return $att_nmbr;
1109
-    }
1110
-
1111
-
1112
-    /**
1113
-     *    _save_registration_form_input
1114
-     *
1115
-     * @param EE_Registration $registration
1116
-     * @param string          $form_input
1117
-     * @param string          $input_value
1118
-     * @return bool
1119
-     * @throws EE_Error
1120
-     * @throws InvalidArgumentException
1121
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1122
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1123
-     */
1124
-    private function _save_registration_form_input(
1125
-        EE_Registration $registration,
1126
-        $form_input = '',
1127
-        $input_value = ''
1128
-    ) {
1129
-        // \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1130
-        // \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1131
-        // \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1132
-        // allow for plugins to hook in and do their own processing of the form input.
1133
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1134
-        if (apply_filters(
1135
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1136
-            false,
1137
-            $registration,
1138
-            $form_input,
1139
-            $input_value,
1140
-            $this
1141
-        )) {
1142
-            return true;
1143
-        }
1144
-        /*
387
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
388
+		return apply_filters(
389
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
390
+			$question_group_reg_form,
391
+			$registration,
392
+			$question_group,
393
+			$this
394
+		);
395
+	}
396
+
397
+
398
+	/**
399
+	 * @access public
400
+	 * @param EE_Question_Group $question_group
401
+	 * @return    EE_Form_Section_HTML
402
+	 */
403
+	private function _question_group_header(EE_Question_Group $question_group)
404
+	{
405
+		$html = '';
406
+		// group_name
407
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
408
+			if ($this->checkout->admin_request) {
409
+				$html .= EEH_HTML::br();
410
+				$html .= EEH_HTML::h3(
411
+					$question_group->name(),
412
+					'',
413
+					'ee-reg-form-qstn-grp-title title',
414
+					'font-size: 1.3em; padding-left:0;'
415
+				);
416
+			} else {
417
+				$html .= EEH_HTML::h4(
418
+					$question_group->name(),
419
+					'',
420
+					'ee-reg-form-qstn-grp-title section-title'
421
+				);
422
+			}
423
+		}
424
+		// group_desc
425
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
426
+			$html .= EEH_HTML::p(
427
+				$question_group->desc(),
428
+				'',
429
+				$this->checkout->admin_request
430
+					? 'ee-reg-form-qstn-grp-desc-pg'
431
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
432
+			);
433
+		}
434
+		return new EE_Form_Section_HTML($html);
435
+	}
436
+
437
+
438
+	/**
439
+	 * @access public
440
+	 * @return    EE_Form_Section_Proper
441
+	 * @throws \EE_Error
442
+	 */
443
+	private function _copy_attendee_info_form()
444
+	{
445
+		// array of params to pass to parent constructor
446
+		return new EE_Form_Section_Proper(
447
+			array(
448
+				'subsections'     => $this->_copy_attendee_info_inputs(),
449
+				'layout_strategy' => new EE_Template_Layout(
450
+					array(
451
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
452
+													  . $this->_slug
453
+													  . DS
454
+													  . 'copy_attendee_info.template.php',
455
+						'begin_template_file'      => null,
456
+						'input_template_file'      => null,
457
+						'subsection_template_file' => null,
458
+						'end_template_file'        => null,
459
+					)
460
+				),
461
+			)
462
+		);
463
+	}
464
+
465
+
466
+	/**
467
+	 * _auto_copy_attendee_info
468
+	 *
469
+	 * @access public
470
+	 * @return EE_Form_Section_HTML
471
+	 */
472
+	private function _auto_copy_attendee_info()
473
+	{
474
+		return new EE_Form_Section_HTML(
475
+			EEH_Template::locate_template(
476
+				SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
477
+				apply_filters(
478
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
479
+					array()
480
+				),
481
+				true,
482
+				true
483
+			)
484
+		);
485
+	}
486
+
487
+
488
+	/**
489
+	 * _copy_attendee_info_inputs
490
+	 *
491
+	 * @access public
492
+	 * @return array
493
+	 * @throws \EE_Error
494
+	 */
495
+	private function _copy_attendee_info_inputs()
496
+	{
497
+		$copy_attendee_info_inputs = array();
498
+		$prev_ticket               = null;
499
+		// grab the saved registrations from the transaction
500
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
501
+		foreach ($registrations as $registration) {
502
+			// for all  attendees other than the primary attendee
503
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
504
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
505
+				if ($registration->ticket()->ID() !== $prev_ticket) {
506
+					$item_name = $registration->ticket()->name();
507
+					$item_name .= $registration->ticket()->description() !== ''
508
+						? ' - ' . $registration->ticket()->description()
509
+						: '';
510
+					$copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
511
+						new EE_Form_Section_HTML(
512
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
513
+						);
514
+					$prev_ticket = $registration->ticket()->ID();
515
+				}
516
+
517
+				$copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
518
+					new EE_Checkbox_Multi_Input(
519
+						array(
520
+							$registration->ID() => sprintf(
521
+								esc_html__('Attendee #%s', 'event_espresso'),
522
+								$registration->count()
523
+							),
524
+						),
525
+						array(
526
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
527
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
528
+							'display_html_label_text' => false,
529
+						)
530
+					);
531
+			}
532
+		}
533
+		return $copy_attendee_info_inputs;
534
+	}
535
+
536
+
537
+	/**
538
+	 * _additional_primary_registrant_inputs
539
+	 *
540
+	 * @access public
541
+	 * @param EE_Registration $registration
542
+	 * @return    EE_Form_Input_Base
543
+	 * @throws \EE_Error
544
+	 */
545
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
546
+	{
547
+		// generate hidden input
548
+		return new EE_Hidden_Input(
549
+			array(
550
+				'html_id' => 'primary_registrant',
551
+				'default' => $registration->reg_url_link(),
552
+			)
553
+		);
554
+	}
555
+
556
+
557
+	/**
558
+	 * @access public
559
+	 * @param EE_Registration $registration
560
+	 * @param EE_Question     $question
561
+	 * @return EE_Form_Input_Base
562
+	 * @throws EE_Error
563
+	 * @throws InvalidArgumentException
564
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
565
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
566
+	 */
567
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
568
+	{
569
+
570
+		// if this question was for an attendee detail, then check for that answer
571
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
572
+			$registration,
573
+			$question->system_ID()
574
+		);
575
+		$answer       = $answer_value === null
576
+			? EEM_Answer::instance()->get_one(
577
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
578
+			)
579
+			: null;
580
+		// if NOT returning to edit an existing registration
581
+		// OR if this question is for an attendee property
582
+		// OR we still don't have an EE_Answer object
583
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
584
+			// create an EE_Answer object for storing everything in
585
+			$answer = EE_Answer::new_instance(array(
586
+				'QST_ID' => $question->ID(),
587
+				'REG_ID' => $registration->ID(),
588
+			));
589
+		}
590
+		// verify instance
591
+		if ($answer instanceof EE_Answer) {
592
+			if (! empty($answer_value)) {
593
+				$answer->set('ANS_value', $answer_value);
594
+			}
595
+			$answer->cache('Question', $question);
596
+			//remember system ID had a bug where sometimes it could be null
597
+			$answer_cache_id = $question->is_system_question()
598
+				? $question->system_ID() . '-' . $registration->reg_url_link()
599
+				: $question->ID() . '-' . $registration->reg_url_link();
600
+			$registration->cache('Answer', $answer, $answer_cache_id);
601
+		}
602
+		return $this->_generate_question_input($registration, $question, $answer);
603
+	}
604
+
605
+
606
+	/**
607
+	 * @param EE_Registration $registration
608
+	 * @param EE_Question     $question
609
+	 * @param                 mixed EE_Answer|NULL      $answer
610
+	 * @return EE_Form_Input_Base
611
+	 * @throws \EE_Error
612
+	 */
613
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
614
+	{
615
+		$identifier                             = $question->is_system_question()
616
+			? $question->system_ID()
617
+			: $question->ID();
618
+		$this->_required_questions[$identifier] = $question->required() ? true : false;
619
+		add_filter(
620
+			'FHEE__EE_Question__generate_form_input__country_options',
621
+			array($this, 'use_cached_countries_for_form_input'),
622
+			10,
623
+			4
624
+		);
625
+		add_filter(
626
+			'FHEE__EE_Question__generate_form_input__state_options',
627
+			array($this, 'use_cached_states_for_form_input'),
628
+			10,
629
+			4
630
+		);
631
+		$input_constructor_args                  = array(
632
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
633
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
634
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
635
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
636
+			'html_label_class' => 'ee-reg-qstn',
637
+		);
638
+		$input_constructor_args['html_label_id'] .= '-lbl';
639
+		if ($answer instanceof EE_Answer && $answer->ID()) {
640
+			$input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
641
+			$input_constructor_args['html_id']       .= '-' . $answer->ID();
642
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
643
+		}
644
+		$form_input = $question->generate_form_input(
645
+			$registration,
646
+			$answer,
647
+			$input_constructor_args
648
+		);
649
+		remove_filter(
650
+			'FHEE__EE_Question__generate_form_input__country_options',
651
+			array($this, 'use_cached_countries_for_form_input')
652
+		);
653
+		remove_filter(
654
+			'FHEE__EE_Question__generate_form_input__state_options',
655
+			array($this, 'use_cached_states_for_form_input')
656
+		);
657
+		return $form_input;
658
+	}
659
+
660
+
661
+	/**
662
+	 * Gets the list of countries for the form input
663
+	 *
664
+	 * @param array|null       $countries_list
665
+	 * @param \EE_Question     $question
666
+	 * @param \EE_Registration $registration
667
+	 * @param \EE_Answer       $answer
668
+	 * @return array 2d keys are country IDs, values are their names
669
+	 * @throws EE_Error
670
+	 * @throws InvalidArgumentException
671
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
672
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
673
+	 */
674
+	public function use_cached_countries_for_form_input(
675
+		$countries_list,
676
+		\EE_Question $question = null,
677
+		\EE_Registration $registration = null,
678
+		\EE_Answer $answer = null
679
+	) {
680
+		$country_options = array('' => '');
681
+		// get possibly cached list of countries
682
+		$countries = $this->checkout->action === 'process_reg_step'
683
+			? EEM_Country::instance()->get_all_countries()
684
+			: EEM_Country::instance()->get_all_active_countries();
685
+		if (! empty($countries)) {
686
+			foreach ($countries as $country) {
687
+				if ($country instanceof EE_Country) {
688
+					$country_options[$country->ID()] = $country->name();
689
+				}
690
+			}
691
+		}
692
+		if ($question instanceof EE_Question
693
+			&& $registration instanceof EE_Registration) {
694
+			$answer = EEM_Answer::instance()->get_one(
695
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
696
+			);
697
+		} else {
698
+			$answer = EE_Answer::new_instance();
699
+		}
700
+		$country_options = apply_filters(
701
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
702
+			$country_options,
703
+			$this,
704
+			$registration,
705
+			$question,
706
+			$answer
707
+		);
708
+		return $country_options;
709
+	}
710
+
711
+
712
+	/**
713
+	 * Gets the list of states for the form input
714
+	 *
715
+	 * @param array|null       $states_list
716
+	 * @param \EE_Question     $question
717
+	 * @param \EE_Registration $registration
718
+	 * @param \EE_Answer       $answer
719
+	 * @return array 2d keys are state IDs, values are their names
720
+	 * @throws EE_Error
721
+	 * @throws InvalidArgumentException
722
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
723
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
724
+	 */
725
+	public function use_cached_states_for_form_input(
726
+		$states_list,
727
+		\EE_Question $question = null,
728
+		\EE_Registration $registration = null,
729
+		\EE_Answer $answer = null
730
+	) {
731
+		$state_options = array('' => array('' => ''));
732
+		$states        = $this->checkout->action === 'process_reg_step'
733
+			? EEM_State::instance()->get_all_states()
734
+			: EEM_State::instance()->get_all_active_states();
735
+		if (! empty($states)) {
736
+			foreach ($states as $state) {
737
+				if ($state instanceof EE_State) {
738
+					$state_options[$state->country()->name()][$state->ID()] = $state->name();
739
+				}
740
+			}
741
+		}
742
+		$state_options = apply_filters(
743
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
744
+			$state_options,
745
+			$this,
746
+			$registration,
747
+			$question,
748
+			$answer
749
+		);
750
+		return $state_options;
751
+	}
752
+
753
+
754
+
755
+
756
+
757
+
758
+	/********************************************************************************************************/
759
+	/****************************************  PROCESS REG STEP  ****************************************/
760
+	/********************************************************************************************************/
761
+	/**
762
+	 * @return bool
763
+	 * @throws EE_Error
764
+	 * @throws InvalidArgumentException
765
+	 * @throws ReflectionException
766
+	 * @throws RuntimeException
767
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
768
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
769
+	 */
770
+	public function process_reg_step()
771
+	{
772
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
773
+		// grab validated data from form
774
+		$valid_data = $this->checkout->current_step->valid_data();
775
+		// EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
776
+		// EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
777
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
778
+		if (empty($valid_data)) {
779
+			EE_Error::add_error(
780
+				esc_html__('No valid question responses were received.', 'event_espresso'),
781
+				__FILE__,
782
+				__FUNCTION__,
783
+				__LINE__
784
+			);
785
+			return false;
786
+		}
787
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
788
+			EE_Error::add_error(
789
+				esc_html__(
790
+					'A valid transaction could not be initiated for processing your registrations.',
791
+					'event_espresso'
792
+				),
793
+				__FILE__,
794
+				__FUNCTION__,
795
+				__LINE__
796
+			);
797
+			return false;
798
+		}
799
+		// get cached registrations
800
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
801
+		// verify we got the goods
802
+		if (empty($registrations)) {
803
+			//combine the old translated string with a new one, in order to not break translations
804
+			$error_message = esc_html__( 'Your form data could not be applied to any valid registrations.', 'event_espresso' )
805
+							 . sprintf(
806
+								 esc_html__('%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.', 'event_espresso'),
807
+								 '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
808
+								 '</a>',
809
+								 '<br />'
810
+							 );
811
+			EE_Error::add_error(
812
+				$error_message,
813
+				__FILE__,
814
+				__FUNCTION__,
815
+				__LINE__
816
+			);
817
+			return false;
818
+		}
819
+		// extract attendee info from form data and save to model objects
820
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
821
+		// if first pass thru SPCO,
822
+		// then let's check processed registrations against the total number of tickets in the cart
823
+		if ($registrations_processed === false) {
824
+			// but return immediately if the previous step exited early due to errors
825
+			return false;
826
+		} elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
827
+			// generate a correctly translated string for all possible singular/plural combinations
828
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
829
+				$error_msg = sprintf(
830
+					esc_html__(
831
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
832
+						'event_espresso'
833
+					),
834
+					$this->checkout->total_ticket_count,
835
+					$registrations_processed
836
+				);
837
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
838
+				$error_msg = sprintf(
839
+					esc_html__(
840
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
841
+						'event_espresso'
842
+					),
843
+					$this->checkout->total_ticket_count,
844
+					$registrations_processed
845
+				);
846
+			} else {
847
+				$error_msg = sprintf(
848
+					esc_html__(
849
+						'There was a total of %1$d tickets in the Event Queue, but %2$ds registrations were processed',
850
+						'event_espresso'
851
+					),
852
+					$this->checkout->total_ticket_count,
853
+					$registrations_processed
854
+				);
855
+			}
856
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
857
+			return false;
858
+		}
859
+		// mark this reg step as completed
860
+		$this->set_completed();
861
+		$this->_set_success_message(
862
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
863
+		);
864
+		//do action in case a plugin wants to do something with the data submitted in step 1.
865
+		//passes EE_Single_Page_Checkout, and it's posted data
866
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
867
+		return true;
868
+	}
869
+
870
+
871
+	/**
872
+	 *    _process_registrations
873
+	 *
874
+	 * @param EE_Registration[] $registrations
875
+	 * @param array             $valid_data
876
+	 * @return bool|int
877
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
878
+	 * @throws EE_Error
879
+	 * @throws InvalidArgumentException
880
+	 * @throws ReflectionException
881
+	 * @throws RuntimeException
882
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
883
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
884
+	 */
885
+	private function _process_registrations($registrations = array(), $valid_data = array())
886
+	{
887
+		// load resources and set some defaults
888
+		EE_Registry::instance()->load_model('Attendee');
889
+		// holder for primary registrant attendee object
890
+		$this->checkout->primary_attendee_obj = null;
891
+		// array for tracking reg form data for the primary registrant
892
+		$primary_registrant = array(
893
+			'line_item_id' => null,
894
+		);
895
+		$copy_primary       = false;
896
+		// reg form sections that do not contain inputs
897
+		$non_input_form_sections = array(
898
+			'primary_registrant',
899
+			'additional_attendee_reg_info',
900
+			'spco_copy_attendee_chk',
901
+		);
902
+		// attendee counter
903
+		$att_nmbr = 0;
904
+		// grab the saved registrations from the transaction
905
+		foreach ($registrations as $registration) {
906
+			// verify EE_Registration object
907
+			if (! $registration instanceof EE_Registration) {
908
+				EE_Error::add_error(
909
+					esc_html__(
910
+						'An invalid Registration object was discovered when attempting to process your registration information.',
911
+						'event_espresso'
912
+					),
913
+					__FILE__,
914
+					__FUNCTION__,
915
+					__LINE__
916
+				);
917
+				return false;
918
+			}
919
+			/** @var string $reg_url_link */
920
+			$reg_url_link = $registration->reg_url_link();
921
+			// reg_url_link exists ?
922
+			if (! empty($reg_url_link)) {
923
+				// should this registration be processed during this visit ?
924
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
925
+					// if NOT revisiting, then let's save the registration now,
926
+					// so that we have a REG_ID to use when generating other objects
927
+					if (! $this->checkout->revisit) {
928
+						$registration->save();
929
+					}
930
+					/**
931
+					 * This allows plugins to trigger a fail on processing of a
932
+					 * registration for any conditions they may have for it to pass.
933
+					 *
934
+					 * @var bool   if true is returned by the plugin then the
935
+					 *            registration processing is halted.
936
+					 */
937
+					if (apply_filters(
938
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
939
+						false,
940
+						$att_nmbr,
941
+						$registration,
942
+						$registrations,
943
+						$valid_data,
944
+						$this
945
+					)) {
946
+						return false;
947
+					}
948
+
949
+					// Houston, we have a registration!
950
+					$att_nmbr++;
951
+					$this->_attendee_data[$reg_url_link] = array();
952
+					// grab any existing related answer objects
953
+					$this->_registration_answers = $registration->answers();
954
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
955
+					if (isset($valid_data[$reg_url_link])) {
956
+						// do we need to copy basic info from primary attendee ?
957
+						$copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
958
+										&& absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0
959
+							? true
960
+							: false;
961
+						// filter form input data for this registration
962
+						$valid_data[$reg_url_link] = (array)apply_filters(
963
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
964
+							$valid_data[$reg_url_link]
965
+						);
966
+						if (isset($valid_data['primary_attendee'])) {
967
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
968
+								? $valid_data['primary_attendee']
969
+								: false;
970
+							unset($valid_data['primary_attendee']);
971
+						}
972
+						// now loop through our array of valid post data && process attendee reg forms
973
+						foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
974
+							if (! in_array($form_section, $non_input_form_sections)) {
975
+								foreach ($form_inputs as $form_input => $input_value) {
976
+									// \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
977
+									// check for critical inputs
978
+									if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
979
+										$form_input,
980
+										$input_value
981
+									)
982
+									) {
983
+										return false;
984
+									}
985
+									// store a bit of data about the primary attendee
986
+									if ($att_nmbr === 1
987
+										&& ! empty($input_value)
988
+										&& $reg_url_link === $primary_registrant['line_item_id']
989
+									) {
990
+										$primary_registrant[$form_input] = $input_value;
991
+									} elseif ($copy_primary
992
+										&& $input_value === null
993
+										&& isset($primary_registrant[$form_input])
994
+									) {
995
+										$input_value = $primary_registrant[$form_input];
996
+									}
997
+									// now attempt to save the input data
998
+									if (! $this->_save_registration_form_input(
999
+										$registration,
1000
+										$form_input,
1001
+										$input_value
1002
+									)
1003
+									) {
1004
+										EE_Error::add_error(
1005
+											sprintf(
1006
+												esc_html__(
1007
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1008
+													'event_espresso'
1009
+												),
1010
+												$form_input,
1011
+												$input_value
1012
+											),
1013
+											__FILE__,
1014
+											__FUNCTION__,
1015
+											__LINE__
1016
+										);
1017
+										return false;
1018
+									}
1019
+								}
1020
+							}
1021
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1022
+					}
1023
+					//EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1024
+					// this registration does not require additional attendee information ?
1025
+					if ($copy_primary
1026
+						&& $att_nmbr > 1
1027
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1028
+					) {
1029
+						// just copy the primary registrant
1030
+						$attendee = $this->checkout->primary_attendee_obj;
1031
+					} else {
1032
+						// ensure critical details are set for additional attendees
1033
+						$this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1034
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1035
+								$this->_attendee_data[$reg_url_link]
1036
+							)
1037
+							: $this->_attendee_data[$reg_url_link];
1038
+						// execute create attendee command (which may return an existing attendee)
1039
+						$attendee = EE_Registry::instance()->BUS->execute(
1040
+							new CreateAttendeeCommand(
1041
+								$this->_attendee_data[$reg_url_link],
1042
+								$registration
1043
+							)
1044
+						);
1045
+						// who's #1 ?
1046
+						if ($att_nmbr === 1) {
1047
+							$this->checkout->primary_attendee_obj = $attendee;
1048
+						}
1049
+					}
1050
+					// EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1051
+					// add relation to registration, set attendee ID, and cache attendee
1052
+					$this->_associate_attendee_with_registration($registration, $attendee);
1053
+					// \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1054
+					if (! $registration->attendee() instanceof EE_Attendee) {
1055
+						EE_Error::add_error(
1056
+							sprintf(
1057
+								esc_html__(
1058
+									'Registration %s has an invalid or missing Attendee object.',
1059
+									'event_espresso'
1060
+								),
1061
+								$reg_url_link
1062
+							),
1063
+							__FILE__,
1064
+							__FUNCTION__,
1065
+							__LINE__
1066
+						);
1067
+						return false;
1068
+					}
1069
+					/** @type EE_Registration_Processor $registration_processor */
1070
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1071
+					// at this point, we should have enough details about the registrant to consider the registration
1072
+					// NOT incomplete
1073
+					$registration_processor->toggle_incomplete_registration_status_to_default(
1074
+						$registration,
1075
+						false,
1076
+						new Context(
1077
+							'spco_reg_step_attendee_information_process_registrations',
1078
+							esc_html__(
1079
+								'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1080
+								'event_espresso'
1081
+							)
1082
+						)
1083
+					);
1084
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1085
+					// abandoned
1086
+					$this->checkout->transaction->toggle_failed_transaction_status();
1087
+					// if we've gotten this far, then let's save what we have
1088
+					$registration->save();
1089
+					// add relation between TXN and registration
1090
+					$this->_associate_registration_with_transaction($registration);
1091
+				}
1092
+			} else {
1093
+				EE_Error::add_error(
1094
+					esc_html__(
1095
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1096
+						'event_espresso'
1097
+					),
1098
+					__FILE__,
1099
+					__FUNCTION__,
1100
+					__LINE__
1101
+				);
1102
+				// remove malformed data
1103
+				unset($valid_data[$reg_url_link]);
1104
+				return false;
1105
+			}
1106
+
1107
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1108
+		return $att_nmbr;
1109
+	}
1110
+
1111
+
1112
+	/**
1113
+	 *    _save_registration_form_input
1114
+	 *
1115
+	 * @param EE_Registration $registration
1116
+	 * @param string          $form_input
1117
+	 * @param string          $input_value
1118
+	 * @return bool
1119
+	 * @throws EE_Error
1120
+	 * @throws InvalidArgumentException
1121
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1122
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1123
+	 */
1124
+	private function _save_registration_form_input(
1125
+		EE_Registration $registration,
1126
+		$form_input = '',
1127
+		$input_value = ''
1128
+	) {
1129
+		// \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1130
+		// \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1131
+		// \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1132
+		// allow for plugins to hook in and do their own processing of the form input.
1133
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1134
+		if (apply_filters(
1135
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1136
+			false,
1137
+			$registration,
1138
+			$form_input,
1139
+			$input_value,
1140
+			$this
1141
+		)) {
1142
+			return true;
1143
+		}
1144
+		/*
1145 1145
          * $answer_cache_id is the key used to find the EE_Answer we want
1146 1146
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1147 1147
          */
1148
-        $answer_cache_id = $this->checkout->reg_url_link
1149
-            ? $form_input . '-' . $registration->reg_url_link()
1150
-            : $form_input;
1151
-        $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1152
-                           && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
1153
-            ? true
1154
-            : false;
1155
-        //rename form_inputs if they are EE_Attendee properties
1156
-        switch ((string) $form_input) {
1157
-            case 'state':
1158
-            case 'STA_ID':
1159
-                $attendee_property = true;
1160
-                $form_input        = 'STA_ID';
1161
-                break;
1162
-
1163
-            case 'country':
1164
-            case 'CNT_ISO':
1165
-                $attendee_property = true;
1166
-                $form_input        = 'CNT_ISO';
1167
-                break;
1168
-
1169
-            default:
1170
-                $ATT_input = 'ATT_' . $form_input;
1171
-                //EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1172
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1173
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1174
-        }
1175
-        // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1176
-        // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1177
-        // EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1178
-        // if this form input has a corresponding attendee property
1179
-        if ($attendee_property) {
1180
-            $this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1181
-            if ($answer_is_obj) {
1182
-                // and delete the corresponding answer since we won't be storing this data in that object
1183
-                $registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1184
-                $this->_registration_answers[$answer_cache_id]->delete_permanently();
1185
-            }
1186
-            return true;
1187
-        } elseif ($answer_is_obj) {
1188
-            // save this data to the answer object
1189
-            $this->_registration_answers[$answer_cache_id]->set_value($input_value);
1190
-            $result = $this->_registration_answers[$answer_cache_id]->save();
1191
-            return $result !== false ? true : false;
1192
-        } else {
1193
-            foreach ($this->_registration_answers as $answer) {
1194
-                if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1195
-                    $answer->set_value($input_value);
1196
-                    $result = $answer->save();
1197
-                    return $result !== false ? true : false;
1198
-                }
1199
-            }
1200
-        }
1201
-        return false;
1202
-    }
1203
-
1204
-
1205
-    /**
1206
-     *    _verify_critical_attendee_details_are_set
1207
-     *
1208
-     * @param string $form_input
1209
-     * @param string $input_value
1210
-     * @return boolean
1211
-     */
1212
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1213
-        $form_input = '',
1214
-        $input_value = ''
1215
-    ) {
1216
-        if (empty($input_value)) {
1217
-            // if the form input isn't marked as being required, then just return
1218
-            if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1219
-                return true;
1220
-            }
1221
-            switch ($form_input) {
1222
-                case 'fname':
1223
-                    EE_Error::add_error(
1224
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1225
-                        __FILE__,
1226
-                        __FUNCTION__,
1227
-                        __LINE__
1228
-                    );
1229
-                    return false;
1230
-                    break;
1231
-                case 'lname':
1232
-                    EE_Error::add_error(
1233
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1234
-                        __FILE__,
1235
-                        __FUNCTION__,
1236
-                        __LINE__
1237
-                    );
1238
-                    return false;
1239
-                    break;
1240
-                case 'email':
1241
-                    EE_Error::add_error(
1242
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1243
-                        __FILE__,
1244
-                        __FUNCTION__,
1245
-                        __LINE__
1246
-                    );
1247
-                    return false;
1248
-                    break;
1249
-            }
1250
-        }
1251
-        return true;
1252
-    }
1253
-
1254
-
1255
-    /**
1256
-     *    _associate_attendee_with_registration
1257
-     *
1258
-     * @param EE_Registration $registration
1259
-     * @param EE_Attendee     $attendee
1260
-     * @return void
1261
-     * @throws EE_Error
1262
-     * @throws RuntimeException
1263
-     */
1264
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1265
-    {
1266
-        // add relation to attendee
1267
-        $registration->_add_relation_to($attendee, 'Attendee');
1268
-        $registration->set_attendee_id($attendee->ID());
1269
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1270
-    }
1271
-
1272
-
1273
-    /**
1274
-     *    _associate_registration_with_transaction
1275
-     *
1276
-     * @param EE_Registration $registration
1277
-     * @return void
1278
-     * @throws \EE_Error
1279
-     */
1280
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1281
-    {
1282
-        // add relation to registration
1283
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1284
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1285
-    }
1286
-
1287
-
1288
-    /**
1289
-     *    _copy_critical_attendee_details_from_primary_registrant
1290
-     *    ensures that all attendees at least have data for first name, last name, and email address
1291
-     *
1292
-     * @param array $attendee_data
1293
-     * @return array
1294
-     * @throws \EE_Error
1295
-     */
1296
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1297
-    {
1298
-        // bare minimum critical details include first name, last name, email address
1299
-        $critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1300
-        // add address info to critical details?
1301
-        if (apply_filters(
1302
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1303
-            false
1304
-        )) {
1305
-            $address_details           = array(
1306
-                'ATT_address',
1307
-                'ATT_address2',
1308
-                'ATT_city',
1309
-                'STA_ID',
1310
-                'CNT_ISO',
1311
-                'ATT_zip',
1312
-                'ATT_phone',
1313
-            );
1314
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1315
-        }
1316
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1317
-            if (! isset($attendee_data[$critical_attendee_detail])
1318
-                || empty($attendee_data[$critical_attendee_detail])
1319
-            ) {
1320
-                $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1321
-                    $critical_attendee_detail
1322
-                );
1323
-            }
1324
-        }
1325
-        return $attendee_data;
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     *    update_reg_step
1331
-     *    this is the final step after a user  revisits the site to edit their attendee information
1332
-     *    this gets called AFTER the process_reg_step() method above
1333
-     *
1334
-     * @return bool
1335
-     * @throws EE_Error
1336
-     * @throws InvalidArgumentException
1337
-     * @throws ReflectionException
1338
-     * @throws RuntimeException
1339
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1340
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1341
-     */
1342
-    public function update_reg_step()
1343
-    {
1344
-        // save everything
1345
-        if ($this->process_reg_step()) {
1346
-            $this->checkout->redirect     = true;
1347
-            $this->checkout->redirect_url = add_query_arg(
1348
-                array(
1349
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1350
-                    'revisit'        => true,
1351
-                ),
1352
-                $this->checkout->thank_you_page_url
1353
-            );
1354
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1355
-            return true;
1356
-        }
1357
-        return false;
1358
-    }
1148
+		$answer_cache_id = $this->checkout->reg_url_link
1149
+			? $form_input . '-' . $registration->reg_url_link()
1150
+			: $form_input;
1151
+		$answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1152
+						   && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
1153
+			? true
1154
+			: false;
1155
+		//rename form_inputs if they are EE_Attendee properties
1156
+		switch ((string) $form_input) {
1157
+			case 'state':
1158
+			case 'STA_ID':
1159
+				$attendee_property = true;
1160
+				$form_input        = 'STA_ID';
1161
+				break;
1162
+
1163
+			case 'country':
1164
+			case 'CNT_ISO':
1165
+				$attendee_property = true;
1166
+				$form_input        = 'CNT_ISO';
1167
+				break;
1168
+
1169
+			default:
1170
+				$ATT_input = 'ATT_' . $form_input;
1171
+				//EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1172
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1173
+				$form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1174
+		}
1175
+		// EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1176
+		// EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1177
+		// EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1178
+		// if this form input has a corresponding attendee property
1179
+		if ($attendee_property) {
1180
+			$this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1181
+			if ($answer_is_obj) {
1182
+				// and delete the corresponding answer since we won't be storing this data in that object
1183
+				$registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1184
+				$this->_registration_answers[$answer_cache_id]->delete_permanently();
1185
+			}
1186
+			return true;
1187
+		} elseif ($answer_is_obj) {
1188
+			// save this data to the answer object
1189
+			$this->_registration_answers[$answer_cache_id]->set_value($input_value);
1190
+			$result = $this->_registration_answers[$answer_cache_id]->save();
1191
+			return $result !== false ? true : false;
1192
+		} else {
1193
+			foreach ($this->_registration_answers as $answer) {
1194
+				if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1195
+					$answer->set_value($input_value);
1196
+					$result = $answer->save();
1197
+					return $result !== false ? true : false;
1198
+				}
1199
+			}
1200
+		}
1201
+		return false;
1202
+	}
1203
+
1204
+
1205
+	/**
1206
+	 *    _verify_critical_attendee_details_are_set
1207
+	 *
1208
+	 * @param string $form_input
1209
+	 * @param string $input_value
1210
+	 * @return boolean
1211
+	 */
1212
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1213
+		$form_input = '',
1214
+		$input_value = ''
1215
+	) {
1216
+		if (empty($input_value)) {
1217
+			// if the form input isn't marked as being required, then just return
1218
+			if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1219
+				return true;
1220
+			}
1221
+			switch ($form_input) {
1222
+				case 'fname':
1223
+					EE_Error::add_error(
1224
+						esc_html__('First Name is a required value.', 'event_espresso'),
1225
+						__FILE__,
1226
+						__FUNCTION__,
1227
+						__LINE__
1228
+					);
1229
+					return false;
1230
+					break;
1231
+				case 'lname':
1232
+					EE_Error::add_error(
1233
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1234
+						__FILE__,
1235
+						__FUNCTION__,
1236
+						__LINE__
1237
+					);
1238
+					return false;
1239
+					break;
1240
+				case 'email':
1241
+					EE_Error::add_error(
1242
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1243
+						__FILE__,
1244
+						__FUNCTION__,
1245
+						__LINE__
1246
+					);
1247
+					return false;
1248
+					break;
1249
+			}
1250
+		}
1251
+		return true;
1252
+	}
1253
+
1254
+
1255
+	/**
1256
+	 *    _associate_attendee_with_registration
1257
+	 *
1258
+	 * @param EE_Registration $registration
1259
+	 * @param EE_Attendee     $attendee
1260
+	 * @return void
1261
+	 * @throws EE_Error
1262
+	 * @throws RuntimeException
1263
+	 */
1264
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1265
+	{
1266
+		// add relation to attendee
1267
+		$registration->_add_relation_to($attendee, 'Attendee');
1268
+		$registration->set_attendee_id($attendee->ID());
1269
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1270
+	}
1271
+
1272
+
1273
+	/**
1274
+	 *    _associate_registration_with_transaction
1275
+	 *
1276
+	 * @param EE_Registration $registration
1277
+	 * @return void
1278
+	 * @throws \EE_Error
1279
+	 */
1280
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1281
+	{
1282
+		// add relation to registration
1283
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1284
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1285
+	}
1286
+
1287
+
1288
+	/**
1289
+	 *    _copy_critical_attendee_details_from_primary_registrant
1290
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1291
+	 *
1292
+	 * @param array $attendee_data
1293
+	 * @return array
1294
+	 * @throws \EE_Error
1295
+	 */
1296
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1297
+	{
1298
+		// bare minimum critical details include first name, last name, email address
1299
+		$critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1300
+		// add address info to critical details?
1301
+		if (apply_filters(
1302
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1303
+			false
1304
+		)) {
1305
+			$address_details           = array(
1306
+				'ATT_address',
1307
+				'ATT_address2',
1308
+				'ATT_city',
1309
+				'STA_ID',
1310
+				'CNT_ISO',
1311
+				'ATT_zip',
1312
+				'ATT_phone',
1313
+			);
1314
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1315
+		}
1316
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1317
+			if (! isset($attendee_data[$critical_attendee_detail])
1318
+				|| empty($attendee_data[$critical_attendee_detail])
1319
+			) {
1320
+				$attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1321
+					$critical_attendee_detail
1322
+				);
1323
+			}
1324
+		}
1325
+		return $attendee_data;
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 *    update_reg_step
1331
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1332
+	 *    this gets called AFTER the process_reg_step() method above
1333
+	 *
1334
+	 * @return bool
1335
+	 * @throws EE_Error
1336
+	 * @throws InvalidArgumentException
1337
+	 * @throws ReflectionException
1338
+	 * @throws RuntimeException
1339
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1340
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1341
+	 */
1342
+	public function update_reg_step()
1343
+	{
1344
+		// save everything
1345
+		if ($this->process_reg_step()) {
1346
+			$this->checkout->redirect     = true;
1347
+			$this->checkout->redirect_url = add_query_arg(
1348
+				array(
1349
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1350
+					'revisit'        => true,
1351
+				),
1352
+				$this->checkout->thank_you_page_url
1353
+			);
1354
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1355
+			return true;
1356
+		}
1357
+		return false;
1358
+	}
1359 1359
 }
Please login to merge, or discard this patch.
Spacing   +51 added lines, -52 removed lines patch added patch discarded remove patch
@@ -48,7 +48,7 @@  discard block
 block discarded – undo
48 48
     {
49 49
         $this->_slug     = 'attendee_information';
50 50
         $this->_name     = esc_html__('Attendee Information', 'event_espresso');
51
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
51
+        $this->_template = SPCO_REG_STEPS_PATH.$this->_slug.DS.'attendee_info_main.template.php';
52 52
         $this->checkout  = $checkout;
53 53
         $this->_reset_success_message();
54 54
         $this->set_instructions(
@@ -59,11 +59,11 @@  discard block
 block discarded – undo
59 59
 
60 60
     public function translate_js_strings()
61 61
     {
62
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
62
+        EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
63 63
             ' is a required question.',
64 64
             'event_espresso'
65 65
         );
66
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
66
+        EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
67 67
             ' is a required question. Please enter a value for at least one of the options.',
68 68
             'event_espresso'
69 69
         );
@@ -71,18 +71,18 @@  discard block
 block discarded – undo
71 71
             'Please answer all required questions correctly before proceeding.',
72 72
             'event_espresso'
73 73
         );
74
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
74
+        EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
75 75
             esc_html__(
76 76
                 'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
77 77
                 'event_espresso'
78 78
             ),
79 79
             '<br/>'
80 80
         );
81
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
81
+        EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
82 82
             'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
83 83
             'event_espresso'
84 84
         );
85
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
85
+        EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
86 86
             'You must enter a valid email address.',
87 87
             'event_espresso'
88 88
         );
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
                     && $this->checkout->visit_allows_processing_of_this_registration($registration)
146 146
                 ) {
147 147
                     $subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
148
-                    if (! $this->checkout->admin_request) {
148
+                    if ( ! $this->checkout->admin_request) {
149 149
                         $template_args['registrations'][$registration->reg_url_link()]    = $registration;
150 150
                         $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
151 151
                             $template_args['ticket_count'][$registration->ticket()->ID()]
@@ -194,8 +194,7 @@  discard block
 block discarded – undo
194 194
                 'html_id'         => $this->reg_form_name(),
195 195
                 'subsections'     => $subsections,
196 196
                 'layout_strategy' => $this->checkout->admin_request ?
197
-                    new EE_Div_Per_Section_Layout() :
198
-                    new EE_Template_Layout(
197
+                    new EE_Div_Per_Section_Layout() : new EE_Template_Layout(
199 198
                         array(
200 199
                             'layout_template_file' => $this->_template, // layout_template
201 200
                             'template_args'        => $template_args,
@@ -238,7 +237,7 @@  discard block
 block discarded – undo
238 237
             if ($question_groups) {
239 238
                 // array of params to pass to parent constructor
240 239
                 $form_args = array(
241
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
240
+                    'html_id'         => 'ee-registration-'.$registration->reg_url_link(),
242 241
                     'html_class'      => 'ee-reg-form-attendee-dv',
243 242
                     'html_style'      => $this->checkout->admin_request
244 243
                         ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
@@ -294,7 +293,7 @@  discard block
 block discarded – undo
294 293
         // generate hidden input
295 294
         return new EE_Hidden_Input(
296 295
             array(
297
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
296
+                'html_id' => 'additional-attendee-reg-info-'.$registration->reg_url_link(),
298 297
                 'default' => $additional_attendee_reg_info,
299 298
             )
300 299
         );
@@ -314,11 +313,11 @@  discard block
 block discarded – undo
314 313
     {
315 314
         // array of params to pass to parent constructor
316 315
         $form_args = array(
317
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
316
+            'html_id'         => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-'.$registration->ID(),
318 317
             'html_class'      => $this->checkout->admin_request
319 318
                 ? 'form-table ee-reg-form-qstn-grp-dv'
320 319
                 : 'ee-reg-form-qstn-grp-dv',
321
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() .  '-' . $registration->ID() . '-lbl',
320
+            'html_label_id'   => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-'.$registration->ID().'-lbl',
322 321
             'subsections'     => array(
323 322
                 'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
324 323
             ),
@@ -329,7 +328,7 @@  discard block
 block discarded – undo
329 328
         // where params
330 329
         $query_params = array('QST_deleted' => 0);
331 330
         // don't load admin only questions on the frontend
332
-        if (! $this->checkout->admin_request) {
331
+        if ( ! $this->checkout->admin_request) {
333 332
             $query_params['QST_admin_only'] = array('!=', true);
334 333
         }
335 334
         $questions = $question_group->get_many_related(
@@ -473,7 +472,7 @@  discard block
 block discarded – undo
473 472
     {
474 473
         return new EE_Form_Section_HTML(
475 474
             EEH_Template::locate_template(
476
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
475
+                SPCO_REG_STEPS_PATH.$this->_slug.DS.'_auto_copy_attendee_info.template.php',
477 476
                 apply_filters(
478 477
                     'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
479 478
                     array()
@@ -505,16 +504,16 @@  discard block
 block discarded – undo
505 504
                 if ($registration->ticket()->ID() !== $prev_ticket) {
506 505
                     $item_name = $registration->ticket()->name();
507 506
                     $item_name .= $registration->ticket()->description() !== ''
508
-                        ? ' - ' . $registration->ticket()->description()
507
+                        ? ' - '.$registration->ticket()->description()
509 508
                         : '';
510
-                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
509
+                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-'.$registration->ticket()->ID().']'] =
511 510
                         new EE_Form_Section_HTML(
512
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
511
+                            '<h6 class="spco-copy-attendee-event-hdr">'.$item_name.'</h6>'
513 512
                         );
514 513
                     $prev_ticket = $registration->ticket()->ID();
515 514
                 }
516 515
 
517
-                $copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
516
+                $copy_attendee_info_inputs['spco_copy_attendee_chk['.$registration->ID().']'] =
518 517
                     new EE_Checkbox_Multi_Input(
519 518
                         array(
520 519
                             $registration->ID() => sprintf(
@@ -523,7 +522,7 @@  discard block
 block discarded – undo
523 522
                             ),
524 523
                         ),
525 524
                         array(
526
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
525
+                            'html_id'                 => 'spco-copy-attendee-chk-'.$registration->reg_url_link(),
527 526
                             'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
528 527
                             'display_html_label_text' => false,
529 528
                         )
@@ -572,7 +571,7 @@  discard block
 block discarded – undo
572 571
             $registration,
573 572
             $question->system_ID()
574 573
         );
575
-        $answer       = $answer_value === null
574
+        $answer = $answer_value === null
576 575
             ? EEM_Answer::instance()->get_one(
577 576
                 array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
578 577
             )
@@ -589,14 +588,14 @@  discard block
 block discarded – undo
589 588
         }
590 589
         // verify instance
591 590
         if ($answer instanceof EE_Answer) {
592
-            if (! empty($answer_value)) {
591
+            if ( ! empty($answer_value)) {
593 592
                 $answer->set('ANS_value', $answer_value);
594 593
             }
595 594
             $answer->cache('Question', $question);
596 595
             //remember system ID had a bug where sometimes it could be null
597 596
             $answer_cache_id = $question->is_system_question()
598
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
599
-                : $question->ID() . '-' . $registration->reg_url_link();
597
+                ? $question->system_ID().'-'.$registration->reg_url_link()
598
+                : $question->ID().'-'.$registration->reg_url_link();
600 599
             $registration->cache('Answer', $answer, $answer_cache_id);
601 600
         }
602 601
         return $this->_generate_question_input($registration, $question, $answer);
@@ -628,18 +627,18 @@  discard block
 block discarded – undo
628 627
             10,
629 628
             4
630 629
         );
631
-        $input_constructor_args                  = array(
632
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
633
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
634
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
635
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
630
+        $input_constructor_args = array(
631
+            'html_name'        => 'ee_reg_qstn['.$registration->ID().']['.$identifier.']',
632
+            'html_id'          => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
633
+            'html_class'       => 'ee-reg-qstn ee-reg-qstn-'.$identifier,
634
+            'html_label_id'    => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
636 635
             'html_label_class' => 'ee-reg-qstn',
637 636
         );
638 637
         $input_constructor_args['html_label_id'] .= '-lbl';
639 638
         if ($answer instanceof EE_Answer && $answer->ID()) {
640
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
641
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
642
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
639
+            $input_constructor_args['html_name']     .= '['.$answer->ID().']';
640
+            $input_constructor_args['html_id']       .= '-'.$answer->ID();
641
+            $input_constructor_args['html_label_id'] .= '-'.$answer->ID();
643 642
         }
644 643
         $form_input = $question->generate_form_input(
645 644
             $registration,
@@ -682,7 +681,7 @@  discard block
 block discarded – undo
682 681
         $countries = $this->checkout->action === 'process_reg_step'
683 682
             ? EEM_Country::instance()->get_all_countries()
684 683
             : EEM_Country::instance()->get_all_active_countries();
685
-        if (! empty($countries)) {
684
+        if ( ! empty($countries)) {
686 685
             foreach ($countries as $country) {
687 686
                 if ($country instanceof EE_Country) {
688 687
                     $country_options[$country->ID()] = $country->name();
@@ -732,7 +731,7 @@  discard block
 block discarded – undo
732 731
         $states        = $this->checkout->action === 'process_reg_step'
733 732
             ? EEM_State::instance()->get_all_states()
734 733
             : EEM_State::instance()->get_all_active_states();
735
-        if (! empty($states)) {
734
+        if ( ! empty($states)) {
736 735
             foreach ($states as $state) {
737 736
                 if ($state instanceof EE_State) {
738 737
                     $state_options[$state->country()->name()][$state->ID()] = $state->name();
@@ -784,7 +783,7 @@  discard block
 block discarded – undo
784 783
             );
785 784
             return false;
786 785
         }
787
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
786
+        if ( ! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
788 787
             EE_Error::add_error(
789 788
                 esc_html__(
790 789
                     'A valid transaction could not be initiated for processing your registrations.',
@@ -801,10 +800,10 @@  discard block
 block discarded – undo
801 800
         // verify we got the goods
802 801
         if (empty($registrations)) {
803 802
             //combine the old translated string with a new one, in order to not break translations
804
-            $error_message = esc_html__( 'Your form data could not be applied to any valid registrations.', 'event_espresso' )
803
+            $error_message = esc_html__('Your form data could not be applied to any valid registrations.', 'event_espresso')
805 804
                              . sprintf(
806 805
                                  esc_html__('%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.', 'event_espresso'),
807
-                                 '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
806
+                                 '<a href="'.get_post_type_archive_link('espresso_events').'" >',
808 807
                                  '</a>',
809 808
                                  '<br />'
810 809
                              );
@@ -823,7 +822,7 @@  discard block
 block discarded – undo
823 822
         if ($registrations_processed === false) {
824 823
             // but return immediately if the previous step exited early due to errors
825 824
             return false;
826
-        } elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
825
+        } elseif ( ! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
827 826
             // generate a correctly translated string for all possible singular/plural combinations
828 827
             if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
829 828
                 $error_msg = sprintf(
@@ -904,7 +903,7 @@  discard block
 block discarded – undo
904 903
         // grab the saved registrations from the transaction
905 904
         foreach ($registrations as $registration) {
906 905
             // verify EE_Registration object
907
-            if (! $registration instanceof EE_Registration) {
906
+            if ( ! $registration instanceof EE_Registration) {
908 907
                 EE_Error::add_error(
909 908
                     esc_html__(
910 909
                         'An invalid Registration object was discovered when attempting to process your registration information.',
@@ -919,12 +918,12 @@  discard block
 block discarded – undo
919 918
             /** @var string $reg_url_link */
920 919
             $reg_url_link = $registration->reg_url_link();
921 920
             // reg_url_link exists ?
922
-            if (! empty($reg_url_link)) {
921
+            if ( ! empty($reg_url_link)) {
923 922
                 // should this registration be processed during this visit ?
924 923
                 if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
925 924
                     // if NOT revisiting, then let's save the registration now,
926 925
                     // so that we have a REG_ID to use when generating other objects
927
-                    if (! $this->checkout->revisit) {
926
+                    if ( ! $this->checkout->revisit) {
928 927
                         $registration->save();
929 928
                     }
930 929
                     /**
@@ -959,7 +958,7 @@  discard block
 block discarded – undo
959 958
                             ? true
960 959
                             : false;
961 960
                         // filter form input data for this registration
962
-                        $valid_data[$reg_url_link] = (array)apply_filters(
961
+                        $valid_data[$reg_url_link] = (array) apply_filters(
963 962
                             'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
964 963
                             $valid_data[$reg_url_link]
965 964
                         );
@@ -971,11 +970,11 @@  discard block
 block discarded – undo
971 970
                         }
972 971
                         // now loop through our array of valid post data && process attendee reg forms
973 972
                         foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
974
-                            if (! in_array($form_section, $non_input_form_sections)) {
973
+                            if ( ! in_array($form_section, $non_input_form_sections)) {
975 974
                                 foreach ($form_inputs as $form_input => $input_value) {
976 975
                                     // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
977 976
                                     // check for critical inputs
978
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
977
+                                    if ( ! $this->_verify_critical_attendee_details_are_set_and_validate_email(
979 978
                                         $form_input,
980 979
                                         $input_value
981 980
                                     )
@@ -995,7 +994,7 @@  discard block
 block discarded – undo
995 994
                                         $input_value = $primary_registrant[$form_input];
996 995
                                     }
997 996
                                     // now attempt to save the input data
998
-                                    if (! $this->_save_registration_form_input(
997
+                                    if ( ! $this->_save_registration_form_input(
999 998
                                         $registration,
1000 999
                                         $form_input,
1001 1000
                                         $input_value
@@ -1051,7 +1050,7 @@  discard block
 block discarded – undo
1051 1050
                     // add relation to registration, set attendee ID, and cache attendee
1052 1051
                     $this->_associate_attendee_with_registration($registration, $attendee);
1053 1052
                     // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1054
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1053
+                    if ( ! $registration->attendee() instanceof EE_Attendee) {
1055 1054
                         EE_Error::add_error(
1056 1055
                             sprintf(
1057 1056
                                 esc_html__(
@@ -1146,7 +1145,7 @@  discard block
 block discarded – undo
1146 1145
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1147 1146
          */
1148 1147
         $answer_cache_id = $this->checkout->reg_url_link
1149
-            ? $form_input . '-' . $registration->reg_url_link()
1148
+            ? $form_input.'-'.$registration->reg_url_link()
1150 1149
             : $form_input;
1151 1150
         $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1152 1151
                            && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
@@ -1167,10 +1166,10 @@  discard block
 block discarded – undo
1167 1166
                 break;
1168 1167
 
1169 1168
             default:
1170
-                $ATT_input = 'ATT_' . $form_input;
1169
+                $ATT_input = 'ATT_'.$form_input;
1171 1170
                 //EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1172 1171
                 $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1173
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1172
+                $form_input        = $attendee_property ? 'ATT_'.$form_input : $form_input;
1174 1173
         }
1175 1174
         // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1176 1175
         // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
@@ -1215,7 +1214,7 @@  discard block
 block discarded – undo
1215 1214
     ) {
1216 1215
         if (empty($input_value)) {
1217 1216
             // if the form input isn't marked as being required, then just return
1218
-            if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1217
+            if ( ! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1219 1218
                 return true;
1220 1219
             }
1221 1220
             switch ($form_input) {
@@ -1302,7 +1301,7 @@  discard block
 block discarded – undo
1302 1301
             'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1303 1302
             false
1304 1303
         )) {
1305
-            $address_details           = array(
1304
+            $address_details = array(
1306 1305
                 'ATT_address',
1307 1306
                 'ATT_address2',
1308 1307
                 'ATT_city',
@@ -1314,7 +1313,7 @@  discard block
 block discarded – undo
1314 1313
             $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1315 1314
         }
1316 1315
         foreach ($critical_attendee_details as $critical_attendee_detail) {
1317
-            if (! isset($attendee_data[$critical_attendee_detail])
1316
+            if ( ! isset($attendee_data[$critical_attendee_detail])
1318 1317
                 || empty($attendee_data[$critical_attendee_detail])
1319 1318
             ) {
1320 1319
                 $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
Please login to merge, or discard this patch.
modules/ticket_sales_monitor/EED_Ticket_Sales_Monitor.module.php 3 patches
Doc Comments   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
      *
327 327
      * @param    EE_Ticket $ticket
328 328
      * @param int          $quantity
329
-     * @return bool
329
+     * @return integer
330 330
      * @throws EE_Error
331 331
      */
332 332
     protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
@@ -343,7 +343,7 @@  discard block
 block discarded – undo
343 343
     /**
344 344
      * @param  EE_Ticket $ticket
345 345
      * @param  int       $quantity
346
-     * @return bool
346
+     * @return integer
347 347
      * @throws EE_Error
348 348
      */
349 349
     protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
@@ -969,6 +969,7 @@  discard block
 block discarded – undo
969 969
     /**
970 970
      * @param EE_Ticket[]    $tickets_with_reservations
971 971
      * @param EE_Line_Item[] $valid_reserved_ticket_line_items
972
+     * @param string $source
972 973
      * @return int
973 974
      * @throws UnexpectedEntityException
974 975
      * @throws DomainException
Please login to merge, or discard this patch.
Indentation   +1050 added lines, -1050 removed lines patch added patch discarded remove patch
@@ -24,1057 +24,1057 @@
 block discarded – undo
24 24
 class EED_Ticket_Sales_Monitor extends EED_Module
25 25
 {
26 26
 
27
-    const debug = false;    //	true false
28
-
29
-    /**
30
-     * an array of raw ticket data from EED_Ticket_Selector
31
-     *
32
-     * @var array $ticket_selections
33
-     */
34
-    protected $ticket_selections = array();
35
-
36
-    /**
37
-     * the raw ticket data from EED_Ticket_Selector is organized in rows
38
-     * according to how they are displayed in the actual Ticket_Selector
39
-     * this tracks the current row being processed
40
-     *
41
-     * @var int $current_row
42
-     */
43
-    protected $current_row = 0;
44
-
45
-    /**
46
-     * an array for tracking names of tickets that have sold out
47
-     *
48
-     * @var array $sold_out_tickets
49
-     */
50
-    protected $sold_out_tickets = array();
51
-
52
-    /**
53
-     * an array for tracking names of tickets that have had their quantities reduced
54
-     *
55
-     * @var array $decremented_tickets
56
-     */
57
-    protected $decremented_tickets = array();
58
-
59
-
60
-
61
-    /**
62
-     * set_hooks - for hooking into EE Core, other modules, etc
63
-     *
64
-     * @return    void
65
-     */
66
-    public static function set_hooks()
67
-    {
68
-        // release tickets for expired carts
69
-        add_action(
70
-            'EED_Ticket_Selector__process_ticket_selections__before',
71
-            array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
72
-            1
73
-        );
74
-        // check ticket reserves AFTER MER does it's check (hence priority 20)
75
-        add_filter(
76
-            'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
77
-            array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
78
-            20,
79
-            3
80
-        );
81
-        // add notices for sold out tickets
82
-        add_action(
83
-            'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
84
-            array('EED_Ticket_Sales_Monitor', 'post_notices'),
85
-            10
86
-        );
87
-        // handle ticket quantities adjusted in cart
88
-        //add_action(
89
-        //	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
90
-        //	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
91
-        //	10, 2
92
-        //);
93
-        // handle tickets deleted from cart
94
-        add_action(
95
-            'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
96
-            array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
97
-            10,
98
-            2
99
-        );
100
-        // handle emptied carts
101
-        add_action(
102
-            'AHEE__EE_Session__reset_cart__before_reset',
103
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
104
-            10,
105
-            1
106
-        );
107
-        add_action(
108
-            'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
109
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
110
-            10,
111
-            1
112
-        );
113
-        // handle cancelled registrations
114
-        add_action(
115
-            'AHEE__EE_Session__reset_checkout__before_reset',
116
-            array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
117
-            10,
118
-            1
119
-        );
120
-        // cron tasks
121
-        add_action(
122
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
123
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
124
-            10,
125
-            1
126
-        );
127
-        add_action(
128
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
129
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
130
-            10,
131
-            1
132
-        );
133
-        add_action(
134
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
135
-            array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
136
-            10,
137
-            1
138
-        );
139
-    }
140
-
141
-
142
-
143
-    /**
144
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
145
-     *
146
-     * @return void
147
-     */
148
-    public static function set_hooks_admin()
149
-    {
150
-        EED_Ticket_Sales_Monitor::set_hooks();
151
-    }
152
-
153
-
154
-
155
-    /**
156
-     * @return EED_Ticket_Sales_Monitor|EED_Module
157
-     */
158
-    public static function instance()
159
-    {
160
-        return parent::get_instance(__CLASS__);
161
-    }
162
-
163
-
164
-
165
-    /**
166
-     * @param WP_Query $WP_Query
167
-     * @return    void
168
-     */
169
-    public function run($WP_Query)
170
-    {
171
-    }
172
-
173
-
174
-
175
-    /********************************** PRE_TICKET_SALES  **********************************/
176
-
177
-
178
-
179
-    /**
180
-     * Retrieves grand totals from the line items that have no TXN ID
181
-     * and timestamps less than the current time minus the session lifespan.
182
-     * These are carts that have been abandoned before the "registrant" even attempted to checkout.
183
-     * We're going to release the tickets for these line items before attempting to add more to the cart.
184
-     *
185
-     * @return void
186
-     * @throws DomainException
187
-     * @throws EE_Error
188
-     * @throws InvalidArgumentException
189
-     * @throws InvalidDataTypeException
190
-     * @throws InvalidInterfaceException
191
-     * @throws UnexpectedEntityException
192
-     */
193
-    public static function release_tickets_for_expired_carts()
194
-    {
195
-        do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
196
-        $expired_ticket_IDs      = array();
197
-        $valid_ticket_line_items = array();
198
-        $total_line_items        = EEM_Line_Item::instance()->get_total_line_items_with_no_transaction();
199
-        if (empty($total_line_items)) {
200
-            do_action(
201
-                'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
202
-                $total_line_items,
203
-                $valid_ticket_line_items,
204
-                $expired_ticket_IDs
205
-            );
206
-            return;
207
-        }
208
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
209
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
210
-            'EventEspresso\core\domain\values\session\SessionLifespan'
211
-        );
212
-        foreach ($total_line_items as $total_line_item) {
213
-            /** @var EE_Line_Item $total_line_item */
214
-            $ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
215
-            foreach ($ticket_line_items as $ticket_line_item) {
216
-                if (! $ticket_line_item instanceof EE_Line_Item) {
217
-                    continue;
218
-                }
219
-                if ($total_line_item->timestamp(true) <= $session_lifespan->expiration()) {
220
-                    $expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
221
-                } else {
222
-                    $valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
223
-                }
224
-            }
225
-        }
226
-        if (! empty($expired_ticket_IDs)) {
227
-            EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
228
-                \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
229
-                $valid_ticket_line_items,
230
-                __FUNCTION__
231
-            );
232
-            // let's get rid of expired line items so that they can't interfere with tracking
233
-            add_action(
234
-                'shutdown',
235
-                array('EED_Ticket_Sales_Monitor', 'clear_expired_line_items_with_no_transaction'),
236
-                999
237
-            );
238
-        }
239
-        do_action(
240
-            'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
241
-            $total_line_items,
242
-            $valid_ticket_line_items,
243
-            $expired_ticket_IDs
244
-        );
245
-    }
246
-
247
-
248
-
249
-    /********************************** VALIDATE_TICKET_SALE  **********************************/
250
-
251
-
252
-
253
-    /**
254
-     * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
255
-     *
256
-     * @param int       $qty
257
-     * @param EE_Ticket $ticket
258
-     * @return bool
259
-     * @throws UnexpectedEntityException
260
-     * @throws EE_Error
261
-     */
262
-    public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
263
-    {
264
-        $qty = absint($qty);
265
-        if ($qty > 0) {
266
-            $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
267
-        }
268
-        if (self::debug) {
269
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
270
-            echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
271
-        }
272
-        return $qty;
273
-    }
274
-
275
-
276
-
277
-    /**
278
-     * checks whether an individual ticket is available for purchase based on datetime, and ticket details
279
-     *
280
-     * @param   EE_Ticket $ticket
281
-     * @param int         $qty
282
-     * @return int
283
-     * @throws UnexpectedEntityException
284
-     * @throws EE_Error
285
-     */
286
-    protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
287
-    {
288
-        if (self::debug) {
289
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
290
-        }
291
-        if (! $ticket instanceof EE_Ticket) {
292
-            return 0;
293
-        }
294
-        if (self::debug) {
295
-            echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
296
-            echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
297
-        }
298
-        $ticket->refresh_from_db();
299
-        // first let's determine the ticket availability based on sales
300
-        $available = $ticket->qty('saleable');
301
-        if (self::debug) {
302
-            echo '<br /> . . . ticket->qty: ' . $ticket->qty();
303
-            echo '<br /> . . . ticket->sold: ' . $ticket->sold();
304
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
305
-            echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
306
-            echo '<br /> . . . available: ' . $available;
307
-        }
308
-        if ($available < 1) {
309
-            $this->_ticket_sold_out($ticket);
310
-            return 0;
311
-        }
312
-        if (self::debug) {
313
-            echo '<br /> . . . qty: ' . $qty;
314
-        }
315
-        if ($available < $qty) {
316
-            $qty = $available;
317
-            if (self::debug) {
318
-                echo '<br /> . . . QTY ADJUSTED: ' . $qty;
319
-            }
320
-            $this->_ticket_quantity_decremented($ticket);
321
-        }
322
-        $this->_reserve_ticket($ticket, $qty);
323
-        return $qty;
324
-    }
325
-
326
-
327
-
328
-    /**
329
-     * increments ticket reserved based on quantity passed
330
-     *
331
-     * @param    EE_Ticket $ticket
332
-     * @param int          $quantity
333
-     * @return bool
334
-     * @throws EE_Error
335
-     */
336
-    protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
337
-    {
338
-        if (self::debug) {
339
-            echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
340
-        }
341
-        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
342
-        return $ticket->save();
343
-    }
344
-
345
-
346
-
347
-    /**
348
-     * @param  EE_Ticket $ticket
349
-     * @param  int       $quantity
350
-     * @return bool
351
-     * @throws EE_Error
352
-     */
353
-    protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
354
-    {
355
-        if (self::debug) {
356
-            echo '<br /> . . . ticket->ID: ' . $ticket->ID();
357
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
358
-        }
359
-        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
360
-        if (self::debug) {
361
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
362
-        }
363
-        return $ticket->save() ? 1 : 0;
364
-    }
365
-
366
-
367
-
368
-    /**
369
-     * removes quantities within the ticket selector based on zero ticket availability
370
-     *
371
-     * @param    EE_Ticket $ticket
372
-     * @return    void
373
-     * @throws UnexpectedEntityException
374
-     * @throws EE_Error
375
-     */
376
-    protected function _ticket_sold_out(EE_Ticket $ticket)
377
-    {
378
-        if (self::debug) {
379
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
380
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
381
-        }
382
-        $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
383
-    }
384
-
385
-
386
-
387
-    /**
388
-     * adjusts quantities within the ticket selector based on decreased ticket availability
389
-     *
390
-     * @param    EE_Ticket $ticket
391
-     * @return void
392
-     * @throws UnexpectedEntityException
393
-     * @throws EE_Error
394
-     */
395
-    protected function _ticket_quantity_decremented(EE_Ticket $ticket)
396
-    {
397
-        if (self::debug) {
398
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
399
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
400
-        }
401
-        $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
402
-    }
403
-
404
-
405
-
406
-    /**
407
-     * builds string out of ticket and event name
408
-     *
409
-     * @param    EE_Ticket $ticket
410
-     * @return string
411
-     * @throws UnexpectedEntityException
412
-     * @throws EE_Error
413
-     */
414
-    protected function _get_ticket_and_event_name(EE_Ticket $ticket)
415
-    {
416
-        $event = $ticket->get_related_event();
417
-        if ($event instanceof EE_Event) {
418
-            $ticket_name = sprintf(
419
-                _x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
420
-                $ticket->name(),
421
-                $event->name()
422
-            );
423
-        } else {
424
-            $ticket_name = $ticket->name();
425
-        }
426
-        return $ticket_name;
427
-    }
428
-
429
-
430
-
431
-    /********************************** EVENT CART  **********************************/
432
-
433
-
434
-
435
-    /**
436
-     * releases or reserves ticket(s) based on quantity passed
437
-     *
438
-     * @param  EE_Line_Item $line_item
439
-     * @param  int          $quantity
440
-     * @return void
441
-     * @throws EE_Error
442
-     * @throws InvalidArgumentException
443
-     * @throws InvalidDataTypeException
444
-     * @throws InvalidInterfaceException
445
-     */
446
-    public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
447
-    {
448
-        $ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
449
-        if ($ticket instanceof EE_Ticket) {
450
-            $ticket->add_extra_meta(
451
-                EE_Ticket::META_KEY_TICKET_RESERVATIONS,
452
-                __LINE__ . ') ' . __METHOD__ . '()'
453
-            );
454
-            if ($quantity > 0) {
455
-                EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
456
-            } else {
457
-                EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
458
-            }
459
-        }
460
-    }
461
-
462
-
463
-
464
-    /**
465
-     * releases reserved ticket(s) based on quantity passed
466
-     *
467
-     * @param  EE_Ticket $ticket
468
-     * @param  int       $quantity
469
-     * @return void
470
-     * @throws EE_Error
471
-     */
472
-    public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
473
-    {
474
-        $ticket->add_extra_meta(
475
-            EE_Ticket::META_KEY_TICKET_RESERVATIONS,
476
-            __LINE__ . ') ' . __METHOD__ . '()'
477
-        );
478
-        EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
479
-    }
480
-
481
-
482
-
483
-    /********************************** POST_NOTICES  **********************************/
484
-
485
-
486
-
487
-    /**
488
-     * @return void
489
-     * @throws EE_Error
490
-     * @throws InvalidArgumentException
491
-     * @throws ReflectionException
492
-     * @throws InvalidDataTypeException
493
-     * @throws InvalidInterfaceException
494
-     */
495
-    public static function post_notices()
496
-    {
497
-        EED_Ticket_Sales_Monitor::instance()->_post_notices();
498
-    }
499
-
500
-
501
-
502
-    /**
503
-     * @return void
504
-     * @throws EE_Error
505
-     * @throws InvalidArgumentException
506
-     * @throws ReflectionException
507
-     * @throws InvalidDataTypeException
508
-     * @throws InvalidInterfaceException
509
-     */
510
-    protected function _post_notices()
511
-    {
512
-        if (self::debug) {
513
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
514
-        }
515
-        $refresh_msg    = '';
516
-        $none_added_msg = '';
517
-        if (defined('DOING_AJAX') && DOING_AJAX) {
518
-            $refresh_msg    = __(
519
-                'Please refresh the page to view updated ticket quantities.',
520
-                'event_espresso'
521
-            );
522
-            $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
523
-        }
524
-        if (! empty($this->sold_out_tickets)) {
525
-            EE_Error::add_attention(
526
-                sprintf(
527
-                    apply_filters(
528
-                        'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
529
-                        __(
530
-                            'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
531
-                            'event_espresso'
532
-                        )
533
-                    ),
534
-                    '<br />',
535
-                    implode('<br />', $this->sold_out_tickets),
536
-                    $none_added_msg,
537
-                    $refresh_msg
538
-                )
539
-            );
540
-            // alter code flow in the Ticket Selector for better UX
541
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
542
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
543
-            $this->sold_out_tickets = array();
544
-            // and reset the cart
545
-            EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
546
-        }
547
-        if (! empty($this->decremented_tickets)) {
548
-            EE_Error::add_attention(
549
-                sprintf(
550
-                    apply_filters(
551
-                        'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
552
-                        __(
553
-                            'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
554
-                            'event_espresso'
555
-                        )
556
-                    ),
557
-                    '<br />',
558
-                    implode('<br />', $this->decremented_tickets),
559
-                    $none_added_msg,
560
-                    $refresh_msg
561
-                )
562
-            );
563
-            $this->decremented_tickets = array();
564
-        }
565
-    }
566
-
567
-
568
-
569
-    /********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
570
-
571
-
572
-
573
-    /**
574
-     * releases reserved tickets for all registrations of an EE_Transaction
575
-     * by default, will NOT release tickets for finalized transactions
576
-     *
577
-     * @param    EE_Transaction $transaction
578
-     * @return int
579
-     * @throws EE_Error
580
-     * @throws InvalidSessionDataException
581
-     */
582
-    protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
583
-    {
584
-        if (self::debug) {
585
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
586
-            echo '<br /> . transaction->ID: ' . $transaction->ID();
587
-            echo '<br /> . TXN status_ID: ' . $transaction->status_ID();
588
-        }
589
-        // check if 'finalize_registration' step has been completed...
590
-        $finalized = $transaction->reg_step_completed('finalize_registration');
591
-        if (self::debug) {
592
-            // DEBUG LOG
593
-            EEH_Debug_Tools::log(
594
-                __CLASS__,
595
-                __FUNCTION__,
596
-                __LINE__,
597
-                array('finalized' => $finalized),
598
-                false,
599
-                'EE_Transaction: ' . $transaction->ID()
600
-            );
601
-        }
602
-        // how many tickets were released
603
-        $count = 0;
604
-        if (self::debug) {
605
-            echo '<br /> . . . TXN finalized: ' . $finalized;
606
-        }
607
-        $release_tickets_with_TXN_status = array(
608
-            EEM_Transaction::failed_status_code,
609
-            EEM_Transaction::abandoned_status_code,
610
-            EEM_Transaction::incomplete_status_code,
611
-        );
612
-        $events = array();
613
-        // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
614
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
615
-            // cancel any reserved tickets for registrations that were not approved
616
-            $registrations = $transaction->registrations();
617
-            if (self::debug) {
618
-                echo '<br /> . . . # registrations: ' . count($registrations);
619
-                $reg    = reset($registrations);
620
-                $ticket = $reg->ticket();
621
-                if ($ticket instanceof EE_Ticket) {
622
-                    $ticket->add_extra_meta(
623
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
624
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
625
-                    );
626
-                }
627
-            }
628
-            if (! empty($registrations)) {
629
-                foreach ($registrations as $registration) {
630
-                    if (
631
-                        $registration instanceof EE_Registration
632
-                        && $this->_release_reserved_ticket_for_registration($registration, $transaction)
633
-                    ) {
634
-                        $count++;
635
-                        $events[ $registration->event_ID() ] = $registration->event();
636
-                    }
637
-                }
638
-            }
639
-        }
640
-        if ($events !== array()) {
641
-            foreach ($events as $event) {
642
-                /** @var EE_Event $event */
643
-                $event->perform_sold_out_status_check();
644
-            }
645
-        }
646
-        return $count;
647
-    }
648
-
649
-
650
-
651
-    /**
652
-     * releases reserved tickets for an EE_Registration
653
-     * by default, will NOT release tickets for APPROVED registrations
654
-     *
655
-     * @param EE_Registration $registration
656
-     * @param EE_Transaction  $transaction
657
-     * @return int
658
-     * @throws EE_Error
659
-     */
660
-    protected function _release_reserved_ticket_for_registration(
661
-        EE_Registration $registration,
662
-        EE_Transaction $transaction
663
-    ) {
664
-        $STS_ID = $transaction->status_ID();
665
-        if (self::debug) {
666
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
667
-            echo '<br /> . . registration->ID: ' . $registration->ID();
668
-            echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
669
-            echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
670
-        }
671
-        if (
672
-            // release Tickets for Failed Transactions and Abandoned Transactions
673
-            $STS_ID === EEM_Transaction::failed_status_code
674
-            || $STS_ID === EEM_Transaction::abandoned_status_code
675
-            || (
676
-                // also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
677
-                $STS_ID === EEM_Transaction::incomplete_status_code
678
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
679
-            )
680
-        ) {
681
-            if (self::debug) {
682
-                echo '<br /><br /> . . RELEASE RESERVED TICKET';
683
-                $rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
684
-                echo '<br /> . . . registration HAS_RESERVED_TICKET_KEY: ';
685
-                var_dump($rsrvd);
686
-            }
687
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
688
-            return 1;
689
-        }
690
-        return 0;
691
-    }
692
-
693
-
694
-
695
-    /********************************** SESSION_CART_RESET  **********************************/
696
-
697
-
698
-
699
-    /**
700
-     * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
701
-     *
702
-     * @param EE_Session $session
703
-     * @return void
704
-     * @throws EE_Error
705
-     * @throws InvalidArgumentException
706
-     * @throws ReflectionException
707
-     * @throws InvalidDataTypeException
708
-     * @throws InvalidInterfaceException
709
-     */
710
-    public static function session_cart_reset(EE_Session $session)
711
-    {
712
-        if (self::debug) {
713
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
714
-        }
715
-        // first check of the session has a valid Checkout object
716
-        $checkout = $session->checkout();
717
-        if ($checkout instanceof EE_Checkout) {
718
-            // and use that to clear ticket reservations because it will update the associated registration meta data
719
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
720
-            return;
721
-        }
722
-        $cart = $session->cart();
723
-        if ($cart instanceof EE_Cart) {
724
-            if (self::debug) {
725
-                echo '<br /><br /> cart instance of EE_Cart: ';
726
-            }
727
-            EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
728
-        } else {
729
-            if (self::debug) {
730
-                echo '<br /><br /> invalid EE_Cart: ';
731
-                var_export($cart, true);
732
-            }
733
-        }
734
-    }
735
-
736
-
737
-
738
-    /**
739
-     * releases reserved tickets in the EE_Cart
740
-     *
741
-     * @param EE_Cart $cart
742
-     * @return void
743
-     * @throws EE_Error
744
-     * @throws InvalidArgumentException
745
-     * @throws ReflectionException
746
-     * @throws InvalidDataTypeException
747
-     * @throws InvalidInterfaceException
748
-     */
749
-    protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
750
-    {
751
-        if (self::debug) {
752
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
753
-        }
754
-        EE_Registry::instance()->load_helper('Line_Item');
755
-        $ticket_line_items = $cart->get_tickets();
756
-        if (empty($ticket_line_items)) {
757
-            return;
758
-        }
759
-        foreach ($ticket_line_items as $ticket_line_item) {
760
-            if (self::debug) {
761
-                echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
762
-            }
763
-            if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
764
-                if (self::debug) {
765
-                    echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
766
-                }
767
-                $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
768
-                if ($ticket instanceof EE_Ticket) {
769
-                    if (self::debug) {
770
-                        echo '<br /> . . ticket->ID(): ' . $ticket->ID();
771
-                        echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
772
-                    }
773
-                    $ticket->add_extra_meta(
774
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
775
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
776
-                    );
777
-                    $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
778
-                }
779
-            }
780
-        }
781
-        if (self::debug) {
782
-            echo '<br /><br /> RESET COMPLETED ';
783
-        }
784
-    }
785
-
786
-
787
-
788
-    /********************************** SESSION_CHECKOUT_RESET  **********************************/
789
-
790
-
791
-
792
-    /**
793
-     * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
794
-     *
795
-     * @param EE_Session $session
796
-     * @return void
797
-     * @throws EE_Error
798
-     * @throws InvalidSessionDataException
799
-     */
800
-    public static function session_checkout_reset(EE_Session $session)
801
-    {
802
-        $checkout = $session->checkout();
803
-        if ($checkout instanceof EE_Checkout) {
804
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
805
-        }
806
-    }
807
-
808
-
809
-
810
-    /**
811
-     * releases reserved tickets for the EE_Checkout->transaction
812
-     *
813
-     * @param EE_Checkout $checkout
814
-     * @return void
815
-     * @throws EE_Error
816
-     * @throws InvalidSessionDataException
817
-     */
818
-    protected function _session_checkout_reset(EE_Checkout $checkout)
819
-    {
820
-        if (self::debug) {
821
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
822
-        }
823
-        // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
824
-        if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
825
-            return;
826
-        }
827
-        $this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
828
-    }
829
-
830
-
831
-
832
-    /********************************** SESSION_EXPIRED_RESET  **********************************/
833
-
834
-
835
-
836
-    /**
837
-     * @param    EE_Session $session
838
-     * @return    void
839
-     */
840
-    public static function session_expired_reset(EE_Session $session)
841
-    {
842
-    }
843
-
844
-
845
-
846
-    /********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
847
-
848
-
849
-
850
-    /**
851
-     * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
852
-     * by default, will NOT release tickets for free transactions, or any that have received a payment
853
-     *
854
-     * @param EE_Transaction $transaction
855
-     * @return void
856
-     * @throws EE_Error
857
-     * @throws InvalidSessionDataException
858
-     */
859
-    public static function process_abandoned_transactions(EE_Transaction $transaction)
860
-    {
861
-        // is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
862
-        if ($transaction->is_free() || $transaction->paid() > 0) {
863
-            if (self::debug) {
864
-                // DEBUG LOG
865
-                EEH_Debug_Tools::log(
866
-                    __CLASS__,
867
-                    __FUNCTION__,
868
-                    __LINE__,
869
-                    array($transaction),
870
-                    false,
871
-                    'EE_Transaction: ' . $transaction->ID()
872
-                );
873
-            }
874
-            return;
875
-        }
876
-        // have their been any successful payments made ?
877
-        $payments = $transaction->payments();
878
-        foreach ($payments as $payment) {
879
-            if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
880
-                if (self::debug) {
881
-                    // DEBUG LOG
882
-                    EEH_Debug_Tools::log(
883
-                        __CLASS__,
884
-                        __FUNCTION__,
885
-                        __LINE__,
886
-                        array($payment),
887
-                        false,
888
-                        'EE_Transaction: ' . $transaction->ID()
889
-                    );
890
-                }
891
-                return;
892
-            }
893
-        }
894
-        // since you haven't even attempted to pay for your ticket...
895
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
896
-    }
897
-
898
-
899
-
900
-    /********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
901
-
902
-
903
-
904
-    /**
905
-     * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
906
-     *
907
-     * @param EE_Transaction $transaction
908
-     * @return void
909
-     * @throws EE_Error
910
-     * @throws InvalidSessionDataException
911
-     */
912
-    public static function process_failed_transactions(EE_Transaction $transaction)
913
-    {
914
-        // since you haven't even attempted to pay for your ticket...
915
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
916
-    }
917
-
918
-
919
-
920
-    /********************************** RESET RESERVATION COUNTS  *********************************/
921
-
922
-
923
-
924
-    /**
925
-     * Resets all ticket and datetime reserved counts to zero
926
-     * Tickets that are currently associated with a Transaction that is in progress
927
-     *
928
-     * @throws EE_Error
929
-     * @throws DomainException
930
-     * @throws InvalidDataTypeException
931
-     * @throws InvalidInterfaceException
932
-     * @throws InvalidArgumentException
933
-     * @throws UnexpectedEntityException
934
-     */
935
-    public static function reset_reservation_counts()
936
-    {
937
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
938
-        $valid_reserved_tickets = array();
939
-        /** @var EE_Transaction[] $transactions_not_in_progress */
940
-        $transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
941
-        foreach ($transactions_not_in_progress as $transaction) {
942
-            // if this TXN has been fully completed, then skip it
943
-            if ($transaction->reg_step_completed('finalize_registration')) {
944
-                continue;
945
-            }
946
-            $total_line_item = $transaction->total_line_item();
947
-            // $transaction_in_progress->line
948
-            if (! $total_line_item instanceof EE_Line_Item) {
949
-                throw new DomainException(
950
-                    esc_html__(
951
-                        'Transaction does not have a valid Total Line Item associated with it.',
952
-                        'event_espresso'
953
-                    )
954
-                );
955
-            }
956
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
957
-                $total_line_item
958
-            );
959
-        }
960
-        $total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
961
-        foreach ($total_line_items as $total_line_item) {
962
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
963
-                $total_line_item
964
-            );
965
-        }
966
-        $tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
967
-        return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
968
-            $tickets_with_reservations,
969
-            $valid_reserved_tickets,
970
-            __FUNCTION__
971
-        );
972
-    }
973
-
974
-
975
-
976
-    /**
977
-     * @param EE_Line_Item $total_line_item
978
-     * @return EE_Line_Item[]
979
-     */
980
-    private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
981
-    {
982
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
983
-        $valid_reserved_tickets = array();
984
-        $ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
985
-        foreach ($ticket_line_items as $ticket_line_item) {
986
-            if ($ticket_line_item instanceof EE_Line_Item) {
987
-                $valid_reserved_tickets[] = $ticket_line_item;
988
-            }
989
-        }
990
-        return $valid_reserved_tickets;
991
-    }
992
-
993
-
994
-
995
-    /**
996
-     * @param EE_Ticket[]    $tickets_with_reservations
997
-     * @param EE_Line_Item[] $valid_reserved_ticket_line_items
998
-     * @return int
999
-     * @throws UnexpectedEntityException
1000
-     * @throws DomainException
1001
-     * @throws EE_Error
1002
-     */
1003
-    private static function release_reservations_for_tickets(
1004
-        array $tickets_with_reservations,
1005
-        array $valid_reserved_ticket_line_items = array(),
1006
-        $source
1007
-    ) {
1008
-        $total_tickets_released = 0;
1009
-        $sold_out_events = array();
1010
-        foreach ($tickets_with_reservations as $ticket_with_reservations) {
1011
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1012
-                continue;
1013
-            }
1014
-            $reserved_qty = $ticket_with_reservations->reserved();
1015
-            foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1016
-                if (
1017
-                    $valid_reserved_ticket_line_item instanceof EE_Line_Item
1018
-                    && $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1019
-                ) {
1020
-                    $reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1021
-                }
1022
-            }
1023
-            if ($reserved_qty > 0) {
1024
-                $ticket_with_reservations->add_extra_meta(
1025
-                    EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1026
-                    __LINE__ . ') ' . $source . '()'
1027
-                );
1028
-                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1029
-                $ticket_with_reservations->save();
1030
-                $total_tickets_released += $reserved_qty;
1031
-                $event = $ticket_with_reservations->get_related_event();
1032
-                // track sold out events
1033
-                if ($event instanceof EE_Event && $event->is_sold_out()) {
1034
-                    $sold_out_events[] = $event;
1035
-                }
1036
-            }
1037
-        }
1038
-        // double check whether sold out events should remain sold out after releasing tickets
1039
-        if($sold_out_events !== array()){
1040
-            foreach ($sold_out_events as $sold_out_event) {
1041
-                /** @var EE_Event $sold_out_event */
1042
-                $sold_out_event->perform_sold_out_status_check();
1043
-            }
1044
-        }
1045
-        return $total_tickets_released;
1046
-    }
1047
-
1048
-
1049
-
1050
-    /********************************** SHUTDOWN  **********************************/
1051
-
1052
-
1053
-
1054
-    /**
1055
-     * @return false|int
1056
-     * @throws EE_Error
1057
-     * @throws InvalidArgumentException
1058
-     * @throws InvalidDataTypeException
1059
-     * @throws InvalidInterfaceException
1060
-     */
1061
-    public static function clear_expired_line_items_with_no_transaction()
1062
-    {
1063
-        /** @type WPDB $wpdb */
1064
-        global $wpdb;
1065
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1066
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
1067
-            'EventEspresso\core\domain\values\session\SessionLifespan'
1068
-        );
1069
-        return $wpdb->query(
1070
-            $wpdb->prepare(
1071
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
27
+	const debug = false;    //	true false
28
+
29
+	/**
30
+	 * an array of raw ticket data from EED_Ticket_Selector
31
+	 *
32
+	 * @var array $ticket_selections
33
+	 */
34
+	protected $ticket_selections = array();
35
+
36
+	/**
37
+	 * the raw ticket data from EED_Ticket_Selector is organized in rows
38
+	 * according to how they are displayed in the actual Ticket_Selector
39
+	 * this tracks the current row being processed
40
+	 *
41
+	 * @var int $current_row
42
+	 */
43
+	protected $current_row = 0;
44
+
45
+	/**
46
+	 * an array for tracking names of tickets that have sold out
47
+	 *
48
+	 * @var array $sold_out_tickets
49
+	 */
50
+	protected $sold_out_tickets = array();
51
+
52
+	/**
53
+	 * an array for tracking names of tickets that have had their quantities reduced
54
+	 *
55
+	 * @var array $decremented_tickets
56
+	 */
57
+	protected $decremented_tickets = array();
58
+
59
+
60
+
61
+	/**
62
+	 * set_hooks - for hooking into EE Core, other modules, etc
63
+	 *
64
+	 * @return    void
65
+	 */
66
+	public static function set_hooks()
67
+	{
68
+		// release tickets for expired carts
69
+		add_action(
70
+			'EED_Ticket_Selector__process_ticket_selections__before',
71
+			array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
72
+			1
73
+		);
74
+		// check ticket reserves AFTER MER does it's check (hence priority 20)
75
+		add_filter(
76
+			'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
77
+			array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
78
+			20,
79
+			3
80
+		);
81
+		// add notices for sold out tickets
82
+		add_action(
83
+			'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
84
+			array('EED_Ticket_Sales_Monitor', 'post_notices'),
85
+			10
86
+		);
87
+		// handle ticket quantities adjusted in cart
88
+		//add_action(
89
+		//	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
90
+		//	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
91
+		//	10, 2
92
+		//);
93
+		// handle tickets deleted from cart
94
+		add_action(
95
+			'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
96
+			array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
97
+			10,
98
+			2
99
+		);
100
+		// handle emptied carts
101
+		add_action(
102
+			'AHEE__EE_Session__reset_cart__before_reset',
103
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
104
+			10,
105
+			1
106
+		);
107
+		add_action(
108
+			'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
109
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
110
+			10,
111
+			1
112
+		);
113
+		// handle cancelled registrations
114
+		add_action(
115
+			'AHEE__EE_Session__reset_checkout__before_reset',
116
+			array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
117
+			10,
118
+			1
119
+		);
120
+		// cron tasks
121
+		add_action(
122
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
123
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
124
+			10,
125
+			1
126
+		);
127
+		add_action(
128
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
129
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
130
+			10,
131
+			1
132
+		);
133
+		add_action(
134
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
135
+			array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
136
+			10,
137
+			1
138
+		);
139
+	}
140
+
141
+
142
+
143
+	/**
144
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
145
+	 *
146
+	 * @return void
147
+	 */
148
+	public static function set_hooks_admin()
149
+	{
150
+		EED_Ticket_Sales_Monitor::set_hooks();
151
+	}
152
+
153
+
154
+
155
+	/**
156
+	 * @return EED_Ticket_Sales_Monitor|EED_Module
157
+	 */
158
+	public static function instance()
159
+	{
160
+		return parent::get_instance(__CLASS__);
161
+	}
162
+
163
+
164
+
165
+	/**
166
+	 * @param WP_Query $WP_Query
167
+	 * @return    void
168
+	 */
169
+	public function run($WP_Query)
170
+	{
171
+	}
172
+
173
+
174
+
175
+	/********************************** PRE_TICKET_SALES  **********************************/
176
+
177
+
178
+
179
+	/**
180
+	 * Retrieves grand totals from the line items that have no TXN ID
181
+	 * and timestamps less than the current time minus the session lifespan.
182
+	 * These are carts that have been abandoned before the "registrant" even attempted to checkout.
183
+	 * We're going to release the tickets for these line items before attempting to add more to the cart.
184
+	 *
185
+	 * @return void
186
+	 * @throws DomainException
187
+	 * @throws EE_Error
188
+	 * @throws InvalidArgumentException
189
+	 * @throws InvalidDataTypeException
190
+	 * @throws InvalidInterfaceException
191
+	 * @throws UnexpectedEntityException
192
+	 */
193
+	public static function release_tickets_for_expired_carts()
194
+	{
195
+		do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
196
+		$expired_ticket_IDs      = array();
197
+		$valid_ticket_line_items = array();
198
+		$total_line_items        = EEM_Line_Item::instance()->get_total_line_items_with_no_transaction();
199
+		if (empty($total_line_items)) {
200
+			do_action(
201
+				'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
202
+				$total_line_items,
203
+				$valid_ticket_line_items,
204
+				$expired_ticket_IDs
205
+			);
206
+			return;
207
+		}
208
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
209
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
210
+			'EventEspresso\core\domain\values\session\SessionLifespan'
211
+		);
212
+		foreach ($total_line_items as $total_line_item) {
213
+			/** @var EE_Line_Item $total_line_item */
214
+			$ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
215
+			foreach ($ticket_line_items as $ticket_line_item) {
216
+				if (! $ticket_line_item instanceof EE_Line_Item) {
217
+					continue;
218
+				}
219
+				if ($total_line_item->timestamp(true) <= $session_lifespan->expiration()) {
220
+					$expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
221
+				} else {
222
+					$valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
223
+				}
224
+			}
225
+		}
226
+		if (! empty($expired_ticket_IDs)) {
227
+			EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
228
+				\EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
229
+				$valid_ticket_line_items,
230
+				__FUNCTION__
231
+			);
232
+			// let's get rid of expired line items so that they can't interfere with tracking
233
+			add_action(
234
+				'shutdown',
235
+				array('EED_Ticket_Sales_Monitor', 'clear_expired_line_items_with_no_transaction'),
236
+				999
237
+			);
238
+		}
239
+		do_action(
240
+			'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
241
+			$total_line_items,
242
+			$valid_ticket_line_items,
243
+			$expired_ticket_IDs
244
+		);
245
+	}
246
+
247
+
248
+
249
+	/********************************** VALIDATE_TICKET_SALE  **********************************/
250
+
251
+
252
+
253
+	/**
254
+	 * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
255
+	 *
256
+	 * @param int       $qty
257
+	 * @param EE_Ticket $ticket
258
+	 * @return bool
259
+	 * @throws UnexpectedEntityException
260
+	 * @throws EE_Error
261
+	 */
262
+	public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
263
+	{
264
+		$qty = absint($qty);
265
+		if ($qty > 0) {
266
+			$qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
267
+		}
268
+		if (self::debug) {
269
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
270
+			echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
271
+		}
272
+		return $qty;
273
+	}
274
+
275
+
276
+
277
+	/**
278
+	 * checks whether an individual ticket is available for purchase based on datetime, and ticket details
279
+	 *
280
+	 * @param   EE_Ticket $ticket
281
+	 * @param int         $qty
282
+	 * @return int
283
+	 * @throws UnexpectedEntityException
284
+	 * @throws EE_Error
285
+	 */
286
+	protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
287
+	{
288
+		if (self::debug) {
289
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
290
+		}
291
+		if (! $ticket instanceof EE_Ticket) {
292
+			return 0;
293
+		}
294
+		if (self::debug) {
295
+			echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
296
+			echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
297
+		}
298
+		$ticket->refresh_from_db();
299
+		// first let's determine the ticket availability based on sales
300
+		$available = $ticket->qty('saleable');
301
+		if (self::debug) {
302
+			echo '<br /> . . . ticket->qty: ' . $ticket->qty();
303
+			echo '<br /> . . . ticket->sold: ' . $ticket->sold();
304
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
305
+			echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
306
+			echo '<br /> . . . available: ' . $available;
307
+		}
308
+		if ($available < 1) {
309
+			$this->_ticket_sold_out($ticket);
310
+			return 0;
311
+		}
312
+		if (self::debug) {
313
+			echo '<br /> . . . qty: ' . $qty;
314
+		}
315
+		if ($available < $qty) {
316
+			$qty = $available;
317
+			if (self::debug) {
318
+				echo '<br /> . . . QTY ADJUSTED: ' . $qty;
319
+			}
320
+			$this->_ticket_quantity_decremented($ticket);
321
+		}
322
+		$this->_reserve_ticket($ticket, $qty);
323
+		return $qty;
324
+	}
325
+
326
+
327
+
328
+	/**
329
+	 * increments ticket reserved based on quantity passed
330
+	 *
331
+	 * @param    EE_Ticket $ticket
332
+	 * @param int          $quantity
333
+	 * @return bool
334
+	 * @throws EE_Error
335
+	 */
336
+	protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
337
+	{
338
+		if (self::debug) {
339
+			echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
340
+		}
341
+		$ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
342
+		return $ticket->save();
343
+	}
344
+
345
+
346
+
347
+	/**
348
+	 * @param  EE_Ticket $ticket
349
+	 * @param  int       $quantity
350
+	 * @return bool
351
+	 * @throws EE_Error
352
+	 */
353
+	protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
354
+	{
355
+		if (self::debug) {
356
+			echo '<br /> . . . ticket->ID: ' . $ticket->ID();
357
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
358
+		}
359
+		$ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
360
+		if (self::debug) {
361
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
362
+		}
363
+		return $ticket->save() ? 1 : 0;
364
+	}
365
+
366
+
367
+
368
+	/**
369
+	 * removes quantities within the ticket selector based on zero ticket availability
370
+	 *
371
+	 * @param    EE_Ticket $ticket
372
+	 * @return    void
373
+	 * @throws UnexpectedEntityException
374
+	 * @throws EE_Error
375
+	 */
376
+	protected function _ticket_sold_out(EE_Ticket $ticket)
377
+	{
378
+		if (self::debug) {
379
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
380
+			echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
381
+		}
382
+		$this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
383
+	}
384
+
385
+
386
+
387
+	/**
388
+	 * adjusts quantities within the ticket selector based on decreased ticket availability
389
+	 *
390
+	 * @param    EE_Ticket $ticket
391
+	 * @return void
392
+	 * @throws UnexpectedEntityException
393
+	 * @throws EE_Error
394
+	 */
395
+	protected function _ticket_quantity_decremented(EE_Ticket $ticket)
396
+	{
397
+		if (self::debug) {
398
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
399
+			echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
400
+		}
401
+		$this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
402
+	}
403
+
404
+
405
+
406
+	/**
407
+	 * builds string out of ticket and event name
408
+	 *
409
+	 * @param    EE_Ticket $ticket
410
+	 * @return string
411
+	 * @throws UnexpectedEntityException
412
+	 * @throws EE_Error
413
+	 */
414
+	protected function _get_ticket_and_event_name(EE_Ticket $ticket)
415
+	{
416
+		$event = $ticket->get_related_event();
417
+		if ($event instanceof EE_Event) {
418
+			$ticket_name = sprintf(
419
+				_x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
420
+				$ticket->name(),
421
+				$event->name()
422
+			);
423
+		} else {
424
+			$ticket_name = $ticket->name();
425
+		}
426
+		return $ticket_name;
427
+	}
428
+
429
+
430
+
431
+	/********************************** EVENT CART  **********************************/
432
+
433
+
434
+
435
+	/**
436
+	 * releases or reserves ticket(s) based on quantity passed
437
+	 *
438
+	 * @param  EE_Line_Item $line_item
439
+	 * @param  int          $quantity
440
+	 * @return void
441
+	 * @throws EE_Error
442
+	 * @throws InvalidArgumentException
443
+	 * @throws InvalidDataTypeException
444
+	 * @throws InvalidInterfaceException
445
+	 */
446
+	public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
447
+	{
448
+		$ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
449
+		if ($ticket instanceof EE_Ticket) {
450
+			$ticket->add_extra_meta(
451
+				EE_Ticket::META_KEY_TICKET_RESERVATIONS,
452
+				__LINE__ . ') ' . __METHOD__ . '()'
453
+			);
454
+			if ($quantity > 0) {
455
+				EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
456
+			} else {
457
+				EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
458
+			}
459
+		}
460
+	}
461
+
462
+
463
+
464
+	/**
465
+	 * releases reserved ticket(s) based on quantity passed
466
+	 *
467
+	 * @param  EE_Ticket $ticket
468
+	 * @param  int       $quantity
469
+	 * @return void
470
+	 * @throws EE_Error
471
+	 */
472
+	public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
473
+	{
474
+		$ticket->add_extra_meta(
475
+			EE_Ticket::META_KEY_TICKET_RESERVATIONS,
476
+			__LINE__ . ') ' . __METHOD__ . '()'
477
+		);
478
+		EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
479
+	}
480
+
481
+
482
+
483
+	/********************************** POST_NOTICES  **********************************/
484
+
485
+
486
+
487
+	/**
488
+	 * @return void
489
+	 * @throws EE_Error
490
+	 * @throws InvalidArgumentException
491
+	 * @throws ReflectionException
492
+	 * @throws InvalidDataTypeException
493
+	 * @throws InvalidInterfaceException
494
+	 */
495
+	public static function post_notices()
496
+	{
497
+		EED_Ticket_Sales_Monitor::instance()->_post_notices();
498
+	}
499
+
500
+
501
+
502
+	/**
503
+	 * @return void
504
+	 * @throws EE_Error
505
+	 * @throws InvalidArgumentException
506
+	 * @throws ReflectionException
507
+	 * @throws InvalidDataTypeException
508
+	 * @throws InvalidInterfaceException
509
+	 */
510
+	protected function _post_notices()
511
+	{
512
+		if (self::debug) {
513
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
514
+		}
515
+		$refresh_msg    = '';
516
+		$none_added_msg = '';
517
+		if (defined('DOING_AJAX') && DOING_AJAX) {
518
+			$refresh_msg    = __(
519
+				'Please refresh the page to view updated ticket quantities.',
520
+				'event_espresso'
521
+			);
522
+			$none_added_msg = __('No tickets were added for the event.', 'event_espresso');
523
+		}
524
+		if (! empty($this->sold_out_tickets)) {
525
+			EE_Error::add_attention(
526
+				sprintf(
527
+					apply_filters(
528
+						'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
529
+						__(
530
+							'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
531
+							'event_espresso'
532
+						)
533
+					),
534
+					'<br />',
535
+					implode('<br />', $this->sold_out_tickets),
536
+					$none_added_msg,
537
+					$refresh_msg
538
+				)
539
+			);
540
+			// alter code flow in the Ticket Selector for better UX
541
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
542
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
543
+			$this->sold_out_tickets = array();
544
+			// and reset the cart
545
+			EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
546
+		}
547
+		if (! empty($this->decremented_tickets)) {
548
+			EE_Error::add_attention(
549
+				sprintf(
550
+					apply_filters(
551
+						'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
552
+						__(
553
+							'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
554
+							'event_espresso'
555
+						)
556
+					),
557
+					'<br />',
558
+					implode('<br />', $this->decremented_tickets),
559
+					$none_added_msg,
560
+					$refresh_msg
561
+				)
562
+			);
563
+			$this->decremented_tickets = array();
564
+		}
565
+	}
566
+
567
+
568
+
569
+	/********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
570
+
571
+
572
+
573
+	/**
574
+	 * releases reserved tickets for all registrations of an EE_Transaction
575
+	 * by default, will NOT release tickets for finalized transactions
576
+	 *
577
+	 * @param    EE_Transaction $transaction
578
+	 * @return int
579
+	 * @throws EE_Error
580
+	 * @throws InvalidSessionDataException
581
+	 */
582
+	protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
583
+	{
584
+		if (self::debug) {
585
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
586
+			echo '<br /> . transaction->ID: ' . $transaction->ID();
587
+			echo '<br /> . TXN status_ID: ' . $transaction->status_ID();
588
+		}
589
+		// check if 'finalize_registration' step has been completed...
590
+		$finalized = $transaction->reg_step_completed('finalize_registration');
591
+		if (self::debug) {
592
+			// DEBUG LOG
593
+			EEH_Debug_Tools::log(
594
+				__CLASS__,
595
+				__FUNCTION__,
596
+				__LINE__,
597
+				array('finalized' => $finalized),
598
+				false,
599
+				'EE_Transaction: ' . $transaction->ID()
600
+			);
601
+		}
602
+		// how many tickets were released
603
+		$count = 0;
604
+		if (self::debug) {
605
+			echo '<br /> . . . TXN finalized: ' . $finalized;
606
+		}
607
+		$release_tickets_with_TXN_status = array(
608
+			EEM_Transaction::failed_status_code,
609
+			EEM_Transaction::abandoned_status_code,
610
+			EEM_Transaction::incomplete_status_code,
611
+		);
612
+		$events = array();
613
+		// if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
614
+		if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
615
+			// cancel any reserved tickets for registrations that were not approved
616
+			$registrations = $transaction->registrations();
617
+			if (self::debug) {
618
+				echo '<br /> . . . # registrations: ' . count($registrations);
619
+				$reg    = reset($registrations);
620
+				$ticket = $reg->ticket();
621
+				if ($ticket instanceof EE_Ticket) {
622
+					$ticket->add_extra_meta(
623
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
624
+						__LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
625
+					);
626
+				}
627
+			}
628
+			if (! empty($registrations)) {
629
+				foreach ($registrations as $registration) {
630
+					if (
631
+						$registration instanceof EE_Registration
632
+						&& $this->_release_reserved_ticket_for_registration($registration, $transaction)
633
+					) {
634
+						$count++;
635
+						$events[ $registration->event_ID() ] = $registration->event();
636
+					}
637
+				}
638
+			}
639
+		}
640
+		if ($events !== array()) {
641
+			foreach ($events as $event) {
642
+				/** @var EE_Event $event */
643
+				$event->perform_sold_out_status_check();
644
+			}
645
+		}
646
+		return $count;
647
+	}
648
+
649
+
650
+
651
+	/**
652
+	 * releases reserved tickets for an EE_Registration
653
+	 * by default, will NOT release tickets for APPROVED registrations
654
+	 *
655
+	 * @param EE_Registration $registration
656
+	 * @param EE_Transaction  $transaction
657
+	 * @return int
658
+	 * @throws EE_Error
659
+	 */
660
+	protected function _release_reserved_ticket_for_registration(
661
+		EE_Registration $registration,
662
+		EE_Transaction $transaction
663
+	) {
664
+		$STS_ID = $transaction->status_ID();
665
+		if (self::debug) {
666
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
667
+			echo '<br /> . . registration->ID: ' . $registration->ID();
668
+			echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
669
+			echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
670
+		}
671
+		if (
672
+			// release Tickets for Failed Transactions and Abandoned Transactions
673
+			$STS_ID === EEM_Transaction::failed_status_code
674
+			|| $STS_ID === EEM_Transaction::abandoned_status_code
675
+			|| (
676
+				// also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
677
+				$STS_ID === EEM_Transaction::incomplete_status_code
678
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
679
+			)
680
+		) {
681
+			if (self::debug) {
682
+				echo '<br /><br /> . . RELEASE RESERVED TICKET';
683
+				$rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
684
+				echo '<br /> . . . registration HAS_RESERVED_TICKET_KEY: ';
685
+				var_dump($rsrvd);
686
+			}
687
+			$registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
688
+			return 1;
689
+		}
690
+		return 0;
691
+	}
692
+
693
+
694
+
695
+	/********************************** SESSION_CART_RESET  **********************************/
696
+
697
+
698
+
699
+	/**
700
+	 * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
701
+	 *
702
+	 * @param EE_Session $session
703
+	 * @return void
704
+	 * @throws EE_Error
705
+	 * @throws InvalidArgumentException
706
+	 * @throws ReflectionException
707
+	 * @throws InvalidDataTypeException
708
+	 * @throws InvalidInterfaceException
709
+	 */
710
+	public static function session_cart_reset(EE_Session $session)
711
+	{
712
+		if (self::debug) {
713
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
714
+		}
715
+		// first check of the session has a valid Checkout object
716
+		$checkout = $session->checkout();
717
+		if ($checkout instanceof EE_Checkout) {
718
+			// and use that to clear ticket reservations because it will update the associated registration meta data
719
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
720
+			return;
721
+		}
722
+		$cart = $session->cart();
723
+		if ($cart instanceof EE_Cart) {
724
+			if (self::debug) {
725
+				echo '<br /><br /> cart instance of EE_Cart: ';
726
+			}
727
+			EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
728
+		} else {
729
+			if (self::debug) {
730
+				echo '<br /><br /> invalid EE_Cart: ';
731
+				var_export($cart, true);
732
+			}
733
+		}
734
+	}
735
+
736
+
737
+
738
+	/**
739
+	 * releases reserved tickets in the EE_Cart
740
+	 *
741
+	 * @param EE_Cart $cart
742
+	 * @return void
743
+	 * @throws EE_Error
744
+	 * @throws InvalidArgumentException
745
+	 * @throws ReflectionException
746
+	 * @throws InvalidDataTypeException
747
+	 * @throws InvalidInterfaceException
748
+	 */
749
+	protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
750
+	{
751
+		if (self::debug) {
752
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
753
+		}
754
+		EE_Registry::instance()->load_helper('Line_Item');
755
+		$ticket_line_items = $cart->get_tickets();
756
+		if (empty($ticket_line_items)) {
757
+			return;
758
+		}
759
+		foreach ($ticket_line_items as $ticket_line_item) {
760
+			if (self::debug) {
761
+				echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
762
+			}
763
+			if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
764
+				if (self::debug) {
765
+					echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
766
+				}
767
+				$ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
768
+				if ($ticket instanceof EE_Ticket) {
769
+					if (self::debug) {
770
+						echo '<br /> . . ticket->ID(): ' . $ticket->ID();
771
+						echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
772
+					}
773
+					$ticket->add_extra_meta(
774
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
775
+						__LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
776
+					);
777
+					$this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
778
+				}
779
+			}
780
+		}
781
+		if (self::debug) {
782
+			echo '<br /><br /> RESET COMPLETED ';
783
+		}
784
+	}
785
+
786
+
787
+
788
+	/********************************** SESSION_CHECKOUT_RESET  **********************************/
789
+
790
+
791
+
792
+	/**
793
+	 * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
794
+	 *
795
+	 * @param EE_Session $session
796
+	 * @return void
797
+	 * @throws EE_Error
798
+	 * @throws InvalidSessionDataException
799
+	 */
800
+	public static function session_checkout_reset(EE_Session $session)
801
+	{
802
+		$checkout = $session->checkout();
803
+		if ($checkout instanceof EE_Checkout) {
804
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
805
+		}
806
+	}
807
+
808
+
809
+
810
+	/**
811
+	 * releases reserved tickets for the EE_Checkout->transaction
812
+	 *
813
+	 * @param EE_Checkout $checkout
814
+	 * @return void
815
+	 * @throws EE_Error
816
+	 * @throws InvalidSessionDataException
817
+	 */
818
+	protected function _session_checkout_reset(EE_Checkout $checkout)
819
+	{
820
+		if (self::debug) {
821
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
822
+		}
823
+		// we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
824
+		if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
825
+			return;
826
+		}
827
+		$this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
828
+	}
829
+
830
+
831
+
832
+	/********************************** SESSION_EXPIRED_RESET  **********************************/
833
+
834
+
835
+
836
+	/**
837
+	 * @param    EE_Session $session
838
+	 * @return    void
839
+	 */
840
+	public static function session_expired_reset(EE_Session $session)
841
+	{
842
+	}
843
+
844
+
845
+
846
+	/********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
847
+
848
+
849
+
850
+	/**
851
+	 * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
852
+	 * by default, will NOT release tickets for free transactions, or any that have received a payment
853
+	 *
854
+	 * @param EE_Transaction $transaction
855
+	 * @return void
856
+	 * @throws EE_Error
857
+	 * @throws InvalidSessionDataException
858
+	 */
859
+	public static function process_abandoned_transactions(EE_Transaction $transaction)
860
+	{
861
+		// is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
862
+		if ($transaction->is_free() || $transaction->paid() > 0) {
863
+			if (self::debug) {
864
+				// DEBUG LOG
865
+				EEH_Debug_Tools::log(
866
+					__CLASS__,
867
+					__FUNCTION__,
868
+					__LINE__,
869
+					array($transaction),
870
+					false,
871
+					'EE_Transaction: ' . $transaction->ID()
872
+				);
873
+			}
874
+			return;
875
+		}
876
+		// have their been any successful payments made ?
877
+		$payments = $transaction->payments();
878
+		foreach ($payments as $payment) {
879
+			if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
880
+				if (self::debug) {
881
+					// DEBUG LOG
882
+					EEH_Debug_Tools::log(
883
+						__CLASS__,
884
+						__FUNCTION__,
885
+						__LINE__,
886
+						array($payment),
887
+						false,
888
+						'EE_Transaction: ' . $transaction->ID()
889
+					);
890
+				}
891
+				return;
892
+			}
893
+		}
894
+		// since you haven't even attempted to pay for your ticket...
895
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
896
+	}
897
+
898
+
899
+
900
+	/********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
901
+
902
+
903
+
904
+	/**
905
+	 * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
906
+	 *
907
+	 * @param EE_Transaction $transaction
908
+	 * @return void
909
+	 * @throws EE_Error
910
+	 * @throws InvalidSessionDataException
911
+	 */
912
+	public static function process_failed_transactions(EE_Transaction $transaction)
913
+	{
914
+		// since you haven't even attempted to pay for your ticket...
915
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
916
+	}
917
+
918
+
919
+
920
+	/********************************** RESET RESERVATION COUNTS  *********************************/
921
+
922
+
923
+
924
+	/**
925
+	 * Resets all ticket and datetime reserved counts to zero
926
+	 * Tickets that are currently associated with a Transaction that is in progress
927
+	 *
928
+	 * @throws EE_Error
929
+	 * @throws DomainException
930
+	 * @throws InvalidDataTypeException
931
+	 * @throws InvalidInterfaceException
932
+	 * @throws InvalidArgumentException
933
+	 * @throws UnexpectedEntityException
934
+	 */
935
+	public static function reset_reservation_counts()
936
+	{
937
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
938
+		$valid_reserved_tickets = array();
939
+		/** @var EE_Transaction[] $transactions_not_in_progress */
940
+		$transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
941
+		foreach ($transactions_not_in_progress as $transaction) {
942
+			// if this TXN has been fully completed, then skip it
943
+			if ($transaction->reg_step_completed('finalize_registration')) {
944
+				continue;
945
+			}
946
+			$total_line_item = $transaction->total_line_item();
947
+			// $transaction_in_progress->line
948
+			if (! $total_line_item instanceof EE_Line_Item) {
949
+				throw new DomainException(
950
+					esc_html__(
951
+						'Transaction does not have a valid Total Line Item associated with it.',
952
+						'event_espresso'
953
+					)
954
+				);
955
+			}
956
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
957
+				$total_line_item
958
+			);
959
+		}
960
+		$total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
961
+		foreach ($total_line_items as $total_line_item) {
962
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
963
+				$total_line_item
964
+			);
965
+		}
966
+		$tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
967
+		return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
968
+			$tickets_with_reservations,
969
+			$valid_reserved_tickets,
970
+			__FUNCTION__
971
+		);
972
+	}
973
+
974
+
975
+
976
+	/**
977
+	 * @param EE_Line_Item $total_line_item
978
+	 * @return EE_Line_Item[]
979
+	 */
980
+	private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
981
+	{
982
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
983
+		$valid_reserved_tickets = array();
984
+		$ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
985
+		foreach ($ticket_line_items as $ticket_line_item) {
986
+			if ($ticket_line_item instanceof EE_Line_Item) {
987
+				$valid_reserved_tickets[] = $ticket_line_item;
988
+			}
989
+		}
990
+		return $valid_reserved_tickets;
991
+	}
992
+
993
+
994
+
995
+	/**
996
+	 * @param EE_Ticket[]    $tickets_with_reservations
997
+	 * @param EE_Line_Item[] $valid_reserved_ticket_line_items
998
+	 * @return int
999
+	 * @throws UnexpectedEntityException
1000
+	 * @throws DomainException
1001
+	 * @throws EE_Error
1002
+	 */
1003
+	private static function release_reservations_for_tickets(
1004
+		array $tickets_with_reservations,
1005
+		array $valid_reserved_ticket_line_items = array(),
1006
+		$source
1007
+	) {
1008
+		$total_tickets_released = 0;
1009
+		$sold_out_events = array();
1010
+		foreach ($tickets_with_reservations as $ticket_with_reservations) {
1011
+			if (! $ticket_with_reservations instanceof EE_Ticket) {
1012
+				continue;
1013
+			}
1014
+			$reserved_qty = $ticket_with_reservations->reserved();
1015
+			foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1016
+				if (
1017
+					$valid_reserved_ticket_line_item instanceof EE_Line_Item
1018
+					&& $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1019
+				) {
1020
+					$reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1021
+				}
1022
+			}
1023
+			if ($reserved_qty > 0) {
1024
+				$ticket_with_reservations->add_extra_meta(
1025
+					EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1026
+					__LINE__ . ') ' . $source . '()'
1027
+				);
1028
+				$ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1029
+				$ticket_with_reservations->save();
1030
+				$total_tickets_released += $reserved_qty;
1031
+				$event = $ticket_with_reservations->get_related_event();
1032
+				// track sold out events
1033
+				if ($event instanceof EE_Event && $event->is_sold_out()) {
1034
+					$sold_out_events[] = $event;
1035
+				}
1036
+			}
1037
+		}
1038
+		// double check whether sold out events should remain sold out after releasing tickets
1039
+		if($sold_out_events !== array()){
1040
+			foreach ($sold_out_events as $sold_out_event) {
1041
+				/** @var EE_Event $sold_out_event */
1042
+				$sold_out_event->perform_sold_out_status_check();
1043
+			}
1044
+		}
1045
+		return $total_tickets_released;
1046
+	}
1047
+
1048
+
1049
+
1050
+	/********************************** SHUTDOWN  **********************************/
1051
+
1052
+
1053
+
1054
+	/**
1055
+	 * @return false|int
1056
+	 * @throws EE_Error
1057
+	 * @throws InvalidArgumentException
1058
+	 * @throws InvalidDataTypeException
1059
+	 * @throws InvalidInterfaceException
1060
+	 */
1061
+	public static function clear_expired_line_items_with_no_transaction()
1062
+	{
1063
+		/** @type WPDB $wpdb */
1064
+		global $wpdb;
1065
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1066
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
1067
+			'EventEspresso\core\domain\values\session\SessionLifespan'
1068
+		);
1069
+		return $wpdb->query(
1070
+			$wpdb->prepare(
1071
+				'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1072 1072
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1073
-                // use GMT time because that's what LIN_timestamps are in
1074
-                date('Y-m-d H:i:s', $session_lifespan->expiration())
1075
-            )
1076
-        );
1077
-    }
1073
+				// use GMT time because that's what LIN_timestamps are in
1074
+				date('Y-m-d H:i:s', $session_lifespan->expiration())
1075
+			)
1076
+		);
1077
+	}
1078 1078
 
1079 1079
 }
1080 1080
 // End of file EED_Ticket_Sales_Monitor.module.php
Please login to merge, or discard this patch.
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
 class EED_Ticket_Sales_Monitor extends EED_Module
25 25
 {
26 26
 
27
-    const debug = false;    //	true false
27
+    const debug = false; //	true false
28 28
 
29 29
     /**
30 30
      * an array of raw ticket data from EED_Ticket_Selector
@@ -213,17 +213,17 @@  discard block
 block discarded – undo
213 213
             /** @var EE_Line_Item $total_line_item */
214 214
             $ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
215 215
             foreach ($ticket_line_items as $ticket_line_item) {
216
-                if (! $ticket_line_item instanceof EE_Line_Item) {
216
+                if ( ! $ticket_line_item instanceof EE_Line_Item) {
217 217
                     continue;
218 218
                 }
219 219
                 if ($total_line_item->timestamp(true) <= $session_lifespan->expiration()) {
220
-                    $expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
220
+                    $expired_ticket_IDs[$ticket_line_item->OBJ_ID()] = $ticket_line_item->OBJ_ID();
221 221
                 } else {
222
-                    $valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
222
+                    $valid_ticket_line_items[$ticket_line_item->OBJ_ID()] = $ticket_line_item;
223 223
                 }
224 224
             }
225 225
         }
226
-        if (! empty($expired_ticket_IDs)) {
226
+        if ( ! empty($expired_ticket_IDs)) {
227 227
             EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
228 228
                 \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
229 229
                 $valid_ticket_line_items,
@@ -266,8 +266,8 @@  discard block
 block discarded – undo
266 266
             $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
267 267
         }
268 268
         if (self::debug) {
269
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
270
-            echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
269
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'()';
270
+            echo '<br /><br /><b> RETURNED QTY: '.$qty.'</b>';
271 271
         }
272 272
         return $qty;
273 273
     }
@@ -286,36 +286,36 @@  discard block
 block discarded – undo
286 286
     protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
287 287
     {
288 288
         if (self::debug) {
289
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
289
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
290 290
         }
291
-        if (! $ticket instanceof EE_Ticket) {
291
+        if ( ! $ticket instanceof EE_Ticket) {
292 292
             return 0;
293 293
         }
294 294
         if (self::debug) {
295
-            echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
296
-            echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
295
+            echo '<br /><b> . ticket->ID: '.$ticket->ID().'</b>';
296
+            echo '<br /> . original ticket->reserved: '.$ticket->reserved();
297 297
         }
298 298
         $ticket->refresh_from_db();
299 299
         // first let's determine the ticket availability based on sales
300 300
         $available = $ticket->qty('saleable');
301 301
         if (self::debug) {
302
-            echo '<br /> . . . ticket->qty: ' . $ticket->qty();
303
-            echo '<br /> . . . ticket->sold: ' . $ticket->sold();
304
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
305
-            echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
306
-            echo '<br /> . . . available: ' . $available;
302
+            echo '<br /> . . . ticket->qty: '.$ticket->qty();
303
+            echo '<br /> . . . ticket->sold: '.$ticket->sold();
304
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
305
+            echo '<br /> . . . ticket->qty(saleable): '.$ticket->qty('saleable');
306
+            echo '<br /> . . . available: '.$available;
307 307
         }
308 308
         if ($available < 1) {
309 309
             $this->_ticket_sold_out($ticket);
310 310
             return 0;
311 311
         }
312 312
         if (self::debug) {
313
-            echo '<br /> . . . qty: ' . $qty;
313
+            echo '<br /> . . . qty: '.$qty;
314 314
         }
315 315
         if ($available < $qty) {
316 316
             $qty = $available;
317 317
             if (self::debug) {
318
-                echo '<br /> . . . QTY ADJUSTED: ' . $qty;
318
+                echo '<br /> . . . QTY ADJUSTED: '.$qty;
319 319
             }
320 320
             $this->_ticket_quantity_decremented($ticket);
321 321
         }
@@ -336,9 +336,9 @@  discard block
 block discarded – undo
336 336
     protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
337 337
     {
338 338
         if (self::debug) {
339
-            echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
339
+            echo '<br /><br /> . . . INCREASE RESERVED: '.$quantity;
340 340
         }
341
-        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
341
+        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'.__LINE__);
342 342
         return $ticket->save();
343 343
     }
344 344
 
@@ -353,12 +353,12 @@  discard block
 block discarded – undo
353 353
     protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
354 354
     {
355 355
         if (self::debug) {
356
-            echo '<br /> . . . ticket->ID: ' . $ticket->ID();
357
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
356
+            echo '<br /> . . . ticket->ID: '.$ticket->ID();
357
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
358 358
         }
359
-        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
359
+        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'.__LINE__);
360 360
         if (self::debug) {
361
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
361
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
362 362
         }
363 363
         return $ticket->save() ? 1 : 0;
364 364
     }
@@ -376,8 +376,8 @@  discard block
 block discarded – undo
376 376
     protected function _ticket_sold_out(EE_Ticket $ticket)
377 377
     {
378 378
         if (self::debug) {
379
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
380
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
379
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
380
+            echo '<br /> . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
381 381
         }
382 382
         $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
383 383
     }
@@ -395,8 +395,8 @@  discard block
 block discarded – undo
395 395
     protected function _ticket_quantity_decremented(EE_Ticket $ticket)
396 396
     {
397 397
         if (self::debug) {
398
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
399
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
398
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
399
+            echo '<br /> . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
400 400
         }
401 401
         $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
402 402
     }
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
         if ($ticket instanceof EE_Ticket) {
450 450
             $ticket->add_extra_meta(
451 451
                 EE_Ticket::META_KEY_TICKET_RESERVATIONS,
452
-                __LINE__ . ') ' . __METHOD__ . '()'
452
+                __LINE__.') '.__METHOD__.'()'
453 453
             );
454 454
             if ($quantity > 0) {
455 455
                 EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
@@ -473,7 +473,7 @@  discard block
 block discarded – undo
473 473
     {
474 474
         $ticket->add_extra_meta(
475 475
             EE_Ticket::META_KEY_TICKET_RESERVATIONS,
476
-            __LINE__ . ') ' . __METHOD__ . '()'
476
+            __LINE__.') '.__METHOD__.'()'
477 477
         );
478 478
         EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
479 479
     }
@@ -510,18 +510,18 @@  discard block
 block discarded – undo
510 510
     protected function _post_notices()
511 511
     {
512 512
         if (self::debug) {
513
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
513
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
514 514
         }
515 515
         $refresh_msg    = '';
516 516
         $none_added_msg = '';
517 517
         if (defined('DOING_AJAX') && DOING_AJAX) {
518
-            $refresh_msg    = __(
518
+            $refresh_msg = __(
519 519
                 'Please refresh the page to view updated ticket quantities.',
520 520
                 'event_espresso'
521 521
             );
522 522
             $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
523 523
         }
524
-        if (! empty($this->sold_out_tickets)) {
524
+        if ( ! empty($this->sold_out_tickets)) {
525 525
             EE_Error::add_attention(
526 526
                 sprintf(
527 527
                     apply_filters(
@@ -544,7 +544,7 @@  discard block
 block discarded – undo
544 544
             // and reset the cart
545 545
             EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
546 546
         }
547
-        if (! empty($this->decremented_tickets)) {
547
+        if ( ! empty($this->decremented_tickets)) {
548 548
             EE_Error::add_attention(
549 549
                 sprintf(
550 550
                     apply_filters(
@@ -582,9 +582,9 @@  discard block
 block discarded – undo
582 582
     protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
583 583
     {
584 584
         if (self::debug) {
585
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
586
-            echo '<br /> . transaction->ID: ' . $transaction->ID();
587
-            echo '<br /> . TXN status_ID: ' . $transaction->status_ID();
585
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
586
+            echo '<br /> . transaction->ID: '.$transaction->ID();
587
+            echo '<br /> . TXN status_ID: '.$transaction->status_ID();
588 588
         }
589 589
         // check if 'finalize_registration' step has been completed...
590 590
         $finalized = $transaction->reg_step_completed('finalize_registration');
@@ -596,13 +596,13 @@  discard block
 block discarded – undo
596 596
                 __LINE__,
597 597
                 array('finalized' => $finalized),
598 598
                 false,
599
-                'EE_Transaction: ' . $transaction->ID()
599
+                'EE_Transaction: '.$transaction->ID()
600 600
             );
601 601
         }
602 602
         // how many tickets were released
603 603
         $count = 0;
604 604
         if (self::debug) {
605
-            echo '<br /> . . . TXN finalized: ' . $finalized;
605
+            echo '<br /> . . . TXN finalized: '.$finalized;
606 606
         }
607 607
         $release_tickets_with_TXN_status = array(
608 608
             EEM_Transaction::failed_status_code,
@@ -611,28 +611,28 @@  discard block
 block discarded – undo
611 611
         );
612 612
         $events = array();
613 613
         // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
614
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
614
+        if ( ! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
615 615
             // cancel any reserved tickets for registrations that were not approved
616 616
             $registrations = $transaction->registrations();
617 617
             if (self::debug) {
618
-                echo '<br /> . . . # registrations: ' . count($registrations);
618
+                echo '<br /> . . . # registrations: '.count($registrations);
619 619
                 $reg    = reset($registrations);
620 620
                 $ticket = $reg->ticket();
621 621
                 if ($ticket instanceof EE_Ticket) {
622 622
                     $ticket->add_extra_meta(
623 623
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
624
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
624
+                        __LINE__.') Release All Tickets TXN:'.$transaction->ID()
625 625
                     );
626 626
                 }
627 627
             }
628
-            if (! empty($registrations)) {
628
+            if ( ! empty($registrations)) {
629 629
                 foreach ($registrations as $registration) {
630 630
                     if (
631 631
                         $registration instanceof EE_Registration
632 632
                         && $this->_release_reserved_ticket_for_registration($registration, $transaction)
633 633
                     ) {
634 634
                         $count++;
635
-                        $events[ $registration->event_ID() ] = $registration->event();
635
+                        $events[$registration->event_ID()] = $registration->event();
636 636
                     }
637 637
                 }
638 638
             }
@@ -663,10 +663,10 @@  discard block
 block discarded – undo
663 663
     ) {
664 664
         $STS_ID = $transaction->status_ID();
665 665
         if (self::debug) {
666
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
667
-            echo '<br /> . . registration->ID: ' . $registration->ID();
668
-            echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
669
-            echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
666
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
667
+            echo '<br /> . . registration->ID: '.$registration->ID();
668
+            echo '<br /> . . registration->status_ID: '.$registration->status_ID();
669
+            echo '<br /> . . transaction->status_ID(): '.$STS_ID;
670 670
         }
671 671
         if (
672 672
             // release Tickets for Failed Transactions and Abandoned Transactions
@@ -684,7 +684,7 @@  discard block
 block discarded – undo
684 684
                 echo '<br /> . . . registration HAS_RESERVED_TICKET_KEY: ';
685 685
                 var_dump($rsrvd);
686 686
             }
687
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
687
+            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'.__LINE__);
688 688
             return 1;
689 689
         }
690 690
         return 0;
@@ -710,7 +710,7 @@  discard block
 block discarded – undo
710 710
     public static function session_cart_reset(EE_Session $session)
711 711
     {
712 712
         if (self::debug) {
713
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
713
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
714 714
         }
715 715
         // first check of the session has a valid Checkout object
716 716
         $checkout = $session->checkout();
@@ -749,7 +749,7 @@  discard block
 block discarded – undo
749 749
     protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
750 750
     {
751 751
         if (self::debug) {
752
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
752
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
753 753
         }
754 754
         EE_Registry::instance()->load_helper('Line_Item');
755 755
         $ticket_line_items = $cart->get_tickets();
@@ -758,21 +758,21 @@  discard block
 block discarded – undo
758 758
         }
759 759
         foreach ($ticket_line_items as $ticket_line_item) {
760 760
             if (self::debug) {
761
-                echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
761
+                echo '<br /> . ticket_line_item->ID(): '.$ticket_line_item->ID();
762 762
             }
763 763
             if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
764 764
                 if (self::debug) {
765
-                    echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
765
+                    echo '<br /> . . ticket_line_item->OBJ_ID(): '.$ticket_line_item->OBJ_ID();
766 766
                 }
767 767
                 $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
768 768
                 if ($ticket instanceof EE_Ticket) {
769 769
                     if (self::debug) {
770
-                        echo '<br /> . . ticket->ID(): ' . $ticket->ID();
771
-                        echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
770
+                        echo '<br /> . . ticket->ID(): '.$ticket->ID();
771
+                        echo '<br /> . . ticket_line_item->quantity(): '.$ticket_line_item->quantity();
772 772
                     }
773 773
                     $ticket->add_extra_meta(
774 774
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
775
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
775
+                        __LINE__.') '.__METHOD__.'() SID = '.$session->id()
776 776
                     );
777 777
                     $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
778 778
                 }
@@ -818,7 +818,7 @@  discard block
 block discarded – undo
818 818
     protected function _session_checkout_reset(EE_Checkout $checkout)
819 819
     {
820 820
         if (self::debug) {
821
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
821
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
822 822
         }
823 823
         // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
824 824
         if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
@@ -868,7 +868,7 @@  discard block
 block discarded – undo
868 868
                     __LINE__,
869 869
                     array($transaction),
870 870
                     false,
871
-                    'EE_Transaction: ' . $transaction->ID()
871
+                    'EE_Transaction: '.$transaction->ID()
872 872
                 );
873 873
             }
874 874
             return;
@@ -885,7 +885,7 @@  discard block
 block discarded – undo
885 885
                         __LINE__,
886 886
                         array($payment),
887 887
                         false,
888
-                        'EE_Transaction: ' . $transaction->ID()
888
+                        'EE_Transaction: '.$transaction->ID()
889 889
                     );
890 890
                 }
891 891
                 return;
@@ -945,7 +945,7 @@  discard block
 block discarded – undo
945 945
             }
946 946
             $total_line_item = $transaction->total_line_item();
947 947
             // $transaction_in_progress->line
948
-            if (! $total_line_item instanceof EE_Line_Item) {
948
+            if ( ! $total_line_item instanceof EE_Line_Item) {
949 949
                 throw new DomainException(
950 950
                     esc_html__(
951 951
                         'Transaction does not have a valid Total Line Item associated with it.',
@@ -1008,7 +1008,7 @@  discard block
 block discarded – undo
1008 1008
         $total_tickets_released = 0;
1009 1009
         $sold_out_events = array();
1010 1010
         foreach ($tickets_with_reservations as $ticket_with_reservations) {
1011
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1011
+            if ( ! $ticket_with_reservations instanceof EE_Ticket) {
1012 1012
                 continue;
1013 1013
             }
1014 1014
             $reserved_qty = $ticket_with_reservations->reserved();
@@ -1023,9 +1023,9 @@  discard block
 block discarded – undo
1023 1023
             if ($reserved_qty > 0) {
1024 1024
                 $ticket_with_reservations->add_extra_meta(
1025 1025
                     EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1026
-                    __LINE__ . ') ' . $source . '()'
1026
+                    __LINE__.') '.$source.'()'
1027 1027
                 );
1028
-                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1028
+                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'.__LINE__);
1029 1029
                 $ticket_with_reservations->save();
1030 1030
                 $total_tickets_released += $reserved_qty;
1031 1031
                 $event = $ticket_with_reservations->get_related_event();
@@ -1036,7 +1036,7 @@  discard block
 block discarded – undo
1036 1036
             }
1037 1037
         }
1038 1038
         // double check whether sold out events should remain sold out after releasing tickets
1039
-        if($sold_out_events !== array()){
1039
+        if ($sold_out_events !== array()) {
1040 1040
             foreach ($sold_out_events as $sold_out_event) {
1041 1041
                 /** @var EE_Event $sold_out_event */
1042 1042
                 $sold_out_event->perform_sold_out_status_check();
@@ -1068,7 +1068,7 @@  discard block
 block discarded – undo
1068 1068
         );
1069 1069
         return $wpdb->query(
1070 1070
             $wpdb->prepare(
1071
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1071
+                'DELETE FROM '.EEM_Line_Item::instance()->table().'
1072 1072
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1073 1073
                 // use GMT time because that's what LIN_timestamps are in
1074 1074
                 date('Y-m-d H:i:s', $session_lifespan->expiration())
Please login to merge, or discard this patch.
core/db_classes/EE_Ticket.class.php 2 patches
Indentation   +665 added lines, -665 removed lines patch added patch discarded remove patch
@@ -53,14 +53,14 @@  discard block
 block discarded – undo
53 53
 	 */
54 54
 	const onsale = 'TKO';
55 55
 
56
-    /**
57
-     * extra meta key for tracking ticket reservations
58
-     *
59
-     * @type string
60
-     */
61
-    const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
62
-
63
-    /**
56
+	/**
57
+	 * extra meta key for tracking ticket reservations
58
+	 *
59
+	 * @type string
60
+	 */
61
+	const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
62
+
63
+	/**
64 64
 	 * cached result from method of the same name
65 65
 	 * @var float $_ticket_total_with_taxes
66 66
 	 */
@@ -68,15 +68,15 @@  discard block
 block discarded – undo
68 68
 
69 69
 
70 70
 
71
-    /**
72
-     * @param array  $props_n_values          incoming values
73
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
74
-     *                                        used.)
75
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
76
-     *                                        date_format and the second value is the time format
77
-     * @return EE_Ticket
78
-     * @throws \EE_Error
79
-     */
71
+	/**
72
+	 * @param array  $props_n_values          incoming values
73
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
74
+	 *                                        used.)
75
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
76
+	 *                                        date_format and the second value is the time format
77
+	 * @return EE_Ticket
78
+	 * @throws \EE_Error
79
+	 */
80 80
 	public static function new_instance( $props_n_values = array(), $timezone = null, $date_formats = array() ) {
81 81
 		$has_object = parent::_check_for_object( $props_n_values, __CLASS__, $timezone, $date_formats );
82 82
 		return $has_object ? $has_object : new self( $props_n_values, false, $timezone, $date_formats );
@@ -84,36 +84,36 @@  discard block
 block discarded – undo
84 84
 
85 85
 
86 86
 
87
-    /**
88
-     * @param array  $props_n_values  incoming values from the database
89
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
90
-     *                                the website will be used.
91
-     * @return EE_Ticket
92
-     * @throws \EE_Error
93
-     */
87
+	/**
88
+	 * @param array  $props_n_values  incoming values from the database
89
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
90
+	 *                                the website will be used.
91
+	 * @return EE_Ticket
92
+	 * @throws \EE_Error
93
+	 */
94 94
 	public static function new_instance_from_db( $props_n_values = array(), $timezone = null ) {
95 95
 		return new self( $props_n_values, TRUE, $timezone );
96 96
 	}
97 97
 
98 98
 
99 99
 
100
-    /**
101
-     * @return bool
102
-     * @throws \EE_Error
103
-     */
100
+	/**
101
+	 * @return bool
102
+	 * @throws \EE_Error
103
+	 */
104 104
 	public function parent() {
105 105
 		return $this->get( 'TKT_parent' );
106 106
 	}
107 107
 
108 108
 
109 109
 
110
-    /**
111
-     * return if a ticket has quantities available for purchase
112
-     *
113
-     * @param  int $DTT_ID the primary key for a particular datetime
114
-     * @return boolean
115
-     * @throws \EE_Error
116
-     */
110
+	/**
111
+	 * return if a ticket has quantities available for purchase
112
+	 *
113
+	 * @param  int $DTT_ID the primary key for a particular datetime
114
+	 * @return boolean
115
+	 * @throws \EE_Error
116
+	 */
117 117
 	public function available( $DTT_ID = 0 ) {
118 118
 		// are we checking availability for a particular datetime ?
119 119
 		if ( $DTT_ID ) {
@@ -130,14 +130,14 @@  discard block
 block discarded – undo
130 130
 
131 131
 
132 132
 
133
-    /**
134
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
135
-     *
136
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the relevant status const
137
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save further processing
138
-     * @return mixed status int if the display string isn't requested
139
-     * @throws \EE_Error
140
-     */
133
+	/**
134
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
135
+	 *
136
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the relevant status const
137
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save further processing
138
+	 * @return mixed status int if the display string isn't requested
139
+	 * @throws \EE_Error
140
+	 */
141 141
 	public function ticket_status( $display = FALSE, $remaining = null ) {
142 142
 		$remaining = is_bool( $remaining ) ? $remaining : $this->is_remaining();
143 143
 		if ( ! $remaining ) {
@@ -160,14 +160,14 @@  discard block
 block discarded – undo
160 160
 
161 161
 
162 162
 
163
-    /**
164
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale considering ALL the factors used for figuring that out.
165
-     *
166
-     * @access public
167
-     * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
168
-     * @return boolean         true = tickets remaining, false not.
169
-     * @throws \EE_Error
170
-     */
163
+	/**
164
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale considering ALL the factors used for figuring that out.
165
+	 *
166
+	 * @access public
167
+	 * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
168
+	 * @return boolean         true = tickets remaining, false not.
169
+	 * @throws \EE_Error
170
+	 */
171 171
 	public function is_remaining( $DTT_ID = 0 ) {
172 172
 		$num_remaining = $this->remaining( $DTT_ID );
173 173
 		if ( $num_remaining === 0 ) {
@@ -181,76 +181,76 @@  discard block
 block discarded – undo
181 181
 
182 182
 
183 183
 
184
-    /**
185
-     * return the total number of tickets available for purchase
186
-     *
187
-     * @param  int $DTT_ID the primary key for a particular datetime.
188
-     *                     set to 0 for all related datetimes
189
-     * @return int
190
-     * @throws \EE_Error
191
-     */
184
+	/**
185
+	 * return the total number of tickets available for purchase
186
+	 *
187
+	 * @param  int $DTT_ID the primary key for a particular datetime.
188
+	 *                     set to 0 for all related datetimes
189
+	 * @return int
190
+	 * @throws \EE_Error
191
+	 */
192 192
 	public function remaining( $DTT_ID = 0 ) {
193 193
 		return $this->real_quantity_on_ticket('saleable', $DTT_ID );
194 194
 	}
195 195
 
196 196
 
197 197
 
198
-    /**
199
-     * Gets min
200
-     *
201
-     * @return int
202
-     * @throws \EE_Error
203
-     */
198
+	/**
199
+	 * Gets min
200
+	 *
201
+	 * @return int
202
+	 * @throws \EE_Error
203
+	 */
204 204
 	public function min() {
205 205
 		return $this->get( 'TKT_min' );
206 206
 	}
207 207
 
208 208
 
209 209
 
210
-    /**
211
-     * return if a ticket is no longer available cause its available dates have expired.
212
-     *
213
-     * @return boolean
214
-     * @throws \EE_Error
215
-     */
210
+	/**
211
+	 * return if a ticket is no longer available cause its available dates have expired.
212
+	 *
213
+	 * @return boolean
214
+	 * @throws \EE_Error
215
+	 */
216 216
 	public function is_expired() {
217 217
 		return ( $this->get_raw( 'TKT_end_date' ) < time() );
218 218
 	}
219 219
 
220 220
 
221 221
 
222
-    /**
223
-     * Return if a ticket is yet to go on sale or not
224
-     *
225
-     * @return boolean
226
-     * @throws \EE_Error
227
-     */
222
+	/**
223
+	 * Return if a ticket is yet to go on sale or not
224
+	 *
225
+	 * @return boolean
226
+	 * @throws \EE_Error
227
+	 */
228 228
 	public function is_pending() {
229 229
 		return ( $this->get_raw( 'TKT_start_date' ) > time() );
230 230
 	}
231 231
 
232 232
 
233 233
 
234
-    /**
235
-     * Return if a ticket is on sale or not
236
-     *
237
-     * @return boolean
238
-     * @throws \EE_Error
239
-     */
234
+	/**
235
+	 * Return if a ticket is on sale or not
236
+	 *
237
+	 * @return boolean
238
+	 * @throws \EE_Error
239
+	 */
240 240
 	public function is_on_sale() {
241 241
 		return ( $this->get_raw( 'TKT_start_date' ) < time() && $this->get_raw( 'TKT_end_date' ) > time() );
242 242
 	}
243 243
 
244 244
 
245 245
 
246
-    /**
247
-     * This returns the chronologically last datetime that this ticket is associated with
248
-     *
249
-     * @param string $dt_frmt
250
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with the end date ie: Jan 01 "to" Dec 31
251
-     * @return string
252
-     * @throws \EE_Error
253
-     */
246
+	/**
247
+	 * This returns the chronologically last datetime that this ticket is associated with
248
+	 *
249
+	 * @param string $dt_frmt
250
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with the end date ie: Jan 01 "to" Dec 31
251
+	 * @return string
252
+	 * @throws \EE_Error
253
+	 */
254 254
 	public function date_range( $dt_frmt = '', $conjunction = ' - ' ) {
255 255
 		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->start_date( $dt_frmt ) : '';
256 256
 		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->end_date( $dt_frmt ) : '';
@@ -260,12 +260,12 @@  discard block
 block discarded – undo
260 260
 
261 261
 
262 262
 
263
-    /**
264
-     * This returns the chronologically first datetime that this ticket is associated with
265
-     *
266
-     * @return EE_Datetime
267
-     * @throws \EE_Error
268
-     */
263
+	/**
264
+	 * This returns the chronologically first datetime that this ticket is associated with
265
+	 *
266
+	 * @return EE_Datetime
267
+	 * @throws \EE_Error
268
+	 */
269 269
 	public function first_datetime() {
270 270
 		$datetimes = $this->datetimes( array( 'limit' => 1 ) );
271 271
 		return reset( $datetimes );
@@ -273,14 +273,14 @@  discard block
 block discarded – undo
273 273
 
274 274
 
275 275
 
276
-    /**
277
-     * Gets all the datetimes this ticket can be used for attending.
278
-     * Unless otherwise specified, orders datetimes by start date.
279
-     *
280
-     * @param array $query_params see EEM_Base::get_all()
281
-     * @return EE_Datetime[]|EE_Base_Class[]
282
-     * @throws \EE_Error
283
-     */
276
+	/**
277
+	 * Gets all the datetimes this ticket can be used for attending.
278
+	 * Unless otherwise specified, orders datetimes by start date.
279
+	 *
280
+	 * @param array $query_params see EEM_Base::get_all()
281
+	 * @return EE_Datetime[]|EE_Base_Class[]
282
+	 * @throws \EE_Error
283
+	 */
284 284
 	public function datetimes( $query_params = array() ) {
285 285
 		if ( ! isset( $query_params[ 'order_by' ] ) ) {
286 286
 			$query_params[ 'order_by' ][ 'DTT_order' ] = 'ASC';
@@ -290,12 +290,12 @@  discard block
 block discarded – undo
290 290
 
291 291
 
292 292
 
293
-    /**
294
-     * This returns the chronologically last datetime that this ticket is associated with
295
-     *
296
-     * @return EE_Datetime
297
-     * @throws \EE_Error
298
-     */
293
+	/**
294
+	 * This returns the chronologically last datetime that this ticket is associated with
295
+	 *
296
+	 * @return EE_Datetime
297
+	 * @throws \EE_Error
298
+	 */
299 299
 	public function last_datetime() {
300 300
 		$datetimes = $this->datetimes( array( 'limit' => 1, 'order_by' => array( 'DTT_EVT_start' => 'DESC' ) ) );
301 301
 		return end( $datetimes );
@@ -303,19 +303,19 @@  discard block
 block discarded – undo
303 303
 
304 304
 
305 305
 
306
-    /**
307
-     * This returns the total tickets sold depending on the given parameters.
308
-     *
309
-     * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
310
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
311
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
312
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
313
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
314
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
315
-     * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
316
-     * @return mixed (array|int)          how many tickets have sold
317
-     * @throws \EE_Error
318
-     */
306
+	/**
307
+	 * This returns the total tickets sold depending on the given parameters.
308
+	 *
309
+	 * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
310
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
311
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
312
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
313
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
314
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
315
+	 * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
316
+	 * @return mixed (array|int)          how many tickets have sold
317
+	 * @throws \EE_Error
318
+	 */
319 319
 	public function tickets_sold( $what = 'ticket', $dtt_id = NULL ) {
320 320
 		$total = 0;
321 321
 		$tickets_sold = $this->_all_tickets_sold();
@@ -340,12 +340,12 @@  discard block
 block discarded – undo
340 340
 
341 341
 
342 342
 
343
-    /**
344
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
345
-     *
346
-     * @return EE_Ticket[]
347
-     * @throws \EE_Error
348
-     */
343
+	/**
344
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
345
+	 *
346
+	 * @return EE_Ticket[]
347
+	 * @throws \EE_Error
348
+	 */
349 349
 	protected function _all_tickets_sold() {
350 350
 		$datetimes = $this->get_many_related( 'Datetime' );
351 351
 		$tickets_sold = array();
@@ -361,29 +361,29 @@  discard block
 block discarded – undo
361 361
 
362 362
 
363 363
 
364
-    /**
365
-     * This returns the base price object for the ticket.
366
-     *
367
-     * @param  bool $return_array whether to return as an array indexed by price id or just the object.
368
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
369
-     * @throws \EE_Error
370
-     */
364
+	/**
365
+	 * This returns the base price object for the ticket.
366
+	 *
367
+	 * @param  bool $return_array whether to return as an array indexed by price id or just the object.
368
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
369
+	 * @throws \EE_Error
370
+	 */
371 371
 	public function base_price( $return_array = FALSE ) {
372 372
 		$_where = array( 'Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price );
373 373
 		return $return_array
374
-            ? $this->get_many_related( 'Price', array( $_where ) )
375
-            : $this->get_first_related( 'Price', array( $_where ) );
374
+			? $this->get_many_related( 'Price', array( $_where ) )
375
+			: $this->get_first_related( 'Price', array( $_where ) );
376 376
 	}
377 377
 
378 378
 
379 379
 
380
-    /**
381
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
382
-     *
383
-     * @access public
384
-     * @return EE_Price[]
385
-     * @throws \EE_Error
386
-     */
380
+	/**
381
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
382
+	 *
383
+	 * @access public
384
+	 * @return EE_Price[]
385
+	 * @throws \EE_Error
386
+	 */
387 387
 	public function price_modifiers() {
388 388
 		$query_params = array( 0 => array( 'Price_Type.PBT_ID' => array( 'NOT IN', array( EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax ) ) ) );
389 389
 		return $this->prices( $query_params );
@@ -391,132 +391,132 @@  discard block
 block discarded – undo
391 391
 
392 392
 
393 393
 
394
-    /**
395
-     * Gets all the prices that combine to form the final price of this ticket
396
-     *
397
-     * @param array $query_params like EEM_Base::get_all
398
-     * @return EE_Price[]|EE_Base_Class[]
399
-     * @throws \EE_Error
400
-     */
394
+	/**
395
+	 * Gets all the prices that combine to form the final price of this ticket
396
+	 *
397
+	 * @param array $query_params like EEM_Base::get_all
398
+	 * @return EE_Price[]|EE_Base_Class[]
399
+	 * @throws \EE_Error
400
+	 */
401 401
 	public function prices( $query_params = array() ) {
402 402
 		return $this->get_many_related( 'Price', $query_params );
403 403
 	}
404 404
 
405 405
 
406 406
 
407
-    /**
408
-     * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
409
-     *
410
-     * @param array $query_params see EEM_Base::get_all()
411
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
412
-     * @throws \EE_Error
413
-     */
407
+	/**
408
+	 * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
409
+	 *
410
+	 * @param array $query_params see EEM_Base::get_all()
411
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
412
+	 * @throws \EE_Error
413
+	 */
414 414
 	public function datetime_tickets( $query_params = array() ) {
415 415
 		return $this->get_many_related( 'Datetime_Ticket', $query_params );
416 416
 	}
417 417
 
418 418
 
419 419
 
420
-    /**
421
-     * Gets all the datetimes from the db ordered by DTT_order
422
-     *
423
-     * @param boolean $show_expired
424
-     * @param boolean $show_deleted
425
-     * @return EE_Datetime[]
426
-     * @throws \EE_Error
427
-     */
420
+	/**
421
+	 * Gets all the datetimes from the db ordered by DTT_order
422
+	 *
423
+	 * @param boolean $show_expired
424
+	 * @param boolean $show_deleted
425
+	 * @return EE_Datetime[]
426
+	 * @throws \EE_Error
427
+	 */
428 428
 	public function datetimes_ordered( $show_expired = TRUE, $show_deleted = FALSE ) {
429 429
 		return EEM_Datetime::instance( $this->_timezone )->get_datetimes_for_ticket_ordered_by_DTT_order( $this->ID(), $show_expired, $show_deleted );
430 430
 	}
431 431
 
432 432
 
433 433
 
434
-    /**
435
-     * Gets ID
436
-     *
437
-     * @return string
438
-     * @throws \EE_Error
439
-     */
434
+	/**
435
+	 * Gets ID
436
+	 *
437
+	 * @return string
438
+	 * @throws \EE_Error
439
+	 */
440 440
 	public function ID() {
441 441
 		return $this->get( 'TKT_ID' );
442 442
 	}
443 443
 
444 444
 
445 445
 
446
-    /**
447
-     * get the author of the ticket.
448
-     *
449
-     * @since 4.5.0
450
-     * @return int
451
-     * @throws \EE_Error
452
-     */
446
+	/**
447
+	 * get the author of the ticket.
448
+	 *
449
+	 * @since 4.5.0
450
+	 * @return int
451
+	 * @throws \EE_Error
452
+	 */
453 453
 	public function wp_user() {
454 454
 		return $this->get('TKT_wp_user');
455 455
 	}
456 456
 
457 457
 
458 458
 
459
-    /**
460
-     * Gets the template for the ticket
461
-     *
462
-     * @return EE_Ticket_Template|EE_Base_Class
463
-     * @throws \EE_Error
464
-     */
459
+	/**
460
+	 * Gets the template for the ticket
461
+	 *
462
+	 * @return EE_Ticket_Template|EE_Base_Class
463
+	 * @throws \EE_Error
464
+	 */
465 465
 	public function template() {
466 466
 		return $this->get_first_related( 'Ticket_Template' );
467 467
 	}
468 468
 
469 469
 
470 470
 
471
-    /**
472
-     * Simply returns an array of EE_Price objects that are taxes.
473
-     *
474
-     * @return EE_Price[]
475
-     * @throws \EE_Error
476
-     */
471
+	/**
472
+	 * Simply returns an array of EE_Price objects that are taxes.
473
+	 *
474
+	 * @return EE_Price[]
475
+	 * @throws \EE_Error
476
+	 */
477 477
 	public function get_ticket_taxes_for_admin() {
478 478
 		return EE_Taxes::get_taxes_for_admin();
479 479
 	}
480 480
 
481 481
 
482 482
 
483
-    /**
484
-     * @return float
485
-     * @throws \EE_Error
486
-     */
483
+	/**
484
+	 * @return float
485
+	 * @throws \EE_Error
486
+	 */
487 487
 	public function ticket_price() {
488 488
 		return $this->get( 'TKT_price' );
489 489
 	}
490 490
 
491 491
 
492 492
 
493
-    /**
494
-     * @return mixed
495
-     * @throws \EE_Error
496
-     */
493
+	/**
494
+	 * @return mixed
495
+	 * @throws \EE_Error
496
+	 */
497 497
 	public function pretty_price() {
498 498
 		return $this->get_pretty( 'TKT_price' );
499 499
 	}
500 500
 
501 501
 
502 502
 
503
-    /**
504
-     * @return bool
505
-     * @throws \EE_Error
506
-     */
503
+	/**
504
+	 * @return bool
505
+	 * @throws \EE_Error
506
+	 */
507 507
 	public function is_free() {
508 508
 		return $this->get_ticket_total_with_taxes() === (float) 0;
509 509
 	}
510 510
 
511 511
 
512 512
 
513
-    /**
514
-     * get_ticket_total_with_taxes
515
-     *
516
-     * @param bool $no_cache
517
-     * @return float
518
-     * @throws \EE_Error
519
-     */
513
+	/**
514
+	 * get_ticket_total_with_taxes
515
+	 *
516
+	 * @param bool $no_cache
517
+	 * @return float
518
+	 * @throws \EE_Error
519
+	 */
520 520
 	public function get_ticket_total_with_taxes( $no_cache = FALSE ) {
521 521
 		if ($this->_ticket_total_with_taxes === null || $no_cache ) {
522 522
 			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
@@ -533,201 +533,201 @@  discard block
 block discarded – undo
533 533
 
534 534
 
535 535
 
536
-    /**
537
-     * @return float
538
-     * @throws \EE_Error
539
-     */
536
+	/**
537
+	 * @return float
538
+	 * @throws \EE_Error
539
+	 */
540 540
 	public function get_ticket_subtotal() {
541 541
 		return EE_Taxes::get_subtotal_for_admin( $this );
542 542
 	}
543 543
 
544 544
 
545 545
 
546
-    /**
547
-     * Returns the total taxes applied to this ticket
548
-     *
549
-     * @return float
550
-     * @throws \EE_Error
551
-     */
546
+	/**
547
+	 * Returns the total taxes applied to this ticket
548
+	 *
549
+	 * @return float
550
+	 * @throws \EE_Error
551
+	 */
552 552
 	public function get_ticket_taxes_total_for_admin() {
553 553
 		return EE_Taxes::get_total_taxes_for_admin( $this );
554 554
 	}
555 555
 
556 556
 
557 557
 
558
-    /**
559
-     * Sets name
560
-     *
561
-     * @param string $name
562
-     * @throws \EE_Error
563
-     */
558
+	/**
559
+	 * Sets name
560
+	 *
561
+	 * @param string $name
562
+	 * @throws \EE_Error
563
+	 */
564 564
 	public function set_name( $name ) {
565 565
 		$this->set( 'TKT_name', $name );
566 566
 	}
567 567
 
568 568
 
569 569
 
570
-    /**
571
-     * Gets description
572
-     *
573
-     * @return string
574
-     * @throws \EE_Error
575
-     */
570
+	/**
571
+	 * Gets description
572
+	 *
573
+	 * @return string
574
+	 * @throws \EE_Error
575
+	 */
576 576
 	public function description() {
577 577
 		return $this->get( 'TKT_description' );
578 578
 	}
579 579
 
580 580
 
581 581
 
582
-    /**
583
-     * Sets description
584
-     *
585
-     * @param string $description
586
-     * @throws \EE_Error
587
-     */
582
+	/**
583
+	 * Sets description
584
+	 *
585
+	 * @param string $description
586
+	 * @throws \EE_Error
587
+	 */
588 588
 	public function set_description( $description ) {
589 589
 		$this->set( 'TKT_description', $description );
590 590
 	}
591 591
 
592 592
 
593 593
 
594
-    /**
595
-     * Gets start_date
596
-     *
597
-     * @param string $dt_frmt
598
-     * @param string $tm_frmt
599
-     * @return string
600
-     * @throws \EE_Error
601
-     */
594
+	/**
595
+	 * Gets start_date
596
+	 *
597
+	 * @param string $dt_frmt
598
+	 * @param string $tm_frmt
599
+	 * @return string
600
+	 * @throws \EE_Error
601
+	 */
602 602
 	public function start_date( $dt_frmt = '', $tm_frmt = '' ) {
603 603
 		return $this->_get_datetime( 'TKT_start_date', $dt_frmt, $tm_frmt );
604 604
 	}
605 605
 
606 606
 
607 607
 
608
-    /**
609
-     * Sets start_date
610
-     *
611
-     * @param string $start_date
612
-     * @return void
613
-     * @throws \EE_Error
614
-     */
608
+	/**
609
+	 * Sets start_date
610
+	 *
611
+	 * @param string $start_date
612
+	 * @return void
613
+	 * @throws \EE_Error
614
+	 */
615 615
 	public function set_start_date( $start_date ) {
616 616
 		$this->_set_date_time( 'B', $start_date, 'TKT_start_date' );
617 617
 	}
618 618
 
619 619
 
620 620
 
621
-    /**
622
-     * Gets end_date
623
-     *
624
-     * @param string $dt_frmt
625
-     * @param string $tm_frmt
626
-     * @return string
627
-     * @throws \EE_Error
628
-     */
621
+	/**
622
+	 * Gets end_date
623
+	 *
624
+	 * @param string $dt_frmt
625
+	 * @param string $tm_frmt
626
+	 * @return string
627
+	 * @throws \EE_Error
628
+	 */
629 629
 	public function end_date( $dt_frmt = '', $tm_frmt = '' ) {
630 630
 		return $this->_get_datetime( 'TKT_end_date', $dt_frmt, $tm_frmt );
631 631
 	}
632 632
 
633 633
 
634 634
 
635
-    /**
636
-     * Sets end_date
637
-     *
638
-     * @param string $end_date
639
-     * @return void
640
-     * @throws \EE_Error
641
-     */
635
+	/**
636
+	 * Sets end_date
637
+	 *
638
+	 * @param string $end_date
639
+	 * @return void
640
+	 * @throws \EE_Error
641
+	 */
642 642
 	public function set_end_date( $end_date ) {
643 643
 		$this->_set_date_time( 'B', $end_date, 'TKT_end_date' );
644 644
 	}
645 645
 
646 646
 
647 647
 
648
-    /**
649
-     * Sets sell until time
650
-     *
651
-     * @since 4.5.0
652
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
653
-     * @throws \EE_Error
654
-     */
648
+	/**
649
+	 * Sets sell until time
650
+	 *
651
+	 * @since 4.5.0
652
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
653
+	 * @throws \EE_Error
654
+	 */
655 655
 	public function set_end_time( $time ) {
656 656
 		$this->_set_time_for( $time, 'TKT_end_date' );
657 657
 	}
658 658
 
659 659
 
660 660
 
661
-    /**
662
-     * Sets min
663
-     *
664
-     * @param int $min
665
-     * @return void
666
-     * @throws \EE_Error
667
-     */
661
+	/**
662
+	 * Sets min
663
+	 *
664
+	 * @param int $min
665
+	 * @return void
666
+	 * @throws \EE_Error
667
+	 */
668 668
 	public function set_min( $min ) {
669 669
 		$this->set( 'TKT_min', $min );
670 670
 	}
671 671
 
672 672
 
673 673
 
674
-    /**
675
-     * Gets max
676
-     *
677
-     * @return int
678
-     * @throws \EE_Error
679
-     */
674
+	/**
675
+	 * Gets max
676
+	 *
677
+	 * @return int
678
+	 * @throws \EE_Error
679
+	 */
680 680
 	public function max() {
681 681
 		return $this->get( 'TKT_max' );
682 682
 	}
683 683
 
684 684
 
685 685
 
686
-    /**
687
-     * Sets max
688
-     *
689
-     * @param int $max
690
-     * @return void
691
-     * @throws \EE_Error
692
-     */
686
+	/**
687
+	 * Sets max
688
+	 *
689
+	 * @param int $max
690
+	 * @return void
691
+	 * @throws \EE_Error
692
+	 */
693 693
 	public function set_max( $max ) {
694 694
 		$this->set( 'TKT_max', $max );
695 695
 	}
696 696
 
697 697
 
698 698
 
699
-    /**
700
-     * Sets price
701
-     *
702
-     * @param float $price
703
-     * @return void
704
-     * @throws \EE_Error
705
-     */
699
+	/**
700
+	 * Sets price
701
+	 *
702
+	 * @param float $price
703
+	 * @return void
704
+	 * @throws \EE_Error
705
+	 */
706 706
 	public function set_price( $price ) {
707 707
 		$this->set( 'TKT_price', $price );
708 708
 	}
709 709
 
710 710
 
711 711
 
712
-    /**
713
-     * Gets sold
714
-     *
715
-     * @return int
716
-     * @throws \EE_Error
717
-     */
712
+	/**
713
+	 * Gets sold
714
+	 *
715
+	 * @return int
716
+	 * @throws \EE_Error
717
+	 */
718 718
 	public function sold() {
719 719
 		return $this->get_raw( 'TKT_sold' );
720 720
 	}
721 721
 
722 722
 
723 723
 
724
-    /**
725
-     * Sets sold
726
-     *
727
-     * @param int $sold
728
-     * @return void
729
-     * @throws \EE_Error
730
-     */
724
+	/**
725
+	 * Sets sold
726
+	 *
727
+	 * @param int $sold
728
+	 * @return void
729
+	 * @throws \EE_Error
730
+	 */
731 731
 	public function set_sold( $sold ) {
732 732
 		// sold can not go below zero
733 733
 		$sold = max( 0, $sold );
@@ -736,13 +736,13 @@  discard block
 block discarded – undo
736 736
 
737 737
 
738 738
 
739
-    /**
740
-     * increments sold by amount passed by $qty
741
-     *
742
-     * @param int $qty
743
-     * @return void
744
-     * @throws \EE_Error
745
-     */
739
+	/**
740
+	 * increments sold by amount passed by $qty
741
+	 *
742
+	 * @param int $qty
743
+	 * @return void
744
+	 * @throws \EE_Error
745
+	 */
746 746
 	public function increase_sold( $qty = 1 ) {
747 747
 		$sold = $this->sold() + $qty;
748 748
 		// remove ticket reservation, but don't adjust datetime reservations,  because that will happen
@@ -751,22 +751,22 @@  discard block
 block discarded – undo
751 751
 		$this->_increase_sold_for_datetimes( $qty );
752 752
 		$this->set_sold( $sold );
753 753
 		do_action(
754
-		    'AHEE__EE_Ticket__increase_sold',
755
-            $this,
756
-            $qty,
757
-            $sold
758
-        );
754
+			'AHEE__EE_Ticket__increase_sold',
755
+			$this,
756
+			$qty,
757
+			$sold
758
+		);
759 759
 	}
760 760
 
761 761
 
762 762
 
763
-    /**
764
-     * Increases sold on related datetimes
765
-     *
766
-     * @param int $qty
767
-     * @return void
768
-     * @throws \EE_Error
769
-     */
763
+	/**
764
+	 * Increases sold on related datetimes
765
+	 *
766
+	 * @param int $qty
767
+	 * @return void
768
+	 * @throws \EE_Error
769
+	 */
770 770
 	protected function _increase_sold_for_datetimes( $qty = 1 ) {
771 771
 		$datetimes = $this->datetimes();
772 772
 		if ( is_array( $datetimes ) ) {
@@ -781,34 +781,34 @@  discard block
 block discarded – undo
781 781
 
782 782
 
783 783
 
784
-    /**
785
-     * decrements (subtracts) sold by amount passed by $qty
786
-     *
787
-     * @param int $qty
788
-     * @return void
789
-     * @throws \EE_Error
790
-     */
784
+	/**
785
+	 * decrements (subtracts) sold by amount passed by $qty
786
+	 *
787
+	 * @param int $qty
788
+	 * @return void
789
+	 * @throws \EE_Error
790
+	 */
791 791
 	public function decrease_sold( $qty = 1 ) {
792 792
 		$sold = $this->sold() - $qty;
793 793
 		$this->_decrease_sold_for_datetimes( $qty );
794 794
 		$this->set_sold( $sold );
795
-        do_action(
796
-            'AHEE__EE_Ticket__decrease_sold',
797
-            $this,
798
-            $qty,
799
-            $sold
800
-        );
801
-    }
802
-
803
-
804
-
805
-    /**
806
-     * Decreases sold on related datetimes
807
-     *
808
-     * @param int $qty
809
-     * @return void
810
-     * @throws \EE_Error
811
-     */
795
+		do_action(
796
+			'AHEE__EE_Ticket__decrease_sold',
797
+			$this,
798
+			$qty,
799
+			$sold
800
+		);
801
+	}
802
+
803
+
804
+
805
+	/**
806
+	 * Decreases sold on related datetimes
807
+	 *
808
+	 * @param int $qty
809
+	 * @return void
810
+	 * @throws \EE_Error
811
+	 */
812 812
 	protected function _decrease_sold_for_datetimes( $qty = 1 ) {
813 813
 		$datetimes = $this->datetimes();
814 814
 		if ( is_array( $datetimes ) ) {
@@ -823,25 +823,25 @@  discard block
 block discarded – undo
823 823
 
824 824
 
825 825
 
826
-    /**
827
-     * Gets qty of reserved tickets
828
-     *
829
-     * @return int
830
-     * @throws \EE_Error
831
-     */
826
+	/**
827
+	 * Gets qty of reserved tickets
828
+	 *
829
+	 * @return int
830
+	 * @throws \EE_Error
831
+	 */
832 832
 	public function reserved() {
833 833
 		return $this->get_raw( 'TKT_reserved' );
834 834
 	}
835 835
 
836 836
 
837 837
 
838
-    /**
839
-     * Sets reserved
840
-     *
841
-     * @param int $reserved
842
-     * @return void
843
-     * @throws \EE_Error
844
-     */
838
+	/**
839
+	 * Sets reserved
840
+	 *
841
+	 * @param int $reserved
842
+	 * @return void
843
+	 * @throws \EE_Error
844
+	 */
845 845
 	public function set_reserved( $reserved ) {
846 846
 		// reserved can not go below zero
847 847
 		$reserved = max( 0, (int) $reserved );
@@ -849,48 +849,48 @@  discard block
 block discarded – undo
849 849
 	}
850 850
 
851 851
 
852
-    /**
853
-     * increments reserved by amount passed by $qty
854
-     *
855
-     * @param int    $qty
856
-     * @param string $source
857
-     * @return void
858
-     * @throws EE_Error
859
-     * @throws InvalidArgumentException
860
-     * @throws ReflectionException
861
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
862
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
863
-     */
852
+	/**
853
+	 * increments reserved by amount passed by $qty
854
+	 *
855
+	 * @param int    $qty
856
+	 * @param string $source
857
+	 * @return void
858
+	 * @throws EE_Error
859
+	 * @throws InvalidArgumentException
860
+	 * @throws ReflectionException
861
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
862
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
863
+	 */
864 864
 	public function increase_reserved( $qty = 1, $source = 'unknown' ) {
865 865
 		$qty = absint( $qty );
866 866
 		$reserved = $this->reserved() + $qty;
867
-        if (
868
-            $reserved
869
-            && $this->add_extra_meta(
870
-                EE_Ticket::META_KEY_TICKET_RESERVATIONS,
871
-                "{$qty} from {$source}"
872
-            )
873
-        ) {
874
-            $this->_increase_reserved_for_datetimes($qty);
875
-            $this->set_reserved($reserved);
876
-            do_action(
877
-                'AHEE__EE_Ticket__increase_reserved',
878
-                $this,
879
-                $qty,
880
-                $reserved
881
-            );
882
-        }
883
-    }
884
-
885
-
886
-
887
-    /**
888
-     * Increases sold on related datetimes
889
-     *
890
-     * @param int $qty
891
-     * @return void
892
-     * @throws \EE_Error
893
-     */
867
+		if (
868
+			$reserved
869
+			&& $this->add_extra_meta(
870
+				EE_Ticket::META_KEY_TICKET_RESERVATIONS,
871
+				"{$qty} from {$source}"
872
+			)
873
+		) {
874
+			$this->_increase_reserved_for_datetimes($qty);
875
+			$this->set_reserved($reserved);
876
+			do_action(
877
+				'AHEE__EE_Ticket__increase_reserved',
878
+				$this,
879
+				$qty,
880
+				$reserved
881
+			);
882
+		}
883
+	}
884
+
885
+
886
+
887
+	/**
888
+	 * Increases sold on related datetimes
889
+	 *
890
+	 * @param int $qty
891
+	 * @return void
892
+	 * @throws \EE_Error
893
+	 */
894 894
 	protected function _increase_reserved_for_datetimes( $qty = 1 ) {
895 895
 		$datetimes = $this->datetimes();
896 896
 		if ( is_array( $datetimes ) ) {
@@ -904,49 +904,49 @@  discard block
 block discarded – undo
904 904
 	}
905 905
 
906 906
 
907
-    /**
908
-     * decrements (subtracts) reserved by amount passed by $qty
909
-     *
910
-     * @param int    $qty
911
-     * @param bool   $adjust_datetimes
912
-     * @param string $source
913
-     * @return void
914
-     * @throws EE_Error
915
-     * @throws InvalidArgumentException
916
-     * @throws ReflectionException
917
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919
-     */
907
+	/**
908
+	 * decrements (subtracts) reserved by amount passed by $qty
909
+	 *
910
+	 * @param int    $qty
911
+	 * @param bool   $adjust_datetimes
912
+	 * @param string $source
913
+	 * @return void
914
+	 * @throws EE_Error
915
+	 * @throws InvalidArgumentException
916
+	 * @throws ReflectionException
917
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919
+	 */
920 920
 	public function decrease_reserved( $qty = 1, $adjust_datetimes = true, $source = 'unknown' ) {
921 921
 		$reserved = $this->reserved() - absint( $qty );
922
-        if (
923
-            $this->add_extra_meta(
924
-                EE_Ticket::META_KEY_TICKET_RESERVATIONS,
925
-                "-{$qty} from {$source}"
926
-            )
927
-        ) {
928
-            if ($adjust_datetimes) {
929
-                $this->_decrease_reserved_for_datetimes($qty);
930
-            }
931
-            $this->set_reserved($reserved);
932
-            do_action(
933
-                'AHEE__EE_Ticket__decrease_reserved',
934
-                $this,
935
-                $qty,
936
-                $reserved
937
-            );
938
-        }
939
-    }
940
-
941
-
942
-
943
-    /**
944
-     * Increases sold on related datetimes
945
-     *
946
-     * @param int $qty
947
-     * @return void
948
-     * @throws \EE_Error
949
-     */
922
+		if (
923
+			$this->add_extra_meta(
924
+				EE_Ticket::META_KEY_TICKET_RESERVATIONS,
925
+				"-{$qty} from {$source}"
926
+			)
927
+		) {
928
+			if ($adjust_datetimes) {
929
+				$this->_decrease_reserved_for_datetimes($qty);
930
+			}
931
+			$this->set_reserved($reserved);
932
+			do_action(
933
+				'AHEE__EE_Ticket__decrease_reserved',
934
+				$this,
935
+				$qty,
936
+				$reserved
937
+			);
938
+		}
939
+	}
940
+
941
+
942
+
943
+	/**
944
+	 * Increases sold on related datetimes
945
+	 *
946
+	 * @param int $qty
947
+	 * @return void
948
+	 * @throws \EE_Error
949
+	 */
950 950
 	protected function _decrease_reserved_for_datetimes( $qty = 1 ) {
951 951
 		$datetimes = $this->datetimes();
952 952
 		if ( is_array( $datetimes ) ) {
@@ -961,18 +961,18 @@  discard block
 block discarded – undo
961 961
 
962 962
 
963 963
 
964
-    /**
965
-     * Gets ticket quantity
966
-     *
967
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
968
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
969
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
970
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
971
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
972
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
973
-     * @return int
974
-     * @throws \EE_Error
975
-     */
964
+	/**
965
+	 * Gets ticket quantity
966
+	 *
967
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
968
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
969
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
970
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
971
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
972
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
973
+	 * @return int
974
+	 * @throws \EE_Error
975
+	 */
976 976
 	public function qty( $context = '' ) {
977 977
 		switch ( $context ) {
978 978
 			case 'reg_limit' :
@@ -986,19 +986,19 @@  discard block
 block discarded – undo
986 986
 
987 987
 
988 988
 
989
-    /**
990
-     * Gets ticket quantity
991
-     *
992
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
993
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
994
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
995
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
996
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
997
-     * @param  int   $DTT_ID      the primary key for a particular datetime.
998
-     *                            set to 0 for all related datetimes
999
-     * @return int
1000
-     * @throws \EE_Error
1001
-     */
989
+	/**
990
+	 * Gets ticket quantity
991
+	 *
992
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
993
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
994
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
995
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
996
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
997
+	 * @param  int   $DTT_ID      the primary key for a particular datetime.
998
+	 *                            set to 0 for all related datetimes
999
+	 * @return int
1000
+	 * @throws \EE_Error
1001
+	 */
1002 1002
 	public function real_quantity_on_ticket( $context = 'reg_limit', $DTT_ID = 0 ) {
1003 1003
 		$raw = $this->get_raw( 'TKT_qty' );
1004 1004
 		// return immediately if it's zero
@@ -1081,212 +1081,212 @@  discard block
 block discarded – undo
1081 1081
 
1082 1082
 
1083 1083
 
1084
-    /**
1085
-     * Gets uses
1086
-     *
1087
-     * @return int
1088
-     * @throws \EE_Error
1089
-     */
1084
+	/**
1085
+	 * Gets uses
1086
+	 *
1087
+	 * @return int
1088
+	 * @throws \EE_Error
1089
+	 */
1090 1090
 	public function uses() {
1091 1091
 		return $this->get( 'TKT_uses' );
1092 1092
 	}
1093 1093
 
1094 1094
 
1095 1095
 
1096
-    /**
1097
-     * Sets uses
1098
-     *
1099
-     * @param int $uses
1100
-     * @return void
1101
-     * @throws \EE_Error
1102
-     */
1096
+	/**
1097
+	 * Sets uses
1098
+	 *
1099
+	 * @param int $uses
1100
+	 * @return void
1101
+	 * @throws \EE_Error
1102
+	 */
1103 1103
 	public function set_uses( $uses ) {
1104 1104
 		$this->set( 'TKT_uses', $uses );
1105 1105
 	}
1106 1106
 
1107 1107
 
1108 1108
 
1109
-    /**
1110
-     * returns whether ticket is required or not.
1111
-     *
1112
-     * @return boolean
1113
-     * @throws \EE_Error
1114
-     */
1109
+	/**
1110
+	 * returns whether ticket is required or not.
1111
+	 *
1112
+	 * @return boolean
1113
+	 * @throws \EE_Error
1114
+	 */
1115 1115
 	public function required() {
1116 1116
 		return $this->get( 'TKT_required' );
1117 1117
 	}
1118 1118
 
1119 1119
 
1120 1120
 
1121
-    /**
1122
-     * sets the TKT_required property
1123
-     *
1124
-     * @param boolean $required
1125
-     * @return void
1126
-     * @throws \EE_Error
1127
-     */
1121
+	/**
1122
+	 * sets the TKT_required property
1123
+	 *
1124
+	 * @param boolean $required
1125
+	 * @return void
1126
+	 * @throws \EE_Error
1127
+	 */
1128 1128
 	public function set_required( $required ) {
1129 1129
 		$this->set( 'TKT_required', $required );
1130 1130
 	}
1131 1131
 
1132 1132
 
1133 1133
 
1134
-    /**
1135
-     * Gets taxable
1136
-     *
1137
-     * @return boolean
1138
-     * @throws \EE_Error
1139
-     */
1134
+	/**
1135
+	 * Gets taxable
1136
+	 *
1137
+	 * @return boolean
1138
+	 * @throws \EE_Error
1139
+	 */
1140 1140
 	public function taxable() {
1141 1141
 		return $this->get( 'TKT_taxable' );
1142 1142
 	}
1143 1143
 
1144 1144
 
1145 1145
 
1146
-    /**
1147
-     * Sets taxable
1148
-     *
1149
-     * @param boolean $taxable
1150
-     * @return void
1151
-     * @throws \EE_Error
1152
-     */
1146
+	/**
1147
+	 * Sets taxable
1148
+	 *
1149
+	 * @param boolean $taxable
1150
+	 * @return void
1151
+	 * @throws \EE_Error
1152
+	 */
1153 1153
 	public function set_taxable( $taxable ) {
1154 1154
 		$this->set( 'TKT_taxable', $taxable );
1155 1155
 	}
1156 1156
 
1157 1157
 
1158 1158
 
1159
-    /**
1160
-     * Gets is_default
1161
-     *
1162
-     * @return boolean
1163
-     * @throws \EE_Error
1164
-     */
1159
+	/**
1160
+	 * Gets is_default
1161
+	 *
1162
+	 * @return boolean
1163
+	 * @throws \EE_Error
1164
+	 */
1165 1165
 	public function is_default() {
1166 1166
 		return $this->get( 'TKT_is_default' );
1167 1167
 	}
1168 1168
 
1169 1169
 
1170 1170
 
1171
-    /**
1172
-     * Sets is_default
1173
-     *
1174
-     * @param boolean $is_default
1175
-     * @return void
1176
-     * @throws \EE_Error
1177
-     */
1171
+	/**
1172
+	 * Sets is_default
1173
+	 *
1174
+	 * @param boolean $is_default
1175
+	 * @return void
1176
+	 * @throws \EE_Error
1177
+	 */
1178 1178
 	public function set_is_default( $is_default ) {
1179 1179
 		$this->set( 'TKT_is_default', $is_default );
1180 1180
 	}
1181 1181
 
1182 1182
 
1183 1183
 
1184
-    /**
1185
-     * Gets order
1186
-     *
1187
-     * @return int
1188
-     * @throws \EE_Error
1189
-     */
1184
+	/**
1185
+	 * Gets order
1186
+	 *
1187
+	 * @return int
1188
+	 * @throws \EE_Error
1189
+	 */
1190 1190
 	public function order() {
1191 1191
 		return $this->get( 'TKT_order' );
1192 1192
 	}
1193 1193
 
1194 1194
 
1195 1195
 
1196
-    /**
1197
-     * Sets order
1198
-     *
1199
-     * @param int $order
1200
-     * @return void
1201
-     * @throws \EE_Error
1202
-     */
1196
+	/**
1197
+	 * Sets order
1198
+	 *
1199
+	 * @param int $order
1200
+	 * @return void
1201
+	 * @throws \EE_Error
1202
+	 */
1203 1203
 	public function set_order( $order ) {
1204 1204
 		$this->set( 'TKT_order', $order );
1205 1205
 	}
1206 1206
 
1207 1207
 
1208 1208
 
1209
-    /**
1210
-     * Gets row
1211
-     *
1212
-     * @return int
1213
-     * @throws \EE_Error
1214
-     */
1209
+	/**
1210
+	 * Gets row
1211
+	 *
1212
+	 * @return int
1213
+	 * @throws \EE_Error
1214
+	 */
1215 1215
 	public function row() {
1216 1216
 		return $this->get( 'TKT_row' );
1217 1217
 	}
1218 1218
 
1219 1219
 
1220 1220
 
1221
-    /**
1222
-     * Sets row
1223
-     *
1224
-     * @param int $row
1225
-     * @return void
1226
-     * @throws \EE_Error
1227
-     */
1221
+	/**
1222
+	 * Sets row
1223
+	 *
1224
+	 * @param int $row
1225
+	 * @return void
1226
+	 * @throws \EE_Error
1227
+	 */
1228 1228
 	public function set_row( $row ) {
1229 1229
 		$this->set( 'TKT_row', $row );
1230 1230
 	}
1231 1231
 
1232 1232
 
1233 1233
 
1234
-    /**
1235
-     * Gets deleted
1236
-     *
1237
-     * @return boolean
1238
-     * @throws \EE_Error
1239
-     */
1234
+	/**
1235
+	 * Gets deleted
1236
+	 *
1237
+	 * @return boolean
1238
+	 * @throws \EE_Error
1239
+	 */
1240 1240
 	public function deleted() {
1241 1241
 		return $this->get( 'TKT_deleted' );
1242 1242
 	}
1243 1243
 
1244 1244
 
1245 1245
 
1246
-    /**
1247
-     * Sets deleted
1248
-     *
1249
-     * @param boolean $deleted
1250
-     * @return void
1251
-     * @throws \EE_Error
1252
-     */
1246
+	/**
1247
+	 * Sets deleted
1248
+	 *
1249
+	 * @param boolean $deleted
1250
+	 * @return void
1251
+	 * @throws \EE_Error
1252
+	 */
1253 1253
 	public function set_deleted( $deleted ) {
1254 1254
 		$this->set( 'TKT_deleted', $deleted );
1255 1255
 	}
1256 1256
 
1257 1257
 
1258 1258
 
1259
-    /**
1260
-     * Gets parent
1261
-     *
1262
-     * @return int
1263
-     * @throws \EE_Error
1264
-     */
1259
+	/**
1260
+	 * Gets parent
1261
+	 *
1262
+	 * @return int
1263
+	 * @throws \EE_Error
1264
+	 */
1265 1265
 	public function parent_ID() {
1266 1266
 		return $this->get( 'TKT_parent' );
1267 1267
 	}
1268 1268
 
1269 1269
 
1270 1270
 
1271
-    /**
1272
-     * Sets parent
1273
-     *
1274
-     * @param int $parent
1275
-     * @return void
1276
-     * @throws \EE_Error
1277
-     */
1271
+	/**
1272
+	 * Sets parent
1273
+	 *
1274
+	 * @param int $parent
1275
+	 * @return void
1276
+	 * @throws \EE_Error
1277
+	 */
1278 1278
 	public function set_parent_ID( $parent ) {
1279 1279
 		$this->set( 'TKT_parent', $parent );
1280 1280
 	}
1281 1281
 
1282 1282
 
1283 1283
 
1284
-    /**
1285
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1286
-     *
1287
-     * @return string
1288
-     * @throws \EE_Error
1289
-     */
1284
+	/**
1285
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1286
+	 *
1287
+	 * @return string
1288
+	 * @throws \EE_Error
1289
+	 */
1290 1290
 	public function name_and_info() {
1291 1291
 		$times = array();
1292 1292
 		foreach ( $this->datetimes() as $datetime ) {
@@ -1297,67 +1297,67 @@  discard block
 block discarded – undo
1297 1297
 
1298 1298
 
1299 1299
 
1300
-    /**
1301
-     * Gets name
1302
-     *
1303
-     * @return string
1304
-     * @throws \EE_Error
1305
-     */
1300
+	/**
1301
+	 * Gets name
1302
+	 *
1303
+	 * @return string
1304
+	 * @throws \EE_Error
1305
+	 */
1306 1306
 	public function name() {
1307 1307
 		return $this->get( 'TKT_name' );
1308 1308
 	}
1309 1309
 
1310 1310
 
1311 1311
 
1312
-    /**
1313
-     * Gets price
1314
-     *
1315
-     * @return float
1316
-     * @throws \EE_Error
1317
-     */
1312
+	/**
1313
+	 * Gets price
1314
+	 *
1315
+	 * @return float
1316
+	 * @throws \EE_Error
1317
+	 */
1318 1318
 	public function price() {
1319 1319
 		return $this->get( 'TKT_price' );
1320 1320
 	}
1321 1321
 
1322 1322
 
1323 1323
 
1324
-    /**
1325
-     * Gets all the registrations for this ticket
1326
-     *
1327
-     * @param array $query_params like EEM_Base::get_all's
1328
-     * @return EE_Registration[]|EE_Base_Class[]
1329
-     * @throws \EE_Error
1330
-     */
1324
+	/**
1325
+	 * Gets all the registrations for this ticket
1326
+	 *
1327
+	 * @param array $query_params like EEM_Base::get_all's
1328
+	 * @return EE_Registration[]|EE_Base_Class[]
1329
+	 * @throws \EE_Error
1330
+	 */
1331 1331
 	public function registrations( $query_params = array() ) {
1332 1332
 		return $this->get_many_related( 'Registration', $query_params );
1333 1333
 	}
1334 1334
 
1335 1335
 
1336 1336
 
1337
-    /**
1338
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1339
-     * into account
1340
-     *
1341
-     * @return int
1342
-     * @throws \EE_Error
1343
-     */
1337
+	/**
1338
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1339
+	 * into account
1340
+	 *
1341
+	 * @return int
1342
+	 * @throws \EE_Error
1343
+	 */
1344 1344
 	public function update_tickets_sold() {
1345
-        $count_regs_for_this_ticket = $this->count_registrations(
1346
-            array(
1347
-                array(
1348
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1349
-                    'REG_deleted' => 0,
1350
-                ),
1351
-            )
1352
-        );
1353
-        $sold = $this->sold();
1354
-        if ($count_regs_for_this_ticket > $sold) {
1355
-            $this->increase_sold($count_regs_for_this_ticket - $sold);
1356
-            $this->save();
1357
-        } else if ($count_regs_for_this_ticket < $sold) {
1358
-            $this->decrease_sold($count_regs_for_this_ticket - $sold);
1359
-            $this->save();
1360
-        }
1345
+		$count_regs_for_this_ticket = $this->count_registrations(
1346
+			array(
1347
+				array(
1348
+					'STS_ID'      => EEM_Registration::status_id_approved,
1349
+					'REG_deleted' => 0,
1350
+				),
1351
+			)
1352
+		);
1353
+		$sold = $this->sold();
1354
+		if ($count_regs_for_this_ticket > $sold) {
1355
+			$this->increase_sold($count_regs_for_this_ticket - $sold);
1356
+			$this->save();
1357
+		} else if ($count_regs_for_this_ticket < $sold) {
1358
+			$this->decrease_sold($count_regs_for_this_ticket - $sold);
1359
+			$this->save();
1360
+		}
1361 1361
 		return $count_regs_for_this_ticket;
1362 1362
 	}
1363 1363
 
@@ -1385,21 +1385,21 @@  discard block
 block discarded – undo
1385 1385
 
1386 1386
 
1387 1387
 
1388
-    /**
1389
-     * Implementation of the EEI_Event_Relation interface method
1390
-     *
1391
-     * @see EEI_Event_Relation for comments
1392
-     * @return EE_Event
1393
-     * @throws \EE_Error
1394
-     * @throws UnexpectedEntityException
1395
-     */
1388
+	/**
1389
+	 * Implementation of the EEI_Event_Relation interface method
1390
+	 *
1391
+	 * @see EEI_Event_Relation for comments
1392
+	 * @return EE_Event
1393
+	 * @throws \EE_Error
1394
+	 * @throws UnexpectedEntityException
1395
+	 */
1396 1396
 	public function get_related_event() {
1397 1397
 		//get one datetime to use for getting the event
1398 1398
 		$datetime = $this->first_datetime();
1399 1399
 		if ( ! $datetime instanceof \EE_Datetime ) {
1400 1400
 			throw new UnexpectedEntityException(
1401 1401
 				$datetime,
1402
-                'EE_Datetime',
1402
+				'EE_Datetime',
1403 1403
 				sprintf(
1404 1404
 					__( 'The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1405 1405
 					$this->name()
@@ -1410,7 +1410,7 @@  discard block
 block discarded – undo
1410 1410
 		if ( ! $event instanceof \EE_Event ) {
1411 1411
 			throw new UnexpectedEntityException(
1412 1412
 				$event,
1413
-                'EE_Event',
1413
+				'EE_Event',
1414 1414
 				sprintf(
1415 1415
 					__( 'The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1416 1416
 					$this->name()
@@ -1422,14 +1422,14 @@  discard block
 block discarded – undo
1422 1422
 
1423 1423
 
1424 1424
 
1425
-    /**
1426
-     * Implementation of the EEI_Event_Relation interface method
1427
-     *
1428
-     * @see EEI_Event_Relation for comments
1429
-     * @return string
1430
-     * @throws UnexpectedEntityException
1431
-     * @throws \EE_Error
1432
-     */
1425
+	/**
1426
+	 * Implementation of the EEI_Event_Relation interface method
1427
+	 *
1428
+	 * @see EEI_Event_Relation for comments
1429
+	 * @return string
1430
+	 * @throws UnexpectedEntityException
1431
+	 * @throws \EE_Error
1432
+	 */
1433 1433
 	public function get_event_name() {
1434 1434
 		$event = $this->get_related_event();
1435 1435
 		return $event instanceof EE_Event ? $event->name() : '';
@@ -1437,28 +1437,28 @@  discard block
 block discarded – undo
1437 1437
 
1438 1438
 
1439 1439
 
1440
-    /**
1441
-     * Implementation of the EEI_Event_Relation interface method
1442
-     *
1443
-     * @see EEI_Event_Relation for comments
1444
-     * @return int
1445
-     * @throws UnexpectedEntityException
1446
-     * @throws \EE_Error
1447
-     */
1440
+	/**
1441
+	 * Implementation of the EEI_Event_Relation interface method
1442
+	 *
1443
+	 * @see EEI_Event_Relation for comments
1444
+	 * @return int
1445
+	 * @throws UnexpectedEntityException
1446
+	 * @throws \EE_Error
1447
+	 */
1448 1448
 	public function get_event_ID() {
1449 1449
 		$event = $this->get_related_event();
1450 1450
 		return $event instanceof EE_Event ? $event->ID() : 0;
1451 1451
 	}
1452 1452
 
1453 1453
 
1454
-    /**
1455
-     * This simply returns whether a ticket can be permanently deleted or not.
1456
-     * The criteria for determining this is whether the ticket has any related registrations.
1457
-     * If there are none then it can be permanently deleted.
1458
-     *
1459
-     * @return bool
1460
-     */
1454
+	/**
1455
+	 * This simply returns whether a ticket can be permanently deleted or not.
1456
+	 * The criteria for determining this is whether the ticket has any related registrations.
1457
+	 * If there are none then it can be permanently deleted.
1458
+	 *
1459
+	 * @return bool
1460
+	 */
1461 1461
 	public function is_permanently_deleteable() {
1462
-	    return $this->count_registrations() === 0;
1463
-    }
1462
+		return $this->count_registrations() === 0;
1463
+	}
1464 1464
 } //end EE_Ticket class
Please login to merge, or discard this patch.
Spacing   +198 added lines, -198 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php use EventEspresso\core\exceptions\UnexpectedEntityException;
2 2
 
3
-if ( !defined( 'EVENT_ESPRESSO_VERSION' ) ) {
4
-	exit( 'No direct script access allowed' );
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4
+	exit('No direct script access allowed');
5 5
 }
6 6
 /**
7 7
  * Event Espresso
@@ -77,9 +77,9 @@  discard block
 block discarded – undo
77 77
      * @return EE_Ticket
78 78
      * @throws \EE_Error
79 79
      */
80
-	public static function new_instance( $props_n_values = array(), $timezone = null, $date_formats = array() ) {
81
-		$has_object = parent::_check_for_object( $props_n_values, __CLASS__, $timezone, $date_formats );
82
-		return $has_object ? $has_object : new self( $props_n_values, false, $timezone, $date_formats );
80
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array()) {
81
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
82
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
83 83
 	}
84 84
 
85 85
 
@@ -91,8 +91,8 @@  discard block
 block discarded – undo
91 91
      * @return EE_Ticket
92 92
      * @throws \EE_Error
93 93
      */
94
-	public static function new_instance_from_db( $props_n_values = array(), $timezone = null ) {
95
-		return new self( $props_n_values, TRUE, $timezone );
94
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null) {
95
+		return new self($props_n_values, TRUE, $timezone);
96 96
 	}
97 97
 
98 98
 
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
      * @throws \EE_Error
103 103
      */
104 104
 	public function parent() {
105
-		return $this->get( 'TKT_parent' );
105
+		return $this->get('TKT_parent');
106 106
 	}
107 107
 
108 108
 
@@ -114,13 +114,13 @@  discard block
 block discarded – undo
114 114
      * @return boolean
115 115
      * @throws \EE_Error
116 116
      */
117
-	public function available( $DTT_ID = 0 ) {
117
+	public function available($DTT_ID = 0) {
118 118
 		// are we checking availability for a particular datetime ?
119
-		if ( $DTT_ID ) {
119
+		if ($DTT_ID) {
120 120
 			// get that datetime object
121
-			$datetime = $this->get_first_related( 'Datetime', array( array( 'DTT_ID' => $DTT_ID ) ) );
121
+			$datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
122 122
 			// if  ticket sales for this datetime have exceeded the reg limit...
123
-			if ( $datetime instanceof EE_Datetime && $datetime->sold_out() ) {
123
+			if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
124 124
 				return FALSE;
125 125
 			}
126 126
 		}
@@ -138,22 +138,22 @@  discard block
 block discarded – undo
138 138
      * @return mixed status int if the display string isn't requested
139 139
      * @throws \EE_Error
140 140
      */
141
-	public function ticket_status( $display = FALSE, $remaining = null ) {
142
-		$remaining = is_bool( $remaining ) ? $remaining : $this->is_remaining();
143
-		if ( ! $remaining ) {
144
-			return $display ? EEH_Template::pretty_status( EE_Ticket::sold_out, FALSE, 'sentence' ) : EE_Ticket::sold_out;
141
+	public function ticket_status($display = FALSE, $remaining = null) {
142
+		$remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
143
+		if ( ! $remaining) {
144
+			return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, FALSE, 'sentence') : EE_Ticket::sold_out;
145 145
 		}
146
-		if ( $this->get( 'TKT_deleted' ) ) {
147
-			return $display ? EEH_Template::pretty_status( EE_Ticket::archived, FALSE, 'sentence' ) : EE_Ticket::archived;
146
+		if ($this->get('TKT_deleted')) {
147
+			return $display ? EEH_Template::pretty_status(EE_Ticket::archived, FALSE, 'sentence') : EE_Ticket::archived;
148 148
 		}
149
-		if ( $this->is_expired() ) {
150
-			return $display ? EEH_Template::pretty_status( EE_Ticket::expired, FALSE, 'sentence' ) : EE_Ticket::expired;
149
+		if ($this->is_expired()) {
150
+			return $display ? EEH_Template::pretty_status(EE_Ticket::expired, FALSE, 'sentence') : EE_Ticket::expired;
151 151
 		}
152
-		if ( $this->is_pending() ) {
153
-			return $display ? EEH_Template::pretty_status( EE_Ticket::pending, FALSE, 'sentence' ) : EE_Ticket::pending;
152
+		if ($this->is_pending()) {
153
+			return $display ? EEH_Template::pretty_status(EE_Ticket::pending, FALSE, 'sentence') : EE_Ticket::pending;
154 154
 		}
155
-		if ( $this->is_on_sale() ) {
156
-			return $display ? EEH_Template::pretty_status( EE_Ticket::onsale, FALSE, 'sentence' ) : EE_Ticket::onsale;
155
+		if ($this->is_on_sale()) {
156
+			return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, FALSE, 'sentence') : EE_Ticket::onsale;
157 157
 		}
158 158
 		return '';
159 159
 	}
@@ -168,12 +168,12 @@  discard block
 block discarded – undo
168 168
      * @return boolean         true = tickets remaining, false not.
169 169
      * @throws \EE_Error
170 170
      */
171
-	public function is_remaining( $DTT_ID = 0 ) {
172
-		$num_remaining = $this->remaining( $DTT_ID );
173
-		if ( $num_remaining === 0 ) {
171
+	public function is_remaining($DTT_ID = 0) {
172
+		$num_remaining = $this->remaining($DTT_ID);
173
+		if ($num_remaining === 0) {
174 174
 			return FALSE;
175 175
 		}
176
-		if ( $num_remaining > 0 && $num_remaining < $this->min() ) {
176
+		if ($num_remaining > 0 && $num_remaining < $this->min()) {
177 177
 			return FALSE;
178 178
 		}
179 179
 		return TRUE;
@@ -189,8 +189,8 @@  discard block
 block discarded – undo
189 189
      * @return int
190 190
      * @throws \EE_Error
191 191
      */
192
-	public function remaining( $DTT_ID = 0 ) {
193
-		return $this->real_quantity_on_ticket('saleable', $DTT_ID );
192
+	public function remaining($DTT_ID = 0) {
193
+		return $this->real_quantity_on_ticket('saleable', $DTT_ID);
194 194
 	}
195 195
 
196 196
 
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
      * @throws \EE_Error
203 203
      */
204 204
 	public function min() {
205
-		return $this->get( 'TKT_min' );
205
+		return $this->get('TKT_min');
206 206
 	}
207 207
 
208 208
 
@@ -214,7 +214,7 @@  discard block
 block discarded – undo
214 214
      * @throws \EE_Error
215 215
      */
216 216
 	public function is_expired() {
217
-		return ( $this->get_raw( 'TKT_end_date' ) < time() );
217
+		return ($this->get_raw('TKT_end_date') < time());
218 218
 	}
219 219
 
220 220
 
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
      * @throws \EE_Error
227 227
      */
228 228
 	public function is_pending() {
229
-		return ( $this->get_raw( 'TKT_start_date' ) > time() );
229
+		return ($this->get_raw('TKT_start_date') > time());
230 230
 	}
231 231
 
232 232
 
@@ -238,7 +238,7 @@  discard block
 block discarded – undo
238 238
      * @throws \EE_Error
239 239
      */
240 240
 	public function is_on_sale() {
241
-		return ( $this->get_raw( 'TKT_start_date' ) < time() && $this->get_raw( 'TKT_end_date' ) > time() );
241
+		return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
242 242
 	}
243 243
 
244 244
 
@@ -251,11 +251,11 @@  discard block
 block discarded – undo
251 251
      * @return string
252 252
      * @throws \EE_Error
253 253
      */
254
-	public function date_range( $dt_frmt = '', $conjunction = ' - ' ) {
255
-		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->start_date( $dt_frmt ) : '';
256
-		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->end_date( $dt_frmt ) : '';
254
+	public function date_range($dt_frmt = '', $conjunction = ' - ') {
255
+		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->start_date($dt_frmt) : '';
256
+		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->end_date($dt_frmt) : '';
257 257
 
258
-		return $first_date && $last_date ? $first_date . $conjunction  . $last_date : '';
258
+		return $first_date && $last_date ? $first_date.$conjunction.$last_date : '';
259 259
 	}
260 260
 
261 261
 
@@ -267,8 +267,8 @@  discard block
 block discarded – undo
267 267
      * @throws \EE_Error
268 268
      */
269 269
 	public function first_datetime() {
270
-		$datetimes = $this->datetimes( array( 'limit' => 1 ) );
271
-		return reset( $datetimes );
270
+		$datetimes = $this->datetimes(array('limit' => 1));
271
+		return reset($datetimes);
272 272
 	}
273 273
 
274 274
 
@@ -281,11 +281,11 @@  discard block
 block discarded – undo
281 281
      * @return EE_Datetime[]|EE_Base_Class[]
282 282
      * @throws \EE_Error
283 283
      */
284
-	public function datetimes( $query_params = array() ) {
285
-		if ( ! isset( $query_params[ 'order_by' ] ) ) {
286
-			$query_params[ 'order_by' ][ 'DTT_order' ] = 'ASC';
284
+	public function datetimes($query_params = array()) {
285
+		if ( ! isset($query_params['order_by'])) {
286
+			$query_params['order_by']['DTT_order'] = 'ASC';
287 287
 		}
288
-		return $this->get_many_related( 'Datetime', $query_params );
288
+		return $this->get_many_related('Datetime', $query_params);
289 289
 	}
290 290
 
291 291
 
@@ -297,8 +297,8 @@  discard block
 block discarded – undo
297 297
      * @throws \EE_Error
298 298
      */
299 299
 	public function last_datetime() {
300
-		$datetimes = $this->datetimes( array( 'limit' => 1, 'order_by' => array( 'DTT_EVT_start' => 'DESC' ) ) );
301
-		return end( $datetimes );
300
+		$datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
301
+		return end($datetimes);
302 302
 	}
303 303
 
304 304
 
@@ -316,22 +316,22 @@  discard block
 block discarded – undo
316 316
      * @return mixed (array|int)          how many tickets have sold
317 317
      * @throws \EE_Error
318 318
      */
319
-	public function tickets_sold( $what = 'ticket', $dtt_id = NULL ) {
319
+	public function tickets_sold($what = 'ticket', $dtt_id = NULL) {
320 320
 		$total = 0;
321 321
 		$tickets_sold = $this->_all_tickets_sold();
322
-		switch ( $what ) {
322
+		switch ($what) {
323 323
 			case 'ticket' :
324
-				return $tickets_sold[ 'ticket' ];
324
+				return $tickets_sold['ticket'];
325 325
 				break;
326 326
 			case 'datetime' :
327
-				if ( empty( $tickets_sold[ 'datetime' ] ) ) {
327
+				if (empty($tickets_sold['datetime'])) {
328 328
 					return $total;
329 329
 				}
330
-				if ( ! empty( $dtt_id ) && ! isset( $tickets_sold[ 'datetime' ][ $dtt_id ] ) ) {
331
-					EE_Error::add_error( __( 'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
330
+				if ( ! empty($dtt_id) && ! isset($tickets_sold['datetime'][$dtt_id])) {
331
+					EE_Error::add_error(__('You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
332 332
 					return $total;
333 333
 				}
334
-				return empty( $dtt_id ) ? $tickets_sold[ 'datetime' ] : $tickets_sold[ 'datetime' ][ $dtt_id ];
334
+				return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][$dtt_id];
335 335
 				break;
336 336
 			default:
337 337
 				return $total;
@@ -347,15 +347,15 @@  discard block
 block discarded – undo
347 347
      * @throws \EE_Error
348 348
      */
349 349
 	protected function _all_tickets_sold() {
350
-		$datetimes = $this->get_many_related( 'Datetime' );
350
+		$datetimes = $this->get_many_related('Datetime');
351 351
 		$tickets_sold = array();
352
-		if ( ! empty( $datetimes ) ) {
353
-			foreach ( $datetimes as $datetime ) {
354
-				$tickets_sold[ 'datetime' ][ $datetime->ID() ] = $datetime->get( 'DTT_sold' );
352
+		if ( ! empty($datetimes)) {
353
+			foreach ($datetimes as $datetime) {
354
+				$tickets_sold['datetime'][$datetime->ID()] = $datetime->get('DTT_sold');
355 355
 			}
356 356
 		}
357 357
 		//Tickets sold
358
-		$tickets_sold[ 'ticket' ] = $this->sold();
358
+		$tickets_sold['ticket'] = $this->sold();
359 359
 		return $tickets_sold;
360 360
 	}
361 361
 
@@ -368,11 +368,11 @@  discard block
 block discarded – undo
368 368
      * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
369 369
      * @throws \EE_Error
370 370
      */
371
-	public function base_price( $return_array = FALSE ) {
372
-		$_where = array( 'Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price );
371
+	public function base_price($return_array = FALSE) {
372
+		$_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
373 373
 		return $return_array
374
-            ? $this->get_many_related( 'Price', array( $_where ) )
375
-            : $this->get_first_related( 'Price', array( $_where ) );
374
+            ? $this->get_many_related('Price', array($_where))
375
+            : $this->get_first_related('Price', array($_where));
376 376
 	}
377 377
 
378 378
 
@@ -385,8 +385,8 @@  discard block
 block discarded – undo
385 385
      * @throws \EE_Error
386 386
      */
387 387
 	public function price_modifiers() {
388
-		$query_params = array( 0 => array( 'Price_Type.PBT_ID' => array( 'NOT IN', array( EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax ) ) ) );
389
-		return $this->prices( $query_params );
388
+		$query_params = array(0 => array('Price_Type.PBT_ID' => array('NOT IN', array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax))));
389
+		return $this->prices($query_params);
390 390
 	}
391 391
 
392 392
 
@@ -398,8 +398,8 @@  discard block
 block discarded – undo
398 398
      * @return EE_Price[]|EE_Base_Class[]
399 399
      * @throws \EE_Error
400 400
      */
401
-	public function prices( $query_params = array() ) {
402
-		return $this->get_many_related( 'Price', $query_params );
401
+	public function prices($query_params = array()) {
402
+		return $this->get_many_related('Price', $query_params);
403 403
 	}
404 404
 
405 405
 
@@ -411,8 +411,8 @@  discard block
 block discarded – undo
411 411
      * @return EE_Datetime_Ticket|EE_Base_Class[]
412 412
      * @throws \EE_Error
413 413
      */
414
-	public function datetime_tickets( $query_params = array() ) {
415
-		return $this->get_many_related( 'Datetime_Ticket', $query_params );
414
+	public function datetime_tickets($query_params = array()) {
415
+		return $this->get_many_related('Datetime_Ticket', $query_params);
416 416
 	}
417 417
 
418 418
 
@@ -425,8 +425,8 @@  discard block
 block discarded – undo
425 425
      * @return EE_Datetime[]
426 426
      * @throws \EE_Error
427 427
      */
428
-	public function datetimes_ordered( $show_expired = TRUE, $show_deleted = FALSE ) {
429
-		return EEM_Datetime::instance( $this->_timezone )->get_datetimes_for_ticket_ordered_by_DTT_order( $this->ID(), $show_expired, $show_deleted );
428
+	public function datetimes_ordered($show_expired = TRUE, $show_deleted = FALSE) {
429
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order($this->ID(), $show_expired, $show_deleted);
430 430
 	}
431 431
 
432 432
 
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
      * @throws \EE_Error
439 439
      */
440 440
 	public function ID() {
441
-		return $this->get( 'TKT_ID' );
441
+		return $this->get('TKT_ID');
442 442
 	}
443 443
 
444 444
 
@@ -463,7 +463,7 @@  discard block
 block discarded – undo
463 463
      * @throws \EE_Error
464 464
      */
465 465
 	public function template() {
466
-		return $this->get_first_related( 'Ticket_Template' );
466
+		return $this->get_first_related('Ticket_Template');
467 467
 	}
468 468
 
469 469
 
@@ -485,7 +485,7 @@  discard block
 block discarded – undo
485 485
      * @throws \EE_Error
486 486
      */
487 487
 	public function ticket_price() {
488
-		return $this->get( 'TKT_price' );
488
+		return $this->get('TKT_price');
489 489
 	}
490 490
 
491 491
 
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
      * @throws \EE_Error
496 496
      */
497 497
 	public function pretty_price() {
498
-		return $this->get_pretty( 'TKT_price' );
498
+		return $this->get_pretty('TKT_price');
499 499
 	}
500 500
 
501 501
 
@@ -517,8 +517,8 @@  discard block
 block discarded – undo
517 517
      * @return float
518 518
      * @throws \EE_Error
519 519
      */
520
-	public function get_ticket_total_with_taxes( $no_cache = FALSE ) {
521
-		if ($this->_ticket_total_with_taxes === null || $no_cache ) {
520
+	public function get_ticket_total_with_taxes($no_cache = FALSE) {
521
+		if ($this->_ticket_total_with_taxes === null || $no_cache) {
522 522
 			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
523 523
 		}
524 524
 		return (float) $this->_ticket_total_with_taxes;
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
 
528 528
 
529 529
 	public function ensure_TKT_Price_correct() {
530
-		$this->set( 'TKT_price', EE_Taxes::get_subtotal_for_admin( $this ) );
530
+		$this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
531 531
 		$this->save();
532 532
 	}
533 533
 
@@ -538,7 +538,7 @@  discard block
 block discarded – undo
538 538
      * @throws \EE_Error
539 539
      */
540 540
 	public function get_ticket_subtotal() {
541
-		return EE_Taxes::get_subtotal_for_admin( $this );
541
+		return EE_Taxes::get_subtotal_for_admin($this);
542 542
 	}
543 543
 
544 544
 
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
      * @throws \EE_Error
551 551
      */
552 552
 	public function get_ticket_taxes_total_for_admin() {
553
-		return EE_Taxes::get_total_taxes_for_admin( $this );
553
+		return EE_Taxes::get_total_taxes_for_admin($this);
554 554
 	}
555 555
 
556 556
 
@@ -561,8 +561,8 @@  discard block
 block discarded – undo
561 561
      * @param string $name
562 562
      * @throws \EE_Error
563 563
      */
564
-	public function set_name( $name ) {
565
-		$this->set( 'TKT_name', $name );
564
+	public function set_name($name) {
565
+		$this->set('TKT_name', $name);
566 566
 	}
567 567
 
568 568
 
@@ -574,7 +574,7 @@  discard block
 block discarded – undo
574 574
      * @throws \EE_Error
575 575
      */
576 576
 	public function description() {
577
-		return $this->get( 'TKT_description' );
577
+		return $this->get('TKT_description');
578 578
 	}
579 579
 
580 580
 
@@ -585,8 +585,8 @@  discard block
 block discarded – undo
585 585
      * @param string $description
586 586
      * @throws \EE_Error
587 587
      */
588
-	public function set_description( $description ) {
589
-		$this->set( 'TKT_description', $description );
588
+	public function set_description($description) {
589
+		$this->set('TKT_description', $description);
590 590
 	}
591 591
 
592 592
 
@@ -599,8 +599,8 @@  discard block
 block discarded – undo
599 599
      * @return string
600 600
      * @throws \EE_Error
601 601
      */
602
-	public function start_date( $dt_frmt = '', $tm_frmt = '' ) {
603
-		return $this->_get_datetime( 'TKT_start_date', $dt_frmt, $tm_frmt );
602
+	public function start_date($dt_frmt = '', $tm_frmt = '') {
603
+		return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
604 604
 	}
605 605
 
606 606
 
@@ -612,8 +612,8 @@  discard block
 block discarded – undo
612 612
      * @return void
613 613
      * @throws \EE_Error
614 614
      */
615
-	public function set_start_date( $start_date ) {
616
-		$this->_set_date_time( 'B', $start_date, 'TKT_start_date' );
615
+	public function set_start_date($start_date) {
616
+		$this->_set_date_time('B', $start_date, 'TKT_start_date');
617 617
 	}
618 618
 
619 619
 
@@ -626,8 +626,8 @@  discard block
 block discarded – undo
626 626
      * @return string
627 627
      * @throws \EE_Error
628 628
      */
629
-	public function end_date( $dt_frmt = '', $tm_frmt = '' ) {
630
-		return $this->_get_datetime( 'TKT_end_date', $dt_frmt, $tm_frmt );
629
+	public function end_date($dt_frmt = '', $tm_frmt = '') {
630
+		return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
631 631
 	}
632 632
 
633 633
 
@@ -639,8 +639,8 @@  discard block
 block discarded – undo
639 639
      * @return void
640 640
      * @throws \EE_Error
641 641
      */
642
-	public function set_end_date( $end_date ) {
643
-		$this->_set_date_time( 'B', $end_date, 'TKT_end_date' );
642
+	public function set_end_date($end_date) {
643
+		$this->_set_date_time('B', $end_date, 'TKT_end_date');
644 644
 	}
645 645
 
646 646
 
@@ -652,8 +652,8 @@  discard block
 block discarded – undo
652 652
      * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
653 653
      * @throws \EE_Error
654 654
      */
655
-	public function set_end_time( $time ) {
656
-		$this->_set_time_for( $time, 'TKT_end_date' );
655
+	public function set_end_time($time) {
656
+		$this->_set_time_for($time, 'TKT_end_date');
657 657
 	}
658 658
 
659 659
 
@@ -665,8 +665,8 @@  discard block
 block discarded – undo
665 665
      * @return void
666 666
      * @throws \EE_Error
667 667
      */
668
-	public function set_min( $min ) {
669
-		$this->set( 'TKT_min', $min );
668
+	public function set_min($min) {
669
+		$this->set('TKT_min', $min);
670 670
 	}
671 671
 
672 672
 
@@ -678,7 +678,7 @@  discard block
 block discarded – undo
678 678
      * @throws \EE_Error
679 679
      */
680 680
 	public function max() {
681
-		return $this->get( 'TKT_max' );
681
+		return $this->get('TKT_max');
682 682
 	}
683 683
 
684 684
 
@@ -690,8 +690,8 @@  discard block
 block discarded – undo
690 690
      * @return void
691 691
      * @throws \EE_Error
692 692
      */
693
-	public function set_max( $max ) {
694
-		$this->set( 'TKT_max', $max );
693
+	public function set_max($max) {
694
+		$this->set('TKT_max', $max);
695 695
 	}
696 696
 
697 697
 
@@ -703,8 +703,8 @@  discard block
 block discarded – undo
703 703
      * @return void
704 704
      * @throws \EE_Error
705 705
      */
706
-	public function set_price( $price ) {
707
-		$this->set( 'TKT_price', $price );
706
+	public function set_price($price) {
707
+		$this->set('TKT_price', $price);
708 708
 	}
709 709
 
710 710
 
@@ -716,7 +716,7 @@  discard block
 block discarded – undo
716 716
      * @throws \EE_Error
717 717
      */
718 718
 	public function sold() {
719
-		return $this->get_raw( 'TKT_sold' );
719
+		return $this->get_raw('TKT_sold');
720 720
 	}
721 721
 
722 722
 
@@ -728,10 +728,10 @@  discard block
 block discarded – undo
728 728
      * @return void
729 729
      * @throws \EE_Error
730 730
      */
731
-	public function set_sold( $sold ) {
731
+	public function set_sold($sold) {
732 732
 		// sold can not go below zero
733
-		$sold = max( 0, $sold );
734
-		$this->set( 'TKT_sold', $sold );
733
+		$sold = max(0, $sold);
734
+		$this->set('TKT_sold', $sold);
735 735
 	}
736 736
 
737 737
 
@@ -743,13 +743,13 @@  discard block
 block discarded – undo
743 743
      * @return void
744 744
      * @throws \EE_Error
745 745
      */
746
-	public function increase_sold( $qty = 1 ) {
746
+	public function increase_sold($qty = 1) {
747 747
 		$sold = $this->sold() + $qty;
748 748
 		// remove ticket reservation, but don't adjust datetime reservations,  because that will happen
749 749
 		// via \EE_Datetime::increase_sold() when \EE_Ticket::_increase_sold_for_datetimes() is called
750
-		$this->decrease_reserved( $qty, false, "TKT: {$this->ID()} (ln:" . __LINE__ . ')');
751
-		$this->_increase_sold_for_datetimes( $qty );
752
-		$this->set_sold( $sold );
750
+		$this->decrease_reserved($qty, false, "TKT: {$this->ID()} (ln:".__LINE__.')');
751
+		$this->_increase_sold_for_datetimes($qty);
752
+		$this->set_sold($sold);
753 753
 		do_action(
754 754
 		    'AHEE__EE_Ticket__increase_sold',
755 755
             $this,
@@ -767,12 +767,12 @@  discard block
 block discarded – undo
767 767
      * @return void
768 768
      * @throws \EE_Error
769 769
      */
770
-	protected function _increase_sold_for_datetimes( $qty = 1 ) {
770
+	protected function _increase_sold_for_datetimes($qty = 1) {
771 771
 		$datetimes = $this->datetimes();
772
-		if ( is_array( $datetimes ) ) {
773
-			foreach ( $datetimes as $datetime ) {
774
-				if ( $datetime instanceof EE_Datetime ) {
775
-					$datetime->increase_sold( $qty );
772
+		if (is_array($datetimes)) {
773
+			foreach ($datetimes as $datetime) {
774
+				if ($datetime instanceof EE_Datetime) {
775
+					$datetime->increase_sold($qty);
776 776
 					$datetime->save();
777 777
 				}
778 778
 			}
@@ -788,10 +788,10 @@  discard block
 block discarded – undo
788 788
      * @return void
789 789
      * @throws \EE_Error
790 790
      */
791
-	public function decrease_sold( $qty = 1 ) {
791
+	public function decrease_sold($qty = 1) {
792 792
 		$sold = $this->sold() - $qty;
793
-		$this->_decrease_sold_for_datetimes( $qty );
794
-		$this->set_sold( $sold );
793
+		$this->_decrease_sold_for_datetimes($qty);
794
+		$this->set_sold($sold);
795 795
         do_action(
796 796
             'AHEE__EE_Ticket__decrease_sold',
797 797
             $this,
@@ -809,12 +809,12 @@  discard block
 block discarded – undo
809 809
      * @return void
810 810
      * @throws \EE_Error
811 811
      */
812
-	protected function _decrease_sold_for_datetimes( $qty = 1 ) {
812
+	protected function _decrease_sold_for_datetimes($qty = 1) {
813 813
 		$datetimes = $this->datetimes();
814
-		if ( is_array( $datetimes ) ) {
815
-			foreach ( $datetimes as $datetime ) {
816
-				if ( $datetime instanceof EE_Datetime ) {
817
-					$datetime->decrease_sold( $qty );
814
+		if (is_array($datetimes)) {
815
+			foreach ($datetimes as $datetime) {
816
+				if ($datetime instanceof EE_Datetime) {
817
+					$datetime->decrease_sold($qty);
818 818
 					$datetime->save();
819 819
 				}
820 820
 			}
@@ -830,7 +830,7 @@  discard block
 block discarded – undo
830 830
      * @throws \EE_Error
831 831
      */
832 832
 	public function reserved() {
833
-		return $this->get_raw( 'TKT_reserved' );
833
+		return $this->get_raw('TKT_reserved');
834 834
 	}
835 835
 
836 836
 
@@ -842,10 +842,10 @@  discard block
 block discarded – undo
842 842
      * @return void
843 843
      * @throws \EE_Error
844 844
      */
845
-	public function set_reserved( $reserved ) {
845
+	public function set_reserved($reserved) {
846 846
 		// reserved can not go below zero
847
-		$reserved = max( 0, (int) $reserved );
848
-		$this->set( 'TKT_reserved', $reserved );
847
+		$reserved = max(0, (int) $reserved);
848
+		$this->set('TKT_reserved', $reserved);
849 849
 	}
850 850
 
851 851
 
@@ -861,8 +861,8 @@  discard block
 block discarded – undo
861 861
      * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
862 862
      * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
863 863
      */
864
-	public function increase_reserved( $qty = 1, $source = 'unknown' ) {
865
-		$qty = absint( $qty );
864
+	public function increase_reserved($qty = 1, $source = 'unknown') {
865
+		$qty = absint($qty);
866 866
 		$reserved = $this->reserved() + $qty;
867 867
         if (
868 868
             $reserved
@@ -891,12 +891,12 @@  discard block
 block discarded – undo
891 891
      * @return void
892 892
      * @throws \EE_Error
893 893
      */
894
-	protected function _increase_reserved_for_datetimes( $qty = 1 ) {
894
+	protected function _increase_reserved_for_datetimes($qty = 1) {
895 895
 		$datetimes = $this->datetimes();
896
-		if ( is_array( $datetimes ) ) {
897
-			foreach ( $datetimes as $datetime ) {
898
-				if ( $datetime instanceof EE_Datetime ) {
899
-					$datetime->increase_reserved( $qty );
896
+		if (is_array($datetimes)) {
897
+			foreach ($datetimes as $datetime) {
898
+				if ($datetime instanceof EE_Datetime) {
899
+					$datetime->increase_reserved($qty);
900 900
 					$datetime->save();
901 901
 				}
902 902
 			}
@@ -917,8 +917,8 @@  discard block
 block discarded – undo
917 917
      * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918 918
      * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919 919
      */
920
-	public function decrease_reserved( $qty = 1, $adjust_datetimes = true, $source = 'unknown' ) {
921
-		$reserved = $this->reserved() - absint( $qty );
920
+	public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown') {
921
+		$reserved = $this->reserved() - absint($qty);
922 922
         if (
923 923
             $this->add_extra_meta(
924 924
                 EE_Ticket::META_KEY_TICKET_RESERVATIONS,
@@ -947,12 +947,12 @@  discard block
 block discarded – undo
947 947
      * @return void
948 948
      * @throws \EE_Error
949 949
      */
950
-	protected function _decrease_reserved_for_datetimes( $qty = 1 ) {
950
+	protected function _decrease_reserved_for_datetimes($qty = 1) {
951 951
 		$datetimes = $this->datetimes();
952
-		if ( is_array( $datetimes ) ) {
953
-			foreach ( $datetimes as $datetime ) {
954
-				if ( $datetime instanceof EE_Datetime ) {
955
-					$datetime->decrease_reserved( $qty );
952
+		if (is_array($datetimes)) {
953
+			foreach ($datetimes as $datetime) {
954
+				if ($datetime instanceof EE_Datetime) {
955
+					$datetime->decrease_reserved($qty);
956 956
 					$datetime->save();
957 957
 				}
958 958
 			}
@@ -973,14 +973,14 @@  discard block
 block discarded – undo
973 973
      * @return int
974 974
      * @throws \EE_Error
975 975
      */
976
-	public function qty( $context = '' ) {
977
-		switch ( $context ) {
976
+	public function qty($context = '') {
977
+		switch ($context) {
978 978
 			case 'reg_limit' :
979 979
 				return $this->real_quantity_on_ticket();
980 980
 			case 'saleable' :
981
-				return $this->real_quantity_on_ticket( 'saleable' );
981
+				return $this->real_quantity_on_ticket('saleable');
982 982
 			default:
983
-				return $this->get_raw( 'TKT_qty' );
983
+				return $this->get_raw('TKT_qty');
984 984
 		}
985 985
 	}
986 986
 
@@ -999,15 +999,15 @@  discard block
 block discarded – undo
999 999
      * @return int
1000 1000
      * @throws \EE_Error
1001 1001
      */
1002
-	public function real_quantity_on_ticket( $context = 'reg_limit', $DTT_ID = 0 ) {
1003
-		$raw = $this->get_raw( 'TKT_qty' );
1002
+	public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0) {
1003
+		$raw = $this->get_raw('TKT_qty');
1004 1004
 		// return immediately if it's zero
1005
-		if ( $raw === 0 ) {
1005
+		if ($raw === 0) {
1006 1006
 			return $raw;
1007 1007
 		}
1008 1008
 		//echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1009 1009
 		// ensure qty doesn't exceed raw value for THIS ticket
1010
-		$qty = min( EE_INF, $raw );
1010
+		$qty = min(EE_INF, $raw);
1011 1011
 		//echo "\n . qty: " . $qty . '<br />';
1012 1012
 		// calculate this ticket's total sales and reservations
1013 1013
 		$sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
@@ -1016,23 +1016,23 @@  discard block
 block discarded – undo
1016 1016
 		//echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1017 1017
 		// first we need to calculate the maximum number of tickets available for the datetime
1018 1018
 		// do we want data for one datetime or all of them ?
1019
-		$query_params = $DTT_ID ? array( array( 'DTT_ID' => $DTT_ID ) ) : array();
1020
-		$datetimes = $this->datetimes( $query_params );
1021
-		if ( is_array( $datetimes ) && ! empty( $datetimes ) ) {
1022
-			foreach ( $datetimes as $datetime ) {
1023
-				if ( $datetime instanceof EE_Datetime ) {
1019
+		$query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1020
+		$datetimes = $this->datetimes($query_params);
1021
+		if (is_array($datetimes) && ! empty($datetimes)) {
1022
+			foreach ($datetimes as $datetime) {
1023
+				if ($datetime instanceof EE_Datetime) {
1024 1024
 					$datetime->refresh_from_db();
1025 1025
 					//echo "\n . . datetime name: " . $datetime->name() . '<br />';
1026 1026
 					//echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1027 1027
 					// initialize with no restrictions for each datetime
1028 1028
 					// but adjust datetime qty based on datetime reg limit
1029
-					$datetime_qty = min( EE_INF, $datetime->reg_limit() );
1029
+					$datetime_qty = min(EE_INF, $datetime->reg_limit());
1030 1030
 					//echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1031 1031
 					//echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1032 1032
 					// if we want the actual saleable amount, then we need to consider OTHER ticket sales
1033 1033
 					// and reservations for this datetime, that do NOT include sales and reservations
1034 1034
 					// for this ticket (so we add $this->sold() and $this->reserved() back in)
1035
-					if ( $context === 'saleable' ) {
1035
+					if ($context === 'saleable') {
1036 1036
 						$datetime_qty = max(
1037 1037
 							$datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1038 1038
 							0
@@ -1044,16 +1044,16 @@  discard block
 block discarded – undo
1044 1044
 						$datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1045 1045
 						//echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1046 1046
 					}
1047
-					$qty = min( $datetime_qty, $qty );
1047
+					$qty = min($datetime_qty, $qty);
1048 1048
 					//echo "\n . . qty: " . $qty . '<br />';
1049 1049
 				}
1050 1050
 			}
1051 1051
 		}
1052 1052
 		// NOW that we know the  maximum number of tickets available for the datetime
1053 1053
 		// we can finally factor in the details for this specific ticket
1054
-		if ( $qty > 0 && $context === 'saleable' ) {
1054
+		if ($qty > 0 && $context === 'saleable') {
1055 1055
 			// and subtract the sales for THIS ticket
1056
-			$qty = max( $qty - $sold_and_reserved_for_this_ticket, 0 );
1056
+			$qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1057 1057
 			//echo "\n . qty: " . $qty . '<br />';
1058 1058
 		}
1059 1059
 		//echo "\nFINAL QTY: " . $qty . "<br /><br />";
@@ -1069,14 +1069,14 @@  discard block
 block discarded – undo
1069 1069
 	 * @return void
1070 1070
 	 * @throws \EE_Error
1071 1071
 	 */
1072
-	public function set_qty( $qty ) {
1072
+	public function set_qty($qty) {
1073 1073
 		$datetimes = $this->datetimes();
1074
-		foreach ( $datetimes as $datetime ) {
1075
-			if ( $datetime instanceof EE_Datetime ) {
1076
-				$qty = min( $qty, $datetime->reg_limit() );
1074
+		foreach ($datetimes as $datetime) {
1075
+			if ($datetime instanceof EE_Datetime) {
1076
+				$qty = min($qty, $datetime->reg_limit());
1077 1077
 			}
1078 1078
 		}
1079
-		$this->set( 'TKT_qty', $qty );
1079
+		$this->set('TKT_qty', $qty);
1080 1080
 	}
1081 1081
 
1082 1082
 
@@ -1088,7 +1088,7 @@  discard block
 block discarded – undo
1088 1088
      * @throws \EE_Error
1089 1089
      */
1090 1090
 	public function uses() {
1091
-		return $this->get( 'TKT_uses' );
1091
+		return $this->get('TKT_uses');
1092 1092
 	}
1093 1093
 
1094 1094
 
@@ -1100,8 +1100,8 @@  discard block
 block discarded – undo
1100 1100
      * @return void
1101 1101
      * @throws \EE_Error
1102 1102
      */
1103
-	public function set_uses( $uses ) {
1104
-		$this->set( 'TKT_uses', $uses );
1103
+	public function set_uses($uses) {
1104
+		$this->set('TKT_uses', $uses);
1105 1105
 	}
1106 1106
 
1107 1107
 
@@ -1113,7 +1113,7 @@  discard block
 block discarded – undo
1113 1113
      * @throws \EE_Error
1114 1114
      */
1115 1115
 	public function required() {
1116
-		return $this->get( 'TKT_required' );
1116
+		return $this->get('TKT_required');
1117 1117
 	}
1118 1118
 
1119 1119
 
@@ -1125,8 +1125,8 @@  discard block
 block discarded – undo
1125 1125
      * @return void
1126 1126
      * @throws \EE_Error
1127 1127
      */
1128
-	public function set_required( $required ) {
1129
-		$this->set( 'TKT_required', $required );
1128
+	public function set_required($required) {
1129
+		$this->set('TKT_required', $required);
1130 1130
 	}
1131 1131
 
1132 1132
 
@@ -1138,7 +1138,7 @@  discard block
 block discarded – undo
1138 1138
      * @throws \EE_Error
1139 1139
      */
1140 1140
 	public function taxable() {
1141
-		return $this->get( 'TKT_taxable' );
1141
+		return $this->get('TKT_taxable');
1142 1142
 	}
1143 1143
 
1144 1144
 
@@ -1150,8 +1150,8 @@  discard block
 block discarded – undo
1150 1150
      * @return void
1151 1151
      * @throws \EE_Error
1152 1152
      */
1153
-	public function set_taxable( $taxable ) {
1154
-		$this->set( 'TKT_taxable', $taxable );
1153
+	public function set_taxable($taxable) {
1154
+		$this->set('TKT_taxable', $taxable);
1155 1155
 	}
1156 1156
 
1157 1157
 
@@ -1163,7 +1163,7 @@  discard block
 block discarded – undo
1163 1163
      * @throws \EE_Error
1164 1164
      */
1165 1165
 	public function is_default() {
1166
-		return $this->get( 'TKT_is_default' );
1166
+		return $this->get('TKT_is_default');
1167 1167
 	}
1168 1168
 
1169 1169
 
@@ -1175,8 +1175,8 @@  discard block
 block discarded – undo
1175 1175
      * @return void
1176 1176
      * @throws \EE_Error
1177 1177
      */
1178
-	public function set_is_default( $is_default ) {
1179
-		$this->set( 'TKT_is_default', $is_default );
1178
+	public function set_is_default($is_default) {
1179
+		$this->set('TKT_is_default', $is_default);
1180 1180
 	}
1181 1181
 
1182 1182
 
@@ -1188,7 +1188,7 @@  discard block
 block discarded – undo
1188 1188
      * @throws \EE_Error
1189 1189
      */
1190 1190
 	public function order() {
1191
-		return $this->get( 'TKT_order' );
1191
+		return $this->get('TKT_order');
1192 1192
 	}
1193 1193
 
1194 1194
 
@@ -1200,8 +1200,8 @@  discard block
 block discarded – undo
1200 1200
      * @return void
1201 1201
      * @throws \EE_Error
1202 1202
      */
1203
-	public function set_order( $order ) {
1204
-		$this->set( 'TKT_order', $order );
1203
+	public function set_order($order) {
1204
+		$this->set('TKT_order', $order);
1205 1205
 	}
1206 1206
 
1207 1207
 
@@ -1213,7 +1213,7 @@  discard block
 block discarded – undo
1213 1213
      * @throws \EE_Error
1214 1214
      */
1215 1215
 	public function row() {
1216
-		return $this->get( 'TKT_row' );
1216
+		return $this->get('TKT_row');
1217 1217
 	}
1218 1218
 
1219 1219
 
@@ -1225,8 +1225,8 @@  discard block
 block discarded – undo
1225 1225
      * @return void
1226 1226
      * @throws \EE_Error
1227 1227
      */
1228
-	public function set_row( $row ) {
1229
-		$this->set( 'TKT_row', $row );
1228
+	public function set_row($row) {
1229
+		$this->set('TKT_row', $row);
1230 1230
 	}
1231 1231
 
1232 1232
 
@@ -1238,7 +1238,7 @@  discard block
 block discarded – undo
1238 1238
      * @throws \EE_Error
1239 1239
      */
1240 1240
 	public function deleted() {
1241
-		return $this->get( 'TKT_deleted' );
1241
+		return $this->get('TKT_deleted');
1242 1242
 	}
1243 1243
 
1244 1244
 
@@ -1250,8 +1250,8 @@  discard block
 block discarded – undo
1250 1250
      * @return void
1251 1251
      * @throws \EE_Error
1252 1252
      */
1253
-	public function set_deleted( $deleted ) {
1254
-		$this->set( 'TKT_deleted', $deleted );
1253
+	public function set_deleted($deleted) {
1254
+		$this->set('TKT_deleted', $deleted);
1255 1255
 	}
1256 1256
 
1257 1257
 
@@ -1263,7 +1263,7 @@  discard block
 block discarded – undo
1263 1263
      * @throws \EE_Error
1264 1264
      */
1265 1265
 	public function parent_ID() {
1266
-		return $this->get( 'TKT_parent' );
1266
+		return $this->get('TKT_parent');
1267 1267
 	}
1268 1268
 
1269 1269
 
@@ -1275,8 +1275,8 @@  discard block
 block discarded – undo
1275 1275
      * @return void
1276 1276
      * @throws \EE_Error
1277 1277
      */
1278
-	public function set_parent_ID( $parent ) {
1279
-		$this->set( 'TKT_parent', $parent );
1278
+	public function set_parent_ID($parent) {
1279
+		$this->set('TKT_parent', $parent);
1280 1280
 	}
1281 1281
 
1282 1282
 
@@ -1289,10 +1289,10 @@  discard block
 block discarded – undo
1289 1289
      */
1290 1290
 	public function name_and_info() {
1291 1291
 		$times = array();
1292
-		foreach ( $this->datetimes() as $datetime ) {
1292
+		foreach ($this->datetimes() as $datetime) {
1293 1293
 			$times[] = $datetime->start_date_and_time();
1294 1294
 		}
1295
-		return $this->name() . ' @ ' . implode( ', ', $times ) . ' for ' . $this->pretty_price();
1295
+		return $this->name().' @ '.implode(', ', $times).' for '.$this->pretty_price();
1296 1296
 	}
1297 1297
 
1298 1298
 
@@ -1304,7 +1304,7 @@  discard block
 block discarded – undo
1304 1304
      * @throws \EE_Error
1305 1305
      */
1306 1306
 	public function name() {
1307
-		return $this->get( 'TKT_name' );
1307
+		return $this->get('TKT_name');
1308 1308
 	}
1309 1309
 
1310 1310
 
@@ -1316,7 +1316,7 @@  discard block
 block discarded – undo
1316 1316
      * @throws \EE_Error
1317 1317
      */
1318 1318
 	public function price() {
1319
-		return $this->get( 'TKT_price' );
1319
+		return $this->get('TKT_price');
1320 1320
 	}
1321 1321
 
1322 1322
 
@@ -1328,8 +1328,8 @@  discard block
 block discarded – undo
1328 1328
      * @return EE_Registration[]|EE_Base_Class[]
1329 1329
      * @throws \EE_Error
1330 1330
      */
1331
-	public function registrations( $query_params = array() ) {
1332
-		return $this->get_many_related( 'Registration', $query_params );
1331
+	public function registrations($query_params = array()) {
1332
+		return $this->get_many_related('Registration', $query_params);
1333 1333
 	}
1334 1334
 
1335 1335
 
@@ -1368,7 +1368,7 @@  discard block
 block discarded – undo
1368 1368
 	 * @param array $query_params like EEM_Base::get_all's
1369 1369
 	 * @return int
1370 1370
 	 */
1371
-	public function count_registrations( $query_params = array() ) {
1371
+	public function count_registrations($query_params = array()) {
1372 1372
 		return $this->count_related('Registration', $query_params);
1373 1373
 	}
1374 1374
 
@@ -1396,23 +1396,23 @@  discard block
 block discarded – undo
1396 1396
 	public function get_related_event() {
1397 1397
 		//get one datetime to use for getting the event
1398 1398
 		$datetime = $this->first_datetime();
1399
-		if ( ! $datetime instanceof \EE_Datetime ) {
1399
+		if ( ! $datetime instanceof \EE_Datetime) {
1400 1400
 			throw new UnexpectedEntityException(
1401 1401
 				$datetime,
1402 1402
                 'EE_Datetime',
1403 1403
 				sprintf(
1404
-					__( 'The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1404
+					__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1405 1405
 					$this->name()
1406 1406
 				)
1407 1407
 			);
1408 1408
 		}
1409 1409
 		$event = $datetime->event();
1410
-		if ( ! $event instanceof \EE_Event ) {
1410
+		if ( ! $event instanceof \EE_Event) {
1411 1411
 			throw new UnexpectedEntityException(
1412 1412
 				$event,
1413 1413
                 'EE_Event',
1414 1414
 				sprintf(
1415
-					__( 'The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1415
+					__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1416 1416
 					$this->name()
1417 1417
 				)
1418 1418
 			);
Please login to merge, or discard this patch.
core/EE_Session.core.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -542,7 +542,7 @@  discard block
 block discarded – undo
542 542
     /**
543 543
      * @initiate session
544 544
      * @access   private
545
-     * @return TRUE on success, FALSE on fail
545
+     * @return boolean on success, FALSE on fail
546 546
      * @throws EE_Error
547 547
      * @throws InvalidArgumentException
548 548
      * @throws InvalidDataTypeException
@@ -778,7 +778,7 @@  discard block
 block discarded – undo
778 778
      * @update session data  prior to saving to the db
779 779
      * @access public
780 780
      * @param bool $new_session
781
-     * @return TRUE on success, FALSE on fail
781
+     * @return boolean on success, FALSE on fail
782 782
      * @throws EE_Error
783 783
      * @throws InvalidArgumentException
784 784
      * @throws InvalidDataTypeException
@@ -879,7 +879,7 @@  discard block
 block discarded – undo
879 879
      * _save_session_to_db
880 880
      *
881 881
      * @param bool $clear_session
882
-     * @return string
882
+     * @return boolean
883 883
      * @throws EE_Error
884 884
      * @throws InvalidArgumentException
885 885
      * @throws InvalidDataTypeException
Please login to merge, or discard this patch.
Indentation   +1215 added lines, -1215 removed lines patch added patch discarded remove patch
@@ -22,1213 +22,1213 @@  discard block
 block discarded – undo
22 22
 class EE_Session implements SessionIdentifierInterface
23 23
 {
24 24
 
25
-    const session_id_prefix    = 'ee_ssn_';
26
-
27
-    const hash_check_prefix    = 'ee_shc_';
28
-
29
-    const OPTION_NAME_SETTINGS = 'ee_session_settings';
30
-
31
-    const STATUS_CLOSED        = 0;
32
-
33
-    const STATUS_OPEN          = 1;
34
-
35
-    /**
36
-     * instance of the EE_Session object
37
-     *
38
-     * @var EE_Session
39
-     */
40
-    private static $_instance;
41
-
42
-    /**
43
-     * @var CacheStorageInterface $cache_storage
44
-     */
45
-    protected $cache_storage;
46
-
47
-    /**
48
-     * EE_Encryption object
49
-     *
50
-     * @var EE_Encryption
51
-     */
52
-    protected $encryption;
53
-
54
-    /**
55
-     * the session id
56
-     *
57
-     * @var string
58
-     */
59
-    private $_sid;
60
-
61
-    /**
62
-     * session id salt
63
-     *
64
-     * @var string
65
-     */
66
-    private $_sid_salt;
67
-
68
-    /**
69
-     * session data
70
-     *
71
-     * @var array
72
-     */
73
-    private $_session_data = array();
74
-
75
-    /**
76
-     * how long an EE session lasts
77
-     * default session lifespan of 1 hour (for not so instant IPNs)
78
-     *
79
-     * @var SessionLifespan $session_lifespan
80
-     */
81
-    private $session_lifespan;
82
-
83
-    /**
84
-     * session expiration time as Unix timestamp in GMT
85
-     *
86
-     * @var int
87
-     */
88
-    private $_expiration;
89
-
90
-    /**
91
-     * whether or not session has expired at some point
92
-     *
93
-     * @var boolean
94
-     */
95
-    private $_expired = false;
96
-
97
-    /**
98
-     * current time as Unix timestamp in GMT
99
-     *
100
-     * @var int
101
-     */
102
-    private $_time;
103
-
104
-    /**
105
-     * whether to encrypt session data
106
-     *
107
-     * @var bool
108
-     */
109
-    private $_use_encryption;
110
-
111
-    /**
112
-     * well... according to the server...
113
-     *
114
-     * @var null
115
-     */
116
-    private $_user_agent;
117
-
118
-    /**
119
-     * do you really trust the server ?
120
-     *
121
-     * @var null
122
-     */
123
-    private $_ip_address;
124
-
125
-    /**
126
-     * current WP user_id
127
-     *
128
-     * @var null
129
-     */
130
-    private $_wp_user_id;
131
-
132
-    /**
133
-     * array for defining default session vars
134
-     *
135
-     * @var array
136
-     */
137
-    private $_default_session_vars = array(
138
-        'id'            => null,
139
-        'user_id'       => null,
140
-        'ip_address'    => null,
141
-        'user_agent'    => null,
142
-        'init_access'   => null,
143
-        'last_access'   => null,
144
-        'expiration'    => null,
145
-        'pages_visited' => array(),
146
-    );
147
-
148
-    /**
149
-     * timestamp for when last garbage collection cycle was performed
150
-     *
151
-     * @var int $_last_gc
152
-     */
153
-    private $_last_gc;
154
-
155
-    /**
156
-     * @var RequestInterface $request
157
-     */
158
-    protected $request;
159
-
160
-    /**
161
-     * whether session is active or not
162
-     *
163
-     * @var int $status
164
-     */
165
-    private $status = EE_Session::STATUS_CLOSED;
166
-
167
-
168
-
169
-    /**
170
-     * @singleton method used to instantiate class object
171
-     * @param CacheStorageInterface $cache_storage
172
-     * @param SessionLifespan|null  $lifespan
173
-     * @param RequestInterface      $request
174
-     * @param EE_Encryption         $encryption
175
-     * @return EE_Session
176
-     * @throws InvalidArgumentException
177
-     * @throws InvalidDataTypeException
178
-     * @throws InvalidInterfaceException
179
-     */
180
-    public static function instance(
181
-        CacheStorageInterface $cache_storage = null,
182
-        SessionLifespan $lifespan = null,
183
-        RequestInterface $request = null,
184
-        EE_Encryption $encryption = null
185
-    ) {
186
-        // check if class object is instantiated
187
-        // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
188
-        // add_filter( 'FHEE_load_EE_Session', '__return_false' );
189
-        if (! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
190
-            self::$_instance = new self(
191
-                $cache_storage,
192
-                $lifespan,
193
-                $request,
194
-                $encryption
195
-            );
196
-        }
197
-        return self::$_instance;
198
-    }
199
-
200
-
201
-    /**
202
-     * protected constructor to prevent direct creation
203
-     *
204
-     * @param CacheStorageInterface $cache_storage
205
-     * @param SessionLifespan       $lifespan
206
-     * @param RequestInterface      $request
207
-     * @param EE_Encryption         $encryption
208
-     * @throws InvalidArgumentException
209
-     * @throws InvalidDataTypeException
210
-     * @throws InvalidInterfaceException
211
-     */
212
-    protected function __construct(
213
-        CacheStorageInterface $cache_storage,
214
-        SessionLifespan $lifespan,
215
-        RequestInterface $request,
216
-        EE_Encryption $encryption = null
217
-    ) {
218
-        // session loading is turned ON by default,
219
-        // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
220
-        // (which currently fires on the init hook at priority 9),
221
-        // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
222
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
223
-            return;
224
-        }
225
-        $this->session_lifespan = $lifespan;
226
-        $this->request          = $request;
227
-        if (! defined('ESPRESSO_SESSION')) {
228
-            define('ESPRESSO_SESSION', true);
229
-        }
230
-        // retrieve session options from db
231
-        $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
232
-        if (! empty($session_settings)) {
233
-            // cycle though existing session options
234
-            foreach ($session_settings as $var_name => $session_setting) {
235
-                // set values for class properties
236
-                $var_name          = '_' . $var_name;
237
-                $this->{$var_name} = $session_setting;
238
-            }
239
-        }
240
-        $this->cache_storage = $cache_storage;
241
-        // are we using encryption?
242
-        $this->_use_encryption = $encryption instanceof EE_Encryption
243
-                                 && EE_Registry::instance()->CFG->admin->encode_session_data();
244
-        // \EEH_Debug_Tools::printr($this->_use_encryption, '$this->_use_encryption', __FILE__, __LINE__);
245
-        // encrypt data via: $this->encryption->encrypt();
246
-        $this->encryption = $encryption;
247
-        // filter hook allows outside functions/classes/plugins to change default empty cart
248
-        $extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
249
-        array_merge($this->_default_session_vars, $extra_default_session_vars);
250
-        // apply default session vars
251
-        $this->_set_defaults();
252
-        add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
253
-        // check request for 'clear_session' param
254
-        add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
255
-        // once everything is all said and done,
256
-        add_action('shutdown', array($this, 'update'), 100);
257
-        add_action('shutdown', array($this, 'garbageCollection'), 1000);
258
-        $this->configure_garbage_collection_filters();
259
-    }
260
-
261
-
262
-    /**
263
-     * @return bool
264
-     * @throws InvalidArgumentException
265
-     * @throws InvalidDataTypeException
266
-     * @throws InvalidInterfaceException
267
-     */
268
-    public static function isLoadedAndActive()
269
-    {
270
-        return did_action('AHEE__EE_System__core_loaded_and_ready')
271
-               && EE_Session::instance() instanceof EE_Session
272
-               && EE_Session::instance()->isActive();
273
-    }
274
-
275
-
276
-    /**
277
-     * @return bool
278
-     */
279
-    public function isActive()
280
-    {
281
-        return $this->status === EE_Session::STATUS_OPEN;
282
-    }
283
-
284
-
285
-
286
-    /**
287
-     * @return void
288
-     * @throws EE_Error
289
-     * @throws InvalidArgumentException
290
-     * @throws InvalidDataTypeException
291
-     * @throws InvalidInterfaceException
292
-     * @throws InvalidSessionDataException
293
-     */
294
-    public function open_session()
295
-    {
296
-        // check for existing session and retrieve it from db
297
-        if (! $this->_espresso_session()) {
298
-            // or just start a new one
299
-            $this->_create_espresso_session();
300
-        }
301
-    }
302
-
303
-
304
-
305
-    /**
306
-     * @return bool
307
-     */
308
-    public function expired()
309
-    {
310
-        return $this->_expired;
311
-    }
312
-
313
-
314
-
315
-    /**
316
-     * @return void
317
-     */
318
-    public function reset_expired()
319
-    {
320
-        $this->_expired = false;
321
-    }
322
-
323
-
324
-    /**
325
-     * @return int
326
-     */
327
-    public function expiration()
328
-    {
329
-        return $this->_expiration;
330
-    }
331
-
332
-
333
-
334
-    /**
335
-     * @return int
336
-     */
337
-    public function extension()
338
-    {
339
-        return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
340
-    }
341
-
342
-
343
-
344
-    /**
345
-     * @param int $time number of seconds to add to session expiration
346
-     */
347
-    public function extend_expiration($time = 0)
348
-    {
349
-        $time              = $time ? $time : $this->extension();
350
-        $this->_expiration += absint($time);
351
-    }
352
-
353
-
354
-
355
-    /**
356
-     * @return int
357
-     */
358
-    public function lifespan()
359
-    {
360
-        return $this->session_lifespan->inSeconds();
361
-    }
362
-
363
-
364
-
365
-    /**
366
-     * This just sets some defaults for the _session data property
367
-     *
368
-     * @access private
369
-     * @return void
370
-     */
371
-    private function _set_defaults()
372
-    {
373
-        // set some defaults
374
-        foreach ($this->_default_session_vars as $key => $default_var) {
375
-            if (is_array($default_var)) {
376
-                $this->_session_data[ $key ] = array();
377
-            } else {
378
-                $this->_session_data[ $key ] = '';
379
-            }
380
-        }
381
-    }
25
+	const session_id_prefix    = 'ee_ssn_';
26
+
27
+	const hash_check_prefix    = 'ee_shc_';
28
+
29
+	const OPTION_NAME_SETTINGS = 'ee_session_settings';
30
+
31
+	const STATUS_CLOSED        = 0;
32
+
33
+	const STATUS_OPEN          = 1;
34
+
35
+	/**
36
+	 * instance of the EE_Session object
37
+	 *
38
+	 * @var EE_Session
39
+	 */
40
+	private static $_instance;
41
+
42
+	/**
43
+	 * @var CacheStorageInterface $cache_storage
44
+	 */
45
+	protected $cache_storage;
46
+
47
+	/**
48
+	 * EE_Encryption object
49
+	 *
50
+	 * @var EE_Encryption
51
+	 */
52
+	protected $encryption;
53
+
54
+	/**
55
+	 * the session id
56
+	 *
57
+	 * @var string
58
+	 */
59
+	private $_sid;
60
+
61
+	/**
62
+	 * session id salt
63
+	 *
64
+	 * @var string
65
+	 */
66
+	private $_sid_salt;
67
+
68
+	/**
69
+	 * session data
70
+	 *
71
+	 * @var array
72
+	 */
73
+	private $_session_data = array();
74
+
75
+	/**
76
+	 * how long an EE session lasts
77
+	 * default session lifespan of 1 hour (for not so instant IPNs)
78
+	 *
79
+	 * @var SessionLifespan $session_lifespan
80
+	 */
81
+	private $session_lifespan;
82
+
83
+	/**
84
+	 * session expiration time as Unix timestamp in GMT
85
+	 *
86
+	 * @var int
87
+	 */
88
+	private $_expiration;
89
+
90
+	/**
91
+	 * whether or not session has expired at some point
92
+	 *
93
+	 * @var boolean
94
+	 */
95
+	private $_expired = false;
96
+
97
+	/**
98
+	 * current time as Unix timestamp in GMT
99
+	 *
100
+	 * @var int
101
+	 */
102
+	private $_time;
103
+
104
+	/**
105
+	 * whether to encrypt session data
106
+	 *
107
+	 * @var bool
108
+	 */
109
+	private $_use_encryption;
110
+
111
+	/**
112
+	 * well... according to the server...
113
+	 *
114
+	 * @var null
115
+	 */
116
+	private $_user_agent;
117
+
118
+	/**
119
+	 * do you really trust the server ?
120
+	 *
121
+	 * @var null
122
+	 */
123
+	private $_ip_address;
124
+
125
+	/**
126
+	 * current WP user_id
127
+	 *
128
+	 * @var null
129
+	 */
130
+	private $_wp_user_id;
131
+
132
+	/**
133
+	 * array for defining default session vars
134
+	 *
135
+	 * @var array
136
+	 */
137
+	private $_default_session_vars = array(
138
+		'id'            => null,
139
+		'user_id'       => null,
140
+		'ip_address'    => null,
141
+		'user_agent'    => null,
142
+		'init_access'   => null,
143
+		'last_access'   => null,
144
+		'expiration'    => null,
145
+		'pages_visited' => array(),
146
+	);
147
+
148
+	/**
149
+	 * timestamp for when last garbage collection cycle was performed
150
+	 *
151
+	 * @var int $_last_gc
152
+	 */
153
+	private $_last_gc;
154
+
155
+	/**
156
+	 * @var RequestInterface $request
157
+	 */
158
+	protected $request;
159
+
160
+	/**
161
+	 * whether session is active or not
162
+	 *
163
+	 * @var int $status
164
+	 */
165
+	private $status = EE_Session::STATUS_CLOSED;
166
+
167
+
168
+
169
+	/**
170
+	 * @singleton method used to instantiate class object
171
+	 * @param CacheStorageInterface $cache_storage
172
+	 * @param SessionLifespan|null  $lifespan
173
+	 * @param RequestInterface      $request
174
+	 * @param EE_Encryption         $encryption
175
+	 * @return EE_Session
176
+	 * @throws InvalidArgumentException
177
+	 * @throws InvalidDataTypeException
178
+	 * @throws InvalidInterfaceException
179
+	 */
180
+	public static function instance(
181
+		CacheStorageInterface $cache_storage = null,
182
+		SessionLifespan $lifespan = null,
183
+		RequestInterface $request = null,
184
+		EE_Encryption $encryption = null
185
+	) {
186
+		// check if class object is instantiated
187
+		// session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
188
+		// add_filter( 'FHEE_load_EE_Session', '__return_false' );
189
+		if (! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
190
+			self::$_instance = new self(
191
+				$cache_storage,
192
+				$lifespan,
193
+				$request,
194
+				$encryption
195
+			);
196
+		}
197
+		return self::$_instance;
198
+	}
199
+
200
+
201
+	/**
202
+	 * protected constructor to prevent direct creation
203
+	 *
204
+	 * @param CacheStorageInterface $cache_storage
205
+	 * @param SessionLifespan       $lifespan
206
+	 * @param RequestInterface      $request
207
+	 * @param EE_Encryption         $encryption
208
+	 * @throws InvalidArgumentException
209
+	 * @throws InvalidDataTypeException
210
+	 * @throws InvalidInterfaceException
211
+	 */
212
+	protected function __construct(
213
+		CacheStorageInterface $cache_storage,
214
+		SessionLifespan $lifespan,
215
+		RequestInterface $request,
216
+		EE_Encryption $encryption = null
217
+	) {
218
+		// session loading is turned ON by default,
219
+		// but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
220
+		// (which currently fires on the init hook at priority 9),
221
+		// can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
222
+		if (! apply_filters('FHEE_load_EE_Session', true)) {
223
+			return;
224
+		}
225
+		$this->session_lifespan = $lifespan;
226
+		$this->request          = $request;
227
+		if (! defined('ESPRESSO_SESSION')) {
228
+			define('ESPRESSO_SESSION', true);
229
+		}
230
+		// retrieve session options from db
231
+		$session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
232
+		if (! empty($session_settings)) {
233
+			// cycle though existing session options
234
+			foreach ($session_settings as $var_name => $session_setting) {
235
+				// set values for class properties
236
+				$var_name          = '_' . $var_name;
237
+				$this->{$var_name} = $session_setting;
238
+			}
239
+		}
240
+		$this->cache_storage = $cache_storage;
241
+		// are we using encryption?
242
+		$this->_use_encryption = $encryption instanceof EE_Encryption
243
+								 && EE_Registry::instance()->CFG->admin->encode_session_data();
244
+		// \EEH_Debug_Tools::printr($this->_use_encryption, '$this->_use_encryption', __FILE__, __LINE__);
245
+		// encrypt data via: $this->encryption->encrypt();
246
+		$this->encryption = $encryption;
247
+		// filter hook allows outside functions/classes/plugins to change default empty cart
248
+		$extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
249
+		array_merge($this->_default_session_vars, $extra_default_session_vars);
250
+		// apply default session vars
251
+		$this->_set_defaults();
252
+		add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
253
+		// check request for 'clear_session' param
254
+		add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
255
+		// once everything is all said and done,
256
+		add_action('shutdown', array($this, 'update'), 100);
257
+		add_action('shutdown', array($this, 'garbageCollection'), 1000);
258
+		$this->configure_garbage_collection_filters();
259
+	}
260
+
261
+
262
+	/**
263
+	 * @return bool
264
+	 * @throws InvalidArgumentException
265
+	 * @throws InvalidDataTypeException
266
+	 * @throws InvalidInterfaceException
267
+	 */
268
+	public static function isLoadedAndActive()
269
+	{
270
+		return did_action('AHEE__EE_System__core_loaded_and_ready')
271
+			   && EE_Session::instance() instanceof EE_Session
272
+			   && EE_Session::instance()->isActive();
273
+	}
274
+
275
+
276
+	/**
277
+	 * @return bool
278
+	 */
279
+	public function isActive()
280
+	{
281
+		return $this->status === EE_Session::STATUS_OPEN;
282
+	}
283
+
284
+
285
+
286
+	/**
287
+	 * @return void
288
+	 * @throws EE_Error
289
+	 * @throws InvalidArgumentException
290
+	 * @throws InvalidDataTypeException
291
+	 * @throws InvalidInterfaceException
292
+	 * @throws InvalidSessionDataException
293
+	 */
294
+	public function open_session()
295
+	{
296
+		// check for existing session and retrieve it from db
297
+		if (! $this->_espresso_session()) {
298
+			// or just start a new one
299
+			$this->_create_espresso_session();
300
+		}
301
+	}
302
+
303
+
304
+
305
+	/**
306
+	 * @return bool
307
+	 */
308
+	public function expired()
309
+	{
310
+		return $this->_expired;
311
+	}
312
+
313
+
314
+
315
+	/**
316
+	 * @return void
317
+	 */
318
+	public function reset_expired()
319
+	{
320
+		$this->_expired = false;
321
+	}
322
+
323
+
324
+	/**
325
+	 * @return int
326
+	 */
327
+	public function expiration()
328
+	{
329
+		return $this->_expiration;
330
+	}
331
+
332
+
333
+
334
+	/**
335
+	 * @return int
336
+	 */
337
+	public function extension()
338
+	{
339
+		return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
340
+	}
341
+
342
+
343
+
344
+	/**
345
+	 * @param int $time number of seconds to add to session expiration
346
+	 */
347
+	public function extend_expiration($time = 0)
348
+	{
349
+		$time              = $time ? $time : $this->extension();
350
+		$this->_expiration += absint($time);
351
+	}
352
+
353
+
354
+
355
+	/**
356
+	 * @return int
357
+	 */
358
+	public function lifespan()
359
+	{
360
+		return $this->session_lifespan->inSeconds();
361
+	}
362
+
363
+
364
+
365
+	/**
366
+	 * This just sets some defaults for the _session data property
367
+	 *
368
+	 * @access private
369
+	 * @return void
370
+	 */
371
+	private function _set_defaults()
372
+	{
373
+		// set some defaults
374
+		foreach ($this->_default_session_vars as $key => $default_var) {
375
+			if (is_array($default_var)) {
376
+				$this->_session_data[ $key ] = array();
377
+			} else {
378
+				$this->_session_data[ $key ] = '';
379
+			}
380
+		}
381
+	}
382 382
 
383 383
 
384
-
385
-    /**
386
-     * @retrieve  session data
387
-     * @access    public
388
-     * @return    string
389
-     */
390
-    public function id()
391
-    {
392
-        return $this->_sid;
393
-    }
384
+
385
+	/**
386
+	 * @retrieve  session data
387
+	 * @access    public
388
+	 * @return    string
389
+	 */
390
+	public function id()
391
+	{
392
+		return $this->_sid;
393
+	}
394 394
 
395 395
 
396 396
 
397
-    /**
398
-     * @param \EE_Cart $cart
399
-     * @return bool
400
-     */
401
-    public function set_cart(EE_Cart $cart)
402
-    {
403
-        $this->_session_data['cart'] = $cart;
404
-        return true;
405
-    }
406
-
407
-
408
-
409
-    /**
410
-     * reset_cart
411
-     */
412
-    public function reset_cart()
413
-    {
414
-        do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
415
-        $this->_session_data['cart'] = null;
416
-    }
417
-
418
-
419
-
420
-    /**
421
-     * @return \EE_Cart
422
-     */
423
-    public function cart()
424
-    {
425
-        return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
426
-            ? $this->_session_data['cart']
427
-            : null;
428
-    }
429
-
430
-
431
-
432
-    /**
433
-     * @param \EE_Checkout $checkout
434
-     * @return bool
435
-     */
436
-    public function set_checkout(EE_Checkout $checkout)
437
-    {
438
-        $this->_session_data['checkout'] = $checkout;
439
-        return true;
440
-    }
441
-
442
-
443
-
444
-    /**
445
-     * reset_checkout
446
-     */
447
-    public function reset_checkout()
448
-    {
449
-        do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
450
-        $this->_session_data['checkout'] = null;
451
-    }
452
-
453
-
454
-
455
-    /**
456
-     * @return \EE_Checkout
457
-     */
458
-    public function checkout()
459
-    {
460
-        return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
461
-            ? $this->_session_data['checkout']
462
-            : null;
463
-    }
464
-
465
-
466
-
467
-    /**
468
-     * @param \EE_Transaction $transaction
469
-     * @return bool
470
-     * @throws EE_Error
471
-     */
472
-    public function set_transaction(EE_Transaction $transaction)
473
-    {
474
-        // first remove the session from the transaction before we save the transaction in the session
475
-        $transaction->set_txn_session_data(null);
476
-        $this->_session_data['transaction'] = $transaction;
477
-        return true;
478
-    }
479
-
480
-
481
-
482
-    /**
483
-     * reset_transaction
484
-     */
485
-    public function reset_transaction()
486
-    {
487
-        do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
488
-        $this->_session_data['transaction'] = null;
489
-    }
490
-
491
-
492
-
493
-    /**
494
-     * @return \EE_Transaction
495
-     */
496
-    public function transaction()
497
-    {
498
-        return isset($this->_session_data['transaction'])
499
-               && $this->_session_data['transaction'] instanceof EE_Transaction
500
-            ? $this->_session_data['transaction']
501
-            : null;
502
-    }
503
-
504
-
505
-    /**
506
-     * retrieve session data
507
-     *
508
-     * @param null $key
509
-     * @param bool $reset_cache
510
-     * @return array
511
-     */
512
-    public function get_session_data($key = null, $reset_cache = false)
513
-    {
514
-        if ($reset_cache) {
515
-            $this->reset_cart();
516
-            $this->reset_checkout();
517
-            $this->reset_transaction();
518
-        }
519
-        if (! empty($key)) {
520
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
521
-        }
522
-        return $this->_session_data;
523
-    }
524
-
525
-
526
-    /**
527
-     * Returns TRUE on success, FALSE on fail
528
-     *
529
-     * @param array $data
530
-     * @return bool
531
-     */
532
-    public function set_session_data($data)
533
-    {
534
-
535
-        // nothing ??? bad data ??? go home!
536
-        if (empty($data) || ! is_array($data)) {
537
-            EE_Error::add_error(__('No session data or invalid session data was provided.', 'event_espresso'), __FILE__,
538
-                __FUNCTION__, __LINE__);
539
-            return false;
540
-        }
541
-        foreach ($data as $key => $value) {
542
-            if (isset($this->_default_session_vars[ $key ])) {
543
-                EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
544
-                    'event_espresso'), $key), __FILE__, __FUNCTION__, __LINE__);
545
-                return false;
546
-            }
547
-            $this->_session_data[ $key ] = $value;
548
-        }
549
-        return true;
550
-    }
551
-
552
-
553
-
554
-    /**
555
-     * @initiate session
556
-     * @access   private
557
-     * @return TRUE on success, FALSE on fail
558
-     * @throws EE_Error
559
-     * @throws InvalidArgumentException
560
-     * @throws InvalidDataTypeException
561
-     * @throws InvalidInterfaceException
562
-     * @throws InvalidSessionDataException
563
-     */
564
-    private function _espresso_session()
565
-    {
566
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
567
-        // check that session has started
568
-        if (session_id() === '') {
569
-            //starts a new session if one doesn't already exist, or re-initiates an existing one
570
-            session_start();
571
-        }
572
-        $this->status = EE_Session::STATUS_OPEN;
573
-        // get our modified session ID
574
-        $this->_sid = $this->_generate_session_id();
575
-        // and the visitors IP
576
-        $this->_ip_address = $this->request->ipAddress();
577
-        // set the "user agent"
578
-        $this->_user_agent = $this->request->userAgent();
579
-        // now let's retrieve what's in the db
580
-        $session_data = $this->_retrieve_session_data();
581
-        if (! empty($session_data)) {
582
-            // get the current time in UTC
583
-            $this->_time = $this->_time !== null ? $this->_time : time();
584
-            // and reset the session expiration
585
-            $this->_expiration = isset($session_data['expiration'])
586
-                ? $session_data['expiration']
587
-                : $this->_time + $this->session_lifespan->inSeconds();
588
-        } else {
589
-            // set initial site access time and the session expiration
590
-            $this->_set_init_access_and_expiration();
591
-            // set referer
592
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = isset($_SERVER['HTTP_REFERER'])
593
-                ? esc_attr($_SERVER['HTTP_REFERER'])
594
-                : '';
595
-            // no previous session = go back and create one (on top of the data above)
596
-            return false;
597
-        }
598
-        // now the user agent
599
-        if ($session_data['user_agent'] !== $this->_user_agent) {
600
-            return false;
601
-        }
602
-        // wait a minute... how old are you?
603
-        if ($this->_time > $this->_expiration) {
604
-            // yer too old fer me!
605
-            $this->_expired = true;
606
-            // wipe out everything that isn't a default session datum
607
-            $this->clear_session(__CLASS__, __FUNCTION__);
608
-        }
609
-        // make event espresso session data available to plugin
610
-        $this->_session_data = array_merge($this->_session_data, $session_data);
611
-        return true;
612
-    }
613
-
614
-
615
-
616
-    /**
617
-     * _get_session_data
618
-     * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
619
-     * databases
620
-     *
621
-     * @return array
622
-     * @throws EE_Error
623
-     * @throws InvalidArgumentException
624
-     * @throws InvalidSessionDataException
625
-     * @throws InvalidDataTypeException
626
-     * @throws InvalidInterfaceException
627
-     */
628
-    protected function _retrieve_session_data()
629
-    {
630
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
631
-        try {
632
-            // we're using WP's Transient API to store session data using the PHP session ID as the option name
633
-            $session_data = $this->cache_storage->get($ssn_key, false);
634
-            if (empty($session_data)) {
635
-                return array();
636
-            }
637
-            if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
638
-                $hash_check = $this->cache_storage->get(
639
-                    EE_Session::hash_check_prefix . $this->_sid,
640
-                    false
641
-                );
642
-                if ($hash_check && $hash_check !== md5($session_data)) {
643
-                    EE_Error::add_error(
644
-                        sprintf(
645
-                            __(
646
-                                'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
647
-                                'event_espresso'
648
-                            ),
649
-                            EE_Session::session_id_prefix . $this->_sid
650
-                        ),
651
-                        __FILE__, __FUNCTION__, __LINE__
652
-                    );
653
-                }
654
-            }
655
-        } catch (Exception $e) {
656
-            // let's just eat that error for now and attempt to correct any corrupted data
657
-            global $wpdb;
658
-            $row          = $wpdb->get_row(
659
-                $wpdb->prepare(
660
-                    "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
661
-                    '_transient_' . $ssn_key
662
-                )
663
-            );
664
-            $session_data = is_object($row) ? $row->option_value : null;
665
-            if ($session_data) {
666
-                $session_data = preg_replace_callback(
667
-                    '!s:(d+):"(.*?)";!',
668
-                    function ($match)
669
-                    {
670
-                        return $match[1] === strlen($match[2])
671
-                            ? $match[0]
672
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
673
-                    },
674
-                    $session_data
675
-                );
676
-            }
677
-            $session_data = maybe_unserialize($session_data);
678
-        }
679
-        // in case the data is encoded... try to decode it
680
-        $session_data = $this->encryption instanceof EE_Encryption
681
-            ? $this->encryption->base64_string_decode($session_data)
682
-            : $session_data;
683
-        if (! is_array($session_data)) {
684
-            try {
685
-                $session_data = maybe_unserialize($session_data);
686
-            } catch (Exception $e) {
687
-                $msg = esc_html__(
688
-                    'An error occurred while attempting to unserialize the session data.',
689
-                    'event_espresso'
690
-                );
691
-                $msg .= WP_DEBUG
692
-                    ? '<br><pre>'
693
-                      . print_r($session_data, true)
694
-                      . '</pre><br>'
695
-                      . $this->find_serialize_error($session_data)
696
-                    : '';
697
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
698
-                throw new InvalidSessionDataException($msg, 0, $e);
699
-            }
700
-        }
701
-        // just a check to make sure the session array is indeed an array
702
-        if (! is_array($session_data)) {
703
-            // no?!?! then something is wrong
704
-            $msg = esc_html__(
705
-                'The session data is missing, invalid, or corrupted.',
706
-                'event_espresso'
707
-            );
708
-            $msg .= WP_DEBUG
709
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
710
-                : '';
711
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
712
-            throw new InvalidSessionDataException($msg);
713
-        }
714
-        if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
715
-            $session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
716
-                $session_data['transaction']
717
-            );
718
-        }
719
-        return $session_data;
720
-    }
721
-
722
-
723
-
724
-    /**
725
-     * _generate_session_id
726
-     * Retrieves the PHP session id either directly from the PHP session,
727
-     * or from the $_REQUEST array if it was passed in from an AJAX request.
728
-     * The session id is then salted and hashed (mmm sounds tasty)
729
-     * so that it can be safely used as a $_REQUEST param
730
-     *
731
-     * @return string
732
-     */
733
-    protected function _generate_session_id()
734
-    {
735
-        // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
736
-        if (isset($_REQUEST['EESID'])) {
737
-            $session_id = sanitize_text_field($_REQUEST['EESID']);
738
-        } else {
739
-            $session_id = md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
740
-        }
741
-        return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
742
-    }
743
-
744
-
745
-
746
-    /**
747
-     * _get_sid_salt
748
-     *
749
-     * @return string
750
-     */
751
-    protected function _get_sid_salt()
752
-    {
753
-        // was session id salt already saved to db ?
754
-        if (empty($this->_sid_salt)) {
755
-            // no?  then maybe use WP defined constant
756
-            if (defined('AUTH_SALT')) {
757
-                $this->_sid_salt = AUTH_SALT;
758
-            }
759
-            // if salt doesn't exist or is too short
760
-            if (strlen($this->_sid_salt) < 32) {
761
-                // create a new one
762
-                $this->_sid_salt = wp_generate_password(64);
763
-            }
764
-            // and save it as a permanent session setting
765
-            $this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
766
-        }
767
-        return $this->_sid_salt;
768
-    }
769
-
770
-
771
-
772
-    /**
773
-     * _set_init_access_and_expiration
774
-     *
775
-     * @return void
776
-     */
777
-    protected function _set_init_access_and_expiration()
778
-    {
779
-        $this->_time       = time();
780
-        $this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
781
-        // set initial site access time
782
-        $this->_session_data['init_access'] = $this->_time;
783
-        // and the session expiration
784
-        $this->_session_data['expiration'] = $this->_expiration;
785
-    }
786
-
787
-
788
-
789
-    /**
790
-     * @update session data  prior to saving to the db
791
-     * @access public
792
-     * @param bool $new_session
793
-     * @return TRUE on success, FALSE on fail
794
-     * @throws EE_Error
795
-     * @throws InvalidArgumentException
796
-     * @throws InvalidDataTypeException
797
-     * @throws InvalidInterfaceException
798
-     */
799
-    public function update($new_session = false)
800
-    {
801
-        $this->_session_data = $this->_session_data !== null
802
-                               && is_array($this->_session_data)
803
-                               && isset($this->_session_data['id'])
804
-            ? $this->_session_data
805
-            : array();
806
-        if (empty($this->_session_data)) {
807
-            $this->_set_defaults();
808
-        }
809
-        $session_data = array();
810
-        foreach ($this->_session_data as $key => $value) {
811
-
812
-            switch ($key) {
813
-
814
-                case 'id' :
815
-                    // session ID
816
-                    $session_data['id'] = $this->_sid;
817
-                    break;
818
-                case 'ip_address' :
819
-                    // visitor ip address
820
-                    $session_data['ip_address'] = $this->request->ipAddress();
821
-                    break;
822
-                case 'user_agent' :
823
-                    // visitor user_agent
824
-                    $session_data['user_agent'] = $this->_user_agent;
825
-                    break;
826
-                case 'init_access' :
827
-                    $session_data['init_access'] = absint($value);
828
-                    break;
829
-                case 'last_access' :
830
-                    // current access time
831
-                    $session_data['last_access'] = $this->_time;
832
-                    break;
833
-                case 'expiration' :
834
-                    // when the session expires
835
-                    $session_data['expiration'] = ! empty($this->_expiration)
836
-                        ? $this->_expiration
837
-                        : $session_data['init_access'] + $this->session_lifespan->inSeconds();
838
-                    break;
839
-                case 'user_id' :
840
-                    // current user if logged in
841
-                    $session_data['user_id'] = $this->_wp_user_id();
842
-                    break;
843
-                case 'pages_visited' :
844
-                    $page_visit = $this->_get_page_visit();
845
-                    if ($page_visit) {
846
-                        // set pages visited where the first will be the http referrer
847
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
848
-                        // we'll only save the last 10 page visits.
849
-                        $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
850
-                    }
851
-                    break;
852
-                default :
853
-                    // carry any other data over
854
-                    $session_data[ $key ] = $this->_session_data[ $key ];
855
-            }
856
-        }
857
-        $this->_session_data = $session_data;
858
-        // creating a new session does not require saving to the db just yet
859
-        if (! $new_session) {
860
-            // ready? let's save
861
-            if ($this->_save_session_to_db()) {
862
-                return true;
863
-            }
864
-            return false;
865
-        }
866
-        // meh, why not?
867
-        return true;
868
-    }
869
-
870
-
871
-
872
-    /**
873
-     * @create session data array
874
-     * @access public
875
-     * @return bool
876
-     * @throws EE_Error
877
-     * @throws InvalidArgumentException
878
-     * @throws InvalidDataTypeException
879
-     * @throws InvalidInterfaceException
880
-     */
881
-    private function _create_espresso_session()
882
-    {
883
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
884
-        // use the update function for now with $new_session arg set to TRUE
885
-        return $this->update(true) ? true : false;
886
-    }
887
-
888
-
889
-
890
-    /**
891
-     * _save_session_to_db
892
-     *
893
-     * @param bool $clear_session
894
-     * @return string
895
-     * @throws EE_Error
896
-     * @throws InvalidArgumentException
897
-     * @throws InvalidDataTypeException
898
-     * @throws InvalidInterfaceException
899
-     */
900
-    private function _save_session_to_db($clear_session = false)
901
-    {
902
-        // don't save sessions for crawlers
903
-        // and unless we're deleting the session data, don't save anything if there isn't a cart
904
-        if ($this->request->isBot() || (! $clear_session && ! $this->cart() instanceof EE_Cart)) {
905
-            return false;
906
-        }
907
-        $transaction = $this->transaction();
908
-        if ($transaction instanceof EE_Transaction) {
909
-            if (! $transaction->ID()) {
910
-                $transaction->save();
911
-            }
912
-            $this->_session_data['transaction'] = $transaction->ID();
913
-        }
914
-        // then serialize all of our session data
915
-        $session_data = serialize($this->_session_data);
916
-        // do we need to also encode it to avoid corrupted data when saved to the db?
917
-        $session_data = $this->_use_encryption
918
-            ? $this->encryption->base64_string_encode($session_data)
919
-            : $session_data;
920
-        // maybe save hash check
921
-        if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
922
-            $this->cache_storage->add(
923
-                EE_Session::hash_check_prefix . $this->_sid,
924
-                md5($session_data),
925
-                $this->session_lifespan->inSeconds()
926
-            );
927
-        }
928
-        // we're using the Transient API for storing session data,
929
-        return $this->cache_storage->add(
930
-            EE_Session::session_id_prefix . $this->_sid,
931
-            $session_data,
932
-            $this->session_lifespan->inSeconds()
933
-        );
934
-    }
935
-
936
-
937
-    /**
938
-     * @get    the full page request the visitor is accessing
939
-     * @access public
940
-     * @return string
941
-     */
942
-    public function _get_page_visit()
943
-    {
944
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
945
-        // check for request url
946
-        if (isset($_SERVER['REQUEST_URI'])) {
947
-            $http_host   = '';
948
-            $page_id     = '?';
949
-            $e_reg       = '';
950
-            $request_uri = esc_url($_SERVER['REQUEST_URI']);
951
-            $ru_bits     = explode('?', $request_uri);
952
-            $request_uri = $ru_bits[0];
953
-            // check for and grab host as well
954
-            if (isset($_SERVER['HTTP_HOST'])) {
955
-                $http_host = esc_url($_SERVER['HTTP_HOST']);
956
-            }
957
-            // check for page_id in SERVER REQUEST
958
-            if (isset($_REQUEST['page_id'])) {
959
-                // rebuild $e_reg without any of the extra parameters
960
-                $page_id = '?page_id=' . esc_attr($_REQUEST['page_id']) . '&amp;';
961
-            }
962
-            // check for $e_reg in SERVER REQUEST
963
-            if (isset($_REQUEST['ee'])) {
964
-                // rebuild $e_reg without any of the extra parameters
965
-                $e_reg = 'ee=' . esc_attr($_REQUEST['ee']);
966
-            }
967
-            $page_visit = rtrim($http_host . $request_uri . $page_id . $e_reg, '?');
968
-        }
969
-        return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
970
-    }
971
-
972
-
973
-
974
-    /**
975
-     * @the    current wp user id
976
-     * @access public
977
-     * @return int
978
-     */
979
-    public function _wp_user_id()
980
-    {
981
-        // if I need to explain the following lines of code, then you shouldn't be looking at this!
982
-        $this->_wp_user_id = get_current_user_id();
983
-        return $this->_wp_user_id;
984
-    }
985
-
986
-
987
-
988
-    /**
989
-     * Clear EE_Session data
990
-     *
991
-     * @access public
992
-     * @param string $class
993
-     * @param string $function
994
-     * @return void
995
-     * @throws EE_Error
996
-     * @throws InvalidArgumentException
997
-     * @throws InvalidDataTypeException
998
-     * @throws InvalidInterfaceException
999
-     */
1000
-    public function clear_session($class = '', $function = '')
1001
-    {
1002
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1003
-        $this->reset_cart();
1004
-        $this->reset_checkout();
1005
-        $this->reset_transaction();
1006
-        // wipe out everything that isn't a default session datum
1007
-        $this->reset_data(array_keys($this->_session_data));
1008
-        // reset initial site access time and the session expiration
1009
-        $this->_set_init_access_and_expiration();
1010
-        $this->_save_session_to_db(true);
1011
-    }
1012
-
1013
-
1014
-    /**
1015
-     * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1016
-     *
1017
-     * @param array|mixed $data_to_reset
1018
-     * @param bool        $show_all_notices
1019
-     * @return bool
1020
-     */
1021
-    public function reset_data($data_to_reset = array(), $show_all_notices = false)
1022
-    {
1023
-        // if $data_to_reset is not in an array, then put it in one
1024
-        if (! is_array($data_to_reset)) {
1025
-            $data_to_reset = array($data_to_reset);
1026
-        }
1027
-        // nothing ??? go home!
1028
-        if (empty($data_to_reset)) {
1029
-            EE_Error::add_error(__('No session data could be reset, because no session var name was provided.',
1030
-                'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
1031
-            return false;
1032
-        }
1033
-        $return_value = true;
1034
-        // since $data_to_reset is an array, cycle through the values
1035
-        foreach ($data_to_reset as $reset) {
1036
-
1037
-            // first check to make sure it is a valid session var
1038
-            if (isset($this->_session_data[ $reset ])) {
1039
-                // then check to make sure it is not a default var
1040
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1041
-                    // remove session var
1042
-                    unset($this->_session_data[ $reset ]);
1043
-                    if ($show_all_notices) {
1044
-                        EE_Error::add_success(sprintf(__('The session variable %s was removed.', 'event_espresso'),
1045
-                            $reset), __FILE__, __FUNCTION__, __LINE__);
1046
-                    }
1047
-                } else {
1048
-                    // yeeeeeeeeerrrrrrrrrrr OUT !!!!
1049
-                    if ($show_all_notices) {
1050
-                        EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
1051
-                            'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1052
-                    }
1053
-                    $return_value = false;
1054
-                }
1055
-            } elseif ($show_all_notices) {
1056
-                // oops! that session var does not exist!
1057
-                EE_Error::add_error(sprintf(__('The session item provided, %s, is invalid or does not exist.',
1058
-                    'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1059
-                $return_value = false;
1060
-            }
1061
-        } // end of foreach
1062
-        return $return_value;
1063
-    }
1064
-
1065
-
1066
-
1067
-    /**
1068
-     *   wp_loaded
1069
-     *
1070
-     * @access public
1071
-     * @throws EE_Error
1072
-     * @throws InvalidDataTypeException
1073
-     * @throws InvalidInterfaceException
1074
-     * @throws InvalidArgumentException
1075
-     */
1076
-    public function wp_loaded()
1077
-    {
1078
-        if ($this->request->requestParamIsSet('clear_session')) {
1079
-            $this->clear_session(__CLASS__, __FUNCTION__);
1080
-        }
1081
-    }
1082
-
1083
-
1084
-
1085
-    /**
1086
-     * Used to reset the entire object (for tests).
1087
-     *
1088
-     * @since 4.3.0
1089
-     * @throws EE_Error
1090
-     * @throws InvalidDataTypeException
1091
-     * @throws InvalidInterfaceException
1092
-     * @throws InvalidArgumentException
1093
-     */
1094
-    public function reset_instance()
1095
-    {
1096
-        $this->clear_session();
1097
-        self::$_instance = null;
1098
-    }
1099
-
1100
-
1101
-
1102
-    public function configure_garbage_collection_filters()
1103
-    {
1104
-        // run old filter we had for controlling session cleanup
1105
-        $expired_session_transient_delete_query_limit = absint(
1106
-            apply_filters(
1107
-                'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1108
-                50
1109
-            )
1110
-        );
1111
-        // is there a value? or one that is different than the default 50 records?
1112
-        if ($expired_session_transient_delete_query_limit === 0) {
1113
-            // hook into TransientCacheStorage in case Session cleanup was turned off
1114
-            add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1115
-        } elseif ($expired_session_transient_delete_query_limit !== 50) {
1116
-            // or use that for the new transient cleanup query limit
1117
-            add_filter(
1118
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1119
-                function () use ($expired_session_transient_delete_query_limit)
1120
-                {
1121
-                    return $expired_session_transient_delete_query_limit;
1122
-                }
1123
-            );
1124
-        }
1125
-    }
1126
-
1127
-
1128
-
1129
-    /**
1130
-     * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1131
-     * @param $data1
1132
-     * @return string
1133
-     */
1134
-    private function find_serialize_error($data1)
1135
-    {
1136
-        $error = '<pre>';
1137
-        $data2 = preg_replace_callback(
1138
-            '!s:(\d+):"(.*?)";!',
1139
-            function ($match)
1140
-            {
1141
-                return ($match[1] === strlen($match[2]))
1142
-                    ? $match[0]
1143
-                    : 's:'
1144
-                      . strlen($match[2])
1145
-                      . ':"'
1146
-                      . $match[2]
1147
-                      . '";';
1148
-            },
1149
-            $data1
1150
-        );
1151
-        $max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1152
-        $error .= $data1 . PHP_EOL;
1153
-        $error .= $data2 . PHP_EOL;
1154
-        for ($i = 0; $i < $max; $i++) {
1155
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1156
-                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1157
-                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1158
-                $error  .= "\t-> Line Number = $i" . PHP_EOL;
1159
-                $start  = ($i - 20);
1160
-                $start  = ($start < 0) ? 0 : $start;
1161
-                $length = 40;
1162
-                $point  = $max - $i;
1163
-                if ($point < 20) {
1164
-                    $rlength = 1;
1165
-                    $rpoint  = -$point;
1166
-                } else {
1167
-                    $rpoint  = $length - 20;
1168
-                    $rlength = 1;
1169
-                }
1170
-                $error .= "\t-> Section Data1  = ";
1171
-                $error .= substr_replace(
1172
-                    substr($data1, $start, $length),
1173
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1174
-                    $rpoint,
1175
-                    $rlength
1176
-                );
1177
-                $error .= PHP_EOL;
1178
-                $error .= "\t-> Section Data2  = ";
1179
-                $error .= substr_replace(
1180
-                    substr($data2, $start, $length),
1181
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1182
-                    $rpoint,
1183
-                    $rlength
1184
-                );
1185
-                $error .= PHP_EOL;
1186
-            }
1187
-        }
1188
-        $error .= '</pre>';
1189
-        return $error;
1190
-    }
1191
-
1192
-
1193
-    /**
1194
-     * Saves an  array of settings used for configuring aspects of session behaviour
1195
-     *
1196
-     * @param array $updated_settings
1197
-     */
1198
-    private function updateSessionSettings(array $updated_settings = array())
1199
-    {
1200
-        // add existing settings, but only if not included in incoming $updated_settings array
1201
-        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1202
-        update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1203
-    }
1204
-
1205
-
1206
-    /**
1207
-     * garbage_collection
1208
-     */
1209
-    public function garbageCollection()
1210
-    {
1211
-        // only perform during regular requests if last garbage collection was over an hour ago
1212
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1213
-            $this->_last_gc = time();
1214
-            $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1215
-            /** @type WPDB $wpdb */
1216
-            global $wpdb;
1217
-            // filter the query limit. Set to 0 to turn off garbage collection
1218
-            $expired_session_transient_delete_query_limit = absint(
1219
-                apply_filters(
1220
-                    'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1221
-                    50
1222
-                )
1223
-            );
1224
-            // non-zero LIMIT means take out the trash
1225
-            if ($expired_session_transient_delete_query_limit) {
1226
-                $session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
1227
-                $hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1228
-                // since transient expiration timestamps are set in the future, we can compare against NOW
1229
-                // but we only want to pick up any trash that's been around for more than a day
1230
-                $expiration = time() - DAY_IN_SECONDS;
1231
-                $SQL        = "
397
+	/**
398
+	 * @param \EE_Cart $cart
399
+	 * @return bool
400
+	 */
401
+	public function set_cart(EE_Cart $cart)
402
+	{
403
+		$this->_session_data['cart'] = $cart;
404
+		return true;
405
+	}
406
+
407
+
408
+
409
+	/**
410
+	 * reset_cart
411
+	 */
412
+	public function reset_cart()
413
+	{
414
+		do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
415
+		$this->_session_data['cart'] = null;
416
+	}
417
+
418
+
419
+
420
+	/**
421
+	 * @return \EE_Cart
422
+	 */
423
+	public function cart()
424
+	{
425
+		return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
426
+			? $this->_session_data['cart']
427
+			: null;
428
+	}
429
+
430
+
431
+
432
+	/**
433
+	 * @param \EE_Checkout $checkout
434
+	 * @return bool
435
+	 */
436
+	public function set_checkout(EE_Checkout $checkout)
437
+	{
438
+		$this->_session_data['checkout'] = $checkout;
439
+		return true;
440
+	}
441
+
442
+
443
+
444
+	/**
445
+	 * reset_checkout
446
+	 */
447
+	public function reset_checkout()
448
+	{
449
+		do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
450
+		$this->_session_data['checkout'] = null;
451
+	}
452
+
453
+
454
+
455
+	/**
456
+	 * @return \EE_Checkout
457
+	 */
458
+	public function checkout()
459
+	{
460
+		return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
461
+			? $this->_session_data['checkout']
462
+			: null;
463
+	}
464
+
465
+
466
+
467
+	/**
468
+	 * @param \EE_Transaction $transaction
469
+	 * @return bool
470
+	 * @throws EE_Error
471
+	 */
472
+	public function set_transaction(EE_Transaction $transaction)
473
+	{
474
+		// first remove the session from the transaction before we save the transaction in the session
475
+		$transaction->set_txn_session_data(null);
476
+		$this->_session_data['transaction'] = $transaction;
477
+		return true;
478
+	}
479
+
480
+
481
+
482
+	/**
483
+	 * reset_transaction
484
+	 */
485
+	public function reset_transaction()
486
+	{
487
+		do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
488
+		$this->_session_data['transaction'] = null;
489
+	}
490
+
491
+
492
+
493
+	/**
494
+	 * @return \EE_Transaction
495
+	 */
496
+	public function transaction()
497
+	{
498
+		return isset($this->_session_data['transaction'])
499
+			   && $this->_session_data['transaction'] instanceof EE_Transaction
500
+			? $this->_session_data['transaction']
501
+			: null;
502
+	}
503
+
504
+
505
+	/**
506
+	 * retrieve session data
507
+	 *
508
+	 * @param null $key
509
+	 * @param bool $reset_cache
510
+	 * @return array
511
+	 */
512
+	public function get_session_data($key = null, $reset_cache = false)
513
+	{
514
+		if ($reset_cache) {
515
+			$this->reset_cart();
516
+			$this->reset_checkout();
517
+			$this->reset_transaction();
518
+		}
519
+		if (! empty($key)) {
520
+			return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
521
+		}
522
+		return $this->_session_data;
523
+	}
524
+
525
+
526
+	/**
527
+	 * Returns TRUE on success, FALSE on fail
528
+	 *
529
+	 * @param array $data
530
+	 * @return bool
531
+	 */
532
+	public function set_session_data($data)
533
+	{
534
+
535
+		// nothing ??? bad data ??? go home!
536
+		if (empty($data) || ! is_array($data)) {
537
+			EE_Error::add_error(__('No session data or invalid session data was provided.', 'event_espresso'), __FILE__,
538
+				__FUNCTION__, __LINE__);
539
+			return false;
540
+		}
541
+		foreach ($data as $key => $value) {
542
+			if (isset($this->_default_session_vars[ $key ])) {
543
+				EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
544
+					'event_espresso'), $key), __FILE__, __FUNCTION__, __LINE__);
545
+				return false;
546
+			}
547
+			$this->_session_data[ $key ] = $value;
548
+		}
549
+		return true;
550
+	}
551
+
552
+
553
+
554
+	/**
555
+	 * @initiate session
556
+	 * @access   private
557
+	 * @return TRUE on success, FALSE on fail
558
+	 * @throws EE_Error
559
+	 * @throws InvalidArgumentException
560
+	 * @throws InvalidDataTypeException
561
+	 * @throws InvalidInterfaceException
562
+	 * @throws InvalidSessionDataException
563
+	 */
564
+	private function _espresso_session()
565
+	{
566
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
567
+		// check that session has started
568
+		if (session_id() === '') {
569
+			//starts a new session if one doesn't already exist, or re-initiates an existing one
570
+			session_start();
571
+		}
572
+		$this->status = EE_Session::STATUS_OPEN;
573
+		// get our modified session ID
574
+		$this->_sid = $this->_generate_session_id();
575
+		// and the visitors IP
576
+		$this->_ip_address = $this->request->ipAddress();
577
+		// set the "user agent"
578
+		$this->_user_agent = $this->request->userAgent();
579
+		// now let's retrieve what's in the db
580
+		$session_data = $this->_retrieve_session_data();
581
+		if (! empty($session_data)) {
582
+			// get the current time in UTC
583
+			$this->_time = $this->_time !== null ? $this->_time : time();
584
+			// and reset the session expiration
585
+			$this->_expiration = isset($session_data['expiration'])
586
+				? $session_data['expiration']
587
+				: $this->_time + $this->session_lifespan->inSeconds();
588
+		} else {
589
+			// set initial site access time and the session expiration
590
+			$this->_set_init_access_and_expiration();
591
+			// set referer
592
+			$this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = isset($_SERVER['HTTP_REFERER'])
593
+				? esc_attr($_SERVER['HTTP_REFERER'])
594
+				: '';
595
+			// no previous session = go back and create one (on top of the data above)
596
+			return false;
597
+		}
598
+		// now the user agent
599
+		if ($session_data['user_agent'] !== $this->_user_agent) {
600
+			return false;
601
+		}
602
+		// wait a minute... how old are you?
603
+		if ($this->_time > $this->_expiration) {
604
+			// yer too old fer me!
605
+			$this->_expired = true;
606
+			// wipe out everything that isn't a default session datum
607
+			$this->clear_session(__CLASS__, __FUNCTION__);
608
+		}
609
+		// make event espresso session data available to plugin
610
+		$this->_session_data = array_merge($this->_session_data, $session_data);
611
+		return true;
612
+	}
613
+
614
+
615
+
616
+	/**
617
+	 * _get_session_data
618
+	 * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
619
+	 * databases
620
+	 *
621
+	 * @return array
622
+	 * @throws EE_Error
623
+	 * @throws InvalidArgumentException
624
+	 * @throws InvalidSessionDataException
625
+	 * @throws InvalidDataTypeException
626
+	 * @throws InvalidInterfaceException
627
+	 */
628
+	protected function _retrieve_session_data()
629
+	{
630
+		$ssn_key = EE_Session::session_id_prefix . $this->_sid;
631
+		try {
632
+			// we're using WP's Transient API to store session data using the PHP session ID as the option name
633
+			$session_data = $this->cache_storage->get($ssn_key, false);
634
+			if (empty($session_data)) {
635
+				return array();
636
+			}
637
+			if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
638
+				$hash_check = $this->cache_storage->get(
639
+					EE_Session::hash_check_prefix . $this->_sid,
640
+					false
641
+				);
642
+				if ($hash_check && $hash_check !== md5($session_data)) {
643
+					EE_Error::add_error(
644
+						sprintf(
645
+							__(
646
+								'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
647
+								'event_espresso'
648
+							),
649
+							EE_Session::session_id_prefix . $this->_sid
650
+						),
651
+						__FILE__, __FUNCTION__, __LINE__
652
+					);
653
+				}
654
+			}
655
+		} catch (Exception $e) {
656
+			// let's just eat that error for now and attempt to correct any corrupted data
657
+			global $wpdb;
658
+			$row          = $wpdb->get_row(
659
+				$wpdb->prepare(
660
+					"SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
661
+					'_transient_' . $ssn_key
662
+				)
663
+			);
664
+			$session_data = is_object($row) ? $row->option_value : null;
665
+			if ($session_data) {
666
+				$session_data = preg_replace_callback(
667
+					'!s:(d+):"(.*?)";!',
668
+					function ($match)
669
+					{
670
+						return $match[1] === strlen($match[2])
671
+							? $match[0]
672
+							: 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
673
+					},
674
+					$session_data
675
+				);
676
+			}
677
+			$session_data = maybe_unserialize($session_data);
678
+		}
679
+		// in case the data is encoded... try to decode it
680
+		$session_data = $this->encryption instanceof EE_Encryption
681
+			? $this->encryption->base64_string_decode($session_data)
682
+			: $session_data;
683
+		if (! is_array($session_data)) {
684
+			try {
685
+				$session_data = maybe_unserialize($session_data);
686
+			} catch (Exception $e) {
687
+				$msg = esc_html__(
688
+					'An error occurred while attempting to unserialize the session data.',
689
+					'event_espresso'
690
+				);
691
+				$msg .= WP_DEBUG
692
+					? '<br><pre>'
693
+					  . print_r($session_data, true)
694
+					  . '</pre><br>'
695
+					  . $this->find_serialize_error($session_data)
696
+					: '';
697
+				$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
698
+				throw new InvalidSessionDataException($msg, 0, $e);
699
+			}
700
+		}
701
+		// just a check to make sure the session array is indeed an array
702
+		if (! is_array($session_data)) {
703
+			// no?!?! then something is wrong
704
+			$msg = esc_html__(
705
+				'The session data is missing, invalid, or corrupted.',
706
+				'event_espresso'
707
+			);
708
+			$msg .= WP_DEBUG
709
+				? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
710
+				: '';
711
+			$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
712
+			throw new InvalidSessionDataException($msg);
713
+		}
714
+		if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
715
+			$session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
716
+				$session_data['transaction']
717
+			);
718
+		}
719
+		return $session_data;
720
+	}
721
+
722
+
723
+
724
+	/**
725
+	 * _generate_session_id
726
+	 * Retrieves the PHP session id either directly from the PHP session,
727
+	 * or from the $_REQUEST array if it was passed in from an AJAX request.
728
+	 * The session id is then salted and hashed (mmm sounds tasty)
729
+	 * so that it can be safely used as a $_REQUEST param
730
+	 *
731
+	 * @return string
732
+	 */
733
+	protected function _generate_session_id()
734
+	{
735
+		// check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
736
+		if (isset($_REQUEST['EESID'])) {
737
+			$session_id = sanitize_text_field($_REQUEST['EESID']);
738
+		} else {
739
+			$session_id = md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
740
+		}
741
+		return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
742
+	}
743
+
744
+
745
+
746
+	/**
747
+	 * _get_sid_salt
748
+	 *
749
+	 * @return string
750
+	 */
751
+	protected function _get_sid_salt()
752
+	{
753
+		// was session id salt already saved to db ?
754
+		if (empty($this->_sid_salt)) {
755
+			// no?  then maybe use WP defined constant
756
+			if (defined('AUTH_SALT')) {
757
+				$this->_sid_salt = AUTH_SALT;
758
+			}
759
+			// if salt doesn't exist or is too short
760
+			if (strlen($this->_sid_salt) < 32) {
761
+				// create a new one
762
+				$this->_sid_salt = wp_generate_password(64);
763
+			}
764
+			// and save it as a permanent session setting
765
+			$this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
766
+		}
767
+		return $this->_sid_salt;
768
+	}
769
+
770
+
771
+
772
+	/**
773
+	 * _set_init_access_and_expiration
774
+	 *
775
+	 * @return void
776
+	 */
777
+	protected function _set_init_access_and_expiration()
778
+	{
779
+		$this->_time       = time();
780
+		$this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
781
+		// set initial site access time
782
+		$this->_session_data['init_access'] = $this->_time;
783
+		// and the session expiration
784
+		$this->_session_data['expiration'] = $this->_expiration;
785
+	}
786
+
787
+
788
+
789
+	/**
790
+	 * @update session data  prior to saving to the db
791
+	 * @access public
792
+	 * @param bool $new_session
793
+	 * @return TRUE on success, FALSE on fail
794
+	 * @throws EE_Error
795
+	 * @throws InvalidArgumentException
796
+	 * @throws InvalidDataTypeException
797
+	 * @throws InvalidInterfaceException
798
+	 */
799
+	public function update($new_session = false)
800
+	{
801
+		$this->_session_data = $this->_session_data !== null
802
+							   && is_array($this->_session_data)
803
+							   && isset($this->_session_data['id'])
804
+			? $this->_session_data
805
+			: array();
806
+		if (empty($this->_session_data)) {
807
+			$this->_set_defaults();
808
+		}
809
+		$session_data = array();
810
+		foreach ($this->_session_data as $key => $value) {
811
+
812
+			switch ($key) {
813
+
814
+				case 'id' :
815
+					// session ID
816
+					$session_data['id'] = $this->_sid;
817
+					break;
818
+				case 'ip_address' :
819
+					// visitor ip address
820
+					$session_data['ip_address'] = $this->request->ipAddress();
821
+					break;
822
+				case 'user_agent' :
823
+					// visitor user_agent
824
+					$session_data['user_agent'] = $this->_user_agent;
825
+					break;
826
+				case 'init_access' :
827
+					$session_data['init_access'] = absint($value);
828
+					break;
829
+				case 'last_access' :
830
+					// current access time
831
+					$session_data['last_access'] = $this->_time;
832
+					break;
833
+				case 'expiration' :
834
+					// when the session expires
835
+					$session_data['expiration'] = ! empty($this->_expiration)
836
+						? $this->_expiration
837
+						: $session_data['init_access'] + $this->session_lifespan->inSeconds();
838
+					break;
839
+				case 'user_id' :
840
+					// current user if logged in
841
+					$session_data['user_id'] = $this->_wp_user_id();
842
+					break;
843
+				case 'pages_visited' :
844
+					$page_visit = $this->_get_page_visit();
845
+					if ($page_visit) {
846
+						// set pages visited where the first will be the http referrer
847
+						$this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
848
+						// we'll only save the last 10 page visits.
849
+						$session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
850
+					}
851
+					break;
852
+				default :
853
+					// carry any other data over
854
+					$session_data[ $key ] = $this->_session_data[ $key ];
855
+			}
856
+		}
857
+		$this->_session_data = $session_data;
858
+		// creating a new session does not require saving to the db just yet
859
+		if (! $new_session) {
860
+			// ready? let's save
861
+			if ($this->_save_session_to_db()) {
862
+				return true;
863
+			}
864
+			return false;
865
+		}
866
+		// meh, why not?
867
+		return true;
868
+	}
869
+
870
+
871
+
872
+	/**
873
+	 * @create session data array
874
+	 * @access public
875
+	 * @return bool
876
+	 * @throws EE_Error
877
+	 * @throws InvalidArgumentException
878
+	 * @throws InvalidDataTypeException
879
+	 * @throws InvalidInterfaceException
880
+	 */
881
+	private function _create_espresso_session()
882
+	{
883
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
884
+		// use the update function for now with $new_session arg set to TRUE
885
+		return $this->update(true) ? true : false;
886
+	}
887
+
888
+
889
+
890
+	/**
891
+	 * _save_session_to_db
892
+	 *
893
+	 * @param bool $clear_session
894
+	 * @return string
895
+	 * @throws EE_Error
896
+	 * @throws InvalidArgumentException
897
+	 * @throws InvalidDataTypeException
898
+	 * @throws InvalidInterfaceException
899
+	 */
900
+	private function _save_session_to_db($clear_session = false)
901
+	{
902
+		// don't save sessions for crawlers
903
+		// and unless we're deleting the session data, don't save anything if there isn't a cart
904
+		if ($this->request->isBot() || (! $clear_session && ! $this->cart() instanceof EE_Cart)) {
905
+			return false;
906
+		}
907
+		$transaction = $this->transaction();
908
+		if ($transaction instanceof EE_Transaction) {
909
+			if (! $transaction->ID()) {
910
+				$transaction->save();
911
+			}
912
+			$this->_session_data['transaction'] = $transaction->ID();
913
+		}
914
+		// then serialize all of our session data
915
+		$session_data = serialize($this->_session_data);
916
+		// do we need to also encode it to avoid corrupted data when saved to the db?
917
+		$session_data = $this->_use_encryption
918
+			? $this->encryption->base64_string_encode($session_data)
919
+			: $session_data;
920
+		// maybe save hash check
921
+		if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
922
+			$this->cache_storage->add(
923
+				EE_Session::hash_check_prefix . $this->_sid,
924
+				md5($session_data),
925
+				$this->session_lifespan->inSeconds()
926
+			);
927
+		}
928
+		// we're using the Transient API for storing session data,
929
+		return $this->cache_storage->add(
930
+			EE_Session::session_id_prefix . $this->_sid,
931
+			$session_data,
932
+			$this->session_lifespan->inSeconds()
933
+		);
934
+	}
935
+
936
+
937
+	/**
938
+	 * @get    the full page request the visitor is accessing
939
+	 * @access public
940
+	 * @return string
941
+	 */
942
+	public function _get_page_visit()
943
+	{
944
+		$page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
945
+		// check for request url
946
+		if (isset($_SERVER['REQUEST_URI'])) {
947
+			$http_host   = '';
948
+			$page_id     = '?';
949
+			$e_reg       = '';
950
+			$request_uri = esc_url($_SERVER['REQUEST_URI']);
951
+			$ru_bits     = explode('?', $request_uri);
952
+			$request_uri = $ru_bits[0];
953
+			// check for and grab host as well
954
+			if (isset($_SERVER['HTTP_HOST'])) {
955
+				$http_host = esc_url($_SERVER['HTTP_HOST']);
956
+			}
957
+			// check for page_id in SERVER REQUEST
958
+			if (isset($_REQUEST['page_id'])) {
959
+				// rebuild $e_reg without any of the extra parameters
960
+				$page_id = '?page_id=' . esc_attr($_REQUEST['page_id']) . '&amp;';
961
+			}
962
+			// check for $e_reg in SERVER REQUEST
963
+			if (isset($_REQUEST['ee'])) {
964
+				// rebuild $e_reg without any of the extra parameters
965
+				$e_reg = 'ee=' . esc_attr($_REQUEST['ee']);
966
+			}
967
+			$page_visit = rtrim($http_host . $request_uri . $page_id . $e_reg, '?');
968
+		}
969
+		return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
970
+	}
971
+
972
+
973
+
974
+	/**
975
+	 * @the    current wp user id
976
+	 * @access public
977
+	 * @return int
978
+	 */
979
+	public function _wp_user_id()
980
+	{
981
+		// if I need to explain the following lines of code, then you shouldn't be looking at this!
982
+		$this->_wp_user_id = get_current_user_id();
983
+		return $this->_wp_user_id;
984
+	}
985
+
986
+
987
+
988
+	/**
989
+	 * Clear EE_Session data
990
+	 *
991
+	 * @access public
992
+	 * @param string $class
993
+	 * @param string $function
994
+	 * @return void
995
+	 * @throws EE_Error
996
+	 * @throws InvalidArgumentException
997
+	 * @throws InvalidDataTypeException
998
+	 * @throws InvalidInterfaceException
999
+	 */
1000
+	public function clear_session($class = '', $function = '')
1001
+	{
1002
+		do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1003
+		$this->reset_cart();
1004
+		$this->reset_checkout();
1005
+		$this->reset_transaction();
1006
+		// wipe out everything that isn't a default session datum
1007
+		$this->reset_data(array_keys($this->_session_data));
1008
+		// reset initial site access time and the session expiration
1009
+		$this->_set_init_access_and_expiration();
1010
+		$this->_save_session_to_db(true);
1011
+	}
1012
+
1013
+
1014
+	/**
1015
+	 * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1016
+	 *
1017
+	 * @param array|mixed $data_to_reset
1018
+	 * @param bool        $show_all_notices
1019
+	 * @return bool
1020
+	 */
1021
+	public function reset_data($data_to_reset = array(), $show_all_notices = false)
1022
+	{
1023
+		// if $data_to_reset is not in an array, then put it in one
1024
+		if (! is_array($data_to_reset)) {
1025
+			$data_to_reset = array($data_to_reset);
1026
+		}
1027
+		// nothing ??? go home!
1028
+		if (empty($data_to_reset)) {
1029
+			EE_Error::add_error(__('No session data could be reset, because no session var name was provided.',
1030
+				'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
1031
+			return false;
1032
+		}
1033
+		$return_value = true;
1034
+		// since $data_to_reset is an array, cycle through the values
1035
+		foreach ($data_to_reset as $reset) {
1036
+
1037
+			// first check to make sure it is a valid session var
1038
+			if (isset($this->_session_data[ $reset ])) {
1039
+				// then check to make sure it is not a default var
1040
+				if (! array_key_exists($reset, $this->_default_session_vars)) {
1041
+					// remove session var
1042
+					unset($this->_session_data[ $reset ]);
1043
+					if ($show_all_notices) {
1044
+						EE_Error::add_success(sprintf(__('The session variable %s was removed.', 'event_espresso'),
1045
+							$reset), __FILE__, __FUNCTION__, __LINE__);
1046
+					}
1047
+				} else {
1048
+					// yeeeeeeeeerrrrrrrrrrr OUT !!!!
1049
+					if ($show_all_notices) {
1050
+						EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
1051
+							'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1052
+					}
1053
+					$return_value = false;
1054
+				}
1055
+			} elseif ($show_all_notices) {
1056
+				// oops! that session var does not exist!
1057
+				EE_Error::add_error(sprintf(__('The session item provided, %s, is invalid or does not exist.',
1058
+					'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1059
+				$return_value = false;
1060
+			}
1061
+		} // end of foreach
1062
+		return $return_value;
1063
+	}
1064
+
1065
+
1066
+
1067
+	/**
1068
+	 *   wp_loaded
1069
+	 *
1070
+	 * @access public
1071
+	 * @throws EE_Error
1072
+	 * @throws InvalidDataTypeException
1073
+	 * @throws InvalidInterfaceException
1074
+	 * @throws InvalidArgumentException
1075
+	 */
1076
+	public function wp_loaded()
1077
+	{
1078
+		if ($this->request->requestParamIsSet('clear_session')) {
1079
+			$this->clear_session(__CLASS__, __FUNCTION__);
1080
+		}
1081
+	}
1082
+
1083
+
1084
+
1085
+	/**
1086
+	 * Used to reset the entire object (for tests).
1087
+	 *
1088
+	 * @since 4.3.0
1089
+	 * @throws EE_Error
1090
+	 * @throws InvalidDataTypeException
1091
+	 * @throws InvalidInterfaceException
1092
+	 * @throws InvalidArgumentException
1093
+	 */
1094
+	public function reset_instance()
1095
+	{
1096
+		$this->clear_session();
1097
+		self::$_instance = null;
1098
+	}
1099
+
1100
+
1101
+
1102
+	public function configure_garbage_collection_filters()
1103
+	{
1104
+		// run old filter we had for controlling session cleanup
1105
+		$expired_session_transient_delete_query_limit = absint(
1106
+			apply_filters(
1107
+				'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1108
+				50
1109
+			)
1110
+		);
1111
+		// is there a value? or one that is different than the default 50 records?
1112
+		if ($expired_session_transient_delete_query_limit === 0) {
1113
+			// hook into TransientCacheStorage in case Session cleanup was turned off
1114
+			add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1115
+		} elseif ($expired_session_transient_delete_query_limit !== 50) {
1116
+			// or use that for the new transient cleanup query limit
1117
+			add_filter(
1118
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1119
+				function () use ($expired_session_transient_delete_query_limit)
1120
+				{
1121
+					return $expired_session_transient_delete_query_limit;
1122
+				}
1123
+			);
1124
+		}
1125
+	}
1126
+
1127
+
1128
+
1129
+	/**
1130
+	 * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1131
+	 * @param $data1
1132
+	 * @return string
1133
+	 */
1134
+	private function find_serialize_error($data1)
1135
+	{
1136
+		$error = '<pre>';
1137
+		$data2 = preg_replace_callback(
1138
+			'!s:(\d+):"(.*?)";!',
1139
+			function ($match)
1140
+			{
1141
+				return ($match[1] === strlen($match[2]))
1142
+					? $match[0]
1143
+					: 's:'
1144
+					  . strlen($match[2])
1145
+					  . ':"'
1146
+					  . $match[2]
1147
+					  . '";';
1148
+			},
1149
+			$data1
1150
+		);
1151
+		$max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1152
+		$error .= $data1 . PHP_EOL;
1153
+		$error .= $data2 . PHP_EOL;
1154
+		for ($i = 0; $i < $max; $i++) {
1155
+			if (@$data1[ $i ] !== @$data2[ $i ]) {
1156
+				$error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1157
+				$error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1158
+				$error  .= "\t-> Line Number = $i" . PHP_EOL;
1159
+				$start  = ($i - 20);
1160
+				$start  = ($start < 0) ? 0 : $start;
1161
+				$length = 40;
1162
+				$point  = $max - $i;
1163
+				if ($point < 20) {
1164
+					$rlength = 1;
1165
+					$rpoint  = -$point;
1166
+				} else {
1167
+					$rpoint  = $length - 20;
1168
+					$rlength = 1;
1169
+				}
1170
+				$error .= "\t-> Section Data1  = ";
1171
+				$error .= substr_replace(
1172
+					substr($data1, $start, $length),
1173
+					"<b style=\"color:green\">{$data1[ $i ]}</b>",
1174
+					$rpoint,
1175
+					$rlength
1176
+				);
1177
+				$error .= PHP_EOL;
1178
+				$error .= "\t-> Section Data2  = ";
1179
+				$error .= substr_replace(
1180
+					substr($data2, $start, $length),
1181
+					"<b style=\"color:red\">{$data2[ $i ]}</b>",
1182
+					$rpoint,
1183
+					$rlength
1184
+				);
1185
+				$error .= PHP_EOL;
1186
+			}
1187
+		}
1188
+		$error .= '</pre>';
1189
+		return $error;
1190
+	}
1191
+
1192
+
1193
+	/**
1194
+	 * Saves an  array of settings used for configuring aspects of session behaviour
1195
+	 *
1196
+	 * @param array $updated_settings
1197
+	 */
1198
+	private function updateSessionSettings(array $updated_settings = array())
1199
+	{
1200
+		// add existing settings, but only if not included in incoming $updated_settings array
1201
+		$updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1202
+		update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1203
+	}
1204
+
1205
+
1206
+	/**
1207
+	 * garbage_collection
1208
+	 */
1209
+	public function garbageCollection()
1210
+	{
1211
+		// only perform during regular requests if last garbage collection was over an hour ago
1212
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1213
+			$this->_last_gc = time();
1214
+			$this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1215
+			/** @type WPDB $wpdb */
1216
+			global $wpdb;
1217
+			// filter the query limit. Set to 0 to turn off garbage collection
1218
+			$expired_session_transient_delete_query_limit = absint(
1219
+				apply_filters(
1220
+					'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1221
+					50
1222
+				)
1223
+			);
1224
+			// non-zero LIMIT means take out the trash
1225
+			if ($expired_session_transient_delete_query_limit) {
1226
+				$session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
1227
+				$hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1228
+				// since transient expiration timestamps are set in the future, we can compare against NOW
1229
+				// but we only want to pick up any trash that's been around for more than a day
1230
+				$expiration = time() - DAY_IN_SECONDS;
1231
+				$SQL        = "
1232 1232
                     SELECT option_name
1233 1233
                     FROM {$wpdb->options}
1234 1234
                     WHERE
@@ -1237,19 +1237,19 @@  discard block
 block discarded – undo
1237 1237
                     AND option_value < {$expiration}
1238 1238
                     LIMIT {$expired_session_transient_delete_query_limit}
1239 1239
                 ";
1240
-                // produces something like:
1241
-                // SELECT option_name FROM wp_options
1242
-                // WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1243
-                // OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1244
-                // AND option_value < 1508368198 LIMIT 50
1245
-                $expired_sessions = $wpdb->get_col($SQL);
1246
-                // valid results?
1247
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1248
-                    $this->cache_storage->deleteMany($expired_sessions, true);
1249
-                }
1250
-            }
1251
-        }
1252
-    }
1240
+				// produces something like:
1241
+				// SELECT option_name FROM wp_options
1242
+				// WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1243
+				// OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1244
+				// AND option_value < 1508368198 LIMIT 50
1245
+				$expired_sessions = $wpdb->get_col($SQL);
1246
+				// valid results?
1247
+				if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1248
+					$this->cache_storage->deleteMany($expired_sessions, true);
1249
+				}
1250
+			}
1251
+		}
1252
+	}
1253 1253
 
1254 1254
 
1255 1255
 
Please login to merge, or discard this patch.
Spacing   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
         // check if class object is instantiated
187 187
         // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
188 188
         // add_filter( 'FHEE_load_EE_Session', '__return_false' );
189
-        if (! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
189
+        if ( ! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
190 190
             self::$_instance = new self(
191 191
                 $cache_storage,
192 192
                 $lifespan,
@@ -219,21 +219,21 @@  discard block
 block discarded – undo
219 219
         // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
220 220
         // (which currently fires on the init hook at priority 9),
221 221
         // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
222
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
222
+        if ( ! apply_filters('FHEE_load_EE_Session', true)) {
223 223
             return;
224 224
         }
225 225
         $this->session_lifespan = $lifespan;
226 226
         $this->request          = $request;
227
-        if (! defined('ESPRESSO_SESSION')) {
227
+        if ( ! defined('ESPRESSO_SESSION')) {
228 228
             define('ESPRESSO_SESSION', true);
229 229
         }
230 230
         // retrieve session options from db
231 231
         $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
232
-        if (! empty($session_settings)) {
232
+        if ( ! empty($session_settings)) {
233 233
             // cycle though existing session options
234 234
             foreach ($session_settings as $var_name => $session_setting) {
235 235
                 // set values for class properties
236
-                $var_name          = '_' . $var_name;
236
+                $var_name          = '_'.$var_name;
237 237
                 $this->{$var_name} = $session_setting;
238 238
             }
239 239
         }
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
     public function open_session()
295 295
     {
296 296
         // check for existing session and retrieve it from db
297
-        if (! $this->_espresso_session()) {
297
+        if ( ! $this->_espresso_session()) {
298 298
             // or just start a new one
299 299
             $this->_create_espresso_session();
300 300
         }
@@ -346,7 +346,7 @@  discard block
 block discarded – undo
346 346
      */
347 347
     public function extend_expiration($time = 0)
348 348
     {
349
-        $time              = $time ? $time : $this->extension();
349
+        $time = $time ? $time : $this->extension();
350 350
         $this->_expiration += absint($time);
351 351
     }
352 352
 
@@ -373,9 +373,9 @@  discard block
 block discarded – undo
373 373
         // set some defaults
374 374
         foreach ($this->_default_session_vars as $key => $default_var) {
375 375
             if (is_array($default_var)) {
376
-                $this->_session_data[ $key ] = array();
376
+                $this->_session_data[$key] = array();
377 377
             } else {
378
-                $this->_session_data[ $key ] = '';
378
+                $this->_session_data[$key] = '';
379 379
             }
380 380
         }
381 381
     }
@@ -516,8 +516,8 @@  discard block
 block discarded – undo
516 516
             $this->reset_checkout();
517 517
             $this->reset_transaction();
518 518
         }
519
-        if (! empty($key)) {
520
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
519
+        if ( ! empty($key)) {
520
+            return isset($this->_session_data[$key]) ? $this->_session_data[$key] : null;
521 521
         }
522 522
         return $this->_session_data;
523 523
     }
@@ -539,12 +539,12 @@  discard block
 block discarded – undo
539 539
             return false;
540 540
         }
541 541
         foreach ($data as $key => $value) {
542
-            if (isset($this->_default_session_vars[ $key ])) {
542
+            if (isset($this->_default_session_vars[$key])) {
543 543
                 EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
544 544
                     'event_espresso'), $key), __FILE__, __FUNCTION__, __LINE__);
545 545
                 return false;
546 546
             }
547
-            $this->_session_data[ $key ] = $value;
547
+            $this->_session_data[$key] = $value;
548 548
         }
549 549
         return true;
550 550
     }
@@ -578,7 +578,7 @@  discard block
 block discarded – undo
578 578
         $this->_user_agent = $this->request->userAgent();
579 579
         // now let's retrieve what's in the db
580 580
         $session_data = $this->_retrieve_session_data();
581
-        if (! empty($session_data)) {
581
+        if ( ! empty($session_data)) {
582 582
             // get the current time in UTC
583 583
             $this->_time = $this->_time !== null ? $this->_time : time();
584 584
             // and reset the session expiration
@@ -589,7 +589,7 @@  discard block
 block discarded – undo
589 589
             // set initial site access time and the session expiration
590 590
             $this->_set_init_access_and_expiration();
591 591
             // set referer
592
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = isset($_SERVER['HTTP_REFERER'])
592
+            $this->_session_data['pages_visited'][$this->_session_data['init_access']] = isset($_SERVER['HTTP_REFERER'])
593 593
                 ? esc_attr($_SERVER['HTTP_REFERER'])
594 594
                 : '';
595 595
             // no previous session = go back and create one (on top of the data above)
@@ -627,7 +627,7 @@  discard block
 block discarded – undo
627 627
      */
628 628
     protected function _retrieve_session_data()
629 629
     {
630
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
630
+        $ssn_key = EE_Session::session_id_prefix.$this->_sid;
631 631
         try {
632 632
             // we're using WP's Transient API to store session data using the PHP session ID as the option name
633 633
             $session_data = $this->cache_storage->get($ssn_key, false);
@@ -636,7 +636,7 @@  discard block
 block discarded – undo
636 636
             }
637 637
             if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
638 638
                 $hash_check = $this->cache_storage->get(
639
-                    EE_Session::hash_check_prefix . $this->_sid,
639
+                    EE_Session::hash_check_prefix.$this->_sid,
640 640
                     false
641 641
                 );
642 642
                 if ($hash_check && $hash_check !== md5($session_data)) {
@@ -646,7 +646,7 @@  discard block
 block discarded – undo
646 646
                                 'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
647 647
                                 'event_espresso'
648 648
                             ),
649
-                            EE_Session::session_id_prefix . $this->_sid
649
+                            EE_Session::session_id_prefix.$this->_sid
650 650
                         ),
651 651
                         __FILE__, __FUNCTION__, __LINE__
652 652
                     );
@@ -655,21 +655,21 @@  discard block
 block discarded – undo
655 655
         } catch (Exception $e) {
656 656
             // let's just eat that error for now and attempt to correct any corrupted data
657 657
             global $wpdb;
658
-            $row          = $wpdb->get_row(
658
+            $row = $wpdb->get_row(
659 659
                 $wpdb->prepare(
660 660
                     "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
661
-                    '_transient_' . $ssn_key
661
+                    '_transient_'.$ssn_key
662 662
                 )
663 663
             );
664 664
             $session_data = is_object($row) ? $row->option_value : null;
665 665
             if ($session_data) {
666 666
                 $session_data = preg_replace_callback(
667 667
                     '!s:(d+):"(.*?)";!',
668
-                    function ($match)
668
+                    function($match)
669 669
                     {
670 670
                         return $match[1] === strlen($match[2])
671 671
                             ? $match[0]
672
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
672
+                            : 's:'.strlen($match[2]).':"'.$match[2].'";';
673 673
                     },
674 674
                     $session_data
675 675
                 );
@@ -680,7 +680,7 @@  discard block
 block discarded – undo
680 680
         $session_data = $this->encryption instanceof EE_Encryption
681 681
             ? $this->encryption->base64_string_decode($session_data)
682 682
             : $session_data;
683
-        if (! is_array($session_data)) {
683
+        if ( ! is_array($session_data)) {
684 684
             try {
685 685
                 $session_data = maybe_unserialize($session_data);
686 686
             } catch (Exception $e) {
@@ -694,21 +694,21 @@  discard block
 block discarded – undo
694 694
                       . '</pre><br>'
695 695
                       . $this->find_serialize_error($session_data)
696 696
                     : '';
697
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
697
+                $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
698 698
                 throw new InvalidSessionDataException($msg, 0, $e);
699 699
             }
700 700
         }
701 701
         // just a check to make sure the session array is indeed an array
702
-        if (! is_array($session_data)) {
702
+        if ( ! is_array($session_data)) {
703 703
             // no?!?! then something is wrong
704 704
             $msg = esc_html__(
705 705
                 'The session data is missing, invalid, or corrupted.',
706 706
                 'event_espresso'
707 707
             );
708 708
             $msg .= WP_DEBUG
709
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
709
+                ? '<br><pre>'.print_r($session_data, true).'</pre><br>'.$this->find_serialize_error($session_data)
710 710
                 : '';
711
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
711
+            $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
712 712
             throw new InvalidSessionDataException($msg);
713 713
         }
714 714
         if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
@@ -736,7 +736,7 @@  discard block
 block discarded – undo
736 736
         if (isset($_REQUEST['EESID'])) {
737 737
             $session_id = sanitize_text_field($_REQUEST['EESID']);
738 738
         } else {
739
-            $session_id = md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
739
+            $session_id = md5(session_id().get_current_blog_id().$this->_get_sid_salt());
740 740
         }
741 741
         return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
742 742
     }
@@ -844,19 +844,19 @@  discard block
 block discarded – undo
844 844
                     $page_visit = $this->_get_page_visit();
845 845
                     if ($page_visit) {
846 846
                         // set pages visited where the first will be the http referrer
847
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
847
+                        $this->_session_data['pages_visited'][$this->_time] = $page_visit;
848 848
                         // we'll only save the last 10 page visits.
849 849
                         $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
850 850
                     }
851 851
                     break;
852 852
                 default :
853 853
                     // carry any other data over
854
-                    $session_data[ $key ] = $this->_session_data[ $key ];
854
+                    $session_data[$key] = $this->_session_data[$key];
855 855
             }
856 856
         }
857 857
         $this->_session_data = $session_data;
858 858
         // creating a new session does not require saving to the db just yet
859
-        if (! $new_session) {
859
+        if ( ! $new_session) {
860 860
             // ready? let's save
861 861
             if ($this->_save_session_to_db()) {
862 862
                 return true;
@@ -901,12 +901,12 @@  discard block
 block discarded – undo
901 901
     {
902 902
         // don't save sessions for crawlers
903 903
         // and unless we're deleting the session data, don't save anything if there isn't a cart
904
-        if ($this->request->isBot() || (! $clear_session && ! $this->cart() instanceof EE_Cart)) {
904
+        if ($this->request->isBot() || ( ! $clear_session && ! $this->cart() instanceof EE_Cart)) {
905 905
             return false;
906 906
         }
907 907
         $transaction = $this->transaction();
908 908
         if ($transaction instanceof EE_Transaction) {
909
-            if (! $transaction->ID()) {
909
+            if ( ! $transaction->ID()) {
910 910
                 $transaction->save();
911 911
             }
912 912
             $this->_session_data['transaction'] = $transaction->ID();
@@ -920,14 +920,14 @@  discard block
 block discarded – undo
920 920
         // maybe save hash check
921 921
         if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
922 922
             $this->cache_storage->add(
923
-                EE_Session::hash_check_prefix . $this->_sid,
923
+                EE_Session::hash_check_prefix.$this->_sid,
924 924
                 md5($session_data),
925 925
                 $this->session_lifespan->inSeconds()
926 926
             );
927 927
         }
928 928
         // we're using the Transient API for storing session data,
929 929
         return $this->cache_storage->add(
930
-            EE_Session::session_id_prefix . $this->_sid,
930
+            EE_Session::session_id_prefix.$this->_sid,
931 931
             $session_data,
932 932
             $this->session_lifespan->inSeconds()
933 933
         );
@@ -941,7 +941,7 @@  discard block
 block discarded – undo
941 941
      */
942 942
     public function _get_page_visit()
943 943
     {
944
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
944
+        $page_visit = home_url('/').'wp-admin/admin-ajax.php';
945 945
         // check for request url
946 946
         if (isset($_SERVER['REQUEST_URI'])) {
947 947
             $http_host   = '';
@@ -957,14 +957,14 @@  discard block
 block discarded – undo
957 957
             // check for page_id in SERVER REQUEST
958 958
             if (isset($_REQUEST['page_id'])) {
959 959
                 // rebuild $e_reg without any of the extra parameters
960
-                $page_id = '?page_id=' . esc_attr($_REQUEST['page_id']) . '&amp;';
960
+                $page_id = '?page_id='.esc_attr($_REQUEST['page_id']).'&amp;';
961 961
             }
962 962
             // check for $e_reg in SERVER REQUEST
963 963
             if (isset($_REQUEST['ee'])) {
964 964
                 // rebuild $e_reg without any of the extra parameters
965
-                $e_reg = 'ee=' . esc_attr($_REQUEST['ee']);
965
+                $e_reg = 'ee='.esc_attr($_REQUEST['ee']);
966 966
             }
967
-            $page_visit = rtrim($http_host . $request_uri . $page_id . $e_reg, '?');
967
+            $page_visit = rtrim($http_host.$request_uri.$page_id.$e_reg, '?');
968 968
         }
969 969
         return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
970 970
     }
@@ -999,7 +999,7 @@  discard block
 block discarded – undo
999 999
      */
1000 1000
     public function clear_session($class = '', $function = '')
1001 1001
     {
1002
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1002
+        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : '.$class.'::'.$function.'()');
1003 1003
         $this->reset_cart();
1004 1004
         $this->reset_checkout();
1005 1005
         $this->reset_transaction();
@@ -1021,7 +1021,7 @@  discard block
 block discarded – undo
1021 1021
     public function reset_data($data_to_reset = array(), $show_all_notices = false)
1022 1022
     {
1023 1023
         // if $data_to_reset is not in an array, then put it in one
1024
-        if (! is_array($data_to_reset)) {
1024
+        if ( ! is_array($data_to_reset)) {
1025 1025
             $data_to_reset = array($data_to_reset);
1026 1026
         }
1027 1027
         // nothing ??? go home!
@@ -1035,11 +1035,11 @@  discard block
 block discarded – undo
1035 1035
         foreach ($data_to_reset as $reset) {
1036 1036
 
1037 1037
             // first check to make sure it is a valid session var
1038
-            if (isset($this->_session_data[ $reset ])) {
1038
+            if (isset($this->_session_data[$reset])) {
1039 1039
                 // then check to make sure it is not a default var
1040
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1040
+                if ( ! array_key_exists($reset, $this->_default_session_vars)) {
1041 1041
                     // remove session var
1042
-                    unset($this->_session_data[ $reset ]);
1042
+                    unset($this->_session_data[$reset]);
1043 1043
                     if ($show_all_notices) {
1044 1044
                         EE_Error::add_success(sprintf(__('The session variable %s was removed.', 'event_espresso'),
1045 1045
                             $reset), __FILE__, __FUNCTION__, __LINE__);
@@ -1116,7 +1116,7 @@  discard block
 block discarded – undo
1116 1116
             // or use that for the new transient cleanup query limit
1117 1117
             add_filter(
1118 1118
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1119
-                function () use ($expired_session_transient_delete_query_limit)
1119
+                function() use ($expired_session_transient_delete_query_limit)
1120 1120
                 {
1121 1121
                     return $expired_session_transient_delete_query_limit;
1122 1122
                 }
@@ -1136,7 +1136,7 @@  discard block
 block discarded – undo
1136 1136
         $error = '<pre>';
1137 1137
         $data2 = preg_replace_callback(
1138 1138
             '!s:(\d+):"(.*?)";!',
1139
-            function ($match)
1139
+            function($match)
1140 1140
             {
1141 1141
                 return ($match[1] === strlen($match[2]))
1142 1142
                     ? $match[0]
@@ -1148,14 +1148,14 @@  discard block
 block discarded – undo
1148 1148
             },
1149 1149
             $data1
1150 1150
         );
1151
-        $max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1152
-        $error .= $data1 . PHP_EOL;
1153
-        $error .= $data2 . PHP_EOL;
1151
+        $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1152
+        $error .= $data1.PHP_EOL;
1153
+        $error .= $data2.PHP_EOL;
1154 1154
         for ($i = 0; $i < $max; $i++) {
1155
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1156
-                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1157
-                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1158
-                $error  .= "\t-> Line Number = $i" . PHP_EOL;
1155
+            if (@$data1[$i] !== @$data2[$i]) {
1156
+                $error  .= 'Difference '.@$data1[$i].' != '.@$data2[$i].PHP_EOL;
1157
+                $error  .= "\t-> ORD number ".ord(@$data1[$i]).' != '.ord(@$data2[$i]).PHP_EOL;
1158
+                $error  .= "\t-> Line Number = $i".PHP_EOL;
1159 1159
                 $start  = ($i - 20);
1160 1160
                 $start  = ($start < 0) ? 0 : $start;
1161 1161
                 $length = 40;
@@ -1170,7 +1170,7 @@  discard block
 block discarded – undo
1170 1170
                 $error .= "\t-> Section Data1  = ";
1171 1171
                 $error .= substr_replace(
1172 1172
                     substr($data1, $start, $length),
1173
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1173
+                    "<b style=\"color:green\">{$data1[$i]}</b>",
1174 1174
                     $rpoint,
1175 1175
                     $rlength
1176 1176
                 );
@@ -1178,7 +1178,7 @@  discard block
 block discarded – undo
1178 1178
                 $error .= "\t-> Section Data2  = ";
1179 1179
                 $error .= substr_replace(
1180 1180
                     substr($data2, $start, $length),
1181
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1181
+                    "<b style=\"color:red\">{$data2[$i]}</b>",
1182 1182
                     $rpoint,
1183 1183
                     $rlength
1184 1184
                 );
@@ -1209,7 +1209,7 @@  discard block
 block discarded – undo
1209 1209
     public function garbageCollection()
1210 1210
     {
1211 1211
         // only perform during regular requests if last garbage collection was over an hour ago
1212
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1212
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1213 1213
             $this->_last_gc = time();
1214 1214
             $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1215 1215
             /** @type WPDB $wpdb */
@@ -1244,7 +1244,7 @@  discard block
 block discarded – undo
1244 1244
                 // AND option_value < 1508368198 LIMIT 50
1245 1245
                 $expired_sessions = $wpdb->get_col($SQL);
1246 1246
                 // valid results?
1247
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1247
+                if ( ! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1248 1248
                     $this->cache_storage->deleteMany($expired_sessions, true);
1249 1249
                 }
1250 1250
             }
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/forms/SettingsForm.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -115,14 +115,14 @@  discard block
 block discarded – undo
115 115
     public function _validate()
116 116
     {
117 117
         parent::_validate();
118
-        if (! $this->_payment_method_type instanceof \EE_PMT_Paypal_Express) {
118
+        if ( ! $this->_payment_method_type instanceof \EE_PMT_Paypal_Express) {
119 119
             throw new EntityNotFoundException('EE_PMT_Paypal_Express', '$this->_payment_method_type');
120 120
         }
121
-        if (! $this->_payment_method_type->get_gateway() instanceof \EEG_Paypal_Express) {
121
+        if ( ! $this->_payment_method_type->get_gateway() instanceof \EEG_Paypal_Express) {
122 122
             throw new EntityNotFoundException('EEG_Paypal_Express', '$this->_payment_method_type->get_gateway()');
123 123
         }
124 124
         $credentials_message = $this->checkForCredentialsErrors();
125
-        if( $credentials_message !== '') {
125
+        if ($credentials_message !== '') {
126 126
             $this->add_validation_error($credentials_message);
127 127
             $this->get_input('PMD_debug_mode')->add_validation_error(
128 128
                 esc_html__('If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".', 'event_espresso')
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
      * Gets the HTML to show the link to the help tab
155 155
      * @return string
156 156
      */
157
-    protected function helpTabLink(){
157
+    protected function helpTabLink() {
158 158
         return $this->helpTabLink;
159 159
     }
160 160
     /**
Please login to merge, or discard this patch.
Indentation   +196 added lines, -196 removed lines patch added patch discarded remove patch
@@ -24,210 +24,210 @@
 block discarded – undo
24 24
 class SettingsForm extends EE_Payment_Method_Form
25 25
 {
26 26
 
27
-    /**
28
-     * @var string of HTML being the help tab link
29
-     */
30
-    protected $helpTabLink;
27
+	/**
28
+	 * @var string of HTML being the help tab link
29
+	 */
30
+	protected $helpTabLink;
31 31
 
32
-    /**
33
-     * SettingsForm constructor.
34
-     *
35
-     * @param array $options_array
36
-     * @param string     $help_tab_link
37
-     */
38
-    public function __construct(array $options_array = array(), $help_tab_link)
39
-    {
40
-        $this->helpTabLink = $help_tab_link;
41
-        $options_array = array_replace_recursive(
42
-            array(
43
-                'extra_meta_inputs' => array(
44
-                    'api_username' => new EE_Text_Input(
45
-                        array(
46
-                            'html_label_text' => sprintf(
47
-                                esc_html__('API Username %s', 'event_espresso'),
48
-                                $help_tab_link
49
-                            ),
50
-                            'required'        => true,
51
-                        )
52
-                    ),
53
-                    'api_password' => new EE_Text_Input(
54
-                        array(
55
-                            'html_label_text' => sprintf(
56
-                                esc_html__('API Password %s', 'event_espresso'),
57
-                                $help_tab_link
58
-                            ),
59
-                            'required'        => true,
60
-                        )
61
-                    ),
62
-                    'api_signature' => new EE_Text_Input(
63
-                        array(
64
-                            'html_label_text' => sprintf(
65
-                                esc_html__('API Signature %s', 'event_espresso'),
66
-                                $help_tab_link
67
-                            ),
68
-                            'required'        => true,
69
-                        )
70
-                    ),
71
-                    'request_shipping_addr' => new EE_Yes_No_Input(
72
-                        array(
73
-                            'html_label_text' => sprintf(
74
-                                esc_html__('Request Shipping Address %s', 'event_espresso'),
75
-                                $help_tab_link
76
-                            ),
77
-                            'html_help_text'  => esc_html__(
78
-                            // @codingStandardsIgnoreStart
79
-                                'If set to "Yes", then a shipping address will be requested on the PayPal checkout page.',
80
-                                // @codingStandardsIgnoreEnd
81
-                                'event_espresso'
82
-                            ),
83
-                            'required'        => true,
84
-                            'default'         => false,
85
-                        )
86
-                    ),
87
-                    'image_url' => new EE_Admin_File_Uploader_Input(
88
-                        array(
89
-                            'html_label_text' => sprintf(
90
-                                esc_html__('Image URL %s', 'event_espresso'),
91
-                                $help_tab_link
92
-                            ),
93
-                            'html_help_text'  => esc_html__(
94
-                                'Used for your business/personal logo on the PayPal page',
95
-                                'event_espresso'
96
-                            ),
97
-                            'required'        => false,
98
-                        )
99
-                    ),
100
-                )
101
-            ),
102
-            $options_array
103
-        );
104
-        parent::__construct($options_array);
105
-    }
32
+	/**
33
+	 * SettingsForm constructor.
34
+	 *
35
+	 * @param array $options_array
36
+	 * @param string     $help_tab_link
37
+	 */
38
+	public function __construct(array $options_array = array(), $help_tab_link)
39
+	{
40
+		$this->helpTabLink = $help_tab_link;
41
+		$options_array = array_replace_recursive(
42
+			array(
43
+				'extra_meta_inputs' => array(
44
+					'api_username' => new EE_Text_Input(
45
+						array(
46
+							'html_label_text' => sprintf(
47
+								esc_html__('API Username %s', 'event_espresso'),
48
+								$help_tab_link
49
+							),
50
+							'required'        => true,
51
+						)
52
+					),
53
+					'api_password' => new EE_Text_Input(
54
+						array(
55
+							'html_label_text' => sprintf(
56
+								esc_html__('API Password %s', 'event_espresso'),
57
+								$help_tab_link
58
+							),
59
+							'required'        => true,
60
+						)
61
+					),
62
+					'api_signature' => new EE_Text_Input(
63
+						array(
64
+							'html_label_text' => sprintf(
65
+								esc_html__('API Signature %s', 'event_espresso'),
66
+								$help_tab_link
67
+							),
68
+							'required'        => true,
69
+						)
70
+					),
71
+					'request_shipping_addr' => new EE_Yes_No_Input(
72
+						array(
73
+							'html_label_text' => sprintf(
74
+								esc_html__('Request Shipping Address %s', 'event_espresso'),
75
+								$help_tab_link
76
+							),
77
+							'html_help_text'  => esc_html__(
78
+							// @codingStandardsIgnoreStart
79
+								'If set to "Yes", then a shipping address will be requested on the PayPal checkout page.',
80
+								// @codingStandardsIgnoreEnd
81
+								'event_espresso'
82
+							),
83
+							'required'        => true,
84
+							'default'         => false,
85
+						)
86
+					),
87
+					'image_url' => new EE_Admin_File_Uploader_Input(
88
+						array(
89
+							'html_label_text' => sprintf(
90
+								esc_html__('Image URL %s', 'event_espresso'),
91
+								$help_tab_link
92
+							),
93
+							'html_help_text'  => esc_html__(
94
+								'Used for your business/personal logo on the PayPal page',
95
+								'event_espresso'
96
+							),
97
+							'required'        => false,
98
+						)
99
+					),
100
+				)
101
+			),
102
+			$options_array
103
+		);
104
+		parent::__construct($options_array);
105
+	}
106 106
 
107 107
 
108 108
 
109
-    /**
110
-     * Does the normal validation, but also verifies the PayPal API credentials work.
111
-     * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more tips)
112
-     * on each of the inputs that could be the cause of the problem.
113
-     * @throws EntityNotFoundException
114
-     */
115
-    public function _validate()
116
-    {
117
-        parent::_validate();
118
-        if (! $this->_payment_method_type instanceof \EE_PMT_Paypal_Express) {
119
-            throw new EntityNotFoundException('EE_PMT_Paypal_Express', '$this->_payment_method_type');
120
-        }
121
-        if (! $this->_payment_method_type->get_gateway() instanceof \EEG_Paypal_Express) {
122
-            throw new EntityNotFoundException('EEG_Paypal_Express', '$this->_payment_method_type->get_gateway()');
123
-        }
124
-        $credentials_message = $this->checkForCredentialsErrors();
125
-        if( $credentials_message !== '') {
126
-            $this->add_validation_error($credentials_message);
127
-            $this->get_input('PMD_debug_mode')->add_validation_error(
128
-                esc_html__('If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".', 'event_espresso')
129
-            );
130
-            $this->get_input('api_username')->add_validation_error(
131
-                sprintf(
132
-                    esc_html__('Are you sure this is your API username, not your login username?%1$s', 'event_espresso'),
133
-                    $this->helpTabLink()
134
-                )
135
-            );
136
-            $this->get_input('api_password')->add_validation_error(
137
-                sprintf(
138
-                    esc_html__('Are you sure this is your API password, not your login password.%1$s', 'event_espresso'),
139
-                    $this->helpTabLink()
140
-                )
141
-            );
142
-            $this->get_input('api_signature')->add_validation_error(
143
-                sprintf(
144
-                    esc_html__('Please verify your API signature is correct.%1$s', 'event_espresso'),
145
-                    $this->helpTabLink()
146
-                )
147
-            );
148
-        }
149
-    }
109
+	/**
110
+	 * Does the normal validation, but also verifies the PayPal API credentials work.
111
+	 * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more tips)
112
+	 * on each of the inputs that could be the cause of the problem.
113
+	 * @throws EntityNotFoundException
114
+	 */
115
+	public function _validate()
116
+	{
117
+		parent::_validate();
118
+		if (! $this->_payment_method_type instanceof \EE_PMT_Paypal_Express) {
119
+			throw new EntityNotFoundException('EE_PMT_Paypal_Express', '$this->_payment_method_type');
120
+		}
121
+		if (! $this->_payment_method_type->get_gateway() instanceof \EEG_Paypal_Express) {
122
+			throw new EntityNotFoundException('EEG_Paypal_Express', '$this->_payment_method_type->get_gateway()');
123
+		}
124
+		$credentials_message = $this->checkForCredentialsErrors();
125
+		if( $credentials_message !== '') {
126
+			$this->add_validation_error($credentials_message);
127
+			$this->get_input('PMD_debug_mode')->add_validation_error(
128
+				esc_html__('If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".', 'event_espresso')
129
+			);
130
+			$this->get_input('api_username')->add_validation_error(
131
+				sprintf(
132
+					esc_html__('Are you sure this is your API username, not your login username?%1$s', 'event_espresso'),
133
+					$this->helpTabLink()
134
+				)
135
+			);
136
+			$this->get_input('api_password')->add_validation_error(
137
+				sprintf(
138
+					esc_html__('Are you sure this is your API password, not your login password.%1$s', 'event_espresso'),
139
+					$this->helpTabLink()
140
+				)
141
+			);
142
+			$this->get_input('api_signature')->add_validation_error(
143
+				sprintf(
144
+					esc_html__('Please verify your API signature is correct.%1$s', 'event_espresso'),
145
+					$this->helpTabLink()
146
+				)
147
+			);
148
+		}
149
+	}
150 150
 
151 151
 
152 152
 
153
-    /**
154
-     * Gets the HTML to show the link to the help tab
155
-     * @return string
156
-     */
157
-    protected function helpTabLink(){
158
-        return $this->helpTabLink;
159
-    }
160
-    /**
161
-     * Tests the the PayPal API credentials work ok
162
-     * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string
163
-     */
164
-    protected function checkForCredentialsErrors()
165
-    {
166
-        $request_params = array(
167
-            'METHOD'    => 'GetBalance',
168
-            'VERSION'   => '204.0',
169
-            'USER'      => urlencode($this->get_input_value('api_username')),
170
-            'PWD'       => urlencode($this->get_input_value('api_password')),
171
-            'SIGNATURE' => urlencode($this->get_input_value('api_signature')),
172
-        );
173
-        $gateway_url = $this->get_input_value('PMD_debug_mode')
174
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
175
-            : 'https://api-3t.paypal.com/nvp';
176
-        // Request Customer Details.
177
-        $response = wp_remote_post(
178
-            $gateway_url,
179
-            array(
180
-                'method'      => 'POST',
181
-                'timeout'     => 45,
182
-                'httpversion' => '1.1',
183
-                'cookies'     => array(),
184
-                'headers'     => array(),
185
-                'body'        => http_build_query($request_params, '', '&'),
186
-            )
187
-        );
188
-        if (is_wp_error($response) || empty($response['body'])) {
189
-            // If we got here then there was an error in this request.
190
-            //maybe is turned off. We don't know the credentials are invalid
191
-            EE_Error::add_error(
192
-                sprintf(
193
-                    esc_html__('Your PayPal credentials could not be verified. There was an error communicating with PayPal, it was %1$s', 'event_espresso'),
194
-                    $response->get_error_message()
195
-                ),
196
-                __FILE__,
197
-                __FUNCTION__,
198
-                __LINE__
199
-            );
200
-        }
201
-        $response_args = array();
202
-        parse_str(urldecode($response['body']), $response_args);
153
+	/**
154
+	 * Gets the HTML to show the link to the help tab
155
+	 * @return string
156
+	 */
157
+	protected function helpTabLink(){
158
+		return $this->helpTabLink;
159
+	}
160
+	/**
161
+	 * Tests the the PayPal API credentials work ok
162
+	 * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string
163
+	 */
164
+	protected function checkForCredentialsErrors()
165
+	{
166
+		$request_params = array(
167
+			'METHOD'    => 'GetBalance',
168
+			'VERSION'   => '204.0',
169
+			'USER'      => urlencode($this->get_input_value('api_username')),
170
+			'PWD'       => urlencode($this->get_input_value('api_password')),
171
+			'SIGNATURE' => urlencode($this->get_input_value('api_signature')),
172
+		);
173
+		$gateway_url = $this->get_input_value('PMD_debug_mode')
174
+			? 'https://api-3t.sandbox.paypal.com/nvp'
175
+			: 'https://api-3t.paypal.com/nvp';
176
+		// Request Customer Details.
177
+		$response = wp_remote_post(
178
+			$gateway_url,
179
+			array(
180
+				'method'      => 'POST',
181
+				'timeout'     => 45,
182
+				'httpversion' => '1.1',
183
+				'cookies'     => array(),
184
+				'headers'     => array(),
185
+				'body'        => http_build_query($request_params, '', '&'),
186
+			)
187
+		);
188
+		if (is_wp_error($response) || empty($response['body'])) {
189
+			// If we got here then there was an error in this request.
190
+			//maybe is turned off. We don't know the credentials are invalid
191
+			EE_Error::add_error(
192
+				sprintf(
193
+					esc_html__('Your PayPal credentials could not be verified. There was an error communicating with PayPal, it was %1$s', 'event_espresso'),
194
+					$response->get_error_message()
195
+				),
196
+				__FILE__,
197
+				__FUNCTION__,
198
+				__LINE__
199
+			);
200
+		}
201
+		$response_args = array();
202
+		parse_str(urldecode($response['body']), $response_args);
203 203
 
204
-        if (empty($response_args['ACK'])) {
205
-            EE_Error::add_error(
206
-                esc_html__('Your PayPal credentials could not be verified. Part of their response was missing.', 'event_espresso'),
207
-                __FILE__,
208
-                __FUNCTION__,
209
-                __LINE__
210
-            );
211
-        }
212
-        if (
213
-        in_array(
214
-            $response_args['ACK'],
215
-            array(
216
-                'Success',
217
-                'SuccessWithWarning'
218
-            ),
219
-            true
220
-        )
221
-        ) {
222
-            return '';
223
-        } else {
224
-            return sprintf(
225
-                esc_html__('Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.', 'event_espresso'),
226
-                    isset($response_args['L_LONGMESSAGE0']) ? $response_args['L_LONGMESSAGE0'] : esc_html__('No error message received from PayPal', 'event_espresso'),
227
-                isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0
228
-            );
229
-        }
230
-    }
204
+		if (empty($response_args['ACK'])) {
205
+			EE_Error::add_error(
206
+				esc_html__('Your PayPal credentials could not be verified. Part of their response was missing.', 'event_espresso'),
207
+				__FILE__,
208
+				__FUNCTION__,
209
+				__LINE__
210
+			);
211
+		}
212
+		if (
213
+		in_array(
214
+			$response_args['ACK'],
215
+			array(
216
+				'Success',
217
+				'SuccessWithWarning'
218
+			),
219
+			true
220
+		)
221
+		) {
222
+			return '';
223
+		} else {
224
+			return sprintf(
225
+				esc_html__('Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.', 'event_espresso'),
226
+					isset($response_args['L_LONGMESSAGE0']) ? $response_args['L_LONGMESSAGE0'] : esc_html__('No error message received from PayPal', 'event_espresso'),
227
+				isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0
228
+			);
229
+		}
230
+	}
231 231
 }
232 232
 // End of file SettingsForm.php
233 233
 // Location: EventEspresso\payment_methods\Paypal_Express\forms/SettingsForm.php
234 234
\ No newline at end of file
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/EE_PMT_Paypal_Express.pm.php 2 patches
Indentation   +78 added lines, -78 removed lines patch added patch discarded remove patch
@@ -3,7 +3,7 @@  discard block
 block discarded – undo
3 3
 use EventEspresso\payment_methods\Paypal_Express\forms\SettingsForm;
4 4
 
5 5
 if (! defined('EVENT_ESPRESSO_VERSION')) {
6
-    exit('NO direct script access allowed');
6
+	exit('NO direct script access allowed');
7 7
 }
8 8
 
9 9
 
@@ -21,91 +21,91 @@  discard block
 block discarded – undo
21 21
 class EE_PMT_Paypal_Express extends EE_PMT_Base
22 22
 {
23 23
 
24
-    /**
25
-     * EE_PMT_Paypal_Express constructor.
26
-     */
27
-    public function __construct($pm_instance = null)
28
-    {
29
-        require_once($this->file_folder() . 'EEG_Paypal_Express.gateway.php');
30
-        $this->_gateway = new EEG_Paypal_Express();
24
+	/**
25
+	 * EE_PMT_Paypal_Express constructor.
26
+	 */
27
+	public function __construct($pm_instance = null)
28
+	{
29
+		require_once($this->file_folder() . 'EEG_Paypal_Express.gateway.php');
30
+		$this->_gateway = new EEG_Paypal_Express();
31 31
 
32
-        $this->_pretty_name = esc_html__('PayPal Express', 'event_espresso');
33
-        $this->_template_path = $this->file_folder() . 'templates' . DS;
34
-        $this->_default_description = esc_html__(
35
-            // @codingStandardsIgnoreStart
36
-            'After clicking \'Finalize Registration\', you will be forwarded to PayPal website to Login and make your payment.',
37
-            // @codingStandardsIgnoreEnd
38
-            'event_espresso'
39
-        );
40
-        $this->_default_button_url = $this->file_url() . 'lib' . DS . 'paypal-express-checkout-logo-gold-160.png';
32
+		$this->_pretty_name = esc_html__('PayPal Express', 'event_espresso');
33
+		$this->_template_path = $this->file_folder() . 'templates' . DS;
34
+		$this->_default_description = esc_html__(
35
+			// @codingStandardsIgnoreStart
36
+			'After clicking \'Finalize Registration\', you will be forwarded to PayPal website to Login and make your payment.',
37
+			// @codingStandardsIgnoreEnd
38
+			'event_espresso'
39
+		);
40
+		$this->_default_button_url = $this->file_url() . 'lib' . DS . 'paypal-express-checkout-logo-gold-160.png';
41 41
 
42
-        parent::__construct($pm_instance);
43
-    }
42
+		parent::__construct($pm_instance);
43
+	}
44 44
 
45 45
 
46
-    /**
47
-     * Adds the help tab.
48
-     *
49
-     * @see EE_PMT_Base::help_tabs_config()
50
-     * @return array
51
-     */
52
-    public function help_tabs_config()
53
-    {
54
-        return array(
55
-            $this->get_help_tab_name() => array(
56
-                'title'    => esc_html__('PayPal Express Settings', 'event_espresso'),
57
-                'filename' => 'payment_methods_overview_paypal_express'
58
-            )
59
-        );
60
-    }
46
+	/**
47
+	 * Adds the help tab.
48
+	 *
49
+	 * @see EE_PMT_Base::help_tabs_config()
50
+	 * @return array
51
+	 */
52
+	public function help_tabs_config()
53
+	{
54
+		return array(
55
+			$this->get_help_tab_name() => array(
56
+				'title'    => esc_html__('PayPal Express Settings', 'event_espresso'),
57
+				'filename' => 'payment_methods_overview_paypal_express'
58
+			)
59
+		);
60
+	}
61 61
 
62 62
 
63
-    /**
64
-     * Gets the form for all the settings related to this payment method type.
65
-     *
66
-     * @return EE_Payment_Method_Form
67
-     */
68
-    public function generate_new_settings_form()
69
-    {
70
-        $form = new SettingsForm(array(), $this->get_help_tab_link());
71
-        return $form;
72
-    }
63
+	/**
64
+	 * Gets the form for all the settings related to this payment method type.
65
+	 *
66
+	 * @return EE_Payment_Method_Form
67
+	 */
68
+	public function generate_new_settings_form()
69
+	{
70
+		$form = new SettingsForm(array(), $this->get_help_tab_link());
71
+		return $form;
72
+	}
73 73
 
74 74
 
75
-    /**
76
-     * Creates a billing form for this payment method type.
77
-     *
78
-     * @param \EE_Transaction $transaction
79
-     * @return \EE_Billing_Info_Form
80
-     */
81
-    public function generate_new_billing_form(EE_Transaction $transaction = null)
82
-    {
83
-        if ($this->_pm_instance->debug_mode()) {
84
-            $form = new EE_Billing_Info_Form(
85
-                $this->_pm_instance,
86
-                array(
87
-                    'name' => 'paypal_express_Info_Form',
88
-                    'subsections' => array(
89
-                        'paypal_express_debug_info' => new EE_Form_Section_Proper(
90
-                            array(
91
-                                'layout_strategy' => new EE_Template_Layout(
92
-                                    array(
93
-                                        'layout_template_file' => $this->_template_path
94
-                                                                    . 'paypal_express_debug_info.template.php',
95
-                                        'template_args'        => array(
96
-                                            'debug_mode' => $this->_pm_instance->debug_mode()
97
-                                        )
98
-                                    )
99
-                                )
100
-                            )
101
-                        )
102
-                    )
103
-                )
104
-            );
105
-            return $form;
106
-        }
75
+	/**
76
+	 * Creates a billing form for this payment method type.
77
+	 *
78
+	 * @param \EE_Transaction $transaction
79
+	 * @return \EE_Billing_Info_Form
80
+	 */
81
+	public function generate_new_billing_form(EE_Transaction $transaction = null)
82
+	{
83
+		if ($this->_pm_instance->debug_mode()) {
84
+			$form = new EE_Billing_Info_Form(
85
+				$this->_pm_instance,
86
+				array(
87
+					'name' => 'paypal_express_Info_Form',
88
+					'subsections' => array(
89
+						'paypal_express_debug_info' => new EE_Form_Section_Proper(
90
+							array(
91
+								'layout_strategy' => new EE_Template_Layout(
92
+									array(
93
+										'layout_template_file' => $this->_template_path
94
+																	. 'paypal_express_debug_info.template.php',
95
+										'template_args'        => array(
96
+											'debug_mode' => $this->_pm_instance->debug_mode()
97
+										)
98
+									)
99
+								)
100
+							)
101
+						)
102
+					)
103
+				)
104
+			);
105
+			return $form;
106
+		}
107 107
 
108
-        return false;
109
-    }
108
+		return false;
109
+	}
110 110
 }
111 111
 // End of file EE_PMT_Paypal_Express.pm.php
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@  discard block
 block discarded – undo
2 2
 
3 3
 use EventEspresso\payment_methods\Paypal_Express\forms\SettingsForm;
4 4
 
5
-if (! defined('EVENT_ESPRESSO_VERSION')) {
5
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
6 6
     exit('NO direct script access allowed');
7 7
 }
8 8
 
@@ -26,18 +26,18 @@  discard block
 block discarded – undo
26 26
      */
27 27
     public function __construct($pm_instance = null)
28 28
     {
29
-        require_once($this->file_folder() . 'EEG_Paypal_Express.gateway.php');
29
+        require_once($this->file_folder().'EEG_Paypal_Express.gateway.php');
30 30
         $this->_gateway = new EEG_Paypal_Express();
31 31
 
32 32
         $this->_pretty_name = esc_html__('PayPal Express', 'event_espresso');
33
-        $this->_template_path = $this->file_folder() . 'templates' . DS;
33
+        $this->_template_path = $this->file_folder().'templates'.DS;
34 34
         $this->_default_description = esc_html__(
35 35
             // @codingStandardsIgnoreStart
36 36
             'After clicking \'Finalize Registration\', you will be forwarded to PayPal website to Login and make your payment.',
37 37
             // @codingStandardsIgnoreEnd
38 38
             'event_espresso'
39 39
         );
40
-        $this->_default_button_url = $this->file_url() . 'lib' . DS . 'paypal-express-checkout-logo-gold-160.png';
40
+        $this->_default_button_url = $this->file_url().'lib'.DS.'paypal-express-checkout-logo-gold-160.png';
41 41
 
42 42
         parent::__construct($pm_instance);
43 43
     }
Please login to merge, or discard this patch.
core/libraries/payment_methods/EE_PMT_Base.lib.php 1 patch
Indentation   +722 added lines, -722 removed lines patch added patch discarded remove patch
@@ -21,728 +21,728 @@
 block discarded – undo
21 21
 abstract class EE_PMT_Base
22 22
 {
23 23
 
24
-    const onsite = 'on-site';
25
-    const offsite = 'off-site';
26
-    const offline = 'off-line';
27
-
28
-    /**
29
-     * @var EE_Payment_Method
30
-     */
31
-    protected $_pm_instance = NULL;
32
-
33
-    /**
34
-     * @var boolean
35
-     */
36
-    protected $_requires_https = FALSE;
37
-
38
-    /**
39
-     * @var boolean
40
-     */
41
-    protected $_has_billing_form;
42
-
43
-    /**
44
-     * @var EE_Gateway
45
-     */
46
-    protected $_gateway = NULL;
47
-
48
-    /**
49
-     * @var EE_Payment_Method_Form
50
-     */
51
-    protected $_settings_form = NULL;
52
-
53
-    /**
54
-     * @var EE_Form_Section_Proper
55
-     */
56
-    protected $_billing_form = NULL;
57
-
58
-    /**
59
-     * @var boolean
60
-     */
61
-    protected $_cache_billing_form = TRUE;
62
-
63
-    /**
64
-     * String of the absolute path to the folder containing this file, with a trailing slash.
65
-     * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
66
-     * @var string
67
-     */
68
-    protected $_file_folder = NULL;
69
-
70
-    /**
71
-     * String to the absolute URL to this file (useful for getting its web-accessible resources
72
-     * like images, js, or css)
73
-     * @var string
74
-     */
75
-    protected $_file_url = NULL;
76
-
77
-    /**
78
-     * Pretty name for the payment method
79
-     * @var string
80
-     */
81
-    protected $_pretty_name = NULL;
82
-
83
-    /**
84
-     *
85
-     * @var string
86
-     */
87
-    protected $_default_button_url = NULL;
88
-
89
-    /**
90
-     *
91
-     * @var string
92
-     */
93
-    protected $_default_description = NULL;
94
-
95
-
96
-    /**
97
-     *
98
-     * @param EE_Payment_Method $pm_instance
99
-     * @throws EE_Error
100
-     * @return EE_PMT_Base
101
-     */
102
-    function __construct($pm_instance = NULL)
103
-    {
104
-        if ($pm_instance instanceof EE_Payment_Method) {
105
-            $this->set_instance($pm_instance);
106
-        }
107
-        if ($this->_gateway) {
108
-            $this->_gateway->set_payment_model(EEM_Payment::instance());
109
-            $this->_gateway->set_payment_log(EEM_Change_Log::instance());
110
-            $this->_gateway->set_template_helper(new EEH_Template());
111
-            $this->_gateway->set_line_item_helper(new EEH_Line_Item());
112
-            $this->_gateway->set_money_helper(new EEH_Money());
113
-            $this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter());
114
-            $this->_gateway->set_unsupported_character_remover(new AsciiOnly());
115
-            do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
116
-        }
117
-        if (!isset($this->_has_billing_form)) {
118
-            // by default, On Site gateways have a billing form
119
-            if ($this->payment_occurs() == EE_PMT_Base::onsite) {
120
-                $this->set_has_billing_form(true);
121
-            } else {
122
-                $this->set_has_billing_form(false);
123
-            }
124
-        }
125
-
126
-        if (!$this->_pretty_name) {
127
-            throw new EE_Error(sprintf(__("You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", "event_espresso")));
128
-        }
129
-        //if the child didn't specify a default button, use the credit card one
130
-        if ($this->_default_button_url === NULL) {
131
-            $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods' . DS . 'pay-by-credit-card.png';
132
-        }
133
-    }
134
-
135
-
136
-    /**
137
-     * @param boolean $has_billing_form
138
-     */
139
-    public function set_has_billing_form($has_billing_form)
140
-    {
141
-        $this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN);
142
-    }
143
-
144
-
145
-    /**
146
-     * sets the file_folder property
147
-     */
148
-    protected function _set_file_folder()
149
-    {
150
-        $reflector = new ReflectionClass(get_class($this));
151
-        $fn = $reflector->getFileName();
152
-        $this->_file_folder = dirname($fn) . DS;
153
-    }
154
-
155
-
156
-    /**
157
-     * sets the file URL with a trailing slash for this PMT
158
-     */
159
-    protected function _set_file_url()
160
-    {
161
-        $plugins_dir_fixed = str_replace('\\', DS, WP_PLUGIN_DIR);
162
-        $file_folder_fixed = str_replace('\\', DS, $this->file_folder());
163
-        $file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed);
164
-        $this->_file_url = $file_path;
165
-    }
166
-
167
-    /**
168
-     * Gets the default description on all payment methods of this type
169
-     * @return string
170
-     */
171
-    public function default_description()
172
-    {
173
-        return $this->_default_description;
174
-    }
175
-
176
-
177
-    /**
178
-     * Returns the folder containing the PMT child class, with a trailing slash
179
-     * @return string
180
-     */
181
-    public function file_folder()
182
-    {
183
-        if (!$this->_file_folder) {
184
-            $this->_set_file_folder();
185
-        }
186
-        return $this->_file_folder;
187
-    }
188
-
189
-
190
-    /**
191
-     * @return string
192
-     */
193
-    public function file_url()
194
-    {
195
-        if (!$this->_file_url) {
196
-            $this->_set_file_url();
197
-        }
198
-        return $this->_file_url;
199
-    }
200
-
201
-
202
-    /**
203
-     * Sets the payment method instance this payment method type is for.
204
-     * Its important teh payment method instance is set before
205
-     * @param EE_Payment_Method $payment_method_instance
206
-     */
207
-    function set_instance($payment_method_instance)
208
-    {
209
-        $this->_pm_instance = $payment_method_instance;
210
-        //if they have already requested the settings form, make sure its
211
-        //data matches this model object
212
-        if ($this->_settings_form) {
213
-            $this->settings_form()->populate_model_obj($payment_method_instance);
214
-        }
215
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
216
-            $this->_gateway->set_settings($payment_method_instance->settings_array());
217
-        }
218
-    }
219
-
220
-
221
-    /**
222
-     * Gets teh form for displaying to admins where they setup the payment method
223
-     * @return EE_Payment_Method_Form
224
-     */
225
-    function settings_form()
226
-    {
227
-        if (!$this->_settings_form) {
228
-            $this->_settings_form = $this->generate_new_settings_form();
229
-            $this->_settings_form->set_payment_method_type($this);
230
-            //if we have already assigned a model object to this pmt, make
231
-            //sure its reflected in teh form we just generated
232
-            if ($this->_pm_instance) {
233
-                $this->_settings_form->populate_model_obj($this->_pm_instance);
234
-            }
235
-        }
236
-        return $this->_settings_form;
237
-    }
238
-
239
-
240
-    /**
241
-     * Gets the form for all the settings related to this payment method type
242
-     * @return EE_Payment_Method_Form
243
-     */
244
-    abstract function generate_new_settings_form();
245
-
246
-
247
-    /**
248
-     * Sets the form for settings. This may be useful if we have already received
249
-     * a form submission and have form data it in, and want to use it anytime we're showing
250
-     * this payment method type's settings form later in the request
251
-     * @param EE_Payment_Method_Form $form
252
-     */
253
-    public function set_settings_form($form)
254
-    {
255
-        $this->_settings_form = $form;
256
-    }
257
-
258
-
259
-    /**
260
-     * @return boolean
261
-     */
262
-    public function has_billing_form()
263
-    {
264
-        return $this->_has_billing_form;
265
-    }
266
-
267
-
268
-    /**
269
-     * Gets the form for displaying to attendees where they can enter their billing info
270
-     * which will be sent to teh gateway (can be null)
271
-     *
272
-     * @param \EE_Transaction $transaction
273
-     * @param array $extra_args
274
-     * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null
275
-     */
276
-    public function billing_form(EE_Transaction $transaction = NULL, $extra_args = array())
277
-    {
278
-        // has billing form already been regenerated ? or overwrite cache?
279
-        if (!$this->_billing_form instanceof EE_Billing_Info_Form || !$this->_cache_billing_form) {
280
-            $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
281
-        }
282
-        //if we know who the attendee is, and this is a billing form
283
-        //that uses attendee info, populate it
284
-        if (
285
-        apply_filters(
286
-            'FHEE__populate_billing_form_fields_from_attendee',
287
-            (
288
-                $this->_billing_form instanceof EE_Billing_Attendee_Info_Form
289
-                && $transaction instanceof EE_Transaction
290
-                && $transaction->primary_registration() instanceof EE_Registration
291
-                && $transaction->primary_registration()->attendee() instanceof EE_Attendee
292
-            ),
293
-            $this->_billing_form,
294
-            $transaction
295
-        )
296
-        ) {
297
-            $this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee());
298
-        }
299
-        return $this->_billing_form;
300
-    }
301
-
302
-
303
-    /**
304
-     * Creates the billing form for this payment method type
305
-     * @param \EE_Transaction $transaction
306
-     * @return \EE_Billing_Info_Form
307
-     */
308
-    abstract function generate_new_billing_form(EE_Transaction $transaction = NULL);
309
-
310
-
311
-    /**
312
-     * apply_billing_form_debug_settings
313
-     * applies debug data to the form
314
-     *
315
-     * @param \EE_Billing_Info_Form $billing_form
316
-     * @return \EE_Billing_Info_Form
317
-     */
318
-    public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
319
-    {
320
-        return $billing_form;
321
-    }
322
-
323
-
324
-    /**
325
-     * Sets the billing form for this payment method type. You may want to use this
326
-     * if you have form
327
-     * @param EE_Payment_Method $form
328
-     */
329
-    public function set_billing_form($form)
330
-    {
331
-        $this->_billing_form = $form;
332
-    }
333
-
334
-
335
-    /**
336
-     * Returns whether or not this payment method requires HTTPS to be used
337
-     * @return boolean
338
-     */
339
-    function requires_https()
340
-    {
341
-        return $this->_requires_https;
342
-    }
343
-
344
-
345
-    /**
346
-     *
347
-     * @param EE_Transaction $transaction
348
-     * @param float $amount
349
-     * @param EE_Billing_Info_Form $billing_info
350
-     * @param string $return_url
351
-     * @param string $fail_url
352
-     * @param string $method
353
-     * @param bool $by_admin
354
-     * @return EE_Payment
355
-     * @throws EE_Error
356
-     */
357
-    function process_payment(EE_Transaction $transaction, $amount = null, $billing_info = null, $return_url = null, $fail_url = '', $method = 'CART', $by_admin = false)
358
-    {
359
-        // @todo: add surcharge for the payment method, if any
360
-        if ($this->_gateway) {
361
-            //there is a gateway, so we're going to make a payment object
362
-            //but wait! do they already have a payment in progress that we thought was failed?
363
-            $duplicate_properties = array(
364
-                'STS_ID' => EEM_Payment::status_id_failed,
365
-                'TXN_ID' => $transaction->ID(),
366
-                'PMD_ID' => $this->_pm_instance->ID(),
367
-                'PAY_source' => $method,
368
-                'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(),
369
-                'PAY_gateway_response' => null,
370
-            );
371
-            $payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
372
-            //if we didn't already have a payment in progress for the same thing,
373
-            //then we actually want to make a new payment
374
-            if (!$payment instanceof EE_Payment) {
375
-                $payment = EE_Payment::new_instance(
376
-                    array_merge(
377
-                        $duplicate_properties,
378
-                        array(
379
-                            'PAY_timestamp' => time(),
380
-                            'PAY_txn_id_chq_nmbr' => null,
381
-                            'PAY_po_number' => null,
382
-                            'PAY_extra_accntng' => null,
383
-                            'PAY_details' => null,
384
-                        )
385
-                    )
386
-                );
387
-            }
388
-            //make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
389
-            $payment->save();
390
-            $billing_values = $this->_get_billing_values_from_form($billing_info);
391
-
392
-            //  Offsite Gateway
393
-            if ($this->_gateway instanceof EE_Offsite_Gateway) {
394
-
395
-                $payment = $this->_gateway->set_redirection_info(
396
-                    $payment,
397
-                    $billing_values,
398
-                    $return_url,
399
-                    EE_Config::instance()->core->txn_page_url(
400
-                        array(
401
-                            'e_reg_url_link' => $transaction->primary_registration()->reg_url_link(),
402
-                            'ee_payment_method' => $this->_pm_instance->slug()
403
-                        )
404
-                    ),
405
-                    $fail_url
406
-                );
407
-                $payment->save();
408
-                //  Onsite Gateway
409
-            } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
410
-
411
-                $payment = $this->_gateway->do_direct_payment($payment, $billing_values);
412
-                $payment->save();
413
-
414
-            } else {
415
-                throw new EE_Error(
416
-                    sprintf(
417
-                        __('Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', 'event_espresso'),
418
-                        get_class($this),
419
-                        gettype($this->_gateway)
420
-                    )
421
-                );
422
-            }
423
-
424
-        } else {
425
-            // no gateway provided
426
-            // there is no payment. Must be an offline gateway
427
-            // create a payment object anyways, but dont save it
428
-            $payment = EE_Payment::new_instance(
429
-                array(
430
-                    'STS_ID' => EEM_Payment::status_id_pending,
431
-                    'TXN_ID' => $transaction->ID(),
432
-                    'PMD_ID' => $transaction->payment_method_ID(),
433
-                    'PAY_amount' => 0.00,
434
-                    'PAY_timestamp' => time(),
435
-                )
436
-            );
437
-
438
-        }
439
-
440
-        // if there is billing info, clean it and save it now
441
-        if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
442
-            $this->_save_billing_info_to_attendee($billing_info, $transaction);
443
-        }
444
-
445
-        return $payment;
446
-    }
447
-
448
-    /**
449
-     * Gets the values we want to pass onto the gateway. Normally these
450
-     * are just the 'pretty' values, but there may be times the data may need
451
-     * a  little massaging. Proper subsections will become arrays of inputs
452
-     * @param EE_Billing_Info_Form $billing_form
453
-     * @return array
454
-     */
455
-    protected function _get_billing_values_from_form($billing_form)
456
-    {
457
-        if ($billing_form instanceof EE_Form_Section_Proper) {
458
-            return $billing_form->input_pretty_values(true);
459
-        } else {
460
-            return NULL;
461
-        }
462
-    }
463
-
464
-
465
-    /**
466
-     * Handles an instant payment notification when the transaction is known (by default).
467
-     * @param array $req_data
468
-     * @param EE_Transaction $transaction
469
-     * @return EE_Payment
470
-     * @throws EE_Error
471
-     */
472
-    public function handle_ipn($req_data, $transaction)
473
-    {
474
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
475
-        if (!$this->_gateway instanceof EE_Offsite_Gateway) {
476
-            throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE)));
477
-
478
-        }
479
-        $payment = $this->_gateway->handle_payment_update($req_data, $transaction);
480
-        return $payment;
481
-    }
482
-
483
-
484
-    /**
485
-     * Saves the billing info onto the attendee of the primary registrant on this transaction, and
486
-     * cleans it first.
487
-     * @param EE_Billing_Attendee_Info_Form $billing_form
488
-     * @param EE_Transaction $transaction
489
-     * @return boolean success
490
-     */
491
-    protected function _save_billing_info_to_attendee($billing_form, $transaction)
492
-    {
493
-        if (!$transaction || !$transaction instanceof EE_Transaction) {
494
-            EE_Error::add_error(__("Cannot save billing info because no transaction was specified", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
495
-            return false;
496
-        }
497
-        $primary_reg = $transaction->primary_registration();
498
-        if (!$primary_reg) {
499
-            EE_Error::add_error(__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
500
-            return false;
501
-        }
502
-        $attendee = $primary_reg->attendee();
503
-        if (!$attendee) {
504
-            EE_Error::add_error(__("Cannot save billing info because the transaction's primary registration has no attendee!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
505
-            return false;
506
-        }
507
-        return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method());
508
-
509
-    }
510
-
511
-
512
-    /**
513
-     * Gets the payment this IPN is for. Children may often want to
514
-     * override this to inspect the request
515
-     * @param EE_Transaction $transaction
516
-     * @param array $req_data
517
-     * @return EE_Payment
518
-     */
519
-    protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array())
520
-    {
521
-        return $transaction->last_payment();
522
-    }
523
-
524
-
525
-    /**
526
-     * In case generic code cannot provide the payment processor with a specific payment method
527
-     * and transaction, it will try calling this method on each activate payment method.
528
-     * If the payment method is able to identify the request as being for it, it should fetch
529
-     * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
530
-     * handle the IPN
531
-     * @param array $req_data
532
-     * @return EE_Payment only if this payment method can find the info its needs from $req_data
533
-     * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
534
-     * @throws EE_Error
535
-     */
536
-    public function handle_unclaimed_ipn($req_data = array())
537
-    {
538
-        throw new EE_Error(sprintf(__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this)));
539
-    }
540
-
541
-
542
-    /**
543
-     * Logic to be accomplished when the payment attempt is complete.
544
-     * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
545
-     * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
546
-     * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
547
-     * of the payment). Fed a transaction because it's always assumed to be the last payment that
548
-     * we're dealing with. Returns that last payment (if there is one)
549
-     *
550
-     * @param EE_Transaction $transaction
551
-     * @return EE_Payment
552
-     */
553
-    public function finalize_payment_for($transaction)
554
-    {
555
-        return $transaction->last_payment();
556
-    }
557
-
558
-
559
-    /**
560
-     * Whether or not this payment method's gateway supports sending refund requests
561
-     * @return boolean
562
-     */
563
-    public function supports_sending_refunds()
564
-    {
565
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
566
-            return $this->_gateway->supports_sending_refunds();
567
-        } else {
568
-            return false;
569
-        }
570
-    }
571
-
572
-
573
-    /**
574
-     *
575
-     * @param EE_Payment $payment
576
-     * @param array $refund_info
577
-     * @throws EE_Error
578
-     * @return EE_Payment
579
-     */
580
-    public function process_refund(EE_Payment $payment, $refund_info = array())
581
-    {
582
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
583
-            return $this->_gateway->do_direct_refund($payment, $refund_info);
584
-        } else {
585
-            throw new EE_Error(
586
-                sprintf(
587
-                    __('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'),
588
-                    get_class($this)
589
-                )
590
-            );
591
-        }
592
-    }
593
-
594
-
595
-    /**
596
-     * Returns one the class's constants onsite,offsite, or offline, depending on this
597
-     * payment method's gateway.
598
-     * @return string
599
-     * @throws EE_Error
600
-     */
601
-    public function payment_occurs()
602
-    {
603
-        if (!$this->_gateway) {
604
-            return EE_PMT_Base::offline;
605
-        } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
606
-            return EE_PMT_Base::onsite;
607
-        } elseif ($this->_gateway instanceof EE_Offsite_Gateway) {
608
-            return EE_PMT_Base::offsite;
609
-        } else {
610
-            throw new EE_Error(sprintf(__("Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", "event_espresso"), get_class($this)));
611
-        }
612
-    }
613
-
614
-
615
-    /**
616
-     * For adding any html output ab ove the payment overview.
617
-     * Many gateways won't want ot display anything, so this function just returns an empty string.
618
-     * Other gateways may want to override this, such as offline gateways.
619
-     * @param EE_Payment $payment
620
-     * @return string
621
-     */
622
-    public function payment_overview_content(EE_Payment $payment)
623
-    {
624
-        return EEH_Template::display_template(EE_LIBRARIES . 'payment_methods' . DS . 'templates' . DS . 'payment_details_content.template.php', array('payment_method' => $this->_pm_instance, 'payment' => $payment), true);
625
-    }
626
-
627
-
628
-    /**
629
-     * @return array where keys are the help tab name,
630
-     * values are: array {
631
-     * @type string $title i18n name for the help tab
632
-     * @type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file)
633
-     * @type array $template_args any arguments you want passed to the template file while rendering.
634
-     *                Keys will be variable names and values with be their values.
635
-     */
636
-    public function help_tabs_config()
637
-    {
638
-        return array();
639
-    }
640
-
641
-
642
-    /**
643
-     * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
644
-     * the payment method's table's PMT_type column)
645
-     * @return string
646
-     */
647
-    public function system_name()
648
-    {
649
-        $classname = get_class($this);
650
-        return str_replace("EE_PMT_", '', $classname);
651
-    }
652
-
653
-
654
-    /**
655
-     * A pretty i18n version of the PMT name
656
-     * @return string
657
-     */
658
-    public function pretty_name()
659
-    {
660
-        return $this->_pretty_name;
661
-    }
662
-
663
-
664
-    /**
665
-     * Gets the default absolute URL to the payment method type's button
666
-     * @return string
667
-     */
668
-    public function default_button_url()
669
-    {
670
-        return $this->_default_button_url;
671
-    }
672
-
673
-
674
-    /**
675
-     * Gets the gateway used by this payment method (if any)
676
-     * @return EE_Gateway
677
-     */
678
-    public function get_gateway()
679
-    {
680
-        return $this->_gateway;
681
-    }
682
-
683
-
684
-    /**
685
-     * @return string html for the link to a help tab
686
-     */
687
-    public function get_help_tab_link()
688
-    {
689
-        return EEH_Template::get_help_tab_link(
690
-            $this->get_help_tab_name(),
691
-            'espresso_payment_settings',
692
-            'default'
693
-        );
694
-    }
695
-
696
-
697
-    /**
698
-     * Returns the name of the help tab for this PMT
699
-     * @return string
700
-     */
701
-    public function get_help_tab_name()
702
-    {
703
-        return 'ee_' . strtolower($this->system_name()) . '_help_tab';
704
-    }
705
-
706
-    /**
707
-     * The name of the wp capability that should be associated with the usage of
708
-     * this PMT by an admin
709
-     * @return string
710
-     */
711
-    public function cap_name()
712
-    {
713
-        return 'ee_payment_method_' . strtolower($this->system_name());
714
-    }
715
-
716
-    /**
717
-     * Called by client code to tell the gateway that if it wants to change
718
-     * the transaction or line items or registrations related to teh payment it already
719
-     * processed (we think, but possibly not) that now's the time to do it.
720
-     * It is expected that gateways will store any info they need for this on the PAY_details,
721
-     * or maybe an extra meta value
722
-     * @param EE_Payment $payment
723
-     * @return void
724
-     */
725
-    public function update_txn_based_on_payment($payment)
726
-    {
727
-        if ($this->_gateway instanceof EE_Gateway) {
728
-            $this->_gateway->update_txn_based_on_payment($payment);
729
-        }
730
-    }
731
-
732
-    /**
733
-     * Returns a string of HTML describing this payment method type for an admin,
734
-     * primarily intended for them to read before activating it.
735
-     * The easiest way to set this is to create a folder 'templates' alongside
736
-     * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php".
737
-     * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php",
738
-     * then you'd create a file named "templates" in the same folder as it, and name the file
739
-     * "foo_bar_intro.template.php", and its content will be returned by this method
740
-     * @return string
741
-     */
742
-    public function introductory_html()
743
-    {
744
-        return EEH_Template::locate_template($this->file_folder() . 'templates' . DS . strtolower($this->system_name()) . '_intro.template.php', array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance));
745
-    }
24
+	const onsite = 'on-site';
25
+	const offsite = 'off-site';
26
+	const offline = 'off-line';
27
+
28
+	/**
29
+	 * @var EE_Payment_Method
30
+	 */
31
+	protected $_pm_instance = NULL;
32
+
33
+	/**
34
+	 * @var boolean
35
+	 */
36
+	protected $_requires_https = FALSE;
37
+
38
+	/**
39
+	 * @var boolean
40
+	 */
41
+	protected $_has_billing_form;
42
+
43
+	/**
44
+	 * @var EE_Gateway
45
+	 */
46
+	protected $_gateway = NULL;
47
+
48
+	/**
49
+	 * @var EE_Payment_Method_Form
50
+	 */
51
+	protected $_settings_form = NULL;
52
+
53
+	/**
54
+	 * @var EE_Form_Section_Proper
55
+	 */
56
+	protected $_billing_form = NULL;
57
+
58
+	/**
59
+	 * @var boolean
60
+	 */
61
+	protected $_cache_billing_form = TRUE;
62
+
63
+	/**
64
+	 * String of the absolute path to the folder containing this file, with a trailing slash.
65
+	 * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
66
+	 * @var string
67
+	 */
68
+	protected $_file_folder = NULL;
69
+
70
+	/**
71
+	 * String to the absolute URL to this file (useful for getting its web-accessible resources
72
+	 * like images, js, or css)
73
+	 * @var string
74
+	 */
75
+	protected $_file_url = NULL;
76
+
77
+	/**
78
+	 * Pretty name for the payment method
79
+	 * @var string
80
+	 */
81
+	protected $_pretty_name = NULL;
82
+
83
+	/**
84
+	 *
85
+	 * @var string
86
+	 */
87
+	protected $_default_button_url = NULL;
88
+
89
+	/**
90
+	 *
91
+	 * @var string
92
+	 */
93
+	protected $_default_description = NULL;
94
+
95
+
96
+	/**
97
+	 *
98
+	 * @param EE_Payment_Method $pm_instance
99
+	 * @throws EE_Error
100
+	 * @return EE_PMT_Base
101
+	 */
102
+	function __construct($pm_instance = NULL)
103
+	{
104
+		if ($pm_instance instanceof EE_Payment_Method) {
105
+			$this->set_instance($pm_instance);
106
+		}
107
+		if ($this->_gateway) {
108
+			$this->_gateway->set_payment_model(EEM_Payment::instance());
109
+			$this->_gateway->set_payment_log(EEM_Change_Log::instance());
110
+			$this->_gateway->set_template_helper(new EEH_Template());
111
+			$this->_gateway->set_line_item_helper(new EEH_Line_Item());
112
+			$this->_gateway->set_money_helper(new EEH_Money());
113
+			$this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter());
114
+			$this->_gateway->set_unsupported_character_remover(new AsciiOnly());
115
+			do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
116
+		}
117
+		if (!isset($this->_has_billing_form)) {
118
+			// by default, On Site gateways have a billing form
119
+			if ($this->payment_occurs() == EE_PMT_Base::onsite) {
120
+				$this->set_has_billing_form(true);
121
+			} else {
122
+				$this->set_has_billing_form(false);
123
+			}
124
+		}
125
+
126
+		if (!$this->_pretty_name) {
127
+			throw new EE_Error(sprintf(__("You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized", "event_espresso")));
128
+		}
129
+		//if the child didn't specify a default button, use the credit card one
130
+		if ($this->_default_button_url === NULL) {
131
+			$this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods' . DS . 'pay-by-credit-card.png';
132
+		}
133
+	}
134
+
135
+
136
+	/**
137
+	 * @param boolean $has_billing_form
138
+	 */
139
+	public function set_has_billing_form($has_billing_form)
140
+	{
141
+		$this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN);
142
+	}
143
+
144
+
145
+	/**
146
+	 * sets the file_folder property
147
+	 */
148
+	protected function _set_file_folder()
149
+	{
150
+		$reflector = new ReflectionClass(get_class($this));
151
+		$fn = $reflector->getFileName();
152
+		$this->_file_folder = dirname($fn) . DS;
153
+	}
154
+
155
+
156
+	/**
157
+	 * sets the file URL with a trailing slash for this PMT
158
+	 */
159
+	protected function _set_file_url()
160
+	{
161
+		$plugins_dir_fixed = str_replace('\\', DS, WP_PLUGIN_DIR);
162
+		$file_folder_fixed = str_replace('\\', DS, $this->file_folder());
163
+		$file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed);
164
+		$this->_file_url = $file_path;
165
+	}
166
+
167
+	/**
168
+	 * Gets the default description on all payment methods of this type
169
+	 * @return string
170
+	 */
171
+	public function default_description()
172
+	{
173
+		return $this->_default_description;
174
+	}
175
+
176
+
177
+	/**
178
+	 * Returns the folder containing the PMT child class, with a trailing slash
179
+	 * @return string
180
+	 */
181
+	public function file_folder()
182
+	{
183
+		if (!$this->_file_folder) {
184
+			$this->_set_file_folder();
185
+		}
186
+		return $this->_file_folder;
187
+	}
188
+
189
+
190
+	/**
191
+	 * @return string
192
+	 */
193
+	public function file_url()
194
+	{
195
+		if (!$this->_file_url) {
196
+			$this->_set_file_url();
197
+		}
198
+		return $this->_file_url;
199
+	}
200
+
201
+
202
+	/**
203
+	 * Sets the payment method instance this payment method type is for.
204
+	 * Its important teh payment method instance is set before
205
+	 * @param EE_Payment_Method $payment_method_instance
206
+	 */
207
+	function set_instance($payment_method_instance)
208
+	{
209
+		$this->_pm_instance = $payment_method_instance;
210
+		//if they have already requested the settings form, make sure its
211
+		//data matches this model object
212
+		if ($this->_settings_form) {
213
+			$this->settings_form()->populate_model_obj($payment_method_instance);
214
+		}
215
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
216
+			$this->_gateway->set_settings($payment_method_instance->settings_array());
217
+		}
218
+	}
219
+
220
+
221
+	/**
222
+	 * Gets teh form for displaying to admins where they setup the payment method
223
+	 * @return EE_Payment_Method_Form
224
+	 */
225
+	function settings_form()
226
+	{
227
+		if (!$this->_settings_form) {
228
+			$this->_settings_form = $this->generate_new_settings_form();
229
+			$this->_settings_form->set_payment_method_type($this);
230
+			//if we have already assigned a model object to this pmt, make
231
+			//sure its reflected in teh form we just generated
232
+			if ($this->_pm_instance) {
233
+				$this->_settings_form->populate_model_obj($this->_pm_instance);
234
+			}
235
+		}
236
+		return $this->_settings_form;
237
+	}
238
+
239
+
240
+	/**
241
+	 * Gets the form for all the settings related to this payment method type
242
+	 * @return EE_Payment_Method_Form
243
+	 */
244
+	abstract function generate_new_settings_form();
245
+
246
+
247
+	/**
248
+	 * Sets the form for settings. This may be useful if we have already received
249
+	 * a form submission and have form data it in, and want to use it anytime we're showing
250
+	 * this payment method type's settings form later in the request
251
+	 * @param EE_Payment_Method_Form $form
252
+	 */
253
+	public function set_settings_form($form)
254
+	{
255
+		$this->_settings_form = $form;
256
+	}
257
+
258
+
259
+	/**
260
+	 * @return boolean
261
+	 */
262
+	public function has_billing_form()
263
+	{
264
+		return $this->_has_billing_form;
265
+	}
266
+
267
+
268
+	/**
269
+	 * Gets the form for displaying to attendees where they can enter their billing info
270
+	 * which will be sent to teh gateway (can be null)
271
+	 *
272
+	 * @param \EE_Transaction $transaction
273
+	 * @param array $extra_args
274
+	 * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null
275
+	 */
276
+	public function billing_form(EE_Transaction $transaction = NULL, $extra_args = array())
277
+	{
278
+		// has billing form already been regenerated ? or overwrite cache?
279
+		if (!$this->_billing_form instanceof EE_Billing_Info_Form || !$this->_cache_billing_form) {
280
+			$this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
281
+		}
282
+		//if we know who the attendee is, and this is a billing form
283
+		//that uses attendee info, populate it
284
+		if (
285
+		apply_filters(
286
+			'FHEE__populate_billing_form_fields_from_attendee',
287
+			(
288
+				$this->_billing_form instanceof EE_Billing_Attendee_Info_Form
289
+				&& $transaction instanceof EE_Transaction
290
+				&& $transaction->primary_registration() instanceof EE_Registration
291
+				&& $transaction->primary_registration()->attendee() instanceof EE_Attendee
292
+			),
293
+			$this->_billing_form,
294
+			$transaction
295
+		)
296
+		) {
297
+			$this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee());
298
+		}
299
+		return $this->_billing_form;
300
+	}
301
+
302
+
303
+	/**
304
+	 * Creates the billing form for this payment method type
305
+	 * @param \EE_Transaction $transaction
306
+	 * @return \EE_Billing_Info_Form
307
+	 */
308
+	abstract function generate_new_billing_form(EE_Transaction $transaction = NULL);
309
+
310
+
311
+	/**
312
+	 * apply_billing_form_debug_settings
313
+	 * applies debug data to the form
314
+	 *
315
+	 * @param \EE_Billing_Info_Form $billing_form
316
+	 * @return \EE_Billing_Info_Form
317
+	 */
318
+	public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
319
+	{
320
+		return $billing_form;
321
+	}
322
+
323
+
324
+	/**
325
+	 * Sets the billing form for this payment method type. You may want to use this
326
+	 * if you have form
327
+	 * @param EE_Payment_Method $form
328
+	 */
329
+	public function set_billing_form($form)
330
+	{
331
+		$this->_billing_form = $form;
332
+	}
333
+
334
+
335
+	/**
336
+	 * Returns whether or not this payment method requires HTTPS to be used
337
+	 * @return boolean
338
+	 */
339
+	function requires_https()
340
+	{
341
+		return $this->_requires_https;
342
+	}
343
+
344
+
345
+	/**
346
+	 *
347
+	 * @param EE_Transaction $transaction
348
+	 * @param float $amount
349
+	 * @param EE_Billing_Info_Form $billing_info
350
+	 * @param string $return_url
351
+	 * @param string $fail_url
352
+	 * @param string $method
353
+	 * @param bool $by_admin
354
+	 * @return EE_Payment
355
+	 * @throws EE_Error
356
+	 */
357
+	function process_payment(EE_Transaction $transaction, $amount = null, $billing_info = null, $return_url = null, $fail_url = '', $method = 'CART', $by_admin = false)
358
+	{
359
+		// @todo: add surcharge for the payment method, if any
360
+		if ($this->_gateway) {
361
+			//there is a gateway, so we're going to make a payment object
362
+			//but wait! do they already have a payment in progress that we thought was failed?
363
+			$duplicate_properties = array(
364
+				'STS_ID' => EEM_Payment::status_id_failed,
365
+				'TXN_ID' => $transaction->ID(),
366
+				'PMD_ID' => $this->_pm_instance->ID(),
367
+				'PAY_source' => $method,
368
+				'PAY_amount' => $amount !== null ? $amount : $transaction->remaining(),
369
+				'PAY_gateway_response' => null,
370
+			);
371
+			$payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
372
+			//if we didn't already have a payment in progress for the same thing,
373
+			//then we actually want to make a new payment
374
+			if (!$payment instanceof EE_Payment) {
375
+				$payment = EE_Payment::new_instance(
376
+					array_merge(
377
+						$duplicate_properties,
378
+						array(
379
+							'PAY_timestamp' => time(),
380
+							'PAY_txn_id_chq_nmbr' => null,
381
+							'PAY_po_number' => null,
382
+							'PAY_extra_accntng' => null,
383
+							'PAY_details' => null,
384
+						)
385
+					)
386
+				);
387
+			}
388
+			//make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
389
+			$payment->save();
390
+			$billing_values = $this->_get_billing_values_from_form($billing_info);
391
+
392
+			//  Offsite Gateway
393
+			if ($this->_gateway instanceof EE_Offsite_Gateway) {
394
+
395
+				$payment = $this->_gateway->set_redirection_info(
396
+					$payment,
397
+					$billing_values,
398
+					$return_url,
399
+					EE_Config::instance()->core->txn_page_url(
400
+						array(
401
+							'e_reg_url_link' => $transaction->primary_registration()->reg_url_link(),
402
+							'ee_payment_method' => $this->_pm_instance->slug()
403
+						)
404
+					),
405
+					$fail_url
406
+				);
407
+				$payment->save();
408
+				//  Onsite Gateway
409
+			} elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
410
+
411
+				$payment = $this->_gateway->do_direct_payment($payment, $billing_values);
412
+				$payment->save();
413
+
414
+			} else {
415
+				throw new EE_Error(
416
+					sprintf(
417
+						__('Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)', 'event_espresso'),
418
+						get_class($this),
419
+						gettype($this->_gateway)
420
+					)
421
+				);
422
+			}
423
+
424
+		} else {
425
+			// no gateway provided
426
+			// there is no payment. Must be an offline gateway
427
+			// create a payment object anyways, but dont save it
428
+			$payment = EE_Payment::new_instance(
429
+				array(
430
+					'STS_ID' => EEM_Payment::status_id_pending,
431
+					'TXN_ID' => $transaction->ID(),
432
+					'PMD_ID' => $transaction->payment_method_ID(),
433
+					'PAY_amount' => 0.00,
434
+					'PAY_timestamp' => time(),
435
+				)
436
+			);
437
+
438
+		}
439
+
440
+		// if there is billing info, clean it and save it now
441
+		if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
442
+			$this->_save_billing_info_to_attendee($billing_info, $transaction);
443
+		}
444
+
445
+		return $payment;
446
+	}
447
+
448
+	/**
449
+	 * Gets the values we want to pass onto the gateway. Normally these
450
+	 * are just the 'pretty' values, but there may be times the data may need
451
+	 * a  little massaging. Proper subsections will become arrays of inputs
452
+	 * @param EE_Billing_Info_Form $billing_form
453
+	 * @return array
454
+	 */
455
+	protected function _get_billing_values_from_form($billing_form)
456
+	{
457
+		if ($billing_form instanceof EE_Form_Section_Proper) {
458
+			return $billing_form->input_pretty_values(true);
459
+		} else {
460
+			return NULL;
461
+		}
462
+	}
463
+
464
+
465
+	/**
466
+	 * Handles an instant payment notification when the transaction is known (by default).
467
+	 * @param array $req_data
468
+	 * @param EE_Transaction $transaction
469
+	 * @return EE_Payment
470
+	 * @throws EE_Error
471
+	 */
472
+	public function handle_ipn($req_data, $transaction)
473
+	{
474
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
475
+		if (!$this->_gateway instanceof EE_Offsite_Gateway) {
476
+			throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE)));
477
+
478
+		}
479
+		$payment = $this->_gateway->handle_payment_update($req_data, $transaction);
480
+		return $payment;
481
+	}
482
+
483
+
484
+	/**
485
+	 * Saves the billing info onto the attendee of the primary registrant on this transaction, and
486
+	 * cleans it first.
487
+	 * @param EE_Billing_Attendee_Info_Form $billing_form
488
+	 * @param EE_Transaction $transaction
489
+	 * @return boolean success
490
+	 */
491
+	protected function _save_billing_info_to_attendee($billing_form, $transaction)
492
+	{
493
+		if (!$transaction || !$transaction instanceof EE_Transaction) {
494
+			EE_Error::add_error(__("Cannot save billing info because no transaction was specified", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
495
+			return false;
496
+		}
497
+		$primary_reg = $transaction->primary_registration();
498
+		if (!$primary_reg) {
499
+			EE_Error::add_error(__("Cannot save billing info because the transaction has no primary registration", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
500
+			return false;
501
+		}
502
+		$attendee = $primary_reg->attendee();
503
+		if (!$attendee) {
504
+			EE_Error::add_error(__("Cannot save billing info because the transaction's primary registration has no attendee!", "event_espresso"), __FILE__, __FUNCTION__, __LINE__);
505
+			return false;
506
+		}
507
+		return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method());
508
+
509
+	}
510
+
511
+
512
+	/**
513
+	 * Gets the payment this IPN is for. Children may often want to
514
+	 * override this to inspect the request
515
+	 * @param EE_Transaction $transaction
516
+	 * @param array $req_data
517
+	 * @return EE_Payment
518
+	 */
519
+	protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array())
520
+	{
521
+		return $transaction->last_payment();
522
+	}
523
+
524
+
525
+	/**
526
+	 * In case generic code cannot provide the payment processor with a specific payment method
527
+	 * and transaction, it will try calling this method on each activate payment method.
528
+	 * If the payment method is able to identify the request as being for it, it should fetch
529
+	 * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
530
+	 * handle the IPN
531
+	 * @param array $req_data
532
+	 * @return EE_Payment only if this payment method can find the info its needs from $req_data
533
+	 * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
534
+	 * @throws EE_Error
535
+	 */
536
+	public function handle_unclaimed_ipn($req_data = array())
537
+	{
538
+		throw new EE_Error(sprintf(__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this)));
539
+	}
540
+
541
+
542
+	/**
543
+	 * Logic to be accomplished when the payment attempt is complete.
544
+	 * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
545
+	 * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
546
+	 * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
547
+	 * of the payment). Fed a transaction because it's always assumed to be the last payment that
548
+	 * we're dealing with. Returns that last payment (if there is one)
549
+	 *
550
+	 * @param EE_Transaction $transaction
551
+	 * @return EE_Payment
552
+	 */
553
+	public function finalize_payment_for($transaction)
554
+	{
555
+		return $transaction->last_payment();
556
+	}
557
+
558
+
559
+	/**
560
+	 * Whether or not this payment method's gateway supports sending refund requests
561
+	 * @return boolean
562
+	 */
563
+	public function supports_sending_refunds()
564
+	{
565
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
566
+			return $this->_gateway->supports_sending_refunds();
567
+		} else {
568
+			return false;
569
+		}
570
+	}
571
+
572
+
573
+	/**
574
+	 *
575
+	 * @param EE_Payment $payment
576
+	 * @param array $refund_info
577
+	 * @throws EE_Error
578
+	 * @return EE_Payment
579
+	 */
580
+	public function process_refund(EE_Payment $payment, $refund_info = array())
581
+	{
582
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
583
+			return $this->_gateway->do_direct_refund($payment, $refund_info);
584
+		} else {
585
+			throw new EE_Error(
586
+				sprintf(
587
+					__('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'),
588
+					get_class($this)
589
+				)
590
+			);
591
+		}
592
+	}
593
+
594
+
595
+	/**
596
+	 * Returns one the class's constants onsite,offsite, or offline, depending on this
597
+	 * payment method's gateway.
598
+	 * @return string
599
+	 * @throws EE_Error
600
+	 */
601
+	public function payment_occurs()
602
+	{
603
+		if (!$this->_gateway) {
604
+			return EE_PMT_Base::offline;
605
+		} elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
606
+			return EE_PMT_Base::onsite;
607
+		} elseif ($this->_gateway instanceof EE_Offsite_Gateway) {
608
+			return EE_PMT_Base::offsite;
609
+		} else {
610
+			throw new EE_Error(sprintf(__("Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those", "event_espresso"), get_class($this)));
611
+		}
612
+	}
613
+
614
+
615
+	/**
616
+	 * For adding any html output ab ove the payment overview.
617
+	 * Many gateways won't want ot display anything, so this function just returns an empty string.
618
+	 * Other gateways may want to override this, such as offline gateways.
619
+	 * @param EE_Payment $payment
620
+	 * @return string
621
+	 */
622
+	public function payment_overview_content(EE_Payment $payment)
623
+	{
624
+		return EEH_Template::display_template(EE_LIBRARIES . 'payment_methods' . DS . 'templates' . DS . 'payment_details_content.template.php', array('payment_method' => $this->_pm_instance, 'payment' => $payment), true);
625
+	}
626
+
627
+
628
+	/**
629
+	 * @return array where keys are the help tab name,
630
+	 * values are: array {
631
+	 * @type string $title i18n name for the help tab
632
+	 * @type string $filename name of the file located in ./help_tabs/ (ie, in a folder next to this file)
633
+	 * @type array $template_args any arguments you want passed to the template file while rendering.
634
+	 *                Keys will be variable names and values with be their values.
635
+	 */
636
+	public function help_tabs_config()
637
+	{
638
+		return array();
639
+	}
640
+
641
+
642
+	/**
643
+	 * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
644
+	 * the payment method's table's PMT_type column)
645
+	 * @return string
646
+	 */
647
+	public function system_name()
648
+	{
649
+		$classname = get_class($this);
650
+		return str_replace("EE_PMT_", '', $classname);
651
+	}
652
+
653
+
654
+	/**
655
+	 * A pretty i18n version of the PMT name
656
+	 * @return string
657
+	 */
658
+	public function pretty_name()
659
+	{
660
+		return $this->_pretty_name;
661
+	}
662
+
663
+
664
+	/**
665
+	 * Gets the default absolute URL to the payment method type's button
666
+	 * @return string
667
+	 */
668
+	public function default_button_url()
669
+	{
670
+		return $this->_default_button_url;
671
+	}
672
+
673
+
674
+	/**
675
+	 * Gets the gateway used by this payment method (if any)
676
+	 * @return EE_Gateway
677
+	 */
678
+	public function get_gateway()
679
+	{
680
+		return $this->_gateway;
681
+	}
682
+
683
+
684
+	/**
685
+	 * @return string html for the link to a help tab
686
+	 */
687
+	public function get_help_tab_link()
688
+	{
689
+		return EEH_Template::get_help_tab_link(
690
+			$this->get_help_tab_name(),
691
+			'espresso_payment_settings',
692
+			'default'
693
+		);
694
+	}
695
+
696
+
697
+	/**
698
+	 * Returns the name of the help tab for this PMT
699
+	 * @return string
700
+	 */
701
+	public function get_help_tab_name()
702
+	{
703
+		return 'ee_' . strtolower($this->system_name()) . '_help_tab';
704
+	}
705
+
706
+	/**
707
+	 * The name of the wp capability that should be associated with the usage of
708
+	 * this PMT by an admin
709
+	 * @return string
710
+	 */
711
+	public function cap_name()
712
+	{
713
+		return 'ee_payment_method_' . strtolower($this->system_name());
714
+	}
715
+
716
+	/**
717
+	 * Called by client code to tell the gateway that if it wants to change
718
+	 * the transaction or line items or registrations related to teh payment it already
719
+	 * processed (we think, but possibly not) that now's the time to do it.
720
+	 * It is expected that gateways will store any info they need for this on the PAY_details,
721
+	 * or maybe an extra meta value
722
+	 * @param EE_Payment $payment
723
+	 * @return void
724
+	 */
725
+	public function update_txn_based_on_payment($payment)
726
+	{
727
+		if ($this->_gateway instanceof EE_Gateway) {
728
+			$this->_gateway->update_txn_based_on_payment($payment);
729
+		}
730
+	}
731
+
732
+	/**
733
+	 * Returns a string of HTML describing this payment method type for an admin,
734
+	 * primarily intended for them to read before activating it.
735
+	 * The easiest way to set this is to create a folder 'templates' alongside
736
+	 * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php".
737
+	 * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php",
738
+	 * then you'd create a file named "templates" in the same folder as it, and name the file
739
+	 * "foo_bar_intro.template.php", and its content will be returned by this method
740
+	 * @return string
741
+	 */
742
+	public function introductory_html()
743
+	{
744
+		return EEH_Template::locate_template($this->file_folder() . 'templates' . DS . strtolower($this->system_name()) . '_intro.template.php', array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance));
745
+	}
746 746
 
747 747
 
748 748
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 3 patches
Doc Comments   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
      *
713 713
      * @param \EE_Datetime_Field $datetime_field
714 714
      * @param bool               $pretty
715
-     * @param null               $date_or_time
715
+     * @param string|null               $date_or_time
716 716
      * @return void
717 717
      * @throws InvalidArgumentException
718 718
      * @throws InvalidInterfaceException
@@ -1066,7 +1066,7 @@  discard block
 block discarded – undo
1066 1066
      *
1067 1067
      * @param null  $field_to_order_by  What field is being used as the reference point.
1068 1068
      * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1069
+     * @param string  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070 1070
      *                                  you can indicate just the columns you want returned
1071 1071
      * @return array|EE_Base_Class
1072 1072
      * @throws ReflectionException
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
      *
1096 1096
      * @param null  $field_to_order_by  What field is being used as the reference point.
1097 1097
      * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1098
+     * @param string  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099 1099
      *                                  you can indicate just the column you want returned
1100 1100
      * @return array|EE_Base_Class
1101 1101
      * @throws ReflectionException
@@ -1178,7 +1178,7 @@  discard block
 block discarded – undo
1178 1178
      * This method simply returns the RAW unprocessed value for the given property in this class
1179 1179
      *
1180 1180
      * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1181
+     * @return integer|null              Whatever the raw value stored on the property is.
1182 1182
      * @throws ReflectionException
1183 1183
      * @throws InvalidArgumentException
1184 1184
      * @throws InvalidInterfaceException
@@ -1526,7 +1526,7 @@  discard block
 block discarded – undo
1526 1526
      * sets the time on a datetime property
1527 1527
      *
1528 1528
      * @access protected
1529
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1529
+     * @param string $time      a valid time string for php datetime functions (or DateTime object)
1530 1530
      * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1531 1531
      * @throws ReflectionException
1532 1532
      * @throws InvalidArgumentException
@@ -1544,7 +1544,7 @@  discard block
 block discarded – undo
1544 1544
      * sets the date on a datetime property
1545 1545
      *
1546 1546
      * @access protected
1547
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1547
+     * @param string $date      a valid date string for php datetime functions ( or DateTime object)
1548 1548
      * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1549 1549
      * @throws ReflectionException
1550 1550
      * @throws InvalidArgumentException
@@ -2066,7 +2066,7 @@  discard block
 block discarded – undo
2066 2066
      *
2067 2067
      * @param  array  $props_n_values   incoming array of properties and their values
2068 2068
      * @param  string $classname        the classname of the child class
2069
-     * @param null    $timezone
2069
+     * @param string|null    $timezone
2070 2070
      * @param array   $date_formats     incoming date_formats in an array where the first value is the
2071 2071
      *                                  date_format and the second value is the time format
2072 2072
      * @return mixed (EE_Base_Class|bool)
@@ -2153,7 +2153,7 @@  discard block
 block discarded – undo
2153 2153
      * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2154 2154
      *
2155 2155
      * @param string $model_classname
2156
-     * @param null   $timezone
2156
+     * @param string|null   $timezone
2157 2157
      * @return EEM_Base
2158 2158
      * @throws ReflectionException
2159 2159
      * @throws InvalidArgumentException
Please login to merge, or discard this patch.
Indentation   +3141 added lines, -3141 removed lines patch added patch discarded remove patch
@@ -15,3147 +15,3147 @@
 block discarded – undo
15 15
 abstract class EE_Base_Class
16 16
 {
17 17
 
18
-    /**
19
-     * This is an array of the original properties and values provided during construction
20
-     * of this model object. (keys are model field names, values are their values).
21
-     * This list is important to remember so that when we are merging data from the db, we know
22
-     * which values to override and which to not override.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $_props_n_values_provided_in_constructor;
27
-
28
-    /**
29
-     * Timezone
30
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
-     * access to it.
34
-     *
35
-     * @var string
36
-     */
37
-    protected $_timezone;
38
-
39
-    /**
40
-     * date format
41
-     * pattern or format for displaying dates
42
-     *
43
-     * @var string $_dt_frmt
44
-     */
45
-    protected $_dt_frmt;
46
-
47
-    /**
48
-     * time format
49
-     * pattern or format for displaying time
50
-     *
51
-     * @var string $_tm_frmt
52
-     */
53
-    protected $_tm_frmt;
54
-
55
-    /**
56
-     * This property is for holding a cached array of object properties indexed by property name as the key.
57
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
58
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
-     *
61
-     * @var array
62
-     */
63
-    protected $_cached_properties = array();
64
-
65
-    /**
66
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
67
-     * single
68
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
-     * all others have an array)
71
-     *
72
-     * @var array
73
-     */
74
-    protected $_model_relations = array();
75
-
76
-    /**
77
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
-     *
80
-     * @var array
81
-     */
82
-    protected $_fields = array();
83
-
84
-    /**
85
-     * @var boolean indicating whether or not this model object is intended to ever be saved
86
-     * For example, we might create model objects intended to only be used for the duration
87
-     * of this request and to be thrown away, and if they were accidentally saved
88
-     * it would be a bug.
89
-     */
90
-    protected $_allow_persist = true;
91
-
92
-    /**
93
-     * @var boolean indicating whether or not this model object's properties have changed since construction
94
-     */
95
-    protected $_has_changes = false;
96
-
97
-    /**
98
-     * @var EEM_Base
99
-     */
100
-    protected $_model;
101
-
102
-    /**
103
-     * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
-     * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
-     * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
-     * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
-     * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
-     * array as:
109
-     * array(
110
-     *  'Registration_Count' => 24
111
-     * );
112
-     * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
-     * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
-     * info)
115
-     *
116
-     * @var array
117
-     */
118
-    protected $custom_selection_results = array();
119
-
120
-
121
-    /**
122
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
-     * play nice
124
-     *
125
-     * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
-     *                                                         TXN_amount, QST_name, etc) and values are their values
128
-     * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
-     *                                                         corresponding db model or not.
130
-     * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
-     *                                                         be in when instantiating a EE_Base_Class object.
132
-     * @param array   $date_formats                            An array of date formats to set on construct where first
133
-     *                                                         value is the date_format and second value is the time
134
-     *                                                         format.
135
-     * @throws InvalidArgumentException
136
-     * @throws InvalidInterfaceException
137
-     * @throws InvalidDataTypeException
138
-     * @throws EE_Error
139
-     * @throws ReflectionException
140
-     */
141
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
-    {
143
-        $className = get_class($this);
144
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
-        $model        = $this->get_model();
146
-        $model_fields = $model->field_settings(false);
147
-        // ensure $fieldValues is an array
148
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
-        // verify client code has not passed any invalid field names
150
-        foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
152
-                throw new EE_Error(
153
-                    sprintf(
154
-                        esc_html__(
155
-                            'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
-                            'event_espresso'
157
-                        ),
158
-                        $field_name,
159
-                        get_class($this),
160
-                        implode(', ', array_keys($model_fields))
161
-                    )
162
-                );
163
-            }
164
-        }
165
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
167
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
-        } else {
169
-            //set default formats for date and time
170
-            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
-            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
-        }
173
-        //if db model is instantiating
174
-        if ($bydb) {
175
-            //client code has indicated these field values are from the database
176
-            foreach ($model_fields as $fieldName => $field) {
177
-                $this->set_from_db(
178
-                    $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
-                );
181
-            }
182
-        } else {
183
-            //we're constructing a brand
184
-            //new instance of the model object. Generally, this means we'll need to do more field validation
185
-            foreach ($model_fields as $fieldName => $field) {
186
-                $this->set(
187
-                    $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
-                );
190
-            }
191
-        }
192
-        //remember what values were passed to this constructor
193
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
194
-        //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
-            $model->add_to_entity_map($this);
197
-        }
198
-        //setup all the relations
199
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
202
-            } else {
203
-                $this->_model_relations[ $relation_name ] = array();
204
-            }
205
-        }
206
-        /**
207
-         * Action done at the end of each model object construction
208
-         *
209
-         * @param EE_Base_Class $this the model object just created
210
-         */
211
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
-    }
213
-
214
-
215
-    /**
216
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
217
-     *
218
-     * @return boolean
219
-     */
220
-    public function allow_persist()
221
-    {
222
-        return $this->_allow_persist;
223
-    }
224
-
225
-
226
-    /**
227
-     * Sets whether or not this model object should be allowed to be saved to the DB.
228
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
-     * you got new information that somehow made you change your mind.
230
-     *
231
-     * @param boolean $allow_persist
232
-     * @return boolean
233
-     */
234
-    public function set_allow_persist($allow_persist)
235
-    {
236
-        return $this->_allow_persist = $allow_persist;
237
-    }
238
-
239
-
240
-    /**
241
-     * Gets the field's original value when this object was constructed during this request.
242
-     * This can be helpful when determining if a model object has changed or not
243
-     *
244
-     * @param string $field_name
245
-     * @return mixed|null
246
-     * @throws ReflectionException
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidDataTypeException
250
-     * @throws EE_Error
251
-     */
252
-    public function get_original($field_name)
253
-    {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
256
-        ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
-        }
259
-        return null;
260
-    }
261
-
262
-
263
-    /**
264
-     * @param EE_Base_Class $obj
265
-     * @return string
266
-     */
267
-    public function get_class($obj)
268
-    {
269
-        return get_class($obj);
270
-    }
271
-
272
-
273
-    /**
274
-     * Overrides parent because parent expects old models.
275
-     * This also doesn't do any validation, and won't work for serialized arrays
276
-     *
277
-     * @param    string $field_name
278
-     * @param    mixed  $field_value
279
-     * @param bool      $use_default
280
-     * @throws InvalidArgumentException
281
-     * @throws InvalidInterfaceException
282
-     * @throws InvalidDataTypeException
283
-     * @throws EE_Error
284
-     * @throws ReflectionException
285
-     * @throws ReflectionException
286
-     * @throws ReflectionException
287
-     */
288
-    public function set($field_name, $field_value, $use_default = false)
289
-    {
290
-        // if not using default and nothing has changed, and object has already been setup (has ID),
291
-        // then don't do anything
292
-        if (
293
-            ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
295
-            && $this->ID()
296
-        ) {
297
-            return;
298
-        }
299
-        $model              = $this->get_model();
300
-        $this->_has_changes = true;
301
-        $field_obj          = $model->field_settings_for($field_name);
302
-        if ($field_obj instanceof EE_Model_Field_Base) {
303
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
304
-            if ($field_obj instanceof EE_Datetime_Field) {
305
-                $field_obj->set_timezone($this->_timezone);
306
-                $field_obj->set_date_format($this->_dt_frmt);
307
-                $field_obj->set_time_format($this->_tm_frmt);
308
-            }
309
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
310
-            //should the value be null?
311
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
313
-                /**
314
-                 * To save having to refactor all the models, if a default value is used for a
315
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
-                 * object.
318
-                 *
319
-                 * @since 4.6.10+
320
-                 */
321
-                if (
322
-                    $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
325
-                ) {
326
-                    empty($this->_fields[ $field_name ])
327
-                        ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
329
-                }
330
-            } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
332
-            }
333
-            //if we're not in the constructor...
334
-            //now check if what we set was a primary key
335
-            if (
336
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
-                $this->_props_n_values_provided_in_constructor
338
-                && $field_value
339
-                && $field_name === $model->primary_key_name()
340
-            ) {
341
-                //if so, we want all this object's fields to be filled either with
342
-                //what we've explicitly set on this model
343
-                //or what we have in the db
344
-                // echo "setting primary key!";
345
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
346
-                $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
-                foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
-                        && $field_obj->get_name() !== $field_name
350
-                    ) {
351
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
-                    }
353
-                }
354
-                //oh this model object has an ID? well make sure its in the entity mapper
355
-                $model->add_to_entity_map($this);
356
-            }
357
-            //let's unset any cache for this field_name from the $_cached_properties property.
358
-            $this->_clear_cached_property($field_name);
359
-        } else {
360
-            throw new EE_Error(
361
-                sprintf(
362
-                    esc_html__(
363
-                        'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
-                        'event_espresso'
365
-                    ),
366
-                    $field_name
367
-                )
368
-            );
369
-        }
370
-    }
371
-
372
-
373
-    /**
374
-     * Set custom select values for model.
375
-     *
376
-     * @param array $custom_select_values
377
-     */
378
-    public function setCustomSelectsValues(array $custom_select_values)
379
-    {
380
-        $this->custom_selection_results = $custom_select_values;
381
-    }
382
-
383
-
384
-    /**
385
-     * Returns the custom select value for the provided alias if its set.
386
-     * If not set, returns null.
387
-     *
388
-     * @param string $alias
389
-     * @return string|int|float|null
390
-     */
391
-    public function getCustomSelect($alias)
392
-    {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
395
-            : null;
396
-    }
397
-
398
-
399
-    /**
400
-     * This sets the field value on the db column if it exists for the given $column_name or
401
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
-     *
403
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
-     * @param string $field_name  Must be the exact column name.
405
-     * @param mixed  $field_value The value to set.
406
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
-     * @throws InvalidArgumentException
408
-     * @throws InvalidInterfaceException
409
-     * @throws InvalidDataTypeException
410
-     * @throws EE_Error
411
-     * @throws ReflectionException
412
-     */
413
-    public function set_field_or_extra_meta($field_name, $field_value)
414
-    {
415
-        if ($this->get_model()->has_field($field_name)) {
416
-            $this->set($field_name, $field_value);
417
-            return true;
418
-        }
419
-        //ensure this object is saved first so that extra meta can be properly related.
420
-        $this->save();
421
-        return $this->update_extra_meta($field_name, $field_value);
422
-    }
423
-
424
-
425
-    /**
426
-     * This retrieves the value of the db column set on this class or if that's not present
427
-     * it will attempt to retrieve from extra_meta if found.
428
-     * Example Usage:
429
-     * Via EE_Message child class:
430
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
433
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
-     * value for those extra fields dynamically via the EE_message object.
435
-     *
436
-     * @param  string $field_name expecting the fully qualified field name.
437
-     * @return mixed|null  value for the field if found.  null if not found.
438
-     * @throws ReflectionException
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidInterfaceException
441
-     * @throws InvalidDataTypeException
442
-     * @throws EE_Error
443
-     */
444
-    public function get_field_or_extra_meta($field_name)
445
-    {
446
-        if ($this->get_model()->has_field($field_name)) {
447
-            $column_value = $this->get($field_name);
448
-        } else {
449
-            //This isn't a column in the main table, let's see if it is in the extra meta.
450
-            $column_value = $this->get_extra_meta($field_name, true, null);
451
-        }
452
-        return $column_value;
453
-    }
454
-
455
-
456
-    /**
457
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
-     *
462
-     * @access public
463
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
-     * @return void
465
-     * @throws InvalidArgumentException
466
-     * @throws InvalidInterfaceException
467
-     * @throws InvalidDataTypeException
468
-     * @throws EE_Error
469
-     * @throws ReflectionException
470
-     */
471
-    public function set_timezone($timezone = '')
472
-    {
473
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
-        //make sure we clear all cached properties because they won't be relevant now
475
-        $this->_clear_cached_properties();
476
-        //make sure we update field settings and the date for all EE_Datetime_Fields
477
-        $model_fields = $this->get_model()->field_settings(false);
478
-        foreach ($model_fields as $field_name => $field_obj) {
479
-            if ($field_obj instanceof EE_Datetime_Field) {
480
-                $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    EEH_DTT_Helper::setTimezone($this->_fields[$field_name], new DateTimeZone($this->_timezone));
483
-                }
484
-            }
485
-        }
486
-    }
487
-
488
-
489
-    /**
490
-     * This just returns whatever is set for the current timezone.
491
-     *
492
-     * @access public
493
-     * @return string timezone string
494
-     */
495
-    public function get_timezone()
496
-    {
497
-        return $this->_timezone;
498
-    }
499
-
500
-
501
-    /**
502
-     * This sets the internal date format to what is sent in to be used as the new default for the class
503
-     * internally instead of wp set date format options
504
-     *
505
-     * @since 4.6
506
-     * @param string $format should be a format recognizable by PHP date() functions.
507
-     */
508
-    public function set_date_format($format)
509
-    {
510
-        $this->_dt_frmt = $format;
511
-        //clear cached_properties because they won't be relevant now.
512
-        $this->_clear_cached_properties();
513
-    }
514
-
515
-
516
-    /**
517
-     * This sets the internal time format string to what is sent in to be used as the new default for the
518
-     * class internally instead of wp set time format options.
519
-     *
520
-     * @since 4.6
521
-     * @param string $format should be a format recognizable by PHP date() functions.
522
-     */
523
-    public function set_time_format($format)
524
-    {
525
-        $this->_tm_frmt = $format;
526
-        //clear cached_properties because they won't be relevant now.
527
-        $this->_clear_cached_properties();
528
-    }
529
-
530
-
531
-    /**
532
-     * This returns the current internal set format for the date and time formats.
533
-     *
534
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
-     *                             where the first value is the date format and the second value is the time format.
536
-     * @return mixed string|array
537
-     */
538
-    public function get_format($full = true)
539
-    {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
-    }
542
-
543
-
544
-    /**
545
-     * cache
546
-     * stores the passed model object on the current model object.
547
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
-     *
549
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
-     *                                       'Registration' associated with this model object
551
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
-     *                                       that could be a payment or a registration)
553
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
-     *                                       items which will be stored in an array on this object
555
-     * @throws ReflectionException
556
-     * @throws InvalidArgumentException
557
-     * @throws InvalidInterfaceException
558
-     * @throws InvalidDataTypeException
559
-     * @throws EE_Error
560
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
-     *                                       related thing, no array)
562
-     */
563
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
-    {
565
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
567
-            return false;
568
-        }
569
-        // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
-            throw new EE_Error(
572
-                sprintf(
573
-                    esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
-                    $relationName,
575
-                    get_class($this)
576
-                )
577
-            );
578
-        }
579
-        // how many things are related ?
580
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
-            // if it's a "belongs to" relationship, then there's only one related model object
582
-            // eg, if this is a registration, there's only 1 attendee for it
583
-            // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
585
-            $return                                  = true;
586
-        } else {
587
-            // otherwise, this is the "many" side of a one to many relationship,
588
-            // so we'll add the object to the array of related objects for that type.
589
-            // eg: if this is an event, there are many registrations for that event,
590
-            // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
592
-                // if for some reason, the cached item is a model object,
593
-                // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
-                                                           instanceof
596
-                                                           EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
598
-            }
599
-            // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
601
-                // if the cache_id exists, then it means we are purposely trying to cache this
602
-                // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
-                $return                                               = $cache_id;
605
-            } elseif ($object_to_cache->ID()) {
606
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
-                $return                                                            = $object_to_cache->ID();
609
-            } else {
610
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
612
-                // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
614
-                // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
616
-            }
617
-        }
618
-        return $return;
619
-    }
620
-
621
-
622
-    /**
623
-     * For adding an item to the cached_properties property.
624
-     *
625
-     * @access protected
626
-     * @param string      $fieldname the property item the corresponding value is for.
627
-     * @param mixed       $value     The value we are caching.
628
-     * @param string|null $cache_type
629
-     * @return void
630
-     * @throws ReflectionException
631
-     * @throws InvalidArgumentException
632
-     * @throws InvalidInterfaceException
633
-     * @throws InvalidDataTypeException
634
-     * @throws EE_Error
635
-     */
636
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
-    {
638
-        //first make sure this property exists
639
-        $this->get_model()->field_settings_for($fieldname);
640
-        $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
-    }
643
-
644
-
645
-    /**
646
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
-     * This also SETS the cache if we return the actual property!
648
-     *
649
-     * @param string $fieldname        the name of the property we're trying to retrieve
650
-     * @param bool   $pretty
651
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
-     *                                 (in cases where the same property may be used for different outputs
653
-     *                                 - i.e. datetime, money etc.)
654
-     *                                 It can also accept certain pre-defined "schema" strings
655
-     *                                 to define how to output the property.
656
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
-     * @return mixed                   whatever the value for the property is we're retrieving
658
-     * @throws ReflectionException
659
-     * @throws InvalidArgumentException
660
-     * @throws InvalidInterfaceException
661
-     * @throws InvalidDataTypeException
662
-     * @throws EE_Error
663
-     */
664
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
-    {
666
-        //verify the field exists
667
-        $model = $this->get_model();
668
-        $model->field_settings_for($fieldname);
669
-        $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
-        }
674
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
-        $this->_set_cached_property($fieldname, $value, $cache_type);
676
-        return $value;
677
-    }
678
-
679
-
680
-    /**
681
-     * If the cache didn't fetch the needed item, this fetches it.
682
-     *
683
-     * @param string $fieldname
684
-     * @param bool   $pretty
685
-     * @param string $extra_cache_ref
686
-     * @return mixed
687
-     * @throws InvalidArgumentException
688
-     * @throws InvalidInterfaceException
689
-     * @throws InvalidDataTypeException
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     */
693
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
-    {
695
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
696
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
-        if ($field_obj instanceof EE_Datetime_Field) {
698
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
-        }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
702
-        }
703
-        $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
-        return $value;
707
-    }
708
-
709
-
710
-    /**
711
-     * set timezone, formats, and output for EE_Datetime_Field objects
712
-     *
713
-     * @param \EE_Datetime_Field $datetime_field
714
-     * @param bool               $pretty
715
-     * @param null               $date_or_time
716
-     * @return void
717
-     * @throws InvalidArgumentException
718
-     * @throws InvalidInterfaceException
719
-     * @throws InvalidDataTypeException
720
-     * @throws EE_Error
721
-     */
722
-    protected function _prepare_datetime_field(
723
-        EE_Datetime_Field $datetime_field,
724
-        $pretty = false,
725
-        $date_or_time = null
726
-    ) {
727
-        $datetime_field->set_timezone($this->_timezone);
728
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
-        //set the output returned
731
-        switch ($date_or_time) {
732
-            case 'D' :
733
-                $datetime_field->set_date_time_output('date');
734
-                break;
735
-            case 'T' :
736
-                $datetime_field->set_date_time_output('time');
737
-                break;
738
-            default :
739
-                $datetime_field->set_date_time_output();
740
-        }
741
-    }
742
-
743
-
744
-    /**
745
-     * This just takes care of clearing out the cached_properties
746
-     *
747
-     * @return void
748
-     */
749
-    protected function _clear_cached_properties()
750
-    {
751
-        $this->_cached_properties = array();
752
-    }
753
-
754
-
755
-    /**
756
-     * This just clears out ONE property if it exists in the cache
757
-     *
758
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
-     * @return void
760
-     */
761
-    protected function _clear_cached_property($property_name)
762
-    {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
765
-        }
766
-    }
767
-
768
-
769
-    /**
770
-     * Ensures that this related thing is a model object.
771
-     *
772
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
-     * @param string $model_name   name of the related thing, eg 'Attendee',
774
-     * @return EE_Base_Class
775
-     * @throws ReflectionException
776
-     * @throws InvalidArgumentException
777
-     * @throws InvalidInterfaceException
778
-     * @throws InvalidDataTypeException
779
-     * @throws EE_Error
780
-     */
781
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
-    {
783
-        $other_model_instance = self::_get_model_instance_with_name(
784
-            self::_get_model_classname($model_name),
785
-            $this->_timezone
786
-        );
787
-        return $other_model_instance->ensure_is_obj($object_or_id);
788
-    }
789
-
790
-
791
-    /**
792
-     * Forgets the cached model of the given relation Name. So the next time we request it,
793
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
796
-     *
797
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
-     *                                                     Eg 'Registration'
799
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
-     *                                                     this is HasMany or HABTM.
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
-     *                                                     relation from all
811
-     */
812
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
-    {
814
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
-        $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
817
-            throw new EE_Error(
818
-                sprintf(
819
-                    esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
-                    $relationName,
821
-                    get_class($this)
822
-                )
823
-            );
824
-        }
825
-        if ($clear_all) {
826
-            $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
828
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
831
-        } else {
832
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
-                && $object_to_remove_or_index_into_array->ID()
834
-            ) {
835
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
-                ) {
839
-                    $index_found_at = null;
840
-                    //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
-                        /** @noinspection TypeUnsafeComparisonInspection */
843
-                        if (
844
-                            $obj instanceof EE_Base_Class
845
-                            && (
846
-                                $obj == $object_to_remove_or_index_into_array
847
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
-                            )
849
-                        ) {
850
-                            $index_found_at = $index;
851
-                            break;
852
-                        }
853
-                    }
854
-                    if ($index_found_at) {
855
-                        $index_in_cache = $index_found_at;
856
-                    } else {
857
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
-                        //if it wasn't in it to begin with. So we're done
859
-                        return $object_to_remove_or_index_into_array;
860
-                    }
861
-                }
862
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
-                    /** @noinspection TypeUnsafeComparisonInspection */
866
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
-                        $index_in_cache = $index;
868
-                    }
869
-                }
870
-            } else {
871
-                $index_in_cache = $object_to_remove_or_index_into_array;
872
-            }
873
-            //supposedly we've found it. But it could just be that the client code
874
-            //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
-            } else {
879
-                //that thing was never cached anyways.
880
-                $obj_removed = null;
881
-            }
882
-        }
883
-        return $obj_removed;
884
-    }
885
-
886
-
887
-    /**
888
-     * update_cache_after_object_save
889
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
-     * obtained after being saved to the db
891
-     *
892
-     * @param string        $relationName       - the type of object that is cached
893
-     * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
-     * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
-     * @return boolean TRUE on success, FALSE on fail
896
-     * @throws ReflectionException
897
-     * @throws InvalidArgumentException
898
-     * @throws InvalidInterfaceException
899
-     * @throws InvalidDataTypeException
900
-     * @throws EE_Error
901
-     */
902
-    public function update_cache_after_object_save(
903
-        $relationName,
904
-        EE_Base_Class $newly_saved_object,
905
-        $current_cache_id = ''
906
-    ) {
907
-        // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
909
-        if ($newly_saved_object instanceof $obj_class) {
910
-            /* @type EE_Base_Class $newly_saved_object */
911
-            // now get the type of relation
912
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
-            // if this is a 1:1 relationship
914
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
-                // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
917
-                return true;
918
-                // or if it's some kind of sordid feral polyamorous relationship...
919
-            }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
-            ) {
923
-                // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
-                // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
-                return true;
928
-            }
929
-        }
930
-        return false;
931
-    }
932
-
933
-
934
-    /**
935
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
-     *
938
-     * @param string $relationName
939
-     * @return EE_Base_Class
940
-     */
941
-    public function get_one_from_cache($relationName)
942
-    {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
945
-            : null;
946
-        if (is_array($cached_array_or_object)) {
947
-            return array_shift($cached_array_or_object);
948
-        }
949
-        return $cached_array_or_object;
950
-    }
951
-
952
-
953
-    /**
954
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
-     *
957
-     * @param string $relationName
958
-     * @throws ReflectionException
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidInterfaceException
961
-     * @throws InvalidDataTypeException
962
-     * @throws EE_Error
963
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
-     */
965
-    public function get_all_from_cache($relationName)
966
-    {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
-        // if the result is not an array, but exists, make it an array
969
-        $objects = is_array($objects) ? $objects : array($objects);
970
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
-        //basically, if this model object was stored in the session, and these cached model objects
972
-        //already have IDs, let's make sure they're in their model's entity mapper
973
-        //otherwise we will have duplicates next time we call
974
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
-        $model = EE_Registry::instance()->load_model($relationName);
976
-        foreach ($objects as $model_object) {
977
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
-                if ($model_object->ID()) {
980
-                    $model->add_to_entity_map($model_object);
981
-                }
982
-            } else {
983
-                throw new EE_Error(
984
-                    sprintf(
985
-                        esc_html__(
986
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
-                            'event_espresso'
988
-                        ),
989
-                        $relationName,
990
-                        gettype($model_object)
991
-                    )
992
-                );
993
-            }
994
-        }
995
-        return $objects;
996
-    }
997
-
998
-
999
-    /**
1000
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
-     * matching the given query conditions.
1002
-     *
1003
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1004
-     * @param int   $limit              How many objects to return.
1005
-     * @param array $query_params       Any additional conditions on the query.
1006
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
-     *                                  you can indicate just the columns you want returned
1008
-     * @return array|EE_Base_Class[]
1009
-     * @throws ReflectionException
1010
-     * @throws InvalidArgumentException
1011
-     * @throws InvalidInterfaceException
1012
-     * @throws InvalidDataTypeException
1013
-     * @throws EE_Error
1014
-     */
1015
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
-    {
1017
-        $model         = $this->get_model();
1018
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
-            ? $model->get_primary_key_field()->get_name()
1020
-            : $field_to_order_by;
1021
-        $current_value = ! empty($field) ? $this->get($field) : null;
1022
-        if (empty($field) || empty($current_value)) {
1023
-            return array();
1024
-        }
1025
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
-    }
1027
-
1028
-
1029
-    /**
1030
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
-     * matching the given query conditions.
1032
-     *
1033
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1034
-     * @param int   $limit              How many objects to return.
1035
-     * @param array $query_params       Any additional conditions on the query.
1036
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
-     *                                  you can indicate just the columns you want returned
1038
-     * @return array|EE_Base_Class[]
1039
-     * @throws ReflectionException
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidInterfaceException
1042
-     * @throws InvalidDataTypeException
1043
-     * @throws EE_Error
1044
-     */
1045
-    public function previous_x(
1046
-        $field_to_order_by = null,
1047
-        $limit = 1,
1048
-        $query_params = array(),
1049
-        $columns_to_select = null
1050
-    ) {
1051
-        $model         = $this->get_model();
1052
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
-            ? $model->get_primary_key_field()->get_name()
1054
-            : $field_to_order_by;
1055
-        $current_value = ! empty($field) ? $this->get($field) : null;
1056
-        if (empty($field) || empty($current_value)) {
1057
-            return array();
1058
-        }
1059
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
-     * matching the given query conditions.
1066
-     *
1067
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1068
-     * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
-     *                                  you can indicate just the columns you want returned
1071
-     * @return array|EE_Base_Class
1072
-     * @throws ReflectionException
1073
-     * @throws InvalidArgumentException
1074
-     * @throws InvalidInterfaceException
1075
-     * @throws InvalidDataTypeException
1076
-     * @throws EE_Error
1077
-     */
1078
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
-    {
1080
-        $model         = $this->get_model();
1081
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
-            ? $model->get_primary_key_field()->get_name()
1083
-            : $field_to_order_by;
1084
-        $current_value = ! empty($field) ? $this->get($field) : null;
1085
-        if (empty($field) || empty($current_value)) {
1086
-            return array();
1087
-        }
1088
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
-     * matching the given query conditions.
1095
-     *
1096
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1097
-     * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
-     *                                  you can indicate just the column you want returned
1100
-     * @return array|EE_Base_Class
1101
-     * @throws ReflectionException
1102
-     * @throws InvalidArgumentException
1103
-     * @throws InvalidInterfaceException
1104
-     * @throws InvalidDataTypeException
1105
-     * @throws EE_Error
1106
-     */
1107
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
-    {
1109
-        $model         = $this->get_model();
1110
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
-            ? $model->get_primary_key_field()->get_name()
1112
-            : $field_to_order_by;
1113
-        $current_value = ! empty($field) ? $this->get($field) : null;
1114
-        if (empty($field) || empty($current_value)) {
1115
-            return array();
1116
-        }
1117
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * Overrides parent because parent expects old models.
1123
-     * This also doesn't do any validation, and won't work for serialized arrays
1124
-     *
1125
-     * @param string $field_name
1126
-     * @param mixed  $field_value_from_db
1127
-     * @throws ReflectionException
1128
-     * @throws InvalidArgumentException
1129
-     * @throws InvalidInterfaceException
1130
-     * @throws InvalidDataTypeException
1131
-     * @throws EE_Error
1132
-     */
1133
-    public function set_from_db($field_name, $field_value_from_db)
1134
-    {
1135
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1136
-        if ($field_obj instanceof EE_Model_Field_Base) {
1137
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1138
-            //eg, a CPT model object could have an entry in the posts table, but no
1139
-            //entry in the meta table. Meaning that all its columns in the meta table
1140
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1141
-            if ($field_value_from_db === null) {
1142
-                if ($field_obj->is_nullable()) {
1143
-                    //if the field allows nulls, then let it be null
1144
-                    $field_value = null;
1145
-                } else {
1146
-                    $field_value = $field_obj->get_default_value();
1147
-                }
1148
-            } else {
1149
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
-            }
1151
-            $this->_fields[ $field_name ] = $field_value;
1152
-            $this->_clear_cached_property($field_name);
1153
-        }
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * verifies that the specified field is of the correct type
1159
-     *
1160
-     * @param string $field_name
1161
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
-     *                                (in cases where the same property may be used for different outputs
1163
-     *                                - i.e. datetime, money etc.)
1164
-     * @return mixed
1165
-     * @throws ReflectionException
1166
-     * @throws InvalidArgumentException
1167
-     * @throws InvalidInterfaceException
1168
-     * @throws InvalidDataTypeException
1169
-     * @throws EE_Error
1170
-     */
1171
-    public function get($field_name, $extra_cache_ref = null)
1172
-    {
1173
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * This method simply returns the RAW unprocessed value for the given property in this class
1179
-     *
1180
-     * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1182
-     * @throws ReflectionException
1183
-     * @throws InvalidArgumentException
1184
-     * @throws InvalidInterfaceException
1185
-     * @throws InvalidDataTypeException
1186
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
-     */
1188
-    public function get_raw($field_name)
1189
-    {
1190
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * This is used to return the internal DateTime object used for a field that is a
1199
-     * EE_Datetime_Field.
1200
-     *
1201
-     * @param string $field_name               The field name retrieving the DateTime object.
1202
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
-     * @throws EE_Error an error is set and false returned.  If the field IS an
1204
-     *                                         EE_Datetime_Field and but the field value is null, then
1205
-     *                                         just null is returned (because that indicates that likely
1206
-     *                                         this field is nullable).
1207
-     * @throws InvalidArgumentException
1208
-     * @throws InvalidDataTypeException
1209
-     * @throws InvalidInterfaceException
1210
-     * @throws ReflectionException
1211
-     */
1212
-    public function get_DateTime_object($field_name)
1213
-    {
1214
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1215
-        if (! $field_settings instanceof EE_Datetime_Field) {
1216
-            EE_Error::add_error(
1217
-                sprintf(
1218
-                    esc_html__(
1219
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1220
-                        'event_espresso'
1221
-                    ),
1222
-                    $field_name
1223
-                ),
1224
-                __FILE__,
1225
-                __FUNCTION__,
1226
-                __LINE__
1227
-            );
1228
-            return false;
1229
-        }
1230
-        return isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime
1231
-            ? clone $this->_fields[$field_name]
1232
-            : null;
1233
-    }
1234
-
1235
-
1236
-    /**
1237
-     * To be used in template to immediately echo out the value, and format it for output.
1238
-     * Eg, should call stripslashes and whatnot before echoing
1239
-     *
1240
-     * @param string $field_name      the name of the field as it appears in the DB
1241
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1242
-     *                                (in cases where the same property may be used for different outputs
1243
-     *                                - i.e. datetime, money etc.)
1244
-     * @return void
1245
-     * @throws ReflectionException
1246
-     * @throws InvalidArgumentException
1247
-     * @throws InvalidInterfaceException
1248
-     * @throws InvalidDataTypeException
1249
-     * @throws EE_Error
1250
-     */
1251
-    public function e($field_name, $extra_cache_ref = null)
1252
-    {
1253
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1254
-    }
1255
-
1256
-
1257
-    /**
1258
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1259
-     * can be easily used as the value of form input.
1260
-     *
1261
-     * @param string $field_name
1262
-     * @return void
1263
-     * @throws ReflectionException
1264
-     * @throws InvalidArgumentException
1265
-     * @throws InvalidInterfaceException
1266
-     * @throws InvalidDataTypeException
1267
-     * @throws EE_Error
1268
-     */
1269
-    public function f($field_name)
1270
-    {
1271
-        $this->e($field_name, 'form_input');
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * Same as `f()` but just returns the value instead of echoing it
1277
-     *
1278
-     * @param string $field_name
1279
-     * @return string
1280
-     * @throws ReflectionException
1281
-     * @throws InvalidArgumentException
1282
-     * @throws InvalidInterfaceException
1283
-     * @throws InvalidDataTypeException
1284
-     * @throws EE_Error
1285
-     */
1286
-    public function get_f($field_name)
1287
-    {
1288
-        return (string) $this->get_pretty($field_name, 'form_input');
1289
-    }
1290
-
1291
-
1292
-    /**
1293
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1294
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1295
-     * to see what options are available.
1296
-     *
1297
-     * @param string $field_name
1298
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1299
-     *                                (in cases where the same property may be used for different outputs
1300
-     *                                - i.e. datetime, money etc.)
1301
-     * @return mixed
1302
-     * @throws ReflectionException
1303
-     * @throws InvalidArgumentException
1304
-     * @throws InvalidInterfaceException
1305
-     * @throws InvalidDataTypeException
1306
-     * @throws EE_Error
1307
-     */
1308
-    public function get_pretty($field_name, $extra_cache_ref = null)
1309
-    {
1310
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * This simply returns the datetime for the given field name
1316
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1317
-     * (and the equivalent e_date, e_time, e_datetime).
1318
-     *
1319
-     * @access   protected
1320
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1321
-     * @param string   $dt_frmt      valid datetime format used for date
1322
-     *                               (if '' then we just use the default on the field,
1323
-     *                               if NULL we use the last-used format)
1324
-     * @param string   $tm_frmt      Same as above except this is for time format
1325
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1326
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1327
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1328
-     *                               if field is not a valid dtt field, or void if echoing
1329
-     * @throws ReflectionException
1330
-     * @throws InvalidArgumentException
1331
-     * @throws InvalidInterfaceException
1332
-     * @throws InvalidDataTypeException
1333
-     * @throws EE_Error
1334
-     */
1335
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1336
-    {
1337
-        // clear cached property
1338
-        $this->_clear_cached_property($field_name);
1339
-        //reset format properties because they are used in get()
1340
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1341
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1342
-        if ($echo) {
1343
-            $this->e($field_name, $date_or_time);
1344
-            return '';
1345
-        }
1346
-        return $this->get($field_name, $date_or_time);
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1352
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1353
-     * other echoes the pretty value for dtt)
1354
-     *
1355
-     * @param  string $field_name name of model object datetime field holding the value
1356
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1357
-     * @return string            datetime value formatted
1358
-     * @throws ReflectionException
1359
-     * @throws InvalidArgumentException
1360
-     * @throws InvalidInterfaceException
1361
-     * @throws InvalidDataTypeException
1362
-     * @throws EE_Error
1363
-     */
1364
-    public function get_date($field_name, $format = '')
1365
-    {
1366
-        return $this->_get_datetime($field_name, $format, null, 'D');
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * @param        $field_name
1372
-     * @param string $format
1373
-     * @throws ReflectionException
1374
-     * @throws InvalidArgumentException
1375
-     * @throws InvalidInterfaceException
1376
-     * @throws InvalidDataTypeException
1377
-     * @throws EE_Error
1378
-     */
1379
-    public function e_date($field_name, $format = '')
1380
-    {
1381
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1387
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1388
-     * other echoes the pretty value for dtt)
1389
-     *
1390
-     * @param  string $field_name name of model object datetime field holding the value
1391
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1392
-     * @return string             datetime value formatted
1393
-     * @throws ReflectionException
1394
-     * @throws InvalidArgumentException
1395
-     * @throws InvalidInterfaceException
1396
-     * @throws InvalidDataTypeException
1397
-     * @throws EE_Error
1398
-     */
1399
-    public function get_time($field_name, $format = '')
1400
-    {
1401
-        return $this->_get_datetime($field_name, null, $format, 'T');
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * @param        $field_name
1407
-     * @param string $format
1408
-     * @throws ReflectionException
1409
-     * @throws InvalidArgumentException
1410
-     * @throws InvalidInterfaceException
1411
-     * @throws InvalidDataTypeException
1412
-     * @throws EE_Error
1413
-     */
1414
-    public function e_time($field_name, $format = '')
1415
-    {
1416
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1417
-    }
1418
-
1419
-
1420
-    /**
1421
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1422
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1423
-     * other echoes the pretty value for dtt)
1424
-     *
1425
-     * @param  string $field_name name of model object datetime field holding the value
1426
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1427
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1428
-     * @return string             datetime value formatted
1429
-     * @throws ReflectionException
1430
-     * @throws InvalidArgumentException
1431
-     * @throws InvalidInterfaceException
1432
-     * @throws InvalidDataTypeException
1433
-     * @throws EE_Error
1434
-     */
1435
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1436
-    {
1437
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1438
-    }
1439
-
1440
-
1441
-    /**
1442
-     * @param string $field_name
1443
-     * @param string $dt_frmt
1444
-     * @param string $tm_frmt
1445
-     * @throws ReflectionException
1446
-     * @throws InvalidArgumentException
1447
-     * @throws InvalidInterfaceException
1448
-     * @throws InvalidDataTypeException
1449
-     * @throws EE_Error
1450
-     */
1451
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1452
-    {
1453
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1454
-    }
1455
-
1456
-
1457
-    /**
1458
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1459
-     *
1460
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1461
-     * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1462
-     *                           on the object will be used.
1463
-     * @return string Date and time string in set locale or false if no field exists for the given
1464
-     * @throws ReflectionException
1465
-     * @throws InvalidArgumentException
1466
-     * @throws InvalidInterfaceException
1467
-     * @throws InvalidDataTypeException
1468
-     * @throws EE_Error
1469
-     *                           field name.
1470
-     */
1471
-    public function get_i18n_datetime($field_name, $format = '')
1472
-    {
1473
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1474
-        return date_i18n(
1475
-            $format,
1476
-            EEH_DTT_Helper::get_timestamp_with_offset(
1477
-                $this->get_raw($field_name),
1478
-                $this->_timezone
1479
-            )
1480
-        );
1481
-    }
1482
-
1483
-
1484
-    /**
1485
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1486
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1487
-     * thrown.
1488
-     *
1489
-     * @param  string $field_name The field name being checked
1490
-     * @throws ReflectionException
1491
-     * @throws InvalidArgumentException
1492
-     * @throws InvalidInterfaceException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws EE_Error
1495
-     * @return EE_Datetime_Field
1496
-     */
1497
-    protected function _get_dtt_field_settings($field_name)
1498
-    {
1499
-        $field = $this->get_model()->field_settings_for($field_name);
1500
-        //check if field is dtt
1501
-        if ($field instanceof EE_Datetime_Field) {
1502
-            return $field;
1503
-        }
1504
-        throw new EE_Error(
1505
-            sprintf(
1506
-                esc_html__(
1507
-                    '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',
1508
-                    'event_espresso'
1509
-                ),
1510
-                $field_name,
1511
-                self::_get_model_classname(get_class($this))
1512
-            )
1513
-        );
1514
-    }
1515
-
1516
-
1517
-
1518
-
1519
-    /**
1520
-     * NOTE ABOUT BELOW:
1521
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1522
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1523
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1524
-     * method and make sure you send the entire datetime value for setting.
1525
-     */
1526
-    /**
1527
-     * sets the time on a datetime property
1528
-     *
1529
-     * @access protected
1530
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1531
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1532
-     * @throws ReflectionException
1533
-     * @throws InvalidArgumentException
1534
-     * @throws InvalidInterfaceException
1535
-     * @throws InvalidDataTypeException
1536
-     * @throws EE_Error
1537
-     */
1538
-    protected function _set_time_for($time, $fieldname)
1539
-    {
1540
-        $this->_set_date_time('T', $time, $fieldname);
1541
-    }
1542
-
1543
-
1544
-    /**
1545
-     * sets the date on a datetime property
1546
-     *
1547
-     * @access protected
1548
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1549
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1550
-     * @throws ReflectionException
1551
-     * @throws InvalidArgumentException
1552
-     * @throws InvalidInterfaceException
1553
-     * @throws InvalidDataTypeException
1554
-     * @throws EE_Error
1555
-     */
1556
-    protected function _set_date_for($date, $fieldname)
1557
-    {
1558
-        $this->_set_date_time('D', $date, $fieldname);
1559
-    }
1560
-
1561
-
1562
-    /**
1563
-     * This takes care of setting a date or time independently on a given model object property. This method also
1564
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1565
-     *
1566
-     * @access protected
1567
-     * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1568
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1569
-     * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1570
-     *                                        EE_Datetime_Field property)
1571
-     * @throws ReflectionException
1572
-     * @throws InvalidArgumentException
1573
-     * @throws InvalidInterfaceException
1574
-     * @throws InvalidDataTypeException
1575
-     * @throws EE_Error
1576
-     */
1577
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1578
-    {
1579
-        $field = $this->_get_dtt_field_settings($fieldname);
1580
-        $field->set_timezone($this->_timezone);
1581
-        $field->set_date_format($this->_dt_frmt);
1582
-        $field->set_time_format($this->_tm_frmt);
1583
-        switch ($what) {
1584
-            case 'T' :
1585
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1586
-                    $datetime_value,
1587
-                    $this->_fields[ $fieldname ]
1588
-                );
1589
-                break;
1590
-            case 'D' :
1591
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1592
-                    $datetime_value,
1593
-                    $this->_fields[ $fieldname ]
1594
-                );
1595
-                break;
1596
-            case 'B' :
1597
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1598
-                break;
1599
-        }
1600
-        $this->_clear_cached_property($fieldname);
1601
-    }
1602
-
1603
-
1604
-    /**
1605
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1606
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1607
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1608
-     * that could lead to some unexpected results!
1609
-     *
1610
-     * @access public
1611
-     * @param string $field_name               This is the name of the field on the object that contains the date/time
1612
-     *                                         value being returned.
1613
-     * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1614
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1615
-     * @param string $prepend                  You can include something to prepend on the timestamp
1616
-     * @param string $append                   You can include something to append on the timestamp
1617
-     * @throws ReflectionException
1618
-     * @throws InvalidArgumentException
1619
-     * @throws InvalidInterfaceException
1620
-     * @throws InvalidDataTypeException
1621
-     * @throws EE_Error
1622
-     * @return string timestamp
1623
-     */
1624
-    public function display_in_my_timezone(
1625
-        $field_name,
1626
-        $callback = 'get_datetime',
1627
-        $args = null,
1628
-        $prepend = '',
1629
-        $append = ''
1630
-    ) {
1631
-        $timezone = EEH_DTT_Helper::get_timezone();
1632
-        if ($timezone === $this->_timezone) {
1633
-            return '';
1634
-        }
1635
-        $original_timezone = $this->_timezone;
1636
-        $this->set_timezone($timezone);
1637
-        $fn   = (array) $field_name;
1638
-        $args = array_merge($fn, (array) $args);
1639
-        if (! method_exists($this, $callback)) {
1640
-            throw new EE_Error(
1641
-                sprintf(
1642
-                    esc_html__(
1643
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1644
-                        'event_espresso'
1645
-                    ),
1646
-                    $callback
1647
-                )
1648
-            );
1649
-        }
1650
-        $args   = (array) $args;
1651
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1652
-        $this->set_timezone($original_timezone);
1653
-        return $return;
1654
-    }
1655
-
1656
-
1657
-    /**
1658
-     * Deletes this model object.
1659
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1660
-     * override
1661
-     * `EE_Base_Class::_delete` NOT this class.
1662
-     *
1663
-     * @return boolean | int
1664
-     * @throws ReflectionException
1665
-     * @throws InvalidArgumentException
1666
-     * @throws InvalidInterfaceException
1667
-     * @throws InvalidDataTypeException
1668
-     * @throws EE_Error
1669
-     */
1670
-    public function delete()
1671
-    {
1672
-        /**
1673
-         * Called just before the `EE_Base_Class::_delete` method call.
1674
-         * Note:
1675
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1676
-         * should be aware that `_delete` may not always result in a permanent delete.
1677
-         * For example, `EE_Soft_Delete_Base_Class::_delete`
1678
-         * soft deletes (trash) the object and does not permanently delete it.
1679
-         *
1680
-         * @param EE_Base_Class $model_object about to be 'deleted'
1681
-         */
1682
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1683
-        $result = $this->_delete();
1684
-        /**
1685
-         * Called just after the `EE_Base_Class::_delete` method call.
1686
-         * Note:
1687
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1688
-         * should be aware that `_delete` may not always result in a permanent delete.
1689
-         * For example `EE_Soft_Base_Class::_delete`
1690
-         * soft deletes (trash) the object and does not permanently delete it.
1691
-         *
1692
-         * @param EE_Base_Class $model_object that was just 'deleted'
1693
-         * @param boolean       $result
1694
-         */
1695
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1696
-        return $result;
1697
-    }
1698
-
1699
-
1700
-    /**
1701
-     * Calls the specific delete method for the instantiated class.
1702
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1703
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1704
-     * `EE_Base_Class::delete`
1705
-     *
1706
-     * @return bool|int
1707
-     * @throws ReflectionException
1708
-     * @throws InvalidArgumentException
1709
-     * @throws InvalidInterfaceException
1710
-     * @throws InvalidDataTypeException
1711
-     * @throws EE_Error
1712
-     */
1713
-    protected function _delete()
1714
-    {
1715
-        return $this->delete_permanently();
1716
-    }
1717
-
1718
-
1719
-    /**
1720
-     * Deletes this model object permanently from db
1721
-     * (but keep in mind related models may block the delete and return an error)
1722
-     *
1723
-     * @return bool | int
1724
-     * @throws ReflectionException
1725
-     * @throws InvalidArgumentException
1726
-     * @throws InvalidInterfaceException
1727
-     * @throws InvalidDataTypeException
1728
-     * @throws EE_Error
1729
-     */
1730
-    public function delete_permanently()
1731
-    {
1732
-        /**
1733
-         * Called just before HARD deleting a model object
1734
-         *
1735
-         * @param EE_Base_Class $model_object about to be 'deleted'
1736
-         */
1737
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1738
-        $model  = $this->get_model();
1739
-        $result = $model->delete_permanently_by_ID($this->ID());
1740
-        $this->refresh_cache_of_related_objects();
1741
-        /**
1742
-         * Called just after HARD deleting a model object
1743
-         *
1744
-         * @param EE_Base_Class $model_object that was just 'deleted'
1745
-         * @param boolean       $result
1746
-         */
1747
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1748
-        return $result;
1749
-    }
1750
-
1751
-
1752
-    /**
1753
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1754
-     * related model objects
1755
-     *
1756
-     * @throws ReflectionException
1757
-     * @throws InvalidArgumentException
1758
-     * @throws InvalidInterfaceException
1759
-     * @throws InvalidDataTypeException
1760
-     * @throws EE_Error
1761
-     */
1762
-    public function refresh_cache_of_related_objects()
1763
-    {
1764
-        $model = $this->get_model();
1765
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
-            if (! empty($this->_model_relations[ $relation_name ])) {
1767
-                $related_objects = $this->_model_relations[ $relation_name ];
1768
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769
-                    //this relation only stores a single model object, not an array
1770
-                    //but let's make it consistent
1771
-                    $related_objects = array($related_objects);
1772
-                }
1773
-                foreach ($related_objects as $related_object) {
1774
-                    //only refresh their cache if they're in memory
1775
-                    if ($related_object instanceof EE_Base_Class) {
1776
-                        $related_object->clear_cache(
1777
-                            $model->get_this_model_name(),
1778
-                            $this
1779
-                        );
1780
-                    }
1781
-                }
1782
-            }
1783
-        }
1784
-    }
1785
-
1786
-
1787
-    /**
1788
-     *        Saves this object to the database. An array may be supplied to set some values on this
1789
-     * object just before saving.
1790
-     *
1791
-     * @access public
1792
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1793
-     *                                 if provided during the save() method (often client code will change the fields'
1794
-     *                                 values before calling save)
1795
-     * @throws InvalidArgumentException
1796
-     * @throws InvalidInterfaceException
1797
-     * @throws InvalidDataTypeException
1798
-     * @throws EE_Error
1799
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1800
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1801
-     * @throws ReflectionException
1802
-     * @throws ReflectionException
1803
-     * @throws ReflectionException
1804
-     */
1805
-    public function save($set_cols_n_values = array())
1806
-    {
1807
-        $model = $this->get_model();
1808
-        /**
1809
-         * Filters the fields we're about to save on the model object
1810
-         *
1811
-         * @param array         $set_cols_n_values
1812
-         * @param EE_Base_Class $model_object
1813
-         */
1814
-        $set_cols_n_values = (array) apply_filters(
1815
-            'FHEE__EE_Base_Class__save__set_cols_n_values',
1816
-            $set_cols_n_values,
1817
-            $this
1818
-        );
1819
-        //set attributes as provided in $set_cols_n_values
1820
-        foreach ($set_cols_n_values as $column => $value) {
1821
-            $this->set($column, $value);
1822
-        }
1823
-        // no changes ? then don't do anything
1824
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825
-            return 0;
1826
-        }
1827
-        /**
1828
-         * Saving a model object.
1829
-         * Before we perform a save, this action is fired.
1830
-         *
1831
-         * @param EE_Base_Class $model_object the model object about to be saved.
1832
-         */
1833
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
-        if (! $this->allow_persist()) {
1835
-            return 0;
1836
-        }
1837
-        // now get current attribute values
1838
-        $save_cols_n_values = $this->_fields;
1839
-        // if the object already has an ID, update it. Otherwise, insert it
1840
-        // also: change the assumption about values passed to the model NOT being prepare dby the model object.
1841
-        // They have been
1842
-        $old_assumption_concerning_value_preparation = $model
1843
-            ->get_assumption_concerning_values_already_prepared_by_model_object();
1844
-        $model->assume_values_already_prepared_by_model_object(true);
1845
-        //does this model have an autoincrement PK?
1846
-        if ($model->has_primary_key_field()) {
1847
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1848
-                //ok check if it's set, if so: update; if not, insert
1849
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1850
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851
-                } else {
1852
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1853
-                    $results = $model->insert($save_cols_n_values);
1854
-                    if ($results) {
1855
-                        //if successful, set the primary key
1856
-                        //but don't use the normal SET method, because it will check if
1857
-                        //an item with the same ID exists in the mapper & db, then
1858
-                        //will find it in the db (because we just added it) and THAT object
1859
-                        //will get added to the mapper before we can add this one!
1860
-                        //but if we just avoid using the SET method, all that headache can be avoided
1861
-                        $pk_field_name                   = $model->primary_key_name();
1862
-                        $this->_fields[ $pk_field_name ] = $results;
1863
-                        $this->_clear_cached_property($pk_field_name);
1864
-                        $model->add_to_entity_map($this);
1865
-                        $this->_update_cached_related_model_objs_fks();
1866
-                    }
1867
-                }
1868
-            } else {//PK is NOT auto-increment
1869
-                //so check if one like it already exists in the db
1870
-                if ($model->exists_by_ID($this->ID())) {
1871
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1872
-                        throw new EE_Error(
1873
-                            sprintf(
1874
-                                esc_html__(
1875
-                                    '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',
1876
-                                    'event_espresso'
1877
-                                ),
1878
-                                get_class($this),
1879
-                                get_class($model) . '::instance()->add_to_entity_map()',
1880
-                                get_class($model) . '::instance()->get_one_by_ID()',
1881
-                                '<br />'
1882
-                            )
1883
-                        );
1884
-                    }
1885
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1886
-                } else {
1887
-                    $results = $model->insert($save_cols_n_values);
1888
-                    $this->_update_cached_related_model_objs_fks();
1889
-                }
1890
-            }
1891
-        } else {//there is NO primary key
1892
-            $already_in_db = false;
1893
-            foreach ($model->unique_indexes() as $index) {
1894
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1895
-                if ($model->exists(array($uniqueness_where_params))) {
1896
-                    $already_in_db = true;
1897
-                }
1898
-            }
1899
-            if ($already_in_db) {
1900
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1901
-                    $model->get_combined_primary_key_fields());
1902
-                $results                     = $model->update(
1903
-                    $save_cols_n_values,
1904
-                    $combined_pk_fields_n_values
1905
-                );
1906
-            } else {
1907
-                $results = $model->insert($save_cols_n_values);
1908
-            }
1909
-        }
1910
-        //restore the old assumption about values being prepared by the model object
1911
-        $model->assume_values_already_prepared_by_model_object(
1912
-                $old_assumption_concerning_value_preparation
1913
-            );
1914
-        /**
1915
-         * After saving the model object this action is called
1916
-         *
1917
-         * @param EE_Base_Class $model_object which was just saved
1918
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1919
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1920
-         */
1921
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1922
-        $this->_has_changes = false;
1923
-        return $results;
1924
-    }
1925
-
1926
-
1927
-    /**
1928
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1929
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1930
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1931
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1932
-     * 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
1933
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1934
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1935
-     *
1936
-     * @return void
1937
-     * @throws ReflectionException
1938
-     * @throws InvalidArgumentException
1939
-     * @throws InvalidInterfaceException
1940
-     * @throws InvalidDataTypeException
1941
-     * @throws EE_Error
1942
-     */
1943
-    protected function _update_cached_related_model_objs_fks()
1944
-    {
1945
-        $model = $this->get_model();
1946
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1947
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1948
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1949
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1950
-                        $model->get_this_model_name()
1951
-                    );
1952
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1953
-                    if ($related_model_obj_in_cache->ID()) {
1954
-                        $related_model_obj_in_cache->save();
1955
-                    }
1956
-                }
1957
-            }
1958
-        }
1959
-    }
1960
-
1961
-
1962
-    /**
1963
-     * Saves this model object and its NEW cached relations to the database.
1964
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1965
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1966
-     * because otherwise, there's a potential for infinite looping of saving
1967
-     * Saves the cached related model objects, and ensures the relation between them
1968
-     * and this object and properly setup
1969
-     *
1970
-     * @return int ID of new model object on save; 0 on failure+
1971
-     * @throws ReflectionException
1972
-     * @throws InvalidArgumentException
1973
-     * @throws InvalidInterfaceException
1974
-     * @throws InvalidDataTypeException
1975
-     * @throws EE_Error
1976
-     */
1977
-    public function save_new_cached_related_model_objs()
1978
-    {
1979
-        //make sure this has been saved
1980
-        if (! $this->ID()) {
1981
-            $id = $this->save();
1982
-        } else {
1983
-            $id = $this->ID();
1984
-        }
1985
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1986
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
-            if ($this->_model_relations[ $relationName ]) {
1988
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990
-                /* @var $related_model_obj EE_Base_Class */
1991
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1992
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1993
-                    //but ONLY if it DOES NOT exist in the DB
1994
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1995
-                    //					if( ! $related_model_obj->ID()){
1996
-                    $this->_add_relation_to($related_model_obj, $relationName);
1997
-                    $related_model_obj->save_new_cached_related_model_objs();
1998
-                    //					}
1999
-                } else {
2000
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2001
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
2002
-                        //but ONLY if it DOES NOT exist in the DB
2003
-                        //						if( ! $related_model_obj->ID()){
2004
-                        $this->_add_relation_to($related_model_obj, $relationName);
2005
-                        $related_model_obj->save_new_cached_related_model_objs();
2006
-                        //						}
2007
-                    }
2008
-                }
2009
-            }
2010
-        }
2011
-        return $id;
2012
-    }
2013
-
2014
-
2015
-    /**
2016
-     * for getting a model while instantiated.
2017
-     *
2018
-     * @return EEM_Base | EEM_CPT_Base
2019
-     * @throws ReflectionException
2020
-     * @throws InvalidArgumentException
2021
-     * @throws InvalidInterfaceException
2022
-     * @throws InvalidDataTypeException
2023
-     * @throws EE_Error
2024
-     */
2025
-    public function get_model()
2026
-    {
2027
-        if (! $this->_model) {
2028
-            $modelName    = self::_get_model_classname(get_class($this));
2029
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030
-        } else {
2031
-            $this->_model->set_timezone($this->_timezone);
2032
-        }
2033
-        return $this->_model;
2034
-    }
2035
-
2036
-
2037
-    /**
2038
-     * @param $props_n_values
2039
-     * @param $classname
2040
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2041
-     * @throws ReflectionException
2042
-     * @throws InvalidArgumentException
2043
-     * @throws InvalidInterfaceException
2044
-     * @throws InvalidDataTypeException
2045
-     * @throws EE_Error
2046
-     */
2047
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2048
-    {
2049
-        //TODO: will not work for Term_Relationships because they have no PK!
2050
-        $primary_id_ref = self::_get_primary_key_name($classname);
2051
-        if (
2052
-            array_key_exists($primary_id_ref, $props_n_values)
2053
-            && ! empty($props_n_values[ $primary_id_ref ])
2054
-        ) {
2055
-            $id = $props_n_values[ $primary_id_ref ];
2056
-            return self::_get_model($classname)->get_from_entity_map($id);
2057
-        }
2058
-        return false;
2059
-    }
2060
-
2061
-
2062
-    /**
2063
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2064
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2065
-     * 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
2066
-     * we return false.
2067
-     *
2068
-     * @param  array  $props_n_values   incoming array of properties and their values
2069
-     * @param  string $classname        the classname of the child class
2070
-     * @param null    $timezone
2071
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
2072
-     *                                  date_format and the second value is the time format
2073
-     * @return mixed (EE_Base_Class|bool)
2074
-     * @throws InvalidArgumentException
2075
-     * @throws InvalidInterfaceException
2076
-     * @throws InvalidDataTypeException
2077
-     * @throws EE_Error
2078
-     * @throws ReflectionException
2079
-     * @throws ReflectionException
2080
-     * @throws ReflectionException
2081
-     */
2082
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2083
-    {
2084
-        $existing = null;
2085
-        $model    = self::_get_model($classname, $timezone);
2086
-        if ($model->has_primary_key_field()) {
2087
-            $primary_id_ref = self::_get_primary_key_name($classname);
2088
-            if (array_key_exists($primary_id_ref, $props_n_values)
2089
-                && ! empty($props_n_values[ $primary_id_ref ])
2090
-            ) {
2091
-                $existing = $model->get_one_by_ID(
2092
-                    $props_n_values[ $primary_id_ref ]
2093
-                );
2094
-            }
2095
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2096
-            //no primary key on this model, but there's still a matching item in the DB
2097
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2098
-                self::_get_model($classname, $timezone)
2099
-                    ->get_index_primary_key_string($props_n_values)
2100
-            );
2101
-        }
2102
-        if ($existing) {
2103
-            //set date formats if present before setting values
2104
-            if (! empty($date_formats) && is_array($date_formats)) {
2105
-                $existing->set_date_format($date_formats[0]);
2106
-                $existing->set_time_format($date_formats[1]);
2107
-            } else {
2108
-                //set default formats for date and time
2109
-                $existing->set_date_format(get_option('date_format'));
2110
-                $existing->set_time_format(get_option('time_format'));
2111
-            }
2112
-            foreach ($props_n_values as $property => $field_value) {
2113
-                $existing->set($property, $field_value);
2114
-            }
2115
-            return $existing;
2116
-        }
2117
-        return false;
2118
-    }
2119
-
2120
-
2121
-    /**
2122
-     * Gets the EEM_*_Model for this class
2123
-     *
2124
-     * @access public now, as this is more convenient
2125
-     * @param      $classname
2126
-     * @param null $timezone
2127
-     * @throws ReflectionException
2128
-     * @throws InvalidArgumentException
2129
-     * @throws InvalidInterfaceException
2130
-     * @throws InvalidDataTypeException
2131
-     * @throws EE_Error
2132
-     * @return EEM_Base
2133
-     */
2134
-    protected static function _get_model($classname, $timezone = null)
2135
-    {
2136
-        //find model for this class
2137
-        if (! $classname) {
2138
-            throw new EE_Error(
2139
-                sprintf(
2140
-                    esc_html__(
2141
-                        'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2142
-                        'event_espresso'
2143
-                    ),
2144
-                    $classname
2145
-                )
2146
-            );
2147
-        }
2148
-        $modelName = self::_get_model_classname($classname);
2149
-        return self::_get_model_instance_with_name($modelName, $timezone);
2150
-    }
2151
-
2152
-
2153
-    /**
2154
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2155
-     *
2156
-     * @param string $model_classname
2157
-     * @param null   $timezone
2158
-     * @return EEM_Base
2159
-     * @throws ReflectionException
2160
-     * @throws InvalidArgumentException
2161
-     * @throws InvalidInterfaceException
2162
-     * @throws InvalidDataTypeException
2163
-     * @throws EE_Error
2164
-     */
2165
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2166
-    {
2167
-        $model_classname = str_replace('EEM_', '', $model_classname);
2168
-        $model           = EE_Registry::instance()->load_model($model_classname);
2169
-        $model->set_timezone($timezone);
2170
-        return $model;
2171
-    }
2172
-
2173
-
2174
-    /**
2175
-     * If a model name is provided (eg Registration), gets the model classname for that model.
2176
-     * Also works if a model class's classname is provided (eg EE_Registration).
2177
-     *
2178
-     * @param null $model_name
2179
-     * @return string like EEM_Attendee
2180
-     */
2181
-    private static function _get_model_classname($model_name = null)
2182
-    {
2183
-        if (strpos($model_name, 'EE_') === 0) {
2184
-            $model_classname = str_replace('EE_', 'EEM_', $model_name);
2185
-        } else {
2186
-            $model_classname = 'EEM_' . $model_name;
2187
-        }
2188
-        return $model_classname;
2189
-    }
2190
-
2191
-
2192
-    /**
2193
-     * returns the name of the primary key attribute
2194
-     *
2195
-     * @param null $classname
2196
-     * @throws ReflectionException
2197
-     * @throws InvalidArgumentException
2198
-     * @throws InvalidInterfaceException
2199
-     * @throws InvalidDataTypeException
2200
-     * @throws EE_Error
2201
-     * @return string
2202
-     */
2203
-    protected static function _get_primary_key_name($classname = null)
2204
-    {
2205
-        if (! $classname) {
2206
-            throw new EE_Error(
2207
-                sprintf(
2208
-                    esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2209
-                    $classname
2210
-                )
2211
-            );
2212
-        }
2213
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
2214
-    }
2215
-
2216
-
2217
-    /**
2218
-     * Gets the value of the primary key.
2219
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
2220
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2221
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2222
-     *
2223
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2224
-     * @throws ReflectionException
2225
-     * @throws InvalidArgumentException
2226
-     * @throws InvalidInterfaceException
2227
-     * @throws InvalidDataTypeException
2228
-     * @throws EE_Error
2229
-     */
2230
-    public function ID()
2231
-    {
2232
-        $model = $this->get_model();
2233
-        //now that we know the name of the variable, use a variable variable to get its value and return its
2234
-        if ($model->has_primary_key_field()) {
2235
-            return $this->_fields[ $model->primary_key_name() ];
2236
-        }
2237
-        return $model->get_index_primary_key_string($this->_fields);
2238
-    }
2239
-
2240
-
2241
-    /**
2242
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2243
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2244
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2245
-     *
2246
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2247
-     * @param string $relationName                     eg 'Events','Question',etc.
2248
-     *                                                 an attendee to a group, you also want to specify which role they
2249
-     *                                                 will have in that group. So you would use this parameter to
2250
-     *                                                 specify array('role-column-name'=>'role-id')
2251
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2252
-     *                                                 allow you to further constrict the relation to being added.
2253
-     *                                                 However, keep in mind that the columns (keys) given must match a
2254
-     *                                                 column on the JOIN table and currently only the HABTM models
2255
-     *                                                 accept these additional conditions.  Also remember that if an
2256
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2257
-     *                                                 NEW row is created in the join table.
2258
-     * @param null   $cache_id
2259
-     * @throws ReflectionException
2260
-     * @throws InvalidArgumentException
2261
-     * @throws InvalidInterfaceException
2262
-     * @throws InvalidDataTypeException
2263
-     * @throws EE_Error
2264
-     * @return EE_Base_Class the object the relation was added to
2265
-     */
2266
-    public function _add_relation_to(
2267
-        $otherObjectModelObjectOrID,
2268
-        $relationName,
2269
-        $extra_join_model_fields_n_values = array(),
2270
-        $cache_id = null
2271
-    ) {
2272
-        $model = $this->get_model();
2273
-        //if this thing exists in the DB, save the relation to the DB
2274
-        if ($this->ID()) {
2275
-            $otherObject = $model->add_relationship_to(
2276
-                $this,
2277
-                $otherObjectModelObjectOrID,
2278
-                $relationName,
2279
-                $extra_join_model_fields_n_values
2280
-            );
2281
-            //clear cache so future get_many_related and get_first_related() return new results.
2282
-            $this->clear_cache($relationName, $otherObject, true);
2283
-            if ($otherObject instanceof EE_Base_Class) {
2284
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2285
-            }
2286
-        } else {
2287
-            //this thing doesn't exist in the DB,  so just cache it
2288
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289
-                throw new EE_Error(
2290
-                    sprintf(
2291
-                        esc_html__(
2292
-                            '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',
2293
-                            'event_espresso'
2294
-                        ),
2295
-                        $otherObjectModelObjectOrID,
2296
-                        get_class($this)
2297
-                    )
2298
-                );
2299
-            }
2300
-            $otherObject = $otherObjectModelObjectOrID;
2301
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2302
-        }
2303
-        if ($otherObject instanceof EE_Base_Class) {
2304
-            //fix the reciprocal relation too
2305
-            if ($otherObject->ID()) {
2306
-                //its saved so assumed relations exist in the DB, so we can just
2307
-                //clear the cache so future queries use the updated info in the DB
2308
-                $otherObject->clear_cache(
2309
-                    $model->get_this_model_name(),
2310
-                    null,
2311
-                    true
2312
-                );
2313
-            } else {
2314
-                //it's not saved, so it caches relations like this
2315
-                $otherObject->cache($model->get_this_model_name(), $this);
2316
-            }
2317
-        }
2318
-        return $otherObject;
2319
-    }
2320
-
2321
-
2322
-    /**
2323
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2324
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2325
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2326
-     * from the cache
2327
-     *
2328
-     * @param mixed  $otherObjectModelObjectOrID
2329
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2330
-     *                to the DB yet
2331
-     * @param string $relationName
2332
-     * @param array  $where_query
2333
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2334
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2335
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2336
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2337
-     *                created in the join table.
2338
-     * @return EE_Base_Class the relation was removed from
2339
-     * @throws ReflectionException
2340
-     * @throws InvalidArgumentException
2341
-     * @throws InvalidInterfaceException
2342
-     * @throws InvalidDataTypeException
2343
-     * @throws EE_Error
2344
-     */
2345
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2346
-    {
2347
-        if ($this->ID()) {
2348
-            //if this exists in the DB, save the relation change to the DB too
2349
-            $otherObject = $this->get_model()->remove_relationship_to(
2350
-                $this,
2351
-                $otherObjectModelObjectOrID,
2352
-                $relationName,
2353
-                $where_query
2354
-            );
2355
-            $this->clear_cache(
2356
-                $relationName,
2357
-                $otherObject
2358
-            );
2359
-        } else {
2360
-            //this doesn't exist in the DB, just remove it from the cache
2361
-            $otherObject = $this->clear_cache(
2362
-                $relationName,
2363
-                $otherObjectModelObjectOrID
2364
-            );
2365
-        }
2366
-        if ($otherObject instanceof EE_Base_Class) {
2367
-            $otherObject->clear_cache(
2368
-                $this->get_model()->get_this_model_name(),
2369
-                $this
2370
-            );
2371
-        }
2372
-        return $otherObject;
2373
-    }
2374
-
2375
-
2376
-    /**
2377
-     * Removes ALL the related things for the $relationName.
2378
-     *
2379
-     * @param string $relationName
2380
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2381
-     * @return EE_Base_Class
2382
-     * @throws ReflectionException
2383
-     * @throws InvalidArgumentException
2384
-     * @throws InvalidInterfaceException
2385
-     * @throws InvalidDataTypeException
2386
-     * @throws EE_Error
2387
-     */
2388
-    public function _remove_relations($relationName, $where_query_params = array())
2389
-    {
2390
-        if ($this->ID()) {
2391
-            //if this exists in the DB, save the relation change to the DB too
2392
-            $otherObjects = $this->get_model()->remove_relations(
2393
-                $this,
2394
-                $relationName,
2395
-                $where_query_params
2396
-            );
2397
-            $this->clear_cache(
2398
-                $relationName,
2399
-                null,
2400
-                true
2401
-            );
2402
-        } else {
2403
-            //this doesn't exist in the DB, just remove it from the cache
2404
-            $otherObjects = $this->clear_cache(
2405
-                $relationName,
2406
-                null,
2407
-                true
2408
-            );
2409
-        }
2410
-        if (is_array($otherObjects)) {
2411
-            foreach ($otherObjects as $otherObject) {
2412
-                $otherObject->clear_cache(
2413
-                    $this->get_model()->get_this_model_name(),
2414
-                    $this
2415
-                );
2416
-            }
2417
-        }
2418
-        return $otherObjects;
2419
-    }
2420
-
2421
-
2422
-    /**
2423
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2424
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2425
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2426
-     * because we want to get even deleted items etc.
2427
-     *
2428
-     * @param string $relationName key in the model's _model_relations array
2429
-     * @param array  $query_params like EEM_Base::get_all
2430
-     * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2431
-     *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2432
-     *                             results if you want IDs
2433
-     * @throws ReflectionException
2434
-     * @throws InvalidArgumentException
2435
-     * @throws InvalidInterfaceException
2436
-     * @throws InvalidDataTypeException
2437
-     * @throws EE_Error
2438
-     */
2439
-    public function get_many_related($relationName, $query_params = array())
2440
-    {
2441
-        if ($this->ID()) {
2442
-            //this exists in the DB, so get the related things from either the cache or the DB
2443
-            //if there are query parameters, forget about caching the related model objects.
2444
-            if ($query_params) {
2445
-                $related_model_objects = $this->get_model()->get_all_related(
2446
-                    $this,
2447
-                    $relationName,
2448
-                    $query_params
2449
-                );
2450
-            } else {
2451
-                //did we already cache the result of this query?
2452
-                $cached_results = $this->get_all_from_cache($relationName);
2453
-                if (! $cached_results) {
2454
-                    $related_model_objects = $this->get_model()->get_all_related(
2455
-                        $this,
2456
-                        $relationName,
2457
-                        $query_params
2458
-                    );
2459
-                    //if no query parameters were passed, then we got all the related model objects
2460
-                    //for that relation. We can cache them then.
2461
-                    foreach ($related_model_objects as $related_model_object) {
2462
-                        $this->cache($relationName, $related_model_object);
2463
-                    }
2464
-                } else {
2465
-                    $related_model_objects = $cached_results;
2466
-                }
2467
-            }
2468
-        } else {
2469
-            //this doesn't exist in the DB, so just get the related things from the cache
2470
-            $related_model_objects = $this->get_all_from_cache($relationName);
2471
-        }
2472
-        return $related_model_objects;
2473
-    }
2474
-
2475
-
2476
-    /**
2477
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2478
-     * unless otherwise specified in the $query_params
2479
-     *
2480
-     * @param string $relation_name  model_name like 'Event', or 'Registration'
2481
-     * @param array  $query_params   like EEM_Base::get_all's
2482
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2483
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2484
-     *                               that by the setting $distinct to TRUE;
2485
-     * @return int
2486
-     * @throws ReflectionException
2487
-     * @throws InvalidArgumentException
2488
-     * @throws InvalidInterfaceException
2489
-     * @throws InvalidDataTypeException
2490
-     * @throws EE_Error
2491
-     */
2492
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2493
-    {
2494
-        return $this->get_model()->count_related(
2495
-            $this,
2496
-            $relation_name,
2497
-            $query_params,
2498
-            $field_to_count,
2499
-            $distinct
2500
-        );
2501
-    }
2502
-
2503
-
2504
-    /**
2505
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2506
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2507
-     *
2508
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2509
-     * @param array  $query_params  like EEM_Base::get_all's
2510
-     * @param string $field_to_sum  name of field to count by.
2511
-     *                              By default, uses primary key
2512
-     *                              (which doesn't make much sense, so you should probably change it)
2513
-     * @return int
2514
-     * @throws ReflectionException
2515
-     * @throws InvalidArgumentException
2516
-     * @throws InvalidInterfaceException
2517
-     * @throws InvalidDataTypeException
2518
-     * @throws EE_Error
2519
-     */
2520
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2521
-    {
2522
-        return $this->get_model()->sum_related(
2523
-            $this,
2524
-            $relation_name,
2525
-            $query_params,
2526
-            $field_to_sum
2527
-        );
2528
-    }
2529
-
2530
-
2531
-    /**
2532
-     * Gets the first (ie, one) related model object of the specified type.
2533
-     *
2534
-     * @param string $relationName key in the model's _model_relations array
2535
-     * @param array  $query_params like EEM_Base::get_all
2536
-     * @return EE_Base_Class (not an array, a single object)
2537
-     * @throws ReflectionException
2538
-     * @throws InvalidArgumentException
2539
-     * @throws InvalidInterfaceException
2540
-     * @throws InvalidDataTypeException
2541
-     * @throws EE_Error
2542
-     */
2543
-    public function get_first_related($relationName, $query_params = array())
2544
-    {
2545
-        $model = $this->get_model();
2546
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2547
-            //if they've provided some query parameters, don't bother trying to cache the result
2548
-            //also make sure we're not caching the result of get_first_related
2549
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2550
-            if ($query_params
2551
-                || ! $model->related_settings_for($relationName)
2552
-                     instanceof
2553
-                     EE_Belongs_To_Relation
2554
-            ) {
2555
-                $related_model_object = $model->get_first_related(
2556
-                    $this,
2557
-                    $relationName,
2558
-                    $query_params
2559
-                );
2560
-            } else {
2561
-                //first, check if we've already cached the result of this query
2562
-                $cached_result = $this->get_one_from_cache($relationName);
2563
-                if (! $cached_result) {
2564
-                    $related_model_object = $model->get_first_related(
2565
-                        $this,
2566
-                        $relationName,
2567
-                        $query_params
2568
-                    );
2569
-                    $this->cache($relationName, $related_model_object);
2570
-                } else {
2571
-                    $related_model_object = $cached_result;
2572
-                }
2573
-            }
2574
-        } else {
2575
-            $related_model_object = null;
2576
-            // this doesn't exist in the Db,
2577
-            // but maybe the relation is of type belongs to, and so the related thing might
2578
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2579
-                $related_model_object = $model->get_first_related(
2580
-                    $this,
2581
-                    $relationName,
2582
-                    $query_params
2583
-                );
2584
-            }
2585
-            // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586
-            // just get what's cached on this object
2587
-            if (! $related_model_object) {
2588
-                $related_model_object = $this->get_one_from_cache($relationName);
2589
-            }
2590
-        }
2591
-        return $related_model_object;
2592
-    }
2593
-
2594
-
2595
-    /**
2596
-     * Does a delete on all related objects of type $relationName and removes
2597
-     * the current model object's relation to them. If they can't be deleted (because
2598
-     * of blocking related model objects) does nothing. If the related model objects are
2599
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2600
-     * If this model object doesn't exist yet in the DB, just removes its related things
2601
-     *
2602
-     * @param string $relationName
2603
-     * @param array  $query_params like EEM_Base::get_all's
2604
-     * @return int how many deleted
2605
-     * @throws ReflectionException
2606
-     * @throws InvalidArgumentException
2607
-     * @throws InvalidInterfaceException
2608
-     * @throws InvalidDataTypeException
2609
-     * @throws EE_Error
2610
-     */
2611
-    public function delete_related($relationName, $query_params = array())
2612
-    {
2613
-        if ($this->ID()) {
2614
-            $count = $this->get_model()->delete_related(
2615
-                $this,
2616
-                $relationName,
2617
-                $query_params
2618
-            );
2619
-        } else {
2620
-            $count = count($this->get_all_from_cache($relationName));
2621
-            $this->clear_cache($relationName, null, true);
2622
-        }
2623
-        return $count;
2624
-    }
2625
-
2626
-
2627
-    /**
2628
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2629
-     * the current model object's relation to them. If they can't be deleted (because
2630
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2631
-     * If the related thing isn't a soft-deletable model object, this function is identical
2632
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2633
-     *
2634
-     * @param string $relationName
2635
-     * @param array  $query_params like EEM_Base::get_all's
2636
-     * @return int how many deleted (including those soft deleted)
2637
-     * @throws ReflectionException
2638
-     * @throws InvalidArgumentException
2639
-     * @throws InvalidInterfaceException
2640
-     * @throws InvalidDataTypeException
2641
-     * @throws EE_Error
2642
-     */
2643
-    public function delete_related_permanently($relationName, $query_params = array())
2644
-    {
2645
-        if ($this->ID()) {
2646
-            $count = $this->get_model()->delete_related_permanently(
2647
-                $this,
2648
-                $relationName,
2649
-                $query_params
2650
-            );
2651
-        } else {
2652
-            $count = count($this->get_all_from_cache($relationName));
2653
-        }
2654
-        $this->clear_cache($relationName, null, true);
2655
-        return $count;
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     * is_set
2661
-     * Just a simple utility function children can use for checking if property exists
2662
-     *
2663
-     * @access  public
2664
-     * @param  string $field_name property to check
2665
-     * @return bool                              TRUE if existing,FALSE if not.
2666
-     */
2667
-    public function is_set($field_name)
2668
-    {
2669
-        return isset($this->_fields[ $field_name ]);
2670
-    }
2671
-
2672
-
2673
-    /**
2674
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2675
-     * EE_Error exception if they don't
2676
-     *
2677
-     * @param  mixed (string|array) $properties properties to check
2678
-     * @throws EE_Error
2679
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2680
-     */
2681
-    protected function _property_exists($properties)
2682
-    {
2683
-        foreach ((array) $properties as $property_name) {
2684
-            //first make sure this property exists
2685
-            if (! $this->_fields[ $property_name ]) {
2686
-                throw new EE_Error(
2687
-                    sprintf(
2688
-                        esc_html__(
2689
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2690
-                            'event_espresso'
2691
-                        ),
2692
-                        $property_name
2693
-                    )
2694
-                );
2695
-            }
2696
-        }
2697
-        return true;
2698
-    }
2699
-
2700
-
2701
-    /**
2702
-     * This simply returns an array of model fields for this object
2703
-     *
2704
-     * @return array
2705
-     * @throws ReflectionException
2706
-     * @throws InvalidArgumentException
2707
-     * @throws InvalidInterfaceException
2708
-     * @throws InvalidDataTypeException
2709
-     * @throws EE_Error
2710
-     */
2711
-    public function model_field_array()
2712
-    {
2713
-        $fields     = $this->get_model()->field_settings(false);
2714
-        $properties = array();
2715
-        //remove prepended underscore
2716
-        foreach ($fields as $field_name => $settings) {
2717
-            $properties[ $field_name ] = $this->get($field_name);
2718
-        }
2719
-        return $properties;
2720
-    }
2721
-
2722
-
2723
-    /**
2724
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2725
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2726
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2727
-     * Instead of requiring a plugin to extend the EE_Base_Class
2728
-     * (which works fine is there's only 1 plugin, but when will that happen?)
2729
-     * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2730
-     * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2731
-     * and accepts 2 arguments: the object on which the function was called,
2732
-     * and an array of the original arguments passed to the function.
2733
-     * Whatever their callback function returns will be returned by this function.
2734
-     * Example: in functions.php (or in a plugin):
2735
-     *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2736
-     *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2737
-     *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2738
-     *          return $previousReturnValue.$returnString;
2739
-     *      }
2740
-     * require('EE_Answer.class.php');
2741
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2742
-     * echo $answer->my_callback('monkeys',100);
2743
-     * //will output "you called my_callback! and passed args:monkeys,100"
2744
-     *
2745
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2746
-     * @param array  $args       array of original arguments passed to the function
2747
-     * @throws EE_Error
2748
-     * @return mixed whatever the plugin which calls add_filter decides
2749
-     */
2750
-    public function __call($methodName, $args)
2751
-    {
2752
-        $className = get_class($this);
2753
-        $tagName   = "FHEE__{$className}__{$methodName}";
2754
-        if (! has_filter($tagName)) {
2755
-            throw new EE_Error(
2756
-                sprintf(
2757
-                    esc_html__(
2758
-                        "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;}",
2759
-                        'event_espresso'
2760
-                    ),
2761
-                    $methodName,
2762
-                    $className,
2763
-                    $tagName
2764
-                )
2765
-            );
2766
-        }
2767
-        return apply_filters($tagName, null, $this, $args);
2768
-    }
2769
-
2770
-
2771
-    /**
2772
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2773
-     * A $previous_value can be specified in case there are many meta rows with the same key
2774
-     *
2775
-     * @param string $meta_key
2776
-     * @param mixed  $meta_value
2777
-     * @param mixed  $previous_value
2778
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2779
-     *                  NOTE: if the values haven't changed, returns 0
2780
-     * @throws InvalidArgumentException
2781
-     * @throws InvalidInterfaceException
2782
-     * @throws InvalidDataTypeException
2783
-     * @throws EE_Error
2784
-     * @throws ReflectionException
2785
-     */
2786
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2787
-    {
2788
-        $query_params = array(
2789
-            array(
2790
-                'EXM_key'  => $meta_key,
2791
-                'OBJ_ID'   => $this->ID(),
2792
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2793
-            ),
2794
-        );
2795
-        if ($previous_value !== null) {
2796
-            $query_params[0]['EXM_value'] = $meta_value;
2797
-        }
2798
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
-        if (! $existing_rows_like_that) {
2800
-            return $this->add_extra_meta($meta_key, $meta_value);
2801
-        }
2802
-        foreach ($existing_rows_like_that as $existing_row) {
2803
-            $existing_row->save(array('EXM_value' => $meta_value));
2804
-        }
2805
-        return count($existing_rows_like_that);
2806
-    }
2807
-
2808
-
2809
-    /**
2810
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2811
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2812
-     * extra meta row was entered, false if not
2813
-     *
2814
-     * @param string  $meta_key
2815
-     * @param mixed   $meta_value
2816
-     * @param boolean $unique
2817
-     * @return boolean
2818
-     * @throws InvalidArgumentException
2819
-     * @throws InvalidInterfaceException
2820
-     * @throws InvalidDataTypeException
2821
-     * @throws EE_Error
2822
-     * @throws ReflectionException
2823
-     * @throws ReflectionException
2824
-     */
2825
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2826
-    {
2827
-        if ($unique) {
2828
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2829
-                array(
2830
-                    array(
2831
-                        'EXM_key'  => $meta_key,
2832
-                        'OBJ_ID'   => $this->ID(),
2833
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2834
-                    ),
2835
-                )
2836
-            );
2837
-            if ($existing_extra_meta) {
2838
-                return false;
2839
-            }
2840
-        }
2841
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2842
-            array(
2843
-                'EXM_key'   => $meta_key,
2844
-                'EXM_value' => $meta_value,
2845
-                'OBJ_ID'    => $this->ID(),
2846
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2847
-            )
2848
-        );
2849
-        $new_extra_meta->save();
2850
-        return true;
2851
-    }
2852
-
2853
-
2854
-    /**
2855
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2856
-     * is specified, only deletes extra meta records with that value.
2857
-     *
2858
-     * @param string $meta_key
2859
-     * @param mixed  $meta_value
2860
-     * @return int number of extra meta rows deleted
2861
-     * @throws InvalidArgumentException
2862
-     * @throws InvalidInterfaceException
2863
-     * @throws InvalidDataTypeException
2864
-     * @throws EE_Error
2865
-     * @throws ReflectionException
2866
-     */
2867
-    public function delete_extra_meta($meta_key, $meta_value = null)
2868
-    {
2869
-        $query_params = array(
2870
-            array(
2871
-                'EXM_key'  => $meta_key,
2872
-                'OBJ_ID'   => $this->ID(),
2873
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2874
-            ),
2875
-        );
2876
-        if ($meta_value !== null) {
2877
-            $query_params[0]['EXM_value'] = $meta_value;
2878
-        }
2879
-        return EEM_Extra_Meta::instance()->delete($query_params);
2880
-    }
2881
-
2882
-
2883
-    /**
2884
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2885
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2886
-     * You can specify $default is case you haven't found the extra meta
2887
-     *
2888
-     * @param string  $meta_key
2889
-     * @param boolean $single
2890
-     * @param mixed   $default if we don't find anything, what should we return?
2891
-     * @return mixed single value if $single; array if ! $single
2892
-     * @throws ReflectionException
2893
-     * @throws InvalidArgumentException
2894
-     * @throws InvalidInterfaceException
2895
-     * @throws InvalidDataTypeException
2896
-     * @throws EE_Error
2897
-     */
2898
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2899
-    {
2900
-        if ($single) {
2901
-            $result = $this->get_first_related(
2902
-                'Extra_Meta',
2903
-                array(array('EXM_key' => $meta_key))
2904
-            );
2905
-            if ($result instanceof EE_Extra_Meta) {
2906
-                return $result->value();
2907
-            }
2908
-        } else {
2909
-            $results = $this->get_many_related(
2910
-                'Extra_Meta',
2911
-                array(array('EXM_key' => $meta_key))
2912
-            );
2913
-            if ($results) {
2914
-                $values = array();
2915
-                foreach ($results as $result) {
2916
-                    if ($result instanceof EE_Extra_Meta) {
2917
-                        $values[ $result->ID() ] = $result->value();
2918
-                    }
2919
-                }
2920
-                return $values;
2921
-            }
2922
-        }
2923
-        //if nothing discovered yet return default.
2924
-        return apply_filters(
2925
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2926
-            $default,
2927
-            $meta_key,
2928
-            $single,
2929
-            $this
2930
-        );
2931
-    }
2932
-
2933
-
2934
-    /**
2935
-     * Returns a simple array of all the extra meta associated with this model object.
2936
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2937
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2938
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2939
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2940
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2941
-     * finally the extra meta's value as each sub-value. (eg
2942
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2943
-     *
2944
-     * @param boolean $one_of_each_key
2945
-     * @return array
2946
-     * @throws ReflectionException
2947
-     * @throws InvalidArgumentException
2948
-     * @throws InvalidInterfaceException
2949
-     * @throws InvalidDataTypeException
2950
-     * @throws EE_Error
2951
-     */
2952
-    public function all_extra_meta_array($one_of_each_key = true)
2953
-    {
2954
-        $return_array = array();
2955
-        if ($one_of_each_key) {
2956
-            $extra_meta_objs = $this->get_many_related(
2957
-                'Extra_Meta',
2958
-                array('group_by' => 'EXM_key')
2959
-            );
2960
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2961
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2963
-                }
2964
-            }
2965
-        } else {
2966
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2967
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2968
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
-                        $return_array[ $extra_meta_obj->key() ] = array();
2971
-                    }
2972
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2973
-                }
2974
-            }
2975
-        }
2976
-        return $return_array;
2977
-    }
2978
-
2979
-
2980
-    /**
2981
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2982
-     *
2983
-     * @return string
2984
-     * @throws ReflectionException
2985
-     * @throws InvalidArgumentException
2986
-     * @throws InvalidInterfaceException
2987
-     * @throws InvalidDataTypeException
2988
-     * @throws EE_Error
2989
-     */
2990
-    public function name()
2991
-    {
2992
-        //find a field that's not a text field
2993
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2994
-        if ($field_we_can_use) {
2995
-            return $this->get($field_we_can_use->get_name());
2996
-        }
2997
-        $first_few_properties = $this->model_field_array();
2998
-        $first_few_properties = array_slice($first_few_properties, 0, 3);
2999
-        $name_parts           = array();
3000
-        foreach ($first_few_properties as $name => $value) {
3001
-            $name_parts[] = "$name:$value";
3002
-        }
3003
-        return implode(',', $name_parts);
3004
-    }
3005
-
3006
-
3007
-    /**
3008
-     * in_entity_map
3009
-     * Checks if this model object has been proven to already be in the entity map
3010
-     *
3011
-     * @return boolean
3012
-     * @throws ReflectionException
3013
-     * @throws InvalidArgumentException
3014
-     * @throws InvalidInterfaceException
3015
-     * @throws InvalidDataTypeException
3016
-     * @throws EE_Error
3017
-     */
3018
-    public function in_entity_map()
3019
-    {
3020
-        // well, if we looked, did we find it in the entity map?
3021
-        return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3022
-    }
3023
-
3024
-
3025
-    /**
3026
-     * refresh_from_db
3027
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
3028
-     *
3029
-     * @throws ReflectionException
3030
-     * @throws InvalidArgumentException
3031
-     * @throws InvalidInterfaceException
3032
-     * @throws InvalidDataTypeException
3033
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3034
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3035
-     */
3036
-    public function refresh_from_db()
3037
-    {
3038
-        if ($this->ID() && $this->in_entity_map()) {
3039
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
3040
-        } else {
3041
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3042
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
3043
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3044
-            //absolutely nothing in it for this ID
3045
-            if (WP_DEBUG) {
3046
-                throw new EE_Error(
3047
-                    sprintf(
3048
-                        esc_html__('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.',
3049
-                            'event_espresso'),
3050
-                        $this->ID(),
3051
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3053
-                    )
3054
-                );
3055
-            }
3056
-        }
3057
-    }
3058
-
3059
-
3060
-    /**
3061
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3062
-     * (probably a bad assumption they have made, oh well)
3063
-     *
3064
-     * @return string
3065
-     */
3066
-    public function __toString()
3067
-    {
3068
-        try {
3069
-            return sprintf('%s (%s)', $this->name(), $this->ID());
3070
-        } catch (Exception $e) {
3071
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3072
-            return '';
3073
-        }
3074
-    }
3075
-
3076
-
3077
-    /**
3078
-     * Clear related model objects if they're already in the DB, because otherwise when we
3079
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
3080
-     * This means if we have made changes to those related model objects, and want to unserialize
3081
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
3082
-     * Instead, those related model objects should be directly serialized and stored.
3083
-     * Eg, the following won't work:
3084
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3085
-     * $att = $reg->attendee();
3086
-     * $att->set( 'ATT_fname', 'Dirk' );
3087
-     * update_option( 'my_option', serialize( $reg ) );
3088
-     * //END REQUEST
3089
-     * //START NEXT REQUEST
3090
-     * $reg = get_option( 'my_option' );
3091
-     * $reg->attendee()->save();
3092
-     * And would need to be replace with:
3093
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3094
-     * $att = $reg->attendee();
3095
-     * $att->set( 'ATT_fname', 'Dirk' );
3096
-     * update_option( 'my_option', serialize( $reg ) );
3097
-     * //END REQUEST
3098
-     * //START NEXT REQUEST
3099
-     * $att = get_option( 'my_option' );
3100
-     * $att->save();
3101
-     *
3102
-     * @return array
3103
-     * @throws ReflectionException
3104
-     * @throws InvalidArgumentException
3105
-     * @throws InvalidInterfaceException
3106
-     * @throws InvalidDataTypeException
3107
-     * @throws EE_Error
3108
-     */
3109
-    public function __sleep()
3110
-    {
3111
-        $model = $this->get_model();
3112
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
-                $classname = 'EE_' . $model->get_this_model_name();
3115
-                if (
3116
-                    $this->get_one_from_cache($relation_name) instanceof $classname
3117
-                    && $this->get_one_from_cache($relation_name)->ID()
3118
-                ) {
3119
-                    $this->clear_cache(
3120
-                        $relation_name,
3121
-                        $this->get_one_from_cache($relation_name)->ID()
3122
-                    );
3123
-                }
3124
-            }
3125
-        }
3126
-        $this->_props_n_values_provided_in_constructor = array();
3127
-        $properties_to_serialize                       = get_object_vars($this);
3128
-        //don't serialize the model. It's big and that risks recursion
3129
-        unset($properties_to_serialize['_model']);
3130
-        return array_keys($properties_to_serialize);
3131
-    }
3132
-
3133
-
3134
-    /**
3135
-     * restore _props_n_values_provided_in_constructor
3136
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3137
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
3138
-     * At best, you would only be able to detect if state change has occurred during THIS request.
3139
-     */
3140
-    public function __wakeup()
3141
-    {
3142
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
3143
-    }
3144
-
3145
-
3146
-    /**
3147
-     * Usage of this magic method is to ensure any internally cached references to object instances that must remain
3148
-     * distinct with the clone host instance are also cloned.
3149
-     */
3150
-    public function __clone()
3151
-    {
3152
-        //handle DateTimes (this is handled in here because there's no one specific child class that uses datetimes).
3153
-        foreach ($this->_fields as $field => $value) {
3154
-            if ($value instanceof DateTime) {
3155
-                $this->_fields[$field] = clone $value;
3156
-            }
3157
-        }
3158
-    }
18
+	/**
19
+	 * This is an array of the original properties and values provided during construction
20
+	 * of this model object. (keys are model field names, values are their values).
21
+	 * This list is important to remember so that when we are merging data from the db, we know
22
+	 * which values to override and which to not override.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $_props_n_values_provided_in_constructor;
27
+
28
+	/**
29
+	 * Timezone
30
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
+	 * access to it.
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $_timezone;
38
+
39
+	/**
40
+	 * date format
41
+	 * pattern or format for displaying dates
42
+	 *
43
+	 * @var string $_dt_frmt
44
+	 */
45
+	protected $_dt_frmt;
46
+
47
+	/**
48
+	 * time format
49
+	 * pattern or format for displaying time
50
+	 *
51
+	 * @var string $_tm_frmt
52
+	 */
53
+	protected $_tm_frmt;
54
+
55
+	/**
56
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
57
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
58
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected $_cached_properties = array();
64
+
65
+	/**
66
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
67
+	 * single
68
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
+	 * all others have an array)
71
+	 *
72
+	 * @var array
73
+	 */
74
+	protected $_model_relations = array();
75
+
76
+	/**
77
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
+	 *
80
+	 * @var array
81
+	 */
82
+	protected $_fields = array();
83
+
84
+	/**
85
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
86
+	 * For example, we might create model objects intended to only be used for the duration
87
+	 * of this request and to be thrown away, and if they were accidentally saved
88
+	 * it would be a bug.
89
+	 */
90
+	protected $_allow_persist = true;
91
+
92
+	/**
93
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
94
+	 */
95
+	protected $_has_changes = false;
96
+
97
+	/**
98
+	 * @var EEM_Base
99
+	 */
100
+	protected $_model;
101
+
102
+	/**
103
+	 * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
+	 * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
+	 * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
+	 * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
+	 * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
+	 * array as:
109
+	 * array(
110
+	 *  'Registration_Count' => 24
111
+	 * );
112
+	 * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
+	 * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
+	 * info)
115
+	 *
116
+	 * @var array
117
+	 */
118
+	protected $custom_selection_results = array();
119
+
120
+
121
+	/**
122
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
+	 * play nice
124
+	 *
125
+	 * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
128
+	 * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
+	 *                                                         corresponding db model or not.
130
+	 * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
+	 *                                                         be in when instantiating a EE_Base_Class object.
132
+	 * @param array   $date_formats                            An array of date formats to set on construct where first
133
+	 *                                                         value is the date_format and second value is the time
134
+	 *                                                         format.
135
+	 * @throws InvalidArgumentException
136
+	 * @throws InvalidInterfaceException
137
+	 * @throws InvalidDataTypeException
138
+	 * @throws EE_Error
139
+	 * @throws ReflectionException
140
+	 */
141
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
+	{
143
+		$className = get_class($this);
144
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
+		$model        = $this->get_model();
146
+		$model_fields = $model->field_settings(false);
147
+		// ensure $fieldValues is an array
148
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
+		// verify client code has not passed any invalid field names
150
+		foreach ($fieldValues as $field_name => $field_value) {
151
+			if (! isset($model_fields[ $field_name ])) {
152
+				throw new EE_Error(
153
+					sprintf(
154
+						esc_html__(
155
+							'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
+							'event_espresso'
157
+						),
158
+						$field_name,
159
+						get_class($this),
160
+						implode(', ', array_keys($model_fields))
161
+					)
162
+				);
163
+			}
164
+		}
165
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
+		if (! empty($date_formats) && is_array($date_formats)) {
167
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
+		} else {
169
+			//set default formats for date and time
170
+			$this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
+			$this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
+		}
173
+		//if db model is instantiating
174
+		if ($bydb) {
175
+			//client code has indicated these field values are from the database
176
+			foreach ($model_fields as $fieldName => $field) {
177
+				$this->set_from_db(
178
+					$fieldName,
179
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
+				);
181
+			}
182
+		} else {
183
+			//we're constructing a brand
184
+			//new instance of the model object. Generally, this means we'll need to do more field validation
185
+			foreach ($model_fields as $fieldName => $field) {
186
+				$this->set(
187
+					$fieldName,
188
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
+				);
190
+			}
191
+		}
192
+		//remember what values were passed to this constructor
193
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
194
+		//remember in entity mapper
195
+		if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
+			$model->add_to_entity_map($this);
197
+		}
198
+		//setup all the relations
199
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
+				$this->_model_relations[ $relation_name ] = null;
202
+			} else {
203
+				$this->_model_relations[ $relation_name ] = array();
204
+			}
205
+		}
206
+		/**
207
+		 * Action done at the end of each model object construction
208
+		 *
209
+		 * @param EE_Base_Class $this the model object just created
210
+		 */
211
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
+	}
213
+
214
+
215
+	/**
216
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
217
+	 *
218
+	 * @return boolean
219
+	 */
220
+	public function allow_persist()
221
+	{
222
+		return $this->_allow_persist;
223
+	}
224
+
225
+
226
+	/**
227
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
228
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
+	 * you got new information that somehow made you change your mind.
230
+	 *
231
+	 * @param boolean $allow_persist
232
+	 * @return boolean
233
+	 */
234
+	public function set_allow_persist($allow_persist)
235
+	{
236
+		return $this->_allow_persist = $allow_persist;
237
+	}
238
+
239
+
240
+	/**
241
+	 * Gets the field's original value when this object was constructed during this request.
242
+	 * This can be helpful when determining if a model object has changed or not
243
+	 *
244
+	 * @param string $field_name
245
+	 * @return mixed|null
246
+	 * @throws ReflectionException
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidDataTypeException
250
+	 * @throws EE_Error
251
+	 */
252
+	public function get_original($field_name)
253
+	{
254
+		if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
256
+		) {
257
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
+		}
259
+		return null;
260
+	}
261
+
262
+
263
+	/**
264
+	 * @param EE_Base_Class $obj
265
+	 * @return string
266
+	 */
267
+	public function get_class($obj)
268
+	{
269
+		return get_class($obj);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Overrides parent because parent expects old models.
275
+	 * This also doesn't do any validation, and won't work for serialized arrays
276
+	 *
277
+	 * @param    string $field_name
278
+	 * @param    mixed  $field_value
279
+	 * @param bool      $use_default
280
+	 * @throws InvalidArgumentException
281
+	 * @throws InvalidInterfaceException
282
+	 * @throws InvalidDataTypeException
283
+	 * @throws EE_Error
284
+	 * @throws ReflectionException
285
+	 * @throws ReflectionException
286
+	 * @throws ReflectionException
287
+	 */
288
+	public function set($field_name, $field_value, $use_default = false)
289
+	{
290
+		// if not using default and nothing has changed, and object has already been setup (has ID),
291
+		// then don't do anything
292
+		if (
293
+			! $use_default
294
+			&& $this->_fields[ $field_name ] === $field_value
295
+			&& $this->ID()
296
+		) {
297
+			return;
298
+		}
299
+		$model              = $this->get_model();
300
+		$this->_has_changes = true;
301
+		$field_obj          = $model->field_settings_for($field_name);
302
+		if ($field_obj instanceof EE_Model_Field_Base) {
303
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
304
+			if ($field_obj instanceof EE_Datetime_Field) {
305
+				$field_obj->set_timezone($this->_timezone);
306
+				$field_obj->set_date_format($this->_dt_frmt);
307
+				$field_obj->set_time_format($this->_tm_frmt);
308
+			}
309
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
310
+			//should the value be null?
311
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
+				$this->_fields[ $field_name ] = $field_obj->get_default_value();
313
+				/**
314
+				 * To save having to refactor all the models, if a default value is used for a
315
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
+				 * object.
318
+				 *
319
+				 * @since 4.6.10+
320
+				 */
321
+				if (
322
+					$field_obj instanceof EE_Datetime_Field
323
+					&& $this->_fields[ $field_name ] !== null
324
+					&& ! $this->_fields[ $field_name ] instanceof DateTime
325
+				) {
326
+					empty($this->_fields[ $field_name ])
327
+						? $this->set($field_name, time())
328
+						: $this->set($field_name, $this->_fields[ $field_name ]);
329
+				}
330
+			} else {
331
+				$this->_fields[ $field_name ] = $holder_of_value;
332
+			}
333
+			//if we're not in the constructor...
334
+			//now check if what we set was a primary key
335
+			if (
336
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
+				$this->_props_n_values_provided_in_constructor
338
+				&& $field_value
339
+				&& $field_name === $model->primary_key_name()
340
+			) {
341
+				//if so, we want all this object's fields to be filled either with
342
+				//what we've explicitly set on this model
343
+				//or what we have in the db
344
+				// echo "setting primary key!";
345
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
346
+				$obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
+				foreach ($fields_on_model as $field_obj) {
348
+					if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
+						&& $field_obj->get_name() !== $field_name
350
+					) {
351
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
+					}
353
+				}
354
+				//oh this model object has an ID? well make sure its in the entity mapper
355
+				$model->add_to_entity_map($this);
356
+			}
357
+			//let's unset any cache for this field_name from the $_cached_properties property.
358
+			$this->_clear_cached_property($field_name);
359
+		} else {
360
+			throw new EE_Error(
361
+				sprintf(
362
+					esc_html__(
363
+						'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
+						'event_espresso'
365
+					),
366
+					$field_name
367
+				)
368
+			);
369
+		}
370
+	}
371
+
372
+
373
+	/**
374
+	 * Set custom select values for model.
375
+	 *
376
+	 * @param array $custom_select_values
377
+	 */
378
+	public function setCustomSelectsValues(array $custom_select_values)
379
+	{
380
+		$this->custom_selection_results = $custom_select_values;
381
+	}
382
+
383
+
384
+	/**
385
+	 * Returns the custom select value for the provided alias if its set.
386
+	 * If not set, returns null.
387
+	 *
388
+	 * @param string $alias
389
+	 * @return string|int|float|null
390
+	 */
391
+	public function getCustomSelect($alias)
392
+	{
393
+		return isset($this->custom_selection_results[ $alias ])
394
+			? $this->custom_selection_results[ $alias ]
395
+			: null;
396
+	}
397
+
398
+
399
+	/**
400
+	 * This sets the field value on the db column if it exists for the given $column_name or
401
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
+	 *
403
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
+	 * @param string $field_name  Must be the exact column name.
405
+	 * @param mixed  $field_value The value to set.
406
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
+	 * @throws InvalidArgumentException
408
+	 * @throws InvalidInterfaceException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws EE_Error
411
+	 * @throws ReflectionException
412
+	 */
413
+	public function set_field_or_extra_meta($field_name, $field_value)
414
+	{
415
+		if ($this->get_model()->has_field($field_name)) {
416
+			$this->set($field_name, $field_value);
417
+			return true;
418
+		}
419
+		//ensure this object is saved first so that extra meta can be properly related.
420
+		$this->save();
421
+		return $this->update_extra_meta($field_name, $field_value);
422
+	}
423
+
424
+
425
+	/**
426
+	 * This retrieves the value of the db column set on this class or if that's not present
427
+	 * it will attempt to retrieve from extra_meta if found.
428
+	 * Example Usage:
429
+	 * Via EE_Message child class:
430
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
433
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
+	 * value for those extra fields dynamically via the EE_message object.
435
+	 *
436
+	 * @param  string $field_name expecting the fully qualified field name.
437
+	 * @return mixed|null  value for the field if found.  null if not found.
438
+	 * @throws ReflectionException
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws EE_Error
443
+	 */
444
+	public function get_field_or_extra_meta($field_name)
445
+	{
446
+		if ($this->get_model()->has_field($field_name)) {
447
+			$column_value = $this->get($field_name);
448
+		} else {
449
+			//This isn't a column in the main table, let's see if it is in the extra meta.
450
+			$column_value = $this->get_extra_meta($field_name, true, null);
451
+		}
452
+		return $column_value;
453
+	}
454
+
455
+
456
+	/**
457
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
+	 *
462
+	 * @access public
463
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
+	 * @return void
465
+	 * @throws InvalidArgumentException
466
+	 * @throws InvalidInterfaceException
467
+	 * @throws InvalidDataTypeException
468
+	 * @throws EE_Error
469
+	 * @throws ReflectionException
470
+	 */
471
+	public function set_timezone($timezone = '')
472
+	{
473
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
+		//make sure we clear all cached properties because they won't be relevant now
475
+		$this->_clear_cached_properties();
476
+		//make sure we update field settings and the date for all EE_Datetime_Fields
477
+		$model_fields = $this->get_model()->field_settings(false);
478
+		foreach ($model_fields as $field_name => $field_obj) {
479
+			if ($field_obj instanceof EE_Datetime_Field) {
480
+				$field_obj->set_timezone($this->_timezone);
481
+				if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
+					EEH_DTT_Helper::setTimezone($this->_fields[$field_name], new DateTimeZone($this->_timezone));
483
+				}
484
+			}
485
+		}
486
+	}
487
+
488
+
489
+	/**
490
+	 * This just returns whatever is set for the current timezone.
491
+	 *
492
+	 * @access public
493
+	 * @return string timezone string
494
+	 */
495
+	public function get_timezone()
496
+	{
497
+		return $this->_timezone;
498
+	}
499
+
500
+
501
+	/**
502
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
503
+	 * internally instead of wp set date format options
504
+	 *
505
+	 * @since 4.6
506
+	 * @param string $format should be a format recognizable by PHP date() functions.
507
+	 */
508
+	public function set_date_format($format)
509
+	{
510
+		$this->_dt_frmt = $format;
511
+		//clear cached_properties because they won't be relevant now.
512
+		$this->_clear_cached_properties();
513
+	}
514
+
515
+
516
+	/**
517
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
518
+	 * class internally instead of wp set time format options.
519
+	 *
520
+	 * @since 4.6
521
+	 * @param string $format should be a format recognizable by PHP date() functions.
522
+	 */
523
+	public function set_time_format($format)
524
+	{
525
+		$this->_tm_frmt = $format;
526
+		//clear cached_properties because they won't be relevant now.
527
+		$this->_clear_cached_properties();
528
+	}
529
+
530
+
531
+	/**
532
+	 * This returns the current internal set format for the date and time formats.
533
+	 *
534
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
+	 *                             where the first value is the date format and the second value is the time format.
536
+	 * @return mixed string|array
537
+	 */
538
+	public function get_format($full = true)
539
+	{
540
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
+	}
542
+
543
+
544
+	/**
545
+	 * cache
546
+	 * stores the passed model object on the current model object.
547
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
+	 *
549
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
+	 *                                       'Registration' associated with this model object
551
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
+	 *                                       that could be a payment or a registration)
553
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
+	 *                                       items which will be stored in an array on this object
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidArgumentException
557
+	 * @throws InvalidInterfaceException
558
+	 * @throws InvalidDataTypeException
559
+	 * @throws EE_Error
560
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
+	 *                                       related thing, no array)
562
+	 */
563
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
+	{
565
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
+		if (! $object_to_cache instanceof EE_Base_Class) {
567
+			return false;
568
+		}
569
+		// also get "how" the object is related, or throw an error
570
+		if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
+			throw new EE_Error(
572
+				sprintf(
573
+					esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
+					$relationName,
575
+					get_class($this)
576
+				)
577
+			);
578
+		}
579
+		// how many things are related ?
580
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
+			// if it's a "belongs to" relationship, then there's only one related model object
582
+			// eg, if this is a registration, there's only 1 attendee for it
583
+			// so for these model objects just set it to be cached
584
+			$this->_model_relations[ $relationName ] = $object_to_cache;
585
+			$return                                  = true;
586
+		} else {
587
+			// otherwise, this is the "many" side of a one to many relationship,
588
+			// so we'll add the object to the array of related objects for that type.
589
+			// eg: if this is an event, there are many registrations for that event,
590
+			// so we cache the registrations in an array
591
+			if (! is_array($this->_model_relations[ $relationName ])) {
592
+				// if for some reason, the cached item is a model object,
593
+				// then stick that in the array, otherwise start with an empty array
594
+				$this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
+														   instanceof
596
+														   EE_Base_Class
597
+					? array($this->_model_relations[ $relationName ]) : array();
598
+			}
599
+			// first check for a cache_id which is normally empty
600
+			if (! empty($cache_id)) {
601
+				// if the cache_id exists, then it means we are purposely trying to cache this
602
+				// with a known key that can then be used to retrieve the object later on
603
+				$this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
+				$return                                               = $cache_id;
605
+			} elseif ($object_to_cache->ID()) {
606
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
607
+				$this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
+				$return                                                            = $object_to_cache->ID();
609
+			} else {
610
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
+				$this->_model_relations[ $relationName ][] = $object_to_cache;
612
+				// move the internal pointer to the end of the array
613
+				end($this->_model_relations[ $relationName ]);
614
+				// and grab the key so that we can return it
615
+				$return = key($this->_model_relations[ $relationName ]);
616
+			}
617
+		}
618
+		return $return;
619
+	}
620
+
621
+
622
+	/**
623
+	 * For adding an item to the cached_properties property.
624
+	 *
625
+	 * @access protected
626
+	 * @param string      $fieldname the property item the corresponding value is for.
627
+	 * @param mixed       $value     The value we are caching.
628
+	 * @param string|null $cache_type
629
+	 * @return void
630
+	 * @throws ReflectionException
631
+	 * @throws InvalidArgumentException
632
+	 * @throws InvalidInterfaceException
633
+	 * @throws InvalidDataTypeException
634
+	 * @throws EE_Error
635
+	 */
636
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
+	{
638
+		//first make sure this property exists
639
+		$this->get_model()->field_settings_for($fieldname);
640
+		$cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
+		$this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
+	}
643
+
644
+
645
+	/**
646
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
+	 * This also SETS the cache if we return the actual property!
648
+	 *
649
+	 * @param string $fieldname        the name of the property we're trying to retrieve
650
+	 * @param bool   $pretty
651
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
+	 *                                 (in cases where the same property may be used for different outputs
653
+	 *                                 - i.e. datetime, money etc.)
654
+	 *                                 It can also accept certain pre-defined "schema" strings
655
+	 *                                 to define how to output the property.
656
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
+	 * @return mixed                   whatever the value for the property is we're retrieving
658
+	 * @throws ReflectionException
659
+	 * @throws InvalidArgumentException
660
+	 * @throws InvalidInterfaceException
661
+	 * @throws InvalidDataTypeException
662
+	 * @throws EE_Error
663
+	 */
664
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
+	{
666
+		//verify the field exists
667
+		$model = $this->get_model();
668
+		$model->field_settings_for($fieldname);
669
+		$cache_type = $pretty ? 'pretty' : 'standard';
670
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
+		if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
+			return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
+		}
674
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
+		$this->_set_cached_property($fieldname, $value, $cache_type);
676
+		return $value;
677
+	}
678
+
679
+
680
+	/**
681
+	 * If the cache didn't fetch the needed item, this fetches it.
682
+	 *
683
+	 * @param string $fieldname
684
+	 * @param bool   $pretty
685
+	 * @param string $extra_cache_ref
686
+	 * @return mixed
687
+	 * @throws InvalidArgumentException
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws InvalidDataTypeException
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 */
693
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
+	{
695
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
696
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
+		if ($field_obj instanceof EE_Datetime_Field) {
698
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
+		}
700
+		if (! isset($this->_fields[ $fieldname ])) {
701
+			$this->_fields[ $fieldname ] = null;
702
+		}
703
+		$value = $pretty
704
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
+			: $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
+		return $value;
707
+	}
708
+
709
+
710
+	/**
711
+	 * set timezone, formats, and output for EE_Datetime_Field objects
712
+	 *
713
+	 * @param \EE_Datetime_Field $datetime_field
714
+	 * @param bool               $pretty
715
+	 * @param null               $date_or_time
716
+	 * @return void
717
+	 * @throws InvalidArgumentException
718
+	 * @throws InvalidInterfaceException
719
+	 * @throws InvalidDataTypeException
720
+	 * @throws EE_Error
721
+	 */
722
+	protected function _prepare_datetime_field(
723
+		EE_Datetime_Field $datetime_field,
724
+		$pretty = false,
725
+		$date_or_time = null
726
+	) {
727
+		$datetime_field->set_timezone($this->_timezone);
728
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
+		//set the output returned
731
+		switch ($date_or_time) {
732
+			case 'D' :
733
+				$datetime_field->set_date_time_output('date');
734
+				break;
735
+			case 'T' :
736
+				$datetime_field->set_date_time_output('time');
737
+				break;
738
+			default :
739
+				$datetime_field->set_date_time_output();
740
+		}
741
+	}
742
+
743
+
744
+	/**
745
+	 * This just takes care of clearing out the cached_properties
746
+	 *
747
+	 * @return void
748
+	 */
749
+	protected function _clear_cached_properties()
750
+	{
751
+		$this->_cached_properties = array();
752
+	}
753
+
754
+
755
+	/**
756
+	 * This just clears out ONE property if it exists in the cache
757
+	 *
758
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
+	 * @return void
760
+	 */
761
+	protected function _clear_cached_property($property_name)
762
+	{
763
+		if (isset($this->_cached_properties[ $property_name ])) {
764
+			unset($this->_cached_properties[ $property_name ]);
765
+		}
766
+	}
767
+
768
+
769
+	/**
770
+	 * Ensures that this related thing is a model object.
771
+	 *
772
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
774
+	 * @return EE_Base_Class
775
+	 * @throws ReflectionException
776
+	 * @throws InvalidArgumentException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws InvalidDataTypeException
779
+	 * @throws EE_Error
780
+	 */
781
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
+	{
783
+		$other_model_instance = self::_get_model_instance_with_name(
784
+			self::_get_model_classname($model_name),
785
+			$this->_timezone
786
+		);
787
+		return $other_model_instance->ensure_is_obj($object_or_id);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
793
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
796
+	 *
797
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
+	 *                                                     Eg 'Registration'
799
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
+	 *                                                     this is HasMany or HABTM.
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
+	 *                                                     relation from all
811
+	 */
812
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
+	{
814
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
+		$index_in_cache        = '';
816
+		if (! $relationship_to_model) {
817
+			throw new EE_Error(
818
+				sprintf(
819
+					esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
+					$relationName,
821
+					get_class($this)
822
+				)
823
+			);
824
+		}
825
+		if ($clear_all) {
826
+			$obj_removed                             = true;
827
+			$this->_model_relations[ $relationName ] = null;
828
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
+			$obj_removed                             = $this->_model_relations[ $relationName ];
830
+			$this->_model_relations[ $relationName ] = null;
831
+		} else {
832
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
+				&& $object_to_remove_or_index_into_array->ID()
834
+			) {
835
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
836
+				if (is_array($this->_model_relations[ $relationName ])
837
+					&& ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
+				) {
839
+					$index_found_at = null;
840
+					//find this object in the array even though it has a different key
841
+					foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
+						/** @noinspection TypeUnsafeComparisonInspection */
843
+						if (
844
+							$obj instanceof EE_Base_Class
845
+							&& (
846
+								$obj == $object_to_remove_or_index_into_array
847
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
+							)
849
+						) {
850
+							$index_found_at = $index;
851
+							break;
852
+						}
853
+					}
854
+					if ($index_found_at) {
855
+						$index_in_cache = $index_found_at;
856
+					} else {
857
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
+						//if it wasn't in it to begin with. So we're done
859
+						return $object_to_remove_or_index_into_array;
860
+					}
861
+				}
862
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
+					/** @noinspection TypeUnsafeComparisonInspection */
866
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
+						$index_in_cache = $index;
868
+					}
869
+				}
870
+			} else {
871
+				$index_in_cache = $object_to_remove_or_index_into_array;
872
+			}
873
+			//supposedly we've found it. But it could just be that the client code
874
+			//provided a bad index/object
875
+			if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
+				$obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
+				unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
+			} else {
879
+				//that thing was never cached anyways.
880
+				$obj_removed = null;
881
+			}
882
+		}
883
+		return $obj_removed;
884
+	}
885
+
886
+
887
+	/**
888
+	 * update_cache_after_object_save
889
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
+	 * obtained after being saved to the db
891
+	 *
892
+	 * @param string        $relationName       - the type of object that is cached
893
+	 * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
+	 * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
+	 * @return boolean TRUE on success, FALSE on fail
896
+	 * @throws ReflectionException
897
+	 * @throws InvalidArgumentException
898
+	 * @throws InvalidInterfaceException
899
+	 * @throws InvalidDataTypeException
900
+	 * @throws EE_Error
901
+	 */
902
+	public function update_cache_after_object_save(
903
+		$relationName,
904
+		EE_Base_Class $newly_saved_object,
905
+		$current_cache_id = ''
906
+	) {
907
+		// verify that incoming object is of the correct type
908
+		$obj_class = 'EE_' . $relationName;
909
+		if ($newly_saved_object instanceof $obj_class) {
910
+			/* @type EE_Base_Class $newly_saved_object */
911
+			// now get the type of relation
912
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
+			// if this is a 1:1 relationship
914
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
+				// then just replace the cached object with the newly saved object
916
+				$this->_model_relations[ $relationName ] = $newly_saved_object;
917
+				return true;
918
+				// or if it's some kind of sordid feral polyamorous relationship...
919
+			}
920
+			if (is_array($this->_model_relations[ $relationName ])
921
+					  && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
+			) {
923
+				// then remove the current cached item
924
+				unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
+				// and cache the newly saved object using it's new ID
926
+				$this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
+				return true;
928
+			}
929
+		}
930
+		return false;
931
+	}
932
+
933
+
934
+	/**
935
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
+	 *
938
+	 * @param string $relationName
939
+	 * @return EE_Base_Class
940
+	 */
941
+	public function get_one_from_cache($relationName)
942
+	{
943
+		$cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
+			? $this->_model_relations[ $relationName ]
945
+			: null;
946
+		if (is_array($cached_array_or_object)) {
947
+			return array_shift($cached_array_or_object);
948
+		}
949
+		return $cached_array_or_object;
950
+	}
951
+
952
+
953
+	/**
954
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
+	 *
957
+	 * @param string $relationName
958
+	 * @throws ReflectionException
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidInterfaceException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws EE_Error
963
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
+	 */
965
+	public function get_all_from_cache($relationName)
966
+	{
967
+		$objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
+		// if the result is not an array, but exists, make it an array
969
+		$objects = is_array($objects) ? $objects : array($objects);
970
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
+		//basically, if this model object was stored in the session, and these cached model objects
972
+		//already have IDs, let's make sure they're in their model's entity mapper
973
+		//otherwise we will have duplicates next time we call
974
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
+		$model = EE_Registry::instance()->load_model($relationName);
976
+		foreach ($objects as $model_object) {
977
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
+				if ($model_object->ID()) {
980
+					$model->add_to_entity_map($model_object);
981
+				}
982
+			} else {
983
+				throw new EE_Error(
984
+					sprintf(
985
+						esc_html__(
986
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
+							'event_espresso'
988
+						),
989
+						$relationName,
990
+						gettype($model_object)
991
+					)
992
+				);
993
+			}
994
+		}
995
+		return $objects;
996
+	}
997
+
998
+
999
+	/**
1000
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
+	 * matching the given query conditions.
1002
+	 *
1003
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1004
+	 * @param int   $limit              How many objects to return.
1005
+	 * @param array $query_params       Any additional conditions on the query.
1006
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
+	 *                                  you can indicate just the columns you want returned
1008
+	 * @return array|EE_Base_Class[]
1009
+	 * @throws ReflectionException
1010
+	 * @throws InvalidArgumentException
1011
+	 * @throws InvalidInterfaceException
1012
+	 * @throws InvalidDataTypeException
1013
+	 * @throws EE_Error
1014
+	 */
1015
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
+	{
1017
+		$model         = $this->get_model();
1018
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
+			? $model->get_primary_key_field()->get_name()
1020
+			: $field_to_order_by;
1021
+		$current_value = ! empty($field) ? $this->get($field) : null;
1022
+		if (empty($field) || empty($current_value)) {
1023
+			return array();
1024
+		}
1025
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
+	}
1027
+
1028
+
1029
+	/**
1030
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
+	 * matching the given query conditions.
1032
+	 *
1033
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1034
+	 * @param int   $limit              How many objects to return.
1035
+	 * @param array $query_params       Any additional conditions on the query.
1036
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
+	 *                                  you can indicate just the columns you want returned
1038
+	 * @return array|EE_Base_Class[]
1039
+	 * @throws ReflectionException
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidInterfaceException
1042
+	 * @throws InvalidDataTypeException
1043
+	 * @throws EE_Error
1044
+	 */
1045
+	public function previous_x(
1046
+		$field_to_order_by = null,
1047
+		$limit = 1,
1048
+		$query_params = array(),
1049
+		$columns_to_select = null
1050
+	) {
1051
+		$model         = $this->get_model();
1052
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
+			? $model->get_primary_key_field()->get_name()
1054
+			: $field_to_order_by;
1055
+		$current_value = ! empty($field) ? $this->get($field) : null;
1056
+		if (empty($field) || empty($current_value)) {
1057
+			return array();
1058
+		}
1059
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
+	 * matching the given query conditions.
1066
+	 *
1067
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1068
+	 * @param array $query_params       Any additional conditions on the query.
1069
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
+	 *                                  you can indicate just the columns you want returned
1071
+	 * @return array|EE_Base_Class
1072
+	 * @throws ReflectionException
1073
+	 * @throws InvalidArgumentException
1074
+	 * @throws InvalidInterfaceException
1075
+	 * @throws InvalidDataTypeException
1076
+	 * @throws EE_Error
1077
+	 */
1078
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
+	{
1080
+		$model         = $this->get_model();
1081
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
+			? $model->get_primary_key_field()->get_name()
1083
+			: $field_to_order_by;
1084
+		$current_value = ! empty($field) ? $this->get($field) : null;
1085
+		if (empty($field) || empty($current_value)) {
1086
+			return array();
1087
+		}
1088
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
+	 * matching the given query conditions.
1095
+	 *
1096
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1097
+	 * @param array $query_params       Any additional conditions on the query.
1098
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
+	 *                                  you can indicate just the column you want returned
1100
+	 * @return array|EE_Base_Class
1101
+	 * @throws ReflectionException
1102
+	 * @throws InvalidArgumentException
1103
+	 * @throws InvalidInterfaceException
1104
+	 * @throws InvalidDataTypeException
1105
+	 * @throws EE_Error
1106
+	 */
1107
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
+	{
1109
+		$model         = $this->get_model();
1110
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
+			? $model->get_primary_key_field()->get_name()
1112
+			: $field_to_order_by;
1113
+		$current_value = ! empty($field) ? $this->get($field) : null;
1114
+		if (empty($field) || empty($current_value)) {
1115
+			return array();
1116
+		}
1117
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * Overrides parent because parent expects old models.
1123
+	 * This also doesn't do any validation, and won't work for serialized arrays
1124
+	 *
1125
+	 * @param string $field_name
1126
+	 * @param mixed  $field_value_from_db
1127
+	 * @throws ReflectionException
1128
+	 * @throws InvalidArgumentException
1129
+	 * @throws InvalidInterfaceException
1130
+	 * @throws InvalidDataTypeException
1131
+	 * @throws EE_Error
1132
+	 */
1133
+	public function set_from_db($field_name, $field_value_from_db)
1134
+	{
1135
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1136
+		if ($field_obj instanceof EE_Model_Field_Base) {
1137
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1138
+			//eg, a CPT model object could have an entry in the posts table, but no
1139
+			//entry in the meta table. Meaning that all its columns in the meta table
1140
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1141
+			if ($field_value_from_db === null) {
1142
+				if ($field_obj->is_nullable()) {
1143
+					//if the field allows nulls, then let it be null
1144
+					$field_value = null;
1145
+				} else {
1146
+					$field_value = $field_obj->get_default_value();
1147
+				}
1148
+			} else {
1149
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
+			}
1151
+			$this->_fields[ $field_name ] = $field_value;
1152
+			$this->_clear_cached_property($field_name);
1153
+		}
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * verifies that the specified field is of the correct type
1159
+	 *
1160
+	 * @param string $field_name
1161
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
+	 *                                (in cases where the same property may be used for different outputs
1163
+	 *                                - i.e. datetime, money etc.)
1164
+	 * @return mixed
1165
+	 * @throws ReflectionException
1166
+	 * @throws InvalidArgumentException
1167
+	 * @throws InvalidInterfaceException
1168
+	 * @throws InvalidDataTypeException
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	public function get($field_name, $extra_cache_ref = null)
1172
+	{
1173
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1179
+	 *
1180
+	 * @param  string $field_name A valid fieldname
1181
+	 * @return mixed              Whatever the raw value stored on the property is.
1182
+	 * @throws ReflectionException
1183
+	 * @throws InvalidArgumentException
1184
+	 * @throws InvalidInterfaceException
1185
+	 * @throws InvalidDataTypeException
1186
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
+	 */
1188
+	public function get_raw($field_name)
1189
+	{
1190
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1191
+		return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
+			? $this->_fields[ $field_name ]->format('U')
1193
+			: $this->_fields[ $field_name ];
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * This is used to return the internal DateTime object used for a field that is a
1199
+	 * EE_Datetime_Field.
1200
+	 *
1201
+	 * @param string $field_name               The field name retrieving the DateTime object.
1202
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
+	 * @throws EE_Error an error is set and false returned.  If the field IS an
1204
+	 *                                         EE_Datetime_Field and but the field value is null, then
1205
+	 *                                         just null is returned (because that indicates that likely
1206
+	 *                                         this field is nullable).
1207
+	 * @throws InvalidArgumentException
1208
+	 * @throws InvalidDataTypeException
1209
+	 * @throws InvalidInterfaceException
1210
+	 * @throws ReflectionException
1211
+	 */
1212
+	public function get_DateTime_object($field_name)
1213
+	{
1214
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1215
+		if (! $field_settings instanceof EE_Datetime_Field) {
1216
+			EE_Error::add_error(
1217
+				sprintf(
1218
+					esc_html__(
1219
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1220
+						'event_espresso'
1221
+					),
1222
+					$field_name
1223
+				),
1224
+				__FILE__,
1225
+				__FUNCTION__,
1226
+				__LINE__
1227
+			);
1228
+			return false;
1229
+		}
1230
+		return isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime
1231
+			? clone $this->_fields[$field_name]
1232
+			: null;
1233
+	}
1234
+
1235
+
1236
+	/**
1237
+	 * To be used in template to immediately echo out the value, and format it for output.
1238
+	 * Eg, should call stripslashes and whatnot before echoing
1239
+	 *
1240
+	 * @param string $field_name      the name of the field as it appears in the DB
1241
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1242
+	 *                                (in cases where the same property may be used for different outputs
1243
+	 *                                - i.e. datetime, money etc.)
1244
+	 * @return void
1245
+	 * @throws ReflectionException
1246
+	 * @throws InvalidArgumentException
1247
+	 * @throws InvalidInterfaceException
1248
+	 * @throws InvalidDataTypeException
1249
+	 * @throws EE_Error
1250
+	 */
1251
+	public function e($field_name, $extra_cache_ref = null)
1252
+	{
1253
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1259
+	 * can be easily used as the value of form input.
1260
+	 *
1261
+	 * @param string $field_name
1262
+	 * @return void
1263
+	 * @throws ReflectionException
1264
+	 * @throws InvalidArgumentException
1265
+	 * @throws InvalidInterfaceException
1266
+	 * @throws InvalidDataTypeException
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	public function f($field_name)
1270
+	{
1271
+		$this->e($field_name, 'form_input');
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * Same as `f()` but just returns the value instead of echoing it
1277
+	 *
1278
+	 * @param string $field_name
1279
+	 * @return string
1280
+	 * @throws ReflectionException
1281
+	 * @throws InvalidArgumentException
1282
+	 * @throws InvalidInterfaceException
1283
+	 * @throws InvalidDataTypeException
1284
+	 * @throws EE_Error
1285
+	 */
1286
+	public function get_f($field_name)
1287
+	{
1288
+		return (string) $this->get_pretty($field_name, 'form_input');
1289
+	}
1290
+
1291
+
1292
+	/**
1293
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1294
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1295
+	 * to see what options are available.
1296
+	 *
1297
+	 * @param string $field_name
1298
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1299
+	 *                                (in cases where the same property may be used for different outputs
1300
+	 *                                - i.e. datetime, money etc.)
1301
+	 * @return mixed
1302
+	 * @throws ReflectionException
1303
+	 * @throws InvalidArgumentException
1304
+	 * @throws InvalidInterfaceException
1305
+	 * @throws InvalidDataTypeException
1306
+	 * @throws EE_Error
1307
+	 */
1308
+	public function get_pretty($field_name, $extra_cache_ref = null)
1309
+	{
1310
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * This simply returns the datetime for the given field name
1316
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1317
+	 * (and the equivalent e_date, e_time, e_datetime).
1318
+	 *
1319
+	 * @access   protected
1320
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1321
+	 * @param string   $dt_frmt      valid datetime format used for date
1322
+	 *                               (if '' then we just use the default on the field,
1323
+	 *                               if NULL we use the last-used format)
1324
+	 * @param string   $tm_frmt      Same as above except this is for time format
1325
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1326
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1327
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1328
+	 *                               if field is not a valid dtt field, or void if echoing
1329
+	 * @throws ReflectionException
1330
+	 * @throws InvalidArgumentException
1331
+	 * @throws InvalidInterfaceException
1332
+	 * @throws InvalidDataTypeException
1333
+	 * @throws EE_Error
1334
+	 */
1335
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1336
+	{
1337
+		// clear cached property
1338
+		$this->_clear_cached_property($field_name);
1339
+		//reset format properties because they are used in get()
1340
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1341
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1342
+		if ($echo) {
1343
+			$this->e($field_name, $date_or_time);
1344
+			return '';
1345
+		}
1346
+		return $this->get($field_name, $date_or_time);
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1352
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1353
+	 * other echoes the pretty value for dtt)
1354
+	 *
1355
+	 * @param  string $field_name name of model object datetime field holding the value
1356
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1357
+	 * @return string            datetime value formatted
1358
+	 * @throws ReflectionException
1359
+	 * @throws InvalidArgumentException
1360
+	 * @throws InvalidInterfaceException
1361
+	 * @throws InvalidDataTypeException
1362
+	 * @throws EE_Error
1363
+	 */
1364
+	public function get_date($field_name, $format = '')
1365
+	{
1366
+		return $this->_get_datetime($field_name, $format, null, 'D');
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * @param        $field_name
1372
+	 * @param string $format
1373
+	 * @throws ReflectionException
1374
+	 * @throws InvalidArgumentException
1375
+	 * @throws InvalidInterfaceException
1376
+	 * @throws InvalidDataTypeException
1377
+	 * @throws EE_Error
1378
+	 */
1379
+	public function e_date($field_name, $format = '')
1380
+	{
1381
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1387
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1388
+	 * other echoes the pretty value for dtt)
1389
+	 *
1390
+	 * @param  string $field_name name of model object datetime field holding the value
1391
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1392
+	 * @return string             datetime value formatted
1393
+	 * @throws ReflectionException
1394
+	 * @throws InvalidArgumentException
1395
+	 * @throws InvalidInterfaceException
1396
+	 * @throws InvalidDataTypeException
1397
+	 * @throws EE_Error
1398
+	 */
1399
+	public function get_time($field_name, $format = '')
1400
+	{
1401
+		return $this->_get_datetime($field_name, null, $format, 'T');
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * @param        $field_name
1407
+	 * @param string $format
1408
+	 * @throws ReflectionException
1409
+	 * @throws InvalidArgumentException
1410
+	 * @throws InvalidInterfaceException
1411
+	 * @throws InvalidDataTypeException
1412
+	 * @throws EE_Error
1413
+	 */
1414
+	public function e_time($field_name, $format = '')
1415
+	{
1416
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1417
+	}
1418
+
1419
+
1420
+	/**
1421
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1422
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1423
+	 * other echoes the pretty value for dtt)
1424
+	 *
1425
+	 * @param  string $field_name name of model object datetime field holding the value
1426
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1427
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1428
+	 * @return string             datetime value formatted
1429
+	 * @throws ReflectionException
1430
+	 * @throws InvalidArgumentException
1431
+	 * @throws InvalidInterfaceException
1432
+	 * @throws InvalidDataTypeException
1433
+	 * @throws EE_Error
1434
+	 */
1435
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1436
+	{
1437
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1438
+	}
1439
+
1440
+
1441
+	/**
1442
+	 * @param string $field_name
1443
+	 * @param string $dt_frmt
1444
+	 * @param string $tm_frmt
1445
+	 * @throws ReflectionException
1446
+	 * @throws InvalidArgumentException
1447
+	 * @throws InvalidInterfaceException
1448
+	 * @throws InvalidDataTypeException
1449
+	 * @throws EE_Error
1450
+	 */
1451
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1452
+	{
1453
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1454
+	}
1455
+
1456
+
1457
+	/**
1458
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1459
+	 *
1460
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1461
+	 * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1462
+	 *                           on the object will be used.
1463
+	 * @return string Date and time string in set locale or false if no field exists for the given
1464
+	 * @throws ReflectionException
1465
+	 * @throws InvalidArgumentException
1466
+	 * @throws InvalidInterfaceException
1467
+	 * @throws InvalidDataTypeException
1468
+	 * @throws EE_Error
1469
+	 *                           field name.
1470
+	 */
1471
+	public function get_i18n_datetime($field_name, $format = '')
1472
+	{
1473
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1474
+		return date_i18n(
1475
+			$format,
1476
+			EEH_DTT_Helper::get_timestamp_with_offset(
1477
+				$this->get_raw($field_name),
1478
+				$this->_timezone
1479
+			)
1480
+		);
1481
+	}
1482
+
1483
+
1484
+	/**
1485
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1486
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1487
+	 * thrown.
1488
+	 *
1489
+	 * @param  string $field_name The field name being checked
1490
+	 * @throws ReflectionException
1491
+	 * @throws InvalidArgumentException
1492
+	 * @throws InvalidInterfaceException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws EE_Error
1495
+	 * @return EE_Datetime_Field
1496
+	 */
1497
+	protected function _get_dtt_field_settings($field_name)
1498
+	{
1499
+		$field = $this->get_model()->field_settings_for($field_name);
1500
+		//check if field is dtt
1501
+		if ($field instanceof EE_Datetime_Field) {
1502
+			return $field;
1503
+		}
1504
+		throw new EE_Error(
1505
+			sprintf(
1506
+				esc_html__(
1507
+					'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',
1508
+					'event_espresso'
1509
+				),
1510
+				$field_name,
1511
+				self::_get_model_classname(get_class($this))
1512
+			)
1513
+		);
1514
+	}
1515
+
1516
+
1517
+
1518
+
1519
+	/**
1520
+	 * NOTE ABOUT BELOW:
1521
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1522
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1523
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1524
+	 * method and make sure you send the entire datetime value for setting.
1525
+	 */
1526
+	/**
1527
+	 * sets the time on a datetime property
1528
+	 *
1529
+	 * @access protected
1530
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1531
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1532
+	 * @throws ReflectionException
1533
+	 * @throws InvalidArgumentException
1534
+	 * @throws InvalidInterfaceException
1535
+	 * @throws InvalidDataTypeException
1536
+	 * @throws EE_Error
1537
+	 */
1538
+	protected function _set_time_for($time, $fieldname)
1539
+	{
1540
+		$this->_set_date_time('T', $time, $fieldname);
1541
+	}
1542
+
1543
+
1544
+	/**
1545
+	 * sets the date on a datetime property
1546
+	 *
1547
+	 * @access protected
1548
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1549
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1550
+	 * @throws ReflectionException
1551
+	 * @throws InvalidArgumentException
1552
+	 * @throws InvalidInterfaceException
1553
+	 * @throws InvalidDataTypeException
1554
+	 * @throws EE_Error
1555
+	 */
1556
+	protected function _set_date_for($date, $fieldname)
1557
+	{
1558
+		$this->_set_date_time('D', $date, $fieldname);
1559
+	}
1560
+
1561
+
1562
+	/**
1563
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1564
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1565
+	 *
1566
+	 * @access protected
1567
+	 * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1568
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1569
+	 * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1570
+	 *                                        EE_Datetime_Field property)
1571
+	 * @throws ReflectionException
1572
+	 * @throws InvalidArgumentException
1573
+	 * @throws InvalidInterfaceException
1574
+	 * @throws InvalidDataTypeException
1575
+	 * @throws EE_Error
1576
+	 */
1577
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1578
+	{
1579
+		$field = $this->_get_dtt_field_settings($fieldname);
1580
+		$field->set_timezone($this->_timezone);
1581
+		$field->set_date_format($this->_dt_frmt);
1582
+		$field->set_time_format($this->_tm_frmt);
1583
+		switch ($what) {
1584
+			case 'T' :
1585
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1586
+					$datetime_value,
1587
+					$this->_fields[ $fieldname ]
1588
+				);
1589
+				break;
1590
+			case 'D' :
1591
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1592
+					$datetime_value,
1593
+					$this->_fields[ $fieldname ]
1594
+				);
1595
+				break;
1596
+			case 'B' :
1597
+				$this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1598
+				break;
1599
+		}
1600
+		$this->_clear_cached_property($fieldname);
1601
+	}
1602
+
1603
+
1604
+	/**
1605
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1606
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1607
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1608
+	 * that could lead to some unexpected results!
1609
+	 *
1610
+	 * @access public
1611
+	 * @param string $field_name               This is the name of the field on the object that contains the date/time
1612
+	 *                                         value being returned.
1613
+	 * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1614
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1615
+	 * @param string $prepend                  You can include something to prepend on the timestamp
1616
+	 * @param string $append                   You can include something to append on the timestamp
1617
+	 * @throws ReflectionException
1618
+	 * @throws InvalidArgumentException
1619
+	 * @throws InvalidInterfaceException
1620
+	 * @throws InvalidDataTypeException
1621
+	 * @throws EE_Error
1622
+	 * @return string timestamp
1623
+	 */
1624
+	public function display_in_my_timezone(
1625
+		$field_name,
1626
+		$callback = 'get_datetime',
1627
+		$args = null,
1628
+		$prepend = '',
1629
+		$append = ''
1630
+	) {
1631
+		$timezone = EEH_DTT_Helper::get_timezone();
1632
+		if ($timezone === $this->_timezone) {
1633
+			return '';
1634
+		}
1635
+		$original_timezone = $this->_timezone;
1636
+		$this->set_timezone($timezone);
1637
+		$fn   = (array) $field_name;
1638
+		$args = array_merge($fn, (array) $args);
1639
+		if (! method_exists($this, $callback)) {
1640
+			throw new EE_Error(
1641
+				sprintf(
1642
+					esc_html__(
1643
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1644
+						'event_espresso'
1645
+					),
1646
+					$callback
1647
+				)
1648
+			);
1649
+		}
1650
+		$args   = (array) $args;
1651
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1652
+		$this->set_timezone($original_timezone);
1653
+		return $return;
1654
+	}
1655
+
1656
+
1657
+	/**
1658
+	 * Deletes this model object.
1659
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1660
+	 * override
1661
+	 * `EE_Base_Class::_delete` NOT this class.
1662
+	 *
1663
+	 * @return boolean | int
1664
+	 * @throws ReflectionException
1665
+	 * @throws InvalidArgumentException
1666
+	 * @throws InvalidInterfaceException
1667
+	 * @throws InvalidDataTypeException
1668
+	 * @throws EE_Error
1669
+	 */
1670
+	public function delete()
1671
+	{
1672
+		/**
1673
+		 * Called just before the `EE_Base_Class::_delete` method call.
1674
+		 * Note:
1675
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1676
+		 * should be aware that `_delete` may not always result in a permanent delete.
1677
+		 * For example, `EE_Soft_Delete_Base_Class::_delete`
1678
+		 * soft deletes (trash) the object and does not permanently delete it.
1679
+		 *
1680
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1681
+		 */
1682
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1683
+		$result = $this->_delete();
1684
+		/**
1685
+		 * Called just after the `EE_Base_Class::_delete` method call.
1686
+		 * Note:
1687
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1688
+		 * should be aware that `_delete` may not always result in a permanent delete.
1689
+		 * For example `EE_Soft_Base_Class::_delete`
1690
+		 * soft deletes (trash) the object and does not permanently delete it.
1691
+		 *
1692
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1693
+		 * @param boolean       $result
1694
+		 */
1695
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1696
+		return $result;
1697
+	}
1698
+
1699
+
1700
+	/**
1701
+	 * Calls the specific delete method for the instantiated class.
1702
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1703
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1704
+	 * `EE_Base_Class::delete`
1705
+	 *
1706
+	 * @return bool|int
1707
+	 * @throws ReflectionException
1708
+	 * @throws InvalidArgumentException
1709
+	 * @throws InvalidInterfaceException
1710
+	 * @throws InvalidDataTypeException
1711
+	 * @throws EE_Error
1712
+	 */
1713
+	protected function _delete()
1714
+	{
1715
+		return $this->delete_permanently();
1716
+	}
1717
+
1718
+
1719
+	/**
1720
+	 * Deletes this model object permanently from db
1721
+	 * (but keep in mind related models may block the delete and return an error)
1722
+	 *
1723
+	 * @return bool | int
1724
+	 * @throws ReflectionException
1725
+	 * @throws InvalidArgumentException
1726
+	 * @throws InvalidInterfaceException
1727
+	 * @throws InvalidDataTypeException
1728
+	 * @throws EE_Error
1729
+	 */
1730
+	public function delete_permanently()
1731
+	{
1732
+		/**
1733
+		 * Called just before HARD deleting a model object
1734
+		 *
1735
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1736
+		 */
1737
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1738
+		$model  = $this->get_model();
1739
+		$result = $model->delete_permanently_by_ID($this->ID());
1740
+		$this->refresh_cache_of_related_objects();
1741
+		/**
1742
+		 * Called just after HARD deleting a model object
1743
+		 *
1744
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1745
+		 * @param boolean       $result
1746
+		 */
1747
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1748
+		return $result;
1749
+	}
1750
+
1751
+
1752
+	/**
1753
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1754
+	 * related model objects
1755
+	 *
1756
+	 * @throws ReflectionException
1757
+	 * @throws InvalidArgumentException
1758
+	 * @throws InvalidInterfaceException
1759
+	 * @throws InvalidDataTypeException
1760
+	 * @throws EE_Error
1761
+	 */
1762
+	public function refresh_cache_of_related_objects()
1763
+	{
1764
+		$model = $this->get_model();
1765
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
+			if (! empty($this->_model_relations[ $relation_name ])) {
1767
+				$related_objects = $this->_model_relations[ $relation_name ];
1768
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769
+					//this relation only stores a single model object, not an array
1770
+					//but let's make it consistent
1771
+					$related_objects = array($related_objects);
1772
+				}
1773
+				foreach ($related_objects as $related_object) {
1774
+					//only refresh their cache if they're in memory
1775
+					if ($related_object instanceof EE_Base_Class) {
1776
+						$related_object->clear_cache(
1777
+							$model->get_this_model_name(),
1778
+							$this
1779
+						);
1780
+					}
1781
+				}
1782
+			}
1783
+		}
1784
+	}
1785
+
1786
+
1787
+	/**
1788
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1789
+	 * object just before saving.
1790
+	 *
1791
+	 * @access public
1792
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1793
+	 *                                 if provided during the save() method (often client code will change the fields'
1794
+	 *                                 values before calling save)
1795
+	 * @throws InvalidArgumentException
1796
+	 * @throws InvalidInterfaceException
1797
+	 * @throws InvalidDataTypeException
1798
+	 * @throws EE_Error
1799
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1800
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1801
+	 * @throws ReflectionException
1802
+	 * @throws ReflectionException
1803
+	 * @throws ReflectionException
1804
+	 */
1805
+	public function save($set_cols_n_values = array())
1806
+	{
1807
+		$model = $this->get_model();
1808
+		/**
1809
+		 * Filters the fields we're about to save on the model object
1810
+		 *
1811
+		 * @param array         $set_cols_n_values
1812
+		 * @param EE_Base_Class $model_object
1813
+		 */
1814
+		$set_cols_n_values = (array) apply_filters(
1815
+			'FHEE__EE_Base_Class__save__set_cols_n_values',
1816
+			$set_cols_n_values,
1817
+			$this
1818
+		);
1819
+		//set attributes as provided in $set_cols_n_values
1820
+		foreach ($set_cols_n_values as $column => $value) {
1821
+			$this->set($column, $value);
1822
+		}
1823
+		// no changes ? then don't do anything
1824
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825
+			return 0;
1826
+		}
1827
+		/**
1828
+		 * Saving a model object.
1829
+		 * Before we perform a save, this action is fired.
1830
+		 *
1831
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1832
+		 */
1833
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
+		if (! $this->allow_persist()) {
1835
+			return 0;
1836
+		}
1837
+		// now get current attribute values
1838
+		$save_cols_n_values = $this->_fields;
1839
+		// if the object already has an ID, update it. Otherwise, insert it
1840
+		// also: change the assumption about values passed to the model NOT being prepare dby the model object.
1841
+		// They have been
1842
+		$old_assumption_concerning_value_preparation = $model
1843
+			->get_assumption_concerning_values_already_prepared_by_model_object();
1844
+		$model->assume_values_already_prepared_by_model_object(true);
1845
+		//does this model have an autoincrement PK?
1846
+		if ($model->has_primary_key_field()) {
1847
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1848
+				//ok check if it's set, if so: update; if not, insert
1849
+				if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1850
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851
+				} else {
1852
+					unset($save_cols_n_values[ $model->primary_key_name() ]);
1853
+					$results = $model->insert($save_cols_n_values);
1854
+					if ($results) {
1855
+						//if successful, set the primary key
1856
+						//but don't use the normal SET method, because it will check if
1857
+						//an item with the same ID exists in the mapper & db, then
1858
+						//will find it in the db (because we just added it) and THAT object
1859
+						//will get added to the mapper before we can add this one!
1860
+						//but if we just avoid using the SET method, all that headache can be avoided
1861
+						$pk_field_name                   = $model->primary_key_name();
1862
+						$this->_fields[ $pk_field_name ] = $results;
1863
+						$this->_clear_cached_property($pk_field_name);
1864
+						$model->add_to_entity_map($this);
1865
+						$this->_update_cached_related_model_objs_fks();
1866
+					}
1867
+				}
1868
+			} else {//PK is NOT auto-increment
1869
+				//so check if one like it already exists in the db
1870
+				if ($model->exists_by_ID($this->ID())) {
1871
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1872
+						throw new EE_Error(
1873
+							sprintf(
1874
+								esc_html__(
1875
+									'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',
1876
+									'event_espresso'
1877
+								),
1878
+								get_class($this),
1879
+								get_class($model) . '::instance()->add_to_entity_map()',
1880
+								get_class($model) . '::instance()->get_one_by_ID()',
1881
+								'<br />'
1882
+							)
1883
+						);
1884
+					}
1885
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1886
+				} else {
1887
+					$results = $model->insert($save_cols_n_values);
1888
+					$this->_update_cached_related_model_objs_fks();
1889
+				}
1890
+			}
1891
+		} else {//there is NO primary key
1892
+			$already_in_db = false;
1893
+			foreach ($model->unique_indexes() as $index) {
1894
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1895
+				if ($model->exists(array($uniqueness_where_params))) {
1896
+					$already_in_db = true;
1897
+				}
1898
+			}
1899
+			if ($already_in_db) {
1900
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1901
+					$model->get_combined_primary_key_fields());
1902
+				$results                     = $model->update(
1903
+					$save_cols_n_values,
1904
+					$combined_pk_fields_n_values
1905
+				);
1906
+			} else {
1907
+				$results = $model->insert($save_cols_n_values);
1908
+			}
1909
+		}
1910
+		//restore the old assumption about values being prepared by the model object
1911
+		$model->assume_values_already_prepared_by_model_object(
1912
+				$old_assumption_concerning_value_preparation
1913
+			);
1914
+		/**
1915
+		 * After saving the model object this action is called
1916
+		 *
1917
+		 * @param EE_Base_Class $model_object which was just saved
1918
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1919
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1920
+		 */
1921
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1922
+		$this->_has_changes = false;
1923
+		return $results;
1924
+	}
1925
+
1926
+
1927
+	/**
1928
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1929
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1930
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1931
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1932
+	 * 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
1933
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1934
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1935
+	 *
1936
+	 * @return void
1937
+	 * @throws ReflectionException
1938
+	 * @throws InvalidArgumentException
1939
+	 * @throws InvalidInterfaceException
1940
+	 * @throws InvalidDataTypeException
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	protected function _update_cached_related_model_objs_fks()
1944
+	{
1945
+		$model = $this->get_model();
1946
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1947
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1948
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1949
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1950
+						$model->get_this_model_name()
1951
+					);
1952
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1953
+					if ($related_model_obj_in_cache->ID()) {
1954
+						$related_model_obj_in_cache->save();
1955
+					}
1956
+				}
1957
+			}
1958
+		}
1959
+	}
1960
+
1961
+
1962
+	/**
1963
+	 * Saves this model object and its NEW cached relations to the database.
1964
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1965
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1966
+	 * because otherwise, there's a potential for infinite looping of saving
1967
+	 * Saves the cached related model objects, and ensures the relation between them
1968
+	 * and this object and properly setup
1969
+	 *
1970
+	 * @return int ID of new model object on save; 0 on failure+
1971
+	 * @throws ReflectionException
1972
+	 * @throws InvalidArgumentException
1973
+	 * @throws InvalidInterfaceException
1974
+	 * @throws InvalidDataTypeException
1975
+	 * @throws EE_Error
1976
+	 */
1977
+	public function save_new_cached_related_model_objs()
1978
+	{
1979
+		//make sure this has been saved
1980
+		if (! $this->ID()) {
1981
+			$id = $this->save();
1982
+		} else {
1983
+			$id = $this->ID();
1984
+		}
1985
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1986
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
+			if ($this->_model_relations[ $relationName ]) {
1988
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990
+				/* @var $related_model_obj EE_Base_Class */
1991
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1992
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1993
+					//but ONLY if it DOES NOT exist in the DB
1994
+					$related_model_obj = $this->_model_relations[ $relationName ];
1995
+					//					if( ! $related_model_obj->ID()){
1996
+					$this->_add_relation_to($related_model_obj, $relationName);
1997
+					$related_model_obj->save_new_cached_related_model_objs();
1998
+					//					}
1999
+				} else {
2000
+					foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2001
+						//add a relation to that relation type (which saves the appropriate thing in the process)
2002
+						//but ONLY if it DOES NOT exist in the DB
2003
+						//						if( ! $related_model_obj->ID()){
2004
+						$this->_add_relation_to($related_model_obj, $relationName);
2005
+						$related_model_obj->save_new_cached_related_model_objs();
2006
+						//						}
2007
+					}
2008
+				}
2009
+			}
2010
+		}
2011
+		return $id;
2012
+	}
2013
+
2014
+
2015
+	/**
2016
+	 * for getting a model while instantiated.
2017
+	 *
2018
+	 * @return EEM_Base | EEM_CPT_Base
2019
+	 * @throws ReflectionException
2020
+	 * @throws InvalidArgumentException
2021
+	 * @throws InvalidInterfaceException
2022
+	 * @throws InvalidDataTypeException
2023
+	 * @throws EE_Error
2024
+	 */
2025
+	public function get_model()
2026
+	{
2027
+		if (! $this->_model) {
2028
+			$modelName    = self::_get_model_classname(get_class($this));
2029
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030
+		} else {
2031
+			$this->_model->set_timezone($this->_timezone);
2032
+		}
2033
+		return $this->_model;
2034
+	}
2035
+
2036
+
2037
+	/**
2038
+	 * @param $props_n_values
2039
+	 * @param $classname
2040
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2041
+	 * @throws ReflectionException
2042
+	 * @throws InvalidArgumentException
2043
+	 * @throws InvalidInterfaceException
2044
+	 * @throws InvalidDataTypeException
2045
+	 * @throws EE_Error
2046
+	 */
2047
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2048
+	{
2049
+		//TODO: will not work for Term_Relationships because they have no PK!
2050
+		$primary_id_ref = self::_get_primary_key_name($classname);
2051
+		if (
2052
+			array_key_exists($primary_id_ref, $props_n_values)
2053
+			&& ! empty($props_n_values[ $primary_id_ref ])
2054
+		) {
2055
+			$id = $props_n_values[ $primary_id_ref ];
2056
+			return self::_get_model($classname)->get_from_entity_map($id);
2057
+		}
2058
+		return false;
2059
+	}
2060
+
2061
+
2062
+	/**
2063
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2064
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2065
+	 * 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
2066
+	 * we return false.
2067
+	 *
2068
+	 * @param  array  $props_n_values   incoming array of properties and their values
2069
+	 * @param  string $classname        the classname of the child class
2070
+	 * @param null    $timezone
2071
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
2072
+	 *                                  date_format and the second value is the time format
2073
+	 * @return mixed (EE_Base_Class|bool)
2074
+	 * @throws InvalidArgumentException
2075
+	 * @throws InvalidInterfaceException
2076
+	 * @throws InvalidDataTypeException
2077
+	 * @throws EE_Error
2078
+	 * @throws ReflectionException
2079
+	 * @throws ReflectionException
2080
+	 * @throws ReflectionException
2081
+	 */
2082
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2083
+	{
2084
+		$existing = null;
2085
+		$model    = self::_get_model($classname, $timezone);
2086
+		if ($model->has_primary_key_field()) {
2087
+			$primary_id_ref = self::_get_primary_key_name($classname);
2088
+			if (array_key_exists($primary_id_ref, $props_n_values)
2089
+				&& ! empty($props_n_values[ $primary_id_ref ])
2090
+			) {
2091
+				$existing = $model->get_one_by_ID(
2092
+					$props_n_values[ $primary_id_ref ]
2093
+				);
2094
+			}
2095
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2096
+			//no primary key on this model, but there's still a matching item in the DB
2097
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2098
+				self::_get_model($classname, $timezone)
2099
+					->get_index_primary_key_string($props_n_values)
2100
+			);
2101
+		}
2102
+		if ($existing) {
2103
+			//set date formats if present before setting values
2104
+			if (! empty($date_formats) && is_array($date_formats)) {
2105
+				$existing->set_date_format($date_formats[0]);
2106
+				$existing->set_time_format($date_formats[1]);
2107
+			} else {
2108
+				//set default formats for date and time
2109
+				$existing->set_date_format(get_option('date_format'));
2110
+				$existing->set_time_format(get_option('time_format'));
2111
+			}
2112
+			foreach ($props_n_values as $property => $field_value) {
2113
+				$existing->set($property, $field_value);
2114
+			}
2115
+			return $existing;
2116
+		}
2117
+		return false;
2118
+	}
2119
+
2120
+
2121
+	/**
2122
+	 * Gets the EEM_*_Model for this class
2123
+	 *
2124
+	 * @access public now, as this is more convenient
2125
+	 * @param      $classname
2126
+	 * @param null $timezone
2127
+	 * @throws ReflectionException
2128
+	 * @throws InvalidArgumentException
2129
+	 * @throws InvalidInterfaceException
2130
+	 * @throws InvalidDataTypeException
2131
+	 * @throws EE_Error
2132
+	 * @return EEM_Base
2133
+	 */
2134
+	protected static function _get_model($classname, $timezone = null)
2135
+	{
2136
+		//find model for this class
2137
+		if (! $classname) {
2138
+			throw new EE_Error(
2139
+				sprintf(
2140
+					esc_html__(
2141
+						'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2142
+						'event_espresso'
2143
+					),
2144
+					$classname
2145
+				)
2146
+			);
2147
+		}
2148
+		$modelName = self::_get_model_classname($classname);
2149
+		return self::_get_model_instance_with_name($modelName, $timezone);
2150
+	}
2151
+
2152
+
2153
+	/**
2154
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2155
+	 *
2156
+	 * @param string $model_classname
2157
+	 * @param null   $timezone
2158
+	 * @return EEM_Base
2159
+	 * @throws ReflectionException
2160
+	 * @throws InvalidArgumentException
2161
+	 * @throws InvalidInterfaceException
2162
+	 * @throws InvalidDataTypeException
2163
+	 * @throws EE_Error
2164
+	 */
2165
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2166
+	{
2167
+		$model_classname = str_replace('EEM_', '', $model_classname);
2168
+		$model           = EE_Registry::instance()->load_model($model_classname);
2169
+		$model->set_timezone($timezone);
2170
+		return $model;
2171
+	}
2172
+
2173
+
2174
+	/**
2175
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
2176
+	 * Also works if a model class's classname is provided (eg EE_Registration).
2177
+	 *
2178
+	 * @param null $model_name
2179
+	 * @return string like EEM_Attendee
2180
+	 */
2181
+	private static function _get_model_classname($model_name = null)
2182
+	{
2183
+		if (strpos($model_name, 'EE_') === 0) {
2184
+			$model_classname = str_replace('EE_', 'EEM_', $model_name);
2185
+		} else {
2186
+			$model_classname = 'EEM_' . $model_name;
2187
+		}
2188
+		return $model_classname;
2189
+	}
2190
+
2191
+
2192
+	/**
2193
+	 * returns the name of the primary key attribute
2194
+	 *
2195
+	 * @param null $classname
2196
+	 * @throws ReflectionException
2197
+	 * @throws InvalidArgumentException
2198
+	 * @throws InvalidInterfaceException
2199
+	 * @throws InvalidDataTypeException
2200
+	 * @throws EE_Error
2201
+	 * @return string
2202
+	 */
2203
+	protected static function _get_primary_key_name($classname = null)
2204
+	{
2205
+		if (! $classname) {
2206
+			throw new EE_Error(
2207
+				sprintf(
2208
+					esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2209
+					$classname
2210
+				)
2211
+			);
2212
+		}
2213
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
2214
+	}
2215
+
2216
+
2217
+	/**
2218
+	 * Gets the value of the primary key.
2219
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
2220
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2221
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2222
+	 *
2223
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2224
+	 * @throws ReflectionException
2225
+	 * @throws InvalidArgumentException
2226
+	 * @throws InvalidInterfaceException
2227
+	 * @throws InvalidDataTypeException
2228
+	 * @throws EE_Error
2229
+	 */
2230
+	public function ID()
2231
+	{
2232
+		$model = $this->get_model();
2233
+		//now that we know the name of the variable, use a variable variable to get its value and return its
2234
+		if ($model->has_primary_key_field()) {
2235
+			return $this->_fields[ $model->primary_key_name() ];
2236
+		}
2237
+		return $model->get_index_primary_key_string($this->_fields);
2238
+	}
2239
+
2240
+
2241
+	/**
2242
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2243
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2244
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2245
+	 *
2246
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2247
+	 * @param string $relationName                     eg 'Events','Question',etc.
2248
+	 *                                                 an attendee to a group, you also want to specify which role they
2249
+	 *                                                 will have in that group. So you would use this parameter to
2250
+	 *                                                 specify array('role-column-name'=>'role-id')
2251
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2252
+	 *                                                 allow you to further constrict the relation to being added.
2253
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2254
+	 *                                                 column on the JOIN table and currently only the HABTM models
2255
+	 *                                                 accept these additional conditions.  Also remember that if an
2256
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2257
+	 *                                                 NEW row is created in the join table.
2258
+	 * @param null   $cache_id
2259
+	 * @throws ReflectionException
2260
+	 * @throws InvalidArgumentException
2261
+	 * @throws InvalidInterfaceException
2262
+	 * @throws InvalidDataTypeException
2263
+	 * @throws EE_Error
2264
+	 * @return EE_Base_Class the object the relation was added to
2265
+	 */
2266
+	public function _add_relation_to(
2267
+		$otherObjectModelObjectOrID,
2268
+		$relationName,
2269
+		$extra_join_model_fields_n_values = array(),
2270
+		$cache_id = null
2271
+	) {
2272
+		$model = $this->get_model();
2273
+		//if this thing exists in the DB, save the relation to the DB
2274
+		if ($this->ID()) {
2275
+			$otherObject = $model->add_relationship_to(
2276
+				$this,
2277
+				$otherObjectModelObjectOrID,
2278
+				$relationName,
2279
+				$extra_join_model_fields_n_values
2280
+			);
2281
+			//clear cache so future get_many_related and get_first_related() return new results.
2282
+			$this->clear_cache($relationName, $otherObject, true);
2283
+			if ($otherObject instanceof EE_Base_Class) {
2284
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2285
+			}
2286
+		} else {
2287
+			//this thing doesn't exist in the DB,  so just cache it
2288
+			if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289
+				throw new EE_Error(
2290
+					sprintf(
2291
+						esc_html__(
2292
+							'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',
2293
+							'event_espresso'
2294
+						),
2295
+						$otherObjectModelObjectOrID,
2296
+						get_class($this)
2297
+					)
2298
+				);
2299
+			}
2300
+			$otherObject = $otherObjectModelObjectOrID;
2301
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2302
+		}
2303
+		if ($otherObject instanceof EE_Base_Class) {
2304
+			//fix the reciprocal relation too
2305
+			if ($otherObject->ID()) {
2306
+				//its saved so assumed relations exist in the DB, so we can just
2307
+				//clear the cache so future queries use the updated info in the DB
2308
+				$otherObject->clear_cache(
2309
+					$model->get_this_model_name(),
2310
+					null,
2311
+					true
2312
+				);
2313
+			} else {
2314
+				//it's not saved, so it caches relations like this
2315
+				$otherObject->cache($model->get_this_model_name(), $this);
2316
+			}
2317
+		}
2318
+		return $otherObject;
2319
+	}
2320
+
2321
+
2322
+	/**
2323
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2324
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2325
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2326
+	 * from the cache
2327
+	 *
2328
+	 * @param mixed  $otherObjectModelObjectOrID
2329
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2330
+	 *                to the DB yet
2331
+	 * @param string $relationName
2332
+	 * @param array  $where_query
2333
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2334
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2335
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2336
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2337
+	 *                created in the join table.
2338
+	 * @return EE_Base_Class the relation was removed from
2339
+	 * @throws ReflectionException
2340
+	 * @throws InvalidArgumentException
2341
+	 * @throws InvalidInterfaceException
2342
+	 * @throws InvalidDataTypeException
2343
+	 * @throws EE_Error
2344
+	 */
2345
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2346
+	{
2347
+		if ($this->ID()) {
2348
+			//if this exists in the DB, save the relation change to the DB too
2349
+			$otherObject = $this->get_model()->remove_relationship_to(
2350
+				$this,
2351
+				$otherObjectModelObjectOrID,
2352
+				$relationName,
2353
+				$where_query
2354
+			);
2355
+			$this->clear_cache(
2356
+				$relationName,
2357
+				$otherObject
2358
+			);
2359
+		} else {
2360
+			//this doesn't exist in the DB, just remove it from the cache
2361
+			$otherObject = $this->clear_cache(
2362
+				$relationName,
2363
+				$otherObjectModelObjectOrID
2364
+			);
2365
+		}
2366
+		if ($otherObject instanceof EE_Base_Class) {
2367
+			$otherObject->clear_cache(
2368
+				$this->get_model()->get_this_model_name(),
2369
+				$this
2370
+			);
2371
+		}
2372
+		return $otherObject;
2373
+	}
2374
+
2375
+
2376
+	/**
2377
+	 * Removes ALL the related things for the $relationName.
2378
+	 *
2379
+	 * @param string $relationName
2380
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2381
+	 * @return EE_Base_Class
2382
+	 * @throws ReflectionException
2383
+	 * @throws InvalidArgumentException
2384
+	 * @throws InvalidInterfaceException
2385
+	 * @throws InvalidDataTypeException
2386
+	 * @throws EE_Error
2387
+	 */
2388
+	public function _remove_relations($relationName, $where_query_params = array())
2389
+	{
2390
+		if ($this->ID()) {
2391
+			//if this exists in the DB, save the relation change to the DB too
2392
+			$otherObjects = $this->get_model()->remove_relations(
2393
+				$this,
2394
+				$relationName,
2395
+				$where_query_params
2396
+			);
2397
+			$this->clear_cache(
2398
+				$relationName,
2399
+				null,
2400
+				true
2401
+			);
2402
+		} else {
2403
+			//this doesn't exist in the DB, just remove it from the cache
2404
+			$otherObjects = $this->clear_cache(
2405
+				$relationName,
2406
+				null,
2407
+				true
2408
+			);
2409
+		}
2410
+		if (is_array($otherObjects)) {
2411
+			foreach ($otherObjects as $otherObject) {
2412
+				$otherObject->clear_cache(
2413
+					$this->get_model()->get_this_model_name(),
2414
+					$this
2415
+				);
2416
+			}
2417
+		}
2418
+		return $otherObjects;
2419
+	}
2420
+
2421
+
2422
+	/**
2423
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2424
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2425
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2426
+	 * because we want to get even deleted items etc.
2427
+	 *
2428
+	 * @param string $relationName key in the model's _model_relations array
2429
+	 * @param array  $query_params like EEM_Base::get_all
2430
+	 * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2431
+	 *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2432
+	 *                             results if you want IDs
2433
+	 * @throws ReflectionException
2434
+	 * @throws InvalidArgumentException
2435
+	 * @throws InvalidInterfaceException
2436
+	 * @throws InvalidDataTypeException
2437
+	 * @throws EE_Error
2438
+	 */
2439
+	public function get_many_related($relationName, $query_params = array())
2440
+	{
2441
+		if ($this->ID()) {
2442
+			//this exists in the DB, so get the related things from either the cache or the DB
2443
+			//if there are query parameters, forget about caching the related model objects.
2444
+			if ($query_params) {
2445
+				$related_model_objects = $this->get_model()->get_all_related(
2446
+					$this,
2447
+					$relationName,
2448
+					$query_params
2449
+				);
2450
+			} else {
2451
+				//did we already cache the result of this query?
2452
+				$cached_results = $this->get_all_from_cache($relationName);
2453
+				if (! $cached_results) {
2454
+					$related_model_objects = $this->get_model()->get_all_related(
2455
+						$this,
2456
+						$relationName,
2457
+						$query_params
2458
+					);
2459
+					//if no query parameters were passed, then we got all the related model objects
2460
+					//for that relation. We can cache them then.
2461
+					foreach ($related_model_objects as $related_model_object) {
2462
+						$this->cache($relationName, $related_model_object);
2463
+					}
2464
+				} else {
2465
+					$related_model_objects = $cached_results;
2466
+				}
2467
+			}
2468
+		} else {
2469
+			//this doesn't exist in the DB, so just get the related things from the cache
2470
+			$related_model_objects = $this->get_all_from_cache($relationName);
2471
+		}
2472
+		return $related_model_objects;
2473
+	}
2474
+
2475
+
2476
+	/**
2477
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2478
+	 * unless otherwise specified in the $query_params
2479
+	 *
2480
+	 * @param string $relation_name  model_name like 'Event', or 'Registration'
2481
+	 * @param array  $query_params   like EEM_Base::get_all's
2482
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2483
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2484
+	 *                               that by the setting $distinct to TRUE;
2485
+	 * @return int
2486
+	 * @throws ReflectionException
2487
+	 * @throws InvalidArgumentException
2488
+	 * @throws InvalidInterfaceException
2489
+	 * @throws InvalidDataTypeException
2490
+	 * @throws EE_Error
2491
+	 */
2492
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2493
+	{
2494
+		return $this->get_model()->count_related(
2495
+			$this,
2496
+			$relation_name,
2497
+			$query_params,
2498
+			$field_to_count,
2499
+			$distinct
2500
+		);
2501
+	}
2502
+
2503
+
2504
+	/**
2505
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2506
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2507
+	 *
2508
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2509
+	 * @param array  $query_params  like EEM_Base::get_all's
2510
+	 * @param string $field_to_sum  name of field to count by.
2511
+	 *                              By default, uses primary key
2512
+	 *                              (which doesn't make much sense, so you should probably change it)
2513
+	 * @return int
2514
+	 * @throws ReflectionException
2515
+	 * @throws InvalidArgumentException
2516
+	 * @throws InvalidInterfaceException
2517
+	 * @throws InvalidDataTypeException
2518
+	 * @throws EE_Error
2519
+	 */
2520
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2521
+	{
2522
+		return $this->get_model()->sum_related(
2523
+			$this,
2524
+			$relation_name,
2525
+			$query_params,
2526
+			$field_to_sum
2527
+		);
2528
+	}
2529
+
2530
+
2531
+	/**
2532
+	 * Gets the first (ie, one) related model object of the specified type.
2533
+	 *
2534
+	 * @param string $relationName key in the model's _model_relations array
2535
+	 * @param array  $query_params like EEM_Base::get_all
2536
+	 * @return EE_Base_Class (not an array, a single object)
2537
+	 * @throws ReflectionException
2538
+	 * @throws InvalidArgumentException
2539
+	 * @throws InvalidInterfaceException
2540
+	 * @throws InvalidDataTypeException
2541
+	 * @throws EE_Error
2542
+	 */
2543
+	public function get_first_related($relationName, $query_params = array())
2544
+	{
2545
+		$model = $this->get_model();
2546
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2547
+			//if they've provided some query parameters, don't bother trying to cache the result
2548
+			//also make sure we're not caching the result of get_first_related
2549
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2550
+			if ($query_params
2551
+				|| ! $model->related_settings_for($relationName)
2552
+					 instanceof
2553
+					 EE_Belongs_To_Relation
2554
+			) {
2555
+				$related_model_object = $model->get_first_related(
2556
+					$this,
2557
+					$relationName,
2558
+					$query_params
2559
+				);
2560
+			} else {
2561
+				//first, check if we've already cached the result of this query
2562
+				$cached_result = $this->get_one_from_cache($relationName);
2563
+				if (! $cached_result) {
2564
+					$related_model_object = $model->get_first_related(
2565
+						$this,
2566
+						$relationName,
2567
+						$query_params
2568
+					);
2569
+					$this->cache($relationName, $related_model_object);
2570
+				} else {
2571
+					$related_model_object = $cached_result;
2572
+				}
2573
+			}
2574
+		} else {
2575
+			$related_model_object = null;
2576
+			// this doesn't exist in the Db,
2577
+			// but maybe the relation is of type belongs to, and so the related thing might
2578
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2579
+				$related_model_object = $model->get_first_related(
2580
+					$this,
2581
+					$relationName,
2582
+					$query_params
2583
+				);
2584
+			}
2585
+			// this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586
+			// just get what's cached on this object
2587
+			if (! $related_model_object) {
2588
+				$related_model_object = $this->get_one_from_cache($relationName);
2589
+			}
2590
+		}
2591
+		return $related_model_object;
2592
+	}
2593
+
2594
+
2595
+	/**
2596
+	 * Does a delete on all related objects of type $relationName and removes
2597
+	 * the current model object's relation to them. If they can't be deleted (because
2598
+	 * of blocking related model objects) does nothing. If the related model objects are
2599
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2600
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2601
+	 *
2602
+	 * @param string $relationName
2603
+	 * @param array  $query_params like EEM_Base::get_all's
2604
+	 * @return int how many deleted
2605
+	 * @throws ReflectionException
2606
+	 * @throws InvalidArgumentException
2607
+	 * @throws InvalidInterfaceException
2608
+	 * @throws InvalidDataTypeException
2609
+	 * @throws EE_Error
2610
+	 */
2611
+	public function delete_related($relationName, $query_params = array())
2612
+	{
2613
+		if ($this->ID()) {
2614
+			$count = $this->get_model()->delete_related(
2615
+				$this,
2616
+				$relationName,
2617
+				$query_params
2618
+			);
2619
+		} else {
2620
+			$count = count($this->get_all_from_cache($relationName));
2621
+			$this->clear_cache($relationName, null, true);
2622
+		}
2623
+		return $count;
2624
+	}
2625
+
2626
+
2627
+	/**
2628
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2629
+	 * the current model object's relation to them. If they can't be deleted (because
2630
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2631
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2632
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2633
+	 *
2634
+	 * @param string $relationName
2635
+	 * @param array  $query_params like EEM_Base::get_all's
2636
+	 * @return int how many deleted (including those soft deleted)
2637
+	 * @throws ReflectionException
2638
+	 * @throws InvalidArgumentException
2639
+	 * @throws InvalidInterfaceException
2640
+	 * @throws InvalidDataTypeException
2641
+	 * @throws EE_Error
2642
+	 */
2643
+	public function delete_related_permanently($relationName, $query_params = array())
2644
+	{
2645
+		if ($this->ID()) {
2646
+			$count = $this->get_model()->delete_related_permanently(
2647
+				$this,
2648
+				$relationName,
2649
+				$query_params
2650
+			);
2651
+		} else {
2652
+			$count = count($this->get_all_from_cache($relationName));
2653
+		}
2654
+		$this->clear_cache($relationName, null, true);
2655
+		return $count;
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 * is_set
2661
+	 * Just a simple utility function children can use for checking if property exists
2662
+	 *
2663
+	 * @access  public
2664
+	 * @param  string $field_name property to check
2665
+	 * @return bool                              TRUE if existing,FALSE if not.
2666
+	 */
2667
+	public function is_set($field_name)
2668
+	{
2669
+		return isset($this->_fields[ $field_name ]);
2670
+	}
2671
+
2672
+
2673
+	/**
2674
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2675
+	 * EE_Error exception if they don't
2676
+	 *
2677
+	 * @param  mixed (string|array) $properties properties to check
2678
+	 * @throws EE_Error
2679
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2680
+	 */
2681
+	protected function _property_exists($properties)
2682
+	{
2683
+		foreach ((array) $properties as $property_name) {
2684
+			//first make sure this property exists
2685
+			if (! $this->_fields[ $property_name ]) {
2686
+				throw new EE_Error(
2687
+					sprintf(
2688
+						esc_html__(
2689
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2690
+							'event_espresso'
2691
+						),
2692
+						$property_name
2693
+					)
2694
+				);
2695
+			}
2696
+		}
2697
+		return true;
2698
+	}
2699
+
2700
+
2701
+	/**
2702
+	 * This simply returns an array of model fields for this object
2703
+	 *
2704
+	 * @return array
2705
+	 * @throws ReflectionException
2706
+	 * @throws InvalidArgumentException
2707
+	 * @throws InvalidInterfaceException
2708
+	 * @throws InvalidDataTypeException
2709
+	 * @throws EE_Error
2710
+	 */
2711
+	public function model_field_array()
2712
+	{
2713
+		$fields     = $this->get_model()->field_settings(false);
2714
+		$properties = array();
2715
+		//remove prepended underscore
2716
+		foreach ($fields as $field_name => $settings) {
2717
+			$properties[ $field_name ] = $this->get($field_name);
2718
+		}
2719
+		return $properties;
2720
+	}
2721
+
2722
+
2723
+	/**
2724
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2725
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2726
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2727
+	 * Instead of requiring a plugin to extend the EE_Base_Class
2728
+	 * (which works fine is there's only 1 plugin, but when will that happen?)
2729
+	 * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2730
+	 * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2731
+	 * and accepts 2 arguments: the object on which the function was called,
2732
+	 * and an array of the original arguments passed to the function.
2733
+	 * Whatever their callback function returns will be returned by this function.
2734
+	 * Example: in functions.php (or in a plugin):
2735
+	 *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2736
+	 *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2737
+	 *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2738
+	 *          return $previousReturnValue.$returnString;
2739
+	 *      }
2740
+	 * require('EE_Answer.class.php');
2741
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2742
+	 * echo $answer->my_callback('monkeys',100);
2743
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2744
+	 *
2745
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2746
+	 * @param array  $args       array of original arguments passed to the function
2747
+	 * @throws EE_Error
2748
+	 * @return mixed whatever the plugin which calls add_filter decides
2749
+	 */
2750
+	public function __call($methodName, $args)
2751
+	{
2752
+		$className = get_class($this);
2753
+		$tagName   = "FHEE__{$className}__{$methodName}";
2754
+		if (! has_filter($tagName)) {
2755
+			throw new EE_Error(
2756
+				sprintf(
2757
+					esc_html__(
2758
+						"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;}",
2759
+						'event_espresso'
2760
+					),
2761
+					$methodName,
2762
+					$className,
2763
+					$tagName
2764
+				)
2765
+			);
2766
+		}
2767
+		return apply_filters($tagName, null, $this, $args);
2768
+	}
2769
+
2770
+
2771
+	/**
2772
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2773
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2774
+	 *
2775
+	 * @param string $meta_key
2776
+	 * @param mixed  $meta_value
2777
+	 * @param mixed  $previous_value
2778
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2779
+	 *                  NOTE: if the values haven't changed, returns 0
2780
+	 * @throws InvalidArgumentException
2781
+	 * @throws InvalidInterfaceException
2782
+	 * @throws InvalidDataTypeException
2783
+	 * @throws EE_Error
2784
+	 * @throws ReflectionException
2785
+	 */
2786
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2787
+	{
2788
+		$query_params = array(
2789
+			array(
2790
+				'EXM_key'  => $meta_key,
2791
+				'OBJ_ID'   => $this->ID(),
2792
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2793
+			),
2794
+		);
2795
+		if ($previous_value !== null) {
2796
+			$query_params[0]['EXM_value'] = $meta_value;
2797
+		}
2798
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
+		if (! $existing_rows_like_that) {
2800
+			return $this->add_extra_meta($meta_key, $meta_value);
2801
+		}
2802
+		foreach ($existing_rows_like_that as $existing_row) {
2803
+			$existing_row->save(array('EXM_value' => $meta_value));
2804
+		}
2805
+		return count($existing_rows_like_that);
2806
+	}
2807
+
2808
+
2809
+	/**
2810
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2811
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2812
+	 * extra meta row was entered, false if not
2813
+	 *
2814
+	 * @param string  $meta_key
2815
+	 * @param mixed   $meta_value
2816
+	 * @param boolean $unique
2817
+	 * @return boolean
2818
+	 * @throws InvalidArgumentException
2819
+	 * @throws InvalidInterfaceException
2820
+	 * @throws InvalidDataTypeException
2821
+	 * @throws EE_Error
2822
+	 * @throws ReflectionException
2823
+	 * @throws ReflectionException
2824
+	 */
2825
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2826
+	{
2827
+		if ($unique) {
2828
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2829
+				array(
2830
+					array(
2831
+						'EXM_key'  => $meta_key,
2832
+						'OBJ_ID'   => $this->ID(),
2833
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2834
+					),
2835
+				)
2836
+			);
2837
+			if ($existing_extra_meta) {
2838
+				return false;
2839
+			}
2840
+		}
2841
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2842
+			array(
2843
+				'EXM_key'   => $meta_key,
2844
+				'EXM_value' => $meta_value,
2845
+				'OBJ_ID'    => $this->ID(),
2846
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2847
+			)
2848
+		);
2849
+		$new_extra_meta->save();
2850
+		return true;
2851
+	}
2852
+
2853
+
2854
+	/**
2855
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2856
+	 * is specified, only deletes extra meta records with that value.
2857
+	 *
2858
+	 * @param string $meta_key
2859
+	 * @param mixed  $meta_value
2860
+	 * @return int number of extra meta rows deleted
2861
+	 * @throws InvalidArgumentException
2862
+	 * @throws InvalidInterfaceException
2863
+	 * @throws InvalidDataTypeException
2864
+	 * @throws EE_Error
2865
+	 * @throws ReflectionException
2866
+	 */
2867
+	public function delete_extra_meta($meta_key, $meta_value = null)
2868
+	{
2869
+		$query_params = array(
2870
+			array(
2871
+				'EXM_key'  => $meta_key,
2872
+				'OBJ_ID'   => $this->ID(),
2873
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2874
+			),
2875
+		);
2876
+		if ($meta_value !== null) {
2877
+			$query_params[0]['EXM_value'] = $meta_value;
2878
+		}
2879
+		return EEM_Extra_Meta::instance()->delete($query_params);
2880
+	}
2881
+
2882
+
2883
+	/**
2884
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2885
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2886
+	 * You can specify $default is case you haven't found the extra meta
2887
+	 *
2888
+	 * @param string  $meta_key
2889
+	 * @param boolean $single
2890
+	 * @param mixed   $default if we don't find anything, what should we return?
2891
+	 * @return mixed single value if $single; array if ! $single
2892
+	 * @throws ReflectionException
2893
+	 * @throws InvalidArgumentException
2894
+	 * @throws InvalidInterfaceException
2895
+	 * @throws InvalidDataTypeException
2896
+	 * @throws EE_Error
2897
+	 */
2898
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2899
+	{
2900
+		if ($single) {
2901
+			$result = $this->get_first_related(
2902
+				'Extra_Meta',
2903
+				array(array('EXM_key' => $meta_key))
2904
+			);
2905
+			if ($result instanceof EE_Extra_Meta) {
2906
+				return $result->value();
2907
+			}
2908
+		} else {
2909
+			$results = $this->get_many_related(
2910
+				'Extra_Meta',
2911
+				array(array('EXM_key' => $meta_key))
2912
+			);
2913
+			if ($results) {
2914
+				$values = array();
2915
+				foreach ($results as $result) {
2916
+					if ($result instanceof EE_Extra_Meta) {
2917
+						$values[ $result->ID() ] = $result->value();
2918
+					}
2919
+				}
2920
+				return $values;
2921
+			}
2922
+		}
2923
+		//if nothing discovered yet return default.
2924
+		return apply_filters(
2925
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2926
+			$default,
2927
+			$meta_key,
2928
+			$single,
2929
+			$this
2930
+		);
2931
+	}
2932
+
2933
+
2934
+	/**
2935
+	 * Returns a simple array of all the extra meta associated with this model object.
2936
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2937
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2938
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2939
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2940
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2941
+	 * finally the extra meta's value as each sub-value. (eg
2942
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2943
+	 *
2944
+	 * @param boolean $one_of_each_key
2945
+	 * @return array
2946
+	 * @throws ReflectionException
2947
+	 * @throws InvalidArgumentException
2948
+	 * @throws InvalidInterfaceException
2949
+	 * @throws InvalidDataTypeException
2950
+	 * @throws EE_Error
2951
+	 */
2952
+	public function all_extra_meta_array($one_of_each_key = true)
2953
+	{
2954
+		$return_array = array();
2955
+		if ($one_of_each_key) {
2956
+			$extra_meta_objs = $this->get_many_related(
2957
+				'Extra_Meta',
2958
+				array('group_by' => 'EXM_key')
2959
+			);
2960
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2961
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
+					$return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2963
+				}
2964
+			}
2965
+		} else {
2966
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2967
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2968
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
+					if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
+						$return_array[ $extra_meta_obj->key() ] = array();
2971
+					}
2972
+					$return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2973
+				}
2974
+			}
2975
+		}
2976
+		return $return_array;
2977
+	}
2978
+
2979
+
2980
+	/**
2981
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2982
+	 *
2983
+	 * @return string
2984
+	 * @throws ReflectionException
2985
+	 * @throws InvalidArgumentException
2986
+	 * @throws InvalidInterfaceException
2987
+	 * @throws InvalidDataTypeException
2988
+	 * @throws EE_Error
2989
+	 */
2990
+	public function name()
2991
+	{
2992
+		//find a field that's not a text field
2993
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2994
+		if ($field_we_can_use) {
2995
+			return $this->get($field_we_can_use->get_name());
2996
+		}
2997
+		$first_few_properties = $this->model_field_array();
2998
+		$first_few_properties = array_slice($first_few_properties, 0, 3);
2999
+		$name_parts           = array();
3000
+		foreach ($first_few_properties as $name => $value) {
3001
+			$name_parts[] = "$name:$value";
3002
+		}
3003
+		return implode(',', $name_parts);
3004
+	}
3005
+
3006
+
3007
+	/**
3008
+	 * in_entity_map
3009
+	 * Checks if this model object has been proven to already be in the entity map
3010
+	 *
3011
+	 * @return boolean
3012
+	 * @throws ReflectionException
3013
+	 * @throws InvalidArgumentException
3014
+	 * @throws InvalidInterfaceException
3015
+	 * @throws InvalidDataTypeException
3016
+	 * @throws EE_Error
3017
+	 */
3018
+	public function in_entity_map()
3019
+	{
3020
+		// well, if we looked, did we find it in the entity map?
3021
+		return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3022
+	}
3023
+
3024
+
3025
+	/**
3026
+	 * refresh_from_db
3027
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
3028
+	 *
3029
+	 * @throws ReflectionException
3030
+	 * @throws InvalidArgumentException
3031
+	 * @throws InvalidInterfaceException
3032
+	 * @throws InvalidDataTypeException
3033
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3034
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3035
+	 */
3036
+	public function refresh_from_db()
3037
+	{
3038
+		if ($this->ID() && $this->in_entity_map()) {
3039
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
3040
+		} else {
3041
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3042
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
3043
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3044
+			//absolutely nothing in it for this ID
3045
+			if (WP_DEBUG) {
3046
+				throw new EE_Error(
3047
+					sprintf(
3048
+						esc_html__('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.',
3049
+							'event_espresso'),
3050
+						$this->ID(),
3051
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3053
+					)
3054
+				);
3055
+			}
3056
+		}
3057
+	}
3058
+
3059
+
3060
+	/**
3061
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3062
+	 * (probably a bad assumption they have made, oh well)
3063
+	 *
3064
+	 * @return string
3065
+	 */
3066
+	public function __toString()
3067
+	{
3068
+		try {
3069
+			return sprintf('%s (%s)', $this->name(), $this->ID());
3070
+		} catch (Exception $e) {
3071
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3072
+			return '';
3073
+		}
3074
+	}
3075
+
3076
+
3077
+	/**
3078
+	 * Clear related model objects if they're already in the DB, because otherwise when we
3079
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
3080
+	 * This means if we have made changes to those related model objects, and want to unserialize
3081
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
3082
+	 * Instead, those related model objects should be directly serialized and stored.
3083
+	 * Eg, the following won't work:
3084
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3085
+	 * $att = $reg->attendee();
3086
+	 * $att->set( 'ATT_fname', 'Dirk' );
3087
+	 * update_option( 'my_option', serialize( $reg ) );
3088
+	 * //END REQUEST
3089
+	 * //START NEXT REQUEST
3090
+	 * $reg = get_option( 'my_option' );
3091
+	 * $reg->attendee()->save();
3092
+	 * And would need to be replace with:
3093
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3094
+	 * $att = $reg->attendee();
3095
+	 * $att->set( 'ATT_fname', 'Dirk' );
3096
+	 * update_option( 'my_option', serialize( $reg ) );
3097
+	 * //END REQUEST
3098
+	 * //START NEXT REQUEST
3099
+	 * $att = get_option( 'my_option' );
3100
+	 * $att->save();
3101
+	 *
3102
+	 * @return array
3103
+	 * @throws ReflectionException
3104
+	 * @throws InvalidArgumentException
3105
+	 * @throws InvalidInterfaceException
3106
+	 * @throws InvalidDataTypeException
3107
+	 * @throws EE_Error
3108
+	 */
3109
+	public function __sleep()
3110
+	{
3111
+		$model = $this->get_model();
3112
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
+				$classname = 'EE_' . $model->get_this_model_name();
3115
+				if (
3116
+					$this->get_one_from_cache($relation_name) instanceof $classname
3117
+					&& $this->get_one_from_cache($relation_name)->ID()
3118
+				) {
3119
+					$this->clear_cache(
3120
+						$relation_name,
3121
+						$this->get_one_from_cache($relation_name)->ID()
3122
+					);
3123
+				}
3124
+			}
3125
+		}
3126
+		$this->_props_n_values_provided_in_constructor = array();
3127
+		$properties_to_serialize                       = get_object_vars($this);
3128
+		//don't serialize the model. It's big and that risks recursion
3129
+		unset($properties_to_serialize['_model']);
3130
+		return array_keys($properties_to_serialize);
3131
+	}
3132
+
3133
+
3134
+	/**
3135
+	 * restore _props_n_values_provided_in_constructor
3136
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3137
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
3138
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
3139
+	 */
3140
+	public function __wakeup()
3141
+	{
3142
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
3143
+	}
3144
+
3145
+
3146
+	/**
3147
+	 * Usage of this magic method is to ensure any internally cached references to object instances that must remain
3148
+	 * distinct with the clone host instance are also cloned.
3149
+	 */
3150
+	public function __clone()
3151
+	{
3152
+		//handle DateTimes (this is handled in here because there's no one specific child class that uses datetimes).
3153
+		foreach ($this->_fields as $field => $value) {
3154
+			if ($value instanceof DateTime) {
3155
+				$this->_fields[$field] = clone $value;
3156
+			}
3157
+		}
3158
+	}
3159 3159
 }
3160 3160
 
3161 3161
 
Please login to merge, or discard this patch.
Spacing   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
         $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149 149
         // verify client code has not passed any invalid field names
150 150
         foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
151
+            if ( ! isset($model_fields[$field_name])) {
152 152
                 throw new EE_Error(
153 153
                     sprintf(
154 154
                         esc_html__(
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
             }
164 164
         }
165 165
         $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
166
+        if ( ! empty($date_formats) && is_array($date_formats)) {
167 167
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168 168
         } else {
169 169
             //set default formats for date and time
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
             foreach ($model_fields as $fieldName => $field) {
177 177
                 $this->set_from_db(
178 178
                     $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
179
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null
180 180
                 );
181 181
             }
182 182
         } else {
@@ -185,22 +185,22 @@  discard block
 block discarded – undo
185 185
             foreach ($model_fields as $fieldName => $field) {
186 186
                 $this->set(
187 187
                     $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
188
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true
189 189
                 );
190 190
             }
191 191
         }
192 192
         //remember what values were passed to this constructor
193 193
         $this->_props_n_values_provided_in_constructor = $fieldValues;
194 194
         //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
195
+        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
196 196
             $model->add_to_entity_map($this);
197 197
         }
198 198
         //setup all the relations
199 199
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200 200
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
201
+                $this->_model_relations[$relation_name] = null;
202 202
             } else {
203
-                $this->_model_relations[ $relation_name ] = array();
203
+                $this->_model_relations[$relation_name] = array();
204 204
             }
205 205
         }
206 206
         /**
@@ -251,10 +251,10 @@  discard block
 block discarded – undo
251 251
      */
252 252
     public function get_original($field_name)
253 253
     {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
254
+        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
255 255
             && $field_settings = $this->get_model()->field_settings_for($field_name)
256 256
         ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
257
+            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
258 258
         }
259 259
         return null;
260 260
     }
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         // then don't do anything
292 292
         if (
293 293
             ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
294
+            && $this->_fields[$field_name] === $field_value
295 295
             && $this->ID()
296 296
         ) {
297 297
             return;
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
             $holder_of_value = $field_obj->prepare_for_set($field_value);
310 310
             //should the value be null?
311 311
             if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
312
+                $this->_fields[$field_name] = $field_obj->get_default_value();
313 313
                 /**
314 314
                  * To save having to refactor all the models, if a default value is used for a
315 315
                  * EE_Datetime_Field, and that value is not null nor is it a DateTime
@@ -320,15 +320,15 @@  discard block
 block discarded – undo
320 320
                  */
321 321
                 if (
322 322
                     $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
323
+                    && $this->_fields[$field_name] !== null
324
+                    && ! $this->_fields[$field_name] instanceof DateTime
325 325
                 ) {
326
-                    empty($this->_fields[ $field_name ])
326
+                    empty($this->_fields[$field_name])
327 327
                         ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
328
+                        : $this->set($field_name, $this->_fields[$field_name]);
329 329
                 }
330 330
             } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
331
+                $this->_fields[$field_name] = $holder_of_value;
332 332
             }
333 333
             //if we're not in the constructor...
334 334
             //now check if what we set was a primary key
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
                 $fields_on_model = self::_get_model(get_class($this))->field_settings();
346 346
                 $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347 347
                 foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
348
+                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349 349
                         && $field_obj->get_name() !== $field_name
350 350
                     ) {
351 351
                         $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
@@ -390,8 +390,8 @@  discard block
 block discarded – undo
390 390
      */
391 391
     public function getCustomSelect($alias)
392 392
     {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
393
+        return isset($this->custom_selection_results[$alias])
394
+            ? $this->custom_selection_results[$alias]
395 395
             : null;
396 396
     }
397 397
 
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
         foreach ($model_fields as $field_name => $field_obj) {
479 479
             if ($field_obj instanceof EE_Datetime_Field) {
480 480
                 $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
481
+                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
482 482
                     EEH_DTT_Helper::setTimezone($this->_fields[$field_name], new DateTimeZone($this->_timezone));
483 483
                 }
484 484
             }
@@ -537,7 +537,7 @@  discard block
 block discarded – undo
537 537
      */
538 538
     public function get_format($full = true)
539 539
     {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
540
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541 541
     }
542 542
 
543 543
 
@@ -563,11 +563,11 @@  discard block
 block discarded – undo
563 563
     public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564 564
     {
565 565
         // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
566
+        if ( ! $object_to_cache instanceof EE_Base_Class) {
567 567
             return false;
568 568
         }
569 569
         // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
570
+        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571 571
             throw new EE_Error(
572 572
                 sprintf(
573 573
                     esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
@@ -581,38 +581,38 @@  discard block
 block discarded – undo
581 581
             // if it's a "belongs to" relationship, then there's only one related model object
582 582
             // eg, if this is a registration, there's only 1 attendee for it
583 583
             // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
584
+            $this->_model_relations[$relationName] = $object_to_cache;
585 585
             $return                                  = true;
586 586
         } else {
587 587
             // otherwise, this is the "many" side of a one to many relationship,
588 588
             // so we'll add the object to the array of related objects for that type.
589 589
             // eg: if this is an event, there are many registrations for that event,
590 590
             // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
591
+            if ( ! is_array($this->_model_relations[$relationName])) {
592 592
                 // if for some reason, the cached item is a model object,
593 593
                 // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
594
+                $this->_model_relations[$relationName] = $this->_model_relations[$relationName]
595 595
                                                            instanceof
596 596
                                                            EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
597
+                    ? array($this->_model_relations[$relationName]) : array();
598 598
             }
599 599
             // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
600
+            if ( ! empty($cache_id)) {
601 601
                 // if the cache_id exists, then it means we are purposely trying to cache this
602 602
                 // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
603
+                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
604 604
                 $return                                               = $cache_id;
605 605
             } elseif ($object_to_cache->ID()) {
606 606
                 // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
607
+                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
608 608
                 $return                                                            = $object_to_cache->ID();
609 609
             } else {
610 610
                 // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
611
+                $this->_model_relations[$relationName][] = $object_to_cache;
612 612
                 // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
613
+                end($this->_model_relations[$relationName]);
614 614
                 // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
615
+                $return = key($this->_model_relations[$relationName]);
616 616
             }
617 617
         }
618 618
         return $return;
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
         //first make sure this property exists
639 639
         $this->get_model()->field_settings_for($fieldname);
640 640
         $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
641
+        $this->_cached_properties[$fieldname][$cache_type] = $value;
642 642
     }
643 643
 
644 644
 
@@ -667,9 +667,9 @@  discard block
 block discarded – undo
667 667
         $model = $this->get_model();
668 668
         $model->field_settings_for($fieldname);
669 669
         $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
670
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
671
+        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
672
+            return $this->_cached_properties[$fieldname][$cache_type];
673 673
         }
674 674
         $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675 675
         $this->_set_cached_property($fieldname, $value, $cache_type);
@@ -697,12 +697,12 @@  discard block
 block discarded – undo
697 697
         if ($field_obj instanceof EE_Datetime_Field) {
698 698
             $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699 699
         }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
700
+        if ( ! isset($this->_fields[$fieldname])) {
701
+            $this->_fields[$fieldname] = null;
702 702
         }
703 703
         $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
704
+            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
705
+            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
706 706
         return $value;
707 707
     }
708 708
 
@@ -760,8 +760,8 @@  discard block
 block discarded – undo
760 760
      */
761 761
     protected function _clear_cached_property($property_name)
762 762
     {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
763
+        if (isset($this->_cached_properties[$property_name])) {
764
+            unset($this->_cached_properties[$property_name]);
765 765
         }
766 766
     }
767 767
 
@@ -813,7 +813,7 @@  discard block
 block discarded – undo
813 813
     {
814 814
         $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815 815
         $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
816
+        if ( ! $relationship_to_model) {
817 817
             throw new EE_Error(
818 818
                 sprintf(
819 819
                     esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
@@ -824,21 +824,21 @@  discard block
 block discarded – undo
824 824
         }
825 825
         if ($clear_all) {
826 826
             $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
827
+            $this->_model_relations[$relationName] = null;
828 828
         } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
829
+            $obj_removed                             = $this->_model_relations[$relationName];
830
+            $this->_model_relations[$relationName] = null;
831 831
         } else {
832 832
             if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833 833
                 && $object_to_remove_or_index_into_array->ID()
834 834
             ) {
835 835
                 $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
836
+                if (is_array($this->_model_relations[$relationName])
837
+                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
838 838
                 ) {
839 839
                     $index_found_at = null;
840 840
                     //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
841
+                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
842 842
                         /** @noinspection TypeUnsafeComparisonInspection */
843 843
                         if (
844 844
                             $obj instanceof EE_Base_Class
@@ -872,9 +872,9 @@  discard block
 block discarded – undo
872 872
             }
873 873
             //supposedly we've found it. But it could just be that the client code
874 874
             //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
875
+            if (isset($this->_model_relations[$relationName][$index_in_cache])) {
876
+                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
877
+                unset($this->_model_relations[$relationName][$index_in_cache]);
878 878
             } else {
879 879
                 //that thing was never cached anyways.
880 880
                 $obj_removed = null;
@@ -905,7 +905,7 @@  discard block
 block discarded – undo
905 905
         $current_cache_id = ''
906 906
     ) {
907 907
         // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
908
+        $obj_class = 'EE_'.$relationName;
909 909
         if ($newly_saved_object instanceof $obj_class) {
910 910
             /* @type EE_Base_Class $newly_saved_object */
911 911
             // now get the type of relation
@@ -913,17 +913,17 @@  discard block
 block discarded – undo
913 913
             // if this is a 1:1 relationship
914 914
             if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915 915
                 // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
916
+                $this->_model_relations[$relationName] = $newly_saved_object;
917 917
                 return true;
918 918
                 // or if it's some kind of sordid feral polyamorous relationship...
919 919
             }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
920
+            if (is_array($this->_model_relations[$relationName])
921
+                      && isset($this->_model_relations[$relationName][$current_cache_id])
922 922
             ) {
923 923
                 // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
924
+                unset($this->_model_relations[$relationName][$current_cache_id]);
925 925
                 // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
926
+                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
927 927
                 return true;
928 928
             }
929 929
         }
@@ -940,8 +940,8 @@  discard block
 block discarded – undo
940 940
      */
941 941
     public function get_one_from_cache($relationName)
942 942
     {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
943
+        $cached_array_or_object = isset($this->_model_relations[$relationName])
944
+            ? $this->_model_relations[$relationName]
945 945
             : null;
946 946
         if (is_array($cached_array_or_object)) {
947 947
             return array_shift($cached_array_or_object);
@@ -964,7 +964,7 @@  discard block
 block discarded – undo
964 964
      */
965 965
     public function get_all_from_cache($relationName)
966 966
     {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
967
+        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
968 968
         // if the result is not an array, but exists, make it an array
969 969
         $objects = is_array($objects) ? $objects : array($objects);
970 970
         //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
@@ -1148,7 +1148,7 @@  discard block
 block discarded – undo
1148 1148
             } else {
1149 1149
                 $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150 1150
             }
1151
-            $this->_fields[ $field_name ] = $field_value;
1151
+            $this->_fields[$field_name] = $field_value;
1152 1152
             $this->_clear_cached_property($field_name);
1153 1153
         }
1154 1154
     }
@@ -1188,9 +1188,9 @@  discard block
 block discarded – undo
1188 1188
     public function get_raw($field_name)
1189 1189
     {
1190 1190
         $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1191
+        return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1192
+            ? $this->_fields[$field_name]->format('U')
1193
+            : $this->_fields[$field_name];
1194 1194
     }
1195 1195
 
1196 1196
 
@@ -1212,7 +1212,7 @@  discard block
 block discarded – undo
1212 1212
     public function get_DateTime_object($field_name)
1213 1213
     {
1214 1214
         $field_settings = $this->get_model()->field_settings_for($field_name);
1215
-        if (! $field_settings instanceof EE_Datetime_Field) {
1215
+        if ( ! $field_settings instanceof EE_Datetime_Field) {
1216 1216
             EE_Error::add_error(
1217 1217
                 sprintf(
1218 1218
                     esc_html__(
@@ -1470,7 +1470,7 @@  discard block
 block discarded – undo
1470 1470
      */
1471 1471
     public function get_i18n_datetime($field_name, $format = '')
1472 1472
     {
1473
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1473
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1474 1474
         return date_i18n(
1475 1475
             $format,
1476 1476
             EEH_DTT_Helper::get_timestamp_with_offset(
@@ -1582,19 +1582,19 @@  discard block
 block discarded – undo
1582 1582
         $field->set_time_format($this->_tm_frmt);
1583 1583
         switch ($what) {
1584 1584
             case 'T' :
1585
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1585
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1586 1586
                     $datetime_value,
1587
-                    $this->_fields[ $fieldname ]
1587
+                    $this->_fields[$fieldname]
1588 1588
                 );
1589 1589
                 break;
1590 1590
             case 'D' :
1591
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1591
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1592 1592
                     $datetime_value,
1593
-                    $this->_fields[ $fieldname ]
1593
+                    $this->_fields[$fieldname]
1594 1594
                 );
1595 1595
                 break;
1596 1596
             case 'B' :
1597
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1597
+                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1598 1598
                 break;
1599 1599
         }
1600 1600
         $this->_clear_cached_property($fieldname);
@@ -1636,7 +1636,7 @@  discard block
 block discarded – undo
1636 1636
         $this->set_timezone($timezone);
1637 1637
         $fn   = (array) $field_name;
1638 1638
         $args = array_merge($fn, (array) $args);
1639
-        if (! method_exists($this, $callback)) {
1639
+        if ( ! method_exists($this, $callback)) {
1640 1640
             throw new EE_Error(
1641 1641
                 sprintf(
1642 1642
                     esc_html__(
@@ -1648,7 +1648,7 @@  discard block
 block discarded – undo
1648 1648
             );
1649 1649
         }
1650 1650
         $args   = (array) $args;
1651
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1651
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1652 1652
         $this->set_timezone($original_timezone);
1653 1653
         return $return;
1654 1654
     }
@@ -1763,8 +1763,8 @@  discard block
 block discarded – undo
1763 1763
     {
1764 1764
         $model = $this->get_model();
1765 1765
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
-            if (! empty($this->_model_relations[ $relation_name ])) {
1767
-                $related_objects = $this->_model_relations[ $relation_name ];
1766
+            if ( ! empty($this->_model_relations[$relation_name])) {
1767
+                $related_objects = $this->_model_relations[$relation_name];
1768 1768
                 if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769 1769
                     //this relation only stores a single model object, not an array
1770 1770
                     //but let's make it consistent
@@ -1821,7 +1821,7 @@  discard block
 block discarded – undo
1821 1821
             $this->set($column, $value);
1822 1822
         }
1823 1823
         // no changes ? then don't do anything
1824
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1824
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825 1825
             return 0;
1826 1826
         }
1827 1827
         /**
@@ -1831,7 +1831,7 @@  discard block
 block discarded – undo
1831 1831
          * @param EE_Base_Class $model_object the model object about to be saved.
1832 1832
          */
1833 1833
         do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
-        if (! $this->allow_persist()) {
1834
+        if ( ! $this->allow_persist()) {
1835 1835
             return 0;
1836 1836
         }
1837 1837
         // now get current attribute values
@@ -1846,10 +1846,10 @@  discard block
 block discarded – undo
1846 1846
         if ($model->has_primary_key_field()) {
1847 1847
             if ($model->get_primary_key_field()->is_auto_increment()) {
1848 1848
                 //ok check if it's set, if so: update; if not, insert
1849
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1849
+                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1850 1850
                     $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851 1851
                 } else {
1852
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1852
+                    unset($save_cols_n_values[$model->primary_key_name()]);
1853 1853
                     $results = $model->insert($save_cols_n_values);
1854 1854
                     if ($results) {
1855 1855
                         //if successful, set the primary key
@@ -1859,7 +1859,7 @@  discard block
 block discarded – undo
1859 1859
                         //will get added to the mapper before we can add this one!
1860 1860
                         //but if we just avoid using the SET method, all that headache can be avoided
1861 1861
                         $pk_field_name                   = $model->primary_key_name();
1862
-                        $this->_fields[ $pk_field_name ] = $results;
1862
+                        $this->_fields[$pk_field_name] = $results;
1863 1863
                         $this->_clear_cached_property($pk_field_name);
1864 1864
                         $model->add_to_entity_map($this);
1865 1865
                         $this->_update_cached_related_model_objs_fks();
@@ -1876,8 +1876,8 @@  discard block
 block discarded – undo
1876 1876
                                     'event_espresso'
1877 1877
                                 ),
1878 1878
                                 get_class($this),
1879
-                                get_class($model) . '::instance()->add_to_entity_map()',
1880
-                                get_class($model) . '::instance()->get_one_by_ID()',
1879
+                                get_class($model).'::instance()->add_to_entity_map()',
1880
+                                get_class($model).'::instance()->get_one_by_ID()',
1881 1881
                                 '<br />'
1882 1882
                             )
1883 1883
                         );
@@ -1977,27 +1977,27 @@  discard block
 block discarded – undo
1977 1977
     public function save_new_cached_related_model_objs()
1978 1978
     {
1979 1979
         //make sure this has been saved
1980
-        if (! $this->ID()) {
1980
+        if ( ! $this->ID()) {
1981 1981
             $id = $this->save();
1982 1982
         } else {
1983 1983
             $id = $this->ID();
1984 1984
         }
1985 1985
         //now save all the NEW cached model objects  (ie they don't exist in the DB)
1986 1986
         foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
-            if ($this->_model_relations[ $relationName ]) {
1987
+            if ($this->_model_relations[$relationName]) {
1988 1988
                 //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989 1989
                 //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990 1990
                 /* @var $related_model_obj EE_Base_Class */
1991 1991
                 if ($relationObj instanceof EE_Belongs_To_Relation) {
1992 1992
                     //add a relation to that relation type (which saves the appropriate thing in the process)
1993 1993
                     //but ONLY if it DOES NOT exist in the DB
1994
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1994
+                    $related_model_obj = $this->_model_relations[$relationName];
1995 1995
                     //					if( ! $related_model_obj->ID()){
1996 1996
                     $this->_add_relation_to($related_model_obj, $relationName);
1997 1997
                     $related_model_obj->save_new_cached_related_model_objs();
1998 1998
                     //					}
1999 1999
                 } else {
2000
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2000
+                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
2001 2001
                         //add a relation to that relation type (which saves the appropriate thing in the process)
2002 2002
                         //but ONLY if it DOES NOT exist in the DB
2003 2003
                         //						if( ! $related_model_obj->ID()){
@@ -2024,7 +2024,7 @@  discard block
 block discarded – undo
2024 2024
      */
2025 2025
     public function get_model()
2026 2026
     {
2027
-        if (! $this->_model) {
2027
+        if ( ! $this->_model) {
2028 2028
             $modelName    = self::_get_model_classname(get_class($this));
2029 2029
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030 2030
         } else {
@@ -2050,9 +2050,9 @@  discard block
 block discarded – undo
2050 2050
         $primary_id_ref = self::_get_primary_key_name($classname);
2051 2051
         if (
2052 2052
             array_key_exists($primary_id_ref, $props_n_values)
2053
-            && ! empty($props_n_values[ $primary_id_ref ])
2053
+            && ! empty($props_n_values[$primary_id_ref])
2054 2054
         ) {
2055
-            $id = $props_n_values[ $primary_id_ref ];
2055
+            $id = $props_n_values[$primary_id_ref];
2056 2056
             return self::_get_model($classname)->get_from_entity_map($id);
2057 2057
         }
2058 2058
         return false;
@@ -2086,10 +2086,10 @@  discard block
 block discarded – undo
2086 2086
         if ($model->has_primary_key_field()) {
2087 2087
             $primary_id_ref = self::_get_primary_key_name($classname);
2088 2088
             if (array_key_exists($primary_id_ref, $props_n_values)
2089
-                && ! empty($props_n_values[ $primary_id_ref ])
2089
+                && ! empty($props_n_values[$primary_id_ref])
2090 2090
             ) {
2091 2091
                 $existing = $model->get_one_by_ID(
2092
-                    $props_n_values[ $primary_id_ref ]
2092
+                    $props_n_values[$primary_id_ref]
2093 2093
                 );
2094 2094
             }
2095 2095
         } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
@@ -2101,7 +2101,7 @@  discard block
 block discarded – undo
2101 2101
         }
2102 2102
         if ($existing) {
2103 2103
             //set date formats if present before setting values
2104
-            if (! empty($date_formats) && is_array($date_formats)) {
2104
+            if ( ! empty($date_formats) && is_array($date_formats)) {
2105 2105
                 $existing->set_date_format($date_formats[0]);
2106 2106
                 $existing->set_time_format($date_formats[1]);
2107 2107
             } else {
@@ -2134,7 +2134,7 @@  discard block
 block discarded – undo
2134 2134
     protected static function _get_model($classname, $timezone = null)
2135 2135
     {
2136 2136
         //find model for this class
2137
-        if (! $classname) {
2137
+        if ( ! $classname) {
2138 2138
             throw new EE_Error(
2139 2139
                 sprintf(
2140 2140
                     esc_html__(
@@ -2183,7 +2183,7 @@  discard block
 block discarded – undo
2183 2183
         if (strpos($model_name, 'EE_') === 0) {
2184 2184
             $model_classname = str_replace('EE_', 'EEM_', $model_name);
2185 2185
         } else {
2186
-            $model_classname = 'EEM_' . $model_name;
2186
+            $model_classname = 'EEM_'.$model_name;
2187 2187
         }
2188 2188
         return $model_classname;
2189 2189
     }
@@ -2202,7 +2202,7 @@  discard block
 block discarded – undo
2202 2202
      */
2203 2203
     protected static function _get_primary_key_name($classname = null)
2204 2204
     {
2205
-        if (! $classname) {
2205
+        if ( ! $classname) {
2206 2206
             throw new EE_Error(
2207 2207
                 sprintf(
2208 2208
                     esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
@@ -2232,7 +2232,7 @@  discard block
 block discarded – undo
2232 2232
         $model = $this->get_model();
2233 2233
         //now that we know the name of the variable, use a variable variable to get its value and return its
2234 2234
         if ($model->has_primary_key_field()) {
2235
-            return $this->_fields[ $model->primary_key_name() ];
2235
+            return $this->_fields[$model->primary_key_name()];
2236 2236
         }
2237 2237
         return $model->get_index_primary_key_string($this->_fields);
2238 2238
     }
@@ -2285,7 +2285,7 @@  discard block
 block discarded – undo
2285 2285
             }
2286 2286
         } else {
2287 2287
             //this thing doesn't exist in the DB,  so just cache it
2288
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2288
+            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289 2289
                 throw new EE_Error(
2290 2290
                     sprintf(
2291 2291
                         esc_html__(
@@ -2450,7 +2450,7 @@  discard block
 block discarded – undo
2450 2450
             } else {
2451 2451
                 //did we already cache the result of this query?
2452 2452
                 $cached_results = $this->get_all_from_cache($relationName);
2453
-                if (! $cached_results) {
2453
+                if ( ! $cached_results) {
2454 2454
                     $related_model_objects = $this->get_model()->get_all_related(
2455 2455
                         $this,
2456 2456
                         $relationName,
@@ -2560,7 +2560,7 @@  discard block
 block discarded – undo
2560 2560
             } else {
2561 2561
                 //first, check if we've already cached the result of this query
2562 2562
                 $cached_result = $this->get_one_from_cache($relationName);
2563
-                if (! $cached_result) {
2563
+                if ( ! $cached_result) {
2564 2564
                     $related_model_object = $model->get_first_related(
2565 2565
                         $this,
2566 2566
                         $relationName,
@@ -2584,7 +2584,7 @@  discard block
 block discarded – undo
2584 2584
             }
2585 2585
             // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586 2586
             // just get what's cached on this object
2587
-            if (! $related_model_object) {
2587
+            if ( ! $related_model_object) {
2588 2588
                 $related_model_object = $this->get_one_from_cache($relationName);
2589 2589
             }
2590 2590
         }
@@ -2666,7 +2666,7 @@  discard block
 block discarded – undo
2666 2666
      */
2667 2667
     public function is_set($field_name)
2668 2668
     {
2669
-        return isset($this->_fields[ $field_name ]);
2669
+        return isset($this->_fields[$field_name]);
2670 2670
     }
2671 2671
 
2672 2672
 
@@ -2682,7 +2682,7 @@  discard block
 block discarded – undo
2682 2682
     {
2683 2683
         foreach ((array) $properties as $property_name) {
2684 2684
             //first make sure this property exists
2685
-            if (! $this->_fields[ $property_name ]) {
2685
+            if ( ! $this->_fields[$property_name]) {
2686 2686
                 throw new EE_Error(
2687 2687
                     sprintf(
2688 2688
                         esc_html__(
@@ -2714,7 +2714,7 @@  discard block
 block discarded – undo
2714 2714
         $properties = array();
2715 2715
         //remove prepended underscore
2716 2716
         foreach ($fields as $field_name => $settings) {
2717
-            $properties[ $field_name ] = $this->get($field_name);
2717
+            $properties[$field_name] = $this->get($field_name);
2718 2718
         }
2719 2719
         return $properties;
2720 2720
     }
@@ -2751,7 +2751,7 @@  discard block
 block discarded – undo
2751 2751
     {
2752 2752
         $className = get_class($this);
2753 2753
         $tagName   = "FHEE__{$className}__{$methodName}";
2754
-        if (! has_filter($tagName)) {
2754
+        if ( ! has_filter($tagName)) {
2755 2755
             throw new EE_Error(
2756 2756
                 sprintf(
2757 2757
                     esc_html__(
@@ -2796,7 +2796,7 @@  discard block
 block discarded – undo
2796 2796
             $query_params[0]['EXM_value'] = $meta_value;
2797 2797
         }
2798 2798
         $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
-        if (! $existing_rows_like_that) {
2799
+        if ( ! $existing_rows_like_that) {
2800 2800
             return $this->add_extra_meta($meta_key, $meta_value);
2801 2801
         }
2802 2802
         foreach ($existing_rows_like_that as $existing_row) {
@@ -2914,7 +2914,7 @@  discard block
 block discarded – undo
2914 2914
                 $values = array();
2915 2915
                 foreach ($results as $result) {
2916 2916
                     if ($result instanceof EE_Extra_Meta) {
2917
-                        $values[ $result->ID() ] = $result->value();
2917
+                        $values[$result->ID()] = $result->value();
2918 2918
                     }
2919 2919
                 }
2920 2920
                 return $values;
@@ -2959,17 +2959,17 @@  discard block
 block discarded – undo
2959 2959
             );
2960 2960
             foreach ($extra_meta_objs as $extra_meta_obj) {
2961 2961
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2962
+                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2963 2963
                 }
2964 2964
             }
2965 2965
         } else {
2966 2966
             $extra_meta_objs = $this->get_many_related('Extra_Meta');
2967 2967
             foreach ($extra_meta_objs as $extra_meta_obj) {
2968 2968
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
-                        $return_array[ $extra_meta_obj->key() ] = array();
2969
+                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2970
+                        $return_array[$extra_meta_obj->key()] = array();
2971 2971
                     }
2972
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2972
+                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2973 2973
                 }
2974 2974
             }
2975 2975
         }
@@ -3048,8 +3048,8 @@  discard block
 block discarded – undo
3048 3048
                         esc_html__('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.',
3049 3049
                             'event_espresso'),
3050 3050
                         $this->ID(),
3051
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3051
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
3052
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
3053 3053
                     )
3054 3054
                 );
3055 3055
             }
@@ -3111,7 +3111,7 @@  discard block
 block discarded – undo
3111 3111
         $model = $this->get_model();
3112 3112
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113 3113
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
-                $classname = 'EE_' . $model->get_this_model_name();
3114
+                $classname = 'EE_'.$model->get_this_model_name();
3115 3115
                 if (
3116 3116
                     $this->get_one_from_cache($relation_name) instanceof $classname
3117 3117
                     && $this->get_one_from_cache($relation_name)->ID()
Please login to merge, or discard this patch.
core/domain/services/registration/CreateRegistrationService.php 2 patches
Indentation   +76 added lines, -76 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
 use OutOfRangeException;
18 18
 
19 19
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
20
-    exit('No direct script access allowed');
20
+	exit('No direct script access allowed');
21 21
 }
22 22
 
23 23
 
@@ -41,54 +41,54 @@  discard block
 block discarded – undo
41 41
 	 * @param EE_Line_Item   $ticket_line_item
42 42
 	 * @param                 $reg_count
43 43
 	 * @param                 $reg_group_size
44
-     * @param string          $reg_status
45
-     * @return EE_Registration
44
+	 * @param string          $reg_status
45
+	 * @return EE_Registration
46 46
 	 * @throws OutOfRangeException
47 47
 	 * @throws EE_Error
48 48
 	 * @throws UnexpectedEntityException
49 49
 	 */
50
-    public function create(
51
-        EE_Event $event,
52
-        EE_Transaction $transaction,
53
-        EE_Ticket $ticket,
54
-        EE_Line_Item $ticket_line_item,
55
-        $reg_count,
56
-        $reg_group_size,
57
-        $reg_status = EEM_Registration::status_id_incomplete
58
-    ) {
59
-        $registrations = $transaction->registrations();
60
-        $reg_count = $reg_count ? $reg_count : count($registrations) + 1;
61
-        $reg_url_link = new RegUrlLink($reg_count, $ticket_line_item);
62
-        $reg_code = new RegCode($reg_url_link, $transaction, $ticket);
63
-        // generate new EE_Registration
64
-        $registration = EE_Registration::new_instance(
65
-            array(
66
-                'EVT_ID'          => $event->ID(),
67
-                'TXN_ID'          => $transaction->ID(),
68
-                'TKT_ID'          => $ticket->ID(),
69
-                'STS_ID'          => $reg_status,
70
-                'REG_final_price' => $this->resolveFinalPrice($transaction, $ticket, $ticket_line_item),
71
-                'REG_session'     => EE_Registry::instance()->SSN->id(),
72
-                'REG_count'       => $reg_count,
73
-                'REG_group_size'  => $reg_group_size ? $reg_group_size : $this->incrementRegCount($registrations),
74
-                'REG_url_link'    => $reg_url_link,
75
-                'REG_code'        => $reg_code,
76
-            )
77
-        );
78
-        if ( ! $registration instanceof EE_Registration) {
79
-            throw new UnexpectedEntityException($registration, 'EE_Registration');
80
-        }
81
-        // save registration so that we have an ID
82
-        $registration->save();
83
-        // track reservation on reg but don't adjust ticket and datetime reserved counts
84
-        // because that is done as soon as the tickets are added/removed from the cart
85
-        $registration->reserve_ticket(false, 'CreateRegistrationService:'. __LINE__);
86
-        $registration->_add_relation_to($event, 'Event', array(), $event->ID());
87
-        $registration->_add_relation_to($ticket, 'Ticket', array(), $ticket->ID());
88
-        $transaction->_add_relation_to($registration, 'Registration', array(), $registration->ID());
89
-        $registration->save();
90
-        return $registration;
91
-    }
50
+	public function create(
51
+		EE_Event $event,
52
+		EE_Transaction $transaction,
53
+		EE_Ticket $ticket,
54
+		EE_Line_Item $ticket_line_item,
55
+		$reg_count,
56
+		$reg_group_size,
57
+		$reg_status = EEM_Registration::status_id_incomplete
58
+	) {
59
+		$registrations = $transaction->registrations();
60
+		$reg_count = $reg_count ? $reg_count : count($registrations) + 1;
61
+		$reg_url_link = new RegUrlLink($reg_count, $ticket_line_item);
62
+		$reg_code = new RegCode($reg_url_link, $transaction, $ticket);
63
+		// generate new EE_Registration
64
+		$registration = EE_Registration::new_instance(
65
+			array(
66
+				'EVT_ID'          => $event->ID(),
67
+				'TXN_ID'          => $transaction->ID(),
68
+				'TKT_ID'          => $ticket->ID(),
69
+				'STS_ID'          => $reg_status,
70
+				'REG_final_price' => $this->resolveFinalPrice($transaction, $ticket, $ticket_line_item),
71
+				'REG_session'     => EE_Registry::instance()->SSN->id(),
72
+				'REG_count'       => $reg_count,
73
+				'REG_group_size'  => $reg_group_size ? $reg_group_size : $this->incrementRegCount($registrations),
74
+				'REG_url_link'    => $reg_url_link,
75
+				'REG_code'        => $reg_code,
76
+			)
77
+		);
78
+		if ( ! $registration instanceof EE_Registration) {
79
+			throw new UnexpectedEntityException($registration, 'EE_Registration');
80
+		}
81
+		// save registration so that we have an ID
82
+		$registration->save();
83
+		// track reservation on reg but don't adjust ticket and datetime reserved counts
84
+		// because that is done as soon as the tickets are added/removed from the cart
85
+		$registration->reserve_ticket(false, 'CreateRegistrationService:'. __LINE__);
86
+		$registration->_add_relation_to($event, 'Event', array(), $event->ID());
87
+		$registration->_add_relation_to($ticket, 'Ticket', array(), $ticket->ID());
88
+		$transaction->_add_relation_to($registration, 'Registration', array(), $registration->ID());
89
+		$registration->save();
90
+		return $registration;
91
+	}
92 92
 
93 93
 
94 94
 
@@ -100,40 +100,40 @@  discard block
 block discarded – undo
100 100
 	 * @throws EE_Error
101 101
 	 * @throws OutOfRangeException
102 102
 	 */
103
-    protected function resolveFinalPrice(
104
-        EE_Transaction $transaction,
105
-        EE_Ticket $ticket,
106
-        EE_Line_Item $ticket_line_item
107
-    ) {
108
-        $final_price = EEH_Line_Item::calculate_final_price_for_ticket_line_item(
109
-            $transaction->total_line_item(),
110
-            $ticket_line_item
111
-        );
112
-        $final_price = $final_price !== null ? $final_price : $ticket->get_ticket_total_with_taxes();
113
-        return (float)$final_price;
114
-    }
103
+	protected function resolveFinalPrice(
104
+		EE_Transaction $transaction,
105
+		EE_Ticket $ticket,
106
+		EE_Line_Item $ticket_line_item
107
+	) {
108
+		$final_price = EEH_Line_Item::calculate_final_price_for_ticket_line_item(
109
+			$transaction->total_line_item(),
110
+			$ticket_line_item
111
+		);
112
+		$final_price = $final_price !== null ? $final_price : $ticket->get_ticket_total_with_taxes();
113
+		return (float)$final_price;
114
+	}
115 115
 
116 116
 
117 117
 
118
-    /**
119
-     * @param  EE_Registration[] $registrations
120
-     * @param  boolean            $update_existing_registrations
121
-     * @return int
122
-     * @throws EE_Error
123
-     */
124
-    protected function incrementRegCount(array $registrations, $update_existing_registrations = true)
125
-    {
126
-        $new_reg_count = count($registrations) + 1;
127
-        if ($update_existing_registrations) {
128
-            foreach ($registrations as $registration) {
129
-                if ($registration instanceof EE_Registration) {
130
-                    $registration->set_count($new_reg_count);
131
-                    $registration->save();
132
-                }
133
-            }
134
-        }
135
-        return $new_reg_count;
136
-    }
118
+	/**
119
+	 * @param  EE_Registration[] $registrations
120
+	 * @param  boolean            $update_existing_registrations
121
+	 * @return int
122
+	 * @throws EE_Error
123
+	 */
124
+	protected function incrementRegCount(array $registrations, $update_existing_registrations = true)
125
+	{
126
+		$new_reg_count = count($registrations) + 1;
127
+		if ($update_existing_registrations) {
128
+			foreach ($registrations as $registration) {
129
+				if ($registration instanceof EE_Registration) {
130
+					$registration->set_count($new_reg_count);
131
+					$registration->save();
132
+				}
133
+			}
134
+		}
135
+		return $new_reg_count;
136
+	}
137 137
 
138 138
 
139 139
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -82,7 +82,7 @@  discard block
 block discarded – undo
82 82
         $registration->save();
83 83
         // track reservation on reg but don't adjust ticket and datetime reserved counts
84 84
         // because that is done as soon as the tickets are added/removed from the cart
85
-        $registration->reserve_ticket(false, 'CreateRegistrationService:'. __LINE__);
85
+        $registration->reserve_ticket(false, 'CreateRegistrationService:'.__LINE__);
86 86
         $registration->_add_relation_to($event, 'Event', array(), $event->ID());
87 87
         $registration->_add_relation_to($ticket, 'Ticket', array(), $ticket->ID());
88 88
         $transaction->_add_relation_to($registration, 'Registration', array(), $registration->ID());
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
             $ticket_line_item
111 111
         );
112 112
         $final_price = $final_price !== null ? $final_price : $ticket->get_ticket_total_with_taxes();
113
-        return (float)$final_price;
113
+        return (float) $final_price;
114 114
     }
115 115
 
116 116
 
Please login to merge, or discard this patch.