Completed
Branch no-trashed-question-groups (2fe455)
by
unknown
14:07 queued 11:50
created
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 1 patch
Indentation   +1451 added lines, -1451 removed lines patch added patch discarded remove patch
@@ -18,1458 +18,1458 @@
 block discarded – undo
18 18
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
19 19
 {
20 20
 
21
-    /**
22
-     * @type bool $_print_copy_info
23
-     */
24
-    private $_print_copy_info = false;
25
-
26
-    /**
27
-     * @type array $_attendee_data
28
-     */
29
-    private $_attendee_data = [];
30
-
31
-    /**
32
-     * @type array $_required_questions
33
-     */
34
-    private $_required_questions = [];
35
-
36
-    /**
37
-     * @type array $_registration_answers
38
-     */
39
-    private $_registration_answers = [];
40
-
41
-    /**
42
-     * @type int $reg_form_count
43
-     */
44
-    protected $reg_form_count = 0;
45
-
46
-
47
-    /**
48
-     *    class constructor
49
-     *
50
-     * @access    public
51
-     * @param EE_Checkout $checkout
52
-     */
53
-    public function __construct(EE_Checkout $checkout)
54
-    {
55
-        $this->request  = EED_Single_Page_Checkout::getRequest();
56
-        $this->_slug    = 'attendee_information';
57
-        $this->_name    = esc_html__('Attendee Information', 'event_espresso');
58
-        $this->checkout = $checkout;
59
-        $this->_reset_success_message();
60
-        $this->set_instructions(
61
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
62
-        );
63
-    }
64
-
65
-
66
-    public function translate_js_strings()
67
-    {
68
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
69
-            ' is a required question.',
70
-            'event_espresso'
71
-        );
72
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
73
-            ' is a required question. Please enter a value for at least one of the options.',
74
-            'event_espresso'
75
-        );
76
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
77
-            'Please answer all required questions correctly before proceeding.',
78
-            'event_espresso'
79
-        );
80
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
81
-            esc_html_x(
82
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
83
-                'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
84
-                'event_espresso'
85
-            ),
86
-            '<br/>'
87
-        );
88
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
89
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
90
-            'event_espresso'
91
-        );
92
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
93
-            'You must enter a valid email address.',
94
-            'event_espresso'
95
-        );
96
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
97
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
98
-            'event_espresso'
99
-        );
100
-    }
101
-
102
-
103
-    public function enqueue_styles_and_scripts()
104
-    {
105
-    }
106
-
107
-
108
-    /**
109
-     * @return boolean
110
-     */
111
-    public function initialize_reg_step()
112
-    {
113
-        return true;
114
-    }
115
-
116
-
117
-    /**
118
-     * @return EE_Form_Section_Proper
119
-     * @throws DomainException
120
-     * @throws EE_Error
121
-     * @throws InvalidArgumentException
122
-     * @throws ReflectionException
123
-     * @throws EntityNotFoundException
124
-     * @throws InvalidDataTypeException
125
-     * @throws InvalidInterfaceException
126
-     */
127
-    public function generate_reg_form()
128
-    {
129
-        /**
130
-         * @var $reg_config EE_Registration_Config
131
-         */
132
-        $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
133
-
134
-        $this->_print_copy_info = $reg_config->copyAttendeeInfo();
135
-
136
-        // Init reg forms count.
137
-        $this->reg_form_count = 0;
138
-
139
-        $primary_registrant = null;
140
-        // autoload Line_Item_Display classes
141
-        EEH_Autoloader::register_line_item_display_autoloaders();
142
-        $Line_Item_Display = new EE_Line_Item_Display();
143
-        // calculate taxes
144
-        $Line_Item_Display->display_line_item(
145
-            $this->checkout->cart->get_grand_total(),
146
-            ['set_tax_rate' => true]
147
-        );
148
-        /** @var $subsections EE_Form_Section_Proper[] */
149
-        $extra_inputs_section = $this->reg_step_hidden_inputs();
150
-        $subsections          = [
151
-            'default_hidden_inputs' => $extra_inputs_section,
152
-        ];
153
-
154
-        // if this isn't a revisit, and they have the privacy consent box enabled, add it
155
-        if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
156
-            $extra_inputs_section->add_subsections(
157
-                [
158
-                    'consent_box' => new EE_Form_Section_Proper(
159
-                        [
160
-                            'layout_strategy' =>
161
-                                new EE_Template_Layout(
162
-                                    [
163
-                                        'input_template_file' => SPCO_REG_STEPS_PATH
164
-                                                                 . $this->_slug
165
-                                                                 . '/privacy_consent.template.php',
166
-                                    ]
167
-                                ),
168
-                            'subsections'     => [
169
-                                'consent' => new EE_Checkbox_Multi_Input(
170
-                                    [
171
-                                        'consent' => $reg_config->getConsentCheckboxLabelText(),
172
-                                    ],
173
-                                    [
174
-                                        'required'                          => true,
175
-                                        'required_validation_error_message' => esc_html__(
176
-                                            'You must consent to these terms in order to register.',
177
-                                            'event_espresso'
178
-                                        ),
179
-                                        'html_label_text'                   => '',
180
-                                    ]
181
-                                ),
182
-                            ],
183
-                        ]
184
-                    ),
185
-                ],
186
-                null,
187
-                false
188
-            );
189
-        }
190
-        $template_args = [
191
-            'revisit'       => $this->checkout->revisit,
192
-            'registrations' => [],
193
-            'ticket_count'  => [],
194
-        ];
195
-        // grab the saved registrations from the transaction
196
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
197
-        if ($registrations) {
198
-            foreach ($registrations as $registration) {
199
-                // can this registration be processed during this visit ?
200
-                if (
201
-                    $registration instanceof EE_Registration
202
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
203
-                ) {
204
-                    $subsections[ $registration->reg_url_link() ]                       =
205
-                        $this->_registrations_reg_form($registration);
206
-                    $template_args['registrations'][ $registration->reg_url_link() ]    = $registration;
207
-                    $template_args['ticket_count'][ $registration->ticket()->ID() ]     = isset(
208
-                        $template_args['ticket_count'][ $registration->ticket()->ID() ]
209
-                    )
210
-                        ? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
211
-                        : 1;
212
-                    $ticket_line_item                                                   =
213
-                        EEH_Line_Item::get_line_items_by_object_type_and_IDs(
214
-                            $this->checkout->cart->get_grand_total(),
215
-                            'Ticket',
216
-                            [$registration->ticket()->ID()]
217
-                        );
218
-                    $ticket_line_item                                                   = is_array($ticket_line_item)
219
-                        ? reset($ticket_line_item)
220
-                        : $ticket_line_item;
221
-                    $template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
222
-                        $Line_Item_Display->display_line_item($ticket_line_item);
223
-                    if ($registration->is_primary_registrant()) {
224
-                        $primary_registrant = $registration->reg_url_link();
225
-                    }
226
-                }
227
-            }
228
-
229
-            if ($primary_registrant && count($registrations) > 1) {
230
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
231
-                    ? $this->_copy_attendee_info_form()
232
-                    : $this->_auto_copy_attendee_info();
233
-                // generate hidden input
234
-                if (
235
-                    isset($subsections[ $primary_registrant ])
236
-                    && $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
237
-                ) {
238
-                    $subsections[ $primary_registrant ]->add_subsections(
239
-                        $copy_options,
240
-                        'primary_registrant',
241
-                        false
242
-                    );
243
-                }
244
-            }
245
-        }
246
-
247
-        // Set the registration form template (default: one form per ticket details table).
248
-        // We decide the template to used based on the number of forms.
249
-        $this->_template = $this->reg_form_count > 1
250
-            ? SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_main.template.php'
251
-            : SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_single.template.php';
252
-
253
-        return new EE_Form_Section_Proper(
254
-            [
255
-                'name'            => $this->reg_form_name(),
256
-                'html_id'         => $this->reg_form_name(),
257
-                'subsections'     => $subsections,
258
-                'layout_strategy' => new EE_Template_Layout(
259
-                    [
260
-                        'layout_template_file' => $this->_template, // layout_template
261
-                        'template_args'        => $template_args,
262
-                    ]
263
-                ),
264
-            ]
265
-        );
266
-    }
267
-
268
-
269
-    /**
270
-     * @param EE_Registration $registration
271
-     * @return EE_Form_Section_Base
272
-     * @throws EE_Error
273
-     * @throws InvalidArgumentException
274
-     * @throws EntityNotFoundException
275
-     * @throws InvalidDataTypeException
276
-     * @throws InvalidInterfaceException
277
-     * @throws ReflectionException
278
-     */
279
-    private function _registrations_reg_form(EE_Registration $registration)
280
-    {
281
-        static $attendee_nmbr = 1;
282
-        $form_args = [];
283
-        // verify that registration has valid event
284
-        if ($registration->event() instanceof EE_Event) {
285
-            $field_name      = 'Event_Question_Group.'
286
-                               . EEM_Event_Question_Group::instance()->fieldNameForContext(
287
-                                   $registration->is_primary_registrant()
288
-                               );
289
-            $question_groups = $registration->event()->question_groups(
290
-                apply_filters(
291
-                // @codingStandardsIgnoreStart
292
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
293
-                    // @codingStandardsIgnoreEnd
294
-                    [
295
-                        [
296
-                            'Event.EVT_ID' => $registration->event()->ID(),
297
-                            $field_name    => true,
298
-                            'QSG_deleted'  => false
299
-                        ],
300
-                        'order_by' => ['QSG_order' => 'ASC'],
301
-                    ],
302
-                    $registration,
303
-                    $this
304
-                )
305
-            );
306
-            if ($question_groups) {
307
-                // array of params to pass to parent constructor
308
-                $form_args = [
309
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
310
-                    'html_class'      => 'ee-reg-form-attendee-dv',
311
-                    'html_style'      => $this->checkout->admin_request
312
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
313
-                        : '',
314
-                    'subsections'     => [],
315
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
316
-                        [
317
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
318
-                            'legend_text'  => sprintf(
319
-                                esc_html_x(
320
-                                    'Attendee %d',
321
-                                    'Attendee 123',
322
-                                    'event_espresso'
323
-                                ),
324
-                                $attendee_nmbr
325
-                            ),
326
-                        ]
327
-                    ),
328
-                ];
329
-                foreach ($question_groups as $question_group) {
330
-                    if ($question_group instanceof EE_Question_Group) {
331
-                        $form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
332
-                            $registration,
333
-                            $question_group
334
-                        );
335
-                    }
336
-                }
337
-                // add hidden input
338
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
339
-                    $registration
340
-                );
341
-
342
-                /**
343
-                 * @var $reg_config EE_Registration_Config
344
-                 */
345
-                $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
346
-
347
-                // If we have question groups for additional attendees, then display the copy options
348
-                $this->_print_copy_info = apply_filters(
349
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form___printCopyInfo',
350
-                    $attendee_nmbr > 1 && $reg_config->copyAttendeeInfo(),
351
-                    $attendee_nmbr
352
-                );
353
-
354
-                if ($registration->is_primary_registrant()) {
355
-                    // generate hidden input
356
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
357
-                        $registration
358
-                    );
359
-                }
360
-            }
361
-        }
362
-        $attendee_nmbr++;
363
-
364
-        // Increment the reg forms number if form is valid.
365
-        if (! empty($form_args)) {
366
-            $this->reg_form_count++;
367
-        }
368
-
369
-        return ! empty($form_args)
370
-            ? new EE_Form_Section_Proper($form_args)
371
-            : new EE_Form_Section_HTML();
372
-    }
373
-
374
-
375
-    /**
376
-     * @param EE_Registration $registration
377
-     * @param bool            $additional_attendee_reg_info
378
-     * @return EE_Form_Input_Base
379
-     * @throws EE_Error
380
-     */
381
-    private function _additional_attendee_reg_info_input(
382
-        EE_Registration $registration,
383
-        $additional_attendee_reg_info = true
384
-    ) {
385
-        // generate hidden input
386
-        return new EE_Hidden_Input(
387
-            [
388
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
389
-                'default' => $additional_attendee_reg_info,
390
-            ]
391
-        );
392
-    }
393
-
394
-
395
-    /**
396
-     * @param EE_Registration   $registration
397
-     * @param EE_Question_Group $question_group
398
-     * @return EE_Form_Section_Proper
399
-     * @throws EE_Error
400
-     * @throws InvalidArgumentException
401
-     * @throws InvalidDataTypeException
402
-     * @throws InvalidInterfaceException
403
-     * @throws ReflectionException
404
-     */
405
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
406
-    {
407
-        // array of params to pass to parent constructor
408
-        $form_args = [
409
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
410
-            'html_class'      => $this->checkout->admin_request
411
-                ? 'form-table ee-reg-form-qstn-grp-dv'
412
-                : 'ee-reg-form-qstn-grp-dv',
413
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
414
-                                 . $registration->ID() . '-lbl',
415
-            'subsections'     => [
416
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
417
-            ],
418
-            'layout_strategy' => $this->checkout->admin_request
419
-                ? new EE_Admin_Two_Column_Layout()
420
-                : new EE_Div_Per_Section_Layout(),
421
-        ];
422
-        // where params
423
-        $query_params = ['QST_deleted' => 0];
424
-        // don't load admin only questions on the frontend
425
-        if (! $this->checkout->admin_request) {
426
-            $query_params['QST_admin_only'] = ['!=', true];
427
-        }
428
-        $questions = $question_group->get_many_related(
429
-            'Question',
430
-            apply_filters(
431
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
432
-                [
433
-                    $query_params,
434
-                    'order_by' => [
435
-                        'Question_Group_Question.QGQ_order' => 'ASC',
436
-                    ],
437
-                ],
438
-                $question_group,
439
-                $registration,
440
-                $this
441
-            )
442
-        );
443
-        // filter for additional content before questions
444
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
445
-            apply_filters(
446
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
447
-                '',
448
-                $registration,
449
-                $question_group,
450
-                $this
451
-            )
452
-        );
453
-        // loop thru questions
454
-        foreach ($questions as $question) {
455
-            if ($question instanceof EE_Question) {
456
-                $identifier                              = $question->is_system_question()
457
-                    ? $question->system_ID()
458
-                    : $question->ID();
459
-                $form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
460
-            }
461
-        }
462
-        $form_args['subsections'] = apply_filters(
463
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
464
-            $form_args['subsections'],
465
-            $registration,
466
-            $question_group,
467
-            $this
468
-        );
469
-        // filter for additional content after questions
470
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
471
-            apply_filters(
472
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
473
-                '',
474
-                $registration,
475
-                $question_group,
476
-                $this
477
-            )
478
-        );
479
-        // d($form_args);
480
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
481
-        return apply_filters(
482
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
483
-            $question_group_reg_form,
484
-            $registration,
485
-            $question_group,
486
-            $this
487
-        );
488
-    }
489
-
490
-
491
-    /**
492
-     * @param EE_Question_Group $question_group
493
-     * @return    EE_Form_Section_HTML
494
-     */
495
-    private function _question_group_header(EE_Question_Group $question_group)
496
-    {
497
-        $html = '';
498
-        // group_name
499
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
500
-            if ($this->checkout->admin_request) {
501
-                $html .= EEH_HTML::br();
502
-                $html .= EEH_HTML::h3(
503
-                    $question_group->name(),
504
-                    '',
505
-                    'ee-reg-form-qstn-grp-title title',
506
-                    'font-size: 1.3em; padding-left:0;'
507
-                );
508
-            } else {
509
-                $html .= EEH_HTML::h4(
510
-                    $question_group->name(),
511
-                    '',
512
-                    'ee-reg-form-qstn-grp-title section-title'
513
-                );
514
-            }
515
-        }
516
-        // group_desc
517
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
518
-            $html .= EEH_HTML::p(
519
-                $question_group->desc(),
520
-                '',
521
-                $this->checkout->admin_request
522
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
523
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
524
-            );
525
-        }
526
-        return new EE_Form_Section_HTML($html);
527
-    }
528
-
529
-
530
-    /**
531
-     * @return    EE_Form_Section_Proper
532
-     * @throws EE_Error
533
-     * @throws InvalidArgumentException
534
-     * @throws ReflectionException
535
-     * @throws InvalidDataTypeException
536
-     * @throws InvalidInterfaceException
537
-     */
538
-    private function _copy_attendee_info_form()
539
-    {
540
-        // array of params to pass to parent constructor
541
-        return new EE_Form_Section_Proper(
542
-            [
543
-                'subsections'     => $this->_copy_attendee_info_inputs(),
544
-                'layout_strategy' => new EE_Template_Layout(
545
-                    [
546
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
547
-                                                      . $this->_slug
548
-                                                      . '/copy_attendee_info.template.php',
549
-                        'begin_template_file'      => null,
550
-                        'input_template_file'      => null,
551
-                        'subsection_template_file' => null,
552
-                        'end_template_file'        => null,
553
-                    ]
554
-                ),
555
-            ]
556
-        );
557
-    }
558
-
559
-
560
-    /**
561
-     * @return EE_Form_Section_HTML
562
-     * @throws DomainException
563
-     * @throws InvalidArgumentException
564
-     * @throws InvalidDataTypeException
565
-     * @throws InvalidInterfaceException
566
-     */
567
-    private function _auto_copy_attendee_info()
568
-    {
569
-        return new EE_Form_Section_HTML(
570
-            EEH_Template::locate_template(
571
-                SPCO_REG_STEPS_PATH . $this->_slug . '/_auto_copy_attendee_info.template.php',
572
-                apply_filters(
573
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
574
-                    []
575
-                )
576
-            )
577
-        );
578
-    }
579
-
580
-
581
-    /**
582
-     * @return array
583
-     * @throws EE_Error
584
-     * @throws InvalidArgumentException
585
-     * @throws ReflectionException
586
-     * @throws InvalidDataTypeException
587
-     * @throws InvalidInterfaceException
588
-     */
589
-    private function _copy_attendee_info_inputs()
590
-    {
591
-        $copy_attendee_info_inputs = [];
592
-        $prev_ticket               = null;
593
-        // grab the saved registrations from the transaction
594
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
595
-        foreach ($registrations as $registration) {
596
-            // for all  attendees other than the primary attendee
597
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
598
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
599
-                if ($registration->ticket()->ID() !== $prev_ticket) {
600
-                    $item_name                          = $registration->ticket()->name();
601
-                    $item_name                          .= $registration->ticket()->description() !== ''
602
-                        ? ' - ' . $registration->ticket()->description()
603
-                        : '';
604
-                    $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-'
605
-                                                . $registration->ticket()->ID()
606
-                                                . ']' ] =
607
-                        new EE_Form_Section_HTML(
608
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
609
-                        );
610
-                    $prev_ticket                        = $registration->ticket()->ID();
611
-                }
612
-
613
-                $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
614
-                    new EE_Checkbox_Multi_Input(
615
-                        [
616
-                            $registration->ID() => sprintf(
617
-                                esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
618
-                                $registration->count()
619
-                            ),
620
-                        ],
621
-                        [
622
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
623
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
624
-                            'display_html_label_text' => false,
625
-                        ]
626
-                    );
627
-            }
628
-        }
629
-        return $copy_attendee_info_inputs;
630
-    }
631
-
632
-
633
-    /**
634
-     * @param EE_Registration $registration
635
-     * @return    EE_Form_Input_Base
636
-     * @throws EE_Error
637
-     */
638
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
639
-    {
640
-        // generate hidden input
641
-        return new EE_Hidden_Input(
642
-            [
643
-                'html_id' => 'primary_registrant',
644
-                'default' => $registration->reg_url_link(),
645
-            ]
646
-        );
647
-    }
648
-
649
-
650
-    /**
651
-     * @param EE_Registration $registration
652
-     * @param EE_Question     $question
653
-     * @return EE_Form_Input_Base
654
-     * @throws EE_Error
655
-     * @throws InvalidArgumentException
656
-     * @throws InvalidDataTypeException
657
-     * @throws InvalidInterfaceException
658
-     * @throws ReflectionException
659
-     */
660
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
661
-    {
662
-
663
-        // if this question was for an attendee detail, then check for that answer
664
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
665
-            $registration,
666
-            $question->system_ID()
667
-        );
668
-        $answer       = $answer_value === null
669
-            ? EEM_Answer::instance()->get_one(
670
-                [['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
671
-            )
672
-            : null;
673
-        // if NOT returning to edit an existing registration
674
-        // OR if this question is for an attendee property
675
-        // OR we still don't have an EE_Answer object
676
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
677
-            // create an EE_Answer object for storing everything in
678
-            $answer = EE_Answer::new_instance(
679
-                [
680
-                    'QST_ID' => $question->ID(),
681
-                    'REG_ID' => $registration->ID(),
682
-                ]
683
-            );
684
-        }
685
-        // verify instance
686
-        if ($answer instanceof EE_Answer) {
687
-            if (! empty($answer_value)) {
688
-                $answer->set('ANS_value', $answer_value);
689
-            }
690
-            $answer->cache('Question', $question);
691
-            // remember system ID had a bug where sometimes it could be null
692
-            $answer_cache_id = $question->is_system_question()
693
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
694
-                : $question->ID() . '-' . $registration->reg_url_link();
695
-            $registration->cache('Answer', $answer, $answer_cache_id);
696
-        }
697
-        return $this->_generate_question_input($registration, $question, $answer);
698
-    }
699
-
700
-
701
-    /**
702
-     * @param EE_Registration $registration
703
-     * @param EE_Question     $question
704
-     * @param                 $answer
705
-     * @return EE_Form_Input_Base
706
-     * @throws EE_Error
707
-     * @throws InvalidArgumentException
708
-     * @throws ReflectionException
709
-     * @throws InvalidDataTypeException
710
-     * @throws InvalidInterfaceException
711
-     */
712
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
713
-    {
714
-        $identifier                               = $question->is_system_question()
715
-            ? $question->system_ID()
716
-            : $question->ID();
717
-        $this->_required_questions[ $identifier ] = $question->required();
718
-        add_filter(
719
-            'FHEE__EE_Question__generate_form_input__country_options',
720
-            [$this, 'use_cached_countries_for_form_input'],
721
-            10,
722
-            4
723
-        );
724
-        add_filter(
725
-            'FHEE__EE_Question__generate_form_input__state_options',
726
-            [$this, 'use_cached_states_for_form_input'],
727
-            10,
728
-            4
729
-        );
730
-        $input_constructor_args                  = [
731
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
732
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
733
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
734
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
735
-            'html_label_class' => 'ee-reg-qstn',
736
-        ];
737
-        $input_constructor_args['html_label_id'] .= '-lbl';
738
-        if ($answer instanceof EE_Answer && $answer->ID()) {
739
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
740
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
741
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
742
-        }
743
-        $form_input = $question->generate_form_input(
744
-            $registration,
745
-            $answer,
746
-            $input_constructor_args
747
-        );
748
-        remove_filter(
749
-            'FHEE__EE_Question__generate_form_input__country_options',
750
-            [$this, 'use_cached_countries_for_form_input']
751
-        );
752
-        remove_filter(
753
-            'FHEE__EE_Question__generate_form_input__state_options',
754
-            [$this, 'use_cached_states_for_form_input']
755
-        );
756
-        return $form_input;
757
-    }
758
-
759
-
760
-    /**
761
-     * Gets the list of countries for the form input
762
-     *
763
-     * @param array|null      $countries_list
764
-     * @param EE_Question     $question
765
-     * @param EE_Registration $registration
766
-     * @param EE_Answer       $answer
767
-     * @return array 2d keys are country IDs, values are their names
768
-     * @throws EE_Error
769
-     * @throws InvalidArgumentException
770
-     * @throws InvalidDataTypeException
771
-     * @throws InvalidInterfaceException
772
-     * @throws ReflectionException
773
-     */
774
-    public function use_cached_countries_for_form_input(
775
-        $countries_list,
776
-        EE_Question $question = null,
777
-        EE_Registration $registration = null,
778
-        EE_Answer $answer = null
779
-    ) {
780
-        $country_options = ['' => ''];
781
-        // get possibly cached list of countries
782
-        $countries = $this->checkout->action === 'process_reg_step'
783
-            ? EEM_Country::instance()->get_all_countries()
784
-            : EEM_Country::instance()->get_all_active_countries();
785
-        if (! empty($countries)) {
786
-            foreach ($countries as $country) {
787
-                if ($country instanceof EE_Country) {
788
-                    $country_options[ $country->ID() ] = $country->name();
789
-                }
790
-            }
791
-        }
792
-        if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
793
-            $answer = EEM_Answer::instance()->get_one(
794
-                [['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
795
-            );
796
-        } else {
797
-            $answer = EE_Answer::new_instance();
798
-        }
799
-        return apply_filters(
800
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
801
-            $country_options,
802
-            $this,
803
-            $registration,
804
-            $question,
805
-            $answer
806
-        );
807
-    }
808
-
809
-
810
-    /**
811
-     * Gets the list of states for the form input
812
-     *
813
-     * @param array|null      $states_list
814
-     * @param EE_Question     $question
815
-     * @param EE_Registration $registration
816
-     * @param EE_Answer       $answer
817
-     * @return array 2d keys are state IDs, values are their names
818
-     * @throws EE_Error
819
-     * @throws InvalidArgumentException
820
-     * @throws InvalidDataTypeException
821
-     * @throws InvalidInterfaceException
822
-     * @throws ReflectionException
823
-     */
824
-    public function use_cached_states_for_form_input(
825
-        $states_list,
826
-        EE_Question $question = null,
827
-        EE_Registration $registration = null,
828
-        EE_Answer $answer = null
829
-    ) {
830
-        $state_options = ['' => ['' => '']];
831
-        $states        = $this->checkout->action === 'process_reg_step'
832
-            ? EEM_State::instance()->get_all_states()
833
-            : EEM_State::instance()->get_all_active_states();
834
-        if (! empty($states)) {
835
-            foreach ($states as $state) {
836
-                if ($state instanceof EE_State) {
837
-                    $state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
838
-                }
839
-            }
840
-        }
841
-        return apply_filters(
842
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
843
-            $state_options,
844
-            $this,
845
-            $registration,
846
-            $question,
847
-            $answer
848
-        );
849
-    }
850
-
851
-
852
-    /********************************************************************************************************/
853
-    /****************************************  PROCESS REG STEP  ****************************************/
854
-    /********************************************************************************************************/
855
-
856
-
857
-    /**
858
-     * @return bool
859
-     * @throws EE_Error
860
-     * @throws InvalidArgumentException
861
-     * @throws ReflectionException
862
-     * @throws RuntimeException
863
-     * @throws InvalidDataTypeException
864
-     * @throws InvalidInterfaceException
865
-     */
866
-    public function process_reg_step()
867
-    {
868
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
869
-        // grab validated data from form
870
-        $valid_data = $this->checkout->current_step->valid_data();
871
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
872
-        if (empty($valid_data)) {
873
-            EE_Error::add_error(
874
-                esc_html__('No valid question responses were received.', 'event_espresso'),
875
-                __FILE__,
876
-                __FUNCTION__,
877
-                __LINE__
878
-            );
879
-            return false;
880
-        }
881
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
882
-            EE_Error::add_error(
883
-                esc_html__(
884
-                    'A valid transaction could not be initiated for processing your registrations.',
885
-                    'event_espresso'
886
-                ),
887
-                __FILE__,
888
-                __FUNCTION__,
889
-                __LINE__
890
-            );
891
-            return false;
892
-        }
893
-        // get cached registrations
894
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
895
-        // verify we got the goods
896
-        if (empty($registrations)) {
897
-            // combine the old translated string with a new one, in order to not break translations
898
-            $error_message = esc_html__(
899
-                'Your form data could not be applied to any valid registrations.',
900
-                'event_espresso'
901
-            )
902
-            . sprintf(
903
-                esc_html_x(
904
-                    '%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.',
905
-                    '(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
906
-                    'event_espresso'
907
-                ),
908
-                '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
909
-                '</a>',
910
-                '<br />'
911
-            );
912
-            EE_Error::add_error(
913
-                $error_message,
914
-                __FILE__,
915
-                __FUNCTION__,
916
-                __LINE__
917
-            );
918
-            return false;
919
-        }
920
-        // extract attendee info from form data and save to model objects
921
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
922
-        // if first pass thru SPCO,
923
-        // then let's check processed registrations against the total number of tickets in the cart
924
-        if ($registrations_processed === false) {
925
-            // but return immediately if the previous step exited early due to errors
926
-            return false;
927
-        }
928
-        if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
929
-            // generate a correctly translated string for all possible singular/plural combinations
930
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
931
-                $error_msg = sprintf(
932
-                    esc_html_x(
933
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
934
-                        'There was 1 ticket in the Event Queue, but 2 registrations were processed',
935
-                        'event_espresso'
936
-                    ),
937
-                    $this->checkout->total_ticket_count,
938
-                    $registrations_processed
939
-                );
940
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
941
-                $error_msg = sprintf(
942
-                    esc_html_x(
943
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
944
-                        'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
945
-                        'event_espresso'
946
-                    ),
947
-                    $this->checkout->total_ticket_count,
948
-                    $registrations_processed
949
-                );
950
-            } else {
951
-                $error_msg = sprintf(
952
-                    esc_html__(
953
-                        'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
954
-                        'event_espresso'
955
-                    ),
956
-                    $this->checkout->total_ticket_count,
957
-                    $registrations_processed
958
-                );
959
-            }
960
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
961
-            return false;
962
-        }
963
-        // mark this reg step as completed
964
-        $this->set_completed();
965
-        $this->_set_success_message(
966
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
967
-        );
968
-        // do action in case a plugin wants to do something with the data submitted in step 1.
969
-        // passes EE_Single_Page_Checkout, and it's posted data
970
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
971
-        return true;
972
-    }
973
-
974
-
975
-    /**
976
-     *    _process_registrations
977
-     *
978
-     * @param EE_Registration[] $registrations
979
-     * @param array[][]         $valid_data
980
-     * @return bool|int
981
-     * @throws EntityNotFoundException
982
-     * @throws EE_Error
983
-     * @throws InvalidArgumentException
984
-     * @throws ReflectionException
985
-     * @throws RuntimeException
986
-     * @throws InvalidDataTypeException
987
-     * @throws InvalidInterfaceException
988
-     */
989
-    private function _process_registrations($registrations = [], $valid_data = [])
990
-    {
991
-        // load resources and set some defaults
992
-        EE_Registry::instance()->load_model('Attendee');
993
-        // holder for primary registrant attendee object
994
-        $this->checkout->primary_attendee_obj = null;
995
-        // array for tracking reg form data for the primary registrant
996
-        $primary_registrant = [
997
-            'line_item_id' => null,
998
-        ];
999
-        $copy_primary       = false;
1000
-        // reg form sections that do not contain inputs
1001
-        $non_input_form_sections = [
1002
-            'primary_registrant',
1003
-            'additional_attendee_reg_info',
1004
-            'spco_copy_attendee_chk',
1005
-        ];
1006
-        // attendee counter
1007
-        $att_nmbr = 0;
1008
-        // grab the saved registrations from the transaction
1009
-        foreach ($registrations as $registration) {
1010
-            // verify EE_Registration object
1011
-            if (! $registration instanceof EE_Registration) {
1012
-                EE_Error::add_error(
1013
-                    esc_html__(
1014
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
1015
-                        'event_espresso'
1016
-                    ),
1017
-                    __FILE__,
1018
-                    __FUNCTION__,
1019
-                    __LINE__
1020
-                );
1021
-                return false;
1022
-            }
1023
-            $reg_url_link = $registration->reg_url_link();
1024
-            // reg_url_link exists ?
1025
-            if (! empty($reg_url_link)) {
1026
-                // should this registration be processed during this visit ?
1027
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1028
-                    // if NOT revisiting, then let's save the registration now,
1029
-                    // so that we have a REG_ID to use when generating other objects
1030
-                    if (! $this->checkout->revisit) {
1031
-                        $registration->save();
1032
-                    }
1033
-                    /**
1034
-                     * This allows plugins to trigger a fail on processing of a
1035
-                     * registration for any conditions they may have for it to pass.
1036
-                     *
1037
-                     * @var bool   if true is returned by the plugin then the
1038
-                     *            registration processing is halted.
1039
-                     */
1040
-                    if (
1041
-                        apply_filters(
1042
-                            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1043
-                            false,
1044
-                            $att_nmbr,
1045
-                            $registration,
1046
-                            $registrations,
1047
-                            $valid_data,
1048
-                            $this
1049
-                        )
1050
-                    ) {
1051
-                        return false;
1052
-                    }
1053
-
1054
-                    // Houston, we have a registration!
1055
-                    $att_nmbr++;
1056
-                    $this->_attendee_data[ $reg_url_link ] = [];
1057
-                    // grab any existing related answer objects
1058
-                    $this->_registration_answers = $registration->answers();
1059
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1060
-                    if (isset($valid_data[ $reg_url_link ])) {
1061
-                        // do we need to copy basic info from primary attendee ?
1062
-                        $copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1063
-                                        && absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1064
-                        // filter form input data for this registration
1065
-                        $valid_data[ $reg_url_link ] = (array) apply_filters(
1066
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1067
-                            $valid_data[ $reg_url_link ]
1068
-                        );
1069
-                        if (isset($valid_data['primary_attendee'])) {
1070
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1071
-                                ? $valid_data['primary_attendee']
1072
-                                : false;
1073
-                            unset($valid_data['primary_attendee']);
1074
-                        }
1075
-                        // now loop through our array of valid post data && process attendee reg forms
1076
-                        foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1077
-                            if (! in_array($form_section, $non_input_form_sections, true)) {
1078
-                                foreach ($form_inputs as $form_input => $input_value) {
1079
-                                    // check for critical inputs
1080
-                                    if (
1081
-                                        ! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1082
-                                            $form_input,
1083
-                                            $input_value
1084
-                                        )
1085
-                                    ) {
1086
-                                        return false;
1087
-                                    }
1088
-                                    // store a bit of data about the primary attendee
1089
-                                    if (
1090
-                                        $att_nmbr === 1
1091
-                                        && ! empty($input_value)
1092
-                                        && $reg_url_link === $primary_registrant['line_item_id']
1093
-                                    ) {
1094
-                                        $primary_registrant[ $form_input ] = $input_value;
1095
-                                    } elseif (
1096
-                                        $copy_primary
1097
-                                              && $input_value === null
1098
-                                              && isset($primary_registrant[ $form_input ])
1099
-                                    ) {
1100
-                                        $input_value = $primary_registrant[ $form_input ];
1101
-                                    }
1102
-                                    // now attempt to save the input data
1103
-                                    if (
1104
-                                        ! $this->_save_registration_form_input(
1105
-                                            $registration,
1106
-                                            $form_input,
1107
-                                            $input_value
1108
-                                        )
1109
-                                    ) {
1110
-                                        EE_Error::add_error(
1111
-                                            sprintf(
1112
-                                                esc_html_x(
1113
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1114
-                                                    'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1115
-                                                    'event_espresso'
1116
-                                                ),
1117
-                                                $form_input,
1118
-                                                $input_value
1119
-                                            ),
1120
-                                            __FILE__,
1121
-                                            __FUNCTION__,
1122
-                                            __LINE__
1123
-                                        );
1124
-                                        return false;
1125
-                                    }
1126
-                                }
1127
-                            }
1128
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1129
-                    }
1130
-                    // this registration does not require additional attendee information ?
1131
-                    if (
1132
-                        $copy_primary
1133
-                        && $att_nmbr > 1
1134
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1135
-                    ) {
1136
-                        // just copy the primary registrant
1137
-                        $attendee = $this->checkout->primary_attendee_obj;
1138
-                    } else {
1139
-                        // ensure critical details are set for additional attendees
1140
-                        $this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1141
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1142
-                                $this->_attendee_data[ $reg_url_link ]
1143
-                            )
1144
-                            : $this->_attendee_data[ $reg_url_link ];
1145
-                        // execute create attendee command (which may return an existing attendee)
1146
-                        $attendee = EE_Registry::instance()->BUS->execute(
1147
-                            new CreateAttendeeCommand(
1148
-                                $this->_attendee_data[ $reg_url_link ],
1149
-                                $registration
1150
-                            )
1151
-                        );
1152
-                        // who's #1 ?
1153
-                        if ($att_nmbr === 1) {
1154
-                            $this->checkout->primary_attendee_obj = $attendee;
1155
-                        }
1156
-                    }
1157
-                    // add relation to registration, set attendee ID, and cache attendee
1158
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1159
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1160
-                        EE_Error::add_error(
1161
-                            sprintf(
1162
-                                esc_html_x(
1163
-                                    'Registration %s has an invalid or missing Attendee object.',
1164
-                                    'Registration 123-456-789 has an invalid or missing Attendee object.',
1165
-                                    'event_espresso'
1166
-                                ),
1167
-                                $reg_url_link
1168
-                            ),
1169
-                            __FILE__,
1170
-                            __FUNCTION__,
1171
-                            __LINE__
1172
-                        );
1173
-                        return false;
1174
-                    }
1175
-                    /** @type EE_Registration_Processor $registration_processor */
1176
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1177
-                    // at this point, we should have enough details about the registrant to consider the registration
1178
-                    // NOT incomplete
1179
-                    $registration_processor->toggle_incomplete_registration_status_to_default(
1180
-                        $registration,
1181
-                        false,
1182
-                        new Context(
1183
-                            'spco_reg_step_attendee_information_process_registrations',
1184
-                            esc_html__(
1185
-                                'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1186
-                                'event_espresso'
1187
-                            )
1188
-                        )
1189
-                    );
1190
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1191
-                    // abandoned
1192
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1193
-                    // if we've gotten this far, then let's save what we have
1194
-                    $registration->save();
1195
-                    // add relation between TXN and registration
1196
-                    $this->_associate_registration_with_transaction($registration);
1197
-                }
1198
-            } else {
1199
-                EE_Error::add_error(
1200
-                    esc_html__(
1201
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1202
-                        'event_espresso'
1203
-                    ),
1204
-                    __FILE__,
1205
-                    __FUNCTION__,
1206
-                    __LINE__
1207
-                );
1208
-                // remove malformed data
1209
-                unset($valid_data[ $reg_url_link ]);
1210
-                return false;
1211
-            }
1212
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1213
-        return $att_nmbr;
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     *    _save_registration_form_input
1219
-     *
1220
-     * @param EE_Registration $registration
1221
-     * @param string          $form_input
1222
-     * @param string          $input_value
1223
-     * @return bool
1224
-     * @throws EE_Error
1225
-     * @throws InvalidArgumentException
1226
-     * @throws InvalidDataTypeException
1227
-     * @throws InvalidInterfaceException
1228
-     * @throws ReflectionException
1229
-     */
1230
-    private function _save_registration_form_input(
1231
-        EE_Registration $registration,
1232
-        $form_input = '',
1233
-        $input_value = ''
1234
-    ) {
1235
-        // If email_confirm is sent it's not saved
1236
-        if ((string) $form_input === 'email_confirm') {
1237
-            return true;
1238
-        }
1239
-
1240
-        // allow for plugins to hook in and do their own processing of the form input.
1241
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1242
-        if (
1243
-            apply_filters(
1244
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1245
-                false,
1246
-                $registration,
1247
-                $form_input,
1248
-                $input_value,
1249
-                $this
1250
-            )
1251
-        ) {
1252
-            return true;
1253
-        }
1254
-        /*
21
+	/**
22
+	 * @type bool $_print_copy_info
23
+	 */
24
+	private $_print_copy_info = false;
25
+
26
+	/**
27
+	 * @type array $_attendee_data
28
+	 */
29
+	private $_attendee_data = [];
30
+
31
+	/**
32
+	 * @type array $_required_questions
33
+	 */
34
+	private $_required_questions = [];
35
+
36
+	/**
37
+	 * @type array $_registration_answers
38
+	 */
39
+	private $_registration_answers = [];
40
+
41
+	/**
42
+	 * @type int $reg_form_count
43
+	 */
44
+	protected $reg_form_count = 0;
45
+
46
+
47
+	/**
48
+	 *    class constructor
49
+	 *
50
+	 * @access    public
51
+	 * @param EE_Checkout $checkout
52
+	 */
53
+	public function __construct(EE_Checkout $checkout)
54
+	{
55
+		$this->request  = EED_Single_Page_Checkout::getRequest();
56
+		$this->_slug    = 'attendee_information';
57
+		$this->_name    = esc_html__('Attendee Information', 'event_espresso');
58
+		$this->checkout = $checkout;
59
+		$this->_reset_success_message();
60
+		$this->set_instructions(
61
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
62
+		);
63
+	}
64
+
65
+
66
+	public function translate_js_strings()
67
+	{
68
+		EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
69
+			' is a required question.',
70
+			'event_espresso'
71
+		);
72
+		EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
73
+			' is a required question. Please enter a value for at least one of the options.',
74
+			'event_espresso'
75
+		);
76
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
77
+			'Please answer all required questions correctly before proceeding.',
78
+			'event_espresso'
79
+		);
80
+		EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
81
+			esc_html_x(
82
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
83
+				'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
84
+				'event_espresso'
85
+			),
86
+			'<br/>'
87
+		);
88
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
89
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
90
+			'event_espresso'
91
+		);
92
+		EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
93
+			'You must enter a valid email address.',
94
+			'event_espresso'
95
+		);
96
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
97
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
98
+			'event_espresso'
99
+		);
100
+	}
101
+
102
+
103
+	public function enqueue_styles_and_scripts()
104
+	{
105
+	}
106
+
107
+
108
+	/**
109
+	 * @return boolean
110
+	 */
111
+	public function initialize_reg_step()
112
+	{
113
+		return true;
114
+	}
115
+
116
+
117
+	/**
118
+	 * @return EE_Form_Section_Proper
119
+	 * @throws DomainException
120
+	 * @throws EE_Error
121
+	 * @throws InvalidArgumentException
122
+	 * @throws ReflectionException
123
+	 * @throws EntityNotFoundException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws InvalidInterfaceException
126
+	 */
127
+	public function generate_reg_form()
128
+	{
129
+		/**
130
+		 * @var $reg_config EE_Registration_Config
131
+		 */
132
+		$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
133
+
134
+		$this->_print_copy_info = $reg_config->copyAttendeeInfo();
135
+
136
+		// Init reg forms count.
137
+		$this->reg_form_count = 0;
138
+
139
+		$primary_registrant = null;
140
+		// autoload Line_Item_Display classes
141
+		EEH_Autoloader::register_line_item_display_autoloaders();
142
+		$Line_Item_Display = new EE_Line_Item_Display();
143
+		// calculate taxes
144
+		$Line_Item_Display->display_line_item(
145
+			$this->checkout->cart->get_grand_total(),
146
+			['set_tax_rate' => true]
147
+		);
148
+		/** @var $subsections EE_Form_Section_Proper[] */
149
+		$extra_inputs_section = $this->reg_step_hidden_inputs();
150
+		$subsections          = [
151
+			'default_hidden_inputs' => $extra_inputs_section,
152
+		];
153
+
154
+		// if this isn't a revisit, and they have the privacy consent box enabled, add it
155
+		if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
156
+			$extra_inputs_section->add_subsections(
157
+				[
158
+					'consent_box' => new EE_Form_Section_Proper(
159
+						[
160
+							'layout_strategy' =>
161
+								new EE_Template_Layout(
162
+									[
163
+										'input_template_file' => SPCO_REG_STEPS_PATH
164
+																 . $this->_slug
165
+																 . '/privacy_consent.template.php',
166
+									]
167
+								),
168
+							'subsections'     => [
169
+								'consent' => new EE_Checkbox_Multi_Input(
170
+									[
171
+										'consent' => $reg_config->getConsentCheckboxLabelText(),
172
+									],
173
+									[
174
+										'required'                          => true,
175
+										'required_validation_error_message' => esc_html__(
176
+											'You must consent to these terms in order to register.',
177
+											'event_espresso'
178
+										),
179
+										'html_label_text'                   => '',
180
+									]
181
+								),
182
+							],
183
+						]
184
+					),
185
+				],
186
+				null,
187
+				false
188
+			);
189
+		}
190
+		$template_args = [
191
+			'revisit'       => $this->checkout->revisit,
192
+			'registrations' => [],
193
+			'ticket_count'  => [],
194
+		];
195
+		// grab the saved registrations from the transaction
196
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
197
+		if ($registrations) {
198
+			foreach ($registrations as $registration) {
199
+				// can this registration be processed during this visit ?
200
+				if (
201
+					$registration instanceof EE_Registration
202
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
203
+				) {
204
+					$subsections[ $registration->reg_url_link() ]                       =
205
+						$this->_registrations_reg_form($registration);
206
+					$template_args['registrations'][ $registration->reg_url_link() ]    = $registration;
207
+					$template_args['ticket_count'][ $registration->ticket()->ID() ]     = isset(
208
+						$template_args['ticket_count'][ $registration->ticket()->ID() ]
209
+					)
210
+						? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
211
+						: 1;
212
+					$ticket_line_item                                                   =
213
+						EEH_Line_Item::get_line_items_by_object_type_and_IDs(
214
+							$this->checkout->cart->get_grand_total(),
215
+							'Ticket',
216
+							[$registration->ticket()->ID()]
217
+						);
218
+					$ticket_line_item                                                   = is_array($ticket_line_item)
219
+						? reset($ticket_line_item)
220
+						: $ticket_line_item;
221
+					$template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
222
+						$Line_Item_Display->display_line_item($ticket_line_item);
223
+					if ($registration->is_primary_registrant()) {
224
+						$primary_registrant = $registration->reg_url_link();
225
+					}
226
+				}
227
+			}
228
+
229
+			if ($primary_registrant && count($registrations) > 1) {
230
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
231
+					? $this->_copy_attendee_info_form()
232
+					: $this->_auto_copy_attendee_info();
233
+				// generate hidden input
234
+				if (
235
+					isset($subsections[ $primary_registrant ])
236
+					&& $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
237
+				) {
238
+					$subsections[ $primary_registrant ]->add_subsections(
239
+						$copy_options,
240
+						'primary_registrant',
241
+						false
242
+					);
243
+				}
244
+			}
245
+		}
246
+
247
+		// Set the registration form template (default: one form per ticket details table).
248
+		// We decide the template to used based on the number of forms.
249
+		$this->_template = $this->reg_form_count > 1
250
+			? SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_main.template.php'
251
+			: SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_single.template.php';
252
+
253
+		return new EE_Form_Section_Proper(
254
+			[
255
+				'name'            => $this->reg_form_name(),
256
+				'html_id'         => $this->reg_form_name(),
257
+				'subsections'     => $subsections,
258
+				'layout_strategy' => new EE_Template_Layout(
259
+					[
260
+						'layout_template_file' => $this->_template, // layout_template
261
+						'template_args'        => $template_args,
262
+					]
263
+				),
264
+			]
265
+		);
266
+	}
267
+
268
+
269
+	/**
270
+	 * @param EE_Registration $registration
271
+	 * @return EE_Form_Section_Base
272
+	 * @throws EE_Error
273
+	 * @throws InvalidArgumentException
274
+	 * @throws EntityNotFoundException
275
+	 * @throws InvalidDataTypeException
276
+	 * @throws InvalidInterfaceException
277
+	 * @throws ReflectionException
278
+	 */
279
+	private function _registrations_reg_form(EE_Registration $registration)
280
+	{
281
+		static $attendee_nmbr = 1;
282
+		$form_args = [];
283
+		// verify that registration has valid event
284
+		if ($registration->event() instanceof EE_Event) {
285
+			$field_name      = 'Event_Question_Group.'
286
+							   . EEM_Event_Question_Group::instance()->fieldNameForContext(
287
+								   $registration->is_primary_registrant()
288
+							   );
289
+			$question_groups = $registration->event()->question_groups(
290
+				apply_filters(
291
+				// @codingStandardsIgnoreStart
292
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
293
+					// @codingStandardsIgnoreEnd
294
+					[
295
+						[
296
+							'Event.EVT_ID' => $registration->event()->ID(),
297
+							$field_name    => true,
298
+							'QSG_deleted'  => false
299
+						],
300
+						'order_by' => ['QSG_order' => 'ASC'],
301
+					],
302
+					$registration,
303
+					$this
304
+				)
305
+			);
306
+			if ($question_groups) {
307
+				// array of params to pass to parent constructor
308
+				$form_args = [
309
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
310
+					'html_class'      => 'ee-reg-form-attendee-dv',
311
+					'html_style'      => $this->checkout->admin_request
312
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
313
+						: '',
314
+					'subsections'     => [],
315
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
316
+						[
317
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
318
+							'legend_text'  => sprintf(
319
+								esc_html_x(
320
+									'Attendee %d',
321
+									'Attendee 123',
322
+									'event_espresso'
323
+								),
324
+								$attendee_nmbr
325
+							),
326
+						]
327
+					),
328
+				];
329
+				foreach ($question_groups as $question_group) {
330
+					if ($question_group instanceof EE_Question_Group) {
331
+						$form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
332
+							$registration,
333
+							$question_group
334
+						);
335
+					}
336
+				}
337
+				// add hidden input
338
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
339
+					$registration
340
+				);
341
+
342
+				/**
343
+				 * @var $reg_config EE_Registration_Config
344
+				 */
345
+				$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
346
+
347
+				// If we have question groups for additional attendees, then display the copy options
348
+				$this->_print_copy_info = apply_filters(
349
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form___printCopyInfo',
350
+					$attendee_nmbr > 1 && $reg_config->copyAttendeeInfo(),
351
+					$attendee_nmbr
352
+				);
353
+
354
+				if ($registration->is_primary_registrant()) {
355
+					// generate hidden input
356
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
357
+						$registration
358
+					);
359
+				}
360
+			}
361
+		}
362
+		$attendee_nmbr++;
363
+
364
+		// Increment the reg forms number if form is valid.
365
+		if (! empty($form_args)) {
366
+			$this->reg_form_count++;
367
+		}
368
+
369
+		return ! empty($form_args)
370
+			? new EE_Form_Section_Proper($form_args)
371
+			: new EE_Form_Section_HTML();
372
+	}
373
+
374
+
375
+	/**
376
+	 * @param EE_Registration $registration
377
+	 * @param bool            $additional_attendee_reg_info
378
+	 * @return EE_Form_Input_Base
379
+	 * @throws EE_Error
380
+	 */
381
+	private function _additional_attendee_reg_info_input(
382
+		EE_Registration $registration,
383
+		$additional_attendee_reg_info = true
384
+	) {
385
+		// generate hidden input
386
+		return new EE_Hidden_Input(
387
+			[
388
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
389
+				'default' => $additional_attendee_reg_info,
390
+			]
391
+		);
392
+	}
393
+
394
+
395
+	/**
396
+	 * @param EE_Registration   $registration
397
+	 * @param EE_Question_Group $question_group
398
+	 * @return EE_Form_Section_Proper
399
+	 * @throws EE_Error
400
+	 * @throws InvalidArgumentException
401
+	 * @throws InvalidDataTypeException
402
+	 * @throws InvalidInterfaceException
403
+	 * @throws ReflectionException
404
+	 */
405
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
406
+	{
407
+		// array of params to pass to parent constructor
408
+		$form_args = [
409
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
410
+			'html_class'      => $this->checkout->admin_request
411
+				? 'form-table ee-reg-form-qstn-grp-dv'
412
+				: 'ee-reg-form-qstn-grp-dv',
413
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
414
+								 . $registration->ID() . '-lbl',
415
+			'subsections'     => [
416
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
417
+			],
418
+			'layout_strategy' => $this->checkout->admin_request
419
+				? new EE_Admin_Two_Column_Layout()
420
+				: new EE_Div_Per_Section_Layout(),
421
+		];
422
+		// where params
423
+		$query_params = ['QST_deleted' => 0];
424
+		// don't load admin only questions on the frontend
425
+		if (! $this->checkout->admin_request) {
426
+			$query_params['QST_admin_only'] = ['!=', true];
427
+		}
428
+		$questions = $question_group->get_many_related(
429
+			'Question',
430
+			apply_filters(
431
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
432
+				[
433
+					$query_params,
434
+					'order_by' => [
435
+						'Question_Group_Question.QGQ_order' => 'ASC',
436
+					],
437
+				],
438
+				$question_group,
439
+				$registration,
440
+				$this
441
+			)
442
+		);
443
+		// filter for additional content before questions
444
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
445
+			apply_filters(
446
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
447
+				'',
448
+				$registration,
449
+				$question_group,
450
+				$this
451
+			)
452
+		);
453
+		// loop thru questions
454
+		foreach ($questions as $question) {
455
+			if ($question instanceof EE_Question) {
456
+				$identifier                              = $question->is_system_question()
457
+					? $question->system_ID()
458
+					: $question->ID();
459
+				$form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
460
+			}
461
+		}
462
+		$form_args['subsections'] = apply_filters(
463
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
464
+			$form_args['subsections'],
465
+			$registration,
466
+			$question_group,
467
+			$this
468
+		);
469
+		// filter for additional content after questions
470
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
471
+			apply_filters(
472
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
473
+				'',
474
+				$registration,
475
+				$question_group,
476
+				$this
477
+			)
478
+		);
479
+		// d($form_args);
480
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
481
+		return apply_filters(
482
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
483
+			$question_group_reg_form,
484
+			$registration,
485
+			$question_group,
486
+			$this
487
+		);
488
+	}
489
+
490
+
491
+	/**
492
+	 * @param EE_Question_Group $question_group
493
+	 * @return    EE_Form_Section_HTML
494
+	 */
495
+	private function _question_group_header(EE_Question_Group $question_group)
496
+	{
497
+		$html = '';
498
+		// group_name
499
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
500
+			if ($this->checkout->admin_request) {
501
+				$html .= EEH_HTML::br();
502
+				$html .= EEH_HTML::h3(
503
+					$question_group->name(),
504
+					'',
505
+					'ee-reg-form-qstn-grp-title title',
506
+					'font-size: 1.3em; padding-left:0;'
507
+				);
508
+			} else {
509
+				$html .= EEH_HTML::h4(
510
+					$question_group->name(),
511
+					'',
512
+					'ee-reg-form-qstn-grp-title section-title'
513
+				);
514
+			}
515
+		}
516
+		// group_desc
517
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
518
+			$html .= EEH_HTML::p(
519
+				$question_group->desc(),
520
+				'',
521
+				$this->checkout->admin_request
522
+					? 'ee-reg-form-qstn-grp-desc-pg'
523
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
524
+			);
525
+		}
526
+		return new EE_Form_Section_HTML($html);
527
+	}
528
+
529
+
530
+	/**
531
+	 * @return    EE_Form_Section_Proper
532
+	 * @throws EE_Error
533
+	 * @throws InvalidArgumentException
534
+	 * @throws ReflectionException
535
+	 * @throws InvalidDataTypeException
536
+	 * @throws InvalidInterfaceException
537
+	 */
538
+	private function _copy_attendee_info_form()
539
+	{
540
+		// array of params to pass to parent constructor
541
+		return new EE_Form_Section_Proper(
542
+			[
543
+				'subsections'     => $this->_copy_attendee_info_inputs(),
544
+				'layout_strategy' => new EE_Template_Layout(
545
+					[
546
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
547
+													  . $this->_slug
548
+													  . '/copy_attendee_info.template.php',
549
+						'begin_template_file'      => null,
550
+						'input_template_file'      => null,
551
+						'subsection_template_file' => null,
552
+						'end_template_file'        => null,
553
+					]
554
+				),
555
+			]
556
+		);
557
+	}
558
+
559
+
560
+	/**
561
+	 * @return EE_Form_Section_HTML
562
+	 * @throws DomainException
563
+	 * @throws InvalidArgumentException
564
+	 * @throws InvalidDataTypeException
565
+	 * @throws InvalidInterfaceException
566
+	 */
567
+	private function _auto_copy_attendee_info()
568
+	{
569
+		return new EE_Form_Section_HTML(
570
+			EEH_Template::locate_template(
571
+				SPCO_REG_STEPS_PATH . $this->_slug . '/_auto_copy_attendee_info.template.php',
572
+				apply_filters(
573
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
574
+					[]
575
+				)
576
+			)
577
+		);
578
+	}
579
+
580
+
581
+	/**
582
+	 * @return array
583
+	 * @throws EE_Error
584
+	 * @throws InvalidArgumentException
585
+	 * @throws ReflectionException
586
+	 * @throws InvalidDataTypeException
587
+	 * @throws InvalidInterfaceException
588
+	 */
589
+	private function _copy_attendee_info_inputs()
590
+	{
591
+		$copy_attendee_info_inputs = [];
592
+		$prev_ticket               = null;
593
+		// grab the saved registrations from the transaction
594
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
595
+		foreach ($registrations as $registration) {
596
+			// for all  attendees other than the primary attendee
597
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
598
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
599
+				if ($registration->ticket()->ID() !== $prev_ticket) {
600
+					$item_name                          = $registration->ticket()->name();
601
+					$item_name                          .= $registration->ticket()->description() !== ''
602
+						? ' - ' . $registration->ticket()->description()
603
+						: '';
604
+					$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-'
605
+												. $registration->ticket()->ID()
606
+												. ']' ] =
607
+						new EE_Form_Section_HTML(
608
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
609
+						);
610
+					$prev_ticket                        = $registration->ticket()->ID();
611
+				}
612
+
613
+				$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
614
+					new EE_Checkbox_Multi_Input(
615
+						[
616
+							$registration->ID() => sprintf(
617
+								esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
618
+								$registration->count()
619
+							),
620
+						],
621
+						[
622
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
623
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
624
+							'display_html_label_text' => false,
625
+						]
626
+					);
627
+			}
628
+		}
629
+		return $copy_attendee_info_inputs;
630
+	}
631
+
632
+
633
+	/**
634
+	 * @param EE_Registration $registration
635
+	 * @return    EE_Form_Input_Base
636
+	 * @throws EE_Error
637
+	 */
638
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
639
+	{
640
+		// generate hidden input
641
+		return new EE_Hidden_Input(
642
+			[
643
+				'html_id' => 'primary_registrant',
644
+				'default' => $registration->reg_url_link(),
645
+			]
646
+		);
647
+	}
648
+
649
+
650
+	/**
651
+	 * @param EE_Registration $registration
652
+	 * @param EE_Question     $question
653
+	 * @return EE_Form_Input_Base
654
+	 * @throws EE_Error
655
+	 * @throws InvalidArgumentException
656
+	 * @throws InvalidDataTypeException
657
+	 * @throws InvalidInterfaceException
658
+	 * @throws ReflectionException
659
+	 */
660
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
661
+	{
662
+
663
+		// if this question was for an attendee detail, then check for that answer
664
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
665
+			$registration,
666
+			$question->system_ID()
667
+		);
668
+		$answer       = $answer_value === null
669
+			? EEM_Answer::instance()->get_one(
670
+				[['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
671
+			)
672
+			: null;
673
+		// if NOT returning to edit an existing registration
674
+		// OR if this question is for an attendee property
675
+		// OR we still don't have an EE_Answer object
676
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
677
+			// create an EE_Answer object for storing everything in
678
+			$answer = EE_Answer::new_instance(
679
+				[
680
+					'QST_ID' => $question->ID(),
681
+					'REG_ID' => $registration->ID(),
682
+				]
683
+			);
684
+		}
685
+		// verify instance
686
+		if ($answer instanceof EE_Answer) {
687
+			if (! empty($answer_value)) {
688
+				$answer->set('ANS_value', $answer_value);
689
+			}
690
+			$answer->cache('Question', $question);
691
+			// remember system ID had a bug where sometimes it could be null
692
+			$answer_cache_id = $question->is_system_question()
693
+				? $question->system_ID() . '-' . $registration->reg_url_link()
694
+				: $question->ID() . '-' . $registration->reg_url_link();
695
+			$registration->cache('Answer', $answer, $answer_cache_id);
696
+		}
697
+		return $this->_generate_question_input($registration, $question, $answer);
698
+	}
699
+
700
+
701
+	/**
702
+	 * @param EE_Registration $registration
703
+	 * @param EE_Question     $question
704
+	 * @param                 $answer
705
+	 * @return EE_Form_Input_Base
706
+	 * @throws EE_Error
707
+	 * @throws InvalidArgumentException
708
+	 * @throws ReflectionException
709
+	 * @throws InvalidDataTypeException
710
+	 * @throws InvalidInterfaceException
711
+	 */
712
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
713
+	{
714
+		$identifier                               = $question->is_system_question()
715
+			? $question->system_ID()
716
+			: $question->ID();
717
+		$this->_required_questions[ $identifier ] = $question->required();
718
+		add_filter(
719
+			'FHEE__EE_Question__generate_form_input__country_options',
720
+			[$this, 'use_cached_countries_for_form_input'],
721
+			10,
722
+			4
723
+		);
724
+		add_filter(
725
+			'FHEE__EE_Question__generate_form_input__state_options',
726
+			[$this, 'use_cached_states_for_form_input'],
727
+			10,
728
+			4
729
+		);
730
+		$input_constructor_args                  = [
731
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
732
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
733
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
734
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
735
+			'html_label_class' => 'ee-reg-qstn',
736
+		];
737
+		$input_constructor_args['html_label_id'] .= '-lbl';
738
+		if ($answer instanceof EE_Answer && $answer->ID()) {
739
+			$input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
740
+			$input_constructor_args['html_id']       .= '-' . $answer->ID();
741
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
742
+		}
743
+		$form_input = $question->generate_form_input(
744
+			$registration,
745
+			$answer,
746
+			$input_constructor_args
747
+		);
748
+		remove_filter(
749
+			'FHEE__EE_Question__generate_form_input__country_options',
750
+			[$this, 'use_cached_countries_for_form_input']
751
+		);
752
+		remove_filter(
753
+			'FHEE__EE_Question__generate_form_input__state_options',
754
+			[$this, 'use_cached_states_for_form_input']
755
+		);
756
+		return $form_input;
757
+	}
758
+
759
+
760
+	/**
761
+	 * Gets the list of countries for the form input
762
+	 *
763
+	 * @param array|null      $countries_list
764
+	 * @param EE_Question     $question
765
+	 * @param EE_Registration $registration
766
+	 * @param EE_Answer       $answer
767
+	 * @return array 2d keys are country IDs, values are their names
768
+	 * @throws EE_Error
769
+	 * @throws InvalidArgumentException
770
+	 * @throws InvalidDataTypeException
771
+	 * @throws InvalidInterfaceException
772
+	 * @throws ReflectionException
773
+	 */
774
+	public function use_cached_countries_for_form_input(
775
+		$countries_list,
776
+		EE_Question $question = null,
777
+		EE_Registration $registration = null,
778
+		EE_Answer $answer = null
779
+	) {
780
+		$country_options = ['' => ''];
781
+		// get possibly cached list of countries
782
+		$countries = $this->checkout->action === 'process_reg_step'
783
+			? EEM_Country::instance()->get_all_countries()
784
+			: EEM_Country::instance()->get_all_active_countries();
785
+		if (! empty($countries)) {
786
+			foreach ($countries as $country) {
787
+				if ($country instanceof EE_Country) {
788
+					$country_options[ $country->ID() ] = $country->name();
789
+				}
790
+			}
791
+		}
792
+		if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
793
+			$answer = EEM_Answer::instance()->get_one(
794
+				[['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
795
+			);
796
+		} else {
797
+			$answer = EE_Answer::new_instance();
798
+		}
799
+		return apply_filters(
800
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
801
+			$country_options,
802
+			$this,
803
+			$registration,
804
+			$question,
805
+			$answer
806
+		);
807
+	}
808
+
809
+
810
+	/**
811
+	 * Gets the list of states for the form input
812
+	 *
813
+	 * @param array|null      $states_list
814
+	 * @param EE_Question     $question
815
+	 * @param EE_Registration $registration
816
+	 * @param EE_Answer       $answer
817
+	 * @return array 2d keys are state IDs, values are their names
818
+	 * @throws EE_Error
819
+	 * @throws InvalidArgumentException
820
+	 * @throws InvalidDataTypeException
821
+	 * @throws InvalidInterfaceException
822
+	 * @throws ReflectionException
823
+	 */
824
+	public function use_cached_states_for_form_input(
825
+		$states_list,
826
+		EE_Question $question = null,
827
+		EE_Registration $registration = null,
828
+		EE_Answer $answer = null
829
+	) {
830
+		$state_options = ['' => ['' => '']];
831
+		$states        = $this->checkout->action === 'process_reg_step'
832
+			? EEM_State::instance()->get_all_states()
833
+			: EEM_State::instance()->get_all_active_states();
834
+		if (! empty($states)) {
835
+			foreach ($states as $state) {
836
+				if ($state instanceof EE_State) {
837
+					$state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
838
+				}
839
+			}
840
+		}
841
+		return apply_filters(
842
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
843
+			$state_options,
844
+			$this,
845
+			$registration,
846
+			$question,
847
+			$answer
848
+		);
849
+	}
850
+
851
+
852
+	/********************************************************************************************************/
853
+	/****************************************  PROCESS REG STEP  ****************************************/
854
+	/********************************************************************************************************/
855
+
856
+
857
+	/**
858
+	 * @return bool
859
+	 * @throws EE_Error
860
+	 * @throws InvalidArgumentException
861
+	 * @throws ReflectionException
862
+	 * @throws RuntimeException
863
+	 * @throws InvalidDataTypeException
864
+	 * @throws InvalidInterfaceException
865
+	 */
866
+	public function process_reg_step()
867
+	{
868
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
869
+		// grab validated data from form
870
+		$valid_data = $this->checkout->current_step->valid_data();
871
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
872
+		if (empty($valid_data)) {
873
+			EE_Error::add_error(
874
+				esc_html__('No valid question responses were received.', 'event_espresso'),
875
+				__FILE__,
876
+				__FUNCTION__,
877
+				__LINE__
878
+			);
879
+			return false;
880
+		}
881
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
882
+			EE_Error::add_error(
883
+				esc_html__(
884
+					'A valid transaction could not be initiated for processing your registrations.',
885
+					'event_espresso'
886
+				),
887
+				__FILE__,
888
+				__FUNCTION__,
889
+				__LINE__
890
+			);
891
+			return false;
892
+		}
893
+		// get cached registrations
894
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
895
+		// verify we got the goods
896
+		if (empty($registrations)) {
897
+			// combine the old translated string with a new one, in order to not break translations
898
+			$error_message = esc_html__(
899
+				'Your form data could not be applied to any valid registrations.',
900
+				'event_espresso'
901
+			)
902
+			. sprintf(
903
+				esc_html_x(
904
+					'%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.',
905
+					'(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
906
+					'event_espresso'
907
+				),
908
+				'<a href="' . get_post_type_archive_link('espresso_events') . '" >',
909
+				'</a>',
910
+				'<br />'
911
+			);
912
+			EE_Error::add_error(
913
+				$error_message,
914
+				__FILE__,
915
+				__FUNCTION__,
916
+				__LINE__
917
+			);
918
+			return false;
919
+		}
920
+		// extract attendee info from form data and save to model objects
921
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
922
+		// if first pass thru SPCO,
923
+		// then let's check processed registrations against the total number of tickets in the cart
924
+		if ($registrations_processed === false) {
925
+			// but return immediately if the previous step exited early due to errors
926
+			return false;
927
+		}
928
+		if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
929
+			// generate a correctly translated string for all possible singular/plural combinations
930
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
931
+				$error_msg = sprintf(
932
+					esc_html_x(
933
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
934
+						'There was 1 ticket in the Event Queue, but 2 registrations were processed',
935
+						'event_espresso'
936
+					),
937
+					$this->checkout->total_ticket_count,
938
+					$registrations_processed
939
+				);
940
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
941
+				$error_msg = sprintf(
942
+					esc_html_x(
943
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
944
+						'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
945
+						'event_espresso'
946
+					),
947
+					$this->checkout->total_ticket_count,
948
+					$registrations_processed
949
+				);
950
+			} else {
951
+				$error_msg = sprintf(
952
+					esc_html__(
953
+						'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
954
+						'event_espresso'
955
+					),
956
+					$this->checkout->total_ticket_count,
957
+					$registrations_processed
958
+				);
959
+			}
960
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
961
+			return false;
962
+		}
963
+		// mark this reg step as completed
964
+		$this->set_completed();
965
+		$this->_set_success_message(
966
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
967
+		);
968
+		// do action in case a plugin wants to do something with the data submitted in step 1.
969
+		// passes EE_Single_Page_Checkout, and it's posted data
970
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
971
+		return true;
972
+	}
973
+
974
+
975
+	/**
976
+	 *    _process_registrations
977
+	 *
978
+	 * @param EE_Registration[] $registrations
979
+	 * @param array[][]         $valid_data
980
+	 * @return bool|int
981
+	 * @throws EntityNotFoundException
982
+	 * @throws EE_Error
983
+	 * @throws InvalidArgumentException
984
+	 * @throws ReflectionException
985
+	 * @throws RuntimeException
986
+	 * @throws InvalidDataTypeException
987
+	 * @throws InvalidInterfaceException
988
+	 */
989
+	private function _process_registrations($registrations = [], $valid_data = [])
990
+	{
991
+		// load resources and set some defaults
992
+		EE_Registry::instance()->load_model('Attendee');
993
+		// holder for primary registrant attendee object
994
+		$this->checkout->primary_attendee_obj = null;
995
+		// array for tracking reg form data for the primary registrant
996
+		$primary_registrant = [
997
+			'line_item_id' => null,
998
+		];
999
+		$copy_primary       = false;
1000
+		// reg form sections that do not contain inputs
1001
+		$non_input_form_sections = [
1002
+			'primary_registrant',
1003
+			'additional_attendee_reg_info',
1004
+			'spco_copy_attendee_chk',
1005
+		];
1006
+		// attendee counter
1007
+		$att_nmbr = 0;
1008
+		// grab the saved registrations from the transaction
1009
+		foreach ($registrations as $registration) {
1010
+			// verify EE_Registration object
1011
+			if (! $registration instanceof EE_Registration) {
1012
+				EE_Error::add_error(
1013
+					esc_html__(
1014
+						'An invalid Registration object was discovered when attempting to process your registration information.',
1015
+						'event_espresso'
1016
+					),
1017
+					__FILE__,
1018
+					__FUNCTION__,
1019
+					__LINE__
1020
+				);
1021
+				return false;
1022
+			}
1023
+			$reg_url_link = $registration->reg_url_link();
1024
+			// reg_url_link exists ?
1025
+			if (! empty($reg_url_link)) {
1026
+				// should this registration be processed during this visit ?
1027
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1028
+					// if NOT revisiting, then let's save the registration now,
1029
+					// so that we have a REG_ID to use when generating other objects
1030
+					if (! $this->checkout->revisit) {
1031
+						$registration->save();
1032
+					}
1033
+					/**
1034
+					 * This allows plugins to trigger a fail on processing of a
1035
+					 * registration for any conditions they may have for it to pass.
1036
+					 *
1037
+					 * @var bool   if true is returned by the plugin then the
1038
+					 *            registration processing is halted.
1039
+					 */
1040
+					if (
1041
+						apply_filters(
1042
+							'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1043
+							false,
1044
+							$att_nmbr,
1045
+							$registration,
1046
+							$registrations,
1047
+							$valid_data,
1048
+							$this
1049
+						)
1050
+					) {
1051
+						return false;
1052
+					}
1053
+
1054
+					// Houston, we have a registration!
1055
+					$att_nmbr++;
1056
+					$this->_attendee_data[ $reg_url_link ] = [];
1057
+					// grab any existing related answer objects
1058
+					$this->_registration_answers = $registration->answers();
1059
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1060
+					if (isset($valid_data[ $reg_url_link ])) {
1061
+						// do we need to copy basic info from primary attendee ?
1062
+						$copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1063
+										&& absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1064
+						// filter form input data for this registration
1065
+						$valid_data[ $reg_url_link ] = (array) apply_filters(
1066
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1067
+							$valid_data[ $reg_url_link ]
1068
+						);
1069
+						if (isset($valid_data['primary_attendee'])) {
1070
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1071
+								? $valid_data['primary_attendee']
1072
+								: false;
1073
+							unset($valid_data['primary_attendee']);
1074
+						}
1075
+						// now loop through our array of valid post data && process attendee reg forms
1076
+						foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1077
+							if (! in_array($form_section, $non_input_form_sections, true)) {
1078
+								foreach ($form_inputs as $form_input => $input_value) {
1079
+									// check for critical inputs
1080
+									if (
1081
+										! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1082
+											$form_input,
1083
+											$input_value
1084
+										)
1085
+									) {
1086
+										return false;
1087
+									}
1088
+									// store a bit of data about the primary attendee
1089
+									if (
1090
+										$att_nmbr === 1
1091
+										&& ! empty($input_value)
1092
+										&& $reg_url_link === $primary_registrant['line_item_id']
1093
+									) {
1094
+										$primary_registrant[ $form_input ] = $input_value;
1095
+									} elseif (
1096
+										$copy_primary
1097
+											  && $input_value === null
1098
+											  && isset($primary_registrant[ $form_input ])
1099
+									) {
1100
+										$input_value = $primary_registrant[ $form_input ];
1101
+									}
1102
+									// now attempt to save the input data
1103
+									if (
1104
+										! $this->_save_registration_form_input(
1105
+											$registration,
1106
+											$form_input,
1107
+											$input_value
1108
+										)
1109
+									) {
1110
+										EE_Error::add_error(
1111
+											sprintf(
1112
+												esc_html_x(
1113
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1114
+													'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1115
+													'event_espresso'
1116
+												),
1117
+												$form_input,
1118
+												$input_value
1119
+											),
1120
+											__FILE__,
1121
+											__FUNCTION__,
1122
+											__LINE__
1123
+										);
1124
+										return false;
1125
+									}
1126
+								}
1127
+							}
1128
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1129
+					}
1130
+					// this registration does not require additional attendee information ?
1131
+					if (
1132
+						$copy_primary
1133
+						&& $att_nmbr > 1
1134
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1135
+					) {
1136
+						// just copy the primary registrant
1137
+						$attendee = $this->checkout->primary_attendee_obj;
1138
+					} else {
1139
+						// ensure critical details are set for additional attendees
1140
+						$this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1141
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1142
+								$this->_attendee_data[ $reg_url_link ]
1143
+							)
1144
+							: $this->_attendee_data[ $reg_url_link ];
1145
+						// execute create attendee command (which may return an existing attendee)
1146
+						$attendee = EE_Registry::instance()->BUS->execute(
1147
+							new CreateAttendeeCommand(
1148
+								$this->_attendee_data[ $reg_url_link ],
1149
+								$registration
1150
+							)
1151
+						);
1152
+						// who's #1 ?
1153
+						if ($att_nmbr === 1) {
1154
+							$this->checkout->primary_attendee_obj = $attendee;
1155
+						}
1156
+					}
1157
+					// add relation to registration, set attendee ID, and cache attendee
1158
+					$this->_associate_attendee_with_registration($registration, $attendee);
1159
+					if (! $registration->attendee() instanceof EE_Attendee) {
1160
+						EE_Error::add_error(
1161
+							sprintf(
1162
+								esc_html_x(
1163
+									'Registration %s has an invalid or missing Attendee object.',
1164
+									'Registration 123-456-789 has an invalid or missing Attendee object.',
1165
+									'event_espresso'
1166
+								),
1167
+								$reg_url_link
1168
+							),
1169
+							__FILE__,
1170
+							__FUNCTION__,
1171
+							__LINE__
1172
+						);
1173
+						return false;
1174
+					}
1175
+					/** @type EE_Registration_Processor $registration_processor */
1176
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1177
+					// at this point, we should have enough details about the registrant to consider the registration
1178
+					// NOT incomplete
1179
+					$registration_processor->toggle_incomplete_registration_status_to_default(
1180
+						$registration,
1181
+						false,
1182
+						new Context(
1183
+							'spco_reg_step_attendee_information_process_registrations',
1184
+							esc_html__(
1185
+								'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1186
+								'event_espresso'
1187
+							)
1188
+						)
1189
+					);
1190
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1191
+					// abandoned
1192
+					$this->checkout->transaction->toggle_failed_transaction_status();
1193
+					// if we've gotten this far, then let's save what we have
1194
+					$registration->save();
1195
+					// add relation between TXN and registration
1196
+					$this->_associate_registration_with_transaction($registration);
1197
+				}
1198
+			} else {
1199
+				EE_Error::add_error(
1200
+					esc_html__(
1201
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1202
+						'event_espresso'
1203
+					),
1204
+					__FILE__,
1205
+					__FUNCTION__,
1206
+					__LINE__
1207
+				);
1208
+				// remove malformed data
1209
+				unset($valid_data[ $reg_url_link ]);
1210
+				return false;
1211
+			}
1212
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1213
+		return $att_nmbr;
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 *    _save_registration_form_input
1219
+	 *
1220
+	 * @param EE_Registration $registration
1221
+	 * @param string          $form_input
1222
+	 * @param string          $input_value
1223
+	 * @return bool
1224
+	 * @throws EE_Error
1225
+	 * @throws InvalidArgumentException
1226
+	 * @throws InvalidDataTypeException
1227
+	 * @throws InvalidInterfaceException
1228
+	 * @throws ReflectionException
1229
+	 */
1230
+	private function _save_registration_form_input(
1231
+		EE_Registration $registration,
1232
+		$form_input = '',
1233
+		$input_value = ''
1234
+	) {
1235
+		// If email_confirm is sent it's not saved
1236
+		if ((string) $form_input === 'email_confirm') {
1237
+			return true;
1238
+		}
1239
+
1240
+		// allow for plugins to hook in and do their own processing of the form input.
1241
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1242
+		if (
1243
+			apply_filters(
1244
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1245
+				false,
1246
+				$registration,
1247
+				$form_input,
1248
+				$input_value,
1249
+				$this
1250
+			)
1251
+		) {
1252
+			return true;
1253
+		}
1254
+		/*
1255 1255
          * $answer_cache_id is the key used to find the EE_Answer we want
1256 1256
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1257 1257
          */
1258
-        $answer_cache_id = $this->checkout->reg_url_link
1259
-            ? $form_input . '-' . $registration->reg_url_link()
1260
-            : (string) $form_input;
1261
-        $answer_is_obj   = isset($this->_registration_answers[ $answer_cache_id ])
1262
-                           && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1263
-        // rename form_inputs if they are EE_Attendee properties
1264
-        switch ((string) $form_input) {
1265
-            case 'state':
1266
-            case 'STA_ID':
1267
-                $attendee_property = true;
1268
-                $form_input        = 'STA_ID';
1269
-                break;
1270
-
1271
-            case 'country':
1272
-            case 'CNT_ISO':
1273
-                $attendee_property = true;
1274
-                $form_input        = 'CNT_ISO';
1275
-                break;
1276
-
1277
-            default:
1278
-                $ATT_input = 'ATT_' . $form_input;
1279
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input);
1280
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1281
-        }
1282
-        // if this form input has a corresponding attendee property
1283
-        if ($attendee_property) {
1284
-            $this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1285
-            if ($answer_is_obj) {
1286
-                // and delete the corresponding answer since we won't be storing this data in that object
1287
-                $registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1288
-                $this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1289
-            }
1290
-            return true;
1291
-        }
1292
-        if ($answer_is_obj) {
1293
-            // save this data to the answer object
1294
-            $this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1295
-            $result = $this->_registration_answers[ $answer_cache_id ]->save();
1296
-            return $result !== false;
1297
-        }
1298
-        foreach ($this->_registration_answers as $answer) {
1299
-            if ($answer instanceof EE_Answer && (string) $answer->question_ID() === $answer_cache_id) {
1300
-                $answer->set_value($input_value);
1301
-                $result = $answer->save();
1302
-                return $result !== false;
1303
-            }
1304
-        }
1305
-        return false;
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     *    _verify_critical_attendee_details_are_set
1311
-     *
1312
-     * @param string $form_input
1313
-     * @param string $input_value
1314
-     * @return boolean
1315
-     */
1316
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1317
-        $form_input = '',
1318
-        $input_value = ''
1319
-    ) {
1320
-        if (empty($input_value)) {
1321
-            // if the form input isn't marked as being required, then just return
1322
-            if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1323
-                return true;
1324
-            }
1325
-            switch ($form_input) {
1326
-                case 'fname':
1327
-                    EE_Error::add_error(
1328
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1329
-                        __FILE__,
1330
-                        __FUNCTION__,
1331
-                        __LINE__
1332
-                    );
1333
-                    return false;
1334
-                case 'lname':
1335
-                    EE_Error::add_error(
1336
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1337
-                        __FILE__,
1338
-                        __FUNCTION__,
1339
-                        __LINE__
1340
-                    );
1341
-                    return false;
1342
-                case 'email':
1343
-                    EE_Error::add_error(
1344
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1345
-                        __FILE__,
1346
-                        __FUNCTION__,
1347
-                        __LINE__
1348
-                    );
1349
-                    return false;
1350
-            }
1351
-        }
1352
-        return true;
1353
-    }
1354
-
1355
-
1356
-    /**
1357
-     *    _associate_attendee_with_registration
1358
-     *
1359
-     * @param EE_Registration $registration
1360
-     * @param EE_Attendee     $attendee
1361
-     * @return void
1362
-     * @throws EE_Error
1363
-     * @throws InvalidArgumentException
1364
-     * @throws ReflectionException
1365
-     * @throws RuntimeException
1366
-     * @throws InvalidDataTypeException
1367
-     * @throws InvalidInterfaceException
1368
-     */
1369
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1370
-    {
1371
-        // add relation to attendee
1372
-        $registration->_add_relation_to($attendee, 'Attendee');
1373
-        $registration->set_attendee_id($attendee->ID());
1374
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1375
-    }
1376
-
1377
-
1378
-    /**
1379
-     *    _associate_registration_with_transaction
1380
-     *
1381
-     * @param EE_Registration $registration
1382
-     * @return void
1383
-     * @throws EE_Error
1384
-     * @throws InvalidArgumentException
1385
-     * @throws ReflectionException
1386
-     * @throws InvalidDataTypeException
1387
-     * @throws InvalidInterfaceException
1388
-     */
1389
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1390
-    {
1391
-        // add relation to registration
1392
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1393
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1394
-    }
1395
-
1396
-
1397
-    /**
1398
-     *    _copy_critical_attendee_details_from_primary_registrant
1399
-     *    ensures that all attendees at least have data for first name, last name, and email address
1400
-     *
1401
-     * @param array $attendee_data
1402
-     * @return array
1403
-     * @throws EE_Error
1404
-     * @throws InvalidArgumentException
1405
-     * @throws ReflectionException
1406
-     * @throws InvalidDataTypeException
1407
-     * @throws InvalidInterfaceException
1408
-     */
1409
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = [])
1410
-    {
1411
-        // bare minimum critical details include first name, last name, email address
1412
-        $critical_attendee_details = ['ATT_fname', 'ATT_lname', 'ATT_email'];
1413
-        // add address info to critical details?
1414
-        if (
1415
-            apply_filters(
1416
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1417
-                false
1418
-            )
1419
-        ) {
1420
-            $address_details           = [
1421
-                'ATT_address',
1422
-                'ATT_address2',
1423
-                'ATT_city',
1424
-                'STA_ID',
1425
-                'CNT_ISO',
1426
-                'ATT_zip',
1427
-                'ATT_phone',
1428
-            ];
1429
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1430
-        }
1431
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1432
-            if (
1433
-                ! isset($attendee_data[ $critical_attendee_detail ])
1434
-                || empty($attendee_data[ $critical_attendee_detail ])
1435
-            ) {
1436
-                $attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1437
-                    $critical_attendee_detail
1438
-                );
1439
-            }
1440
-        }
1441
-        return $attendee_data;
1442
-    }
1443
-
1444
-
1445
-    /**
1446
-     *    update_reg_step
1447
-     *    this is the final step after a user  revisits the site to edit their attendee information
1448
-     *    this gets called AFTER the process_reg_step() method above
1449
-     *
1450
-     * @return bool
1451
-     * @throws EE_Error
1452
-     * @throws InvalidArgumentException
1453
-     * @throws ReflectionException
1454
-     * @throws RuntimeException
1455
-     * @throws InvalidDataTypeException
1456
-     * @throws InvalidInterfaceException
1457
-     */
1458
-    public function update_reg_step()
1459
-    {
1460
-        // save everything
1461
-        if ($this->process_reg_step()) {
1462
-            $this->checkout->redirect     = true;
1463
-            $this->checkout->redirect_url = add_query_arg(
1464
-                [
1465
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1466
-                    'revisit'        => true,
1467
-                ],
1468
-                $this->checkout->thank_you_page_url
1469
-            );
1470
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1471
-            return true;
1472
-        }
1473
-        return false;
1474
-    }
1258
+		$answer_cache_id = $this->checkout->reg_url_link
1259
+			? $form_input . '-' . $registration->reg_url_link()
1260
+			: (string) $form_input;
1261
+		$answer_is_obj   = isset($this->_registration_answers[ $answer_cache_id ])
1262
+						   && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1263
+		// rename form_inputs if they are EE_Attendee properties
1264
+		switch ((string) $form_input) {
1265
+			case 'state':
1266
+			case 'STA_ID':
1267
+				$attendee_property = true;
1268
+				$form_input        = 'STA_ID';
1269
+				break;
1270
+
1271
+			case 'country':
1272
+			case 'CNT_ISO':
1273
+				$attendee_property = true;
1274
+				$form_input        = 'CNT_ISO';
1275
+				break;
1276
+
1277
+			default:
1278
+				$ATT_input = 'ATT_' . $form_input;
1279
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input);
1280
+				$form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1281
+		}
1282
+		// if this form input has a corresponding attendee property
1283
+		if ($attendee_property) {
1284
+			$this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1285
+			if ($answer_is_obj) {
1286
+				// and delete the corresponding answer since we won't be storing this data in that object
1287
+				$registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1288
+				$this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1289
+			}
1290
+			return true;
1291
+		}
1292
+		if ($answer_is_obj) {
1293
+			// save this data to the answer object
1294
+			$this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1295
+			$result = $this->_registration_answers[ $answer_cache_id ]->save();
1296
+			return $result !== false;
1297
+		}
1298
+		foreach ($this->_registration_answers as $answer) {
1299
+			if ($answer instanceof EE_Answer && (string) $answer->question_ID() === $answer_cache_id) {
1300
+				$answer->set_value($input_value);
1301
+				$result = $answer->save();
1302
+				return $result !== false;
1303
+			}
1304
+		}
1305
+		return false;
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 *    _verify_critical_attendee_details_are_set
1311
+	 *
1312
+	 * @param string $form_input
1313
+	 * @param string $input_value
1314
+	 * @return boolean
1315
+	 */
1316
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1317
+		$form_input = '',
1318
+		$input_value = ''
1319
+	) {
1320
+		if (empty($input_value)) {
1321
+			// if the form input isn't marked as being required, then just return
1322
+			if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1323
+				return true;
1324
+			}
1325
+			switch ($form_input) {
1326
+				case 'fname':
1327
+					EE_Error::add_error(
1328
+						esc_html__('First Name is a required value.', 'event_espresso'),
1329
+						__FILE__,
1330
+						__FUNCTION__,
1331
+						__LINE__
1332
+					);
1333
+					return false;
1334
+				case 'lname':
1335
+					EE_Error::add_error(
1336
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1337
+						__FILE__,
1338
+						__FUNCTION__,
1339
+						__LINE__
1340
+					);
1341
+					return false;
1342
+				case 'email':
1343
+					EE_Error::add_error(
1344
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1345
+						__FILE__,
1346
+						__FUNCTION__,
1347
+						__LINE__
1348
+					);
1349
+					return false;
1350
+			}
1351
+		}
1352
+		return true;
1353
+	}
1354
+
1355
+
1356
+	/**
1357
+	 *    _associate_attendee_with_registration
1358
+	 *
1359
+	 * @param EE_Registration $registration
1360
+	 * @param EE_Attendee     $attendee
1361
+	 * @return void
1362
+	 * @throws EE_Error
1363
+	 * @throws InvalidArgumentException
1364
+	 * @throws ReflectionException
1365
+	 * @throws RuntimeException
1366
+	 * @throws InvalidDataTypeException
1367
+	 * @throws InvalidInterfaceException
1368
+	 */
1369
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1370
+	{
1371
+		// add relation to attendee
1372
+		$registration->_add_relation_to($attendee, 'Attendee');
1373
+		$registration->set_attendee_id($attendee->ID());
1374
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1375
+	}
1376
+
1377
+
1378
+	/**
1379
+	 *    _associate_registration_with_transaction
1380
+	 *
1381
+	 * @param EE_Registration $registration
1382
+	 * @return void
1383
+	 * @throws EE_Error
1384
+	 * @throws InvalidArgumentException
1385
+	 * @throws ReflectionException
1386
+	 * @throws InvalidDataTypeException
1387
+	 * @throws InvalidInterfaceException
1388
+	 */
1389
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1390
+	{
1391
+		// add relation to registration
1392
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1393
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1394
+	}
1395
+
1396
+
1397
+	/**
1398
+	 *    _copy_critical_attendee_details_from_primary_registrant
1399
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1400
+	 *
1401
+	 * @param array $attendee_data
1402
+	 * @return array
1403
+	 * @throws EE_Error
1404
+	 * @throws InvalidArgumentException
1405
+	 * @throws ReflectionException
1406
+	 * @throws InvalidDataTypeException
1407
+	 * @throws InvalidInterfaceException
1408
+	 */
1409
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = [])
1410
+	{
1411
+		// bare minimum critical details include first name, last name, email address
1412
+		$critical_attendee_details = ['ATT_fname', 'ATT_lname', 'ATT_email'];
1413
+		// add address info to critical details?
1414
+		if (
1415
+			apply_filters(
1416
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1417
+				false
1418
+			)
1419
+		) {
1420
+			$address_details           = [
1421
+				'ATT_address',
1422
+				'ATT_address2',
1423
+				'ATT_city',
1424
+				'STA_ID',
1425
+				'CNT_ISO',
1426
+				'ATT_zip',
1427
+				'ATT_phone',
1428
+			];
1429
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1430
+		}
1431
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1432
+			if (
1433
+				! isset($attendee_data[ $critical_attendee_detail ])
1434
+				|| empty($attendee_data[ $critical_attendee_detail ])
1435
+			) {
1436
+				$attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1437
+					$critical_attendee_detail
1438
+				);
1439
+			}
1440
+		}
1441
+		return $attendee_data;
1442
+	}
1443
+
1444
+
1445
+	/**
1446
+	 *    update_reg_step
1447
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1448
+	 *    this gets called AFTER the process_reg_step() method above
1449
+	 *
1450
+	 * @return bool
1451
+	 * @throws EE_Error
1452
+	 * @throws InvalidArgumentException
1453
+	 * @throws ReflectionException
1454
+	 * @throws RuntimeException
1455
+	 * @throws InvalidDataTypeException
1456
+	 * @throws InvalidInterfaceException
1457
+	 */
1458
+	public function update_reg_step()
1459
+	{
1460
+		// save everything
1461
+		if ($this->process_reg_step()) {
1462
+			$this->checkout->redirect     = true;
1463
+			$this->checkout->redirect_url = add_query_arg(
1464
+				[
1465
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1466
+					'revisit'        => true,
1467
+				],
1468
+				$this->checkout->thank_you_page_url
1469
+			);
1470
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1471
+			return true;
1472
+		}
1473
+		return false;
1474
+	}
1475 1475
 }
Please login to merge, or discard this patch.