Completed
Branch BUG-10878-event-spaces-remaini... (49b4f1)
by
unknown
53:16 queued 42:45
created
core/libraries/messages/messenger/EE_Email_messenger.class.php 2 patches
Indentation   +641 added lines, -641 removed lines patch added patch discarded remove patch
@@ -8,645 +8,645 @@
 block discarded – undo
8 8
 class EE_Email_messenger extends EE_messenger
9 9
 {
10 10
 
11
-    /**
12
-     * To field for email
13
-     * @var string
14
-     */
15
-    protected $_to = '';
16
-
17
-
18
-    /**
19
-     * CC field for email.
20
-     * @var string
21
-     */
22
-    protected $_cc = '';
23
-
24
-    /**
25
-     * From field for email
26
-     * @var string
27
-     */
28
-    protected $_from = '';
29
-
30
-
31
-    /**
32
-     * Subject field for email
33
-     * @var string
34
-     */
35
-    protected $_subject = '';
36
-
37
-
38
-    /**
39
-     * Content field for email
40
-     * @var string
41
-     */
42
-    protected $_content = '';
43
-
44
-
45
-    /**
46
-     * constructor
47
-     *
48
-     * @access public
49
-     */
50
-    public function __construct()
51
-    {
52
-        //set name and description properties
53
-        $this->name                = 'email';
54
-        $this->description         = sprintf(
55
-            esc_html__(
56
-                'This messenger delivers messages via email using the built-in %s function included with WordPress',
57
-                'event_espresso'
58
-            ),
59
-            '<code>wp_mail</code>'
60
-        );
61
-        $this->label               = array(
62
-            'singular' => esc_html__('email', 'event_espresso'),
63
-            'plural'   => esc_html__('emails', 'event_espresso'),
64
-        );
65
-        $this->activate_on_install = true;
66
-
67
-        //we're using defaults so let's call parent constructor that will take care of setting up all the other
68
-        // properties
69
-        parent::__construct();
70
-    }
71
-
72
-
73
-    /**
74
-     * see abstract declaration in parent class for details.
75
-     */
76
-    protected function _set_admin_pages()
77
-    {
78
-        $this->admin_registered_pages = array(
79
-            'events_edit' => true,
80
-        );
81
-    }
82
-
83
-
84
-    /**
85
-     * see abstract declaration in parent class for details
86
-     */
87
-    protected function _set_valid_shortcodes()
88
-    {
89
-        //remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
90
-        // message type.
91
-        $this->_valid_shortcodes = array(
92
-            'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
93
-            'cc' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
94
-            'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
95
-        );
96
-    }
97
-
98
-
99
-    /**
100
-     * see abstract declaration in parent class for details
101
-     *
102
-     * @access protected
103
-     * @return void
104
-     */
105
-    protected function _set_validator_config()
106
-    {
107
-        $valid_shortcodes = $this->get_valid_shortcodes();
108
-
109
-        $this->_validator_config = array(
110
-            'to'            => array(
111
-                'shortcodes' => $valid_shortcodes['to'],
112
-                'type'       => 'email',
113
-            ),
114
-            'cc' => array(
115
-                'shortcodes' => $valid_shortcodes['to'],
116
-                'type' => 'email',
117
-            ),
118
-            'from'          => array(
119
-                'shortcodes' => $valid_shortcodes['from'],
120
-                'type'       => 'email',
121
-            ),
122
-            'subject'       => array(
123
-                'shortcodes' => array(
124
-                    'organization',
125
-                    'primary_registration_details',
126
-                    'event_author',
127
-                    'primary_registration_details',
128
-                    'recipient_details',
129
-                ),
130
-            ),
131
-            'content'       => array(
132
-                'shortcodes' => array(
133
-                    'event_list',
134
-                    'attendee_list',
135
-                    'ticket_list',
136
-                    'organization',
137
-                    'primary_registration_details',
138
-                    'primary_registration_list',
139
-                    'event_author',
140
-                    'recipient_details',
141
-                    'recipient_list',
142
-                    'transaction',
143
-                    'messenger',
144
-                ),
145
-            ),
146
-            'attendee_list' => array(
147
-                'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
148
-                'required'   => array('[ATTENDEE_LIST]'),
149
-            ),
150
-            'event_list'    => array(
151
-                'shortcodes' => array(
152
-                    'event',
153
-                    'attendee_list',
154
-                    'ticket_list',
155
-                    'venue',
156
-                    'datetime_list',
157
-                    'attendee',
158
-                    'primary_registration_details',
159
-                    'primary_registration_list',
160
-                    'event_author',
161
-                    'recipient_details',
162
-                    'recipient_list',
163
-                ),
164
-                'required'   => array('[EVENT_LIST]'),
165
-            ),
166
-            'ticket_list'   => array(
167
-                'shortcodes' => array(
168
-                    'event_list',
169
-                    'attendee_list',
170
-                    'ticket',
171
-                    'datetime_list',
172
-                    'primary_registration_details',
173
-                    'recipient_details',
174
-                ),
175
-                'required'   => array('[TICKET_LIST]'),
176
-            ),
177
-            'datetime_list' => array(
178
-                'shortcodes' => array('datetime'),
179
-                'required'   => array('[DATETIME_LIST]'),
180
-            ),
181
-        );
182
-    }
183
-
184
-
185
-    /**
186
-     * @see   parent EE_messenger class for docs
187
-     * @since 4.5.0
188
-     */
189
-    public function do_secondary_messenger_hooks($sending_messenger_name)
190
-    {
191
-        if ($sending_messenger_name = 'html') {
192
-            add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
193
-        }
194
-    }
195
-
196
-
197
-    public function add_email_css(
198
-        $variation_path,
199
-        $messenger,
200
-        $message_type,
201
-        $type,
202
-        $variation,
203
-        $file_extension,
204
-        $url,
205
-        EE_Messages_Template_Pack $template_pack
206
-    ) {
207
-        //prevent recursion on this callback.
208
-        remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
209
-        $variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
210
-
211
-        add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
212
-        return $variation;
213
-    }
214
-
215
-
216
-    /**
217
-     * See parent for details
218
-     *
219
-     * @access protected
220
-     * @return void
221
-     */
222
-    protected function _set_test_settings_fields()
223
-    {
224
-        $this->_test_settings_fields = array(
225
-            'to'      => array(
226
-                'input'      => 'text',
227
-                'label'      => esc_html__('Send a test email to', 'event_espresso'),
228
-                'type'       => 'email',
229
-                'required'   => true,
230
-                'validation' => true,
231
-                'css_class'  => 'large-text',
232
-                'format'     => '%s',
233
-                'default'    => get_bloginfo('admin_email'),
234
-            ),
235
-            'subject' => array(
236
-                'input'      => 'hidden',
237
-                'label'      => '',
238
-                'type'       => 'string',
239
-                'required'   => false,
240
-                'validation' => false,
241
-                'format'     => '%s',
242
-                'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
243
-                'default'    => '',
244
-                'css_class'  => '',
245
-            ),
246
-        );
247
-    }
248
-
249
-
250
-    /**
251
-     * _set_template_fields
252
-     * This sets up the fields that a messenger requires for the message to go out.
253
-     *
254
-     * @access  protected
255
-     * @return void
256
-     */
257
-    protected function _set_template_fields()
258
-    {
259
-        // any extra template fields that are NOT used by the messenger but will get used by a messenger field for
260
-        // shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
261
-        // they relate to.  This is important for the Messages_admin to know what fields to display to the user.
262
-        //  Also, notice that the "values" are equal to the field type that messages admin will use to know what
263
-        // kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
264
-        // indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
265
-        // displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
266
-        // will not be displayed/parsed.
267
-        $this->_template_fields = array(
268
-            'to'      => array(
269
-                'input'      => 'text',
270
-                'label'      => esc_html_x(
271
-                    'To',
272
-                    'Label for the "To" field for email addresses',
273
-                    'event_espresso'
274
-                ),
275
-                'type'       => 'string',
276
-                'required'   => true,
277
-                'validation' => true,
278
-                'css_class'  => 'large-text',
279
-                'format'     => '%s',
280
-            ),
281
-            'cc'      => array(
282
-                'input'      => 'text',
283
-                'label'      => esc_html_x(
284
-                    'CC',
285
-                    'Label for the "Carbon Copy" field used for additional email addresses',
286
-                    'event_espresso'
287
-                ),
288
-                'type'       => 'string',
289
-                'required'   => false,
290
-                'validation' => true,
291
-                'css_class'  => 'large-text',
292
-                'format'     => '%s',
293
-            ),
294
-            'from'    => array(
295
-                'input'      => 'text',
296
-                'label'      => esc_html_x(
297
-                    'From',
298
-                    'Label for the "From" field for email addresses.',
299
-                    'event_espresso'
300
-                ),
301
-                'type'       => 'string',
302
-                'required'   => true,
303
-                'validation' => true,
304
-                'css_class'  => 'large-text',
305
-                'format'     => '%s',
306
-            ),
307
-            'subject' => array(
308
-                'input'      => 'text',
309
-                'label'      => esc_html_x(
310
-                    'Subject',
311
-                    'Label for the "Subject" field (short description of contents) for emails.',
312
-                    'event_espresso'
313
-                ),
314
-                'type'       => 'string',
315
-                'required'   => true,
316
-                'validation' => true,
317
-                'css_class'  => 'large-text',
318
-                'format'     => '%s',
319
-            ),
320
-            'content' => '',
321
-            //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
322
-            'extra'   => array(
323
-                'content' => array(
324
-                    'main'          => array(
325
-                        'input'      => 'wp_editor',
326
-                        'label'      => esc_html__('Main Content', 'event_espresso'),
327
-                        'type'       => 'string',
328
-                        'required'   => true,
329
-                        'validation' => true,
330
-                        'format'     => '%s',
331
-                        'rows'       => '15',
332
-                    ),
333
-                    'event_list'    => array(
334
-                        'input'               => 'wp_editor',
335
-                        'label'               => '[EVENT_LIST]',
336
-                        'type'                => 'string',
337
-                        'required'            => true,
338
-                        'validation'          => true,
339
-                        'format'              => '%s',
340
-                        'rows'                => '15',
341
-                        'shortcodes_required' => array('[EVENT_LIST]'),
342
-                    ),
343
-                    'attendee_list' => array(
344
-                        'input'               => 'textarea',
345
-                        'label'               => '[ATTENDEE_LIST]',
346
-                        'type'                => 'string',
347
-                        'required'            => true,
348
-                        'validation'          => true,
349
-                        'format'              => '%s',
350
-                        'css_class'           => 'large-text',
351
-                        'rows'                => '5',
352
-                        'shortcodes_required' => array('[ATTENDEE_LIST]'),
353
-                    ),
354
-                    'ticket_list'   => array(
355
-                        'input'               => 'textarea',
356
-                        'label'               => '[TICKET_LIST]',
357
-                        'type'                => 'string',
358
-                        'required'            => true,
359
-                        'validation'          => true,
360
-                        'format'              => '%s',
361
-                        'css_class'           => 'large-text',
362
-                        'rows'                => '10',
363
-                        'shortcodes_required' => array('[TICKET_LIST]'),
364
-                    ),
365
-                    'datetime_list' => array(
366
-                        'input'               => 'textarea',
367
-                        'label'               => '[DATETIME_LIST]',
368
-                        'type'                => 'string',
369
-                        'required'            => true,
370
-                        'validation'          => true,
371
-                        'format'              => '%s',
372
-                        'css_class'           => 'large-text',
373
-                        'rows'                => '10',
374
-                        'shortcodes_required' => array('[DATETIME_LIST]'),
375
-                    ),
376
-                ),
377
-            ),
378
-        );
379
-    }
380
-
381
-
382
-    /**
383
-     * See definition of this class in parent
384
-     */
385
-    protected function _set_default_message_types()
386
-    {
387
-        $this->_default_message_types = array(
388
-            'payment',
389
-            'payment_refund',
390
-            'registration',
391
-            'not_approved_registration',
392
-            'pending_approval',
393
-        );
394
-    }
395
-
396
-
397
-    /**
398
-     * @see   definition of this class in parent
399
-     * @since 4.5.0
400
-     */
401
-    protected function _set_valid_message_types()
402
-    {
403
-        $this->_valid_message_types = array(
404
-            'payment',
405
-            'registration',
406
-            'not_approved_registration',
407
-            'declined_registration',
408
-            'cancelled_registration',
409
-            'pending_approval',
410
-            'registration_summary',
411
-            'payment_reminder',
412
-            'payment_declined',
413
-            'payment_refund',
414
-        );
415
-    }
416
-
417
-
418
-    /**
419
-     * setting up admin_settings_fields for messenger.
420
-     */
421
-    protected function _set_admin_settings_fields()
422
-    {
423
-    }
424
-
425
-    /**
426
-     * We just deliver the messages don't kill us!!
427
-     *
428
-     * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
429
-     *              present.
430
-     * @throws EE_Error
431
-     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
432
-     */
433
-    protected function _send_message()
434
-    {
435
-        $success = wp_mail(
436
-            html_entity_decode($this->_to, ENT_QUOTES, "UTF-8"),
437
-            stripslashes(html_entity_decode($this->_subject, ENT_QUOTES, "UTF-8")),
438
-            $this->_body(),
439
-            $this->_headers()
440
-        );
441
-        if (! $success) {
442
-            EE_Error::add_error(
443
-                sprintf(
444
-                    esc_html__(
445
-                        'The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
446
-                        'event_espresso'
447
-                    ),
448
-                    $this->_to,
449
-                    $this->_from,
450
-                    '<br />'
451
-                ),
452
-                __FILE__,
453
-                __FUNCTION__,
454
-                __LINE__
455
-            );
456
-        }
457
-        return $success;
458
-    }
459
-
460
-
461
-    /**
462
-     * see parent for definition
463
-     *
464
-     * @return string html body of the message content and the related css.
465
-     * @throws EE_Error
466
-     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
467
-     */
468
-    protected function _preview()
469
-    {
470
-        return $this->_body(true);
471
-    }
472
-
473
-
474
-    /**
475
-     * Setup headers for email
476
-     *
477
-     * @access protected
478
-     * @return string formatted header for email
479
-     */
480
-    protected function _headers()
481
-    {
482
-        $this->_ensure_has_from_email_address();
483
-        $from    = stripslashes_deep(html_entity_decode($this->_from, ENT_QUOTES, "UTF-8"));
484
-        $headers = array(
485
-            'From:' . $from,
486
-            'Reply-To:' . $from,
487
-            'Content-Type:text/html; charset=utf-8',
488
-        );
489
-
490
-        if (! empty($this->_cc)) {
491
-            $headers[] = 'cc: ' . $this->_cc;
492
-        }
493
-
494
-        //but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
495
-        // header.
496
-        add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
497
-        add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
498
-        return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
499
-    }
500
-
501
-
502
-    /**
503
-     * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
504
-     * address for the from address to avoid problems with sending emails.
505
-     */
506
-    protected function _ensure_has_from_email_address()
507
-    {
508
-        if (empty($this->_from)) {
509
-            $this->_from = get_bloginfo('admin_email');
510
-        }
511
-    }
512
-
513
-
514
-    /**
515
-     * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
516
-     * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
517
-     * be empty
518
-     *
519
-     * @since 4.3.1
520
-     * @return array
521
-     */
522
-    private function _parse_from()
523
-    {
524
-        if (strpos($this->_from, '<') !== false) {
525
-            $from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
526
-            $from_name = str_replace('"', '', $from_name);
527
-            $from_name = trim($from_name);
528
-
529
-            $from_email = substr($this->_from, strpos($this->_from, '<') + 1);
530
-            $from_email = str_replace('>', '', $from_email);
531
-            $from_email = trim($from_email);
532
-        } elseif (trim($this->_from) !== '') {
533
-            $from_name  = '';
534
-            $from_email = trim($this->_from);
535
-        } else {
536
-            $from_name = $from_email = '';
537
-        }
538
-        return array($from_name, $from_email);
539
-    }
540
-
541
-
542
-    /**
543
-     * Callback for the wp_mail_from filter.
544
-     *
545
-     * @since 4.3.1
546
-     * @param string $from_email What the original from_email is.
547
-     * @return string
548
-     */
549
-    public function set_from_address($from_email)
550
-    {
551
-        $parsed_from = $this->_parse_from();
552
-        //includes fallback if the parsing failed.
553
-        $from_email = is_array($parsed_from) && ! empty($parsed_from[1])
554
-            ? $parsed_from[1]
555
-            : get_bloginfo('admin_email');
556
-        return $from_email;
557
-    }
558
-
559
-
560
-    /**
561
-     * Callback fro the wp_mail_from_name filter.
562
-     *
563
-     * @since 4.3.1
564
-     * @param string $from_name The original from_name.
565
-     * @return string
566
-     */
567
-    public function set_from_name($from_name)
568
-    {
569
-        $parsed_from = $this->_parse_from();
570
-        if (is_array($parsed_from) && ! empty($parsed_from[0])) {
571
-            $from_name = $parsed_from[0];
572
-        }
573
-
574
-        //if from name is "WordPress" let's sub in the site name instead (more friendly!)
575
-        $from_name = $from_name == 'WordPress' ? get_bloginfo() : $from_name;
576
-
577
-        return stripslashes_deep(html_entity_decode($from_name, ENT_QUOTES, "UTF-8"));
578
-    }
579
-
580
-
581
-    /**
582
-     * setup body for email
583
-     *
584
-     * @param bool $preview will determine whether this is preview template or not.
585
-     * @return string formatted body for email.
586
-     * @throws EE_Error
587
-     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
588
-     */
589
-    protected function _body($preview = false)
590
-    {
591
-        //setup template args!
592
-        $this->_template_args = array(
593
-            'subject'   => $this->_subject,
594
-            'from'      => $this->_from,
595
-            'main_body' => wpautop(
596
-                stripslashes_deep(
597
-                    html_entity_decode($this->_content, ENT_QUOTES, "UTF-8")
598
-                )
599
-            ),
600
-        );
601
-        $body                 = $this->_get_main_template($preview);
602
-
603
-        /**
604
-         * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
605
-         *
606
-         * @type    bool $preview Indicates whether a preview is being generated or not.
607
-         * @return  bool    true  indicates to use the inliner, false bypasses it.
608
-         */
609
-        if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
610
-            //require CssToInlineStyles library and its dependencies via composer autoloader
611
-            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
612
-
613
-            //now if this isn't a preview, let's setup the body so it has inline styles
614
-            if (! $preview || ($preview && defined('DOING_AJAX'))) {
615
-                $style = file_get_contents(
616
-                    $this->get_variation(
617
-                        $this->_tmp_pack,
618
-                        $this->_incoming_message_type->name,
619
-                        false,
620
-                        'main',
621
-                        $this->_variation
622
-                    ),
623
-                    true
624
-                );
625
-                $CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
626
-                //for some reason the library has a bracket and new line at the beginning.  This takes care of that.
627
-                $body  = ltrim($CSS->convert(true), ">\n");
628
-                //see https://events.codebasehq.com/projects/event-espresso/tickets/8609
629
-                $body  = ltrim($body, "<?");
630
-            }
631
-
632
-        }
633
-        return $body;
634
-    }
635
-
636
-
637
-    /**
638
-     * This just returns any existing test settings that might be saved in the database
639
-     *
640
-     * @access public
641
-     * @return array
642
-     */
643
-    public function get_existing_test_settings()
644
-    {
645
-        $settings = parent::get_existing_test_settings();
646
-        //override subject if present because we always want it to be fresh.
647
-        if (is_array($settings) && ! empty($settings['subject'])) {
648
-            $settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
649
-        }
650
-        return $settings;
651
-    }
11
+	/**
12
+	 * To field for email
13
+	 * @var string
14
+	 */
15
+	protected $_to = '';
16
+
17
+
18
+	/**
19
+	 * CC field for email.
20
+	 * @var string
21
+	 */
22
+	protected $_cc = '';
23
+
24
+	/**
25
+	 * From field for email
26
+	 * @var string
27
+	 */
28
+	protected $_from = '';
29
+
30
+
31
+	/**
32
+	 * Subject field for email
33
+	 * @var string
34
+	 */
35
+	protected $_subject = '';
36
+
37
+
38
+	/**
39
+	 * Content field for email
40
+	 * @var string
41
+	 */
42
+	protected $_content = '';
43
+
44
+
45
+	/**
46
+	 * constructor
47
+	 *
48
+	 * @access public
49
+	 */
50
+	public function __construct()
51
+	{
52
+		//set name and description properties
53
+		$this->name                = 'email';
54
+		$this->description         = sprintf(
55
+			esc_html__(
56
+				'This messenger delivers messages via email using the built-in %s function included with WordPress',
57
+				'event_espresso'
58
+			),
59
+			'<code>wp_mail</code>'
60
+		);
61
+		$this->label               = array(
62
+			'singular' => esc_html__('email', 'event_espresso'),
63
+			'plural'   => esc_html__('emails', 'event_espresso'),
64
+		);
65
+		$this->activate_on_install = true;
66
+
67
+		//we're using defaults so let's call parent constructor that will take care of setting up all the other
68
+		// properties
69
+		parent::__construct();
70
+	}
71
+
72
+
73
+	/**
74
+	 * see abstract declaration in parent class for details.
75
+	 */
76
+	protected function _set_admin_pages()
77
+	{
78
+		$this->admin_registered_pages = array(
79
+			'events_edit' => true,
80
+		);
81
+	}
82
+
83
+
84
+	/**
85
+	 * see abstract declaration in parent class for details
86
+	 */
87
+	protected function _set_valid_shortcodes()
88
+	{
89
+		//remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
90
+		// message type.
91
+		$this->_valid_shortcodes = array(
92
+			'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
93
+			'cc' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
94
+			'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
95
+		);
96
+	}
97
+
98
+
99
+	/**
100
+	 * see abstract declaration in parent class for details
101
+	 *
102
+	 * @access protected
103
+	 * @return void
104
+	 */
105
+	protected function _set_validator_config()
106
+	{
107
+		$valid_shortcodes = $this->get_valid_shortcodes();
108
+
109
+		$this->_validator_config = array(
110
+			'to'            => array(
111
+				'shortcodes' => $valid_shortcodes['to'],
112
+				'type'       => 'email',
113
+			),
114
+			'cc' => array(
115
+				'shortcodes' => $valid_shortcodes['to'],
116
+				'type' => 'email',
117
+			),
118
+			'from'          => array(
119
+				'shortcodes' => $valid_shortcodes['from'],
120
+				'type'       => 'email',
121
+			),
122
+			'subject'       => array(
123
+				'shortcodes' => array(
124
+					'organization',
125
+					'primary_registration_details',
126
+					'event_author',
127
+					'primary_registration_details',
128
+					'recipient_details',
129
+				),
130
+			),
131
+			'content'       => array(
132
+				'shortcodes' => array(
133
+					'event_list',
134
+					'attendee_list',
135
+					'ticket_list',
136
+					'organization',
137
+					'primary_registration_details',
138
+					'primary_registration_list',
139
+					'event_author',
140
+					'recipient_details',
141
+					'recipient_list',
142
+					'transaction',
143
+					'messenger',
144
+				),
145
+			),
146
+			'attendee_list' => array(
147
+				'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
148
+				'required'   => array('[ATTENDEE_LIST]'),
149
+			),
150
+			'event_list'    => array(
151
+				'shortcodes' => array(
152
+					'event',
153
+					'attendee_list',
154
+					'ticket_list',
155
+					'venue',
156
+					'datetime_list',
157
+					'attendee',
158
+					'primary_registration_details',
159
+					'primary_registration_list',
160
+					'event_author',
161
+					'recipient_details',
162
+					'recipient_list',
163
+				),
164
+				'required'   => array('[EVENT_LIST]'),
165
+			),
166
+			'ticket_list'   => array(
167
+				'shortcodes' => array(
168
+					'event_list',
169
+					'attendee_list',
170
+					'ticket',
171
+					'datetime_list',
172
+					'primary_registration_details',
173
+					'recipient_details',
174
+				),
175
+				'required'   => array('[TICKET_LIST]'),
176
+			),
177
+			'datetime_list' => array(
178
+				'shortcodes' => array('datetime'),
179
+				'required'   => array('[DATETIME_LIST]'),
180
+			),
181
+		);
182
+	}
183
+
184
+
185
+	/**
186
+	 * @see   parent EE_messenger class for docs
187
+	 * @since 4.5.0
188
+	 */
189
+	public function do_secondary_messenger_hooks($sending_messenger_name)
190
+	{
191
+		if ($sending_messenger_name = 'html') {
192
+			add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
193
+		}
194
+	}
195
+
196
+
197
+	public function add_email_css(
198
+		$variation_path,
199
+		$messenger,
200
+		$message_type,
201
+		$type,
202
+		$variation,
203
+		$file_extension,
204
+		$url,
205
+		EE_Messages_Template_Pack $template_pack
206
+	) {
207
+		//prevent recursion on this callback.
208
+		remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
209
+		$variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
210
+
211
+		add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
212
+		return $variation;
213
+	}
214
+
215
+
216
+	/**
217
+	 * See parent for details
218
+	 *
219
+	 * @access protected
220
+	 * @return void
221
+	 */
222
+	protected function _set_test_settings_fields()
223
+	{
224
+		$this->_test_settings_fields = array(
225
+			'to'      => array(
226
+				'input'      => 'text',
227
+				'label'      => esc_html__('Send a test email to', 'event_espresso'),
228
+				'type'       => 'email',
229
+				'required'   => true,
230
+				'validation' => true,
231
+				'css_class'  => 'large-text',
232
+				'format'     => '%s',
233
+				'default'    => get_bloginfo('admin_email'),
234
+			),
235
+			'subject' => array(
236
+				'input'      => 'hidden',
237
+				'label'      => '',
238
+				'type'       => 'string',
239
+				'required'   => false,
240
+				'validation' => false,
241
+				'format'     => '%s',
242
+				'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
243
+				'default'    => '',
244
+				'css_class'  => '',
245
+			),
246
+		);
247
+	}
248
+
249
+
250
+	/**
251
+	 * _set_template_fields
252
+	 * This sets up the fields that a messenger requires for the message to go out.
253
+	 *
254
+	 * @access  protected
255
+	 * @return void
256
+	 */
257
+	protected function _set_template_fields()
258
+	{
259
+		// any extra template fields that are NOT used by the messenger but will get used by a messenger field for
260
+		// shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
261
+		// they relate to.  This is important for the Messages_admin to know what fields to display to the user.
262
+		//  Also, notice that the "values" are equal to the field type that messages admin will use to know what
263
+		// kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
264
+		// indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
265
+		// displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
266
+		// will not be displayed/parsed.
267
+		$this->_template_fields = array(
268
+			'to'      => array(
269
+				'input'      => 'text',
270
+				'label'      => esc_html_x(
271
+					'To',
272
+					'Label for the "To" field for email addresses',
273
+					'event_espresso'
274
+				),
275
+				'type'       => 'string',
276
+				'required'   => true,
277
+				'validation' => true,
278
+				'css_class'  => 'large-text',
279
+				'format'     => '%s',
280
+			),
281
+			'cc'      => array(
282
+				'input'      => 'text',
283
+				'label'      => esc_html_x(
284
+					'CC',
285
+					'Label for the "Carbon Copy" field used for additional email addresses',
286
+					'event_espresso'
287
+				),
288
+				'type'       => 'string',
289
+				'required'   => false,
290
+				'validation' => true,
291
+				'css_class'  => 'large-text',
292
+				'format'     => '%s',
293
+			),
294
+			'from'    => array(
295
+				'input'      => 'text',
296
+				'label'      => esc_html_x(
297
+					'From',
298
+					'Label for the "From" field for email addresses.',
299
+					'event_espresso'
300
+				),
301
+				'type'       => 'string',
302
+				'required'   => true,
303
+				'validation' => true,
304
+				'css_class'  => 'large-text',
305
+				'format'     => '%s',
306
+			),
307
+			'subject' => array(
308
+				'input'      => 'text',
309
+				'label'      => esc_html_x(
310
+					'Subject',
311
+					'Label for the "Subject" field (short description of contents) for emails.',
312
+					'event_espresso'
313
+				),
314
+				'type'       => 'string',
315
+				'required'   => true,
316
+				'validation' => true,
317
+				'css_class'  => 'large-text',
318
+				'format'     => '%s',
319
+			),
320
+			'content' => '',
321
+			//left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
322
+			'extra'   => array(
323
+				'content' => array(
324
+					'main'          => array(
325
+						'input'      => 'wp_editor',
326
+						'label'      => esc_html__('Main Content', 'event_espresso'),
327
+						'type'       => 'string',
328
+						'required'   => true,
329
+						'validation' => true,
330
+						'format'     => '%s',
331
+						'rows'       => '15',
332
+					),
333
+					'event_list'    => array(
334
+						'input'               => 'wp_editor',
335
+						'label'               => '[EVENT_LIST]',
336
+						'type'                => 'string',
337
+						'required'            => true,
338
+						'validation'          => true,
339
+						'format'              => '%s',
340
+						'rows'                => '15',
341
+						'shortcodes_required' => array('[EVENT_LIST]'),
342
+					),
343
+					'attendee_list' => array(
344
+						'input'               => 'textarea',
345
+						'label'               => '[ATTENDEE_LIST]',
346
+						'type'                => 'string',
347
+						'required'            => true,
348
+						'validation'          => true,
349
+						'format'              => '%s',
350
+						'css_class'           => 'large-text',
351
+						'rows'                => '5',
352
+						'shortcodes_required' => array('[ATTENDEE_LIST]'),
353
+					),
354
+					'ticket_list'   => array(
355
+						'input'               => 'textarea',
356
+						'label'               => '[TICKET_LIST]',
357
+						'type'                => 'string',
358
+						'required'            => true,
359
+						'validation'          => true,
360
+						'format'              => '%s',
361
+						'css_class'           => 'large-text',
362
+						'rows'                => '10',
363
+						'shortcodes_required' => array('[TICKET_LIST]'),
364
+					),
365
+					'datetime_list' => array(
366
+						'input'               => 'textarea',
367
+						'label'               => '[DATETIME_LIST]',
368
+						'type'                => 'string',
369
+						'required'            => true,
370
+						'validation'          => true,
371
+						'format'              => '%s',
372
+						'css_class'           => 'large-text',
373
+						'rows'                => '10',
374
+						'shortcodes_required' => array('[DATETIME_LIST]'),
375
+					),
376
+				),
377
+			),
378
+		);
379
+	}
380
+
381
+
382
+	/**
383
+	 * See definition of this class in parent
384
+	 */
385
+	protected function _set_default_message_types()
386
+	{
387
+		$this->_default_message_types = array(
388
+			'payment',
389
+			'payment_refund',
390
+			'registration',
391
+			'not_approved_registration',
392
+			'pending_approval',
393
+		);
394
+	}
395
+
396
+
397
+	/**
398
+	 * @see   definition of this class in parent
399
+	 * @since 4.5.0
400
+	 */
401
+	protected function _set_valid_message_types()
402
+	{
403
+		$this->_valid_message_types = array(
404
+			'payment',
405
+			'registration',
406
+			'not_approved_registration',
407
+			'declined_registration',
408
+			'cancelled_registration',
409
+			'pending_approval',
410
+			'registration_summary',
411
+			'payment_reminder',
412
+			'payment_declined',
413
+			'payment_refund',
414
+		);
415
+	}
416
+
417
+
418
+	/**
419
+	 * setting up admin_settings_fields for messenger.
420
+	 */
421
+	protected function _set_admin_settings_fields()
422
+	{
423
+	}
424
+
425
+	/**
426
+	 * We just deliver the messages don't kill us!!
427
+	 *
428
+	 * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
429
+	 *              present.
430
+	 * @throws EE_Error
431
+	 * @throws \TijsVerkoyen\CssToInlineStyles\Exception
432
+	 */
433
+	protected function _send_message()
434
+	{
435
+		$success = wp_mail(
436
+			html_entity_decode($this->_to, ENT_QUOTES, "UTF-8"),
437
+			stripslashes(html_entity_decode($this->_subject, ENT_QUOTES, "UTF-8")),
438
+			$this->_body(),
439
+			$this->_headers()
440
+		);
441
+		if (! $success) {
442
+			EE_Error::add_error(
443
+				sprintf(
444
+					esc_html__(
445
+						'The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
446
+						'event_espresso'
447
+					),
448
+					$this->_to,
449
+					$this->_from,
450
+					'<br />'
451
+				),
452
+				__FILE__,
453
+				__FUNCTION__,
454
+				__LINE__
455
+			);
456
+		}
457
+		return $success;
458
+	}
459
+
460
+
461
+	/**
462
+	 * see parent for definition
463
+	 *
464
+	 * @return string html body of the message content and the related css.
465
+	 * @throws EE_Error
466
+	 * @throws \TijsVerkoyen\CssToInlineStyles\Exception
467
+	 */
468
+	protected function _preview()
469
+	{
470
+		return $this->_body(true);
471
+	}
472
+
473
+
474
+	/**
475
+	 * Setup headers for email
476
+	 *
477
+	 * @access protected
478
+	 * @return string formatted header for email
479
+	 */
480
+	protected function _headers()
481
+	{
482
+		$this->_ensure_has_from_email_address();
483
+		$from    = stripslashes_deep(html_entity_decode($this->_from, ENT_QUOTES, "UTF-8"));
484
+		$headers = array(
485
+			'From:' . $from,
486
+			'Reply-To:' . $from,
487
+			'Content-Type:text/html; charset=utf-8',
488
+		);
489
+
490
+		if (! empty($this->_cc)) {
491
+			$headers[] = 'cc: ' . $this->_cc;
492
+		}
493
+
494
+		//but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
495
+		// header.
496
+		add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
497
+		add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
498
+		return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
499
+	}
500
+
501
+
502
+	/**
503
+	 * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
504
+	 * address for the from address to avoid problems with sending emails.
505
+	 */
506
+	protected function _ensure_has_from_email_address()
507
+	{
508
+		if (empty($this->_from)) {
509
+			$this->_from = get_bloginfo('admin_email');
510
+		}
511
+	}
512
+
513
+
514
+	/**
515
+	 * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
516
+	 * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
517
+	 * be empty
518
+	 *
519
+	 * @since 4.3.1
520
+	 * @return array
521
+	 */
522
+	private function _parse_from()
523
+	{
524
+		if (strpos($this->_from, '<') !== false) {
525
+			$from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
526
+			$from_name = str_replace('"', '', $from_name);
527
+			$from_name = trim($from_name);
528
+
529
+			$from_email = substr($this->_from, strpos($this->_from, '<') + 1);
530
+			$from_email = str_replace('>', '', $from_email);
531
+			$from_email = trim($from_email);
532
+		} elseif (trim($this->_from) !== '') {
533
+			$from_name  = '';
534
+			$from_email = trim($this->_from);
535
+		} else {
536
+			$from_name = $from_email = '';
537
+		}
538
+		return array($from_name, $from_email);
539
+	}
540
+
541
+
542
+	/**
543
+	 * Callback for the wp_mail_from filter.
544
+	 *
545
+	 * @since 4.3.1
546
+	 * @param string $from_email What the original from_email is.
547
+	 * @return string
548
+	 */
549
+	public function set_from_address($from_email)
550
+	{
551
+		$parsed_from = $this->_parse_from();
552
+		//includes fallback if the parsing failed.
553
+		$from_email = is_array($parsed_from) && ! empty($parsed_from[1])
554
+			? $parsed_from[1]
555
+			: get_bloginfo('admin_email');
556
+		return $from_email;
557
+	}
558
+
559
+
560
+	/**
561
+	 * Callback fro the wp_mail_from_name filter.
562
+	 *
563
+	 * @since 4.3.1
564
+	 * @param string $from_name The original from_name.
565
+	 * @return string
566
+	 */
567
+	public function set_from_name($from_name)
568
+	{
569
+		$parsed_from = $this->_parse_from();
570
+		if (is_array($parsed_from) && ! empty($parsed_from[0])) {
571
+			$from_name = $parsed_from[0];
572
+		}
573
+
574
+		//if from name is "WordPress" let's sub in the site name instead (more friendly!)
575
+		$from_name = $from_name == 'WordPress' ? get_bloginfo() : $from_name;
576
+
577
+		return stripslashes_deep(html_entity_decode($from_name, ENT_QUOTES, "UTF-8"));
578
+	}
579
+
580
+
581
+	/**
582
+	 * setup body for email
583
+	 *
584
+	 * @param bool $preview will determine whether this is preview template or not.
585
+	 * @return string formatted body for email.
586
+	 * @throws EE_Error
587
+	 * @throws \TijsVerkoyen\CssToInlineStyles\Exception
588
+	 */
589
+	protected function _body($preview = false)
590
+	{
591
+		//setup template args!
592
+		$this->_template_args = array(
593
+			'subject'   => $this->_subject,
594
+			'from'      => $this->_from,
595
+			'main_body' => wpautop(
596
+				stripslashes_deep(
597
+					html_entity_decode($this->_content, ENT_QUOTES, "UTF-8")
598
+				)
599
+			),
600
+		);
601
+		$body                 = $this->_get_main_template($preview);
602
+
603
+		/**
604
+		 * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
605
+		 *
606
+		 * @type    bool $preview Indicates whether a preview is being generated or not.
607
+		 * @return  bool    true  indicates to use the inliner, false bypasses it.
608
+		 */
609
+		if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
610
+			//require CssToInlineStyles library and its dependencies via composer autoloader
611
+			require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
612
+
613
+			//now if this isn't a preview, let's setup the body so it has inline styles
614
+			if (! $preview || ($preview && defined('DOING_AJAX'))) {
615
+				$style = file_get_contents(
616
+					$this->get_variation(
617
+						$this->_tmp_pack,
618
+						$this->_incoming_message_type->name,
619
+						false,
620
+						'main',
621
+						$this->_variation
622
+					),
623
+					true
624
+				);
625
+				$CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
626
+				//for some reason the library has a bracket and new line at the beginning.  This takes care of that.
627
+				$body  = ltrim($CSS->convert(true), ">\n");
628
+				//see https://events.codebasehq.com/projects/event-espresso/tickets/8609
629
+				$body  = ltrim($body, "<?");
630
+			}
631
+
632
+		}
633
+		return $body;
634
+	}
635
+
636
+
637
+	/**
638
+	 * This just returns any existing test settings that might be saved in the database
639
+	 *
640
+	 * @access public
641
+	 * @return array
642
+	 */
643
+	public function get_existing_test_settings()
644
+	{
645
+		$settings = parent::get_existing_test_settings();
646
+		//override subject if present because we always want it to be fresh.
647
+		if (is_array($settings) && ! empty($settings['subject'])) {
648
+			$settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
649
+		}
650
+		return $settings;
651
+	}
652 652
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -58,7 +58,7 @@  discard block
 block discarded – undo
58 58
             ),
59 59
             '<code>wp_mail</code>'
60 60
         );
61
-        $this->label               = array(
61
+        $this->label = array(
62 62
             'singular' => esc_html__('email', 'event_espresso'),
63 63
             'plural'   => esc_html__('emails', 'event_espresso'),
64 64
         );
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
             $this->_body(),
439 439
             $this->_headers()
440 440
         );
441
-        if (! $success) {
441
+        if ( ! $success) {
442 442
             EE_Error::add_error(
443 443
                 sprintf(
444 444
                     esc_html__(
@@ -482,13 +482,13 @@  discard block
 block discarded – undo
482 482
         $this->_ensure_has_from_email_address();
483 483
         $from    = stripslashes_deep(html_entity_decode($this->_from, ENT_QUOTES, "UTF-8"));
484 484
         $headers = array(
485
-            'From:' . $from,
486
-            'Reply-To:' . $from,
485
+            'From:'.$from,
486
+            'Reply-To:'.$from,
487 487
             'Content-Type:text/html; charset=utf-8',
488 488
         );
489 489
 
490
-        if (! empty($this->_cc)) {
491
-            $headers[] = 'cc: ' . $this->_cc;
490
+        if ( ! empty($this->_cc)) {
491
+            $headers[] = 'cc: '.$this->_cc;
492 492
         }
493 493
 
494 494
         //but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
                 )
599 599
             ),
600 600
         );
601
-        $body                 = $this->_get_main_template($preview);
601
+        $body = $this->_get_main_template($preview);
602 602
 
603 603
         /**
604 604
          * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
@@ -608,10 +608,10 @@  discard block
 block discarded – undo
608 608
          */
609 609
         if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
610 610
             //require CssToInlineStyles library and its dependencies via composer autoloader
611
-            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
611
+            require_once EE_THIRD_PARTY.'cssinliner/vendor/autoload.php';
612 612
 
613 613
             //now if this isn't a preview, let's setup the body so it has inline styles
614
-            if (! $preview || ($preview && defined('DOING_AJAX'))) {
614
+            if ( ! $preview || ($preview && defined('DOING_AJAX'))) {
615 615
                 $style = file_get_contents(
616 616
                     $this->get_variation(
617 617
                         $this->_tmp_pack,
Please login to merge, or discard this patch.
core/exceptions/ExceptionStackTraceDisplay.php 2 patches
Indentation   +280 added lines, -280 removed lines patch added patch discarded remove patch
@@ -8,7 +8,7 @@  discard block
 block discarded – undo
8 8
 use ReflectionMethod;
9 9
 
10 10
 if (! defined('EVENT_ESPRESSO_VERSION')) {
11
-    exit('No direct script access allowed');
11
+	exit('No direct script access allowed');
12 12
 }
13 13
 
14 14
 
@@ -26,53 +26,53 @@  discard block
 block discarded – undo
26 26
 
27 27
 
28 28
 
29
-    /**
30
-     * @param Exception $exception
31
-     * @throws Exception
32
-     */
33
-    public function __construct(Exception $exception)
34
-    {
35
-        if (WP_DEBUG && ! defined('EE_TESTS_DIR')) {
36
-            $this->displayException($exception);
37
-        } else {
38
-            throw $exception;
39
-        }
40
-    }
29
+	/**
30
+	 * @param Exception $exception
31
+	 * @throws Exception
32
+	 */
33
+	public function __construct(Exception $exception)
34
+	{
35
+		if (WP_DEBUG && ! defined('EE_TESTS_DIR')) {
36
+			$this->displayException($exception);
37
+		} else {
38
+			throw $exception;
39
+		}
40
+	}
41 41
 
42 42
 
43 43
 
44
-    /**
45
-     * @access protected
46
-     * @param Exception $exception
47
-     * @throws ReflectionException
48
-     */
49
-    protected function displayException(Exception $exception)
50
-    {
51
-        $error_code = '';
52
-        $trace_details = '';
53
-        $time = time();
54
-        $trace = $exception->getTrace();
55
-        // get separate user and developer messages if they exist
56
-        $msg = explode('||', $exception->getMessage());
57
-        $user_msg = $msg[0];
58
-        $dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
59
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
60
-        // start gathering output
61
-        $output = $this->exceptionStyles();
62
-        $output .= '
44
+	/**
45
+	 * @access protected
46
+	 * @param Exception $exception
47
+	 * @throws ReflectionException
48
+	 */
49
+	protected function displayException(Exception $exception)
50
+	{
51
+		$error_code = '';
52
+		$trace_details = '';
53
+		$time = time();
54
+		$trace = $exception->getTrace();
55
+		// get separate user and developer messages if they exist
56
+		$msg = explode('||', $exception->getMessage());
57
+		$user_msg = $msg[0];
58
+		$dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
59
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
60
+		// start gathering output
61
+		$output = $this->exceptionStyles();
62
+		$output .= '
63 63
 <div id="ee-error-message" class="error">';
64
-        if (! WP_DEBUG) {
65
-            $output .= '
64
+		if (! WP_DEBUG) {
65
+			$output .= '
66 66
 	<p>';
67
-        }
68
-        // process trace info
69
-        if (empty($trace)) {
70
-            $trace_details .= __(
71
-                'Sorry, but no trace information was available for this exception.',
72
-                'event_espresso'
73
-            );
74
-        } else {
75
-            $trace_details .= '
67
+		}
68
+		// process trace info
69
+		if (empty($trace)) {
70
+			$trace_details .= __(
71
+				'Sorry, but no trace information was available for this exception.',
72
+				'event_espresso'
73
+			);
74
+		} else {
75
+			$trace_details .= '
76 76
 			<div id="ee-trace-details">
77 77
 			<table width="100%" border="0" cellpadding="5" cellspacing="0">
78 78
 				<tr>
@@ -80,260 +80,260 @@  discard block
 block discarded – undo
80 80
 					<th scope="col" align="right" style="width:3.5%;">Line</th>
81 81
 					<th scope="col" align="left" style="width:40%;">File</th>
82 82
 					<th scope="col" align="left">' . __('Class', 'event_espresso') . '->' . __('Method( arguments )',
83
-                    'event_espresso') . '</th>
83
+					'event_espresso') . '</th>
84 84
 				</tr>';
85
-            $last_on_stack = count($trace) - 1;
86
-            // reverse array so that stack is in proper chronological order
87
-            $sorted_trace = array_reverse($trace);
88
-            foreach ($sorted_trace as $nmbr => $trace) {
89
-                $file = isset($trace['file']) ? $trace['file'] : '';
90
-                $class = isset($trace['class']) ? $trace['class'] : '';
91
-                $type = isset($trace['type']) ? $trace['type'] : '';
92
-                $function = isset($trace['function']) ? $trace['function'] : '';
93
-                $args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
94
-                $args = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />' . $args . '<br />' : $args;
95
-                $line = isset($trace['line']) ? $trace['line'] : '';
96
-                $zebra = $nmbr % 2 !== 0 ? ' odd' : '';
97
-                if (empty($file) && ! empty($class)) {
98
-                    $a = new ReflectionClass($class);
99
-                    $file = $a->getFileName();
100
-                    if (empty($line) && ! empty($function)) {
101
-                        try {
102
-                            //if $function is a closure, this throws an exception
103
-                            $b = new ReflectionMethod($class, $function);
104
-                            $line = $b->getStartLine();
105
-                        } catch (Exception $closure_exception) {
106
-                            $line = 'unknown';
107
-                        }
108
-                    }
109
-                }
110
-                if ($nmbr === $last_on_stack) {
111
-                    $file = $exception->getFile() !== '' ? $exception->getFile() : $file;
112
-                    $line = $exception->getLine() !== '' ? $exception->getLine() : $line;
113
-                    $error_code = $this->generate_error_code($file, $trace['function'], $line);
114
-                }
115
-                $file = \EEH_File::standardise_directory_separators($file);
116
-                $nmbr = ! empty($nmbr) ? $nmbr : '&nbsp;';
117
-                $line = ! empty($line) ? $line : '&nbsp;';
118
-                $file = ! empty($file) ? $file : '&nbsp;';
119
-                $class_display = ! empty($class) ? $class : '';
120
-                $type = ! empty($type) ? $type : '';
121
-                $function = ! empty($function) ? $function : '';
122
-                $args = ! empty($args) ? '( ' . $args . ' )' : '()';
123
-                $trace_details .= '
85
+			$last_on_stack = count($trace) - 1;
86
+			// reverse array so that stack is in proper chronological order
87
+			$sorted_trace = array_reverse($trace);
88
+			foreach ($sorted_trace as $nmbr => $trace) {
89
+				$file = isset($trace['file']) ? $trace['file'] : '';
90
+				$class = isset($trace['class']) ? $trace['class'] : '';
91
+				$type = isset($trace['type']) ? $trace['type'] : '';
92
+				$function = isset($trace['function']) ? $trace['function'] : '';
93
+				$args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
94
+				$args = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />' . $args . '<br />' : $args;
95
+				$line = isset($trace['line']) ? $trace['line'] : '';
96
+				$zebra = $nmbr % 2 !== 0 ? ' odd' : '';
97
+				if (empty($file) && ! empty($class)) {
98
+					$a = new ReflectionClass($class);
99
+					$file = $a->getFileName();
100
+					if (empty($line) && ! empty($function)) {
101
+						try {
102
+							//if $function is a closure, this throws an exception
103
+							$b = new ReflectionMethod($class, $function);
104
+							$line = $b->getStartLine();
105
+						} catch (Exception $closure_exception) {
106
+							$line = 'unknown';
107
+						}
108
+					}
109
+				}
110
+				if ($nmbr === $last_on_stack) {
111
+					$file = $exception->getFile() !== '' ? $exception->getFile() : $file;
112
+					$line = $exception->getLine() !== '' ? $exception->getLine() : $line;
113
+					$error_code = $this->generate_error_code($file, $trace['function'], $line);
114
+				}
115
+				$file = \EEH_File::standardise_directory_separators($file);
116
+				$nmbr = ! empty($nmbr) ? $nmbr : '&nbsp;';
117
+				$line = ! empty($line) ? $line : '&nbsp;';
118
+				$file = ! empty($file) ? $file : '&nbsp;';
119
+				$class_display = ! empty($class) ? $class : '';
120
+				$type = ! empty($type) ? $type : '';
121
+				$function = ! empty($function) ? $function : '';
122
+				$args = ! empty($args) ? '( ' . $args . ' )' : '()';
123
+				$trace_details .= '
124 124
 					<tr>
125 125
 						<td align="right" valign="top" class="'
126
-                                  . $zebra
127
-                                  . '">'
128
-                                  . $nmbr
129
-                                  . '</td>
126
+								  . $zebra
127
+								  . '">'
128
+								  . $nmbr
129
+								  . '</td>
130 130
 						<td align="right" valign="top" class="'
131
-                                  . $zebra
132
-                                  . '">'
133
-                                  . $line
134
-                                  . '</td>
131
+								  . $zebra
132
+								  . '">'
133
+								  . $line
134
+								  . '</td>
135 135
 						<td align="left" valign="top" class="'
136
-                                  . $zebra
137
-                                  . '">'
138
-                                  . $file
139
-                                  . '</td>
136
+								  . $zebra
137
+								  . '">'
138
+								  . $file
139
+								  . '</td>
140 140
 						<td align="left" valign="top" class="'
141
-                                  . $zebra
142
-                                  . '">'
143
-                                  . $class_display
144
-                                  . $type
145
-                                  . $function
146
-                                  . $args
147
-                                  . '</td>
141
+								  . $zebra
142
+								  . '">'
143
+								  . $class_display
144
+								  . $type
145
+								  . $function
146
+								  . $args
147
+								  . '</td>
148 148
 					</tr>';
149
-            }
150
-            $trace_details .= '
149
+			}
150
+			$trace_details .= '
151 151
 			 </table>
152 152
 			</div>';
153
-        }
154
-        $code = $exception->getCode() ? $exception->getCode() : $error_code;
155
-        // add generic non-identifying messages for non-privileged users
156
-        if (! WP_DEBUG) {
157
-            $output .= '<span class="ee-error-user-msg-spn">'
158
-                       . trim($msg)
159
-                       . '</span> &nbsp; <sup>'
160
-                       . $code
161
-                       . '</sup><br />';
162
-        } else {
163
-            // or helpful developer messages if debugging is on
164
-            $output .= '
153
+		}
154
+		$code = $exception->getCode() ? $exception->getCode() : $error_code;
155
+		// add generic non-identifying messages for non-privileged users
156
+		if (! WP_DEBUG) {
157
+			$output .= '<span class="ee-error-user-msg-spn">'
158
+					   . trim($msg)
159
+					   . '</span> &nbsp; <sup>'
160
+					   . $code
161
+					   . '</sup><br />';
162
+		} else {
163
+			// or helpful developer messages if debugging is on
164
+			$output .= '
165 165
 		<div class="ee-error-dev-msg-dv">
166 166
 			<p class="ee-error-dev-msg-pg">
167 167
 				'
168
-                       . sprintf(
169
-                           __('%1$sAn %2$s was thrown!%3$s code: %4$s', 'event_espresso'),
170
-                           '<strong class="ee-error-dev-msg-str">',
171
-                           get_class($exception),
172
-                           '</strong>  &nbsp; <span>',
173
-                           $code . '</span>'
174
-                       )
175
-                       . '<br />
168
+					   . sprintf(
169
+						   __('%1$sAn %2$s was thrown!%3$s code: %4$s', 'event_espresso'),
170
+						   '<strong class="ee-error-dev-msg-str">',
171
+						   get_class($exception),
172
+						   '</strong>  &nbsp; <span>',
173
+						   $code . '</span>'
174
+					   )
175
+					   . '<br />
176 176
 				<span class="big-text">"'
177
-                       . trim($msg)
178
-                       . '"</span><br/>
177
+					   . trim($msg)
178
+					   . '"</span><br/>
179 179
 				<a id="display-ee-error-trace-1'
180
-                       . $time
181
-                       . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-1'
182
-                       . $time
183
-                       . '">
180
+					   . $time
181
+					   . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-1'
182
+					   . $time
183
+					   . '">
184 184
 					'
185
-                       . __('click to view backtrace and class/method details', 'event_espresso')
186
-                       . '
185
+					   . __('click to view backtrace and class/method details', 'event_espresso')
186
+					   . '
187 187
 				</a><br />
188 188
 				'
189
-                       . $exception->getFile()
190
-                       . sprintf(
191
-                           __('%1$s( line no: %2$s )%3$s', 'event_espresso'),
192
-                           ' &nbsp; <span class="small-text lt-grey-text">',
193
-                           $exception->getLine(),
194
-                           '</span>'
195
-                       )
196
-                       . '
189
+					   . $exception->getFile()
190
+					   . sprintf(
191
+						   __('%1$s( line no: %2$s )%3$s', 'event_espresso'),
192
+						   ' &nbsp; <span class="small-text lt-grey-text">',
193
+						   $exception->getLine(),
194
+						   '</span>'
195
+					   )
196
+					   . '
197 197
 			</p>
198 198
 			<div id="ee-error-trace-1'
199
-                       . $time
200
-                       . '-dv" class="ee-error-trace-dv" style="display: none;">
199
+					   . $time
200
+					   . '-dv" class="ee-error-trace-dv" style="display: none;">
201 201
 				'
202
-                       . $trace_details;
203
-            if (! empty($class)) {
204
-                $output .= '
202
+					   . $trace_details;
203
+			if (! empty($class)) {
204
+				$output .= '
205 205
 				<div style="padding:3px; margin:0 0 1em; border:1px solid #999; background:#fff; border-radius:3px;">
206 206
 					<div style="padding:1em 2em; border:1px solid #999; background:#fcfcfc;">
207 207
 						<h3>' . __('Class Details', 'event_espresso') . '</h3>';
208
-                $a = new ReflectionClass($class);
209
-                $output .= '
208
+				$a = new ReflectionClass($class);
209
+				$output .= '
210 210
 						<pre>' . $a . '</pre>
211 211
 					</div>
212 212
 				</div>';
213
-            }
214
-            $output .= '
213
+			}
214
+			$output .= '
215 215
 			</div>
216 216
 		</div>
217 217
 		<br />';
218
-        }
219
-        // remove last linebreak
220
-        $output = substr($output, 0, -6);
221
-        if (! WP_DEBUG) {
222
-            $output .= '
218
+		}
219
+		// remove last linebreak
220
+		$output = substr($output, 0, -6);
221
+		if (! WP_DEBUG) {
222
+			$output .= '
223 223
 	</p>';
224
-        }
225
-        $output .= '
224
+		}
225
+		$output .= '
226 226
 </div>';
227
-        $output .= $this->printScripts(true);
228
-        if (defined('DOING_AJAX')) {
229
-            echo wp_json_encode(array('error' => $output));
230
-            exit();
231
-        }
232
-        echo $output;
233
-    }
227
+		$output .= $this->printScripts(true);
228
+		if (defined('DOING_AJAX')) {
229
+			echo wp_json_encode(array('error' => $output));
230
+			exit();
231
+		}
232
+		echo $output;
233
+	}
234 234
 
235 235
 
236 236
 
237
-    /**
238
-     * generate string from exception trace args
239
-     *
240
-     * @param array $arguments
241
-     * @param int   $indent
242
-     * @param bool  $array
243
-     * @return string
244
-     */
245
-    private function _convert_args_to_string($arguments = array(), $indent = 0, $array = false)
246
-    {
247
-        $args = array();
248
-        $args_count = count($arguments);
249
-        if ($args_count > 2) {
250
-            $indent++;
251
-            $args[] = '<br />';
252
-        }
253
-        $x = 0;
254
-        foreach ($arguments as $arg) {
255
-            $x++;
256
-            for ($i = 0; $i < $indent; $i++) {
257
-                $args[] = ' &nbsp;&nbsp; ';
258
-            }
259
-            if (is_string($arg)) {
260
-                if (! $array && strlen($arg) > 75) {
261
-                    $args[] = '<br />';
262
-                    for ($i = 0; $i <= $indent; $i++) {
263
-                        $args[] = ' &nbsp;&nbsp; ';
264
-                    }
265
-                    $args[] = "'" . $arg . "'<br />";
266
-                } else {
267
-                    $args[] = " '" . $arg . "'";
268
-                }
269
-            } elseif (is_array($arg)) {
270
-                $arg_count = count($arg);
271
-                if ($arg_count > 2) {
272
-                    $indent++;
273
-                    $args[] = ' array(' . $this->_convert_args_to_string($arg, $indent, true) . ')';
274
-                    $indent--;
275
-                } else if ($arg_count === 0) {
276
-                    $args[] = ' array()';
277
-                } else {
278
-                    $args[] = ' array( ' . $this->_convert_args_to_string($arg) . ' )';
279
-                }
280
-            } elseif ($arg === null) {
281
-                $args[] = ' null';
282
-            } elseif (is_bool($arg)) {
283
-                $args[] = $arg ? ' true' : ' false';
284
-            } elseif (is_object($arg)) {
285
-                $args[] = get_class($arg);
286
-            } elseif (is_resource($arg)) {
287
-                $args[] = get_resource_type($arg);
288
-            } else {
289
-                $args[] = $arg;
290
-            }
291
-            if ($x === $args_count) {
292
-                if ($args_count > 2) {
293
-                    $args[] = '<br />';
294
-                    $indent--;
295
-                    for ($i = 1; $i < $indent; $i++) {
296
-                        $args[] = ' &nbsp;&nbsp; ';
297
-                    }
298
-                }
299
-            } else {
300
-                $args[] = $args_count > 2 ? ',<br />' : ', ';
301
-            }
302
-        }
303
-        return implode('', $args);
304
-    }
237
+	/**
238
+	 * generate string from exception trace args
239
+	 *
240
+	 * @param array $arguments
241
+	 * @param int   $indent
242
+	 * @param bool  $array
243
+	 * @return string
244
+	 */
245
+	private function _convert_args_to_string($arguments = array(), $indent = 0, $array = false)
246
+	{
247
+		$args = array();
248
+		$args_count = count($arguments);
249
+		if ($args_count > 2) {
250
+			$indent++;
251
+			$args[] = '<br />';
252
+		}
253
+		$x = 0;
254
+		foreach ($arguments as $arg) {
255
+			$x++;
256
+			for ($i = 0; $i < $indent; $i++) {
257
+				$args[] = ' &nbsp;&nbsp; ';
258
+			}
259
+			if (is_string($arg)) {
260
+				if (! $array && strlen($arg) > 75) {
261
+					$args[] = '<br />';
262
+					for ($i = 0; $i <= $indent; $i++) {
263
+						$args[] = ' &nbsp;&nbsp; ';
264
+					}
265
+					$args[] = "'" . $arg . "'<br />";
266
+				} else {
267
+					$args[] = " '" . $arg . "'";
268
+				}
269
+			} elseif (is_array($arg)) {
270
+				$arg_count = count($arg);
271
+				if ($arg_count > 2) {
272
+					$indent++;
273
+					$args[] = ' array(' . $this->_convert_args_to_string($arg, $indent, true) . ')';
274
+					$indent--;
275
+				} else if ($arg_count === 0) {
276
+					$args[] = ' array()';
277
+				} else {
278
+					$args[] = ' array( ' . $this->_convert_args_to_string($arg) . ' )';
279
+				}
280
+			} elseif ($arg === null) {
281
+				$args[] = ' null';
282
+			} elseif (is_bool($arg)) {
283
+				$args[] = $arg ? ' true' : ' false';
284
+			} elseif (is_object($arg)) {
285
+				$args[] = get_class($arg);
286
+			} elseif (is_resource($arg)) {
287
+				$args[] = get_resource_type($arg);
288
+			} else {
289
+				$args[] = $arg;
290
+			}
291
+			if ($x === $args_count) {
292
+				if ($args_count > 2) {
293
+					$args[] = '<br />';
294
+					$indent--;
295
+					for ($i = 1; $i < $indent; $i++) {
296
+						$args[] = ' &nbsp;&nbsp; ';
297
+					}
298
+				}
299
+			} else {
300
+				$args[] = $args_count > 2 ? ',<br />' : ', ';
301
+			}
302
+		}
303
+		return implode('', $args);
304
+	}
305 305
 
306 306
 
307 307
 
308
-    /**
309
-     * create error code from filepath, function name,
310
-     * and line number where exception or error was thrown
311
-     *
312
-     * @access protected
313
-     * @param string $file
314
-     * @param string $func
315
-     * @param string $line
316
-     * @return string
317
-     */
318
-    protected function generate_error_code($file = '', $func = '', $line = '')
319
-    {
320
-        $file_bits = explode('.', basename($file));
321
-        $error_code = ! empty($file_bits[0]) ? $file_bits[0] : '';
322
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
323
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
324
-        return $error_code;
325
-    }
308
+	/**
309
+	 * create error code from filepath, function name,
310
+	 * and line number where exception or error was thrown
311
+	 *
312
+	 * @access protected
313
+	 * @param string $file
314
+	 * @param string $func
315
+	 * @param string $line
316
+	 * @return string
317
+	 */
318
+	protected function generate_error_code($file = '', $func = '', $line = '')
319
+	{
320
+		$file_bits = explode('.', basename($file));
321
+		$error_code = ! empty($file_bits[0]) ? $file_bits[0] : '';
322
+		$error_code .= ! empty($func) ? ' - ' . $func : '';
323
+		$error_code .= ! empty($line) ? ' - ' . $line : '';
324
+		return $error_code;
325
+	}
326 326
 
327 327
 
328 328
 
329
-    /**
330
-     * _exception_styles
331
-     *
332
-     * @return string
333
-     */
334
-    private function exceptionStyles()
335
-    {
336
-        return '
329
+	/**
330
+	 * _exception_styles
331
+	 *
332
+	 * @return string
333
+	 */
334
+	private function exceptionStyles()
335
+	{
336
+		return '
337 337
 <style type="text/css">
338 338
 	#ee-error-message {
339 339
 		max-width:90% !important;
@@ -390,30 +390,30 @@  discard block
 block discarded – undo
390 390
 		color: #999;
391 391
 	}
392 392
 </style>';
393
-    }
393
+	}
394 394
 
395 395
 
396 396
 
397
-    /**
398
-     * _print_scripts
399
-     *
400
-     * @param bool $force_print
401
-     * @return string
402
-     */
403
-    private function printScripts($force_print = false)
404
-    {
405
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
406
-            if (wp_script_is('ee_error_js', 'enqueued')) {
407
-                return '';
408
-            }
409
-            if (wp_script_is('ee_error_js', 'registered')) {
410
-                wp_enqueue_style('espresso_default');
411
-                wp_enqueue_style('espresso_custom_css');
412
-                wp_enqueue_script( 'ee_error_js' );
397
+	/**
398
+	 * _print_scripts
399
+	 *
400
+	 * @param bool $force_print
401
+	 * @return string
402
+	 */
403
+	private function printScripts($force_print = false)
404
+	{
405
+		if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
406
+			if (wp_script_is('ee_error_js', 'enqueued')) {
407
+				return '';
408
+			}
409
+			if (wp_script_is('ee_error_js', 'registered')) {
410
+				wp_enqueue_style('espresso_default');
411
+				wp_enqueue_style('espresso_custom_css');
412
+				wp_enqueue_script( 'ee_error_js' );
413 413
 				wp_localize_script( 'ee_error_js', 'ee_settings', array( 'wp_debug' => WP_DEBUG ) );
414
-            }
415
-        } else {
416
-            return '
414
+			}
415
+		} else {
416
+			return '
417 417
 <script>
418 418
 /* <![CDATA[ */
419 419
 var ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
@@ -423,9 +423,9 @@  discard block
 block discarded – undo
423 423
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
424 424
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
425 425
 ';
426
-        }
427
-        return '';
428
-    }
426
+		}
427
+		return '';
428
+	}
429 429
 
430 430
 
431 431
 
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@  discard block
 block discarded – undo
7 7
 use ReflectionException;
8 8
 use ReflectionMethod;
9 9
 
10
-if (! defined('EVENT_ESPRESSO_VERSION')) {
10
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
11 11
     exit('No direct script access allowed');
12 12
 }
13 13
 
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
         $output = $this->exceptionStyles();
62 62
         $output .= '
63 63
 <div id="ee-error-message" class="error">';
64
-        if (! WP_DEBUG) {
64
+        if ( ! WP_DEBUG) {
65 65
             $output .= '
66 66
 	<p>';
67 67
         }
@@ -79,8 +79,8 @@  discard block
 block discarded – undo
79 79
 					<th scope="col" align="right" style="width:2.5%;">#</th>
80 80
 					<th scope="col" align="right" style="width:3.5%;">Line</th>
81 81
 					<th scope="col" align="left" style="width:40%;">File</th>
82
-					<th scope="col" align="left">' . __('Class', 'event_espresso') . '->' . __('Method( arguments )',
83
-                    'event_espresso') . '</th>
82
+					<th scope="col" align="left">' . __('Class', 'event_espresso').'->'.__('Method( arguments )',
83
+                    'event_espresso').'</th>
84 84
 				</tr>';
85 85
             $last_on_stack = count($trace) - 1;
86 86
             // reverse array so that stack is in proper chronological order
@@ -91,7 +91,7 @@  discard block
 block discarded – undo
91 91
                 $type = isset($trace['type']) ? $trace['type'] : '';
92 92
                 $function = isset($trace['function']) ? $trace['function'] : '';
93 93
                 $args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
94
-                $args = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />' . $args . '<br />' : $args;
94
+                $args = isset($trace['args']) && count($trace['args']) > 4 ? ' <br />'.$args.'<br />' : $args;
95 95
                 $line = isset($trace['line']) ? $trace['line'] : '';
96 96
                 $zebra = $nmbr % 2 !== 0 ? ' odd' : '';
97 97
                 if (empty($file) && ! empty($class)) {
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
                 $class_display = ! empty($class) ? $class : '';
120 120
                 $type = ! empty($type) ? $type : '';
121 121
                 $function = ! empty($function) ? $function : '';
122
-                $args = ! empty($args) ? '( ' . $args . ' )' : '()';
122
+                $args = ! empty($args) ? '( '.$args.' )' : '()';
123 123
                 $trace_details .= '
124 124
 					<tr>
125 125
 						<td align="right" valign="top" class="'
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
         }
154 154
         $code = $exception->getCode() ? $exception->getCode() : $error_code;
155 155
         // add generic non-identifying messages for non-privileged users
156
-        if (! WP_DEBUG) {
156
+        if ( ! WP_DEBUG) {
157 157
             $output .= '<span class="ee-error-user-msg-spn">'
158 158
                        . trim($msg)
159 159
                        . '</span> &nbsp; <sup>'
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
                            '<strong class="ee-error-dev-msg-str">',
171 171
                            get_class($exception),
172 172
                            '</strong>  &nbsp; <span>',
173
-                           $code . '</span>'
173
+                           $code.'</span>'
174 174
                        )
175 175
                        . '<br />
176 176
 				<span class="big-text">"'
@@ -200,14 +200,14 @@  discard block
 block discarded – undo
200 200
                        . '-dv" class="ee-error-trace-dv" style="display: none;">
201 201
 				'
202 202
                        . $trace_details;
203
-            if (! empty($class)) {
203
+            if ( ! empty($class)) {
204 204
                 $output .= '
205 205
 				<div style="padding:3px; margin:0 0 1em; border:1px solid #999; background:#fff; border-radius:3px;">
206 206
 					<div style="padding:1em 2em; border:1px solid #999; background:#fcfcfc;">
207
-						<h3>' . __('Class Details', 'event_espresso') . '</h3>';
207
+						<h3>' . __('Class Details', 'event_espresso').'</h3>';
208 208
                 $a = new ReflectionClass($class);
209 209
                 $output .= '
210
-						<pre>' . $a . '</pre>
210
+						<pre>' . $a.'</pre>
211 211
 					</div>
212 212
 				</div>';
213 213
             }
@@ -218,7 +218,7 @@  discard block
 block discarded – undo
218 218
         }
219 219
         // remove last linebreak
220 220
         $output = substr($output, 0, -6);
221
-        if (! WP_DEBUG) {
221
+        if ( ! WP_DEBUG) {
222 222
             $output .= '
223 223
 	</p>';
224 224
         }
@@ -257,25 +257,25 @@  discard block
 block discarded – undo
257 257
                 $args[] = ' &nbsp;&nbsp; ';
258 258
             }
259 259
             if (is_string($arg)) {
260
-                if (! $array && strlen($arg) > 75) {
260
+                if ( ! $array && strlen($arg) > 75) {
261 261
                     $args[] = '<br />';
262 262
                     for ($i = 0; $i <= $indent; $i++) {
263 263
                         $args[] = ' &nbsp;&nbsp; ';
264 264
                     }
265
-                    $args[] = "'" . $arg . "'<br />";
265
+                    $args[] = "'".$arg."'<br />";
266 266
                 } else {
267
-                    $args[] = " '" . $arg . "'";
267
+                    $args[] = " '".$arg."'";
268 268
                 }
269 269
             } elseif (is_array($arg)) {
270 270
                 $arg_count = count($arg);
271 271
                 if ($arg_count > 2) {
272 272
                     $indent++;
273
-                    $args[] = ' array(' . $this->_convert_args_to_string($arg, $indent, true) . ')';
273
+                    $args[] = ' array('.$this->_convert_args_to_string($arg, $indent, true).')';
274 274
                     $indent--;
275 275
                 } else if ($arg_count === 0) {
276 276
                     $args[] = ' array()';
277 277
                 } else {
278
-                    $args[] = ' array( ' . $this->_convert_args_to_string($arg) . ' )';
278
+                    $args[] = ' array( '.$this->_convert_args_to_string($arg).' )';
279 279
                 }
280 280
             } elseif ($arg === null) {
281 281
                 $args[] = ' null';
@@ -319,8 +319,8 @@  discard block
 block discarded – undo
319 319
     {
320 320
         $file_bits = explode('.', basename($file));
321 321
         $error_code = ! empty($file_bits[0]) ? $file_bits[0] : '';
322
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
323
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
322
+        $error_code .= ! empty($func) ? ' - '.$func : '';
323
+        $error_code .= ! empty($line) ? ' - '.$line : '';
324 324
         return $error_code;
325 325
     }
326 326
 
@@ -402,26 +402,26 @@  discard block
 block discarded – undo
402 402
      */
403 403
     private function printScripts($force_print = false)
404 404
     {
405
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
405
+        if ( ! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
406 406
             if (wp_script_is('ee_error_js', 'enqueued')) {
407 407
                 return '';
408 408
             }
409 409
             if (wp_script_is('ee_error_js', 'registered')) {
410 410
                 wp_enqueue_style('espresso_default');
411 411
                 wp_enqueue_style('espresso_custom_css');
412
-                wp_enqueue_script( 'ee_error_js' );
413
-				wp_localize_script( 'ee_error_js', 'ee_settings', array( 'wp_debug' => WP_DEBUG ) );
412
+                wp_enqueue_script('ee_error_js');
413
+				wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
414 414
             }
415 415
         } else {
416 416
             return '
417 417
 <script>
418 418
 /* <![CDATA[ */
419
-var ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
419
+var ee_settings = {"wp_debug":"' . WP_DEBUG.'"};
420 420
 /* ]]> */
421 421
 </script>
422
-<script src="' . includes_url() . 'js/jquery/jquery.js" type="text/javascript"></script>
423
-<script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
424
-<script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
422
+<script src="' . includes_url().'js/jquery/jquery.js" type="text/javascript"></script>
423
+<script src="' . EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js'.'?ver='.espresso_version().'" type="text/javascript"></script>
424
+<script src="' . EE_GLOBAL_ASSETS_URL.'scripts/EE_Error.js'.'?ver='.espresso_version().'" type="text/javascript"></script>
425 425
 ';
426 426
         }
427 427
         return '';
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 2 patches
Indentation   +789 added lines, -789 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
11 11
 use EEM_Base;
12 12
 
13 13
 if (! defined('EVENT_ESPRESSO_VERSION')) {
14
-    exit('No direct script access allowed');
14
+	exit('No direct script access allowed');
15 15
 }
16 16
 
17 17
 
@@ -36,792 +36,792 @@  discard block
 block discarded – undo
36 36
 class ModelDataTranslator
37 37
 {
38 38
 
39
-    /**
40
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
41
-     * fields that COULD contain -1; so we use null
42
-     */
43
-    const EE_INF_IN_REST = null;
44
-
45
-
46
-
47
-    /**
48
-     * Prepares a possible array of input values from JSON for use by the models
49
-     *
50
-     * @param EE_Model_Field_Base $field_obj
51
-     * @param mixed                $original_value_maybe_array
52
-     * @param string               $requested_version
53
-     * @param string               $timezone_string treat values as being in this timezone
54
-     * @return mixed
55
-     * @throws RestException
56
-     */
57
-    public static function prepareFieldValuesFromJson(
58
-        $field_obj,
59
-        $original_value_maybe_array,
60
-        $requested_version,
61
-        $timezone_string = 'UTC'
62
-    ) {
63
-        if (is_array($original_value_maybe_array)
64
-            && ! $field_obj instanceof EE_Serialized_Text_Field
65
-        ) {
66
-            $new_value_maybe_array = array();
67
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
68
-                $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
69
-                    $field_obj,
70
-                    $array_item,
71
-                    $requested_version,
72
-                    $timezone_string
73
-                );
74
-            }
75
-        } else {
76
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
77
-                $field_obj,
78
-                $original_value_maybe_array,
79
-                $requested_version,
80
-                $timezone_string
81
-            );
82
-        }
83
-        return $new_value_maybe_array;
84
-    }
85
-
86
-
87
-
88
-    /**
89
-     * Prepares an array of field values FOR use in JSON/REST API
90
-     *
91
-     * @param EE_Model_Field_Base $field_obj
92
-     * @param mixed                $original_value_maybe_array
93
-     * @param string               $request_version (eg 4.8.36)
94
-     * @return array
95
-     */
96
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
97
-    {
98
-        if (is_array($original_value_maybe_array)) {
99
-            $new_value = array();
100
-            foreach ($original_value_maybe_array as $key => $value) {
101
-                $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version);
102
-            }
103
-        } else {
104
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
105
-                $field_obj,
106
-                $original_value_maybe_array,
107
-                $request_version
108
-            );
109
-        }
110
-        return $new_value;
111
-    }
112
-
113
-
114
-
115
-    /**
116
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
117
-     * "$query_params".
118
-     *
119
-     * @param EE_Model_Field_Base $field_obj
120
-     * @param mixed                $original_value
121
-     * @param string               $requested_version
122
-     * @param string               $timezone_string treat values as being in this timezone
123
-     * @return mixed
124
-     * @throws RestException
125
-     */
126
-    public static function prepareFieldValueFromJson(
127
-        $field_obj,
128
-        $original_value,
129
-        $requested_version,
130
-        $timezone_string = 'UTC' // UTC
131
-    ) {
132
-        //check if they accidentally submitted an error value. If so throw an exception
133
-        if (is_array($original_value)
134
-            && isset($original_value['error_code'], $original_value['error_message'])) {
135
-            throw new RestException(
136
-                'rest_submitted_error_value',
137
-                sprintf(
138
-                    esc_html__(
139
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
140
-                        'event_espresso'
141
-                    ),
142
-                    $field_obj->get_name()
143
-                ),
144
-                array(
145
-                    'status' => 400,
146
-                )
147
-            );
148
-        }
149
-        //double-check for serialized PHP. We never accept serialized PHP. No way Jose.
150
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
151
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
152
-        $new_value = null;
153
-        //walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
154
-        // way Jose.
155
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
156
-        if ($field_obj instanceof EE_Infinite_Integer_Field
157
-            && in_array($original_value, array(null, ''), true)
158
-        ) {
159
-            $new_value = EE_INF;
160
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
161
-            list($offset_sign, $offset_secs) = ModelDataTranslator::parseTimezoneOffset(
162
-                $field_obj->get_timezone_offset(
163
-                    new \DateTimeZone($timezone_string),
164
-                    $original_value
165
-                )
166
-            );
167
-            $offset_string =
168
-                str_pad(
169
-                    floor($offset_secs / HOUR_IN_SECONDS),
170
-                    2,
171
-                    '0',
172
-                    STR_PAD_LEFT
173
-                )
174
-                . ':'
175
-                . str_pad(
176
-                    ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
177
-                    2,
178
-                    '0',
179
-                    STR_PAD_LEFT
180
-                );
181
-            $new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
182
-        } else {
183
-            $new_value = $original_value;
184
-        }
185
-        return $new_value;
186
-    }
187
-
188
-
189
-
190
-    /**
191
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
192
-     * think that can happen). If $data is an array, recurses into its keys and values
193
-     * @param mixed $data
194
-     * @throws RestException
195
-     * @return void
196
-     */
197
-    public static function throwExceptionIfContainsSerializedData($data)
198
-    {
199
-        if (is_array($data)) {
200
-            foreach ($data as $key => $value) {
201
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
202
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
203
-            }
204
-        } else {
205
-            if (is_serialized($data) || is_object($data)) {
206
-                throw new RestException(
207
-                    'serialized_data_submission_prohibited',
208
-                    esc_html__(
209
-                        // @codingStandardsIgnoreStart
210
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
211
-                        // @codingStandardsIgnoreEnd
212
-                        'event_espresso'
213
-                    )
214
-                );
215
-            }
216
-        }
217
-    }
218
-
219
-
220
-
221
-    /**
222
-     * determines what's going on with them timezone strings
223
-     *
224
-     * @param int $timezone_offset
225
-     * @return array
226
-     */
227
-    private static function parseTimezoneOffset($timezone_offset)
228
-    {
229
-        $first_char = substr((string)$timezone_offset, 0, 1);
230
-        if ($first_char === '+' || $first_char === '-') {
231
-            $offset_sign = $first_char;
232
-            $offset_secs = substr((string)$timezone_offset, 1);
233
-        } else {
234
-            $offset_sign = '+';
235
-            $offset_secs = $timezone_offset;
236
-        }
237
-        return array($offset_sign, $offset_secs);
238
-    }
239
-
240
-
241
-
242
-    /**
243
-     * Prepares a field's value for display in the API
244
-     *
245
-     * @param EE_Model_Field_Base $field_obj
246
-     * @param mixed                $original_value
247
-     * @param string               $requested_version
248
-     * @return mixed
249
-     */
250
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
251
-    {
252
-        if ($original_value === EE_INF) {
253
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
254
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
255
-            if (is_string($original_value)) {
256
-                //did they submit a string of a unix timestamp?
257
-                if (is_numeric($original_value)) {
258
-                    $datetime_obj = new \DateTime();
259
-                    $datetime_obj->setTimestamp((int)$original_value);
260
-                } else {
261
-                    //first, check if its a MySQL timestamp in GMT
262
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
263
-                }
264
-                if (! $datetime_obj instanceof \DateTime) {
265
-                    //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
266
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
267
-                }
268
-                $original_value = $datetime_obj;
269
-            }
270
-            if ($original_value instanceof \DateTime) {
271
-                $new_value = $original_value->format('Y-m-d H:i:s');
272
-            } elseif (is_int($original_value) || is_float($original_value)) {
273
-                $new_value = date('Y-m-d H:i:s', $original_value);
274
-            } elseif($original_value === null || $original_value === '') {
275
-                $new_value = null;
276
-            } else {
277
-                //so it's not a datetime object, unix timestamp (as string or int),
278
-                //MySQL timestamp, or even a string in the field object's format. So no idea what it is
279
-                throw new \EE_Error(
280
-                    sprintf(
281
-                        esc_html__(
282
-                        // @codingStandardsIgnoreStart
283
-                            'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
284
-                            // @codingStandardsIgnoreEnd
285
-                            'event_espressso'
286
-                        ),
287
-                        $original_value,
288
-                        $field_obj->get_name(),
289
-                        $field_obj->get_model_name(),
290
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
291
-                    )
292
-                );
293
-            }
294
-            $new_value = mysql_to_rfc3339($new_value);
295
-        } else {
296
-            $new_value = $original_value;
297
-        }
298
-        //are we about to send an object? just don't. We have no good way to represent it in JSON.
299
-        // can't just check using is_object() because that missed PHP incomplete objects
300
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
301
-            $new_value = array(
302
-                'error_code' => 'php_object_not_return',
303
-                'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
304
-            );
305
-        }
306
-        return apply_filters(
307
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
308
-            $new_value,
309
-            $field_obj,
310
-            $original_value,
311
-            $requested_version
312
-        );
313
-    }
314
-
315
-
316
-
317
-    /**
318
-     * Prepares condition-query-parameters (like what's in where and having) from
319
-     * the format expected in the API to use in the models
320
-     *
321
-     * @param array     $inputted_query_params_of_this_type
322
-     * @param EEM_Base $model
323
-     * @param string    $requested_version
324
-     * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
325
-     *                         If we're writing to the DB, we don't expect any operators, or any logic query parameters,
326
-     *                         and we also won't accept serialized data unless the current user has unfiltered_html.
327
-     * @return array
328
-     * @throws \DomainException
329
-     * @throws RestException
330
-     * @throws EE_Error
331
-     */
332
-    public static function prepareConditionsQueryParamsForModels(
333
-        $inputted_query_params_of_this_type,
334
-        EEM_Base $model,
335
-        $requested_version,
336
-        $writing = false
337
-    ) {
338
-        $query_param_for_models = array();
339
-        $valid_operators = $model->valid_operators();
340
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
341
-            $is_gmt_datetime_field = false;
342
-            $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
343
-                $query_param_key
344
-            );
345
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
346
-                $query_param_sans_stars,
347
-                $model
348
-            );
349
-            //double-check is it a *_gmt field?
350
-            if (! $field instanceof EE_Model_Field_Base
351
-                && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
352
-            ) {
353
-                //yep, take off '_gmt', and find the field
354
-                $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
355
-                $field = ModelDataTranslator::deduceFieldFromQueryParam(
356
-                    $query_param_key,
357
-                    $model
358
-                );
359
-                $timezone = 'UTC';
360
-                $is_gmt_datetime_field = true;
361
-            } elseif ($field instanceof EE_Datetime_Field) {
362
-                //so it's not a GMT field. Set the timezone on the model to the default
363
-                $timezone = \EEH_DTT_Helper::get_valid_timezone_string();
364
-            } else {
365
-                //just keep using what's already set for the timezone
366
-                $timezone = $model->get_timezone();
367
-            }
368
-            if ($field instanceof EE_Model_Field_Base) {
369
-                if (! $writing && is_array($query_param_value)) {
370
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
371
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
372
-                            throw new RestException(
373
-                                'numerically_indexed_array_of_values_only',
374
-                                sprintf(
375
-                                    esc_html__(
376
-                                        'The array provided for the parameter "%1$s" should be numerically indexed.',
377
-                                        'event_espresso'
378
-                                    ),
379
-                                    $query_param_key
380
-                                ),
381
-                                array(
382
-                                    'status' => 400,
383
-                                )
384
-                            );
385
-                        }
386
-                    }
387
-                    //did they specify an operator?
388
-                    if (isset($query_param_value[0])
389
-                        && isset($valid_operators[$query_param_value[0]])
390
-                    ) {
391
-                        $op = $query_param_value[0];
392
-                        $translated_value = array($op);
393
-                        if (array_key_exists($op, $model->valid_in_style_operators())
394
-                            && isset($query_param_value[1])
395
-                            && ! isset($query_param_value[2])
396
-                        ) {
397
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
398
-                                $field,
399
-                                $query_param_value[1],
400
-                                $requested_version,
401
-                                $timezone
402
-                            );
403
-                        } elseif (array_key_exists($op, $model->valid_between_style_operators())
404
-                            && isset($query_param_value[1], $query_param_value[2])
405
-                            && !isset($query_param_value[3])
406
-                        ) {
407
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
408
-                                $field,
409
-                                $query_param_value[1],
410
-                                $requested_version,
411
-                                $timezone
412
-                            );
413
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
414
-                                $field,
415
-                                $query_param_value[2],
416
-                                $requested_version,
417
-                                $timezone
418
-                            );
419
-                        } elseif (array_key_exists($op, $model->valid_like_style_operators())
420
-                            && isset($query_param_value[1])
421
-                            && ! isset($query_param_value[2])
422
-                        ) {
423
-                            //we want to leave this value mostly-as-is (eg don't force it to be a float
424
-                            //or a boolean or an enum value. Leave it as-is with wildcards etc)
425
-                            //but do verify it at least doesn't have any serialized data
426
-                            ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
427
-                            $translated_value[] = $query_param_value[1];
428
-                        } elseif (array_key_exists($op, $model->valid_null_style_operators())
429
-                            && !isset($query_param_value[1])) {
430
-                            //no arguments should have been provided, so don't look for any
431
-                        } elseif (isset($query_param_value[1])
432
-                            && !isset($query_param_value[2])
433
-                            && ! array_key_exists(
434
-                                $op,
435
-                                array_merge(
436
-                                    $model->valid_in_style_operators(),
437
-                                    $model->valid_null_style_operators(),
438
-                                    $model->valid_like_style_operators(),
439
-                                    $model->valid_between_style_operators()
440
-                                )
441
-                            )
442
-                        ) {
443
-                            //it's a valid operator, but none of the exceptions. Treat it normally.
444
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
445
-                                $field,
446
-                                $query_param_value[1],
447
-                                $requested_version,
448
-                                $timezone
449
-                            );
450
-                        } else {
451
-                            //so they provided a valid operator, but wrong number of arguments
452
-                            if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
453
-                                throw new RestException(
454
-                                    'wrong_number_of_arguments',
455
-                                    sprintf(
456
-                                        esc_html__(
457
-                                            'The operator you provided, "%1$s" had the wrong number of arguments',
458
-                                            'event_espresso'
459
-                                        ),
460
-                                        $op
461
-                                    ),
462
-                                    array(
463
-                                        'status' => 400,
464
-                                    )
465
-                                );
466
-                            }
467
-                            $translated_value = null;
468
-                        }
469
-                    } else {
470
-                        //so they didn't provide a valid operator
471
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
472
-                            throw new RestException(
473
-                                'invalid_operator',
474
-                                sprintf(
475
-                                    esc_html__(
476
-                                        'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
477
-                                        'event_espresso'
478
-                                    ),
479
-                                    $query_param_key,
480
-                                    $query_param_value
481
-                                ),
482
-                                array(
483
-                                    'status' => 400,
484
-                                )
485
-                            );
486
-                        }
487
-                        //if we aren't in debug mode, then just try our best to fulfill the user's request
488
-                        $translated_value = null;
489
-                    }
490
-                } else {
491
-                    $translated_value = ModelDataTranslator::prepareFieldValueFromJson(
492
-                        $field,
493
-                        $query_param_value,
494
-                        $requested_version,
495
-                        $timezone
496
-                    );
497
-                }
498
-                if (
499
-                    (isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
500
-                    ||
501
-                    $translated_value === null
502
-                ) {
503
-                    //they have already provided a non-gmt field, ignore the gmt one. That's what WP core
504
-                    //currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
505
-                    //OR we couldn't create a translated value from their input
506
-                    continue;
507
-                }
508
-                $query_param_for_models[$query_param_key] = $translated_value;
509
-            } else {
510
-                //so this param doesn't correspond to a field eh?
511
-                if ($writing) {
512
-                    //always tell API clients about invalid parameters when they're creating data. Otherwise,
513
-                    //they are probably going to create invalid data
514
-                    throw new RestException(
515
-                        'invalid_field',
516
-                        sprintf(
517
-                            esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
518
-                            $query_param_key
519
-                        )
520
-                    );
521
-                } else {
522
-                    //so it's not for a field, is it a logic query param key?
523
-                    if (in_array(
524
-                        $query_param_sans_stars,
525
-                        $model->logic_query_param_keys()
526
-                    )) {
527
-                        $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
528
-                            $query_param_value,
529
-                            $model,
530
-                            $requested_version
531
-                        );
532
-                    } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
533
-                        //only tell API clients they got it wrong if we're in debug mode
534
-                        //otherwise try our best ot fulfill their request by ignoring this invalid data
535
-                        throw new RestException(
536
-                            'invalid_parameter',
537
-                            sprintf(
538
-                                esc_html__(
539
-                                    'You provided an invalid parameter, with key "%1$s"',
540
-                                    'event_espresso'
541
-                                ),
542
-                                $query_param_sans_stars
543
-                            ),
544
-                            array(
545
-                                'status' => 400,
546
-                            )
547
-                        );
548
-                    }
549
-                }
550
-            }
551
-        }
552
-        return $query_param_for_models;
553
-    }
554
-
555
-
556
-
557
-    /**
558
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
559
-     * gmt date field name
560
-     *
561
-     * @param string $field_name
562
-     * @return boolean
563
-     */
564
-    public static function isGmtDateFieldName($field_name)
565
-    {
566
-        return substr(
567
-            ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
568
-            -4,
569
-            4
570
-        ) === '_gmt';
571
-    }
572
-
573
-
574
-
575
-    /**
576
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
577
-     *
578
-     * @param string $field_name
579
-     * @return string
580
-     */
581
-    public static function removeGmtFromFieldName($field_name)
582
-    {
583
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
584
-            return $field_name;
585
-        }
586
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
587
-            $field_name
588
-        );
589
-        $query_param_sans_gmt_and_sans_stars = substr(
590
-            $query_param_sans_stars,
591
-            0,
592
-            strrpos(
593
-                $field_name,
594
-                '_gmt'
595
-            )
596
-        );
597
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
598
-    }
599
-
600
-
601
-
602
-    /**
603
-     * Takes a field name from the REST API and prepares it for the model querying
604
-     *
605
-     * @param string $field_name
606
-     * @return string
607
-     */
608
-    public static function prepareFieldNameFromJson($field_name)
609
-    {
610
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
611
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
612
-        }
613
-        return $field_name;
614
-    }
615
-
616
-
617
-
618
-    /**
619
-     * Takes array of field names from REST API and prepares for models
620
-     *
621
-     * @param array $field_names
622
-     * @return array of field names (possibly include model prefixes)
623
-     */
624
-    public static function prepareFieldNamesFromJson(array $field_names)
625
-    {
626
-        $new_array = array();
627
-        foreach ($field_names as $key => $field_name) {
628
-            $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
629
-        }
630
-        return $new_array;
631
-    }
632
-
633
-
634
-
635
-    /**
636
-     * Takes array where array keys are field names (possibly with model path prefixes)
637
-     * from the REST API and prepares them for model querying
638
-     *
639
-     * @param array $field_names_as_keys
640
-     * @return array
641
-     */
642
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
643
-    {
644
-        $new_array = array();
645
-        foreach ($field_names_as_keys as $field_name => $value) {
646
-            $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
647
-        }
648
-        return $new_array;
649
-    }
650
-
651
-
652
-
653
-    /**
654
-     * Prepares an array of model query params for use in the REST API
655
-     *
656
-     * @param array     $model_query_params
657
-     * @param EEM_Base $model
658
-     * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
659
-     *                                     REST API
660
-     * @return array which can be passed into the EE4 REST API when querying a model resource
661
-     * @throws EE_Error
662
-     */
663
-    public static function prepareQueryParamsForRestApi(
664
-        array $model_query_params,
665
-        EEM_Base $model,
666
-        $requested_version = null
667
-    ) {
668
-        if ($requested_version === null) {
669
-            $requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
670
-        }
671
-        $rest_query_params = $model_query_params;
672
-        if (isset($model_query_params[0])) {
673
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
674
-                $model_query_params[0],
675
-                $model,
676
-                $requested_version
677
-            );
678
-            unset($rest_query_params[0]);
679
-        }
680
-        if (isset($model_query_params['having'])) {
681
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
682
-                $model_query_params['having'],
683
-                $model,
684
-                $requested_version
685
-            );
686
-        }
687
-        return apply_filters(
688
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
689
-            $rest_query_params,
690
-            $model_query_params,
691
-            $model,
692
-            $requested_version
693
-        );
694
-    }
695
-
696
-
697
-
698
-    /**
699
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
700
-     *
701
-     * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
702
-     *                                                      passed into EEM_Base::get_all()
703
-     * @param EEM_Base $model
704
-     * @param string    $requested_version                  eg "4.8.36"
705
-     * @return array ready for use in the rest api query params
706
-     * @throws EE_Error
707
-     * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
708
-     *                                     (which would be really unusual)
709
-     */
710
-    public static function prepareConditionsQueryParamsForRestApi(
711
-        $inputted_query_params_of_this_type,
712
-        EEM_Base $model,
713
-        $requested_version
714
-    ) {
715
-        $query_param_for_models = array();
716
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
717
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
718
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
719
-                $model
720
-            );
721
-            if ($field instanceof EE_Model_Field_Base) {
722
-                //did they specify an operator?
723
-                if (is_array($query_param_value)) {
724
-                    $op = $query_param_value[0];
725
-                    $translated_value = array($op);
726
-                    if (isset($query_param_value[1])) {
727
-                        $value = $query_param_value[1];
728
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
729
-                            $field,
730
-                            $value,
731
-                            $requested_version
732
-                        );
733
-                    }
734
-                } else {
735
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
736
-                        $field,
737
-                        $query_param_value,
738
-                        $requested_version
739
-                    );
740
-                }
741
-                $query_param_for_models[$query_param_key] = $translated_value;
742
-            } else {
743
-                //so it's not for a field, assume it's a logic query param key
744
-                $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
745
-                    $query_param_value,
746
-                    $model,
747
-                    $requested_version
748
-                );
749
-            }
750
-        }
751
-        return $query_param_for_models;
752
-    }
753
-
754
-
755
-
756
-    /**
757
-     * @param $condition_query_param_key
758
-     * @return string
759
-     */
760
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
761
-    {
762
-        $pos_of_star = strpos($condition_query_param_key, '*');
763
-        if ($pos_of_star === false) {
764
-            return $condition_query_param_key;
765
-        } else {
766
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
767
-            return $condition_query_param_sans_star;
768
-        }
769
-    }
770
-
771
-
772
-
773
-    /**
774
-     * Takes the input parameter and finds the model field that it indicates.
775
-     *
776
-     * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
777
-     * @param EEM_Base $model
778
-     * @return EE_Model_Field_Base
779
-     * @throws EE_Error
780
-     */
781
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
782
-    {
783
-        //ok, now proceed with deducing which part is the model's name, and which is the field's name
784
-        //which will help us find the database table and column
785
-        $query_param_parts = explode('.', $query_param_name);
786
-        if (empty($query_param_parts)) {
787
-            throw new EE_Error(
788
-                sprintf(
789
-                    __(
790
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
791
-                        'event_espresso'
792
-                    ),
793
-                    $query_param_name
794
-                )
795
-            );
796
-        }
797
-        $number_of_parts = count($query_param_parts);
798
-        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
799
-        if ($number_of_parts === 1) {
800
-            $field_name = $last_query_param_part;
801
-        } else {// $number_of_parts >= 2
802
-            //the last part is the column name, and there are only 2parts. therefore...
803
-            $field_name = $last_query_param_part;
804
-            $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
805
-        }
806
-        try {
807
-            return $model->field_settings_for($field_name, false);
808
-        } catch (EE_Error $e) {
809
-            return null;
810
-        }
811
-    }
812
-
813
-
814
-
815
-    /**
816
-     * Returns true if $data can be easily represented in JSON.
817
-     * Basically, objects and resources can't be represented in JSON easily.
818
-     * @param mixed $data
819
-     * @return bool
820
-     */
821
-    protected static function isRepresentableInJson($data)
822
-    {
823
-        return is_scalar($data)
824
-               || is_array($data)
825
-               || is_null($data);
826
-    }
39
+	/**
40
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
41
+	 * fields that COULD contain -1; so we use null
42
+	 */
43
+	const EE_INF_IN_REST = null;
44
+
45
+
46
+
47
+	/**
48
+	 * Prepares a possible array of input values from JSON for use by the models
49
+	 *
50
+	 * @param EE_Model_Field_Base $field_obj
51
+	 * @param mixed                $original_value_maybe_array
52
+	 * @param string               $requested_version
53
+	 * @param string               $timezone_string treat values as being in this timezone
54
+	 * @return mixed
55
+	 * @throws RestException
56
+	 */
57
+	public static function prepareFieldValuesFromJson(
58
+		$field_obj,
59
+		$original_value_maybe_array,
60
+		$requested_version,
61
+		$timezone_string = 'UTC'
62
+	) {
63
+		if (is_array($original_value_maybe_array)
64
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
65
+		) {
66
+			$new_value_maybe_array = array();
67
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
68
+				$new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
69
+					$field_obj,
70
+					$array_item,
71
+					$requested_version,
72
+					$timezone_string
73
+				);
74
+			}
75
+		} else {
76
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
77
+				$field_obj,
78
+				$original_value_maybe_array,
79
+				$requested_version,
80
+				$timezone_string
81
+			);
82
+		}
83
+		return $new_value_maybe_array;
84
+	}
85
+
86
+
87
+
88
+	/**
89
+	 * Prepares an array of field values FOR use in JSON/REST API
90
+	 *
91
+	 * @param EE_Model_Field_Base $field_obj
92
+	 * @param mixed                $original_value_maybe_array
93
+	 * @param string               $request_version (eg 4.8.36)
94
+	 * @return array
95
+	 */
96
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
97
+	{
98
+		if (is_array($original_value_maybe_array)) {
99
+			$new_value = array();
100
+			foreach ($original_value_maybe_array as $key => $value) {
101
+				$new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version);
102
+			}
103
+		} else {
104
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
105
+				$field_obj,
106
+				$original_value_maybe_array,
107
+				$request_version
108
+			);
109
+		}
110
+		return $new_value;
111
+	}
112
+
113
+
114
+
115
+	/**
116
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
117
+	 * "$query_params".
118
+	 *
119
+	 * @param EE_Model_Field_Base $field_obj
120
+	 * @param mixed                $original_value
121
+	 * @param string               $requested_version
122
+	 * @param string               $timezone_string treat values as being in this timezone
123
+	 * @return mixed
124
+	 * @throws RestException
125
+	 */
126
+	public static function prepareFieldValueFromJson(
127
+		$field_obj,
128
+		$original_value,
129
+		$requested_version,
130
+		$timezone_string = 'UTC' // UTC
131
+	) {
132
+		//check if they accidentally submitted an error value. If so throw an exception
133
+		if (is_array($original_value)
134
+			&& isset($original_value['error_code'], $original_value['error_message'])) {
135
+			throw new RestException(
136
+				'rest_submitted_error_value',
137
+				sprintf(
138
+					esc_html__(
139
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
140
+						'event_espresso'
141
+					),
142
+					$field_obj->get_name()
143
+				),
144
+				array(
145
+					'status' => 400,
146
+				)
147
+			);
148
+		}
149
+		//double-check for serialized PHP. We never accept serialized PHP. No way Jose.
150
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
151
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
152
+		$new_value = null;
153
+		//walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
154
+		// way Jose.
155
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
156
+		if ($field_obj instanceof EE_Infinite_Integer_Field
157
+			&& in_array($original_value, array(null, ''), true)
158
+		) {
159
+			$new_value = EE_INF;
160
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
161
+			list($offset_sign, $offset_secs) = ModelDataTranslator::parseTimezoneOffset(
162
+				$field_obj->get_timezone_offset(
163
+					new \DateTimeZone($timezone_string),
164
+					$original_value
165
+				)
166
+			);
167
+			$offset_string =
168
+				str_pad(
169
+					floor($offset_secs / HOUR_IN_SECONDS),
170
+					2,
171
+					'0',
172
+					STR_PAD_LEFT
173
+				)
174
+				. ':'
175
+				. str_pad(
176
+					($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
177
+					2,
178
+					'0',
179
+					STR_PAD_LEFT
180
+				);
181
+			$new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
182
+		} else {
183
+			$new_value = $original_value;
184
+		}
185
+		return $new_value;
186
+	}
187
+
188
+
189
+
190
+	/**
191
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
192
+	 * think that can happen). If $data is an array, recurses into its keys and values
193
+	 * @param mixed $data
194
+	 * @throws RestException
195
+	 * @return void
196
+	 */
197
+	public static function throwExceptionIfContainsSerializedData($data)
198
+	{
199
+		if (is_array($data)) {
200
+			foreach ($data as $key => $value) {
201
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
202
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
203
+			}
204
+		} else {
205
+			if (is_serialized($data) || is_object($data)) {
206
+				throw new RestException(
207
+					'serialized_data_submission_prohibited',
208
+					esc_html__(
209
+						// @codingStandardsIgnoreStart
210
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
211
+						// @codingStandardsIgnoreEnd
212
+						'event_espresso'
213
+					)
214
+				);
215
+			}
216
+		}
217
+	}
218
+
219
+
220
+
221
+	/**
222
+	 * determines what's going on with them timezone strings
223
+	 *
224
+	 * @param int $timezone_offset
225
+	 * @return array
226
+	 */
227
+	private static function parseTimezoneOffset($timezone_offset)
228
+	{
229
+		$first_char = substr((string)$timezone_offset, 0, 1);
230
+		if ($first_char === '+' || $first_char === '-') {
231
+			$offset_sign = $first_char;
232
+			$offset_secs = substr((string)$timezone_offset, 1);
233
+		} else {
234
+			$offset_sign = '+';
235
+			$offset_secs = $timezone_offset;
236
+		}
237
+		return array($offset_sign, $offset_secs);
238
+	}
239
+
240
+
241
+
242
+	/**
243
+	 * Prepares a field's value for display in the API
244
+	 *
245
+	 * @param EE_Model_Field_Base $field_obj
246
+	 * @param mixed                $original_value
247
+	 * @param string               $requested_version
248
+	 * @return mixed
249
+	 */
250
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
251
+	{
252
+		if ($original_value === EE_INF) {
253
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
254
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
255
+			if (is_string($original_value)) {
256
+				//did they submit a string of a unix timestamp?
257
+				if (is_numeric($original_value)) {
258
+					$datetime_obj = new \DateTime();
259
+					$datetime_obj->setTimestamp((int)$original_value);
260
+				} else {
261
+					//first, check if its a MySQL timestamp in GMT
262
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
263
+				}
264
+				if (! $datetime_obj instanceof \DateTime) {
265
+					//so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
266
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
267
+				}
268
+				$original_value = $datetime_obj;
269
+			}
270
+			if ($original_value instanceof \DateTime) {
271
+				$new_value = $original_value->format('Y-m-d H:i:s');
272
+			} elseif (is_int($original_value) || is_float($original_value)) {
273
+				$new_value = date('Y-m-d H:i:s', $original_value);
274
+			} elseif($original_value === null || $original_value === '') {
275
+				$new_value = null;
276
+			} else {
277
+				//so it's not a datetime object, unix timestamp (as string or int),
278
+				//MySQL timestamp, or even a string in the field object's format. So no idea what it is
279
+				throw new \EE_Error(
280
+					sprintf(
281
+						esc_html__(
282
+						// @codingStandardsIgnoreStart
283
+							'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
284
+							// @codingStandardsIgnoreEnd
285
+							'event_espressso'
286
+						),
287
+						$original_value,
288
+						$field_obj->get_name(),
289
+						$field_obj->get_model_name(),
290
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
291
+					)
292
+				);
293
+			}
294
+			$new_value = mysql_to_rfc3339($new_value);
295
+		} else {
296
+			$new_value = $original_value;
297
+		}
298
+		//are we about to send an object? just don't. We have no good way to represent it in JSON.
299
+		// can't just check using is_object() because that missed PHP incomplete objects
300
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
301
+			$new_value = array(
302
+				'error_code' => 'php_object_not_return',
303
+				'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
304
+			);
305
+		}
306
+		return apply_filters(
307
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
308
+			$new_value,
309
+			$field_obj,
310
+			$original_value,
311
+			$requested_version
312
+		);
313
+	}
314
+
315
+
316
+
317
+	/**
318
+	 * Prepares condition-query-parameters (like what's in where and having) from
319
+	 * the format expected in the API to use in the models
320
+	 *
321
+	 * @param array     $inputted_query_params_of_this_type
322
+	 * @param EEM_Base $model
323
+	 * @param string    $requested_version
324
+	 * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
325
+	 *                         If we're writing to the DB, we don't expect any operators, or any logic query parameters,
326
+	 *                         and we also won't accept serialized data unless the current user has unfiltered_html.
327
+	 * @return array
328
+	 * @throws \DomainException
329
+	 * @throws RestException
330
+	 * @throws EE_Error
331
+	 */
332
+	public static function prepareConditionsQueryParamsForModels(
333
+		$inputted_query_params_of_this_type,
334
+		EEM_Base $model,
335
+		$requested_version,
336
+		$writing = false
337
+	) {
338
+		$query_param_for_models = array();
339
+		$valid_operators = $model->valid_operators();
340
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
341
+			$is_gmt_datetime_field = false;
342
+			$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
343
+				$query_param_key
344
+			);
345
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
346
+				$query_param_sans_stars,
347
+				$model
348
+			);
349
+			//double-check is it a *_gmt field?
350
+			if (! $field instanceof EE_Model_Field_Base
351
+				&& ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
352
+			) {
353
+				//yep, take off '_gmt', and find the field
354
+				$query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
355
+				$field = ModelDataTranslator::deduceFieldFromQueryParam(
356
+					$query_param_key,
357
+					$model
358
+				);
359
+				$timezone = 'UTC';
360
+				$is_gmt_datetime_field = true;
361
+			} elseif ($field instanceof EE_Datetime_Field) {
362
+				//so it's not a GMT field. Set the timezone on the model to the default
363
+				$timezone = \EEH_DTT_Helper::get_valid_timezone_string();
364
+			} else {
365
+				//just keep using what's already set for the timezone
366
+				$timezone = $model->get_timezone();
367
+			}
368
+			if ($field instanceof EE_Model_Field_Base) {
369
+				if (! $writing && is_array($query_param_value)) {
370
+					if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
371
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
372
+							throw new RestException(
373
+								'numerically_indexed_array_of_values_only',
374
+								sprintf(
375
+									esc_html__(
376
+										'The array provided for the parameter "%1$s" should be numerically indexed.',
377
+										'event_espresso'
378
+									),
379
+									$query_param_key
380
+								),
381
+								array(
382
+									'status' => 400,
383
+								)
384
+							);
385
+						}
386
+					}
387
+					//did they specify an operator?
388
+					if (isset($query_param_value[0])
389
+						&& isset($valid_operators[$query_param_value[0]])
390
+					) {
391
+						$op = $query_param_value[0];
392
+						$translated_value = array($op);
393
+						if (array_key_exists($op, $model->valid_in_style_operators())
394
+							&& isset($query_param_value[1])
395
+							&& ! isset($query_param_value[2])
396
+						) {
397
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
398
+								$field,
399
+								$query_param_value[1],
400
+								$requested_version,
401
+								$timezone
402
+							);
403
+						} elseif (array_key_exists($op, $model->valid_between_style_operators())
404
+							&& isset($query_param_value[1], $query_param_value[2])
405
+							&& !isset($query_param_value[3])
406
+						) {
407
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
408
+								$field,
409
+								$query_param_value[1],
410
+								$requested_version,
411
+								$timezone
412
+							);
413
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
414
+								$field,
415
+								$query_param_value[2],
416
+								$requested_version,
417
+								$timezone
418
+							);
419
+						} elseif (array_key_exists($op, $model->valid_like_style_operators())
420
+							&& isset($query_param_value[1])
421
+							&& ! isset($query_param_value[2])
422
+						) {
423
+							//we want to leave this value mostly-as-is (eg don't force it to be a float
424
+							//or a boolean or an enum value. Leave it as-is with wildcards etc)
425
+							//but do verify it at least doesn't have any serialized data
426
+							ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
427
+							$translated_value[] = $query_param_value[1];
428
+						} elseif (array_key_exists($op, $model->valid_null_style_operators())
429
+							&& !isset($query_param_value[1])) {
430
+							//no arguments should have been provided, so don't look for any
431
+						} elseif (isset($query_param_value[1])
432
+							&& !isset($query_param_value[2])
433
+							&& ! array_key_exists(
434
+								$op,
435
+								array_merge(
436
+									$model->valid_in_style_operators(),
437
+									$model->valid_null_style_operators(),
438
+									$model->valid_like_style_operators(),
439
+									$model->valid_between_style_operators()
440
+								)
441
+							)
442
+						) {
443
+							//it's a valid operator, but none of the exceptions. Treat it normally.
444
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
445
+								$field,
446
+								$query_param_value[1],
447
+								$requested_version,
448
+								$timezone
449
+							);
450
+						} else {
451
+							//so they provided a valid operator, but wrong number of arguments
452
+							if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
453
+								throw new RestException(
454
+									'wrong_number_of_arguments',
455
+									sprintf(
456
+										esc_html__(
457
+											'The operator you provided, "%1$s" had the wrong number of arguments',
458
+											'event_espresso'
459
+										),
460
+										$op
461
+									),
462
+									array(
463
+										'status' => 400,
464
+									)
465
+								);
466
+							}
467
+							$translated_value = null;
468
+						}
469
+					} else {
470
+						//so they didn't provide a valid operator
471
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
472
+							throw new RestException(
473
+								'invalid_operator',
474
+								sprintf(
475
+									esc_html__(
476
+										'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
477
+										'event_espresso'
478
+									),
479
+									$query_param_key,
480
+									$query_param_value
481
+								),
482
+								array(
483
+									'status' => 400,
484
+								)
485
+							);
486
+						}
487
+						//if we aren't in debug mode, then just try our best to fulfill the user's request
488
+						$translated_value = null;
489
+					}
490
+				} else {
491
+					$translated_value = ModelDataTranslator::prepareFieldValueFromJson(
492
+						$field,
493
+						$query_param_value,
494
+						$requested_version,
495
+						$timezone
496
+					);
497
+				}
498
+				if (
499
+					(isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
500
+					||
501
+					$translated_value === null
502
+				) {
503
+					//they have already provided a non-gmt field, ignore the gmt one. That's what WP core
504
+					//currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
505
+					//OR we couldn't create a translated value from their input
506
+					continue;
507
+				}
508
+				$query_param_for_models[$query_param_key] = $translated_value;
509
+			} else {
510
+				//so this param doesn't correspond to a field eh?
511
+				if ($writing) {
512
+					//always tell API clients about invalid parameters when they're creating data. Otherwise,
513
+					//they are probably going to create invalid data
514
+					throw new RestException(
515
+						'invalid_field',
516
+						sprintf(
517
+							esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
518
+							$query_param_key
519
+						)
520
+					);
521
+				} else {
522
+					//so it's not for a field, is it a logic query param key?
523
+					if (in_array(
524
+						$query_param_sans_stars,
525
+						$model->logic_query_param_keys()
526
+					)) {
527
+						$query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
528
+							$query_param_value,
529
+							$model,
530
+							$requested_version
531
+						);
532
+					} elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
533
+						//only tell API clients they got it wrong if we're in debug mode
534
+						//otherwise try our best ot fulfill their request by ignoring this invalid data
535
+						throw new RestException(
536
+							'invalid_parameter',
537
+							sprintf(
538
+								esc_html__(
539
+									'You provided an invalid parameter, with key "%1$s"',
540
+									'event_espresso'
541
+								),
542
+								$query_param_sans_stars
543
+							),
544
+							array(
545
+								'status' => 400,
546
+							)
547
+						);
548
+					}
549
+				}
550
+			}
551
+		}
552
+		return $query_param_for_models;
553
+	}
554
+
555
+
556
+
557
+	/**
558
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
559
+	 * gmt date field name
560
+	 *
561
+	 * @param string $field_name
562
+	 * @return boolean
563
+	 */
564
+	public static function isGmtDateFieldName($field_name)
565
+	{
566
+		return substr(
567
+			ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
568
+			-4,
569
+			4
570
+		) === '_gmt';
571
+	}
572
+
573
+
574
+
575
+	/**
576
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
577
+	 *
578
+	 * @param string $field_name
579
+	 * @return string
580
+	 */
581
+	public static function removeGmtFromFieldName($field_name)
582
+	{
583
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
584
+			return $field_name;
585
+		}
586
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
587
+			$field_name
588
+		);
589
+		$query_param_sans_gmt_and_sans_stars = substr(
590
+			$query_param_sans_stars,
591
+			0,
592
+			strrpos(
593
+				$field_name,
594
+				'_gmt'
595
+			)
596
+		);
597
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
598
+	}
599
+
600
+
601
+
602
+	/**
603
+	 * Takes a field name from the REST API and prepares it for the model querying
604
+	 *
605
+	 * @param string $field_name
606
+	 * @return string
607
+	 */
608
+	public static function prepareFieldNameFromJson($field_name)
609
+	{
610
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
611
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
612
+		}
613
+		return $field_name;
614
+	}
615
+
616
+
617
+
618
+	/**
619
+	 * Takes array of field names from REST API and prepares for models
620
+	 *
621
+	 * @param array $field_names
622
+	 * @return array of field names (possibly include model prefixes)
623
+	 */
624
+	public static function prepareFieldNamesFromJson(array $field_names)
625
+	{
626
+		$new_array = array();
627
+		foreach ($field_names as $key => $field_name) {
628
+			$new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
629
+		}
630
+		return $new_array;
631
+	}
632
+
633
+
634
+
635
+	/**
636
+	 * Takes array where array keys are field names (possibly with model path prefixes)
637
+	 * from the REST API and prepares them for model querying
638
+	 *
639
+	 * @param array $field_names_as_keys
640
+	 * @return array
641
+	 */
642
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
643
+	{
644
+		$new_array = array();
645
+		foreach ($field_names_as_keys as $field_name => $value) {
646
+			$new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
647
+		}
648
+		return $new_array;
649
+	}
650
+
651
+
652
+
653
+	/**
654
+	 * Prepares an array of model query params for use in the REST API
655
+	 *
656
+	 * @param array     $model_query_params
657
+	 * @param EEM_Base $model
658
+	 * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
659
+	 *                                     REST API
660
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
661
+	 * @throws EE_Error
662
+	 */
663
+	public static function prepareQueryParamsForRestApi(
664
+		array $model_query_params,
665
+		EEM_Base $model,
666
+		$requested_version = null
667
+	) {
668
+		if ($requested_version === null) {
669
+			$requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
670
+		}
671
+		$rest_query_params = $model_query_params;
672
+		if (isset($model_query_params[0])) {
673
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
674
+				$model_query_params[0],
675
+				$model,
676
+				$requested_version
677
+			);
678
+			unset($rest_query_params[0]);
679
+		}
680
+		if (isset($model_query_params['having'])) {
681
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
682
+				$model_query_params['having'],
683
+				$model,
684
+				$requested_version
685
+			);
686
+		}
687
+		return apply_filters(
688
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
689
+			$rest_query_params,
690
+			$model_query_params,
691
+			$model,
692
+			$requested_version
693
+		);
694
+	}
695
+
696
+
697
+
698
+	/**
699
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
700
+	 *
701
+	 * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
702
+	 *                                                      passed into EEM_Base::get_all()
703
+	 * @param EEM_Base $model
704
+	 * @param string    $requested_version                  eg "4.8.36"
705
+	 * @return array ready for use in the rest api query params
706
+	 * @throws EE_Error
707
+	 * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
708
+	 *                                     (which would be really unusual)
709
+	 */
710
+	public static function prepareConditionsQueryParamsForRestApi(
711
+		$inputted_query_params_of_this_type,
712
+		EEM_Base $model,
713
+		$requested_version
714
+	) {
715
+		$query_param_for_models = array();
716
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
717
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
718
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
719
+				$model
720
+			);
721
+			if ($field instanceof EE_Model_Field_Base) {
722
+				//did they specify an operator?
723
+				if (is_array($query_param_value)) {
724
+					$op = $query_param_value[0];
725
+					$translated_value = array($op);
726
+					if (isset($query_param_value[1])) {
727
+						$value = $query_param_value[1];
728
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
729
+							$field,
730
+							$value,
731
+							$requested_version
732
+						);
733
+					}
734
+				} else {
735
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
736
+						$field,
737
+						$query_param_value,
738
+						$requested_version
739
+					);
740
+				}
741
+				$query_param_for_models[$query_param_key] = $translated_value;
742
+			} else {
743
+				//so it's not for a field, assume it's a logic query param key
744
+				$query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
745
+					$query_param_value,
746
+					$model,
747
+					$requested_version
748
+				);
749
+			}
750
+		}
751
+		return $query_param_for_models;
752
+	}
753
+
754
+
755
+
756
+	/**
757
+	 * @param $condition_query_param_key
758
+	 * @return string
759
+	 */
760
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
761
+	{
762
+		$pos_of_star = strpos($condition_query_param_key, '*');
763
+		if ($pos_of_star === false) {
764
+			return $condition_query_param_key;
765
+		} else {
766
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
767
+			return $condition_query_param_sans_star;
768
+		}
769
+	}
770
+
771
+
772
+
773
+	/**
774
+	 * Takes the input parameter and finds the model field that it indicates.
775
+	 *
776
+	 * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
777
+	 * @param EEM_Base $model
778
+	 * @return EE_Model_Field_Base
779
+	 * @throws EE_Error
780
+	 */
781
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
782
+	{
783
+		//ok, now proceed with deducing which part is the model's name, and which is the field's name
784
+		//which will help us find the database table and column
785
+		$query_param_parts = explode('.', $query_param_name);
786
+		if (empty($query_param_parts)) {
787
+			throw new EE_Error(
788
+				sprintf(
789
+					__(
790
+						'_extract_column_name is empty when trying to extract column and table name from %s',
791
+						'event_espresso'
792
+					),
793
+					$query_param_name
794
+				)
795
+			);
796
+		}
797
+		$number_of_parts = count($query_param_parts);
798
+		$last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
799
+		if ($number_of_parts === 1) {
800
+			$field_name = $last_query_param_part;
801
+		} else {// $number_of_parts >= 2
802
+			//the last part is the column name, and there are only 2parts. therefore...
803
+			$field_name = $last_query_param_part;
804
+			$model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
805
+		}
806
+		try {
807
+			return $model->field_settings_for($field_name, false);
808
+		} catch (EE_Error $e) {
809
+			return null;
810
+		}
811
+	}
812
+
813
+
814
+
815
+	/**
816
+	 * Returns true if $data can be easily represented in JSON.
817
+	 * Basically, objects and resources can't be represented in JSON easily.
818
+	 * @param mixed $data
819
+	 * @return bool
820
+	 */
821
+	protected static function isRepresentableInJson($data)
822
+	{
823
+		return is_scalar($data)
824
+			   || is_array($data)
825
+			   || is_null($data);
826
+	}
827 827
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -10,7 +10,7 @@  discard block
 block discarded – undo
10 10
 use EE_Serialized_Text_Field;
11 11
 use EEM_Base;
12 12
 
13
-if (! defined('EVENT_ESPRESSO_VERSION')) {
13
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
14 14
     exit('No direct script access allowed');
15 15
 }
16 16
 
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
                     '0',
179 179
                     STR_PAD_LEFT
180 180
                 );
181
-            $new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
181
+            $new_value = rest_parse_date($original_value.$offset_sign.$offset_string);
182 182
         } else {
183 183
             $new_value = $original_value;
184 184
         }
@@ -226,10 +226,10 @@  discard block
 block discarded – undo
226 226
      */
227 227
     private static function parseTimezoneOffset($timezone_offset)
228 228
     {
229
-        $first_char = substr((string)$timezone_offset, 0, 1);
229
+        $first_char = substr((string) $timezone_offset, 0, 1);
230 230
         if ($first_char === '+' || $first_char === '-') {
231 231
             $offset_sign = $first_char;
232
-            $offset_secs = substr((string)$timezone_offset, 1);
232
+            $offset_secs = substr((string) $timezone_offset, 1);
233 233
         } else {
234 234
             $offset_sign = '+';
235 235
             $offset_secs = $timezone_offset;
@@ -256,12 +256,12 @@  discard block
 block discarded – undo
256 256
                 //did they submit a string of a unix timestamp?
257 257
                 if (is_numeric($original_value)) {
258 258
                     $datetime_obj = new \DateTime();
259
-                    $datetime_obj->setTimestamp((int)$original_value);
259
+                    $datetime_obj->setTimestamp((int) $original_value);
260 260
                 } else {
261 261
                     //first, check if its a MySQL timestamp in GMT
262 262
                     $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
263 263
                 }
264
-                if (! $datetime_obj instanceof \DateTime) {
264
+                if ( ! $datetime_obj instanceof \DateTime) {
265 265
                     //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
266 266
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
267 267
                 }
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
                 $new_value = $original_value->format('Y-m-d H:i:s');
272 272
             } elseif (is_int($original_value) || is_float($original_value)) {
273 273
                 $new_value = date('Y-m-d H:i:s', $original_value);
274
-            } elseif($original_value === null || $original_value === '') {
274
+            } elseif ($original_value === null || $original_value === '') {
275 275
                 $new_value = null;
276 276
             } else {
277 277
                 //so it's not a datetime object, unix timestamp (as string or int),
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
                         $original_value,
288 288
                         $field_obj->get_name(),
289 289
                         $field_obj->get_model_name(),
290
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
290
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
291 291
                     )
292 292
                 );
293 293
             }
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
         }
298 298
         //are we about to send an object? just don't. We have no good way to represent it in JSON.
299 299
         // can't just check using is_object() because that missed PHP incomplete objects
300
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
300
+        if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) {
301 301
             $new_value = array(
302 302
                 'error_code' => 'php_object_not_return',
303 303
                 'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
@@ -347,7 +347,7 @@  discard block
 block discarded – undo
347 347
                 $model
348 348
             );
349 349
             //double-check is it a *_gmt field?
350
-            if (! $field instanceof EE_Model_Field_Base
350
+            if ( ! $field instanceof EE_Model_Field_Base
351 351
                 && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
352 352
             ) {
353 353
                 //yep, take off '_gmt', and find the field
@@ -366,8 +366,8 @@  discard block
 block discarded – undo
366 366
                 $timezone = $model->get_timezone();
367 367
             }
368 368
             if ($field instanceof EE_Model_Field_Base) {
369
-                if (! $writing && is_array($query_param_value)) {
370
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
369
+                if ( ! $writing && is_array($query_param_value)) {
370
+                    if ( ! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
371 371
                         if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
372 372
                             throw new RestException(
373 373
                                 'numerically_indexed_array_of_values_only',
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
                             );
403 403
                         } elseif (array_key_exists($op, $model->valid_between_style_operators())
404 404
                             && isset($query_param_value[1], $query_param_value[2])
405
-                            && !isset($query_param_value[3])
405
+                            && ! isset($query_param_value[3])
406 406
                         ) {
407 407
                             $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
408 408
                                 $field,
@@ -426,10 +426,10 @@  discard block
 block discarded – undo
426 426
                             ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
427 427
                             $translated_value[] = $query_param_value[1];
428 428
                         } elseif (array_key_exists($op, $model->valid_null_style_operators())
429
-                            && !isset($query_param_value[1])) {
429
+                            && ! isset($query_param_value[1])) {
430 430
                             //no arguments should have been provided, so don't look for any
431 431
                         } elseif (isset($query_param_value[1])
432
-                            && !isset($query_param_value[2])
432
+                            && ! isset($query_param_value[2])
433 433
                             && ! array_key_exists(
434 434
                                 $op,
435 435
                                 array_merge(
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
      */
581 581
     public static function removeGmtFromFieldName($field_name)
582 582
     {
583
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
583
+        if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) {
584 584
             return $field_name;
585 585
         }
586 586
         $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
Please login to merge, or discard this patch.
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 3 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -569,6 +569,7 @@
 block discarded – undo
569 569
      * @param EE_Registration $registration
570 570
      * @param EE_Question     $question
571 571
      * @param                 mixed EE_Answer|NULL      $answer
572
+     * @param EE_Answer $answer
572 573
      * @return EE_Form_Input_Base
573 574
      * @throws \EE_Error
574 575
      */
Please login to merge, or discard this patch.
Indentation   +1311 added lines, -1311 removed lines patch added patch discarded remove patch
@@ -16,1319 +16,1319 @@
 block discarded – undo
16 16
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
17 17
 {
18 18
 
19
-    /**
20
-     * @type bool $_print_copy_info
21
-     */
22
-    private $_print_copy_info = false;
23
-
24
-    /**
25
-     * @type array $_attendee_data
26
-     */
27
-    private $_attendee_data = array();
28
-
29
-    /**
30
-     * @type array $_required_questions
31
-     */
32
-    private $_required_questions = array();
33
-
34
-    /**
35
-     * @type array $_registration_answers
36
-     */
37
-    private $_registration_answers = array();
38
-
39
-
40
-    /**
41
-     *    class constructor
42
-     *
43
-     * @access    public
44
-     * @param    EE_Checkout $checkout
45
-     */
46
-    public function __construct(EE_Checkout $checkout)
47
-    {
48
-        $this->_slug     = 'attendee_information';
49
-        $this->_name     = esc_html__('Attendee Information', 'event_espresso');
50
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
51
-        $this->checkout  = $checkout;
52
-        $this->_reset_success_message();
53
-        $this->set_instructions(
54
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
55
-        );
56
-    }
57
-
58
-
59
-    public function translate_js_strings()
60
-    {
61
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
62
-            ' is a required question.',
63
-            'event_espresso'
64
-        );
65
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
66
-            ' is a required question. Please enter a value for at least one of the options.',
67
-            'event_espresso'
68
-        );
69
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
70
-            'Please answer all required questions correctly before proceeding.',
71
-            'event_espresso'
72
-        );
73
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
74
-            esc_html__(
75
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
76
-                'event_espresso'
77
-            ),
78
-            '<br/>'
79
-        );
80
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
81
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
82
-            'event_espresso'
83
-        );
84
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
85
-            'You must enter a valid email address.',
86
-            'event_espresso'
87
-        );
88
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
89
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
90
-            'event_espresso'
91
-        );
92
-    }
93
-
94
-
95
-    public function enqueue_styles_and_scripts()
96
-    {
97
-    }
98
-
99
-
100
-    /**
101
-     * @return boolean
102
-     */
103
-    public function initialize_reg_step()
104
-    {
105
-        return true;
106
-    }
107
-
108
-
109
-    /**
110
-     * @return EE_Form_Section_Proper
111
-     * @throws EE_Error
112
-     * @throws InvalidArgumentException
113
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
114
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
115
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
116
-     */
117
-    public function generate_reg_form()
118
-    {
119
-        $this->_print_copy_info = false;
120
-        $primary_registrant     = null;
121
-        // autoload Line_Item_Display classes
122
-        EEH_Autoloader::register_line_item_display_autoloaders();
123
-        $Line_Item_Display = new EE_Line_Item_Display();
124
-        // calculate taxes
125
-        $Line_Item_Display->display_line_item(
126
-            $this->checkout->cart->get_grand_total(),
127
-            array('set_tax_rate' => true)
128
-        );
129
-        /** @var $subsections EE_Form_Section_Proper[] */
130
-        $subsections   = array(
131
-            'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
132
-        );
133
-        $template_args = array(
134
-            'revisit'       => $this->checkout->revisit,
135
-            'registrations' => array(),
136
-            'ticket_count'  => array(),
137
-        );
138
-        // grab the saved registrations from the transaction
139
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
140
-        if ($registrations) {
141
-            foreach ($registrations as $registration) {
142
-                // can this registration be processed during this visit ?
143
-                if ($registration instanceof EE_Registration
144
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
145
-                ) {
146
-                    $subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
147
-                    if (! $this->checkout->admin_request) {
148
-                        $template_args['registrations'][$registration->reg_url_link()]    = $registration;
149
-                        $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
150
-                            $template_args['ticket_count'][$registration->ticket()->ID()]
151
-                        )
152
-                            ? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
153
-                            : 1;
154
-                        $ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
155
-                            $this->checkout->cart->get_grand_total(),
156
-                            'Ticket',
157
-                            array($registration->ticket()->ID())
158
-                        );
159
-                        $ticket_line_item = is_array($ticket_line_item)
160
-                            ? reset($ticket_line_item)
161
-                            : $ticket_line_item;
162
-                        $template_args['ticket_line_item'][$registration->ticket()->ID()] =
163
-                            $Line_Item_Display->display_line_item($ticket_line_item);
164
-                    }
165
-                    if ($registration->is_primary_registrant()) {
166
-                        $primary_registrant = $registration->reg_url_link();
167
-                    }
168
-                }
169
-            }
170
-            // print_copy_info ?
171
-            if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
172
-                // TODO: add admin option for toggling copy attendee info,
173
-                // then use that value to change $this->_print_copy_info
174
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
175
-                    ? $this->_copy_attendee_info_form()
176
-                    : $this->_auto_copy_attendee_info();
177
-                // generate hidden input
178
-                if (isset($subsections[$primary_registrant])
179
-                    && $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
180
-                ) {
181
-                    $subsections[$primary_registrant]->add_subsections(
182
-                        $copy_options,
183
-                        'primary_registrant',
184
-                        false
185
-                    );
186
-                }
187
-            }
188
-        }
189
-
190
-        return new EE_Form_Section_Proper(
191
-            array(
192
-                'name'            => $this->reg_form_name(),
193
-                'html_id'         => $this->reg_form_name(),
194
-                'subsections'     => $subsections,
195
-                'layout_strategy' => $this->checkout->admin_request ?
196
-                    new EE_Div_Per_Section_Layout() :
197
-                    new EE_Template_Layout(
198
-                        array(
199
-                            'layout_template_file' => $this->_template, // layout_template
200
-                            'template_args'        => $template_args,
201
-                        )
202
-                    ),
203
-            )
204
-        );
205
-    }
206
-
207
-
208
-    /**
209
-     * @param EE_Registration $registration
210
-     * @return EE_Form_Section_Base
211
-     * @throws EE_Error
212
-     * @throws InvalidArgumentException
213
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
214
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
215
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
216
-     */
217
-    private function _registrations_reg_form(EE_Registration $registration)
218
-    {
219
-        static $attendee_nmbr = 1;
220
-        $form_args = array();
221
-        // verify that registration has valid event
222
-        if ($registration->event() instanceof EE_Event) {
223
-            $question_groups = $registration->event()->question_groups(
224
-                array(
225
-                    array(
226
-                        'Event.EVT_ID'                     => $registration->event()->ID(),
227
-                        'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
228
-                    ),
229
-                    'order_by' => array('QSG_order' => 'ASC'),
230
-                )
231
-            );
232
-            if ($question_groups) {
233
-                // array of params to pass to parent constructor
234
-                $form_args = array(
235
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
236
-                    'html_class'      => 'ee-reg-form-attendee-dv',
237
-                    'html_style'      => $this->checkout->admin_request
238
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
239
-                        : '',
240
-                    'subsections'     => array(),
241
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
242
-                        array(
243
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
244
-                            'legend_text'  => sprintf(__('Attendee %d', 'event_espresso'), $attendee_nmbr),
245
-                        )
246
-                    ),
247
-                );
248
-                foreach ($question_groups as $question_group) {
249
-                    if ($question_group instanceof EE_Question_Group) {
250
-                        $form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
251
-                            $registration,
252
-                            $question_group
253
-                        );
254
-                    }
255
-                }
256
-                // add hidden input
257
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
258
-                    $registration
259
-                );
260
-                // if we have question groups for additional attendees, then display the copy options
261
-                $this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
262
-                if ($registration->is_primary_registrant()) {
263
-                    // generate hidden input
264
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
265
-                        $registration
266
-                    );
267
-                }
268
-            }
269
-        }
270
-        $attendee_nmbr++;
271
-        return ! empty($form_args) ? new EE_Form_Section_Proper($form_args) : new EE_Form_Section_HTML();
272
-    }
273
-
274
-
275
-    /**
276
-     * _additional_attendee_reg_info_input
277
-     *
278
-     * @access public
279
-     * @param EE_Registration $registration
280
-     * @param bool            $additional_attendee_reg_info
281
-     * @return    EE_Form_Input_Base
282
-     * @throws \EE_Error
283
-     */
284
-    private function _additional_attendee_reg_info_input(
285
-        EE_Registration $registration,
286
-        $additional_attendee_reg_info = true
287
-    ) {
288
-        // generate hidden input
289
-        return new EE_Hidden_Input(
290
-            array(
291
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
292
-                'default' => $additional_attendee_reg_info,
293
-            )
294
-        );
295
-    }
296
-
297
-
298
-    /**
299
-     * @param EE_Registration   $registration
300
-     * @param EE_Question_Group $question_group
301
-     * @return EE_Form_Section_Proper
302
-     * @throws EE_Error
303
-     * @throws InvalidArgumentException
304
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
305
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
306
-     */
307
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
308
-    {
309
-        // array of params to pass to parent constructor
310
-        $form_args = array(
311
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier(),
312
-            'html_class'      => $this->checkout->admin_request
313
-                ? 'form-table ee-reg-form-qstn-grp-dv'
314
-                : 'ee-reg-form-qstn-grp-dv',
315
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-lbl',
316
-            'subsections'     => array(
317
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
318
-            ),
319
-            'layout_strategy' => $this->checkout->admin_request
320
-                ? new EE_Admin_Two_Column_Layout()
321
-                : new EE_Div_Per_Section_Layout(),
322
-        );
323
-        // where params
324
-        $query_params = array('QST_deleted' => 0);
325
-        // don't load admin only questions on the frontend
326
-        if (! $this->checkout->admin_request) {
327
-            $query_params['QST_admin_only'] = array('!=', true);
328
-        }
329
-        $questions = $question_group->get_many_related(
330
-            'Question',
331
-            apply_filters(
332
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
333
-                array(
334
-                    $query_params,
335
-                    'order_by' => array(
336
-                        'Question_Group_Question.QGQ_order' => 'ASC',
337
-                    ),
338
-                ),
339
-                $question_group,
340
-                $registration,
341
-                $this
342
-            )
343
-        );
344
-        // filter for additional content before questions
345
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
346
-            apply_filters(
347
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
348
-                '',
349
-                $registration,
350
-                $question_group,
351
-                $this
352
-            )
353
-        );
354
-        // loop thru questions
355
-        foreach ($questions as $question) {
356
-            if ($question instanceof EE_Question) {
357
-                $identifier                            = $question->is_system_question()
358
-                    ? $question->system_ID()
359
-                    : $question->ID();
360
-                $form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
361
-            }
362
-        }
363
-        $form_args['subsections'] = apply_filters(
364
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
365
-            $form_args['subsections'],
366
-            $registration,
367
-            $question_group,
368
-            $this
369
-        );
370
-        // filter for additional content after questions
371
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
372
-            apply_filters(
373
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
374
-                '',
375
-                $registration,
376
-                $question_group,
377
-                $this
378
-            )
379
-        );
19
+	/**
20
+	 * @type bool $_print_copy_info
21
+	 */
22
+	private $_print_copy_info = false;
23
+
24
+	/**
25
+	 * @type array $_attendee_data
26
+	 */
27
+	private $_attendee_data = array();
28
+
29
+	/**
30
+	 * @type array $_required_questions
31
+	 */
32
+	private $_required_questions = array();
33
+
34
+	/**
35
+	 * @type array $_registration_answers
36
+	 */
37
+	private $_registration_answers = array();
38
+
39
+
40
+	/**
41
+	 *    class constructor
42
+	 *
43
+	 * @access    public
44
+	 * @param    EE_Checkout $checkout
45
+	 */
46
+	public function __construct(EE_Checkout $checkout)
47
+	{
48
+		$this->_slug     = 'attendee_information';
49
+		$this->_name     = esc_html__('Attendee Information', 'event_espresso');
50
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
51
+		$this->checkout  = $checkout;
52
+		$this->_reset_success_message();
53
+		$this->set_instructions(
54
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
55
+		);
56
+	}
57
+
58
+
59
+	public function translate_js_strings()
60
+	{
61
+		EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
62
+			' is a required question.',
63
+			'event_espresso'
64
+		);
65
+		EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
66
+			' is a required question. Please enter a value for at least one of the options.',
67
+			'event_espresso'
68
+		);
69
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
70
+			'Please answer all required questions correctly before proceeding.',
71
+			'event_espresso'
72
+		);
73
+		EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
74
+			esc_html__(
75
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
76
+				'event_espresso'
77
+			),
78
+			'<br/>'
79
+		);
80
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
81
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
82
+			'event_espresso'
83
+		);
84
+		EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
85
+			'You must enter a valid email address.',
86
+			'event_espresso'
87
+		);
88
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
89
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
90
+			'event_espresso'
91
+		);
92
+	}
93
+
94
+
95
+	public function enqueue_styles_and_scripts()
96
+	{
97
+	}
98
+
99
+
100
+	/**
101
+	 * @return boolean
102
+	 */
103
+	public function initialize_reg_step()
104
+	{
105
+		return true;
106
+	}
107
+
108
+
109
+	/**
110
+	 * @return EE_Form_Section_Proper
111
+	 * @throws EE_Error
112
+	 * @throws InvalidArgumentException
113
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
114
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
115
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
116
+	 */
117
+	public function generate_reg_form()
118
+	{
119
+		$this->_print_copy_info = false;
120
+		$primary_registrant     = null;
121
+		// autoload Line_Item_Display classes
122
+		EEH_Autoloader::register_line_item_display_autoloaders();
123
+		$Line_Item_Display = new EE_Line_Item_Display();
124
+		// calculate taxes
125
+		$Line_Item_Display->display_line_item(
126
+			$this->checkout->cart->get_grand_total(),
127
+			array('set_tax_rate' => true)
128
+		);
129
+		/** @var $subsections EE_Form_Section_Proper[] */
130
+		$subsections   = array(
131
+			'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
132
+		);
133
+		$template_args = array(
134
+			'revisit'       => $this->checkout->revisit,
135
+			'registrations' => array(),
136
+			'ticket_count'  => array(),
137
+		);
138
+		// grab the saved registrations from the transaction
139
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
140
+		if ($registrations) {
141
+			foreach ($registrations as $registration) {
142
+				// can this registration be processed during this visit ?
143
+				if ($registration instanceof EE_Registration
144
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
145
+				) {
146
+					$subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
147
+					if (! $this->checkout->admin_request) {
148
+						$template_args['registrations'][$registration->reg_url_link()]    = $registration;
149
+						$template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
150
+							$template_args['ticket_count'][$registration->ticket()->ID()]
151
+						)
152
+							? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
153
+							: 1;
154
+						$ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
155
+							$this->checkout->cart->get_grand_total(),
156
+							'Ticket',
157
+							array($registration->ticket()->ID())
158
+						);
159
+						$ticket_line_item = is_array($ticket_line_item)
160
+							? reset($ticket_line_item)
161
+							: $ticket_line_item;
162
+						$template_args['ticket_line_item'][$registration->ticket()->ID()] =
163
+							$Line_Item_Display->display_line_item($ticket_line_item);
164
+					}
165
+					if ($registration->is_primary_registrant()) {
166
+						$primary_registrant = $registration->reg_url_link();
167
+					}
168
+				}
169
+			}
170
+			// print_copy_info ?
171
+			if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
172
+				// TODO: add admin option for toggling copy attendee info,
173
+				// then use that value to change $this->_print_copy_info
174
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
175
+					? $this->_copy_attendee_info_form()
176
+					: $this->_auto_copy_attendee_info();
177
+				// generate hidden input
178
+				if (isset($subsections[$primary_registrant])
179
+					&& $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
180
+				) {
181
+					$subsections[$primary_registrant]->add_subsections(
182
+						$copy_options,
183
+						'primary_registrant',
184
+						false
185
+					);
186
+				}
187
+			}
188
+		}
189
+
190
+		return new EE_Form_Section_Proper(
191
+			array(
192
+				'name'            => $this->reg_form_name(),
193
+				'html_id'         => $this->reg_form_name(),
194
+				'subsections'     => $subsections,
195
+				'layout_strategy' => $this->checkout->admin_request ?
196
+					new EE_Div_Per_Section_Layout() :
197
+					new EE_Template_Layout(
198
+						array(
199
+							'layout_template_file' => $this->_template, // layout_template
200
+							'template_args'        => $template_args,
201
+						)
202
+					),
203
+			)
204
+		);
205
+	}
206
+
207
+
208
+	/**
209
+	 * @param EE_Registration $registration
210
+	 * @return EE_Form_Section_Base
211
+	 * @throws EE_Error
212
+	 * @throws InvalidArgumentException
213
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
214
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
215
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
216
+	 */
217
+	private function _registrations_reg_form(EE_Registration $registration)
218
+	{
219
+		static $attendee_nmbr = 1;
220
+		$form_args = array();
221
+		// verify that registration has valid event
222
+		if ($registration->event() instanceof EE_Event) {
223
+			$question_groups = $registration->event()->question_groups(
224
+				array(
225
+					array(
226
+						'Event.EVT_ID'                     => $registration->event()->ID(),
227
+						'Event_Question_Group.EQG_primary' => $registration->count() === 1 ? true : false,
228
+					),
229
+					'order_by' => array('QSG_order' => 'ASC'),
230
+				)
231
+			);
232
+			if ($question_groups) {
233
+				// array of params to pass to parent constructor
234
+				$form_args = array(
235
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
236
+					'html_class'      => 'ee-reg-form-attendee-dv',
237
+					'html_style'      => $this->checkout->admin_request
238
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
239
+						: '',
240
+					'subsections'     => array(),
241
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
242
+						array(
243
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
244
+							'legend_text'  => sprintf(__('Attendee %d', 'event_espresso'), $attendee_nmbr),
245
+						)
246
+					),
247
+				);
248
+				foreach ($question_groups as $question_group) {
249
+					if ($question_group instanceof EE_Question_Group) {
250
+						$form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
251
+							$registration,
252
+							$question_group
253
+						);
254
+					}
255
+				}
256
+				// add hidden input
257
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
258
+					$registration
259
+				);
260
+				// if we have question groups for additional attendees, then display the copy options
261
+				$this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
262
+				if ($registration->is_primary_registrant()) {
263
+					// generate hidden input
264
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
265
+						$registration
266
+					);
267
+				}
268
+			}
269
+		}
270
+		$attendee_nmbr++;
271
+		return ! empty($form_args) ? new EE_Form_Section_Proper($form_args) : new EE_Form_Section_HTML();
272
+	}
273
+
274
+
275
+	/**
276
+	 * _additional_attendee_reg_info_input
277
+	 *
278
+	 * @access public
279
+	 * @param EE_Registration $registration
280
+	 * @param bool            $additional_attendee_reg_info
281
+	 * @return    EE_Form_Input_Base
282
+	 * @throws \EE_Error
283
+	 */
284
+	private function _additional_attendee_reg_info_input(
285
+		EE_Registration $registration,
286
+		$additional_attendee_reg_info = true
287
+	) {
288
+		// generate hidden input
289
+		return new EE_Hidden_Input(
290
+			array(
291
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
292
+				'default' => $additional_attendee_reg_info,
293
+			)
294
+		);
295
+	}
296
+
297
+
298
+	/**
299
+	 * @param EE_Registration   $registration
300
+	 * @param EE_Question_Group $question_group
301
+	 * @return EE_Form_Section_Proper
302
+	 * @throws EE_Error
303
+	 * @throws InvalidArgumentException
304
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
305
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
306
+	 */
307
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
308
+	{
309
+		// array of params to pass to parent constructor
310
+		$form_args = array(
311
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier(),
312
+			'html_class'      => $this->checkout->admin_request
313
+				? 'form-table ee-reg-form-qstn-grp-dv'
314
+				: 'ee-reg-form-qstn-grp-dv',
315
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-lbl',
316
+			'subsections'     => array(
317
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
318
+			),
319
+			'layout_strategy' => $this->checkout->admin_request
320
+				? new EE_Admin_Two_Column_Layout()
321
+				: new EE_Div_Per_Section_Layout(),
322
+		);
323
+		// where params
324
+		$query_params = array('QST_deleted' => 0);
325
+		// don't load admin only questions on the frontend
326
+		if (! $this->checkout->admin_request) {
327
+			$query_params['QST_admin_only'] = array('!=', true);
328
+		}
329
+		$questions = $question_group->get_many_related(
330
+			'Question',
331
+			apply_filters(
332
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
333
+				array(
334
+					$query_params,
335
+					'order_by' => array(
336
+						'Question_Group_Question.QGQ_order' => 'ASC',
337
+					),
338
+				),
339
+				$question_group,
340
+				$registration,
341
+				$this
342
+			)
343
+		);
344
+		// filter for additional content before questions
345
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
346
+			apply_filters(
347
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
348
+				'',
349
+				$registration,
350
+				$question_group,
351
+				$this
352
+			)
353
+		);
354
+		// loop thru questions
355
+		foreach ($questions as $question) {
356
+			if ($question instanceof EE_Question) {
357
+				$identifier                            = $question->is_system_question()
358
+					? $question->system_ID()
359
+					: $question->ID();
360
+				$form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
361
+			}
362
+		}
363
+		$form_args['subsections'] = apply_filters(
364
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
365
+			$form_args['subsections'],
366
+			$registration,
367
+			$question_group,
368
+			$this
369
+		);
370
+		// filter for additional content after questions
371
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
372
+			apply_filters(
373
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
374
+				'',
375
+				$registration,
376
+				$question_group,
377
+				$this
378
+			)
379
+		);
380 380
 //		d( $form_args );
381
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
382
-        return apply_filters(
383
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
384
-            $question_group_reg_form,
385
-            $registration,
386
-            $question_group,
387
-            $this
388
-        );
389
-    }
390
-
391
-
392
-    /**
393
-     * @access public
394
-     * @param EE_Question_Group $question_group
395
-     * @return    EE_Form_Section_HTML
396
-     */
397
-    private function _question_group_header(EE_Question_Group $question_group)
398
-    {
399
-        $html = '';
400
-        // group_name
401
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
402
-            if ($this->checkout->admin_request) {
403
-                $html .= EEH_HTML::br();
404
-                $html .= EEH_HTML::h3(
405
-                    $question_group->name(),
406
-                    '',
407
-                    'ee-reg-form-qstn-grp-title title',
408
-                    'font-size: 1.3em; padding-left:0;'
409
-                );
410
-            } else {
411
-                $html .= EEH_HTML::h4(
412
-                    $question_group->name(),
413
-                    '',
414
-                    'ee-reg-form-qstn-grp-title section-title'
415
-                );
416
-            }
417
-        }
418
-        // group_desc
419
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
420
-            $html .= EEH_HTML::p(
421
-                $question_group->desc(),
422
-                '',
423
-                $this->checkout->admin_request
424
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
425
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
426
-            );
427
-        }
428
-        return new EE_Form_Section_HTML($html);
429
-    }
430
-
431
-
432
-    /**
433
-     * @access public
434
-     * @return    EE_Form_Section_Proper
435
-     * @throws \EE_Error
436
-     */
437
-    private function _copy_attendee_info_form()
438
-    {
439
-        // array of params to pass to parent constructor
440
-        return new EE_Form_Section_Proper(
441
-            array(
442
-                'subsections'     => $this->_copy_attendee_info_inputs(),
443
-                'layout_strategy' => new EE_Template_Layout(
444
-                    array(
445
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
446
-                                                      . $this->_slug
447
-                                                      . DS
448
-                                                      . 'copy_attendee_info.template.php',
449
-                        'begin_template_file'      => null,
450
-                        'input_template_file'      => null,
451
-                        'subsection_template_file' => null,
452
-                        'end_template_file'        => null,
453
-                    )
454
-                ),
455
-            )
456
-        );
457
-    }
458
-
459
-
460
-    /**
461
-     * _auto_copy_attendee_info
462
-     *
463
-     * @access public
464
-     * @return EE_Form_Section_HTML
465
-     */
466
-    private function _auto_copy_attendee_info()
467
-    {
468
-        return new EE_Form_Section_HTML(
469
-            EEH_Template::locate_template(
470
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
471
-                apply_filters(
472
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
473
-                    array()
474
-                ),
475
-                true,
476
-                true
477
-            )
478
-        );
479
-    }
480
-
481
-
482
-    /**
483
-     * _copy_attendee_info_inputs
484
-     *
485
-     * @access public
486
-     * @return array
487
-     * @throws \EE_Error
488
-     */
489
-    private function _copy_attendee_info_inputs()
490
-    {
491
-        $copy_attendee_info_inputs = array();
492
-        $prev_ticket               = null;
493
-        // grab the saved registrations from the transaction
494
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
495
-        foreach ($registrations as $registration) {
496
-            // for all  attendees other than the primary attendee
497
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
498
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
499
-                if ($registration->ticket()->ID() !== $prev_ticket) {
500
-                    $item_name = $registration->ticket()->name();
501
-                    $item_name .= $registration->ticket()->description() !== ''
502
-                        ? ' - ' . $registration->ticket()->description()
503
-                        : '';
504
-                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
505
-                        new EE_Form_Section_HTML(
506
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
507
-                        );
508
-                    $prev_ticket = $registration->ticket()->ID();
509
-                }
510
-
511
-                $copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
512
-                    new EE_Checkbox_Multi_Input(
513
-                        array(
514
-                            $registration->ID() => sprintf(
515
-                                esc_html__('Attendee #%s', 'event_espresso'),
516
-                                $registration->count()
517
-                            ),
518
-                        ),
519
-                        array(
520
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
521
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
522
-                            'display_html_label_text' => false,
523
-                        )
524
-                    );
525
-            }
526
-        }
527
-        return $copy_attendee_info_inputs;
528
-    }
529
-
530
-
531
-    /**
532
-     * _additional_primary_registrant_inputs
533
-     *
534
-     * @access public
535
-     * @param EE_Registration $registration
536
-     * @return    EE_Form_Input_Base
537
-     * @throws \EE_Error
538
-     */
539
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
540
-    {
541
-        // generate hidden input
542
-        return new EE_Hidden_Input(
543
-            array(
544
-                'html_id' => 'primary_registrant',
545
-                'default' => $registration->reg_url_link(),
546
-            )
547
-        );
548
-    }
549
-
550
-
551
-    /**
552
-     * @access public
553
-     * @param EE_Registration $registration
554
-     * @param EE_Question     $question
555
-     * @return EE_Form_Input_Base
556
-     * @throws EE_Error
557
-     * @throws InvalidArgumentException
558
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
559
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
560
-     */
561
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
562
-    {
563
-
564
-        // if this question was for an attendee detail, then check for that answer
565
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
566
-            $registration,
567
-            $question->system_ID()
568
-        );
569
-        $answer       = $answer_value === null
570
-            ? EEM_Answer::instance()->get_one(
571
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
572
-            )
573
-            : null;
574
-        // if NOT returning to edit an existing registration
575
-        // OR if this question is for an attendee property
576
-        // OR we still don't have an EE_Answer object
577
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
578
-            // create an EE_Answer object for storing everything in
579
-            $answer = EE_Answer::new_instance(array(
580
-                'QST_ID' => $question->ID(),
581
-                'REG_ID' => $registration->ID(),
582
-            ));
583
-        }
584
-        // verify instance
585
-        if ($answer instanceof EE_Answer) {
586
-            if (! empty($answer_value)) {
587
-                $answer->set('ANS_value', $answer_value);
588
-            }
589
-            $answer->cache('Question', $question);
590
-            //remember system ID had a bug where sometimes it could be null
591
-            $answer_cache_id = $question->is_system_question()
592
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
593
-                : $question->ID() . '-' . $registration->reg_url_link();
594
-            $registration->cache('Answer', $answer, $answer_cache_id);
595
-        }
596
-        return $this->_generate_question_input($registration, $question, $answer);
597
-    }
598
-
599
-
600
-    /**
601
-     * @param EE_Registration $registration
602
-     * @param EE_Question     $question
603
-     * @param                 mixed EE_Answer|NULL      $answer
604
-     * @return EE_Form_Input_Base
605
-     * @throws \EE_Error
606
-     */
607
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
608
-    {
609
-        $identifier                             = $question->is_system_question()
610
-            ? $question->system_ID()
611
-            : $question->ID();
612
-        $this->_required_questions[$identifier] = $question->required() ? true : false;
613
-        add_filter(
614
-            'FHEE__EE_Question__generate_form_input__country_options',
615
-            array($this, 'use_cached_countries_for_form_input'),
616
-            10,
617
-            4
618
-        );
619
-        add_filter(
620
-            'FHEE__EE_Question__generate_form_input__state_options',
621
-            array($this, 'use_cached_states_for_form_input'),
622
-            10,
623
-            4
624
-        );
625
-        $input_constructor_args                  = array(
626
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
627
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
628
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
629
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
630
-            'html_label_class' => 'ee-reg-qstn',
631
-        );
632
-        $input_constructor_args['html_label_id'] .= '-lbl';
633
-        if ($answer instanceof EE_Answer && $answer->ID()) {
634
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
635
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
636
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
637
-        }
638
-        $form_input = $question->generate_form_input(
639
-            $registration,
640
-            $answer,
641
-            $input_constructor_args
642
-        );
643
-        remove_filter(
644
-            'FHEE__EE_Question__generate_form_input__country_options',
645
-            array($this, 'use_cached_countries_for_form_input')
646
-        );
647
-        remove_filter(
648
-            'FHEE__EE_Question__generate_form_input__state_options',
649
-            array($this, 'use_cached_states_for_form_input')
650
-        );
651
-        return $form_input;
652
-    }
653
-
654
-
655
-    /**
656
-     * Gets the list of countries for the form input
657
-     *
658
-     * @param array|null       $countries_list
659
-     * @param \EE_Question     $question
660
-     * @param \EE_Registration $registration
661
-     * @param \EE_Answer       $answer
662
-     * @return array 2d keys are country IDs, values are their names
663
-     * @throws EE_Error
664
-     * @throws InvalidArgumentException
665
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
666
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
667
-     */
668
-    public function use_cached_countries_for_form_input(
669
-        $countries_list,
670
-        \EE_Question $question = null,
671
-        \EE_Registration $registration = null,
672
-        \EE_Answer $answer = null
673
-    ) {
674
-        $country_options = array('' => '');
675
-        // get possibly cached list of countries
676
-        $countries = $this->checkout->action === 'process_reg_step'
677
-            ? EEM_Country::instance()->get_all_countries()
678
-            : EEM_Country::instance()->get_all_active_countries();
679
-        if (! empty($countries)) {
680
-            foreach ($countries as $country) {
681
-                if ($country instanceof EE_Country) {
682
-                    $country_options[$country->ID()] = $country->name();
683
-                }
684
-            }
685
-        }
686
-        if ($question instanceof EE_Question
687
-            && $registration instanceof EE_Registration) {
688
-            $answer = EEM_Answer::instance()->get_one(
689
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
690
-            );
691
-        } else {
692
-            $answer = EE_Answer::new_instance();
693
-        }
694
-        $country_options = apply_filters(
695
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
696
-            $country_options,
697
-            $this,
698
-            $registration,
699
-            $question,
700
-            $answer
701
-        );
702
-        return $country_options;
703
-    }
704
-
705
-
706
-    /**
707
-     * Gets the list of states for the form input
708
-     *
709
-     * @param array|null       $states_list
710
-     * @param \EE_Question     $question
711
-     * @param \EE_Registration $registration
712
-     * @param \EE_Answer       $answer
713
-     * @return array 2d keys are state IDs, values are their names
714
-     * @throws EE_Error
715
-     * @throws InvalidArgumentException
716
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
717
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
718
-     */
719
-    public function use_cached_states_for_form_input(
720
-        $states_list,
721
-        \EE_Question $question = null,
722
-        \EE_Registration $registration = null,
723
-        \EE_Answer $answer = null
724
-    ) {
725
-        $state_options = array('' => array('' => ''));
726
-        $states        = $this->checkout->action === 'process_reg_step'
727
-            ? EEM_State::instance()->get_all_states()
728
-            : EEM_State::instance()->get_all_active_states();
729
-        if (! empty($states)) {
730
-            foreach ($states as $state) {
731
-                if ($state instanceof EE_State) {
732
-                    $state_options[$state->country()->name()][$state->ID()] = $state->name();
733
-                }
734
-            }
735
-        }
736
-        $state_options = apply_filters(
737
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
738
-            $state_options,
739
-            $this,
740
-            $registration,
741
-            $question,
742
-            $answer
743
-        );
744
-        return $state_options;
745
-    }
746
-
747
-
748
-
749
-
750
-
751
-
752
-    /********************************************************************************************************/
753
-    /****************************************  PROCESS REG STEP  ****************************************/
754
-    /********************************************************************************************************/
755
-    /**
756
-     * @return bool
757
-     * @throws EE_Error
758
-     * @throws InvalidArgumentException
759
-     * @throws ReflectionException
760
-     * @throws RuntimeException
761
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
762
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
763
-     */
764
-    public function process_reg_step()
765
-    {
766
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
767
-        // grab validated data from form
768
-        $valid_data = $this->checkout->current_step->valid_data();
769
-        // EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
770
-        // EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
771
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
772
-        if (empty($valid_data)) {
773
-            EE_Error::add_error(
774
-                esc_html__('No valid question responses were received.', 'event_espresso'),
775
-                __FILE__,
776
-                __FUNCTION__,
777
-                __LINE__
778
-            );
779
-            return false;
780
-        }
781
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
782
-            EE_Error::add_error(
783
-                esc_html__(
784
-                    'A valid transaction could not be initiated for processing your registrations.',
785
-                    'event_espresso'
786
-                ),
787
-                __FILE__,
788
-                __FUNCTION__,
789
-                __LINE__
790
-            );
791
-            return false;
792
-        }
793
-        // get cached registrations
794
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
795
-        // verify we got the goods
796
-        if (empty($registrations)) {
797
-            EE_Error::add_error(
798
-                esc_html__('Your form data could not be applied to any valid registrations.', 'event_espresso'),
799
-                __FILE__,
800
-                __FUNCTION__,
801
-                __LINE__
802
-            );
803
-            return false;
804
-        }
805
-        // extract attendee info from form data and save to model objects
806
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
807
-        // if first pass thru SPCO,
808
-        // then let's check processed registrations against the total number of tickets in the cart
809
-        if ($registrations_processed === false) {
810
-            // but return immediately if the previous step exited early due to errors
811
-            return false;
812
-        } elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
813
-            // generate a correctly translated string for all possible singular/plural combinations
814
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
815
-                $error_msg = sprintf(
816
-                    esc_html__(
817
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
818
-                        'event_espresso'
819
-                    ),
820
-                    $this->checkout->total_ticket_count,
821
-                    $registrations_processed
822
-                );
823
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
824
-                $error_msg = sprintf(
825
-                    esc_html__(
826
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
827
-                        'event_espresso'
828
-                    ),
829
-                    $this->checkout->total_ticket_count,
830
-                    $registrations_processed
831
-                );
832
-            } else {
833
-                $error_msg = sprintf(
834
-                    esc_html__(
835
-                        'There was a total of %1$d tickets in the Event Queue, but %2$ds registrations were processed',
836
-                        'event_espresso'
837
-                    ),
838
-                    $this->checkout->total_ticket_count,
839
-                    $registrations_processed
840
-                );
841
-            }
842
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
843
-            return false;
844
-        }
845
-        // mark this reg step as completed
846
-        $this->set_completed();
847
-        $this->_set_success_message(
848
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
849
-        );
850
-        //do action in case a plugin wants to do something with the data submitted in step 1.
851
-        //passes EE_Single_Page_Checkout, and it's posted data
852
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
853
-        return true;
854
-    }
855
-
856
-
857
-    /**
858
-     *    _process_registrations
859
-     *
860
-     * @param EE_Registration[] $registrations
861
-     * @param array             $valid_data
862
-     * @return bool|int
863
-     * @throws EE_Error
864
-     * @throws InvalidArgumentException
865
-     * @throws ReflectionException
866
-     * @throws RuntimeException
867
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
868
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
869
-     */
870
-    private function _process_registrations($registrations = array(), $valid_data = array())
871
-    {
872
-        // load resources and set some defaults
873
-        EE_Registry::instance()->load_model('Attendee');
874
-        // holder for primary registrant attendee object
875
-        $this->checkout->primary_attendee_obj = null;
876
-        // array for tracking reg form data for the primary registrant
877
-        $primary_registrant = array(
878
-            'line_item_id' => null,
879
-        );
880
-        $copy_primary       = false;
881
-        // reg form sections that do not contain inputs
882
-        $non_input_form_sections = array(
883
-            'primary_registrant',
884
-            'additional_attendee_reg_info',
885
-            'spco_copy_attendee_chk',
886
-        );
887
-        // attendee counter
888
-        $att_nmbr = 0;
889
-        // grab the saved registrations from the transaction
890
-        foreach ($registrations as $registration) {
891
-            // verify EE_Registration object
892
-            if (! $registration instanceof EE_Registration) {
893
-                EE_Error::add_error(
894
-                    esc_html__(
895
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
896
-                        'event_espresso'
897
-                    ),
898
-                    __FILE__,
899
-                    __FUNCTION__,
900
-                    __LINE__
901
-                );
902
-                return false;
903
-            }
904
-            /** @var string $reg_url_link */
905
-            $reg_url_link = $registration->reg_url_link();
906
-            // reg_url_link exists ?
907
-            if (! empty($reg_url_link)) {
908
-                // should this registration be processed during this visit ?
909
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
910
-                    // if NOT revisiting, then let's save the registration now,
911
-                    // so that we have a REG_ID to use when generating other objects
912
-                    if (! $this->checkout->revisit) {
913
-                        $registration->save();
914
-                    }
915
-                    /**
916
-                     * This allows plugins to trigger a fail on processing of a
917
-                     * registration for any conditions they may have for it to pass.
918
-                     *
919
-                     * @var bool   if true is returned by the plugin then the
920
-                     *            registration processing is halted.
921
-                     */
922
-                    if (apply_filters(
923
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
924
-                        false,
925
-                        $att_nmbr,
926
-                        $registration,
927
-                        $registrations,
928
-                        $valid_data,
929
-                        $this
930
-                    )) {
931
-                        return false;
932
-                    }
933
-
934
-                    // Houston, we have a registration!
935
-                    $att_nmbr++;
936
-                    $this->_attendee_data[$reg_url_link] = array();
937
-                    // grab any existing related answer objects
938
-                    $this->_registration_answers = $registration->answers();
939
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
940
-                    if (isset($valid_data[$reg_url_link])) {
941
-                        // do we need to copy basic info from primary attendee ?
942
-                        $copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
943
-                                        && absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0
944
-                            ? true
945
-                            : false;
946
-                        // filter form input data for this registration
947
-                        $valid_data[$reg_url_link] = (array)apply_filters(
948
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
949
-                            $valid_data[$reg_url_link]
950
-                        );
951
-                        if (isset($valid_data['primary_attendee'])) {
952
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
953
-                                ? $valid_data['primary_attendee']
954
-                                : false;
955
-                            unset($valid_data['primary_attendee']);
956
-                        }
957
-                        // now loop through our array of valid post data && process attendee reg forms
958
-                        foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
959
-                            if (! in_array($form_section, $non_input_form_sections)) {
960
-                                foreach ($form_inputs as $form_input => $input_value) {
961
-                                    // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
962
-                                    // check for critical inputs
963
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
964
-                                        $form_input,
965
-                                        $input_value
966
-                                    )
967
-                                    ) {
968
-                                        return false;
969
-                                    }
970
-                                    // store a bit of data about the primary attendee
971
-                                    if ($att_nmbr === 1
972
-                                        && ! empty($input_value)
973
-                                        && $reg_url_link === $primary_registrant['line_item_id']
974
-                                    ) {
975
-                                        $primary_registrant[$form_input] = $input_value;
976
-                                    } elseif ($copy_primary
977
-                                        && $input_value === null
978
-                                        && isset($primary_registrant[$form_input])
979
-                                    ) {
980
-                                        $input_value = $primary_registrant[$form_input];
981
-                                    }
982
-                                    // now attempt to save the input data
983
-                                    if (! $this->_save_registration_form_input(
984
-                                        $registration,
985
-                                        $form_input,
986
-                                        $input_value
987
-                                    )
988
-                                    ) {
989
-                                        EE_Error::add_error(
990
-                                            sprintf(
991
-                                                esc_html__(
992
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
993
-                                                    'event_espresso'
994
-                                                ),
995
-                                                $form_input,
996
-                                                $input_value
997
-                                            ),
998
-                                            __FILE__,
999
-                                            __FUNCTION__,
1000
-                                            __LINE__
1001
-                                        );
1002
-                                        return false;
1003
-                                    }
1004
-                                }
1005
-                            }
1006
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1007
-                    }
1008
-                    //EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1009
-                    // this registration does not require additional attendee information ?
1010
-                    if ($copy_primary
1011
-                        && $att_nmbr > 1
1012
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1013
-                    ) {
1014
-                        // just copy the primary registrant
1015
-                        $attendee = $this->checkout->primary_attendee_obj;
1016
-                    } else {
1017
-                        // ensure critical details are set for additional attendees
1018
-                        $this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1019
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1020
-                                $this->_attendee_data[$reg_url_link]
1021
-                            )
1022
-                            : $this->_attendee_data[$reg_url_link];
1023
-                        // execute create attendee command (which may return an existing attendee)
1024
-                        $attendee = EE_Registry::instance()->BUS->execute(
1025
-                            new CreateAttendeeCommand(
1026
-                                $this->_attendee_data[$reg_url_link],
1027
-                                $registration
1028
-                            )
1029
-                        );
1030
-                        // who's #1 ?
1031
-                        if ($att_nmbr === 1) {
1032
-                            $this->checkout->primary_attendee_obj = $attendee;
1033
-                        }
1034
-                    }
1035
-                    // EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1036
-                    // add relation to registration, set attendee ID, and cache attendee
1037
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1038
-                    // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1039
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1040
-                        EE_Error::add_error(
1041
-                            sprintf(
1042
-                                esc_html__(
1043
-                                    'Registration %s has an invalid or missing Attendee object.',
1044
-                                    'event_espresso'
1045
-                                ),
1046
-                                $reg_url_link
1047
-                            ),
1048
-                            __FILE__,
1049
-                            __FUNCTION__,
1050
-                            __LINE__
1051
-                        );
1052
-                        return false;
1053
-                    }
1054
-                    /** @type EE_Registration_Processor $registration_processor */
1055
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1056
-                    // at this point, we should have enough details about the registrant to consider the registration
1057
-                    // NOT incomplete
1058
-                    $registration_processor->toggle_incomplete_registration_status_to_default($registration, false);
1059
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1060
-                    // abandoned
1061
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1062
-                    // if we've gotten this far, then let's save what we have
1063
-                    $registration->save();
1064
-                    // add relation between TXN and registration
1065
-                    $this->_associate_registration_with_transaction($registration);
1066
-                }
1067
-            } else {
1068
-                EE_Error::add_error(
1069
-                    esc_html__(
1070
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1071
-                        'event_espresso'
1072
-                    ),
1073
-                    __FILE__,
1074
-                    __FUNCTION__,
1075
-                    __LINE__
1076
-                );
1077
-                // remove malformed data
1078
-                unset($valid_data[$reg_url_link]);
1079
-                return false;
1080
-            }
1081
-
1082
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1083
-        return $att_nmbr;
1084
-    }
1085
-
1086
-
1087
-    /**
1088
-     *    _save_registration_form_input
1089
-     *
1090
-     * @param EE_Registration $registration
1091
-     * @param string          $form_input
1092
-     * @param string          $input_value
1093
-     * @return bool
1094
-     * @throws EE_Error
1095
-     * @throws InvalidArgumentException
1096
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1097
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1098
-     */
1099
-    private function _save_registration_form_input(
1100
-        EE_Registration $registration,
1101
-        $form_input = '',
1102
-        $input_value = ''
1103
-    ) {
1104
-        // \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1105
-        // \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1106
-        // \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1107
-        // allow for plugins to hook in and do their own processing of the form input.
1108
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1109
-        if (apply_filters(
1110
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1111
-            false,
1112
-            $registration,
1113
-            $form_input,
1114
-            $input_value,
1115
-            $this
1116
-        )) {
1117
-            return true;
1118
-        }
1119
-        /*
381
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
382
+		return apply_filters(
383
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
384
+			$question_group_reg_form,
385
+			$registration,
386
+			$question_group,
387
+			$this
388
+		);
389
+	}
390
+
391
+
392
+	/**
393
+	 * @access public
394
+	 * @param EE_Question_Group $question_group
395
+	 * @return    EE_Form_Section_HTML
396
+	 */
397
+	private function _question_group_header(EE_Question_Group $question_group)
398
+	{
399
+		$html = '';
400
+		// group_name
401
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
402
+			if ($this->checkout->admin_request) {
403
+				$html .= EEH_HTML::br();
404
+				$html .= EEH_HTML::h3(
405
+					$question_group->name(),
406
+					'',
407
+					'ee-reg-form-qstn-grp-title title',
408
+					'font-size: 1.3em; padding-left:0;'
409
+				);
410
+			} else {
411
+				$html .= EEH_HTML::h4(
412
+					$question_group->name(),
413
+					'',
414
+					'ee-reg-form-qstn-grp-title section-title'
415
+				);
416
+			}
417
+		}
418
+		// group_desc
419
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
420
+			$html .= EEH_HTML::p(
421
+				$question_group->desc(),
422
+				'',
423
+				$this->checkout->admin_request
424
+					? 'ee-reg-form-qstn-grp-desc-pg'
425
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
426
+			);
427
+		}
428
+		return new EE_Form_Section_HTML($html);
429
+	}
430
+
431
+
432
+	/**
433
+	 * @access public
434
+	 * @return    EE_Form_Section_Proper
435
+	 * @throws \EE_Error
436
+	 */
437
+	private function _copy_attendee_info_form()
438
+	{
439
+		// array of params to pass to parent constructor
440
+		return new EE_Form_Section_Proper(
441
+			array(
442
+				'subsections'     => $this->_copy_attendee_info_inputs(),
443
+				'layout_strategy' => new EE_Template_Layout(
444
+					array(
445
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
446
+													  . $this->_slug
447
+													  . DS
448
+													  . 'copy_attendee_info.template.php',
449
+						'begin_template_file'      => null,
450
+						'input_template_file'      => null,
451
+						'subsection_template_file' => null,
452
+						'end_template_file'        => null,
453
+					)
454
+				),
455
+			)
456
+		);
457
+	}
458
+
459
+
460
+	/**
461
+	 * _auto_copy_attendee_info
462
+	 *
463
+	 * @access public
464
+	 * @return EE_Form_Section_HTML
465
+	 */
466
+	private function _auto_copy_attendee_info()
467
+	{
468
+		return new EE_Form_Section_HTML(
469
+			EEH_Template::locate_template(
470
+				SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
471
+				apply_filters(
472
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
473
+					array()
474
+				),
475
+				true,
476
+				true
477
+			)
478
+		);
479
+	}
480
+
481
+
482
+	/**
483
+	 * _copy_attendee_info_inputs
484
+	 *
485
+	 * @access public
486
+	 * @return array
487
+	 * @throws \EE_Error
488
+	 */
489
+	private function _copy_attendee_info_inputs()
490
+	{
491
+		$copy_attendee_info_inputs = array();
492
+		$prev_ticket               = null;
493
+		// grab the saved registrations from the transaction
494
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
495
+		foreach ($registrations as $registration) {
496
+			// for all  attendees other than the primary attendee
497
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
498
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
499
+				if ($registration->ticket()->ID() !== $prev_ticket) {
500
+					$item_name = $registration->ticket()->name();
501
+					$item_name .= $registration->ticket()->description() !== ''
502
+						? ' - ' . $registration->ticket()->description()
503
+						: '';
504
+					$copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
505
+						new EE_Form_Section_HTML(
506
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
507
+						);
508
+					$prev_ticket = $registration->ticket()->ID();
509
+				}
510
+
511
+				$copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
512
+					new EE_Checkbox_Multi_Input(
513
+						array(
514
+							$registration->ID() => sprintf(
515
+								esc_html__('Attendee #%s', 'event_espresso'),
516
+								$registration->count()
517
+							),
518
+						),
519
+						array(
520
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
521
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
522
+							'display_html_label_text' => false,
523
+						)
524
+					);
525
+			}
526
+		}
527
+		return $copy_attendee_info_inputs;
528
+	}
529
+
530
+
531
+	/**
532
+	 * _additional_primary_registrant_inputs
533
+	 *
534
+	 * @access public
535
+	 * @param EE_Registration $registration
536
+	 * @return    EE_Form_Input_Base
537
+	 * @throws \EE_Error
538
+	 */
539
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
540
+	{
541
+		// generate hidden input
542
+		return new EE_Hidden_Input(
543
+			array(
544
+				'html_id' => 'primary_registrant',
545
+				'default' => $registration->reg_url_link(),
546
+			)
547
+		);
548
+	}
549
+
550
+
551
+	/**
552
+	 * @access public
553
+	 * @param EE_Registration $registration
554
+	 * @param EE_Question     $question
555
+	 * @return EE_Form_Input_Base
556
+	 * @throws EE_Error
557
+	 * @throws InvalidArgumentException
558
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
559
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
560
+	 */
561
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
562
+	{
563
+
564
+		// if this question was for an attendee detail, then check for that answer
565
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
566
+			$registration,
567
+			$question->system_ID()
568
+		);
569
+		$answer       = $answer_value === null
570
+			? EEM_Answer::instance()->get_one(
571
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
572
+			)
573
+			: null;
574
+		// if NOT returning to edit an existing registration
575
+		// OR if this question is for an attendee property
576
+		// OR we still don't have an EE_Answer object
577
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
578
+			// create an EE_Answer object for storing everything in
579
+			$answer = EE_Answer::new_instance(array(
580
+				'QST_ID' => $question->ID(),
581
+				'REG_ID' => $registration->ID(),
582
+			));
583
+		}
584
+		// verify instance
585
+		if ($answer instanceof EE_Answer) {
586
+			if (! empty($answer_value)) {
587
+				$answer->set('ANS_value', $answer_value);
588
+			}
589
+			$answer->cache('Question', $question);
590
+			//remember system ID had a bug where sometimes it could be null
591
+			$answer_cache_id = $question->is_system_question()
592
+				? $question->system_ID() . '-' . $registration->reg_url_link()
593
+				: $question->ID() . '-' . $registration->reg_url_link();
594
+			$registration->cache('Answer', $answer, $answer_cache_id);
595
+		}
596
+		return $this->_generate_question_input($registration, $question, $answer);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @param EE_Registration $registration
602
+	 * @param EE_Question     $question
603
+	 * @param                 mixed EE_Answer|NULL      $answer
604
+	 * @return EE_Form_Input_Base
605
+	 * @throws \EE_Error
606
+	 */
607
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
608
+	{
609
+		$identifier                             = $question->is_system_question()
610
+			? $question->system_ID()
611
+			: $question->ID();
612
+		$this->_required_questions[$identifier] = $question->required() ? true : false;
613
+		add_filter(
614
+			'FHEE__EE_Question__generate_form_input__country_options',
615
+			array($this, 'use_cached_countries_for_form_input'),
616
+			10,
617
+			4
618
+		);
619
+		add_filter(
620
+			'FHEE__EE_Question__generate_form_input__state_options',
621
+			array($this, 'use_cached_states_for_form_input'),
622
+			10,
623
+			4
624
+		);
625
+		$input_constructor_args                  = array(
626
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
627
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
628
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
629
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
630
+			'html_label_class' => 'ee-reg-qstn',
631
+		);
632
+		$input_constructor_args['html_label_id'] .= '-lbl';
633
+		if ($answer instanceof EE_Answer && $answer->ID()) {
634
+			$input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
635
+			$input_constructor_args['html_id']       .= '-' . $answer->ID();
636
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
637
+		}
638
+		$form_input = $question->generate_form_input(
639
+			$registration,
640
+			$answer,
641
+			$input_constructor_args
642
+		);
643
+		remove_filter(
644
+			'FHEE__EE_Question__generate_form_input__country_options',
645
+			array($this, 'use_cached_countries_for_form_input')
646
+		);
647
+		remove_filter(
648
+			'FHEE__EE_Question__generate_form_input__state_options',
649
+			array($this, 'use_cached_states_for_form_input')
650
+		);
651
+		return $form_input;
652
+	}
653
+
654
+
655
+	/**
656
+	 * Gets the list of countries for the form input
657
+	 *
658
+	 * @param array|null       $countries_list
659
+	 * @param \EE_Question     $question
660
+	 * @param \EE_Registration $registration
661
+	 * @param \EE_Answer       $answer
662
+	 * @return array 2d keys are country IDs, values are their names
663
+	 * @throws EE_Error
664
+	 * @throws InvalidArgumentException
665
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
666
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
667
+	 */
668
+	public function use_cached_countries_for_form_input(
669
+		$countries_list,
670
+		\EE_Question $question = null,
671
+		\EE_Registration $registration = null,
672
+		\EE_Answer $answer = null
673
+	) {
674
+		$country_options = array('' => '');
675
+		// get possibly cached list of countries
676
+		$countries = $this->checkout->action === 'process_reg_step'
677
+			? EEM_Country::instance()->get_all_countries()
678
+			: EEM_Country::instance()->get_all_active_countries();
679
+		if (! empty($countries)) {
680
+			foreach ($countries as $country) {
681
+				if ($country instanceof EE_Country) {
682
+					$country_options[$country->ID()] = $country->name();
683
+				}
684
+			}
685
+		}
686
+		if ($question instanceof EE_Question
687
+			&& $registration instanceof EE_Registration) {
688
+			$answer = EEM_Answer::instance()->get_one(
689
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
690
+			);
691
+		} else {
692
+			$answer = EE_Answer::new_instance();
693
+		}
694
+		$country_options = apply_filters(
695
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
696
+			$country_options,
697
+			$this,
698
+			$registration,
699
+			$question,
700
+			$answer
701
+		);
702
+		return $country_options;
703
+	}
704
+
705
+
706
+	/**
707
+	 * Gets the list of states for the form input
708
+	 *
709
+	 * @param array|null       $states_list
710
+	 * @param \EE_Question     $question
711
+	 * @param \EE_Registration $registration
712
+	 * @param \EE_Answer       $answer
713
+	 * @return array 2d keys are state IDs, values are their names
714
+	 * @throws EE_Error
715
+	 * @throws InvalidArgumentException
716
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
717
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
718
+	 */
719
+	public function use_cached_states_for_form_input(
720
+		$states_list,
721
+		\EE_Question $question = null,
722
+		\EE_Registration $registration = null,
723
+		\EE_Answer $answer = null
724
+	) {
725
+		$state_options = array('' => array('' => ''));
726
+		$states        = $this->checkout->action === 'process_reg_step'
727
+			? EEM_State::instance()->get_all_states()
728
+			: EEM_State::instance()->get_all_active_states();
729
+		if (! empty($states)) {
730
+			foreach ($states as $state) {
731
+				if ($state instanceof EE_State) {
732
+					$state_options[$state->country()->name()][$state->ID()] = $state->name();
733
+				}
734
+			}
735
+		}
736
+		$state_options = apply_filters(
737
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
738
+			$state_options,
739
+			$this,
740
+			$registration,
741
+			$question,
742
+			$answer
743
+		);
744
+		return $state_options;
745
+	}
746
+
747
+
748
+
749
+
750
+
751
+
752
+	/********************************************************************************************************/
753
+	/****************************************  PROCESS REG STEP  ****************************************/
754
+	/********************************************************************************************************/
755
+	/**
756
+	 * @return bool
757
+	 * @throws EE_Error
758
+	 * @throws InvalidArgumentException
759
+	 * @throws ReflectionException
760
+	 * @throws RuntimeException
761
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
762
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
763
+	 */
764
+	public function process_reg_step()
765
+	{
766
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
767
+		// grab validated data from form
768
+		$valid_data = $this->checkout->current_step->valid_data();
769
+		// EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
770
+		// EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
771
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
772
+		if (empty($valid_data)) {
773
+			EE_Error::add_error(
774
+				esc_html__('No valid question responses were received.', 'event_espresso'),
775
+				__FILE__,
776
+				__FUNCTION__,
777
+				__LINE__
778
+			);
779
+			return false;
780
+		}
781
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
782
+			EE_Error::add_error(
783
+				esc_html__(
784
+					'A valid transaction could not be initiated for processing your registrations.',
785
+					'event_espresso'
786
+				),
787
+				__FILE__,
788
+				__FUNCTION__,
789
+				__LINE__
790
+			);
791
+			return false;
792
+		}
793
+		// get cached registrations
794
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
795
+		// verify we got the goods
796
+		if (empty($registrations)) {
797
+			EE_Error::add_error(
798
+				esc_html__('Your form data could not be applied to any valid registrations.', 'event_espresso'),
799
+				__FILE__,
800
+				__FUNCTION__,
801
+				__LINE__
802
+			);
803
+			return false;
804
+		}
805
+		// extract attendee info from form data and save to model objects
806
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
807
+		// if first pass thru SPCO,
808
+		// then let's check processed registrations against the total number of tickets in the cart
809
+		if ($registrations_processed === false) {
810
+			// but return immediately if the previous step exited early due to errors
811
+			return false;
812
+		} elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
813
+			// generate a correctly translated string for all possible singular/plural combinations
814
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
815
+				$error_msg = sprintf(
816
+					esc_html__(
817
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
818
+						'event_espresso'
819
+					),
820
+					$this->checkout->total_ticket_count,
821
+					$registrations_processed
822
+				);
823
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
824
+				$error_msg = sprintf(
825
+					esc_html__(
826
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
827
+						'event_espresso'
828
+					),
829
+					$this->checkout->total_ticket_count,
830
+					$registrations_processed
831
+				);
832
+			} else {
833
+				$error_msg = sprintf(
834
+					esc_html__(
835
+						'There was a total of %1$d tickets in the Event Queue, but %2$ds registrations were processed',
836
+						'event_espresso'
837
+					),
838
+					$this->checkout->total_ticket_count,
839
+					$registrations_processed
840
+				);
841
+			}
842
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
843
+			return false;
844
+		}
845
+		// mark this reg step as completed
846
+		$this->set_completed();
847
+		$this->_set_success_message(
848
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
849
+		);
850
+		//do action in case a plugin wants to do something with the data submitted in step 1.
851
+		//passes EE_Single_Page_Checkout, and it's posted data
852
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
853
+		return true;
854
+	}
855
+
856
+
857
+	/**
858
+	 *    _process_registrations
859
+	 *
860
+	 * @param EE_Registration[] $registrations
861
+	 * @param array             $valid_data
862
+	 * @return bool|int
863
+	 * @throws EE_Error
864
+	 * @throws InvalidArgumentException
865
+	 * @throws ReflectionException
866
+	 * @throws RuntimeException
867
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
868
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
869
+	 */
870
+	private function _process_registrations($registrations = array(), $valid_data = array())
871
+	{
872
+		// load resources and set some defaults
873
+		EE_Registry::instance()->load_model('Attendee');
874
+		// holder for primary registrant attendee object
875
+		$this->checkout->primary_attendee_obj = null;
876
+		// array for tracking reg form data for the primary registrant
877
+		$primary_registrant = array(
878
+			'line_item_id' => null,
879
+		);
880
+		$copy_primary       = false;
881
+		// reg form sections that do not contain inputs
882
+		$non_input_form_sections = array(
883
+			'primary_registrant',
884
+			'additional_attendee_reg_info',
885
+			'spco_copy_attendee_chk',
886
+		);
887
+		// attendee counter
888
+		$att_nmbr = 0;
889
+		// grab the saved registrations from the transaction
890
+		foreach ($registrations as $registration) {
891
+			// verify EE_Registration object
892
+			if (! $registration instanceof EE_Registration) {
893
+				EE_Error::add_error(
894
+					esc_html__(
895
+						'An invalid Registration object was discovered when attempting to process your registration information.',
896
+						'event_espresso'
897
+					),
898
+					__FILE__,
899
+					__FUNCTION__,
900
+					__LINE__
901
+				);
902
+				return false;
903
+			}
904
+			/** @var string $reg_url_link */
905
+			$reg_url_link = $registration->reg_url_link();
906
+			// reg_url_link exists ?
907
+			if (! empty($reg_url_link)) {
908
+				// should this registration be processed during this visit ?
909
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
910
+					// if NOT revisiting, then let's save the registration now,
911
+					// so that we have a REG_ID to use when generating other objects
912
+					if (! $this->checkout->revisit) {
913
+						$registration->save();
914
+					}
915
+					/**
916
+					 * This allows plugins to trigger a fail on processing of a
917
+					 * registration for any conditions they may have for it to pass.
918
+					 *
919
+					 * @var bool   if true is returned by the plugin then the
920
+					 *            registration processing is halted.
921
+					 */
922
+					if (apply_filters(
923
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
924
+						false,
925
+						$att_nmbr,
926
+						$registration,
927
+						$registrations,
928
+						$valid_data,
929
+						$this
930
+					)) {
931
+						return false;
932
+					}
933
+
934
+					// Houston, we have a registration!
935
+					$att_nmbr++;
936
+					$this->_attendee_data[$reg_url_link] = array();
937
+					// grab any existing related answer objects
938
+					$this->_registration_answers = $registration->answers();
939
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
940
+					if (isset($valid_data[$reg_url_link])) {
941
+						// do we need to copy basic info from primary attendee ?
942
+						$copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
943
+										&& absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0
944
+							? true
945
+							: false;
946
+						// filter form input data for this registration
947
+						$valid_data[$reg_url_link] = (array)apply_filters(
948
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
949
+							$valid_data[$reg_url_link]
950
+						);
951
+						if (isset($valid_data['primary_attendee'])) {
952
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
953
+								? $valid_data['primary_attendee']
954
+								: false;
955
+							unset($valid_data['primary_attendee']);
956
+						}
957
+						// now loop through our array of valid post data && process attendee reg forms
958
+						foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
959
+							if (! in_array($form_section, $non_input_form_sections)) {
960
+								foreach ($form_inputs as $form_input => $input_value) {
961
+									// \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
962
+									// check for critical inputs
963
+									if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
964
+										$form_input,
965
+										$input_value
966
+									)
967
+									) {
968
+										return false;
969
+									}
970
+									// store a bit of data about the primary attendee
971
+									if ($att_nmbr === 1
972
+										&& ! empty($input_value)
973
+										&& $reg_url_link === $primary_registrant['line_item_id']
974
+									) {
975
+										$primary_registrant[$form_input] = $input_value;
976
+									} elseif ($copy_primary
977
+										&& $input_value === null
978
+										&& isset($primary_registrant[$form_input])
979
+									) {
980
+										$input_value = $primary_registrant[$form_input];
981
+									}
982
+									// now attempt to save the input data
983
+									if (! $this->_save_registration_form_input(
984
+										$registration,
985
+										$form_input,
986
+										$input_value
987
+									)
988
+									) {
989
+										EE_Error::add_error(
990
+											sprintf(
991
+												esc_html__(
992
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
993
+													'event_espresso'
994
+												),
995
+												$form_input,
996
+												$input_value
997
+											),
998
+											__FILE__,
999
+											__FUNCTION__,
1000
+											__LINE__
1001
+										);
1002
+										return false;
1003
+									}
1004
+								}
1005
+							}
1006
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1007
+					}
1008
+					//EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1009
+					// this registration does not require additional attendee information ?
1010
+					if ($copy_primary
1011
+						&& $att_nmbr > 1
1012
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1013
+					) {
1014
+						// just copy the primary registrant
1015
+						$attendee = $this->checkout->primary_attendee_obj;
1016
+					} else {
1017
+						// ensure critical details are set for additional attendees
1018
+						$this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1019
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1020
+								$this->_attendee_data[$reg_url_link]
1021
+							)
1022
+							: $this->_attendee_data[$reg_url_link];
1023
+						// execute create attendee command (which may return an existing attendee)
1024
+						$attendee = EE_Registry::instance()->BUS->execute(
1025
+							new CreateAttendeeCommand(
1026
+								$this->_attendee_data[$reg_url_link],
1027
+								$registration
1028
+							)
1029
+						);
1030
+						// who's #1 ?
1031
+						if ($att_nmbr === 1) {
1032
+							$this->checkout->primary_attendee_obj = $attendee;
1033
+						}
1034
+					}
1035
+					// EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1036
+					// add relation to registration, set attendee ID, and cache attendee
1037
+					$this->_associate_attendee_with_registration($registration, $attendee);
1038
+					// \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1039
+					if (! $registration->attendee() instanceof EE_Attendee) {
1040
+						EE_Error::add_error(
1041
+							sprintf(
1042
+								esc_html__(
1043
+									'Registration %s has an invalid or missing Attendee object.',
1044
+									'event_espresso'
1045
+								),
1046
+								$reg_url_link
1047
+							),
1048
+							__FILE__,
1049
+							__FUNCTION__,
1050
+							__LINE__
1051
+						);
1052
+						return false;
1053
+					}
1054
+					/** @type EE_Registration_Processor $registration_processor */
1055
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1056
+					// at this point, we should have enough details about the registrant to consider the registration
1057
+					// NOT incomplete
1058
+					$registration_processor->toggle_incomplete_registration_status_to_default($registration, false);
1059
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1060
+					// abandoned
1061
+					$this->checkout->transaction->toggle_failed_transaction_status();
1062
+					// if we've gotten this far, then let's save what we have
1063
+					$registration->save();
1064
+					// add relation between TXN and registration
1065
+					$this->_associate_registration_with_transaction($registration);
1066
+				}
1067
+			} else {
1068
+				EE_Error::add_error(
1069
+					esc_html__(
1070
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1071
+						'event_espresso'
1072
+					),
1073
+					__FILE__,
1074
+					__FUNCTION__,
1075
+					__LINE__
1076
+				);
1077
+				// remove malformed data
1078
+				unset($valid_data[$reg_url_link]);
1079
+				return false;
1080
+			}
1081
+
1082
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1083
+		return $att_nmbr;
1084
+	}
1085
+
1086
+
1087
+	/**
1088
+	 *    _save_registration_form_input
1089
+	 *
1090
+	 * @param EE_Registration $registration
1091
+	 * @param string          $form_input
1092
+	 * @param string          $input_value
1093
+	 * @return bool
1094
+	 * @throws EE_Error
1095
+	 * @throws InvalidArgumentException
1096
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1097
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1098
+	 */
1099
+	private function _save_registration_form_input(
1100
+		EE_Registration $registration,
1101
+		$form_input = '',
1102
+		$input_value = ''
1103
+	) {
1104
+		// \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1105
+		// \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1106
+		// \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1107
+		// allow for plugins to hook in and do their own processing of the form input.
1108
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1109
+		if (apply_filters(
1110
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1111
+			false,
1112
+			$registration,
1113
+			$form_input,
1114
+			$input_value,
1115
+			$this
1116
+		)) {
1117
+			return true;
1118
+		}
1119
+		/*
1120 1120
          * $answer_cache_id is the key used to find the EE_Answer we want
1121 1121
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1122 1122
          */
1123
-        $answer_cache_id = $this->checkout->reg_url_link
1124
-            ? $form_input . '-' . $registration->reg_url_link()
1125
-            : $form_input;
1126
-        $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1127
-                           && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
1128
-            ? true
1129
-            : false;
1130
-        //rename form_inputs if they are EE_Attendee properties
1131
-        switch ((string) $form_input) {
1132
-            case 'state':
1133
-            case 'STA_ID':
1134
-                $attendee_property = true;
1135
-                $form_input        = 'STA_ID';
1136
-                break;
1137
-
1138
-            case 'country':
1139
-            case 'CNT_ISO':
1140
-                $attendee_property = true;
1141
-                $form_input        = 'CNT_ISO';
1142
-                break;
1143
-
1144
-            default:
1145
-                $ATT_input = 'ATT_' . $form_input;
1146
-                //EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1147
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1148
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1149
-        }
1150
-        // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1151
-        // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1152
-        // EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1153
-        // if this form input has a corresponding attendee property
1154
-        if ($attendee_property) {
1155
-            $this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1156
-            if ($answer_is_obj) {
1157
-                // and delete the corresponding answer since we won't be storing this data in that object
1158
-                $registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1159
-                $this->_registration_answers[$answer_cache_id]->delete_permanently();
1160
-            }
1161
-            return true;
1162
-        } elseif ($answer_is_obj) {
1163
-            // save this data to the answer object
1164
-            $this->_registration_answers[$answer_cache_id]->set_value($input_value);
1165
-            $result = $this->_registration_answers[$answer_cache_id]->save();
1166
-            return $result !== false ? true : false;
1167
-        } else {
1168
-            foreach ($this->_registration_answers as $answer) {
1169
-                if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1170
-                    $answer->set_value($input_value);
1171
-                    $result = $answer->save();
1172
-                    return $result !== false ? true : false;
1173
-                }
1174
-            }
1175
-        }
1176
-        return false;
1177
-    }
1178
-
1179
-
1180
-    /**
1181
-     *    _verify_critical_attendee_details_are_set
1182
-     *
1183
-     * @param string $form_input
1184
-     * @param string $input_value
1185
-     * @return boolean
1186
-     */
1187
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1188
-        $form_input = '',
1189
-        $input_value = ''
1190
-    ) {
1191
-        if (empty($input_value)) {
1192
-            // if the form input isn't marked as being required, then just return
1193
-            if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1194
-                return true;
1195
-            }
1196
-            switch ($form_input) {
1197
-                case 'fname':
1198
-                    EE_Error::add_error(
1199
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1200
-                        __FILE__,
1201
-                        __FUNCTION__,
1202
-                        __LINE__
1203
-                    );
1204
-                    return false;
1205
-                    break;
1206
-                case 'lname':
1207
-                    EE_Error::add_error(
1208
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1209
-                        __FILE__,
1210
-                        __FUNCTION__,
1211
-                        __LINE__
1212
-                    );
1213
-                    return false;
1214
-                    break;
1215
-                case 'email':
1216
-                    EE_Error::add_error(
1217
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1218
-                        __FILE__,
1219
-                        __FUNCTION__,
1220
-                        __LINE__
1221
-                    );
1222
-                    return false;
1223
-                    break;
1224
-            }
1225
-        }
1226
-        return true;
1227
-    }
1228
-
1229
-
1230
-    /**
1231
-     *    _associate_attendee_with_registration
1232
-     *
1233
-     * @param EE_Registration $registration
1234
-     * @param EE_Attendee     $attendee
1235
-     * @return void
1236
-     * @throws EE_Error
1237
-     * @throws RuntimeException
1238
-     */
1239
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1240
-    {
1241
-        // add relation to attendee
1242
-        $registration->_add_relation_to($attendee, 'Attendee');
1243
-        $registration->set_attendee_id($attendee->ID());
1244
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     *    _associate_registration_with_transaction
1250
-     *
1251
-     * @param EE_Registration $registration
1252
-     * @return void
1253
-     * @throws \EE_Error
1254
-     */
1255
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1256
-    {
1257
-        // add relation to registration
1258
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1259
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1260
-    }
1261
-
1262
-
1263
-    /**
1264
-     *    _copy_critical_attendee_details_from_primary_registrant
1265
-     *    ensures that all attendees at least have data for first name, last name, and email address
1266
-     *
1267
-     * @param array $attendee_data
1268
-     * @return array
1269
-     * @throws \EE_Error
1270
-     */
1271
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1272
-    {
1273
-        // bare minimum critical details include first name, last name, email address
1274
-        $critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1275
-        // add address info to critical details?
1276
-        if (apply_filters(
1277
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1278
-            false
1279
-        )) {
1280
-            $address_details           = array(
1281
-                'ATT_address',
1282
-                'ATT_address2',
1283
-                'ATT_city',
1284
-                'STA_ID',
1285
-                'CNT_ISO',
1286
-                'ATT_zip',
1287
-                'ATT_phone',
1288
-            );
1289
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1290
-        }
1291
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1292
-            if (! isset($attendee_data[$critical_attendee_detail])
1293
-                || empty($attendee_data[$critical_attendee_detail])
1294
-            ) {
1295
-                $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1296
-                    $critical_attendee_detail
1297
-                );
1298
-            }
1299
-        }
1300
-        return $attendee_data;
1301
-    }
1302
-
1303
-
1304
-    /**
1305
-     *    update_reg_step
1306
-     *    this is the final step after a user  revisits the site to edit their attendee information
1307
-     *    this gets called AFTER the process_reg_step() method above
1308
-     *
1309
-     * @return bool
1310
-     * @throws EE_Error
1311
-     * @throws InvalidArgumentException
1312
-     * @throws ReflectionException
1313
-     * @throws RuntimeException
1314
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1315
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1316
-     */
1317
-    public function update_reg_step()
1318
-    {
1319
-        // save everything
1320
-        if ($this->process_reg_step()) {
1321
-            $this->checkout->redirect     = true;
1322
-            $this->checkout->redirect_url = add_query_arg(
1323
-                array(
1324
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1325
-                    'revisit'        => true,
1326
-                ),
1327
-                $this->checkout->thank_you_page_url
1328
-            );
1329
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1330
-            return true;
1331
-        }
1332
-        return false;
1333
-    }
1123
+		$answer_cache_id = $this->checkout->reg_url_link
1124
+			? $form_input . '-' . $registration->reg_url_link()
1125
+			: $form_input;
1126
+		$answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1127
+						   && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
1128
+			? true
1129
+			: false;
1130
+		//rename form_inputs if they are EE_Attendee properties
1131
+		switch ((string) $form_input) {
1132
+			case 'state':
1133
+			case 'STA_ID':
1134
+				$attendee_property = true;
1135
+				$form_input        = 'STA_ID';
1136
+				break;
1137
+
1138
+			case 'country':
1139
+			case 'CNT_ISO':
1140
+				$attendee_property = true;
1141
+				$form_input        = 'CNT_ISO';
1142
+				break;
1143
+
1144
+			default:
1145
+				$ATT_input = 'ATT_' . $form_input;
1146
+				//EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1147
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1148
+				$form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1149
+		}
1150
+		// EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1151
+		// EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1152
+		// EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1153
+		// if this form input has a corresponding attendee property
1154
+		if ($attendee_property) {
1155
+			$this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1156
+			if ($answer_is_obj) {
1157
+				// and delete the corresponding answer since we won't be storing this data in that object
1158
+				$registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1159
+				$this->_registration_answers[$answer_cache_id]->delete_permanently();
1160
+			}
1161
+			return true;
1162
+		} elseif ($answer_is_obj) {
1163
+			// save this data to the answer object
1164
+			$this->_registration_answers[$answer_cache_id]->set_value($input_value);
1165
+			$result = $this->_registration_answers[$answer_cache_id]->save();
1166
+			return $result !== false ? true : false;
1167
+		} else {
1168
+			foreach ($this->_registration_answers as $answer) {
1169
+				if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1170
+					$answer->set_value($input_value);
1171
+					$result = $answer->save();
1172
+					return $result !== false ? true : false;
1173
+				}
1174
+			}
1175
+		}
1176
+		return false;
1177
+	}
1178
+
1179
+
1180
+	/**
1181
+	 *    _verify_critical_attendee_details_are_set
1182
+	 *
1183
+	 * @param string $form_input
1184
+	 * @param string $input_value
1185
+	 * @return boolean
1186
+	 */
1187
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1188
+		$form_input = '',
1189
+		$input_value = ''
1190
+	) {
1191
+		if (empty($input_value)) {
1192
+			// if the form input isn't marked as being required, then just return
1193
+			if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1194
+				return true;
1195
+			}
1196
+			switch ($form_input) {
1197
+				case 'fname':
1198
+					EE_Error::add_error(
1199
+						esc_html__('First Name is a required value.', 'event_espresso'),
1200
+						__FILE__,
1201
+						__FUNCTION__,
1202
+						__LINE__
1203
+					);
1204
+					return false;
1205
+					break;
1206
+				case 'lname':
1207
+					EE_Error::add_error(
1208
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1209
+						__FILE__,
1210
+						__FUNCTION__,
1211
+						__LINE__
1212
+					);
1213
+					return false;
1214
+					break;
1215
+				case 'email':
1216
+					EE_Error::add_error(
1217
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1218
+						__FILE__,
1219
+						__FUNCTION__,
1220
+						__LINE__
1221
+					);
1222
+					return false;
1223
+					break;
1224
+			}
1225
+		}
1226
+		return true;
1227
+	}
1228
+
1229
+
1230
+	/**
1231
+	 *    _associate_attendee_with_registration
1232
+	 *
1233
+	 * @param EE_Registration $registration
1234
+	 * @param EE_Attendee     $attendee
1235
+	 * @return void
1236
+	 * @throws EE_Error
1237
+	 * @throws RuntimeException
1238
+	 */
1239
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1240
+	{
1241
+		// add relation to attendee
1242
+		$registration->_add_relation_to($attendee, 'Attendee');
1243
+		$registration->set_attendee_id($attendee->ID());
1244
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 *    _associate_registration_with_transaction
1250
+	 *
1251
+	 * @param EE_Registration $registration
1252
+	 * @return void
1253
+	 * @throws \EE_Error
1254
+	 */
1255
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1256
+	{
1257
+		// add relation to registration
1258
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1259
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1260
+	}
1261
+
1262
+
1263
+	/**
1264
+	 *    _copy_critical_attendee_details_from_primary_registrant
1265
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1266
+	 *
1267
+	 * @param array $attendee_data
1268
+	 * @return array
1269
+	 * @throws \EE_Error
1270
+	 */
1271
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1272
+	{
1273
+		// bare minimum critical details include first name, last name, email address
1274
+		$critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1275
+		// add address info to critical details?
1276
+		if (apply_filters(
1277
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1278
+			false
1279
+		)) {
1280
+			$address_details           = array(
1281
+				'ATT_address',
1282
+				'ATT_address2',
1283
+				'ATT_city',
1284
+				'STA_ID',
1285
+				'CNT_ISO',
1286
+				'ATT_zip',
1287
+				'ATT_phone',
1288
+			);
1289
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1290
+		}
1291
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1292
+			if (! isset($attendee_data[$critical_attendee_detail])
1293
+				|| empty($attendee_data[$critical_attendee_detail])
1294
+			) {
1295
+				$attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1296
+					$critical_attendee_detail
1297
+				);
1298
+			}
1299
+		}
1300
+		return $attendee_data;
1301
+	}
1302
+
1303
+
1304
+	/**
1305
+	 *    update_reg_step
1306
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1307
+	 *    this gets called AFTER the process_reg_step() method above
1308
+	 *
1309
+	 * @return bool
1310
+	 * @throws EE_Error
1311
+	 * @throws InvalidArgumentException
1312
+	 * @throws ReflectionException
1313
+	 * @throws RuntimeException
1314
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1315
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1316
+	 */
1317
+	public function update_reg_step()
1318
+	{
1319
+		// save everything
1320
+		if ($this->process_reg_step()) {
1321
+			$this->checkout->redirect     = true;
1322
+			$this->checkout->redirect_url = add_query_arg(
1323
+				array(
1324
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1325
+					'revisit'        => true,
1326
+				),
1327
+				$this->checkout->thank_you_page_url
1328
+			);
1329
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1330
+			return true;
1331
+		}
1332
+		return false;
1333
+	}
1334 1334
 }
Please login to merge, or discard this patch.
Spacing   +49 added lines, -50 removed lines patch added patch discarded remove patch
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
     {
48 48
         $this->_slug     = 'attendee_information';
49 49
         $this->_name     = esc_html__('Attendee Information', 'event_espresso');
50
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
50
+        $this->_template = SPCO_REG_STEPS_PATH.$this->_slug.DS.'attendee_info_main.template.php';
51 51
         $this->checkout  = $checkout;
52 52
         $this->_reset_success_message();
53 53
         $this->set_instructions(
@@ -58,11 +58,11 @@  discard block
 block discarded – undo
58 58
 
59 59
     public function translate_js_strings()
60 60
     {
61
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
61
+        EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
62 62
             ' is a required question.',
63 63
             'event_espresso'
64 64
         );
65
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
65
+        EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
66 66
             ' is a required question. Please enter a value for at least one of the options.',
67 67
             'event_espresso'
68 68
         );
@@ -70,18 +70,18 @@  discard block
 block discarded – undo
70 70
             'Please answer all required questions correctly before proceeding.',
71 71
             'event_espresso'
72 72
         );
73
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
73
+        EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
74 74
             esc_html__(
75 75
                 'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
76 76
                 'event_espresso'
77 77
             ),
78 78
             '<br/>'
79 79
         );
80
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
80
+        EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
81 81
             'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
82 82
             'event_espresso'
83 83
         );
84
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
84
+        EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
85 85
             'You must enter a valid email address.',
86 86
             'event_espresso'
87 87
         );
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
                     && $this->checkout->visit_allows_processing_of_this_registration($registration)
145 145
                 ) {
146 146
                     $subsections[$registration->reg_url_link()] = $this->_registrations_reg_form($registration);
147
-                    if (! $this->checkout->admin_request) {
147
+                    if ( ! $this->checkout->admin_request) {
148 148
                         $template_args['registrations'][$registration->reg_url_link()]    = $registration;
149 149
                         $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
150 150
                             $template_args['ticket_count'][$registration->ticket()->ID()]
@@ -193,8 +193,7 @@  discard block
 block discarded – undo
193 193
                 'html_id'         => $this->reg_form_name(),
194 194
                 'subsections'     => $subsections,
195 195
                 'layout_strategy' => $this->checkout->admin_request ?
196
-                    new EE_Div_Per_Section_Layout() :
197
-                    new EE_Template_Layout(
196
+                    new EE_Div_Per_Section_Layout() : new EE_Template_Layout(
198 197
                         array(
199 198
                             'layout_template_file' => $this->_template, // layout_template
200 199
                             'template_args'        => $template_args,
@@ -232,7 +231,7 @@  discard block
 block discarded – undo
232 231
             if ($question_groups) {
233 232
                 // array of params to pass to parent constructor
234 233
                 $form_args = array(
235
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
234
+                    'html_id'         => 'ee-registration-'.$registration->reg_url_link(),
236 235
                     'html_class'      => 'ee-reg-form-attendee-dv',
237 236
                     'html_style'      => $this->checkout->admin_request
238 237
                         ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
@@ -288,7 +287,7 @@  discard block
 block discarded – undo
288 287
         // generate hidden input
289 288
         return new EE_Hidden_Input(
290 289
             array(
291
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
290
+                'html_id' => 'additional-attendee-reg-info-'.$registration->reg_url_link(),
292 291
                 'default' => $additional_attendee_reg_info,
293 292
             )
294 293
         );
@@ -308,11 +307,11 @@  discard block
 block discarded – undo
308 307
     {
309 308
         // array of params to pass to parent constructor
310 309
         $form_args = array(
311
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier(),
310
+            'html_id'         => 'ee-reg-form-qstn-grp-'.$question_group->identifier(),
312 311
             'html_class'      => $this->checkout->admin_request
313 312
                 ? 'form-table ee-reg-form-qstn-grp-dv'
314 313
                 : 'ee-reg-form-qstn-grp-dv',
315
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-lbl',
314
+            'html_label_id'   => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-lbl',
316 315
             'subsections'     => array(
317 316
                 'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
318 317
             ),
@@ -323,7 +322,7 @@  discard block
 block discarded – undo
323 322
         // where params
324 323
         $query_params = array('QST_deleted' => 0);
325 324
         // don't load admin only questions on the frontend
326
-        if (! $this->checkout->admin_request) {
325
+        if ( ! $this->checkout->admin_request) {
327 326
             $query_params['QST_admin_only'] = array('!=', true);
328 327
         }
329 328
         $questions = $question_group->get_many_related(
@@ -467,7 +466,7 @@  discard block
 block discarded – undo
467 466
     {
468 467
         return new EE_Form_Section_HTML(
469 468
             EEH_Template::locate_template(
470
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
469
+                SPCO_REG_STEPS_PATH.$this->_slug.DS.'_auto_copy_attendee_info.template.php',
471 470
                 apply_filters(
472 471
                     'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
473 472
                     array()
@@ -499,16 +498,16 @@  discard block
 block discarded – undo
499 498
                 if ($registration->ticket()->ID() !== $prev_ticket) {
500 499
                     $item_name = $registration->ticket()->name();
501 500
                     $item_name .= $registration->ticket()->description() !== ''
502
-                        ? ' - ' . $registration->ticket()->description()
501
+                        ? ' - '.$registration->ticket()->description()
503 502
                         : '';
504
-                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID() . ']'] =
503
+                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-'.$registration->ticket()->ID().']'] =
505 504
                         new EE_Form_Section_HTML(
506
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
505
+                            '<h6 class="spco-copy-attendee-event-hdr">'.$item_name.'</h6>'
507 506
                         );
508 507
                     $prev_ticket = $registration->ticket()->ID();
509 508
                 }
510 509
 
511
-                $copy_attendee_info_inputs['spco_copy_attendee_chk[' . $registration->ID() . ']'] =
510
+                $copy_attendee_info_inputs['spco_copy_attendee_chk['.$registration->ID().']'] =
512 511
                     new EE_Checkbox_Multi_Input(
513 512
                         array(
514 513
                             $registration->ID() => sprintf(
@@ -517,7 +516,7 @@  discard block
 block discarded – undo
517 516
                             ),
518 517
                         ),
519 518
                         array(
520
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
519
+                            'html_id'                 => 'spco-copy-attendee-chk-'.$registration->reg_url_link(),
521 520
                             'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
522 521
                             'display_html_label_text' => false,
523 522
                         )
@@ -566,7 +565,7 @@  discard block
 block discarded – undo
566 565
             $registration,
567 566
             $question->system_ID()
568 567
         );
569
-        $answer       = $answer_value === null
568
+        $answer = $answer_value === null
570 569
             ? EEM_Answer::instance()->get_one(
571 570
                 array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
572 571
             )
@@ -583,14 +582,14 @@  discard block
 block discarded – undo
583 582
         }
584 583
         // verify instance
585 584
         if ($answer instanceof EE_Answer) {
586
-            if (! empty($answer_value)) {
585
+            if ( ! empty($answer_value)) {
587 586
                 $answer->set('ANS_value', $answer_value);
588 587
             }
589 588
             $answer->cache('Question', $question);
590 589
             //remember system ID had a bug where sometimes it could be null
591 590
             $answer_cache_id = $question->is_system_question()
592
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
593
-                : $question->ID() . '-' . $registration->reg_url_link();
591
+                ? $question->system_ID().'-'.$registration->reg_url_link()
592
+                : $question->ID().'-'.$registration->reg_url_link();
594 593
             $registration->cache('Answer', $answer, $answer_cache_id);
595 594
         }
596 595
         return $this->_generate_question_input($registration, $question, $answer);
@@ -622,18 +621,18 @@  discard block
 block discarded – undo
622 621
             10,
623 622
             4
624 623
         );
625
-        $input_constructor_args                  = array(
626
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
627
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
628
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
629
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
624
+        $input_constructor_args = array(
625
+            'html_name'        => 'ee_reg_qstn['.$registration->ID().']['.$identifier.']',
626
+            'html_id'          => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
627
+            'html_class'       => 'ee-reg-qstn ee-reg-qstn-'.$identifier,
628
+            'html_label_id'    => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
630 629
             'html_label_class' => 'ee-reg-qstn',
631 630
         );
632 631
         $input_constructor_args['html_label_id'] .= '-lbl';
633 632
         if ($answer instanceof EE_Answer && $answer->ID()) {
634
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
635
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
636
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
633
+            $input_constructor_args['html_name']     .= '['.$answer->ID().']';
634
+            $input_constructor_args['html_id']       .= '-'.$answer->ID();
635
+            $input_constructor_args['html_label_id'] .= '-'.$answer->ID();
637 636
         }
638 637
         $form_input = $question->generate_form_input(
639 638
             $registration,
@@ -676,7 +675,7 @@  discard block
 block discarded – undo
676 675
         $countries = $this->checkout->action === 'process_reg_step'
677 676
             ? EEM_Country::instance()->get_all_countries()
678 677
             : EEM_Country::instance()->get_all_active_countries();
679
-        if (! empty($countries)) {
678
+        if ( ! empty($countries)) {
680 679
             foreach ($countries as $country) {
681 680
                 if ($country instanceof EE_Country) {
682 681
                     $country_options[$country->ID()] = $country->name();
@@ -726,7 +725,7 @@  discard block
 block discarded – undo
726 725
         $states        = $this->checkout->action === 'process_reg_step'
727 726
             ? EEM_State::instance()->get_all_states()
728 727
             : EEM_State::instance()->get_all_active_states();
729
-        if (! empty($states)) {
728
+        if ( ! empty($states)) {
730 729
             foreach ($states as $state) {
731 730
                 if ($state instanceof EE_State) {
732 731
                     $state_options[$state->country()->name()][$state->ID()] = $state->name();
@@ -778,7 +777,7 @@  discard block
 block discarded – undo
778 777
             );
779 778
             return false;
780 779
         }
781
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
780
+        if ( ! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
782 781
             EE_Error::add_error(
783 782
                 esc_html__(
784 783
                     'A valid transaction could not be initiated for processing your registrations.',
@@ -809,7 +808,7 @@  discard block
 block discarded – undo
809 808
         if ($registrations_processed === false) {
810 809
             // but return immediately if the previous step exited early due to errors
811 810
             return false;
812
-        } elseif (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
811
+        } elseif ( ! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
813 812
             // generate a correctly translated string for all possible singular/plural combinations
814 813
             if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
815 814
                 $error_msg = sprintf(
@@ -889,7 +888,7 @@  discard block
 block discarded – undo
889 888
         // grab the saved registrations from the transaction
890 889
         foreach ($registrations as $registration) {
891 890
             // verify EE_Registration object
892
-            if (! $registration instanceof EE_Registration) {
891
+            if ( ! $registration instanceof EE_Registration) {
893 892
                 EE_Error::add_error(
894 893
                     esc_html__(
895 894
                         'An invalid Registration object was discovered when attempting to process your registration information.',
@@ -904,12 +903,12 @@  discard block
 block discarded – undo
904 903
             /** @var string $reg_url_link */
905 904
             $reg_url_link = $registration->reg_url_link();
906 905
             // reg_url_link exists ?
907
-            if (! empty($reg_url_link)) {
906
+            if ( ! empty($reg_url_link)) {
908 907
                 // should this registration be processed during this visit ?
909 908
                 if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
910 909
                     // if NOT revisiting, then let's save the registration now,
911 910
                     // so that we have a REG_ID to use when generating other objects
912
-                    if (! $this->checkout->revisit) {
911
+                    if ( ! $this->checkout->revisit) {
913 912
                         $registration->save();
914 913
                     }
915 914
                     /**
@@ -944,7 +943,7 @@  discard block
 block discarded – undo
944 943
                             ? true
945 944
                             : false;
946 945
                         // filter form input data for this registration
947
-                        $valid_data[$reg_url_link] = (array)apply_filters(
946
+                        $valid_data[$reg_url_link] = (array) apply_filters(
948 947
                             'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
949 948
                             $valid_data[$reg_url_link]
950 949
                         );
@@ -956,11 +955,11 @@  discard block
 block discarded – undo
956 955
                         }
957 956
                         // now loop through our array of valid post data && process attendee reg forms
958 957
                         foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
959
-                            if (! in_array($form_section, $non_input_form_sections)) {
958
+                            if ( ! in_array($form_section, $non_input_form_sections)) {
960 959
                                 foreach ($form_inputs as $form_input => $input_value) {
961 960
                                     // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
962 961
                                     // check for critical inputs
963
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
962
+                                    if ( ! $this->_verify_critical_attendee_details_are_set_and_validate_email(
964 963
                                         $form_input,
965 964
                                         $input_value
966 965
                                     )
@@ -980,7 +979,7 @@  discard block
 block discarded – undo
980 979
                                         $input_value = $primary_registrant[$form_input];
981 980
                                     }
982 981
                                     // now attempt to save the input data
983
-                                    if (! $this->_save_registration_form_input(
982
+                                    if ( ! $this->_save_registration_form_input(
984 983
                                         $registration,
985 984
                                         $form_input,
986 985
                                         $input_value
@@ -1036,7 +1035,7 @@  discard block
 block discarded – undo
1036 1035
                     // add relation to registration, set attendee ID, and cache attendee
1037 1036
                     $this->_associate_attendee_with_registration($registration, $attendee);
1038 1037
                     // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1039
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1038
+                    if ( ! $registration->attendee() instanceof EE_Attendee) {
1040 1039
                         EE_Error::add_error(
1041 1040
                             sprintf(
1042 1041
                                 esc_html__(
@@ -1121,7 +1120,7 @@  discard block
 block discarded – undo
1121 1120
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1122 1121
          */
1123 1122
         $answer_cache_id = $this->checkout->reg_url_link
1124
-            ? $form_input . '-' . $registration->reg_url_link()
1123
+            ? $form_input.'-'.$registration->reg_url_link()
1125 1124
             : $form_input;
1126 1125
         $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1127 1126
                            && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer
@@ -1142,10 +1141,10 @@  discard block
 block discarded – undo
1142 1141
                 break;
1143 1142
 
1144 1143
             default:
1145
-                $ATT_input = 'ATT_' . $form_input;
1144
+                $ATT_input = 'ATT_'.$form_input;
1146 1145
                 //EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1147 1146
                 $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1148
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1147
+                $form_input        = $attendee_property ? 'ATT_'.$form_input : $form_input;
1149 1148
         }
1150 1149
         // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1151 1150
         // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
@@ -1190,7 +1189,7 @@  discard block
 block discarded – undo
1190 1189
     ) {
1191 1190
         if (empty($input_value)) {
1192 1191
             // if the form input isn't marked as being required, then just return
1193
-            if (! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1192
+            if ( ! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1194 1193
                 return true;
1195 1194
             }
1196 1195
             switch ($form_input) {
@@ -1277,7 +1276,7 @@  discard block
 block discarded – undo
1277 1276
             'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1278 1277
             false
1279 1278
         )) {
1280
-            $address_details           = array(
1279
+            $address_details = array(
1281 1280
                 'ATT_address',
1282 1281
                 'ATT_address2',
1283 1282
                 'ATT_city',
@@ -1289,7 +1288,7 @@  discard block
 block discarded – undo
1289 1288
             $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1290 1289
         }
1291 1290
         foreach ($critical_attendee_details as $critical_attendee_detail) {
1292
-            if (! isset($attendee_data[$critical_attendee_detail])
1291
+            if ( ! isset($attendee_data[$critical_attendee_detail])
1293 1292
                 || empty($attendee_data[$critical_attendee_detail])
1294 1293
             ) {
1295 1294
                 $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
Please login to merge, or discard this patch.
reg_steps/payment_options/EE_SPCO_Reg_Step_Payment_Options.class.php 3 patches
Doc Comments   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 
143 143
 
144 144
     /**
145
-     * @return null
145
+     * @return EE_Line_Item_Display
146 146
      */
147 147
     public function line_item_display()
148 148
     {
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
 
152 152
 
153 153
     /**
154
-     * @param null $line_item_display
154
+     * @param EE_Line_Item_Display $line_item_display
155 155
      */
156 156
     public function set_line_item_display($line_item_display)
157 157
     {
@@ -849,7 +849,7 @@  discard block
 block discarded – undo
849 849
      *    _apply_registration_payments_to_amount_owing
850 850
      *
851 851
      * @access protected
852
-     * @param array $registrations
852
+     * @param EE_Base_Class[] $registrations
853 853
      */
854 854
     protected function _apply_registration_payments_to_amount_owing(array $registrations)
855 855
     {
@@ -1122,7 +1122,7 @@  discard block
 block discarded – undo
1122 1122
      * get_billing_form_html_for_payment_method
1123 1123
      *
1124 1124
      * @access public
1125
-     * @return string
1125
+     * @return boolean
1126 1126
      * @throws \EE_Error
1127 1127
      */
1128 1128
     public function get_billing_form_html_for_payment_method()
@@ -1186,7 +1186,7 @@  discard block
 block discarded – undo
1186 1186
      *
1187 1187
      * @access private
1188 1188
      * @param EE_Payment_Method $payment_method
1189
-     * @return \EE_Billing_Info_Form|\EE_Form_Section_HTML
1189
+     * @return EE_Billing_Info_Form
1190 1190
      * @throws \EE_Error
1191 1191
      */
1192 1192
     private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
@@ -1290,7 +1290,7 @@  discard block
 block discarded – undo
1290 1290
      * switch_payment_method
1291 1291
      *
1292 1292
      * @access public
1293
-     * @return string
1293
+     * @return boolean
1294 1294
      * @throws \EE_Error
1295 1295
      */
1296 1296
     public function switch_payment_method()
@@ -1545,7 +1545,7 @@  discard block
 block discarded – undo
1545 1545
     /**
1546 1546
      * process_reg_step
1547 1547
      *
1548
-     * @return boolean
1548
+     * @return null|boolean
1549 1549
      * @throws \EE_Error
1550 1550
      */
1551 1551
     public function process_reg_step()
@@ -1671,7 +1671,7 @@  discard block
 block discarded – undo
1671 1671
      *    update_reg_step
1672 1672
      *    this is the final step after a user  revisits the site to retry a payment
1673 1673
      *
1674
-     * @return boolean
1674
+     * @return null|boolean
1675 1675
      * @throws \EE_Error
1676 1676
      */
1677 1677
     public function update_reg_step()
@@ -2084,7 +2084,7 @@  discard block
 block discarded – undo
2084 2084
      *
2085 2085
      * @access    private
2086 2086
      * @type    EE_Payment_Method $payment_method
2087
-     * @return    mixed    EE_Payment | boolean
2087
+     * @return    EE_Payment|null    EE_Payment | boolean
2088 2088
      * @throws \EE_Error
2089 2089
      */
2090 2090
     private function _attempt_payment(EE_Payment_Method $payment_method)
@@ -2215,7 +2215,7 @@  discard block
 block discarded – undo
2215 2215
      * _post_payment_processing
2216 2216
      *
2217 2217
      * @access private
2218
-     * @param EE_Payment|bool $payment
2218
+     * @param EE_Payment $payment
2219 2219
      * @return bool
2220 2220
      * @throws \EE_Error
2221 2221
      */
@@ -2406,7 +2406,7 @@  discard block
 block discarded – undo
2406 2406
      *        or present the payment options again
2407 2407
      *
2408 2408
      * @access private
2409
-     * @return EE_Payment | FALSE
2409
+     * @return boolean | FALSE
2410 2410
      * @throws \EE_Error
2411 2411
      */
2412 2412
     public function process_gateway_response()
@@ -2538,8 +2538,8 @@  discard block
 block discarded – undo
2538 2538
      * _redirect_wayward_request
2539 2539
      *
2540 2540
      * @access private
2541
-     * @param \EE_Registration|null $primary_registrant
2542
-     * @return bool
2541
+     * @param EE_Registration $primary_registrant
2542
+     * @return false|null
2543 2543
      * @throws \EE_Error
2544 2544
      */
2545 2545
     private function _redirect_wayward_request(EE_Registration $primary_registrant)
Please login to merge, or discard this patch.
Indentation   +2711 added lines, -2711 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if (! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 
5 5
 
@@ -15,2716 +15,2716 @@  discard block
 block discarded – undo
15 15
 class EE_SPCO_Reg_Step_Payment_Options extends EE_SPCO_Reg_Step
16 16
 {
17 17
 
18
-    /**
19
-     * @access protected
20
-     * @var EE_Line_Item_Display $Line_Item_Display
21
-     */
22
-    protected $line_item_display;
23
-
24
-    /**
25
-     * @access protected
26
-     * @var boolean $handle_IPN_in_this_request
27
-     */
28
-    protected $handle_IPN_in_this_request = false;
29
-
30
-
31
-    /**
32
-     *    set_hooks - for hooking into EE Core, other modules, etc
33
-     *
34
-     * @access    public
35
-     * @return    void
36
-     */
37
-    public static function set_hooks()
38
-    {
39
-        add_filter(
40
-            'FHEE__SPCO__EE_Line_Item_Filter_Collection',
41
-            array('EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters')
42
-        );
43
-        add_action(
44
-            'wp_ajax_switch_spco_billing_form',
45
-            array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
46
-        );
47
-        add_action(
48
-            'wp_ajax_nopriv_switch_spco_billing_form',
49
-            array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
50
-        );
51
-        add_action('wp_ajax_save_payer_details', array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details'));
52
-        add_action(
53
-            'wp_ajax_nopriv_save_payer_details',
54
-            array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details')
55
-        );
56
-        add_action(
57
-            'wp_ajax_get_transaction_details_for_gateways',
58
-            array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
59
-        );
60
-        add_action(
61
-            'wp_ajax_nopriv_get_transaction_details_for_gateways',
62
-            array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
63
-        );
64
-        add_filter(
65
-            'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
66
-            array('EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'),
67
-            10,
68
-            1
69
-        );
70
-    }
71
-
72
-
73
-    /**
74
-     *    ajax switch_spco_billing_form
75
-     *
76
-     * @throws \EE_Error
77
-     */
78
-    public static function switch_spco_billing_form()
79
-    {
80
-        EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
81
-    }
82
-
83
-
84
-    /**
85
-     *    ajax save_payer_details
86
-     *
87
-     * @throws \EE_Error
88
-     */
89
-    public static function save_payer_details()
90
-    {
91
-        EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
92
-    }
93
-
94
-
95
-    /**
96
-     *    ajax get_transaction_details
97
-     *
98
-     * @throws \EE_Error
99
-     */
100
-    public static function get_transaction_details()
101
-    {
102
-        EED_Single_Page_Checkout::process_ajax_request('get_transaction_details_for_gateways');
103
-    }
104
-
105
-
106
-    /**
107
-     * bypass_recaptcha_for_load_payment_method
108
-     *
109
-     * @access public
110
-     * @return array
111
-     */
112
-    public static function bypass_recaptcha_for_load_payment_method()
113
-    {
114
-        return array(
115
-            'EESID'  => EE_Registry::instance()->SSN->id(),
116
-            'step'   => 'payment_options',
117
-            'action' => 'spco_billing_form',
118
-        );
119
-    }
120
-
121
-
122
-    /**
123
-     *    class constructor
124
-     *
125
-     * @access    public
126
-     * @param    EE_Checkout $checkout
127
-     */
128
-    public function __construct(EE_Checkout $checkout)
129
-    {
130
-        $this->_slug     = 'payment_options';
131
-        $this->_name     = __('Payment Options', 'event_espresso');
132
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
133
-        $this->checkout  = $checkout;
134
-        $this->_reset_success_message();
135
-        $this->set_instructions(
136
-            __(
137
-                'Please select a method of payment and provide any necessary billing information before proceeding.',
138
-                'event_espresso'
139
-            )
140
-        );
141
-    }
142
-
143
-
144
-    /**
145
-     * @return null
146
-     */
147
-    public function line_item_display()
148
-    {
149
-        return $this->line_item_display;
150
-    }
151
-
152
-
153
-    /**
154
-     * @param null $line_item_display
155
-     */
156
-    public function set_line_item_display($line_item_display)
157
-    {
158
-        $this->line_item_display = $line_item_display;
159
-    }
160
-
161
-
162
-    /**
163
-     * @return boolean
164
-     */
165
-    public function handle_IPN_in_this_request()
166
-    {
167
-        return $this->handle_IPN_in_this_request;
168
-    }
169
-
170
-
171
-    /**
172
-     * @param boolean $handle_IPN_in_this_request
173
-     */
174
-    public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
175
-    {
176
-        $this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
177
-    }
178
-
179
-
180
-    /**
181
-     * translate_js_strings
182
-     *
183
-     * @return void
184
-     */
185
-    public function translate_js_strings()
186
-    {
187
-        EE_Registry::$i18n_js_strings['no_payment_method']      = __(
188
-            'Please select a method of payment in order to continue.',
189
-            'event_espresso'
190
-        );
191
-        EE_Registry::$i18n_js_strings['invalid_payment_method'] = __(
192
-            'A valid method of payment could not be determined. Please refresh the page and try again.',
193
-            'event_espresso'
194
-        );
195
-        EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = __(
196
-            'Forwarding to Secure Payment Provider.',
197
-            'event_espresso'
198
-        );
199
-    }
200
-
201
-
202
-    /**
203
-     * enqueue_styles_and_scripts
204
-     *
205
-     * @return void
206
-     */
207
-    public function enqueue_styles_and_scripts()
208
-    {
209
-        $transaction = $this->checkout->transaction;
210
-        //if the transaction isn't set or nothing is owed on it, don't enqueue any JS
211
-        if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
212
-            return;
213
-        }
214
-        foreach (
215
-            EEM_Payment_Method::instance()->get_all_for_transaction($transaction,
216
-                EEM_Payment_Method::scope_cart) as $payment_method
217
-        ) {
218
-            $type_obj = $payment_method->type_obj();
219
-            if ($type_obj instanceof EE_PMT_Base) {
220
-                $billing_form = $type_obj->generate_new_billing_form($transaction);
221
-                if ($billing_form instanceof EE_Form_Section_Proper) {
222
-                    $billing_form->enqueue_js();
223
-                }
224
-            }
225
-        }
226
-    }
227
-
228
-
229
-    /**
230
-     * initialize_reg_step
231
-     *
232
-     * @return boolean
233
-     * @throws \EE_Error
234
-     */
235
-    public function initialize_reg_step()
236
-    {
237
-        // TODO: if /when we implement donations, then this will need overriding
238
-        if (
239
-            // don't need payment options for:
240
-            // 	registrations made via the admin
241
-            // 	completed transactions
242
-            // 	overpaid transactions
243
-            // 	$ 0.00 transactions (no payment required)
244
-            ! $this->checkout->payment_required()
245
-            // but do NOT remove if current action being called belongs to this reg step
246
-            && ! is_callable(array($this, $this->checkout->action))
247
-            && ! $this->completed()
248
-        ) {
249
-            // and if so, then we no longer need the Payment Options step
250
-            if ($this->is_current_step()) {
251
-                $this->checkout->generate_reg_form = false;
252
-            }
253
-            $this->checkout->remove_reg_step($this->_slug);
254
-            // DEBUG LOG
255
-            //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
256
-            return false;
257
-        }
258
-        // load EEM_Payment_Method
259
-        EE_Registry::instance()->load_model('Payment_Method');
260
-        // get all active payment methods
261
-        $this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
262
-            $this->checkout->transaction,
263
-            EEM_Payment_Method::scope_cart
264
-        );
265
-        return true;
266
-    }
267
-
268
-
269
-    /**
270
-     * @return \EE_Form_Section_Proper
271
-     * @throws \EE_Error
272
-     */
273
-    public function generate_reg_form()
274
-    {
275
-        // reset in case someone changes their mind
276
-        $this->_reset_selected_method_of_payment();
277
-        // set some defaults
278
-        $this->checkout->selected_method_of_payment = 'payments_closed';
279
-        $registrations_requiring_payment            = array();
280
-        $registrations_for_free_events              = array();
281
-        $registrations_requiring_pre_approval       = array();
282
-        $sold_out_events                            = array();
283
-        $insufficient_spaces_available              = array();
284
-        $no_payment_required                        = true;
285
-        // loop thru registrations to gather info
286
-        $registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
287
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
288
-            $registrations,
289
-            $this->checkout->revisit
290
-        );
291
-        foreach ($registrations as $REG_ID => $registration) {
292
-            /** @var $registration EE_Registration */
293
-            // has this registration lost it's space ?
294
-            if (isset($ejected_registrations[$REG_ID])) {
295
-                $insufficient_spaces_available[$registration->event()->ID()] = $registration->event();
296
-                continue;
297
-            }
298
-            // event requires admin approval
299
-            if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
300
-                // add event to list of events with pre-approval reg status
301
-                $registrations_requiring_pre_approval[$REG_ID] = $registration;
302
-                do_action(
303
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
304
-                    $registration->event(),
305
-                    $this
306
-                );
307
-                continue;
308
-            }
309
-            if (
310
-                // returning registrant
311
-                $this->checkout->revisit
312
-                // anything other than Approved
313
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
314
-                && (
315
-                    $registration->event()->is_sold_out()
316
-                    || $registration->event()->is_sold_out(true)
317
-                )
318
-            ) {
319
-                // add event to list of events that are sold out
320
-                $sold_out_events[$registration->event()->ID()] = $registration->event();
321
-                do_action(
322
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
323
-                    $registration->event(),
324
-                    $this
325
-                );
326
-                continue;
327
-            }
328
-            // are they allowed to pay now and is there monies owing?
329
-            if ($registration->owes_monies_and_can_pay()) {
330
-                $registrations_requiring_payment[$REG_ID] = $registration;
331
-                do_action(
332
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
333
-                    $registration->event(),
334
-                    $this
335
-                );
336
-            } else if (
337
-                ! $this->checkout->revisit
338
-                && $registration->status_ID() !== EEM_Registration::status_id_not_approved
339
-                && $registration->ticket()->is_free()
340
-            ) {
341
-                $registrations_for_free_events[$registration->event()->ID()] = $registration;
342
-            }
343
-        }
344
-        $subsections = array();
345
-        // now decide which template to load
346
-        if (! empty($sold_out_events)) {
347
-            $subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
348
-        }
349
-        if (! empty($insufficient_spaces_available)) {
350
-            $subsections['insufficient_space'] = $this->_insufficient_spaces_available(
351
-                $insufficient_spaces_available
352
-            );
353
-        }
354
-        if (! empty($registrations_requiring_pre_approval)) {
355
-            $subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
356
-                $registrations_requiring_pre_approval
357
-            );
358
-        }
359
-        if (! empty($registrations_for_free_events)) {
360
-            $subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
361
-        }
362
-        if (! empty($registrations_requiring_payment)) {
363
-            if ($this->checkout->amount_owing > 0) {
364
-                // autoload Line_Item_Display classes
365
-                EEH_Autoloader::register_line_item_filter_autoloaders();
366
-                $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
367
-                    apply_filters(
368
-                        'FHEE__SPCO__EE_Line_Item_Filter_Collection',
369
-                        new EE_Line_Item_Filter_Collection()
370
-                    ),
371
-                    $this->checkout->cart->get_grand_total()
372
-                );
373
-                /** @var EE_Line_Item $filtered_line_item_tree */
374
-                $filtered_line_item_tree = $line_item_filter_processor->process();
375
-                EEH_Autoloader::register_line_item_display_autoloaders();
376
-                $this->set_line_item_display(new EE_Line_Item_Display('spco'));
377
-                $subsections['payment_options'] = $this->_display_payment_options(
378
-                    $this->line_item_display->display_line_item(
379
-                        $filtered_line_item_tree,
380
-                        array('registrations' => $registrations)
381
-                    )
382
-                );
383
-                $this->checkout->amount_owing   = $filtered_line_item_tree->total();
384
-                $this->_apply_registration_payments_to_amount_owing($registrations);
385
-            }
386
-            $no_payment_required = false;
387
-        } else {
388
-            $this->_hide_reg_step_submit_button_if_revisit();
389
-        }
390
-        $this->_save_selected_method_of_payment();
391
-
392
-        $subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
393
-        $subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
394
-
395
-        return new EE_Form_Section_Proper(
396
-            array(
397
-                'name'            => $this->reg_form_name(),
398
-                'html_id'         => $this->reg_form_name(),
399
-                'subsections'     => $subsections,
400
-                'layout_strategy' => new EE_No_Layout(),
401
-            )
402
-        );
403
-    }
404
-
405
-
406
-    /**
407
-     * add line item filters required for this reg step
408
-     * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
409
-     *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
410
-     *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
411
-     *        payment options reg step, can apply these filters via the following: apply_filters(
412
-     *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
413
-     *        filter collection by passing that instead of instantiating a new collection
414
-     *
415
-     * @param \EE_Line_Item_Filter_Collection $line_item_filter_collection
416
-     * @return \EE_Line_Item_Filter_Collection
417
-     * @throws \EE_Error
418
-     */
419
-    public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
420
-    {
421
-        if (! EE_Registry::instance()->SSN instanceof EE_Session) {
422
-            return $line_item_filter_collection;
423
-        }
424
-        if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
425
-            return $line_item_filter_collection;
426
-        }
427
-        if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
428
-            return $line_item_filter_collection;
429
-        }
430
-        $line_item_filter_collection->add(
431
-            new EE_Billable_Line_Item_Filter(
432
-                EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
433
-                    EE_Registry::instance()->SSN->checkout()->transaction->registrations(
434
-                        EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
435
-                    )
436
-                )
437
-            )
438
-        );
439
-        $line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
440
-        return $line_item_filter_collection;
441
-    }
442
-
443
-
444
-    /**
445
-     * remove_ejected_registrations
446
-     * if a registrant has lost their potential space at an event due to lack of payment,
447
-     * then this method removes them from the list of registrations being paid for during this request
448
-     *
449
-     * @param \EE_Registration[] $registrations
450
-     * @return \EE_Registration[]
451
-     * @throws \EE_Error
452
-     */
453
-    public static function remove_ejected_registrations(array $registrations)
454
-    {
455
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
456
-            $registrations,
457
-            EE_Registry::instance()->SSN->checkout()->revisit
458
-        );
459
-        foreach ($registrations as $REG_ID => $registration) {
460
-            // has this registration lost it's space ?
461
-            if (isset($ejected_registrations[$REG_ID])) {
462
-                unset($registrations[$REG_ID]);
463
-                continue;
464
-            }
465
-        }
466
-        return $registrations;
467
-    }
468
-
469
-
470
-    /**
471
-     * find_registrations_that_lost_their_space
472
-     * If a registrant chooses an offline payment method like Invoice,
473
-     * then no space is reserved for them at the event until they fully pay fo that site
474
-     * (unless the event's default reg status is set to APPROVED)
475
-     * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
476
-     * then this method will determine which registrations have lost the ability to complete the reg process.
477
-     *
478
-     * @param \EE_Registration[] $registrations
479
-     * @param bool               $revisit
480
-     * @return array
481
-     * @throws \EE_Error
482
-     */
483
-    public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
484
-    {
485
-        // registrations per event
486
-        $event_reg_count = array();
487
-        // spaces left per event
488
-        $event_spaces_remaining = array();
489
-        // tickets left sorted by ID
490
-        $tickets_remaining = array();
491
-        // registrations that have lost their space
492
-        $ejected_registrations = array();
493
-        foreach ($registrations as $REG_ID => $registration) {
494
-            if (
495
-                $registration->status_ID() === EEM_Registration::status_id_approved
496
-                || apply_filters(
497
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
498
-                    false,
499
-                    $registration,
500
-                    $revisit
501
-                )
502
-            ) {
503
-                continue;
504
-            }
505
-            $EVT_ID = $registration->event_ID();
506
-            $ticket = $registration->ticket();
507
-            if (! isset($tickets_remaining[$ticket->ID()])) {
508
-                $tickets_remaining[$ticket->ID()] = $ticket->remaining();
509
-            }
510
-            if ($tickets_remaining[$ticket->ID()] > 0) {
511
-                if (! isset($event_reg_count[$EVT_ID])) {
512
-                    $event_reg_count[$EVT_ID] = 0;
513
-                }
514
-                $event_reg_count[$EVT_ID]++;
515
-                if (! isset($event_spaces_remaining[$EVT_ID])) {
516
-                    $event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
517
-                }
518
-            }
519
-            if (
520
-                $revisit
521
-                && (
522
-                    $tickets_remaining[$ticket->ID()] === 0
523
-                    || $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
524
-                )
525
-            ) {
526
-                $ejected_registrations[$REG_ID] = $registration->event();
527
-                if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
528
-                    /** @type EE_Registration_Processor $registration_processor */
529
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
530
-                    // at this point, we should have enough details about the registrant to consider the registration NOT incomplete
531
-                    $registration_processor->manually_update_registration_status(
532
-                        $registration,
533
-                        EEM_Registration::status_id_wait_list
534
-                    );
535
-                }
536
-
537
-            }
538
-        }
539
-        return $ejected_registrations;
540
-    }
541
-
542
-
543
-    /**
544
-     * _hide_reg_step_submit_button
545
-     * removes the html for the reg step submit button
546
-     * by replacing it with an empty string via filter callback
547
-     *
548
-     * @return void
549
-     */
550
-    protected function _adjust_registration_status_if_event_old_sold()
551
-    {
552
-    }
553
-
554
-
555
-    /**
556
-     * _hide_reg_step_submit_button
557
-     * removes the html for the reg step submit button
558
-     * by replacing it with an empty string via filter callback
559
-     *
560
-     * @return void
561
-     */
562
-    protected function _hide_reg_step_submit_button_if_revisit()
563
-    {
564
-        if ($this->checkout->revisit) {
565
-            add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
566
-        }
567
-    }
568
-
569
-
570
-    /**
571
-     * sold_out_events
572
-     * displays notices regarding events that have sold out since hte registrant first signed up
573
-     *
574
-     * @param \EE_Event[] $sold_out_events_array
575
-     * @return \EE_Form_Section_Proper
576
-     * @throws \EE_Error
577
-     */
578
-    private function _sold_out_events($sold_out_events_array = array())
579
-    {
580
-        // set some defaults
581
-        $this->checkout->selected_method_of_payment = 'events_sold_out';
582
-        $sold_out_events                            = '';
583
-        foreach ($sold_out_events_array as $sold_out_event) {
584
-            $sold_out_events .= EEH_HTML::li(
585
-                EEH_HTML::span('  ' . $sold_out_event->name(), '',
586
-                    'dashicons dashicons-marker ee-icon-size-16 pink-text')
587
-            );
588
-        }
589
-        return new EE_Form_Section_Proper(
590
-            array(
591
-                'layout_strategy' => new EE_Template_Layout(
592
-                    array(
593
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
594
-                                                  . $this->_slug
595
-                                                  . DS
596
-                                                  . 'sold_out_events.template.php',
597
-                        'template_args'        => apply_filters(
598
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
599
-                            array(
600
-                                'sold_out_events'     => $sold_out_events,
601
-                                'sold_out_events_msg' => apply_filters(
602
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
603
-                                    sprintf(
604
-                                        __('It appears that the event you were about to make a payment for has sold out since you first registered. If you have already made a partial payment towards this event, please contact the event administrator for a refund.%3$s%3$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%2$s',
605
-                                            'event_espresso'),
606
-                                        '<strong>',
607
-                                        '</strong>',
608
-                                        '<br />'
609
-                                    )
610
-                                ),
611
-                            )
612
-                        ),
613
-                    )
614
-                ),
615
-            )
616
-        );
617
-    }
618
-
619
-
620
-    /**
621
-     * _insufficient_spaces_available
622
-     * displays notices regarding events that do not have enough remaining spaces
623
-     * to satisfy the current number of registrations looking to pay
624
-     *
625
-     * @param \EE_Event[] $insufficient_spaces_events_array
626
-     * @return \EE_Form_Section_Proper
627
-     * @throws \EE_Error
628
-     */
629
-    private function _insufficient_spaces_available($insufficient_spaces_events_array = array())
630
-    {
631
-        // set some defaults
632
-        $this->checkout->selected_method_of_payment = 'invoice';
633
-        $insufficient_space_events                  = '';
634
-        foreach ($insufficient_spaces_events_array as $event) {
635
-            if ($event instanceof EE_Event) {
636
-                $insufficient_space_events .= EEH_HTML::li(
637
-                    EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
638
-                );
639
-            }
640
-        }
641
-        return new EE_Form_Section_Proper(
642
-            array(
643
-                'subsections'     => array(
644
-                    'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
645
-                    'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
646
-                ),
647
-                'layout_strategy' => new EE_Template_Layout(
648
-                    array(
649
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
650
-                                                  . $this->_slug
651
-                                                  . DS
652
-                                                  . 'sold_out_events.template.php',
653
-                        'template_args'        => apply_filters(
654
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
655
-                            array(
656
-                                'sold_out_events'     => $insufficient_space_events,
657
-                                'sold_out_events_msg' => apply_filters(
658
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
659
-                                    __(
660
-                                        'It appears that the event you were about to make a payment for has sold additional tickets since you first registered, and there are no longer enough spaces left to accommodate your selections. You may continue to pay and secure the available space(s) remaining, or simply cancel if you no longer wish to purchase. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
661
-                                        'event_espresso'
662
-                                    )
663
-                                ),
664
-                            )
665
-                        ),
666
-                    )
667
-                ),
668
-            )
669
-        );
670
-    }
671
-
672
-
673
-    /**
674
-     * registrations_requiring_pre_approval
675
-     *
676
-     * @param array $registrations_requiring_pre_approval
677
-     * @return \EE_Form_Section_Proper
678
-     * @throws \EE_Error
679
-     */
680
-    private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = array())
681
-    {
682
-        $events_requiring_pre_approval = '';
683
-        foreach ($registrations_requiring_pre_approval as $registration) {
684
-            if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
685
-                $events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
686
-                    EEH_HTML::span(
687
-                        '',
688
-                        '',
689
-                        'dashicons dashicons-marker ee-icon-size-16 orange-text'
690
-                    )
691
-                    . EEH_HTML::span($registration->event()->name(), '', 'orange-text')
692
-                );
693
-            }
694
-        }
695
-        return new EE_Form_Section_Proper(
696
-            array(
697
-                'layout_strategy' => new EE_Template_Layout(
698
-                    array(
699
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
700
-                                                  . $this->_slug
701
-                                                  . DS
702
-                                                  . 'events_requiring_pre_approval.template.php', // layout_template
703
-                        'template_args'        => apply_filters(
704
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
705
-                            array(
706
-                                'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
707
-                                'events_requiring_pre_approval_msg' => apply_filters(
708
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
709
-                                    __(
710
-                                        'The following events do not require payment at this time and will not be billed during this transaction. Billing will only occur after the attendee has been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
711
-                                        'event_espresso'
712
-                                    )
713
-                                ),
714
-                            )
715
-                        ),
716
-                    )
717
-                ),
718
-            )
719
-        );
720
-    }
721
-
722
-
723
-    /**
724
-     * _no_payment_required
725
-     *
726
-     * @param \EE_Event[] $registrations_for_free_events
727
-     * @return \EE_Form_Section_Proper
728
-     * @throws \EE_Error
729
-     */
730
-    private function _no_payment_required($registrations_for_free_events = array())
731
-    {
732
-        // set some defaults
733
-        $this->checkout->selected_method_of_payment = 'no_payment_required';
734
-        // generate no_payment_required form
735
-        return new EE_Form_Section_Proper(
736
-            array(
737
-                'layout_strategy' => new EE_Template_Layout(
738
-                    array(
739
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
740
-                                                  . $this->_slug
741
-                                                  . DS
742
-                                                  . 'no_payment_required.template.php', // layout_template
743
-                        'template_args'        => apply_filters(
744
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
745
-                            array(
746
-                                'revisit'                       => $this->checkout->revisit,
747
-                                'registrations'                 => array(),
748
-                                'ticket_count'                  => array(),
749
-                                'registrations_for_free_events' => $registrations_for_free_events,
750
-                                'no_payment_required_msg'       => EEH_HTML::p(
751
-                                    __('This is a free event, so no billing will occur.', 'event_espresso')
752
-                                ),
753
-                            )
754
-                        ),
755
-                    )
756
-                ),
757
-            )
758
-        );
759
-    }
760
-
761
-
762
-    /**
763
-     * _display_payment_options
764
-     *
765
-     * @param string $transaction_details
766
-     * @return \EE_Form_Section_Proper
767
-     * @throws \EE_Error
768
-     */
769
-    private function _display_payment_options($transaction_details = '')
770
-    {
771
-        // has method_of_payment been set by no-js user?
772
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
773
-        // build payment options form
774
-        return apply_filters(
775
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
776
-            new EE_Form_Section_Proper(
777
-                array(
778
-                    'subsections'     => array(
779
-                        'before_payment_options' => apply_filters(
780
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
781
-                            new EE_Form_Section_Proper(
782
-                                array('layout_strategy' => new EE_Div_Per_Section_Layout())
783
-                            )
784
-                        ),
785
-                        'payment_options'        => $this->_setup_payment_options(),
786
-                        'after_payment_options'  => apply_filters(
787
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
788
-                            new EE_Form_Section_Proper(
789
-                                array('layout_strategy' => new EE_Div_Per_Section_Layout())
790
-                            )
791
-                        ),
792
-                    ),
793
-                    'layout_strategy' => new EE_Template_Layout(
794
-                        array(
795
-                            'layout_template_file' => $this->_template,
796
-                            'template_args'        => apply_filters(
797
-                                'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
798
-                                array(
799
-                                    'reg_count'                 => $this->line_item_display->total_items(),
800
-                                    'transaction_details'       => $transaction_details,
801
-                                    'available_payment_methods' => array(),
802
-                                )
803
-                            ),
804
-                        )
805
-                    ),
806
-                )
807
-            )
808
-        );
809
-    }
810
-
811
-
812
-    /**
813
-     * _extra_hidden_inputs
814
-     *
815
-     * @param bool $no_payment_required
816
-     * @return \EE_Form_Section_Proper
817
-     * @throws \EE_Error
818
-     */
819
-    private function _extra_hidden_inputs($no_payment_required = true)
820
-    {
821
-        return new EE_Form_Section_Proper(
822
-            array(
823
-                'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
824
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
825
-                'subsections'     => array(
826
-                    'spco_no_payment_required' => new EE_Hidden_Input(
827
-                        array(
828
-                            'normalization_strategy' => new EE_Boolean_Normalization(),
829
-                            'html_name'              => 'spco_no_payment_required',
830
-                            'html_id'                => 'spco-no-payment-required-payment_options',
831
-                            'default'                => $no_payment_required,
832
-                        )
833
-                    ),
834
-                    'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
835
-                        array(
836
-                            'normalization_strategy' => new EE_Int_Normalization(),
837
-                            'html_name'              => 'spco_transaction_id',
838
-                            'html_id'                => 'spco-transaction-id',
839
-                            'default'                => $this->checkout->transaction->ID(),
840
-                        )
841
-                    ),
842
-                ),
843
-            )
844
-        );
845
-    }
846
-
847
-
848
-    /**
849
-     *    _apply_registration_payments_to_amount_owing
850
-     *
851
-     * @access protected
852
-     * @param array $registrations
853
-     */
854
-    protected function _apply_registration_payments_to_amount_owing(array $registrations)
855
-    {
856
-        $payments = array();
857
-        foreach ($registrations as $registration) {
858
-            if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
859
-                $payments += $registration->registration_payments();
860
-            }
861
-        }
862
-        if (! empty($payments)) {
863
-            foreach ($payments as $payment) {
864
-                if ($payment instanceof EE_Registration_Payment) {
865
-                    $this->checkout->amount_owing -= $payment->amount();
866
-                }
867
-            }
868
-        }
869
-    }
870
-
871
-
872
-    /**
873
-     *    _reset_selected_method_of_payment
874
-     *
875
-     * @access    private
876
-     * @param    bool $force_reset
877
-     * @return    void
878
-     */
879
-    private function _reset_selected_method_of_payment($force_reset = false)
880
-    {
881
-        $reset_payment_method = $force_reset
882
-            ? true
883
-            : sanitize_text_field(EE_Registry::instance()->REQ->get('reset_payment_method', false));
884
-        if ($reset_payment_method) {
885
-            $this->checkout->selected_method_of_payment = null;
886
-            $this->checkout->payment_method             = null;
887
-            $this->checkout->billing_form               = null;
888
-            $this->_save_selected_method_of_payment();
889
-        }
890
-    }
891
-
892
-
893
-    /**
894
-     * _save_selected_method_of_payment
895
-     * stores the selected_method_of_payment in the session
896
-     * so that it's available for all subsequent requests including AJAX
897
-     *
898
-     * @access        private
899
-     * @param string $selected_method_of_payment
900
-     * @return  void
901
-     */
902
-    private function _save_selected_method_of_payment($selected_method_of_payment = '')
903
-    {
904
-        $selected_method_of_payment = ! empty($selected_method_of_payment)
905
-            ? $selected_method_of_payment
906
-            : $this->checkout->selected_method_of_payment;
907
-        EE_Registry::instance()->SSN->set_session_data(
908
-            array('selected_method_of_payment' => $selected_method_of_payment)
909
-        );
910
-    }
911
-
912
-
913
-    /**
914
-     * _setup_payment_options
915
-     *
916
-     * @return \EE_Form_Section_Proper
917
-     * @throws \EE_Error
918
-     */
919
-    public function _setup_payment_options()
920
-    {
921
-        // load payment method classes
922
-        $this->checkout->available_payment_methods = $this->_get_available_payment_methods();
923
-        // switch up header depending on number of available payment methods
924
-        $payment_method_header     = count($this->checkout->available_payment_methods) > 1
925
-            ? apply_filters(
926
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
927
-                __('Please Select Your Method of Payment', 'event_espresso')
928
-            )
929
-            : apply_filters(
930
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
931
-                __('Method of Payment', 'event_espresso')
932
-            );
933
-        $available_payment_methods = array(
934
-            // display the "Payment Method" header
935
-            'payment_method_header' => new EE_Form_Section_HTML(
936
-                EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr')
937
-            ),
938
-        );
939
-        // the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
940
-        $available_payment_method_options = array();
941
-        $default_payment_method_option    = array();
942
-        // additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
943
-        $payment_methods_billing_info = array(
944
-            new EE_Form_Section_HTML(
945
-                EEH_HTML::div('<br />', '', '', 'clear:both;')
946
-            ),
947
-        );
948
-        // loop through payment methods
949
-        foreach ($this->checkout->available_payment_methods as $payment_method) {
950
-            if ($payment_method instanceof EE_Payment_Method) {
951
-                $payment_method_button = EEH_HTML::img(
952
-                    $payment_method->button_url(),
953
-                    $payment_method->name(),
954
-                    'spco-payment-method-' . $payment_method->slug() . '-btn-img',
955
-                    'spco-payment-method-btn-img'
956
-                );
957
-                // check if any payment methods are set as default
958
-                // if payment method is already selected OR nothing is selected and this payment method should be open_by_default
959
-                if (
960
-                    ($this->checkout->selected_method_of_payment === $payment_method->slug())
961
-                    || (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
962
-                ) {
963
-                    $this->checkout->selected_method_of_payment = $payment_method->slug();
964
-                    $this->_save_selected_method_of_payment();
965
-                    $default_payment_method_option[$payment_method->slug()] = $payment_method_button;
966
-                } else {
967
-                    $available_payment_method_options[$payment_method->slug()] = $payment_method_button;
968
-                }
969
-                $payment_methods_billing_info[$payment_method->slug()
970
-                                              . '-info'] = $this->_payment_method_billing_info(
971
-                    $payment_method
972
-                );
973
-            }
974
-        }
975
-        // prepend available_payment_method_options with default_payment_method_option so that it appears first in list of PMs
976
-        $available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
977
-        // now generate the actual form  inputs
978
-        $available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
979
-            $available_payment_method_options
980
-        );
981
-        $available_payment_methods                              += $payment_methods_billing_info;
982
-        // build the available payment methods form
983
-        return new EE_Form_Section_Proper(
984
-            array(
985
-                'html_id'         => 'spco-available-methods-of-payment-dv',
986
-                'subsections'     => $available_payment_methods,
987
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
988
-            )
989
-        );
990
-    }
991
-
992
-
993
-    /**
994
-     * _get_available_payment_methods
995
-     *
996
-     * @return EE_Payment_Method[]
997
-     */
998
-    protected function _get_available_payment_methods()
999
-    {
1000
-        if (! empty($this->checkout->available_payment_methods)) {
1001
-            return $this->checkout->available_payment_methods;
1002
-        }
1003
-        $available_payment_methods = array();
1004
-        // load EEM_Payment_Method
1005
-        EE_Registry::instance()->load_model('Payment_Method');
1006
-        /** @type EEM_Payment_Method $EEM_Payment_Method */
1007
-        $EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
1008
-        // get all active payment methods
1009
-        $payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1010
-            $this->checkout->transaction,
1011
-            EEM_Payment_Method::scope_cart
1012
-        );
1013
-        foreach ($payment_methods as $payment_method) {
1014
-            if ($payment_method instanceof EE_Payment_Method) {
1015
-                $available_payment_methods[$payment_method->slug()] = $payment_method;
1016
-            }
1017
-        }
1018
-        return $available_payment_methods;
1019
-    }
1020
-
1021
-
1022
-    /**
1023
-     *    _available_payment_method_inputs
1024
-     *
1025
-     * @access    private
1026
-     * @param    array $available_payment_method_options
1027
-     * @return    \EE_Form_Section_Proper
1028
-     */
1029
-    private function _available_payment_method_inputs($available_payment_method_options = array())
1030
-    {
1031
-        // generate inputs
1032
-        return new EE_Form_Section_Proper(
1033
-            array(
1034
-                'html_id'         => 'ee-available-payment-method-inputs',
1035
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1036
-                'subsections'     => array(
1037
-                    '' => new EE_Radio_Button_Input (
1038
-                        $available_payment_method_options,
1039
-                        array(
1040
-                            'html_name'          => 'selected_method_of_payment',
1041
-                            'html_class'         => 'spco-payment-method',
1042
-                            'default'            => $this->checkout->selected_method_of_payment,
1043
-                            'label_size'         => 11,
1044
-                            'enforce_label_size' => true,
1045
-                        )
1046
-                    ),
1047
-                ),
1048
-            )
1049
-        );
1050
-    }
1051
-
1052
-
1053
-    /**
1054
-     *    _payment_method_billing_info
1055
-     *
1056
-     * @access    private
1057
-     * @param    EE_Payment_Method $payment_method
1058
-     * @return    \EE_Form_Section_Proper
1059
-     * @throws \EE_Error
1060
-     */
1061
-    private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1062
-    {
1063
-        $currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug()
1064
-            ? true
1065
-            : false;
1066
-        // generate the billing form for payment method
1067
-        $billing_form                 = $currently_selected
1068
-            ? $this->_get_billing_form_for_payment_method($payment_method)
1069
-            : new EE_Form_Section_HTML();
1070
-        $this->checkout->billing_form = $currently_selected
1071
-            ? $billing_form
1072
-            : $this->checkout->billing_form;
1073
-        // it's all in the details
1074
-        $info_html = EEH_HTML::h3(
1075
-            __('Important information regarding your payment', 'event_espresso'),
1076
-            '',
1077
-            'spco-payment-method-hdr'
1078
-        );
1079
-        // add some info regarding the step, either from what's saved in the admin,
1080
-        // or a default string depending on whether the PM has a billing form or not
1081
-        if ($payment_method->description()) {
1082
-            $payment_method_info = $payment_method->description();
1083
-        } elseif ($billing_form instanceof EE_Billing_Info_Form) {
1084
-            $payment_method_info = sprintf(
1085
-                __(
1086
-                    'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1087
-                    'event_espresso'
1088
-                ),
1089
-                $this->submit_button_text()
1090
-            );
1091
-        } else {
1092
-            $payment_method_info = sprintf(
1093
-                __('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1094
-                $this->submit_button_text()
1095
-            );
1096
-        }
1097
-        $info_html .= EEH_HTML::p(
1098
-            apply_filters(
1099
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1100
-                $payment_method_info
1101
-            ),
1102
-            '',
1103
-            'spco-payment-method-desc ee-attention'
1104
-        );
1105
-        return new EE_Form_Section_Proper(
1106
-            array(
1107
-                'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1108
-                'html_class'      => 'spco-payment-method-info-dv',
1109
-                // only display the selected or default PM
1110
-                'html_style'      => $currently_selected ? '' : 'display:none;',
1111
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1112
-                'subsections'     => array(
1113
-                    'info'         => new EE_Form_Section_HTML($info_html),
1114
-                    'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1115
-                ),
1116
-            )
1117
-        );
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * get_billing_form_html_for_payment_method
1123
-     *
1124
-     * @access public
1125
-     * @return string
1126
-     * @throws \EE_Error
1127
-     */
1128
-    public function get_billing_form_html_for_payment_method()
1129
-    {
1130
-        // how have they chosen to pay?
1131
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1132
-        $this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1133
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1134
-            return false;
1135
-        }
1136
-        if (apply_filters(
1137
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1138
-            false
1139
-        )) {
1140
-            EE_Error::add_success(
1141
-                apply_filters(
1142
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1143
-                    sprintf(
1144
-                        __(
1145
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1146
-                            'event_espresso'
1147
-                        ),
1148
-                        $this->checkout->payment_method->name()
1149
-                    )
1150
-                )
1151
-            );
1152
-        }
1153
-        // now generate billing form for selected method of payment
1154
-        $payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1155
-        // fill form with attendee info if applicable
1156
-        if (
1157
-            $payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1158
-            && $this->checkout->transaction_has_primary_registrant()
1159
-        ) {
1160
-            $payment_method_billing_form->populate_from_attendee(
1161
-                $this->checkout->transaction->primary_registration()->attendee()
1162
-            );
1163
-        }
1164
-        // and debug content
1165
-        if (
1166
-            $payment_method_billing_form instanceof EE_Billing_Info_Form
1167
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1168
-        ) {
1169
-            $payment_method_billing_form = $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1170
-                $payment_method_billing_form
1171
-            );
1172
-        }
1173
-        $billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1174
-            ? $payment_method_billing_form->get_html()
1175
-            : '';
1176
-        $this->checkout->json_response->set_return_data(array('payment_method_info' => $billing_info));
1177
-        // localize validation rules for main form
1178
-        $this->checkout->current_step->reg_form->localize_validation_rules();
1179
-        $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1180
-        return true;
1181
-    }
1182
-
1183
-
1184
-    /**
1185
-     * _get_billing_form_for_payment_method
1186
-     *
1187
-     * @access private
1188
-     * @param EE_Payment_Method $payment_method
1189
-     * @return \EE_Billing_Info_Form|\EE_Form_Section_HTML
1190
-     * @throws \EE_Error
1191
-     */
1192
-    private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
1193
-    {
1194
-        $billing_form = $payment_method->type_obj()->billing_form(
1195
-            $this->checkout->transaction,
1196
-            array('amount_owing' => $this->checkout->amount_owing)
1197
-        );
1198
-        if ($billing_form instanceof EE_Billing_Info_Form) {
1199
-            if (
1200
-                apply_filters(
1201
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1202
-                    false
1203
-                )
1204
-                && EE_Registry::instance()->REQ->is_set('payment_method')
1205
-            ) {
1206
-                EE_Error::add_success(
1207
-                    apply_filters(
1208
-                        'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1209
-                        sprintf(
1210
-                            __(
1211
-                                'You have selected "%s" as your method of payment. Please note the important payment information below.',
1212
-                                'event_espresso'
1213
-                            ),
1214
-                            $payment_method->name()
1215
-                        )
1216
-                    )
1217
-                );
1218
-            }
1219
-            return apply_filters(
1220
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
1221
-                $billing_form,
1222
-                $payment_method
1223
-            );
1224
-        }
1225
-        // no actual billing form, so return empty HTML form section
1226
-        return new EE_Form_Section_HTML();
1227
-    }
1228
-
1229
-
1230
-    /**
1231
-     * _get_selected_method_of_payment
1232
-     *
1233
-     * @access private
1234
-     * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1235
-     *                          is not found in the incoming request
1236
-     * @param string  $request_param
1237
-     * @return NULL|string
1238
-     * @throws \EE_Error
1239
-     */
1240
-    private function _get_selected_method_of_payment(
1241
-        $required = false,
1242
-        $request_param = 'selected_method_of_payment'
1243
-    ) {
1244
-        // is selected_method_of_payment set in the request ?
1245
-        $selected_method_of_payment = EE_Registry::instance()->REQ->get($request_param, false);
1246
-        if ($selected_method_of_payment) {
1247
-            // sanitize it
1248
-            $selected_method_of_payment = is_array($selected_method_of_payment)
1249
-                ? array_shift($selected_method_of_payment)
1250
-                : $selected_method_of_payment;
1251
-            $selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1252
-            // store it in the session so that it's available for all subsequent requests including AJAX
1253
-            $this->_save_selected_method_of_payment($selected_method_of_payment);
1254
-        } else {
1255
-            // or is is set in the session ?
1256
-            $selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1257
-                'selected_method_of_payment'
1258
-            );
1259
-        }
1260
-        // do ya really really gotta have it?
1261
-        if (empty($selected_method_of_payment) && $required) {
1262
-            EE_Error::add_error(
1263
-                sprintf(
1264
-                    __(
1265
-                        'The selected method of payment could not be determined.%sPlease ensure that you have selected one before proceeding.%sIf you continue to experience difficulties, then refresh your browser and try again, or contact %s for assistance.',
1266
-                        'event_espresso'
1267
-                    ),
1268
-                    '<br/>',
1269
-                    '<br/>',
1270
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
1271
-                ),
1272
-                __FILE__,
1273
-                __FUNCTION__,
1274
-                __LINE__
1275
-            );
1276
-            return null;
1277
-        }
1278
-        return $selected_method_of_payment;
1279
-    }
1280
-
1281
-
1282
-
1283
-
1284
-
1285
-
1286
-    /********************************************************************************************************/
1287
-    /***********************************  SWITCH PAYMENT METHOD  ************************************/
1288
-    /********************************************************************************************************/
1289
-    /**
1290
-     * switch_payment_method
1291
-     *
1292
-     * @access public
1293
-     * @return string
1294
-     * @throws \EE_Error
1295
-     */
1296
-    public function switch_payment_method()
1297
-    {
1298
-        if (! $this->_verify_payment_method_is_set()) {
1299
-            return false;
1300
-        }
1301
-        if (apply_filters(
1302
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1303
-            false
1304
-        )) {
1305
-            EE_Error::add_success(
1306
-                apply_filters(
1307
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1308
-                    sprintf(
1309
-                        __(
1310
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1311
-                            'event_espresso'
1312
-                        ),
1313
-                        $this->checkout->payment_method->name()
1314
-                    )
1315
-                )
1316
-            );
1317
-        }
1318
-        // generate billing form for selected method of payment if it hasn't been done already
1319
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1320
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1321
-                $this->checkout->payment_method
1322
-            );
1323
-        }
1324
-        // fill form with attendee info if applicable
1325
-        if (
1326
-        apply_filters(
1327
-            'FHEE__populate_billing_form_fields_from_attendee',
1328
-            (
1329
-                $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1330
-                && $this->checkout->transaction_has_primary_registrant()
1331
-            ),
1332
-            $this->checkout->billing_form,
1333
-            $this->checkout->transaction
1334
-        )
1335
-        ) {
1336
-            $this->checkout->billing_form->populate_from_attendee(
1337
-                $this->checkout->transaction->primary_registration()->attendee()
1338
-            );
1339
-        }
1340
-        // and debug content
1341
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1342
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1343
-        ) {
1344
-            $this->checkout->billing_form = $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1345
-                $this->checkout->billing_form
1346
-            );
1347
-        }
1348
-        // get html and validation rules for form
1349
-        if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1350
-            $this->checkout->json_response->set_return_data(
1351
-                array('payment_method_info' => $this->checkout->billing_form->get_html())
1352
-            );
1353
-            // localize validation rules for main form
1354
-            $this->checkout->billing_form->localize_validation_rules(true);
1355
-            $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1356
-        } else {
1357
-            $this->checkout->json_response->set_return_data(array('payment_method_info' => ''));
1358
-        }
1359
-        //prevents advancement to next step
1360
-        $this->checkout->continue_reg = false;
1361
-        return true;
1362
-    }
1363
-
1364
-
1365
-    /**
1366
-     * _verify_payment_method_is_set
1367
-     *
1368
-     * @return boolean
1369
-     * @throws \EE_Error
1370
-     */
1371
-    protected function _verify_payment_method_is_set()
1372
-    {
1373
-        // generate billing form for selected method of payment if it hasn't been done already
1374
-        if (empty($this->checkout->selected_method_of_payment)) {
1375
-            // how have they chosen to pay?
1376
-            $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1377
-        } else {
1378
-            // choose your own adventure based on method_of_payment
1379
-            switch ($this->checkout->selected_method_of_payment) {
1380
-                case 'events_sold_out' :
1381
-                    EE_Error::add_attention(
1382
-                        apply_filters(
1383
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1384
-                            __('It appears that the event you were about to make a payment for has sold out since this form first loaded. Please contact the event administrator if you believe this is an error.',
1385
-                                'event_espresso')
1386
-                        ),
1387
-                        __FILE__, __FUNCTION__, __LINE__
1388
-                    );
1389
-                    return false;
1390
-                    break;
1391
-                case 'payments_closed' :
1392
-                    EE_Error::add_attention(
1393
-                        apply_filters(
1394
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__payments_closed_msg',
1395
-                            __('It appears that the event you were about to make a payment for is not accepting payments at this time. Please contact the event administrator if you believe this is an error.',
1396
-                                'event_espresso')
1397
-                        ),
1398
-                        __FILE__, __FUNCTION__, __LINE__
1399
-                    );
1400
-                    return false;
1401
-                    break;
1402
-                case 'no_payment_required' :
1403
-                    EE_Error::add_attention(
1404
-                        apply_filters(
1405
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1406
-                            __('It appears that the event you were about to make a payment for does not require payment. Please contact the event administrator if you believe this is an error.',
1407
-                                'event_espresso')
1408
-                        ),
1409
-                        __FILE__, __FUNCTION__, __LINE__
1410
-                    );
1411
-                    return false;
1412
-                    break;
1413
-                default:
1414
-            }
1415
-        }
1416
-        // verify payment method
1417
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1418
-            // get payment method for selected method of payment
1419
-            $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1420
-        }
1421
-        return $this->checkout->payment_method instanceof EE_Payment_Method ? true : false;
1422
-    }
1423
-
1424
-
1425
-
1426
-    /********************************************************************************************************/
1427
-    /***************************************  SAVE PAYER DETAILS  ****************************************/
1428
-    /********************************************************************************************************/
1429
-    /**
1430
-     * save_payer_details_via_ajax
1431
-     *
1432
-     * @return void
1433
-     * @throws \EE_Error
1434
-     */
1435
-    public function save_payer_details_via_ajax()
1436
-    {
1437
-        if (! $this->_verify_payment_method_is_set()) {
1438
-            return;
1439
-        }
1440
-        // generate billing form for selected method of payment if it hasn't been done already
1441
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1442
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1443
-                $this->checkout->payment_method
1444
-            );
1445
-        }
1446
-        // generate primary attendee from payer info if applicable
1447
-        if (! $this->checkout->transaction_has_primary_registrant()) {
1448
-            $attendee = $this->_create_attendee_from_request_data();
1449
-            if ($attendee instanceof EE_Attendee) {
1450
-                foreach ($this->checkout->transaction->registrations() as $registration) {
1451
-                    if ($registration->is_primary_registrant()) {
1452
-                        $this->checkout->primary_attendee_obj = $attendee;
1453
-                        $registration->_add_relation_to($attendee, 'Attendee');
1454
-                        $registration->set_attendee_id($attendee->ID());
1455
-                        $registration->update_cache_after_object_save('Attendee', $attendee);
1456
-                    }
1457
-                }
1458
-            }
1459
-        }
1460
-    }
1461
-
1462
-
1463
-    /**
1464
-     * create_attendee_from_request_data
1465
-     * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1466
-     *
1467
-     * @return \EE_Attendee
1468
-     * @throws \EE_Error
1469
-     */
1470
-    protected function _create_attendee_from_request_data()
1471
-    {
1472
-        // get State ID
1473
-        $STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1474
-        if (! empty($STA_ID)) {
1475
-            // can we get state object from name ?
1476
-            EE_Registry::instance()->load_model('State');
1477
-            $state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
1478
-            $STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1479
-        }
1480
-        // get Country ISO
1481
-        $CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1482
-        if (! empty($CNT_ISO)) {
1483
-            // can we get country object from name ?
1484
-            EE_Registry::instance()->load_model('Country');
1485
-            $country = EEM_Country::instance()->get_col(
1486
-                array(array('CNT_name' => $CNT_ISO), 'limit' => 1),
1487
-                'CNT_ISO'
1488
-            );
1489
-            $CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1490
-        }
1491
-        // grab attendee data
1492
-        $attendee_data = array(
1493
-            'ATT_fname'    => ! empty($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : '',
1494
-            'ATT_lname'    => ! empty($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : '',
1495
-            'ATT_email'    => ! empty($_REQUEST['email']) ? sanitize_email($_REQUEST['email']) : '',
1496
-            'ATT_address'  => ! empty($_REQUEST['address']) ? sanitize_text_field($_REQUEST['address']) : '',
1497
-            'ATT_address2' => ! empty($_REQUEST['address2']) ? sanitize_text_field($_REQUEST['address2']) : '',
1498
-            'ATT_city'     => ! empty($_REQUEST['city']) ? sanitize_text_field($_REQUEST['city']) : '',
1499
-            'STA_ID'       => $STA_ID,
1500
-            'CNT_ISO'      => $CNT_ISO,
1501
-            'ATT_zip'      => ! empty($_REQUEST['zip']) ? sanitize_text_field($_REQUEST['zip']) : '',
1502
-            'ATT_phone'    => ! empty($_REQUEST['phone']) ? sanitize_text_field($_REQUEST['phone']) : '',
1503
-        );
1504
-        // validate the email address since it is the most important piece of info
1505
-        if (empty($attendee_data['ATT_email']) || $attendee_data['ATT_email'] !== $_REQUEST['email']) {
1506
-            EE_Error::add_error(
1507
-                __('An invalid email address was submitted.', 'event_espresso'),
1508
-                __FILE__,
1509
-                __FUNCTION__,
1510
-                __LINE__
1511
-            );
1512
-        }
1513
-        // does this attendee already exist in the db ? we're searching using a combination of first name, last name, AND email address
1514
-        if (! empty($attendee_data['ATT_fname'])
1515
-            && ! empty($attendee_data['ATT_lname'])
1516
-            && ! empty($attendee_data['ATT_email'])
1517
-        ) {
1518
-            $existing_attendee = EE_Registry::instance()->LIB->EEM_Attendee->find_existing_attendee(
1519
-                array(
1520
-                    'ATT_fname' => $attendee_data['ATT_fname'],
1521
-                    'ATT_lname' => $attendee_data['ATT_lname'],
1522
-                    'ATT_email' => $attendee_data['ATT_email'],
1523
-                )
1524
-            );
1525
-            if ($existing_attendee instanceof EE_Attendee) {
1526
-                return $existing_attendee;
1527
-            }
1528
-        }
1529
-        // no existing attendee? kk let's create a new one
1530
-        // kinda lame, but we need a first and last name to create an attendee, so use the email address if those don't exist
1531
-        $attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1532
-            ? $attendee_data['ATT_fname']
1533
-            : $attendee_data['ATT_email'];
1534
-        $attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1535
-            ? $attendee_data['ATT_lname']
1536
-            : $attendee_data['ATT_email'];
1537
-        return EE_Attendee::new_instance($attendee_data);
1538
-    }
1539
-
1540
-
1541
-
1542
-    /********************************************************************************************************/
1543
-    /****************************************  PROCESS REG STEP  *****************************************/
1544
-    /********************************************************************************************************/
1545
-    /**
1546
-     * process_reg_step
1547
-     *
1548
-     * @return boolean
1549
-     * @throws \EE_Error
1550
-     */
1551
-    public function process_reg_step()
1552
-    {
1553
-        // how have they chosen to pay?
1554
-        $this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1555
-            ? 'no_payment_required'
1556
-            : $this->_get_selected_method_of_payment(true);
1557
-        // choose your own adventure based on method_of_payment
1558
-        switch ($this->checkout->selected_method_of_payment) {
1559
-
1560
-            case 'events_sold_out' :
1561
-                $this->checkout->redirect     = true;
1562
-                $this->checkout->redirect_url = $this->checkout->cancel_page_url;
1563
-                $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1564
-                // mark this reg step as completed
1565
-                $this->set_completed();
1566
-                return false;
1567
-                break;
1568
-
1569
-            case 'payments_closed' :
1570
-                if (apply_filters(
1571
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__payments_closed__display_success',
1572
-                    false
1573
-                )) {
1574
-                    EE_Error::add_success(
1575
-                        __('no payment required at this time.', 'event_espresso'),
1576
-                        __FILE__,
1577
-                        __FUNCTION__,
1578
-                        __LINE__
1579
-                    );
1580
-                }
1581
-                // mark this reg step as completed
1582
-                $this->set_completed();
1583
-                return true;
1584
-                break;
1585
-
1586
-            case 'no_payment_required' :
1587
-                if (apply_filters(
1588
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1589
-                    false
1590
-                )) {
1591
-                    EE_Error::add_success(
1592
-                        __('no payment required.', 'event_espresso'),
1593
-                        __FILE__,
1594
-                        __FUNCTION__,
1595
-                        __LINE__
1596
-                    );
1597
-                }
1598
-                // mark this reg step as completed
1599
-                $this->set_completed();
1600
-                return true;
1601
-                break;
1602
-
1603
-            default:
1604
-                $registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1605
-                    EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1606
-                );
1607
-                $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1608
-                    $registrations,
1609
-                    EE_Registry::instance()->SSN->checkout()->revisit
1610
-                );
1611
-                // calculate difference between the two arrays
1612
-                $registrations = array_diff($registrations, $ejected_registrations);
1613
-                if (empty($registrations)) {
1614
-                    $this->_redirect_because_event_sold_out();
1615
-                    return false;
1616
-                }
1617
-                $payment_successful = $this->_process_payment();
1618
-                if ($payment_successful) {
1619
-                    $this->checkout->continue_reg = true;
1620
-                    $this->_maybe_set_completed($this->checkout->payment_method);
1621
-                } else {
1622
-                    $this->checkout->continue_reg = false;
1623
-                }
1624
-                return $payment_successful;
1625
-
1626
-        }
1627
-    }
1628
-
1629
-
1630
-    /**
1631
-     * _redirect_because_event_sold_out
1632
-     *
1633
-     * @access protected
1634
-     * @return void
1635
-     */
1636
-    protected function _redirect_because_event_sold_out()
1637
-    {
1638
-        $this->checkout->continue_reg = false;
1639
-        // set redirect URL
1640
-        $this->checkout->redirect_url = add_query_arg(
1641
-            array('e_reg_url_link' => $this->checkout->reg_url_link),
1642
-            $this->checkout->current_step->reg_step_url()
1643
-        );
1644
-        $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1645
-    }
1646
-
1647
-
1648
-    /**
1649
-     * _maybe_set_completed
1650
-     *
1651
-     * @access protected
1652
-     * @param \EE_Payment_Method $payment_method
1653
-     * @return void
1654
-     * @throws \EE_Error
1655
-     */
1656
-    protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1657
-    {
1658
-        switch ($payment_method->type_obj()->payment_occurs()) {
1659
-            case EE_PMT_Base::offsite :
1660
-                break;
1661
-            case EE_PMT_Base::onsite :
1662
-            case EE_PMT_Base::offline :
1663
-                // mark this reg step as completed
1664
-                $this->set_completed();
1665
-                break;
1666
-        }
1667
-    }
1668
-
1669
-
1670
-    /**
1671
-     *    update_reg_step
1672
-     *    this is the final step after a user  revisits the site to retry a payment
1673
-     *
1674
-     * @return boolean
1675
-     * @throws \EE_Error
1676
-     */
1677
-    public function update_reg_step()
1678
-    {
1679
-        $success = true;
1680
-        // if payment required
1681
-        if ($this->checkout->transaction->total() > 0) {
1682
-            do_action(
1683
-                'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1684
-                $this->checkout->transaction
1685
-            );
1686
-            // attempt payment via payment method
1687
-            $success = $this->process_reg_step();
1688
-        }
1689
-        if ($success && ! $this->checkout->redirect) {
1690
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1691
-                $this->checkout->transaction->ID()
1692
-            );
1693
-            // set return URL
1694
-            $this->checkout->redirect_url = add_query_arg(
1695
-                array('e_reg_url_link' => $this->checkout->reg_url_link),
1696
-                $this->checkout->thank_you_page_url
1697
-            );
1698
-        }
1699
-        return $success;
1700
-    }
1701
-
1702
-
1703
-    /**
1704
-     *    _process_payment
1705
-     *
1706
-     * @access private
1707
-     * @return    bool
1708
-     * @throws \EE_Error
1709
-     */
1710
-    private function _process_payment()
1711
-    {
1712
-        // basically confirm that the event hasn't sold out since they hit the page
1713
-        if (! $this->_last_second_ticket_verifications()) {
1714
-            return false;
1715
-        }
1716
-        // ya gotta make a choice man
1717
-        if (empty($this->checkout->selected_method_of_payment)) {
1718
-            $this->checkout->json_response->set_plz_select_method_of_payment(
1719
-                __('Please select a method of payment before proceeding.', 'event_espresso')
1720
-            );
1721
-            return false;
1722
-        }
1723
-        // get EE_Payment_Method object
1724
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1725
-            return false;
1726
-        }
1727
-        // setup billing form
1728
-        if ($this->checkout->payment_method->is_on_site()) {
1729
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1730
-                $this->checkout->payment_method
1731
-            );
1732
-            // bad billing form ?
1733
-            if (! $this->_billing_form_is_valid()) {
1734
-                return false;
1735
-            }
1736
-        }
1737
-        // ensure primary registrant has been fully processed
1738
-        if (! $this->_setup_primary_registrant_prior_to_payment()) {
1739
-            return false;
1740
-        }
1741
-        // if session is close to expiring (under 10 minutes by default)
1742
-        if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1743
-            // add some time to session expiration so that payment can be completed
1744
-            EE_Registry::instance()->SSN->extend_expiration();
1745
-        }
1746
-        /** @type EE_Transaction_Processor $transaction_processor */
1747
-        //$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1748
-        // in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations for events with a default reg status of Approved
1749
-        //$transaction_processor->toggle_registration_statuses_for_default_approved_events( $this->checkout->transaction, $this->checkout->reg_cache_where_params );
1750
-        // attempt payment
1751
-        $payment = $this->_attempt_payment($this->checkout->payment_method);
1752
-        // process results
1753
-        $payment = $this->_validate_payment($payment);
1754
-        $payment = $this->_post_payment_processing($payment);
1755
-        // verify payment
1756
-        if ($payment instanceof EE_Payment) {
1757
-            // store that for later
1758
-            $this->checkout->payment = $payment;
1759
-            // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1760
-            $this->checkout->transaction->toggle_failed_transaction_status();
1761
-            $payment_status = $payment->status();
1762
-            if (
1763
-                $payment_status === EEM_Payment::status_id_approved
1764
-                || $payment_status === EEM_Payment::status_id_pending
1765
-            ) {
1766
-                return true;
1767
-            } else {
1768
-                return false;
1769
-            }
1770
-        } else if ($payment === true) {
1771
-            // please note that offline payment methods will NOT make a payment,
1772
-            // but instead just mark themselves as the PMD_ID on the transaction, and return true
1773
-            $this->checkout->payment = $payment;
1774
-            return true;
1775
-        }
1776
-        // where's my money?
1777
-        return false;
1778
-    }
1779
-
1780
-
1781
-    /**
1782
-     * _last_second_ticket_verifications
1783
-     *
1784
-     * @access public
1785
-     * @return bool
1786
-     */
1787
-    protected function _last_second_ticket_verifications()
1788
-    {
1789
-        // don't bother re-validating if not a return visit
1790
-        if (! $this->checkout->revisit) {
1791
-            return true;
1792
-        }
1793
-        $registrations = $this->checkout->transaction->registrations();
1794
-        if (empty($registrations)) {
1795
-            return false;
1796
-        }
1797
-        foreach ($registrations as $registration) {
1798
-            if ($registration instanceof EE_Registration) {
1799
-                $event = $registration->event_obj();
1800
-                if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1801
-                    EE_Error::add_error(
1802
-                        apply_filters(
1803
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1804
-                            sprintf(
1805
-                                __('It appears that the %1$s event that you were about to make a payment for has sold out since you first registered and/or arrived at this page. Please refresh the page and try again. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
1806
-                                    'event_espresso'),
1807
-                                $event->name()
1808
-                            )
1809
-                        ),
1810
-                        __FILE__,
1811
-                        __FUNCTION__,
1812
-                        __LINE__
1813
-                    );
1814
-                    return false;
1815
-                }
1816
-            }
1817
-        }
1818
-        return true;
1819
-    }
1820
-
1821
-
1822
-    /**
1823
-     * redirect_form
1824
-     *
1825
-     * @access public
1826
-     * @return bool
1827
-     * @throws \EE_Error
1828
-     */
1829
-    public function redirect_form()
1830
-    {
1831
-        $payment_method_billing_info = $this->_payment_method_billing_info(
1832
-            $this->_get_payment_method_for_selected_method_of_payment()
1833
-        );
1834
-        $html                        = $payment_method_billing_info->get_html();
1835
-        $html                        .= $this->checkout->redirect_form;
1836
-        EE_Registry::instance()->REQ->add_output($html);
1837
-        return true;
1838
-    }
1839
-
1840
-
1841
-    /**
1842
-     * _billing_form_is_valid
1843
-     *
1844
-     * @access private
1845
-     * @return bool
1846
-     * @throws \EE_Error
1847
-     */
1848
-    private function _billing_form_is_valid()
1849
-    {
1850
-        if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1851
-            return true;
1852
-        }
1853
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1854
-            if ($this->checkout->billing_form->was_submitted()) {
1855
-                $this->checkout->billing_form->receive_form_submission();
1856
-                if ($this->checkout->billing_form->is_valid()) {
1857
-                    return true;
1858
-                }
1859
-                $validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1860
-                $error_strings     = array();
1861
-                foreach ($validation_errors as $validation_error) {
1862
-                    if ($validation_error instanceof EE_Validation_Error) {
1863
-                        $form_section = $validation_error->get_form_section();
1864
-                        if ($form_section instanceof EE_Form_Input_Base) {
1865
-                            $label = $form_section->html_label_text();
1866
-                        } elseif ($form_section instanceof EE_Form_Section_Base) {
1867
-                            $label = $form_section->name();
1868
-                        } else {
1869
-                            $label = __('Validation Error', 'event_espresso');
1870
-                        }
1871
-                        $error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
1872
-                    }
1873
-                }
1874
-                EE_Error::add_error(
1875
-                    sprintf(
1876
-                        __(
1877
-                            'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
1878
-                            'event_espresso'
1879
-                        ),
1880
-                        '<br/>',
1881
-                        implode('<br/>', $error_strings)
1882
-                    ),
1883
-                    __FILE__,
1884
-                    __FUNCTION__,
1885
-                    __LINE__
1886
-                );
1887
-            } else {
1888
-                EE_Error::add_error(
1889
-                    __(
1890
-                        'The billing form was not submitted or something prevented it\'s submission.',
1891
-                        'event_espresso'
1892
-                    ),
1893
-                    __FILE__,
1894
-                    __FUNCTION__,
1895
-                    __LINE__
1896
-                );
1897
-            }
1898
-        } else {
1899
-            EE_Error::add_error(
1900
-                __('The submitted billing form is invalid possibly due to a technical reason.', 'event_espresso'),
1901
-                __FILE__,
1902
-                __FUNCTION__,
1903
-                __LINE__
1904
-            );
1905
-        }
1906
-        return false;
1907
-    }
1908
-
1909
-
1910
-    /**
1911
-     * _setup_primary_registrant_prior_to_payment
1912
-     * ensures that the primary registrant has a valid attendee object created with the critical details populated
1913
-     * (first & last name & email) and that both the transaction object and primary registration object have been saved
1914
-     * plz note that any other registrations will NOT be saved at this point (because they may not have any details
1915
-     * yet)
1916
-     *
1917
-     * @access private
1918
-     * @return bool
1919
-     * @throws \EE_Error
1920
-     */
1921
-    private function _setup_primary_registrant_prior_to_payment()
1922
-    {
1923
-        // check if transaction has a primary registrant and that it has a related Attendee object
1924
-        // if not, then we need to at least gather some primary registrant data before attempting payment
1925
-        if (
1926
-            $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1927
-            && ! $this->checkout->transaction_has_primary_registrant()
1928
-            && ! $this->_capture_primary_registration_data_from_billing_form()
1929
-        ) {
1930
-            return false;
1931
-        }
1932
-        // because saving an object clears it's cache, we need to do the chevy shuffle
1933
-        // grab the primary_registration object
1934
-        $primary_registration = $this->checkout->transaction->primary_registration();
1935
-        // at this point we'll consider a TXN to not have been failed
1936
-        $this->checkout->transaction->toggle_failed_transaction_status();
1937
-        // save the TXN ( which clears cached copy of primary_registration)
1938
-        $this->checkout->transaction->save();
1939
-        // grab TXN ID and save it to the primary_registration
1940
-        $primary_registration->set_transaction_id($this->checkout->transaction->ID());
1941
-        // save what we have so far
1942
-        $primary_registration->save();
1943
-        return true;
1944
-    }
1945
-
1946
-
1947
-    /**
1948
-     * _capture_primary_registration_data_from_billing_form
1949
-     *
1950
-     * @access private
1951
-     * @return bool
1952
-     * @throws \EE_Error
1953
-     */
1954
-    private function _capture_primary_registration_data_from_billing_form()
1955
-    {
1956
-        // convert billing form data into an attendee
1957
-        $this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
1958
-        if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
1959
-            EE_Error::add_error(
1960
-                sprintf(
1961
-                    __(
1962
-                        'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
1963
-                        'event_espresso'
1964
-                    ),
1965
-                    '<br/>',
1966
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
1967
-                ),
1968
-                __FILE__,
1969
-                __FUNCTION__,
1970
-                __LINE__
1971
-            );
1972
-            return false;
1973
-        }
1974
-        $primary_registration = $this->checkout->transaction->primary_registration();
1975
-        if (! $primary_registration instanceof EE_Registration) {
1976
-            EE_Error::add_error(
1977
-                sprintf(
1978
-                    __(
1979
-                        'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
1980
-                        'event_espresso'
1981
-                    ),
1982
-                    '<br/>',
1983
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
1984
-                ),
1985
-                __FILE__,
1986
-                __FUNCTION__,
1987
-                __LINE__
1988
-            );
1989
-            return false;
1990
-        }
1991
-        if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
1992
-              instanceof
1993
-              EE_Attendee
1994
-        ) {
1995
-            EE_Error::add_error(
1996
-                sprintf(
1997
-                    __(
1998
-                        'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
1999
-                        'event_espresso'
2000
-                    ),
2001
-                    '<br/>',
2002
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2003
-                ),
2004
-                __FILE__,
2005
-                __FUNCTION__,
2006
-                __LINE__
2007
-            );
2008
-            return false;
2009
-        }
2010
-        /** @type EE_Registration_Processor $registration_processor */
2011
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2012
-        // at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2013
-        $registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2014
-        return true;
2015
-    }
2016
-
2017
-
2018
-    /**
2019
-     * _get_payment_method_for_selected_method_of_payment
2020
-     * retrieves a valid payment method
2021
-     *
2022
-     * @access public
2023
-     * @return \EE_Payment_Method
2024
-     * @throws \EE_Error
2025
-     */
2026
-    private function _get_payment_method_for_selected_method_of_payment()
2027
-    {
2028
-        if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2029
-            $this->_redirect_because_event_sold_out();
2030
-            return null;
2031
-        }
2032
-        // get EE_Payment_Method object
2033
-        if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2034
-            $payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2035
-        } else {
2036
-            // load EEM_Payment_Method
2037
-            EE_Registry::instance()->load_model('Payment_Method');
2038
-            /** @type EEM_Payment_Method $EEM_Payment_Method */
2039
-            $EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
2040
-            $payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2041
-        }
2042
-        // verify $payment_method
2043
-        if (! $payment_method instanceof EE_Payment_Method) {
2044
-            // not a payment
2045
-            EE_Error::add_error(
2046
-                sprintf(
2047
-                    __(
2048
-                        'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2049
-                        'event_espresso'
2050
-                    ),
2051
-                    '<br/>',
2052
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2053
-                ),
2054
-                __FILE__,
2055
-                __FUNCTION__,
2056
-                __LINE__
2057
-            );
2058
-            return null;
2059
-        }
2060
-        // and verify it has a valid Payment_Method Type object
2061
-        if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2062
-            // not a payment
2063
-            EE_Error::add_error(
2064
-                sprintf(
2065
-                    __(
2066
-                        'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2067
-                        'event_espresso'
2068
-                    ),
2069
-                    '<br/>',
2070
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2071
-                ),
2072
-                __FILE__,
2073
-                __FUNCTION__,
2074
-                __LINE__
2075
-            );
2076
-            return null;
2077
-        }
2078
-        return $payment_method;
2079
-    }
2080
-
2081
-
2082
-    /**
2083
-     *    _attempt_payment
2084
-     *
2085
-     * @access    private
2086
-     * @type    EE_Payment_Method $payment_method
2087
-     * @return    mixed    EE_Payment | boolean
2088
-     * @throws \EE_Error
2089
-     */
2090
-    private function _attempt_payment(EE_Payment_Method $payment_method)
2091
-    {
2092
-        $payment = null;
2093
-        $this->checkout->transaction->save();
2094
-        $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2095
-        if (! $payment_processor instanceof EE_Payment_Processor) {
2096
-            return false;
2097
-        }
2098
-        try {
2099
-            $payment_processor->set_revisit($this->checkout->revisit);
2100
-            // generate payment object
2101
-            $payment = $payment_processor->process_payment(
2102
-                $payment_method,
2103
-                $this->checkout->transaction,
2104
-                $this->checkout->amount_owing,
2105
-                $this->checkout->billing_form,
2106
-                $this->_get_return_url($payment_method),
2107
-                'CART',
2108
-                $this->checkout->admin_request,
2109
-                true,
2110
-                $this->reg_step_url()
2111
-            );
2112
-        } catch (Exception $e) {
2113
-            $this->_handle_payment_processor_exception($e);
2114
-        }
2115
-        return $payment;
2116
-    }
2117
-
2118
-
2119
-    /**
2120
-     * _handle_payment_processor_exception
2121
-     *
2122
-     * @access protected
2123
-     * @param \Exception $e
2124
-     * @return void
2125
-     * @throws \EE_Error
2126
-     */
2127
-    protected function _handle_payment_processor_exception(Exception $e)
2128
-    {
2129
-        EE_Error::add_error(
2130
-            sprintf(
2131
-                __(
2132
-                    'The payment could not br processed due to a technical issue.%1$sPlease try again or contact %2$s for assistance.||The following Exception was thrown in %4$s on line %5$s:%1$s%3$s',
2133
-                    'event_espresso'
2134
-                ),
2135
-                '<br/>',
2136
-                EE_Registry::instance()->CFG->organization->get_pretty('email'),
2137
-                $e->getMessage(),
2138
-                $e->getFile(),
2139
-                $e->getLine()
2140
-            ),
2141
-            __FILE__,
2142
-            __FUNCTION__,
2143
-            __LINE__
2144
-        );
2145
-    }
2146
-
2147
-
2148
-    /**
2149
-     * _get_return_url
2150
-     *
2151
-     * @access protected
2152
-     * @param \EE_Payment_Method $payment_method
2153
-     * @return string
2154
-     * @throws \EE_Error
2155
-     */
2156
-    protected function _get_return_url(EE_Payment_Method $payment_method)
2157
-    {
2158
-        $return_url = '';
2159
-        switch ($payment_method->type_obj()->payment_occurs()) {
2160
-            case EE_PMT_Base::offsite :
2161
-                $return_url = add_query_arg(
2162
-                    array(
2163
-                        'action'                     => 'process_gateway_response',
2164
-                        'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2165
-                        'spco_txn'                   => $this->checkout->transaction->ID(),
2166
-                    ),
2167
-                    $this->reg_step_url()
2168
-                );
2169
-                break;
2170
-            case EE_PMT_Base::onsite :
2171
-            case EE_PMT_Base::offline :
2172
-                $return_url = $this->checkout->next_step->reg_step_url();
2173
-                break;
2174
-        }
2175
-        return $return_url;
2176
-    }
2177
-
2178
-
2179
-    /**
2180
-     * _validate_payment
2181
-     *
2182
-     * @access private
2183
-     * @param EE_Payment $payment
2184
-     * @return EE_Payment | FALSE
2185
-     * @throws \EE_Error
2186
-     */
2187
-    private function _validate_payment($payment = null)
2188
-    {
2189
-        if ($this->checkout->payment_method->is_off_line()) {
2190
-            return true;
2191
-        }
2192
-        // verify payment object
2193
-        if (! $payment instanceof EE_Payment) {
2194
-            // not a payment
2195
-            EE_Error::add_error(
2196
-                sprintf(
2197
-                    __(
2198
-                        'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2199
-                        'event_espresso'
2200
-                    ),
2201
-                    '<br/>',
2202
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2203
-                ),
2204
-                __FILE__,
2205
-                __FUNCTION__,
2206
-                __LINE__
2207
-            );
2208
-            return false;
2209
-        }
2210
-        return $payment;
2211
-    }
2212
-
2213
-
2214
-    /**
2215
-     * _post_payment_processing
2216
-     *
2217
-     * @access private
2218
-     * @param EE_Payment|bool $payment
2219
-     * @return bool
2220
-     * @throws \EE_Error
2221
-     */
2222
-    private function _post_payment_processing($payment = null)
2223
-    {
2224
-        // Off-Line payment?
2225
-        if ($payment === true) {
2226
-            //$this->_setup_redirect_for_next_step();
2227
-            return true;
2228
-            // On-Site payment?
2229
-        } else if ($this->checkout->payment_method->is_on_site()) {
2230
-            if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2231
-                //$this->_setup_redirect_for_next_step();
2232
-                $this->checkout->continue_reg = false;
2233
-            }
2234
-            // Off-Site payment?
2235
-        } else if ($this->checkout->payment_method->is_off_site()) {
2236
-            // if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2237
-            if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2238
-                do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2239
-                $this->checkout->redirect      = true;
2240
-                $this->checkout->redirect_form = $payment->redirect_form();
2241
-                $this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2242
-                // set JSON response
2243
-                $this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2244
-                // set cron job for finalizing the TXN
2245
-                // in case the user does not return from the off-site gateway
2246
-                EE_Cron_Tasks::schedule_finalize_abandoned_transactions_check(
2247
-                    EE_Registry::instance()->SSN->expiration() + 1,
2248
-                    $this->checkout->transaction->ID()
2249
-                );
2250
-                // and lastly, let's bump the payment status to pending
2251
-                $payment->set_status(EEM_Payment::status_id_pending);
2252
-                $payment->save();
2253
-            } else {
2254
-                // not a payment
2255
-                $this->checkout->continue_reg = false;
2256
-                EE_Error::add_error(
2257
-                    sprintf(
2258
-                        __(
2259
-                            'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2260
-                            'event_espresso'
2261
-                        ),
2262
-                        '<br/>',
2263
-                        EE_Registry::instance()->CFG->organization->get_pretty('email')
2264
-                    ),
2265
-                    __FILE__,
2266
-                    __FUNCTION__,
2267
-                    __LINE__
2268
-                );
2269
-            }
2270
-        } else {
2271
-            // ummm ya... not Off-Line, not On-Site, not off-Site ????
2272
-            $this->checkout->continue_reg = false;
2273
-            return false;
2274
-        }
2275
-        return $payment;
2276
-    }
2277
-
2278
-
2279
-
2280
-    /**
2281
-     *    _setup_redirect_for_next_step
2282
-     *
2283
-     * @access private
2284
-     * @return    void
2285
-     */
2286
-    //private function _setup_redirect_for_next_step() {
2287
-    //$this->checkout->redirect = TRUE;
2288
-    //$this->checkout->redirect_url = $this->checkout->next_step->reg_step_url();
2289
-    // set JSON response
2290
-    //$this->checkout->json_response->set_redirect_url( $this->checkout->redirect_url );
2291
-    //}
2292
-    /**
2293
-     *    _process_payment_status
2294
-     *
2295
-     * @access private
2296
-     * @type    EE_Payment $payment
2297
-     * @param string       $payment_occurs
2298
-     * @return bool
2299
-     * @throws \EE_Error
2300
-     */
2301
-    private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2302
-    {
2303
-        // off-line payment? carry on
2304
-        if ($payment_occurs === EE_PMT_Base::offline) {
2305
-            return true;
2306
-        }
2307
-        // verify payment validity
2308
-        if ($payment instanceof EE_Payment) {
2309
-            do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2310
-            $msg = $payment->gateway_response();
2311
-            // check results
2312
-            switch ($payment->status()) {
2313
-                // good payment
2314
-                case EEM_Payment::status_id_approved :
2315
-                    EE_Error::add_success(
2316
-                        __('Your payment was processed successfully.', 'event_espresso'),
2317
-                        __FILE__,
2318
-                        __FUNCTION__,
2319
-                        __LINE__
2320
-                    );
2321
-                    return true;
2322
-                    break;
2323
-                // slow payment
2324
-                case EEM_Payment::status_id_pending :
2325
-                    if (empty($msg)) {
2326
-                        $msg = __(
2327
-                            'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2328
-                            'event_espresso'
2329
-                        );
2330
-                    }
2331
-                    EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2332
-                    return true;
2333
-                    break;
2334
-                // don't wanna payment
2335
-                case EEM_Payment::status_id_cancelled :
2336
-                    if (empty($msg)) {
2337
-                        $msg = _n(
2338
-                            'Payment cancelled. Please try again.',
2339
-                            'Payment cancelled. Please try again or select another method of payment.',
2340
-                            count($this->checkout->available_payment_methods),
2341
-                            'event_espresso'
2342
-                        );
2343
-                    }
2344
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2345
-                    return false;
2346
-                    break;
2347
-                // not enough payment
2348
-                case EEM_Payment::status_id_declined :
2349
-                    if (empty($msg)) {
2350
-                        $msg = _n(
2351
-                            'We\'re sorry but your payment was declined. Please try again.',
2352
-                            'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2353
-                            count($this->checkout->available_payment_methods),
2354
-                            'event_espresso'
2355
-                        );
2356
-                    }
2357
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2358
-                    return false;
2359
-                    break;
2360
-                // bad payment
2361
-                case EEM_Payment::status_id_failed :
2362
-                    if (! empty($msg)) {
2363
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2364
-                        return false;
2365
-                    }
2366
-                    // default to error below
2367
-                    break;
2368
-            }
2369
-        }
2370
-        // off-site payment gateway responses are too unreliable, so let's just assume that
2371
-        // the payment processing is just running slower than the registrant's request
2372
-        if ($payment_occurs === EE_PMT_Base::offsite) {
2373
-            return true;
2374
-        }
2375
-        EE_Error::add_error(
2376
-            sprintf(
2377
-                __(
2378
-                    'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2379
-                    'event_espresso'
2380
-                ),
2381
-                '<br/>',
2382
-                EE_Registry::instance()->CFG->organization->get_pretty('email')
2383
-            ),
2384
-            __FILE__,
2385
-            __FUNCTION__,
2386
-            __LINE__
2387
-        );
2388
-        return false;
2389
-    }
2390
-
2391
-
2392
-
2393
-
2394
-
2395
-
2396
-    /********************************************************************************************************/
2397
-    /**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2398
-    /********************************************************************************************************/
2399
-    /**
2400
-     * process_gateway_response
2401
-     * this is the return point for Off-Site Payment Methods
2402
-     * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2403
-     * otherwise, it will load up the last payment made for the TXN.
2404
-     * If the payment retrieved looks good, it will then either:
2405
-     *    complete the current step and allow advancement to the next reg step
2406
-     *        or present the payment options again
2407
-     *
2408
-     * @access private
2409
-     * @return EE_Payment | FALSE
2410
-     * @throws \EE_Error
2411
-     */
2412
-    public function process_gateway_response()
2413
-    {
2414
-        $payment = null;
2415
-        // how have they chosen to pay?
2416
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2417
-        // get EE_Payment_Method object
2418
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2419
-            $this->checkout->continue_reg = false;
2420
-            return false;
2421
-        }
2422
-        if (! $this->checkout->payment_method->is_off_site()) {
2423
-            return false;
2424
-        }
2425
-        $this->_validate_offsite_return();
2426
-        // DEBUG LOG
2427
-        //$this->checkout->log(
2428
-        //	__CLASS__, __FUNCTION__, __LINE__,
2429
-        //	array(
2430
-        //		'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2431
-        //		'payment_method' => $this->checkout->payment_method,
2432
-        //	),
2433
-        //	true
2434
-        //);
2435
-        // verify TXN
2436
-        if ($this->checkout->transaction instanceof EE_Transaction) {
2437
-            $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2438
-            if (! $gateway instanceof EE_Offsite_Gateway) {
2439
-                $this->checkout->continue_reg = false;
2440
-                return false;
2441
-            }
2442
-            $payment = $this->_process_off_site_payment($gateway);
2443
-            $payment = $this->_process_cancelled_payments($payment);
2444
-            $payment = $this->_validate_payment($payment);
2445
-            // if payment was not declined by the payment gateway or cancelled by the registrant
2446
-            if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2447
-                //$this->_setup_redirect_for_next_step();
2448
-                // store that for later
2449
-                $this->checkout->payment = $payment;
2450
-                // mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2451
-                // because we will complete this step during the IPN processing then
2452
-                if ($gateway instanceof EE_Offsite_Gateway && ! $this->handle_IPN_in_this_request()) {
2453
-                    $this->set_completed();
2454
-                }
2455
-                return true;
2456
-            }
2457
-        }
2458
-        // DEBUG LOG
2459
-        //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2460
-        //	array( 'payment' => $payment )
2461
-        //);
2462
-        $this->checkout->continue_reg = false;
2463
-        return false;
2464
-    }
2465
-
2466
-
2467
-    /**
2468
-     * _validate_return
2469
-     *
2470
-     * @access private
2471
-     * @return void
2472
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2473
-     * @throws \EE_Error
2474
-     */
2475
-    private function _validate_offsite_return()
2476
-    {
2477
-        $TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2478
-        if ($TXN_ID !== $this->checkout->transaction->ID()) {
2479
-            // Houston... we might have a problem
2480
-            $invalid_TXN = false;
2481
-            // first gather some info
2482
-            $valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2483
-            $primary_registrant = $valid_TXN instanceof EE_Transaction
2484
-                ? $valid_TXN->primary_registration()
2485
-                : null;
2486
-            // let's start by retrieving the cart for this TXN
2487
-            $cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2488
-            if ($cart instanceof EE_Cart) {
2489
-                // verify that the current cart has tickets
2490
-                $tickets = $cart->get_tickets();
2491
-                if (empty($tickets)) {
2492
-                    $invalid_TXN = true;
2493
-                }
2494
-            } else {
2495
-                $invalid_TXN = true;
2496
-            }
2497
-            $valid_TXN_SID = $primary_registrant instanceof EE_Registration
2498
-                ? $primary_registrant->session_ID()
2499
-                : null;
2500
-            // validate current Session ID and compare against valid TXN session ID
2501
-            if (
2502
-                $invalid_TXN // if this is already true, then skip other checks
2503
-                || EE_Session::instance()->id() === null
2504
-                || (
2505
-                    // WARNING !!!
2506
-                    // this could be PayPal sending back duplicate requests (ya they do that)
2507
-                    // or it **could** mean someone is simply registering AGAIN after having just done so
2508
-                    // so now we need to determine if this current TXN looks valid or not
2509
-                    // and whether this reg step has even been started ?
2510
-                    EE_Session::instance()->id() === $valid_TXN_SID
2511
-                    // really? you're half way through this reg step, but you never started it ?
2512
-                    && $this->checkout->transaction->reg_step_completed($this->slug()) === false
2513
-                )
2514
-            ) {
2515
-                $invalid_TXN = true;
2516
-            }
2517
-            if ($invalid_TXN) {
2518
-                // is the valid TXN completed ?
2519
-                if ($valid_TXN instanceof EE_Transaction) {
2520
-                    // has this step even been started ?
2521
-                    $reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2522
-                    if ($reg_step_completed !== false && $reg_step_completed !== true) {
2523
-                        // so it **looks** like this is a double request from PayPal
2524
-                        // so let's try to pick up where we left off
2525
-                        $this->checkout->transaction = $valid_TXN;
2526
-                        $this->checkout->refresh_all_entities(true);
2527
-                        return;
2528
-                    }
2529
-                }
2530
-                // you appear to be lost?
2531
-                $this->_redirect_wayward_request($primary_registrant);
2532
-            }
2533
-        }
2534
-    }
2535
-
2536
-
2537
-    /**
2538
-     * _redirect_wayward_request
2539
-     *
2540
-     * @access private
2541
-     * @param \EE_Registration|null $primary_registrant
2542
-     * @return bool
2543
-     * @throws \EE_Error
2544
-     */
2545
-    private function _redirect_wayward_request(EE_Registration $primary_registrant)
2546
-    {
2547
-        if (! $primary_registrant instanceof EE_Registration) {
2548
-            // try redirecting based on the current TXN
2549
-            $primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2550
-                ? $this->checkout->transaction->primary_registration()
2551
-                : null;
2552
-        }
2553
-        if (! $primary_registrant instanceof EE_Registration) {
2554
-            EE_Error::add_error(
2555
-                sprintf(
2556
-                    __(
2557
-                        'Invalid information was received from the Off-Site Payment Processor and your Transaction details could not be retrieved from the database.%1$sPlease try again or contact %2$s for assistance.',
2558
-                        'event_espresso'
2559
-                    ),
2560
-                    '<br/>',
2561
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2562
-                ),
2563
-                __FILE__,
2564
-                __FUNCTION__,
2565
-                __LINE__
2566
-            );
2567
-            return false;
2568
-        }
2569
-        // make sure transaction is not locked
2570
-        $this->checkout->transaction->unlock();
2571
-        wp_safe_redirect(
2572
-            add_query_arg(
2573
-                array(
2574
-                    'e_reg_url_link' => $primary_registrant->reg_url_link(),
2575
-                ),
2576
-                $this->checkout->thank_you_page_url
2577
-            )
2578
-        );
2579
-        exit();
2580
-    }
2581
-
2582
-
2583
-    /**
2584
-     * _process_off_site_payment
2585
-     *
2586
-     * @access private
2587
-     * @param \EE_Offsite_Gateway $gateway
2588
-     * @return \EE_Payment
2589
-     * @throws \EE_Error
2590
-     */
2591
-    private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2592
-    {
2593
-        try {
2594
-            $request_data = \EE_Registry::instance()->REQ->params();
2595
-            // if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2596
-            $this->set_handle_IPN_in_this_request(
2597
-                $gateway->handle_IPN_in_this_request($request_data, false)
2598
-            );
2599
-            if ($this->handle_IPN_in_this_request()) {
2600
-                // get payment details and process results
2601
-                /** @type EE_Payment_Processor $payment_processor */
2602
-                $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2603
-                $payment           = $payment_processor->process_ipn(
2604
-                    $request_data,
2605
-                    $this->checkout->transaction,
2606
-                    $this->checkout->payment_method,
2607
-                    true,
2608
-                    false
2609
-                );
2610
-                //$payment_source = 'process_ipn';
2611
-            } else {
2612
-                $payment = $this->checkout->transaction->last_payment();
2613
-                //$payment_source = 'last_payment';
2614
-            }
2615
-        } catch (Exception $e) {
2616
-            // let's just eat the exception and try to move on using any previously set payment info
2617
-            $payment = $this->checkout->transaction->last_payment();
2618
-            //$payment_source = 'last_payment after Exception';
2619
-            // but if we STILL don't have a payment object
2620
-            if (! $payment instanceof EE_Payment) {
2621
-                // then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2622
-                $this->_handle_payment_processor_exception($e);
2623
-            }
2624
-        }
2625
-        // DEBUG LOG
2626
-        //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2627
-        //	array(
2628
-        //		'process_ipn_payment' => $payment,
2629
-        //		'payment_source'      => $payment_source,
2630
-        //	)
2631
-        //);
2632
-        return $payment;
2633
-    }
2634
-
2635
-
2636
-    /**
2637
-     * _process_cancelled_payments
2638
-     * just makes sure that the payment status gets updated correctly
2639
-     * so tha tan error isn't generated during payment validation
2640
-     *
2641
-     * @access private
2642
-     * @param EE_Payment $payment
2643
-     * @return EE_Payment | FALSE
2644
-     * @throws \EE_Error
2645
-     */
2646
-    private function _process_cancelled_payments($payment = null)
2647
-    {
2648
-        if (
2649
-            $payment instanceof EE_Payment
2650
-            && isset($_REQUEST['ee_cancel_payment'])
2651
-            && $payment->status() === EEM_Payment::status_id_failed
2652
-        ) {
2653
-            $payment->set_status(EEM_Payment::status_id_cancelled);
2654
-        }
2655
-        return $payment;
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     *    get_transaction_details_for_gateways
2661
-     *
2662
-     * @access    public
2663
-     * @return    int
2664
-     * @throws \EE_Error
2665
-     */
2666
-    public function get_transaction_details_for_gateways()
2667
-    {
2668
-        $txn_details = array();
2669
-        // ya gotta make a choice man
2670
-        if (empty($this->checkout->selected_method_of_payment)) {
2671
-            $txn_details = array(
2672
-                'error' => __('Please select a method of payment before proceeding.', 'event_espresso'),
2673
-            );
2674
-        }
2675
-        // get EE_Payment_Method object
2676
-        if (
2677
-            empty($txn_details)
2678
-            &&
2679
-            ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2680
-        ) {
2681
-            $txn_details = array(
2682
-                'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2683
-                'error'                      => __(
2684
-                    'A valid Payment Method could not be determined.',
2685
-                    'event_espresso'
2686
-                ),
2687
-            );
2688
-        }
2689
-        if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2690
-            $return_url  = $this->_get_return_url($this->checkout->payment_method);
2691
-            $txn_details = array(
2692
-                'TXN_ID'         => $this->checkout->transaction->ID(),
2693
-                'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2694
-                'TXN_total'      => $this->checkout->transaction->total(),
2695
-                'TXN_paid'       => $this->checkout->transaction->paid(),
2696
-                'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2697
-                'STS_ID'         => $this->checkout->transaction->status_ID(),
2698
-                'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2699
-                'payment_amount' => $this->checkout->amount_owing,
2700
-                'return_url'     => $return_url,
2701
-                'cancel_url'     => add_query_arg(array('ee_cancel_payment' => true), $return_url),
2702
-                'notify_url'     => EE_Config::instance()->core->txn_page_url(
2703
-                    array(
2704
-                        'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2705
-                        'ee_payment_method' => $this->checkout->payment_method->slug(),
2706
-                    )
2707
-                ),
2708
-            );
2709
-        }
2710
-        echo wp_json_encode($txn_details);
2711
-        exit();
2712
-    }
2713
-
2714
-
2715
-    /**
2716
-     *    __sleep
2717
-     * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2718
-     * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2719
-     * reg form, because if needed, it will be regenerated anyways
2720
-     *
2721
-     * @return array
2722
-     */
2723
-    public function __sleep()
2724
-    {
2725
-        // remove the reg form and the checkout
2726
-        return array_diff(array_keys(get_object_vars($this)), array('reg_form', 'checkout', 'line_item_display'));
2727
-    }
18
+	/**
19
+	 * @access protected
20
+	 * @var EE_Line_Item_Display $Line_Item_Display
21
+	 */
22
+	protected $line_item_display;
23
+
24
+	/**
25
+	 * @access protected
26
+	 * @var boolean $handle_IPN_in_this_request
27
+	 */
28
+	protected $handle_IPN_in_this_request = false;
29
+
30
+
31
+	/**
32
+	 *    set_hooks - for hooking into EE Core, other modules, etc
33
+	 *
34
+	 * @access    public
35
+	 * @return    void
36
+	 */
37
+	public static function set_hooks()
38
+	{
39
+		add_filter(
40
+			'FHEE__SPCO__EE_Line_Item_Filter_Collection',
41
+			array('EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters')
42
+		);
43
+		add_action(
44
+			'wp_ajax_switch_spco_billing_form',
45
+			array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
46
+		);
47
+		add_action(
48
+			'wp_ajax_nopriv_switch_spco_billing_form',
49
+			array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
50
+		);
51
+		add_action('wp_ajax_save_payer_details', array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details'));
52
+		add_action(
53
+			'wp_ajax_nopriv_save_payer_details',
54
+			array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details')
55
+		);
56
+		add_action(
57
+			'wp_ajax_get_transaction_details_for_gateways',
58
+			array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
59
+		);
60
+		add_action(
61
+			'wp_ajax_nopriv_get_transaction_details_for_gateways',
62
+			array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
63
+		);
64
+		add_filter(
65
+			'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
66
+			array('EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'),
67
+			10,
68
+			1
69
+		);
70
+	}
71
+
72
+
73
+	/**
74
+	 *    ajax switch_spco_billing_form
75
+	 *
76
+	 * @throws \EE_Error
77
+	 */
78
+	public static function switch_spco_billing_form()
79
+	{
80
+		EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
81
+	}
82
+
83
+
84
+	/**
85
+	 *    ajax save_payer_details
86
+	 *
87
+	 * @throws \EE_Error
88
+	 */
89
+	public static function save_payer_details()
90
+	{
91
+		EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
92
+	}
93
+
94
+
95
+	/**
96
+	 *    ajax get_transaction_details
97
+	 *
98
+	 * @throws \EE_Error
99
+	 */
100
+	public static function get_transaction_details()
101
+	{
102
+		EED_Single_Page_Checkout::process_ajax_request('get_transaction_details_for_gateways');
103
+	}
104
+
105
+
106
+	/**
107
+	 * bypass_recaptcha_for_load_payment_method
108
+	 *
109
+	 * @access public
110
+	 * @return array
111
+	 */
112
+	public static function bypass_recaptcha_for_load_payment_method()
113
+	{
114
+		return array(
115
+			'EESID'  => EE_Registry::instance()->SSN->id(),
116
+			'step'   => 'payment_options',
117
+			'action' => 'spco_billing_form',
118
+		);
119
+	}
120
+
121
+
122
+	/**
123
+	 *    class constructor
124
+	 *
125
+	 * @access    public
126
+	 * @param    EE_Checkout $checkout
127
+	 */
128
+	public function __construct(EE_Checkout $checkout)
129
+	{
130
+		$this->_slug     = 'payment_options';
131
+		$this->_name     = __('Payment Options', 'event_espresso');
132
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
133
+		$this->checkout  = $checkout;
134
+		$this->_reset_success_message();
135
+		$this->set_instructions(
136
+			__(
137
+				'Please select a method of payment and provide any necessary billing information before proceeding.',
138
+				'event_espresso'
139
+			)
140
+		);
141
+	}
142
+
143
+
144
+	/**
145
+	 * @return null
146
+	 */
147
+	public function line_item_display()
148
+	{
149
+		return $this->line_item_display;
150
+	}
151
+
152
+
153
+	/**
154
+	 * @param null $line_item_display
155
+	 */
156
+	public function set_line_item_display($line_item_display)
157
+	{
158
+		$this->line_item_display = $line_item_display;
159
+	}
160
+
161
+
162
+	/**
163
+	 * @return boolean
164
+	 */
165
+	public function handle_IPN_in_this_request()
166
+	{
167
+		return $this->handle_IPN_in_this_request;
168
+	}
169
+
170
+
171
+	/**
172
+	 * @param boolean $handle_IPN_in_this_request
173
+	 */
174
+	public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
175
+	{
176
+		$this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
177
+	}
178
+
179
+
180
+	/**
181
+	 * translate_js_strings
182
+	 *
183
+	 * @return void
184
+	 */
185
+	public function translate_js_strings()
186
+	{
187
+		EE_Registry::$i18n_js_strings['no_payment_method']      = __(
188
+			'Please select a method of payment in order to continue.',
189
+			'event_espresso'
190
+		);
191
+		EE_Registry::$i18n_js_strings['invalid_payment_method'] = __(
192
+			'A valid method of payment could not be determined. Please refresh the page and try again.',
193
+			'event_espresso'
194
+		);
195
+		EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = __(
196
+			'Forwarding to Secure Payment Provider.',
197
+			'event_espresso'
198
+		);
199
+	}
200
+
201
+
202
+	/**
203
+	 * enqueue_styles_and_scripts
204
+	 *
205
+	 * @return void
206
+	 */
207
+	public function enqueue_styles_and_scripts()
208
+	{
209
+		$transaction = $this->checkout->transaction;
210
+		//if the transaction isn't set or nothing is owed on it, don't enqueue any JS
211
+		if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
212
+			return;
213
+		}
214
+		foreach (
215
+			EEM_Payment_Method::instance()->get_all_for_transaction($transaction,
216
+				EEM_Payment_Method::scope_cart) as $payment_method
217
+		) {
218
+			$type_obj = $payment_method->type_obj();
219
+			if ($type_obj instanceof EE_PMT_Base) {
220
+				$billing_form = $type_obj->generate_new_billing_form($transaction);
221
+				if ($billing_form instanceof EE_Form_Section_Proper) {
222
+					$billing_form->enqueue_js();
223
+				}
224
+			}
225
+		}
226
+	}
227
+
228
+
229
+	/**
230
+	 * initialize_reg_step
231
+	 *
232
+	 * @return boolean
233
+	 * @throws \EE_Error
234
+	 */
235
+	public function initialize_reg_step()
236
+	{
237
+		// TODO: if /when we implement donations, then this will need overriding
238
+		if (
239
+			// don't need payment options for:
240
+			// 	registrations made via the admin
241
+			// 	completed transactions
242
+			// 	overpaid transactions
243
+			// 	$ 0.00 transactions (no payment required)
244
+			! $this->checkout->payment_required()
245
+			// but do NOT remove if current action being called belongs to this reg step
246
+			&& ! is_callable(array($this, $this->checkout->action))
247
+			&& ! $this->completed()
248
+		) {
249
+			// and if so, then we no longer need the Payment Options step
250
+			if ($this->is_current_step()) {
251
+				$this->checkout->generate_reg_form = false;
252
+			}
253
+			$this->checkout->remove_reg_step($this->_slug);
254
+			// DEBUG LOG
255
+			//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
256
+			return false;
257
+		}
258
+		// load EEM_Payment_Method
259
+		EE_Registry::instance()->load_model('Payment_Method');
260
+		// get all active payment methods
261
+		$this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
262
+			$this->checkout->transaction,
263
+			EEM_Payment_Method::scope_cart
264
+		);
265
+		return true;
266
+	}
267
+
268
+
269
+	/**
270
+	 * @return \EE_Form_Section_Proper
271
+	 * @throws \EE_Error
272
+	 */
273
+	public function generate_reg_form()
274
+	{
275
+		// reset in case someone changes their mind
276
+		$this->_reset_selected_method_of_payment();
277
+		// set some defaults
278
+		$this->checkout->selected_method_of_payment = 'payments_closed';
279
+		$registrations_requiring_payment            = array();
280
+		$registrations_for_free_events              = array();
281
+		$registrations_requiring_pre_approval       = array();
282
+		$sold_out_events                            = array();
283
+		$insufficient_spaces_available              = array();
284
+		$no_payment_required                        = true;
285
+		// loop thru registrations to gather info
286
+		$registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
287
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
288
+			$registrations,
289
+			$this->checkout->revisit
290
+		);
291
+		foreach ($registrations as $REG_ID => $registration) {
292
+			/** @var $registration EE_Registration */
293
+			// has this registration lost it's space ?
294
+			if (isset($ejected_registrations[$REG_ID])) {
295
+				$insufficient_spaces_available[$registration->event()->ID()] = $registration->event();
296
+				continue;
297
+			}
298
+			// event requires admin approval
299
+			if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
300
+				// add event to list of events with pre-approval reg status
301
+				$registrations_requiring_pre_approval[$REG_ID] = $registration;
302
+				do_action(
303
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
304
+					$registration->event(),
305
+					$this
306
+				);
307
+				continue;
308
+			}
309
+			if (
310
+				// returning registrant
311
+				$this->checkout->revisit
312
+				// anything other than Approved
313
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
314
+				&& (
315
+					$registration->event()->is_sold_out()
316
+					|| $registration->event()->is_sold_out(true)
317
+				)
318
+			) {
319
+				// add event to list of events that are sold out
320
+				$sold_out_events[$registration->event()->ID()] = $registration->event();
321
+				do_action(
322
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
323
+					$registration->event(),
324
+					$this
325
+				);
326
+				continue;
327
+			}
328
+			// are they allowed to pay now and is there monies owing?
329
+			if ($registration->owes_monies_and_can_pay()) {
330
+				$registrations_requiring_payment[$REG_ID] = $registration;
331
+				do_action(
332
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
333
+					$registration->event(),
334
+					$this
335
+				);
336
+			} else if (
337
+				! $this->checkout->revisit
338
+				&& $registration->status_ID() !== EEM_Registration::status_id_not_approved
339
+				&& $registration->ticket()->is_free()
340
+			) {
341
+				$registrations_for_free_events[$registration->event()->ID()] = $registration;
342
+			}
343
+		}
344
+		$subsections = array();
345
+		// now decide which template to load
346
+		if (! empty($sold_out_events)) {
347
+			$subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
348
+		}
349
+		if (! empty($insufficient_spaces_available)) {
350
+			$subsections['insufficient_space'] = $this->_insufficient_spaces_available(
351
+				$insufficient_spaces_available
352
+			);
353
+		}
354
+		if (! empty($registrations_requiring_pre_approval)) {
355
+			$subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
356
+				$registrations_requiring_pre_approval
357
+			);
358
+		}
359
+		if (! empty($registrations_for_free_events)) {
360
+			$subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
361
+		}
362
+		if (! empty($registrations_requiring_payment)) {
363
+			if ($this->checkout->amount_owing > 0) {
364
+				// autoload Line_Item_Display classes
365
+				EEH_Autoloader::register_line_item_filter_autoloaders();
366
+				$line_item_filter_processor = new EE_Line_Item_Filter_Processor(
367
+					apply_filters(
368
+						'FHEE__SPCO__EE_Line_Item_Filter_Collection',
369
+						new EE_Line_Item_Filter_Collection()
370
+					),
371
+					$this->checkout->cart->get_grand_total()
372
+				);
373
+				/** @var EE_Line_Item $filtered_line_item_tree */
374
+				$filtered_line_item_tree = $line_item_filter_processor->process();
375
+				EEH_Autoloader::register_line_item_display_autoloaders();
376
+				$this->set_line_item_display(new EE_Line_Item_Display('spco'));
377
+				$subsections['payment_options'] = $this->_display_payment_options(
378
+					$this->line_item_display->display_line_item(
379
+						$filtered_line_item_tree,
380
+						array('registrations' => $registrations)
381
+					)
382
+				);
383
+				$this->checkout->amount_owing   = $filtered_line_item_tree->total();
384
+				$this->_apply_registration_payments_to_amount_owing($registrations);
385
+			}
386
+			$no_payment_required = false;
387
+		} else {
388
+			$this->_hide_reg_step_submit_button_if_revisit();
389
+		}
390
+		$this->_save_selected_method_of_payment();
391
+
392
+		$subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
393
+		$subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
394
+
395
+		return new EE_Form_Section_Proper(
396
+			array(
397
+				'name'            => $this->reg_form_name(),
398
+				'html_id'         => $this->reg_form_name(),
399
+				'subsections'     => $subsections,
400
+				'layout_strategy' => new EE_No_Layout(),
401
+			)
402
+		);
403
+	}
404
+
405
+
406
+	/**
407
+	 * add line item filters required for this reg step
408
+	 * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
409
+	 *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
410
+	 *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
411
+	 *        payment options reg step, can apply these filters via the following: apply_filters(
412
+	 *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
413
+	 *        filter collection by passing that instead of instantiating a new collection
414
+	 *
415
+	 * @param \EE_Line_Item_Filter_Collection $line_item_filter_collection
416
+	 * @return \EE_Line_Item_Filter_Collection
417
+	 * @throws \EE_Error
418
+	 */
419
+	public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
420
+	{
421
+		if (! EE_Registry::instance()->SSN instanceof EE_Session) {
422
+			return $line_item_filter_collection;
423
+		}
424
+		if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
425
+			return $line_item_filter_collection;
426
+		}
427
+		if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
428
+			return $line_item_filter_collection;
429
+		}
430
+		$line_item_filter_collection->add(
431
+			new EE_Billable_Line_Item_Filter(
432
+				EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
433
+					EE_Registry::instance()->SSN->checkout()->transaction->registrations(
434
+						EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
435
+					)
436
+				)
437
+			)
438
+		);
439
+		$line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
440
+		return $line_item_filter_collection;
441
+	}
442
+
443
+
444
+	/**
445
+	 * remove_ejected_registrations
446
+	 * if a registrant has lost their potential space at an event due to lack of payment,
447
+	 * then this method removes them from the list of registrations being paid for during this request
448
+	 *
449
+	 * @param \EE_Registration[] $registrations
450
+	 * @return \EE_Registration[]
451
+	 * @throws \EE_Error
452
+	 */
453
+	public static function remove_ejected_registrations(array $registrations)
454
+	{
455
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
456
+			$registrations,
457
+			EE_Registry::instance()->SSN->checkout()->revisit
458
+		);
459
+		foreach ($registrations as $REG_ID => $registration) {
460
+			// has this registration lost it's space ?
461
+			if (isset($ejected_registrations[$REG_ID])) {
462
+				unset($registrations[$REG_ID]);
463
+				continue;
464
+			}
465
+		}
466
+		return $registrations;
467
+	}
468
+
469
+
470
+	/**
471
+	 * find_registrations_that_lost_their_space
472
+	 * If a registrant chooses an offline payment method like Invoice,
473
+	 * then no space is reserved for them at the event until they fully pay fo that site
474
+	 * (unless the event's default reg status is set to APPROVED)
475
+	 * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
476
+	 * then this method will determine which registrations have lost the ability to complete the reg process.
477
+	 *
478
+	 * @param \EE_Registration[] $registrations
479
+	 * @param bool               $revisit
480
+	 * @return array
481
+	 * @throws \EE_Error
482
+	 */
483
+	public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
484
+	{
485
+		// registrations per event
486
+		$event_reg_count = array();
487
+		// spaces left per event
488
+		$event_spaces_remaining = array();
489
+		// tickets left sorted by ID
490
+		$tickets_remaining = array();
491
+		// registrations that have lost their space
492
+		$ejected_registrations = array();
493
+		foreach ($registrations as $REG_ID => $registration) {
494
+			if (
495
+				$registration->status_ID() === EEM_Registration::status_id_approved
496
+				|| apply_filters(
497
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
498
+					false,
499
+					$registration,
500
+					$revisit
501
+				)
502
+			) {
503
+				continue;
504
+			}
505
+			$EVT_ID = $registration->event_ID();
506
+			$ticket = $registration->ticket();
507
+			if (! isset($tickets_remaining[$ticket->ID()])) {
508
+				$tickets_remaining[$ticket->ID()] = $ticket->remaining();
509
+			}
510
+			if ($tickets_remaining[$ticket->ID()] > 0) {
511
+				if (! isset($event_reg_count[$EVT_ID])) {
512
+					$event_reg_count[$EVT_ID] = 0;
513
+				}
514
+				$event_reg_count[$EVT_ID]++;
515
+				if (! isset($event_spaces_remaining[$EVT_ID])) {
516
+					$event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
517
+				}
518
+			}
519
+			if (
520
+				$revisit
521
+				&& (
522
+					$tickets_remaining[$ticket->ID()] === 0
523
+					|| $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
524
+				)
525
+			) {
526
+				$ejected_registrations[$REG_ID] = $registration->event();
527
+				if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
528
+					/** @type EE_Registration_Processor $registration_processor */
529
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
530
+					// at this point, we should have enough details about the registrant to consider the registration NOT incomplete
531
+					$registration_processor->manually_update_registration_status(
532
+						$registration,
533
+						EEM_Registration::status_id_wait_list
534
+					);
535
+				}
536
+
537
+			}
538
+		}
539
+		return $ejected_registrations;
540
+	}
541
+
542
+
543
+	/**
544
+	 * _hide_reg_step_submit_button
545
+	 * removes the html for the reg step submit button
546
+	 * by replacing it with an empty string via filter callback
547
+	 *
548
+	 * @return void
549
+	 */
550
+	protected function _adjust_registration_status_if_event_old_sold()
551
+	{
552
+	}
553
+
554
+
555
+	/**
556
+	 * _hide_reg_step_submit_button
557
+	 * removes the html for the reg step submit button
558
+	 * by replacing it with an empty string via filter callback
559
+	 *
560
+	 * @return void
561
+	 */
562
+	protected function _hide_reg_step_submit_button_if_revisit()
563
+	{
564
+		if ($this->checkout->revisit) {
565
+			add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
566
+		}
567
+	}
568
+
569
+
570
+	/**
571
+	 * sold_out_events
572
+	 * displays notices regarding events that have sold out since hte registrant first signed up
573
+	 *
574
+	 * @param \EE_Event[] $sold_out_events_array
575
+	 * @return \EE_Form_Section_Proper
576
+	 * @throws \EE_Error
577
+	 */
578
+	private function _sold_out_events($sold_out_events_array = array())
579
+	{
580
+		// set some defaults
581
+		$this->checkout->selected_method_of_payment = 'events_sold_out';
582
+		$sold_out_events                            = '';
583
+		foreach ($sold_out_events_array as $sold_out_event) {
584
+			$sold_out_events .= EEH_HTML::li(
585
+				EEH_HTML::span('  ' . $sold_out_event->name(), '',
586
+					'dashicons dashicons-marker ee-icon-size-16 pink-text')
587
+			);
588
+		}
589
+		return new EE_Form_Section_Proper(
590
+			array(
591
+				'layout_strategy' => new EE_Template_Layout(
592
+					array(
593
+						'layout_template_file' => SPCO_REG_STEPS_PATH
594
+												  . $this->_slug
595
+												  . DS
596
+												  . 'sold_out_events.template.php',
597
+						'template_args'        => apply_filters(
598
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
599
+							array(
600
+								'sold_out_events'     => $sold_out_events,
601
+								'sold_out_events_msg' => apply_filters(
602
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
603
+									sprintf(
604
+										__('It appears that the event you were about to make a payment for has sold out since you first registered. If you have already made a partial payment towards this event, please contact the event administrator for a refund.%3$s%3$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%2$s',
605
+											'event_espresso'),
606
+										'<strong>',
607
+										'</strong>',
608
+										'<br />'
609
+									)
610
+								),
611
+							)
612
+						),
613
+					)
614
+				),
615
+			)
616
+		);
617
+	}
618
+
619
+
620
+	/**
621
+	 * _insufficient_spaces_available
622
+	 * displays notices regarding events that do not have enough remaining spaces
623
+	 * to satisfy the current number of registrations looking to pay
624
+	 *
625
+	 * @param \EE_Event[] $insufficient_spaces_events_array
626
+	 * @return \EE_Form_Section_Proper
627
+	 * @throws \EE_Error
628
+	 */
629
+	private function _insufficient_spaces_available($insufficient_spaces_events_array = array())
630
+	{
631
+		// set some defaults
632
+		$this->checkout->selected_method_of_payment = 'invoice';
633
+		$insufficient_space_events                  = '';
634
+		foreach ($insufficient_spaces_events_array as $event) {
635
+			if ($event instanceof EE_Event) {
636
+				$insufficient_space_events .= EEH_HTML::li(
637
+					EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
638
+				);
639
+			}
640
+		}
641
+		return new EE_Form_Section_Proper(
642
+			array(
643
+				'subsections'     => array(
644
+					'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
645
+					'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
646
+				),
647
+				'layout_strategy' => new EE_Template_Layout(
648
+					array(
649
+						'layout_template_file' => SPCO_REG_STEPS_PATH
650
+												  . $this->_slug
651
+												  . DS
652
+												  . 'sold_out_events.template.php',
653
+						'template_args'        => apply_filters(
654
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
655
+							array(
656
+								'sold_out_events'     => $insufficient_space_events,
657
+								'sold_out_events_msg' => apply_filters(
658
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
659
+									__(
660
+										'It appears that the event you were about to make a payment for has sold additional tickets since you first registered, and there are no longer enough spaces left to accommodate your selections. You may continue to pay and secure the available space(s) remaining, or simply cancel if you no longer wish to purchase. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
661
+										'event_espresso'
662
+									)
663
+								),
664
+							)
665
+						),
666
+					)
667
+				),
668
+			)
669
+		);
670
+	}
671
+
672
+
673
+	/**
674
+	 * registrations_requiring_pre_approval
675
+	 *
676
+	 * @param array $registrations_requiring_pre_approval
677
+	 * @return \EE_Form_Section_Proper
678
+	 * @throws \EE_Error
679
+	 */
680
+	private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = array())
681
+	{
682
+		$events_requiring_pre_approval = '';
683
+		foreach ($registrations_requiring_pre_approval as $registration) {
684
+			if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
685
+				$events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
686
+					EEH_HTML::span(
687
+						'',
688
+						'',
689
+						'dashicons dashicons-marker ee-icon-size-16 orange-text'
690
+					)
691
+					. EEH_HTML::span($registration->event()->name(), '', 'orange-text')
692
+				);
693
+			}
694
+		}
695
+		return new EE_Form_Section_Proper(
696
+			array(
697
+				'layout_strategy' => new EE_Template_Layout(
698
+					array(
699
+						'layout_template_file' => SPCO_REG_STEPS_PATH
700
+												  . $this->_slug
701
+												  . DS
702
+												  . 'events_requiring_pre_approval.template.php', // layout_template
703
+						'template_args'        => apply_filters(
704
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
705
+							array(
706
+								'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
707
+								'events_requiring_pre_approval_msg' => apply_filters(
708
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
709
+									__(
710
+										'The following events do not require payment at this time and will not be billed during this transaction. Billing will only occur after the attendee has been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
711
+										'event_espresso'
712
+									)
713
+								),
714
+							)
715
+						),
716
+					)
717
+				),
718
+			)
719
+		);
720
+	}
721
+
722
+
723
+	/**
724
+	 * _no_payment_required
725
+	 *
726
+	 * @param \EE_Event[] $registrations_for_free_events
727
+	 * @return \EE_Form_Section_Proper
728
+	 * @throws \EE_Error
729
+	 */
730
+	private function _no_payment_required($registrations_for_free_events = array())
731
+	{
732
+		// set some defaults
733
+		$this->checkout->selected_method_of_payment = 'no_payment_required';
734
+		// generate no_payment_required form
735
+		return new EE_Form_Section_Proper(
736
+			array(
737
+				'layout_strategy' => new EE_Template_Layout(
738
+					array(
739
+						'layout_template_file' => SPCO_REG_STEPS_PATH
740
+												  . $this->_slug
741
+												  . DS
742
+												  . 'no_payment_required.template.php', // layout_template
743
+						'template_args'        => apply_filters(
744
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
745
+							array(
746
+								'revisit'                       => $this->checkout->revisit,
747
+								'registrations'                 => array(),
748
+								'ticket_count'                  => array(),
749
+								'registrations_for_free_events' => $registrations_for_free_events,
750
+								'no_payment_required_msg'       => EEH_HTML::p(
751
+									__('This is a free event, so no billing will occur.', 'event_espresso')
752
+								),
753
+							)
754
+						),
755
+					)
756
+				),
757
+			)
758
+		);
759
+	}
760
+
761
+
762
+	/**
763
+	 * _display_payment_options
764
+	 *
765
+	 * @param string $transaction_details
766
+	 * @return \EE_Form_Section_Proper
767
+	 * @throws \EE_Error
768
+	 */
769
+	private function _display_payment_options($transaction_details = '')
770
+	{
771
+		// has method_of_payment been set by no-js user?
772
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
773
+		// build payment options form
774
+		return apply_filters(
775
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
776
+			new EE_Form_Section_Proper(
777
+				array(
778
+					'subsections'     => array(
779
+						'before_payment_options' => apply_filters(
780
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
781
+							new EE_Form_Section_Proper(
782
+								array('layout_strategy' => new EE_Div_Per_Section_Layout())
783
+							)
784
+						),
785
+						'payment_options'        => $this->_setup_payment_options(),
786
+						'after_payment_options'  => apply_filters(
787
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
788
+							new EE_Form_Section_Proper(
789
+								array('layout_strategy' => new EE_Div_Per_Section_Layout())
790
+							)
791
+						),
792
+					),
793
+					'layout_strategy' => new EE_Template_Layout(
794
+						array(
795
+							'layout_template_file' => $this->_template,
796
+							'template_args'        => apply_filters(
797
+								'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
798
+								array(
799
+									'reg_count'                 => $this->line_item_display->total_items(),
800
+									'transaction_details'       => $transaction_details,
801
+									'available_payment_methods' => array(),
802
+								)
803
+							),
804
+						)
805
+					),
806
+				)
807
+			)
808
+		);
809
+	}
810
+
811
+
812
+	/**
813
+	 * _extra_hidden_inputs
814
+	 *
815
+	 * @param bool $no_payment_required
816
+	 * @return \EE_Form_Section_Proper
817
+	 * @throws \EE_Error
818
+	 */
819
+	private function _extra_hidden_inputs($no_payment_required = true)
820
+	{
821
+		return new EE_Form_Section_Proper(
822
+			array(
823
+				'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
824
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
825
+				'subsections'     => array(
826
+					'spco_no_payment_required' => new EE_Hidden_Input(
827
+						array(
828
+							'normalization_strategy' => new EE_Boolean_Normalization(),
829
+							'html_name'              => 'spco_no_payment_required',
830
+							'html_id'                => 'spco-no-payment-required-payment_options',
831
+							'default'                => $no_payment_required,
832
+						)
833
+					),
834
+					'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
835
+						array(
836
+							'normalization_strategy' => new EE_Int_Normalization(),
837
+							'html_name'              => 'spco_transaction_id',
838
+							'html_id'                => 'spco-transaction-id',
839
+							'default'                => $this->checkout->transaction->ID(),
840
+						)
841
+					),
842
+				),
843
+			)
844
+		);
845
+	}
846
+
847
+
848
+	/**
849
+	 *    _apply_registration_payments_to_amount_owing
850
+	 *
851
+	 * @access protected
852
+	 * @param array $registrations
853
+	 */
854
+	protected function _apply_registration_payments_to_amount_owing(array $registrations)
855
+	{
856
+		$payments = array();
857
+		foreach ($registrations as $registration) {
858
+			if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
859
+				$payments += $registration->registration_payments();
860
+			}
861
+		}
862
+		if (! empty($payments)) {
863
+			foreach ($payments as $payment) {
864
+				if ($payment instanceof EE_Registration_Payment) {
865
+					$this->checkout->amount_owing -= $payment->amount();
866
+				}
867
+			}
868
+		}
869
+	}
870
+
871
+
872
+	/**
873
+	 *    _reset_selected_method_of_payment
874
+	 *
875
+	 * @access    private
876
+	 * @param    bool $force_reset
877
+	 * @return    void
878
+	 */
879
+	private function _reset_selected_method_of_payment($force_reset = false)
880
+	{
881
+		$reset_payment_method = $force_reset
882
+			? true
883
+			: sanitize_text_field(EE_Registry::instance()->REQ->get('reset_payment_method', false));
884
+		if ($reset_payment_method) {
885
+			$this->checkout->selected_method_of_payment = null;
886
+			$this->checkout->payment_method             = null;
887
+			$this->checkout->billing_form               = null;
888
+			$this->_save_selected_method_of_payment();
889
+		}
890
+	}
891
+
892
+
893
+	/**
894
+	 * _save_selected_method_of_payment
895
+	 * stores the selected_method_of_payment in the session
896
+	 * so that it's available for all subsequent requests including AJAX
897
+	 *
898
+	 * @access        private
899
+	 * @param string $selected_method_of_payment
900
+	 * @return  void
901
+	 */
902
+	private function _save_selected_method_of_payment($selected_method_of_payment = '')
903
+	{
904
+		$selected_method_of_payment = ! empty($selected_method_of_payment)
905
+			? $selected_method_of_payment
906
+			: $this->checkout->selected_method_of_payment;
907
+		EE_Registry::instance()->SSN->set_session_data(
908
+			array('selected_method_of_payment' => $selected_method_of_payment)
909
+		);
910
+	}
911
+
912
+
913
+	/**
914
+	 * _setup_payment_options
915
+	 *
916
+	 * @return \EE_Form_Section_Proper
917
+	 * @throws \EE_Error
918
+	 */
919
+	public function _setup_payment_options()
920
+	{
921
+		// load payment method classes
922
+		$this->checkout->available_payment_methods = $this->_get_available_payment_methods();
923
+		// switch up header depending on number of available payment methods
924
+		$payment_method_header     = count($this->checkout->available_payment_methods) > 1
925
+			? apply_filters(
926
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
927
+				__('Please Select Your Method of Payment', 'event_espresso')
928
+			)
929
+			: apply_filters(
930
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
931
+				__('Method of Payment', 'event_espresso')
932
+			);
933
+		$available_payment_methods = array(
934
+			// display the "Payment Method" header
935
+			'payment_method_header' => new EE_Form_Section_HTML(
936
+				EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr')
937
+			),
938
+		);
939
+		// the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
940
+		$available_payment_method_options = array();
941
+		$default_payment_method_option    = array();
942
+		// additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
943
+		$payment_methods_billing_info = array(
944
+			new EE_Form_Section_HTML(
945
+				EEH_HTML::div('<br />', '', '', 'clear:both;')
946
+			),
947
+		);
948
+		// loop through payment methods
949
+		foreach ($this->checkout->available_payment_methods as $payment_method) {
950
+			if ($payment_method instanceof EE_Payment_Method) {
951
+				$payment_method_button = EEH_HTML::img(
952
+					$payment_method->button_url(),
953
+					$payment_method->name(),
954
+					'spco-payment-method-' . $payment_method->slug() . '-btn-img',
955
+					'spco-payment-method-btn-img'
956
+				);
957
+				// check if any payment methods are set as default
958
+				// if payment method is already selected OR nothing is selected and this payment method should be open_by_default
959
+				if (
960
+					($this->checkout->selected_method_of_payment === $payment_method->slug())
961
+					|| (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
962
+				) {
963
+					$this->checkout->selected_method_of_payment = $payment_method->slug();
964
+					$this->_save_selected_method_of_payment();
965
+					$default_payment_method_option[$payment_method->slug()] = $payment_method_button;
966
+				} else {
967
+					$available_payment_method_options[$payment_method->slug()] = $payment_method_button;
968
+				}
969
+				$payment_methods_billing_info[$payment_method->slug()
970
+											  . '-info'] = $this->_payment_method_billing_info(
971
+					$payment_method
972
+				);
973
+			}
974
+		}
975
+		// prepend available_payment_method_options with default_payment_method_option so that it appears first in list of PMs
976
+		$available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
977
+		// now generate the actual form  inputs
978
+		$available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
979
+			$available_payment_method_options
980
+		);
981
+		$available_payment_methods                              += $payment_methods_billing_info;
982
+		// build the available payment methods form
983
+		return new EE_Form_Section_Proper(
984
+			array(
985
+				'html_id'         => 'spco-available-methods-of-payment-dv',
986
+				'subsections'     => $available_payment_methods,
987
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
988
+			)
989
+		);
990
+	}
991
+
992
+
993
+	/**
994
+	 * _get_available_payment_methods
995
+	 *
996
+	 * @return EE_Payment_Method[]
997
+	 */
998
+	protected function _get_available_payment_methods()
999
+	{
1000
+		if (! empty($this->checkout->available_payment_methods)) {
1001
+			return $this->checkout->available_payment_methods;
1002
+		}
1003
+		$available_payment_methods = array();
1004
+		// load EEM_Payment_Method
1005
+		EE_Registry::instance()->load_model('Payment_Method');
1006
+		/** @type EEM_Payment_Method $EEM_Payment_Method */
1007
+		$EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
1008
+		// get all active payment methods
1009
+		$payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1010
+			$this->checkout->transaction,
1011
+			EEM_Payment_Method::scope_cart
1012
+		);
1013
+		foreach ($payment_methods as $payment_method) {
1014
+			if ($payment_method instanceof EE_Payment_Method) {
1015
+				$available_payment_methods[$payment_method->slug()] = $payment_method;
1016
+			}
1017
+		}
1018
+		return $available_payment_methods;
1019
+	}
1020
+
1021
+
1022
+	/**
1023
+	 *    _available_payment_method_inputs
1024
+	 *
1025
+	 * @access    private
1026
+	 * @param    array $available_payment_method_options
1027
+	 * @return    \EE_Form_Section_Proper
1028
+	 */
1029
+	private function _available_payment_method_inputs($available_payment_method_options = array())
1030
+	{
1031
+		// generate inputs
1032
+		return new EE_Form_Section_Proper(
1033
+			array(
1034
+				'html_id'         => 'ee-available-payment-method-inputs',
1035
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1036
+				'subsections'     => array(
1037
+					'' => new EE_Radio_Button_Input (
1038
+						$available_payment_method_options,
1039
+						array(
1040
+							'html_name'          => 'selected_method_of_payment',
1041
+							'html_class'         => 'spco-payment-method',
1042
+							'default'            => $this->checkout->selected_method_of_payment,
1043
+							'label_size'         => 11,
1044
+							'enforce_label_size' => true,
1045
+						)
1046
+					),
1047
+				),
1048
+			)
1049
+		);
1050
+	}
1051
+
1052
+
1053
+	/**
1054
+	 *    _payment_method_billing_info
1055
+	 *
1056
+	 * @access    private
1057
+	 * @param    EE_Payment_Method $payment_method
1058
+	 * @return    \EE_Form_Section_Proper
1059
+	 * @throws \EE_Error
1060
+	 */
1061
+	private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1062
+	{
1063
+		$currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug()
1064
+			? true
1065
+			: false;
1066
+		// generate the billing form for payment method
1067
+		$billing_form                 = $currently_selected
1068
+			? $this->_get_billing_form_for_payment_method($payment_method)
1069
+			: new EE_Form_Section_HTML();
1070
+		$this->checkout->billing_form = $currently_selected
1071
+			? $billing_form
1072
+			: $this->checkout->billing_form;
1073
+		// it's all in the details
1074
+		$info_html = EEH_HTML::h3(
1075
+			__('Important information regarding your payment', 'event_espresso'),
1076
+			'',
1077
+			'spco-payment-method-hdr'
1078
+		);
1079
+		// add some info regarding the step, either from what's saved in the admin,
1080
+		// or a default string depending on whether the PM has a billing form or not
1081
+		if ($payment_method->description()) {
1082
+			$payment_method_info = $payment_method->description();
1083
+		} elseif ($billing_form instanceof EE_Billing_Info_Form) {
1084
+			$payment_method_info = sprintf(
1085
+				__(
1086
+					'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1087
+					'event_espresso'
1088
+				),
1089
+				$this->submit_button_text()
1090
+			);
1091
+		} else {
1092
+			$payment_method_info = sprintf(
1093
+				__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1094
+				$this->submit_button_text()
1095
+			);
1096
+		}
1097
+		$info_html .= EEH_HTML::p(
1098
+			apply_filters(
1099
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1100
+				$payment_method_info
1101
+			),
1102
+			'',
1103
+			'spco-payment-method-desc ee-attention'
1104
+		);
1105
+		return new EE_Form_Section_Proper(
1106
+			array(
1107
+				'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1108
+				'html_class'      => 'spco-payment-method-info-dv',
1109
+				// only display the selected or default PM
1110
+				'html_style'      => $currently_selected ? '' : 'display:none;',
1111
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1112
+				'subsections'     => array(
1113
+					'info'         => new EE_Form_Section_HTML($info_html),
1114
+					'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1115
+				),
1116
+			)
1117
+		);
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * get_billing_form_html_for_payment_method
1123
+	 *
1124
+	 * @access public
1125
+	 * @return string
1126
+	 * @throws \EE_Error
1127
+	 */
1128
+	public function get_billing_form_html_for_payment_method()
1129
+	{
1130
+		// how have they chosen to pay?
1131
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1132
+		$this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1133
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1134
+			return false;
1135
+		}
1136
+		if (apply_filters(
1137
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1138
+			false
1139
+		)) {
1140
+			EE_Error::add_success(
1141
+				apply_filters(
1142
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1143
+					sprintf(
1144
+						__(
1145
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1146
+							'event_espresso'
1147
+						),
1148
+						$this->checkout->payment_method->name()
1149
+					)
1150
+				)
1151
+			);
1152
+		}
1153
+		// now generate billing form for selected method of payment
1154
+		$payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1155
+		// fill form with attendee info if applicable
1156
+		if (
1157
+			$payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1158
+			&& $this->checkout->transaction_has_primary_registrant()
1159
+		) {
1160
+			$payment_method_billing_form->populate_from_attendee(
1161
+				$this->checkout->transaction->primary_registration()->attendee()
1162
+			);
1163
+		}
1164
+		// and debug content
1165
+		if (
1166
+			$payment_method_billing_form instanceof EE_Billing_Info_Form
1167
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1168
+		) {
1169
+			$payment_method_billing_form = $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1170
+				$payment_method_billing_form
1171
+			);
1172
+		}
1173
+		$billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1174
+			? $payment_method_billing_form->get_html()
1175
+			: '';
1176
+		$this->checkout->json_response->set_return_data(array('payment_method_info' => $billing_info));
1177
+		// localize validation rules for main form
1178
+		$this->checkout->current_step->reg_form->localize_validation_rules();
1179
+		$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1180
+		return true;
1181
+	}
1182
+
1183
+
1184
+	/**
1185
+	 * _get_billing_form_for_payment_method
1186
+	 *
1187
+	 * @access private
1188
+	 * @param EE_Payment_Method $payment_method
1189
+	 * @return \EE_Billing_Info_Form|\EE_Form_Section_HTML
1190
+	 * @throws \EE_Error
1191
+	 */
1192
+	private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
1193
+	{
1194
+		$billing_form = $payment_method->type_obj()->billing_form(
1195
+			$this->checkout->transaction,
1196
+			array('amount_owing' => $this->checkout->amount_owing)
1197
+		);
1198
+		if ($billing_form instanceof EE_Billing_Info_Form) {
1199
+			if (
1200
+				apply_filters(
1201
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1202
+					false
1203
+				)
1204
+				&& EE_Registry::instance()->REQ->is_set('payment_method')
1205
+			) {
1206
+				EE_Error::add_success(
1207
+					apply_filters(
1208
+						'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1209
+						sprintf(
1210
+							__(
1211
+								'You have selected "%s" as your method of payment. Please note the important payment information below.',
1212
+								'event_espresso'
1213
+							),
1214
+							$payment_method->name()
1215
+						)
1216
+					)
1217
+				);
1218
+			}
1219
+			return apply_filters(
1220
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
1221
+				$billing_form,
1222
+				$payment_method
1223
+			);
1224
+		}
1225
+		// no actual billing form, so return empty HTML form section
1226
+		return new EE_Form_Section_HTML();
1227
+	}
1228
+
1229
+
1230
+	/**
1231
+	 * _get_selected_method_of_payment
1232
+	 *
1233
+	 * @access private
1234
+	 * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1235
+	 *                          is not found in the incoming request
1236
+	 * @param string  $request_param
1237
+	 * @return NULL|string
1238
+	 * @throws \EE_Error
1239
+	 */
1240
+	private function _get_selected_method_of_payment(
1241
+		$required = false,
1242
+		$request_param = 'selected_method_of_payment'
1243
+	) {
1244
+		// is selected_method_of_payment set in the request ?
1245
+		$selected_method_of_payment = EE_Registry::instance()->REQ->get($request_param, false);
1246
+		if ($selected_method_of_payment) {
1247
+			// sanitize it
1248
+			$selected_method_of_payment = is_array($selected_method_of_payment)
1249
+				? array_shift($selected_method_of_payment)
1250
+				: $selected_method_of_payment;
1251
+			$selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1252
+			// store it in the session so that it's available for all subsequent requests including AJAX
1253
+			$this->_save_selected_method_of_payment($selected_method_of_payment);
1254
+		} else {
1255
+			// or is is set in the session ?
1256
+			$selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1257
+				'selected_method_of_payment'
1258
+			);
1259
+		}
1260
+		// do ya really really gotta have it?
1261
+		if (empty($selected_method_of_payment) && $required) {
1262
+			EE_Error::add_error(
1263
+				sprintf(
1264
+					__(
1265
+						'The selected method of payment could not be determined.%sPlease ensure that you have selected one before proceeding.%sIf you continue to experience difficulties, then refresh your browser and try again, or contact %s for assistance.',
1266
+						'event_espresso'
1267
+					),
1268
+					'<br/>',
1269
+					'<br/>',
1270
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
1271
+				),
1272
+				__FILE__,
1273
+				__FUNCTION__,
1274
+				__LINE__
1275
+			);
1276
+			return null;
1277
+		}
1278
+		return $selected_method_of_payment;
1279
+	}
1280
+
1281
+
1282
+
1283
+
1284
+
1285
+
1286
+	/********************************************************************************************************/
1287
+	/***********************************  SWITCH PAYMENT METHOD  ************************************/
1288
+	/********************************************************************************************************/
1289
+	/**
1290
+	 * switch_payment_method
1291
+	 *
1292
+	 * @access public
1293
+	 * @return string
1294
+	 * @throws \EE_Error
1295
+	 */
1296
+	public function switch_payment_method()
1297
+	{
1298
+		if (! $this->_verify_payment_method_is_set()) {
1299
+			return false;
1300
+		}
1301
+		if (apply_filters(
1302
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1303
+			false
1304
+		)) {
1305
+			EE_Error::add_success(
1306
+				apply_filters(
1307
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1308
+					sprintf(
1309
+						__(
1310
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1311
+							'event_espresso'
1312
+						),
1313
+						$this->checkout->payment_method->name()
1314
+					)
1315
+				)
1316
+			);
1317
+		}
1318
+		// generate billing form for selected method of payment if it hasn't been done already
1319
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1320
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1321
+				$this->checkout->payment_method
1322
+			);
1323
+		}
1324
+		// fill form with attendee info if applicable
1325
+		if (
1326
+		apply_filters(
1327
+			'FHEE__populate_billing_form_fields_from_attendee',
1328
+			(
1329
+				$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1330
+				&& $this->checkout->transaction_has_primary_registrant()
1331
+			),
1332
+			$this->checkout->billing_form,
1333
+			$this->checkout->transaction
1334
+		)
1335
+		) {
1336
+			$this->checkout->billing_form->populate_from_attendee(
1337
+				$this->checkout->transaction->primary_registration()->attendee()
1338
+			);
1339
+		}
1340
+		// and debug content
1341
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1342
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1343
+		) {
1344
+			$this->checkout->billing_form = $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1345
+				$this->checkout->billing_form
1346
+			);
1347
+		}
1348
+		// get html and validation rules for form
1349
+		if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1350
+			$this->checkout->json_response->set_return_data(
1351
+				array('payment_method_info' => $this->checkout->billing_form->get_html())
1352
+			);
1353
+			// localize validation rules for main form
1354
+			$this->checkout->billing_form->localize_validation_rules(true);
1355
+			$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1356
+		} else {
1357
+			$this->checkout->json_response->set_return_data(array('payment_method_info' => ''));
1358
+		}
1359
+		//prevents advancement to next step
1360
+		$this->checkout->continue_reg = false;
1361
+		return true;
1362
+	}
1363
+
1364
+
1365
+	/**
1366
+	 * _verify_payment_method_is_set
1367
+	 *
1368
+	 * @return boolean
1369
+	 * @throws \EE_Error
1370
+	 */
1371
+	protected function _verify_payment_method_is_set()
1372
+	{
1373
+		// generate billing form for selected method of payment if it hasn't been done already
1374
+		if (empty($this->checkout->selected_method_of_payment)) {
1375
+			// how have they chosen to pay?
1376
+			$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1377
+		} else {
1378
+			// choose your own adventure based on method_of_payment
1379
+			switch ($this->checkout->selected_method_of_payment) {
1380
+				case 'events_sold_out' :
1381
+					EE_Error::add_attention(
1382
+						apply_filters(
1383
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1384
+							__('It appears that the event you were about to make a payment for has sold out since this form first loaded. Please contact the event administrator if you believe this is an error.',
1385
+								'event_espresso')
1386
+						),
1387
+						__FILE__, __FUNCTION__, __LINE__
1388
+					);
1389
+					return false;
1390
+					break;
1391
+				case 'payments_closed' :
1392
+					EE_Error::add_attention(
1393
+						apply_filters(
1394
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__payments_closed_msg',
1395
+							__('It appears that the event you were about to make a payment for is not accepting payments at this time. Please contact the event administrator if you believe this is an error.',
1396
+								'event_espresso')
1397
+						),
1398
+						__FILE__, __FUNCTION__, __LINE__
1399
+					);
1400
+					return false;
1401
+					break;
1402
+				case 'no_payment_required' :
1403
+					EE_Error::add_attention(
1404
+						apply_filters(
1405
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1406
+							__('It appears that the event you were about to make a payment for does not require payment. Please contact the event administrator if you believe this is an error.',
1407
+								'event_espresso')
1408
+						),
1409
+						__FILE__, __FUNCTION__, __LINE__
1410
+					);
1411
+					return false;
1412
+					break;
1413
+				default:
1414
+			}
1415
+		}
1416
+		// verify payment method
1417
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1418
+			// get payment method for selected method of payment
1419
+			$this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1420
+		}
1421
+		return $this->checkout->payment_method instanceof EE_Payment_Method ? true : false;
1422
+	}
1423
+
1424
+
1425
+
1426
+	/********************************************************************************************************/
1427
+	/***************************************  SAVE PAYER DETAILS  ****************************************/
1428
+	/********************************************************************************************************/
1429
+	/**
1430
+	 * save_payer_details_via_ajax
1431
+	 *
1432
+	 * @return void
1433
+	 * @throws \EE_Error
1434
+	 */
1435
+	public function save_payer_details_via_ajax()
1436
+	{
1437
+		if (! $this->_verify_payment_method_is_set()) {
1438
+			return;
1439
+		}
1440
+		// generate billing form for selected method of payment if it hasn't been done already
1441
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1442
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1443
+				$this->checkout->payment_method
1444
+			);
1445
+		}
1446
+		// generate primary attendee from payer info if applicable
1447
+		if (! $this->checkout->transaction_has_primary_registrant()) {
1448
+			$attendee = $this->_create_attendee_from_request_data();
1449
+			if ($attendee instanceof EE_Attendee) {
1450
+				foreach ($this->checkout->transaction->registrations() as $registration) {
1451
+					if ($registration->is_primary_registrant()) {
1452
+						$this->checkout->primary_attendee_obj = $attendee;
1453
+						$registration->_add_relation_to($attendee, 'Attendee');
1454
+						$registration->set_attendee_id($attendee->ID());
1455
+						$registration->update_cache_after_object_save('Attendee', $attendee);
1456
+					}
1457
+				}
1458
+			}
1459
+		}
1460
+	}
1461
+
1462
+
1463
+	/**
1464
+	 * create_attendee_from_request_data
1465
+	 * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1466
+	 *
1467
+	 * @return \EE_Attendee
1468
+	 * @throws \EE_Error
1469
+	 */
1470
+	protected function _create_attendee_from_request_data()
1471
+	{
1472
+		// get State ID
1473
+		$STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1474
+		if (! empty($STA_ID)) {
1475
+			// can we get state object from name ?
1476
+			EE_Registry::instance()->load_model('State');
1477
+			$state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
1478
+			$STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1479
+		}
1480
+		// get Country ISO
1481
+		$CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1482
+		if (! empty($CNT_ISO)) {
1483
+			// can we get country object from name ?
1484
+			EE_Registry::instance()->load_model('Country');
1485
+			$country = EEM_Country::instance()->get_col(
1486
+				array(array('CNT_name' => $CNT_ISO), 'limit' => 1),
1487
+				'CNT_ISO'
1488
+			);
1489
+			$CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1490
+		}
1491
+		// grab attendee data
1492
+		$attendee_data = array(
1493
+			'ATT_fname'    => ! empty($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : '',
1494
+			'ATT_lname'    => ! empty($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : '',
1495
+			'ATT_email'    => ! empty($_REQUEST['email']) ? sanitize_email($_REQUEST['email']) : '',
1496
+			'ATT_address'  => ! empty($_REQUEST['address']) ? sanitize_text_field($_REQUEST['address']) : '',
1497
+			'ATT_address2' => ! empty($_REQUEST['address2']) ? sanitize_text_field($_REQUEST['address2']) : '',
1498
+			'ATT_city'     => ! empty($_REQUEST['city']) ? sanitize_text_field($_REQUEST['city']) : '',
1499
+			'STA_ID'       => $STA_ID,
1500
+			'CNT_ISO'      => $CNT_ISO,
1501
+			'ATT_zip'      => ! empty($_REQUEST['zip']) ? sanitize_text_field($_REQUEST['zip']) : '',
1502
+			'ATT_phone'    => ! empty($_REQUEST['phone']) ? sanitize_text_field($_REQUEST['phone']) : '',
1503
+		);
1504
+		// validate the email address since it is the most important piece of info
1505
+		if (empty($attendee_data['ATT_email']) || $attendee_data['ATT_email'] !== $_REQUEST['email']) {
1506
+			EE_Error::add_error(
1507
+				__('An invalid email address was submitted.', 'event_espresso'),
1508
+				__FILE__,
1509
+				__FUNCTION__,
1510
+				__LINE__
1511
+			);
1512
+		}
1513
+		// does this attendee already exist in the db ? we're searching using a combination of first name, last name, AND email address
1514
+		if (! empty($attendee_data['ATT_fname'])
1515
+			&& ! empty($attendee_data['ATT_lname'])
1516
+			&& ! empty($attendee_data['ATT_email'])
1517
+		) {
1518
+			$existing_attendee = EE_Registry::instance()->LIB->EEM_Attendee->find_existing_attendee(
1519
+				array(
1520
+					'ATT_fname' => $attendee_data['ATT_fname'],
1521
+					'ATT_lname' => $attendee_data['ATT_lname'],
1522
+					'ATT_email' => $attendee_data['ATT_email'],
1523
+				)
1524
+			);
1525
+			if ($existing_attendee instanceof EE_Attendee) {
1526
+				return $existing_attendee;
1527
+			}
1528
+		}
1529
+		// no existing attendee? kk let's create a new one
1530
+		// kinda lame, but we need a first and last name to create an attendee, so use the email address if those don't exist
1531
+		$attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1532
+			? $attendee_data['ATT_fname']
1533
+			: $attendee_data['ATT_email'];
1534
+		$attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1535
+			? $attendee_data['ATT_lname']
1536
+			: $attendee_data['ATT_email'];
1537
+		return EE_Attendee::new_instance($attendee_data);
1538
+	}
1539
+
1540
+
1541
+
1542
+	/********************************************************************************************************/
1543
+	/****************************************  PROCESS REG STEP  *****************************************/
1544
+	/********************************************************************************************************/
1545
+	/**
1546
+	 * process_reg_step
1547
+	 *
1548
+	 * @return boolean
1549
+	 * @throws \EE_Error
1550
+	 */
1551
+	public function process_reg_step()
1552
+	{
1553
+		// how have they chosen to pay?
1554
+		$this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1555
+			? 'no_payment_required'
1556
+			: $this->_get_selected_method_of_payment(true);
1557
+		// choose your own adventure based on method_of_payment
1558
+		switch ($this->checkout->selected_method_of_payment) {
1559
+
1560
+			case 'events_sold_out' :
1561
+				$this->checkout->redirect     = true;
1562
+				$this->checkout->redirect_url = $this->checkout->cancel_page_url;
1563
+				$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1564
+				// mark this reg step as completed
1565
+				$this->set_completed();
1566
+				return false;
1567
+				break;
1568
+
1569
+			case 'payments_closed' :
1570
+				if (apply_filters(
1571
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__payments_closed__display_success',
1572
+					false
1573
+				)) {
1574
+					EE_Error::add_success(
1575
+						__('no payment required at this time.', 'event_espresso'),
1576
+						__FILE__,
1577
+						__FUNCTION__,
1578
+						__LINE__
1579
+					);
1580
+				}
1581
+				// mark this reg step as completed
1582
+				$this->set_completed();
1583
+				return true;
1584
+				break;
1585
+
1586
+			case 'no_payment_required' :
1587
+				if (apply_filters(
1588
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1589
+					false
1590
+				)) {
1591
+					EE_Error::add_success(
1592
+						__('no payment required.', 'event_espresso'),
1593
+						__FILE__,
1594
+						__FUNCTION__,
1595
+						__LINE__
1596
+					);
1597
+				}
1598
+				// mark this reg step as completed
1599
+				$this->set_completed();
1600
+				return true;
1601
+				break;
1602
+
1603
+			default:
1604
+				$registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1605
+					EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1606
+				);
1607
+				$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1608
+					$registrations,
1609
+					EE_Registry::instance()->SSN->checkout()->revisit
1610
+				);
1611
+				// calculate difference between the two arrays
1612
+				$registrations = array_diff($registrations, $ejected_registrations);
1613
+				if (empty($registrations)) {
1614
+					$this->_redirect_because_event_sold_out();
1615
+					return false;
1616
+				}
1617
+				$payment_successful = $this->_process_payment();
1618
+				if ($payment_successful) {
1619
+					$this->checkout->continue_reg = true;
1620
+					$this->_maybe_set_completed($this->checkout->payment_method);
1621
+				} else {
1622
+					$this->checkout->continue_reg = false;
1623
+				}
1624
+				return $payment_successful;
1625
+
1626
+		}
1627
+	}
1628
+
1629
+
1630
+	/**
1631
+	 * _redirect_because_event_sold_out
1632
+	 *
1633
+	 * @access protected
1634
+	 * @return void
1635
+	 */
1636
+	protected function _redirect_because_event_sold_out()
1637
+	{
1638
+		$this->checkout->continue_reg = false;
1639
+		// set redirect URL
1640
+		$this->checkout->redirect_url = add_query_arg(
1641
+			array('e_reg_url_link' => $this->checkout->reg_url_link),
1642
+			$this->checkout->current_step->reg_step_url()
1643
+		);
1644
+		$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1645
+	}
1646
+
1647
+
1648
+	/**
1649
+	 * _maybe_set_completed
1650
+	 *
1651
+	 * @access protected
1652
+	 * @param \EE_Payment_Method $payment_method
1653
+	 * @return void
1654
+	 * @throws \EE_Error
1655
+	 */
1656
+	protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1657
+	{
1658
+		switch ($payment_method->type_obj()->payment_occurs()) {
1659
+			case EE_PMT_Base::offsite :
1660
+				break;
1661
+			case EE_PMT_Base::onsite :
1662
+			case EE_PMT_Base::offline :
1663
+				// mark this reg step as completed
1664
+				$this->set_completed();
1665
+				break;
1666
+		}
1667
+	}
1668
+
1669
+
1670
+	/**
1671
+	 *    update_reg_step
1672
+	 *    this is the final step after a user  revisits the site to retry a payment
1673
+	 *
1674
+	 * @return boolean
1675
+	 * @throws \EE_Error
1676
+	 */
1677
+	public function update_reg_step()
1678
+	{
1679
+		$success = true;
1680
+		// if payment required
1681
+		if ($this->checkout->transaction->total() > 0) {
1682
+			do_action(
1683
+				'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1684
+				$this->checkout->transaction
1685
+			);
1686
+			// attempt payment via payment method
1687
+			$success = $this->process_reg_step();
1688
+		}
1689
+		if ($success && ! $this->checkout->redirect) {
1690
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1691
+				$this->checkout->transaction->ID()
1692
+			);
1693
+			// set return URL
1694
+			$this->checkout->redirect_url = add_query_arg(
1695
+				array('e_reg_url_link' => $this->checkout->reg_url_link),
1696
+				$this->checkout->thank_you_page_url
1697
+			);
1698
+		}
1699
+		return $success;
1700
+	}
1701
+
1702
+
1703
+	/**
1704
+	 *    _process_payment
1705
+	 *
1706
+	 * @access private
1707
+	 * @return    bool
1708
+	 * @throws \EE_Error
1709
+	 */
1710
+	private function _process_payment()
1711
+	{
1712
+		// basically confirm that the event hasn't sold out since they hit the page
1713
+		if (! $this->_last_second_ticket_verifications()) {
1714
+			return false;
1715
+		}
1716
+		// ya gotta make a choice man
1717
+		if (empty($this->checkout->selected_method_of_payment)) {
1718
+			$this->checkout->json_response->set_plz_select_method_of_payment(
1719
+				__('Please select a method of payment before proceeding.', 'event_espresso')
1720
+			);
1721
+			return false;
1722
+		}
1723
+		// get EE_Payment_Method object
1724
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1725
+			return false;
1726
+		}
1727
+		// setup billing form
1728
+		if ($this->checkout->payment_method->is_on_site()) {
1729
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1730
+				$this->checkout->payment_method
1731
+			);
1732
+			// bad billing form ?
1733
+			if (! $this->_billing_form_is_valid()) {
1734
+				return false;
1735
+			}
1736
+		}
1737
+		// ensure primary registrant has been fully processed
1738
+		if (! $this->_setup_primary_registrant_prior_to_payment()) {
1739
+			return false;
1740
+		}
1741
+		// if session is close to expiring (under 10 minutes by default)
1742
+		if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1743
+			// add some time to session expiration so that payment can be completed
1744
+			EE_Registry::instance()->SSN->extend_expiration();
1745
+		}
1746
+		/** @type EE_Transaction_Processor $transaction_processor */
1747
+		//$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1748
+		// in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations for events with a default reg status of Approved
1749
+		//$transaction_processor->toggle_registration_statuses_for_default_approved_events( $this->checkout->transaction, $this->checkout->reg_cache_where_params );
1750
+		// attempt payment
1751
+		$payment = $this->_attempt_payment($this->checkout->payment_method);
1752
+		// process results
1753
+		$payment = $this->_validate_payment($payment);
1754
+		$payment = $this->_post_payment_processing($payment);
1755
+		// verify payment
1756
+		if ($payment instanceof EE_Payment) {
1757
+			// store that for later
1758
+			$this->checkout->payment = $payment;
1759
+			// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1760
+			$this->checkout->transaction->toggle_failed_transaction_status();
1761
+			$payment_status = $payment->status();
1762
+			if (
1763
+				$payment_status === EEM_Payment::status_id_approved
1764
+				|| $payment_status === EEM_Payment::status_id_pending
1765
+			) {
1766
+				return true;
1767
+			} else {
1768
+				return false;
1769
+			}
1770
+		} else if ($payment === true) {
1771
+			// please note that offline payment methods will NOT make a payment,
1772
+			// but instead just mark themselves as the PMD_ID on the transaction, and return true
1773
+			$this->checkout->payment = $payment;
1774
+			return true;
1775
+		}
1776
+		// where's my money?
1777
+		return false;
1778
+	}
1779
+
1780
+
1781
+	/**
1782
+	 * _last_second_ticket_verifications
1783
+	 *
1784
+	 * @access public
1785
+	 * @return bool
1786
+	 */
1787
+	protected function _last_second_ticket_verifications()
1788
+	{
1789
+		// don't bother re-validating if not a return visit
1790
+		if (! $this->checkout->revisit) {
1791
+			return true;
1792
+		}
1793
+		$registrations = $this->checkout->transaction->registrations();
1794
+		if (empty($registrations)) {
1795
+			return false;
1796
+		}
1797
+		foreach ($registrations as $registration) {
1798
+			if ($registration instanceof EE_Registration) {
1799
+				$event = $registration->event_obj();
1800
+				if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1801
+					EE_Error::add_error(
1802
+						apply_filters(
1803
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1804
+							sprintf(
1805
+								__('It appears that the %1$s event that you were about to make a payment for has sold out since you first registered and/or arrived at this page. Please refresh the page and try again. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
1806
+									'event_espresso'),
1807
+								$event->name()
1808
+							)
1809
+						),
1810
+						__FILE__,
1811
+						__FUNCTION__,
1812
+						__LINE__
1813
+					);
1814
+					return false;
1815
+				}
1816
+			}
1817
+		}
1818
+		return true;
1819
+	}
1820
+
1821
+
1822
+	/**
1823
+	 * redirect_form
1824
+	 *
1825
+	 * @access public
1826
+	 * @return bool
1827
+	 * @throws \EE_Error
1828
+	 */
1829
+	public function redirect_form()
1830
+	{
1831
+		$payment_method_billing_info = $this->_payment_method_billing_info(
1832
+			$this->_get_payment_method_for_selected_method_of_payment()
1833
+		);
1834
+		$html                        = $payment_method_billing_info->get_html();
1835
+		$html                        .= $this->checkout->redirect_form;
1836
+		EE_Registry::instance()->REQ->add_output($html);
1837
+		return true;
1838
+	}
1839
+
1840
+
1841
+	/**
1842
+	 * _billing_form_is_valid
1843
+	 *
1844
+	 * @access private
1845
+	 * @return bool
1846
+	 * @throws \EE_Error
1847
+	 */
1848
+	private function _billing_form_is_valid()
1849
+	{
1850
+		if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1851
+			return true;
1852
+		}
1853
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1854
+			if ($this->checkout->billing_form->was_submitted()) {
1855
+				$this->checkout->billing_form->receive_form_submission();
1856
+				if ($this->checkout->billing_form->is_valid()) {
1857
+					return true;
1858
+				}
1859
+				$validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1860
+				$error_strings     = array();
1861
+				foreach ($validation_errors as $validation_error) {
1862
+					if ($validation_error instanceof EE_Validation_Error) {
1863
+						$form_section = $validation_error->get_form_section();
1864
+						if ($form_section instanceof EE_Form_Input_Base) {
1865
+							$label = $form_section->html_label_text();
1866
+						} elseif ($form_section instanceof EE_Form_Section_Base) {
1867
+							$label = $form_section->name();
1868
+						} else {
1869
+							$label = __('Validation Error', 'event_espresso');
1870
+						}
1871
+						$error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
1872
+					}
1873
+				}
1874
+				EE_Error::add_error(
1875
+					sprintf(
1876
+						__(
1877
+							'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
1878
+							'event_espresso'
1879
+						),
1880
+						'<br/>',
1881
+						implode('<br/>', $error_strings)
1882
+					),
1883
+					__FILE__,
1884
+					__FUNCTION__,
1885
+					__LINE__
1886
+				);
1887
+			} else {
1888
+				EE_Error::add_error(
1889
+					__(
1890
+						'The billing form was not submitted or something prevented it\'s submission.',
1891
+						'event_espresso'
1892
+					),
1893
+					__FILE__,
1894
+					__FUNCTION__,
1895
+					__LINE__
1896
+				);
1897
+			}
1898
+		} else {
1899
+			EE_Error::add_error(
1900
+				__('The submitted billing form is invalid possibly due to a technical reason.', 'event_espresso'),
1901
+				__FILE__,
1902
+				__FUNCTION__,
1903
+				__LINE__
1904
+			);
1905
+		}
1906
+		return false;
1907
+	}
1908
+
1909
+
1910
+	/**
1911
+	 * _setup_primary_registrant_prior_to_payment
1912
+	 * ensures that the primary registrant has a valid attendee object created with the critical details populated
1913
+	 * (first & last name & email) and that both the transaction object and primary registration object have been saved
1914
+	 * plz note that any other registrations will NOT be saved at this point (because they may not have any details
1915
+	 * yet)
1916
+	 *
1917
+	 * @access private
1918
+	 * @return bool
1919
+	 * @throws \EE_Error
1920
+	 */
1921
+	private function _setup_primary_registrant_prior_to_payment()
1922
+	{
1923
+		// check if transaction has a primary registrant and that it has a related Attendee object
1924
+		// if not, then we need to at least gather some primary registrant data before attempting payment
1925
+		if (
1926
+			$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1927
+			&& ! $this->checkout->transaction_has_primary_registrant()
1928
+			&& ! $this->_capture_primary_registration_data_from_billing_form()
1929
+		) {
1930
+			return false;
1931
+		}
1932
+		// because saving an object clears it's cache, we need to do the chevy shuffle
1933
+		// grab the primary_registration object
1934
+		$primary_registration = $this->checkout->transaction->primary_registration();
1935
+		// at this point we'll consider a TXN to not have been failed
1936
+		$this->checkout->transaction->toggle_failed_transaction_status();
1937
+		// save the TXN ( which clears cached copy of primary_registration)
1938
+		$this->checkout->transaction->save();
1939
+		// grab TXN ID and save it to the primary_registration
1940
+		$primary_registration->set_transaction_id($this->checkout->transaction->ID());
1941
+		// save what we have so far
1942
+		$primary_registration->save();
1943
+		return true;
1944
+	}
1945
+
1946
+
1947
+	/**
1948
+	 * _capture_primary_registration_data_from_billing_form
1949
+	 *
1950
+	 * @access private
1951
+	 * @return bool
1952
+	 * @throws \EE_Error
1953
+	 */
1954
+	private function _capture_primary_registration_data_from_billing_form()
1955
+	{
1956
+		// convert billing form data into an attendee
1957
+		$this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
1958
+		if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
1959
+			EE_Error::add_error(
1960
+				sprintf(
1961
+					__(
1962
+						'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
1963
+						'event_espresso'
1964
+					),
1965
+					'<br/>',
1966
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
1967
+				),
1968
+				__FILE__,
1969
+				__FUNCTION__,
1970
+				__LINE__
1971
+			);
1972
+			return false;
1973
+		}
1974
+		$primary_registration = $this->checkout->transaction->primary_registration();
1975
+		if (! $primary_registration instanceof EE_Registration) {
1976
+			EE_Error::add_error(
1977
+				sprintf(
1978
+					__(
1979
+						'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
1980
+						'event_espresso'
1981
+					),
1982
+					'<br/>',
1983
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
1984
+				),
1985
+				__FILE__,
1986
+				__FUNCTION__,
1987
+				__LINE__
1988
+			);
1989
+			return false;
1990
+		}
1991
+		if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
1992
+			  instanceof
1993
+			  EE_Attendee
1994
+		) {
1995
+			EE_Error::add_error(
1996
+				sprintf(
1997
+					__(
1998
+						'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
1999
+						'event_espresso'
2000
+					),
2001
+					'<br/>',
2002
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2003
+				),
2004
+				__FILE__,
2005
+				__FUNCTION__,
2006
+				__LINE__
2007
+			);
2008
+			return false;
2009
+		}
2010
+		/** @type EE_Registration_Processor $registration_processor */
2011
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2012
+		// at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2013
+		$registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2014
+		return true;
2015
+	}
2016
+
2017
+
2018
+	/**
2019
+	 * _get_payment_method_for_selected_method_of_payment
2020
+	 * retrieves a valid payment method
2021
+	 *
2022
+	 * @access public
2023
+	 * @return \EE_Payment_Method
2024
+	 * @throws \EE_Error
2025
+	 */
2026
+	private function _get_payment_method_for_selected_method_of_payment()
2027
+	{
2028
+		if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2029
+			$this->_redirect_because_event_sold_out();
2030
+			return null;
2031
+		}
2032
+		// get EE_Payment_Method object
2033
+		if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2034
+			$payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2035
+		} else {
2036
+			// load EEM_Payment_Method
2037
+			EE_Registry::instance()->load_model('Payment_Method');
2038
+			/** @type EEM_Payment_Method $EEM_Payment_Method */
2039
+			$EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
2040
+			$payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2041
+		}
2042
+		// verify $payment_method
2043
+		if (! $payment_method instanceof EE_Payment_Method) {
2044
+			// not a payment
2045
+			EE_Error::add_error(
2046
+				sprintf(
2047
+					__(
2048
+						'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2049
+						'event_espresso'
2050
+					),
2051
+					'<br/>',
2052
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2053
+				),
2054
+				__FILE__,
2055
+				__FUNCTION__,
2056
+				__LINE__
2057
+			);
2058
+			return null;
2059
+		}
2060
+		// and verify it has a valid Payment_Method Type object
2061
+		if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2062
+			// not a payment
2063
+			EE_Error::add_error(
2064
+				sprintf(
2065
+					__(
2066
+						'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2067
+						'event_espresso'
2068
+					),
2069
+					'<br/>',
2070
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2071
+				),
2072
+				__FILE__,
2073
+				__FUNCTION__,
2074
+				__LINE__
2075
+			);
2076
+			return null;
2077
+		}
2078
+		return $payment_method;
2079
+	}
2080
+
2081
+
2082
+	/**
2083
+	 *    _attempt_payment
2084
+	 *
2085
+	 * @access    private
2086
+	 * @type    EE_Payment_Method $payment_method
2087
+	 * @return    mixed    EE_Payment | boolean
2088
+	 * @throws \EE_Error
2089
+	 */
2090
+	private function _attempt_payment(EE_Payment_Method $payment_method)
2091
+	{
2092
+		$payment = null;
2093
+		$this->checkout->transaction->save();
2094
+		$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2095
+		if (! $payment_processor instanceof EE_Payment_Processor) {
2096
+			return false;
2097
+		}
2098
+		try {
2099
+			$payment_processor->set_revisit($this->checkout->revisit);
2100
+			// generate payment object
2101
+			$payment = $payment_processor->process_payment(
2102
+				$payment_method,
2103
+				$this->checkout->transaction,
2104
+				$this->checkout->amount_owing,
2105
+				$this->checkout->billing_form,
2106
+				$this->_get_return_url($payment_method),
2107
+				'CART',
2108
+				$this->checkout->admin_request,
2109
+				true,
2110
+				$this->reg_step_url()
2111
+			);
2112
+		} catch (Exception $e) {
2113
+			$this->_handle_payment_processor_exception($e);
2114
+		}
2115
+		return $payment;
2116
+	}
2117
+
2118
+
2119
+	/**
2120
+	 * _handle_payment_processor_exception
2121
+	 *
2122
+	 * @access protected
2123
+	 * @param \Exception $e
2124
+	 * @return void
2125
+	 * @throws \EE_Error
2126
+	 */
2127
+	protected function _handle_payment_processor_exception(Exception $e)
2128
+	{
2129
+		EE_Error::add_error(
2130
+			sprintf(
2131
+				__(
2132
+					'The payment could not br processed due to a technical issue.%1$sPlease try again or contact %2$s for assistance.||The following Exception was thrown in %4$s on line %5$s:%1$s%3$s',
2133
+					'event_espresso'
2134
+				),
2135
+				'<br/>',
2136
+				EE_Registry::instance()->CFG->organization->get_pretty('email'),
2137
+				$e->getMessage(),
2138
+				$e->getFile(),
2139
+				$e->getLine()
2140
+			),
2141
+			__FILE__,
2142
+			__FUNCTION__,
2143
+			__LINE__
2144
+		);
2145
+	}
2146
+
2147
+
2148
+	/**
2149
+	 * _get_return_url
2150
+	 *
2151
+	 * @access protected
2152
+	 * @param \EE_Payment_Method $payment_method
2153
+	 * @return string
2154
+	 * @throws \EE_Error
2155
+	 */
2156
+	protected function _get_return_url(EE_Payment_Method $payment_method)
2157
+	{
2158
+		$return_url = '';
2159
+		switch ($payment_method->type_obj()->payment_occurs()) {
2160
+			case EE_PMT_Base::offsite :
2161
+				$return_url = add_query_arg(
2162
+					array(
2163
+						'action'                     => 'process_gateway_response',
2164
+						'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2165
+						'spco_txn'                   => $this->checkout->transaction->ID(),
2166
+					),
2167
+					$this->reg_step_url()
2168
+				);
2169
+				break;
2170
+			case EE_PMT_Base::onsite :
2171
+			case EE_PMT_Base::offline :
2172
+				$return_url = $this->checkout->next_step->reg_step_url();
2173
+				break;
2174
+		}
2175
+		return $return_url;
2176
+	}
2177
+
2178
+
2179
+	/**
2180
+	 * _validate_payment
2181
+	 *
2182
+	 * @access private
2183
+	 * @param EE_Payment $payment
2184
+	 * @return EE_Payment | FALSE
2185
+	 * @throws \EE_Error
2186
+	 */
2187
+	private function _validate_payment($payment = null)
2188
+	{
2189
+		if ($this->checkout->payment_method->is_off_line()) {
2190
+			return true;
2191
+		}
2192
+		// verify payment object
2193
+		if (! $payment instanceof EE_Payment) {
2194
+			// not a payment
2195
+			EE_Error::add_error(
2196
+				sprintf(
2197
+					__(
2198
+						'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2199
+						'event_espresso'
2200
+					),
2201
+					'<br/>',
2202
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2203
+				),
2204
+				__FILE__,
2205
+				__FUNCTION__,
2206
+				__LINE__
2207
+			);
2208
+			return false;
2209
+		}
2210
+		return $payment;
2211
+	}
2212
+
2213
+
2214
+	/**
2215
+	 * _post_payment_processing
2216
+	 *
2217
+	 * @access private
2218
+	 * @param EE_Payment|bool $payment
2219
+	 * @return bool
2220
+	 * @throws \EE_Error
2221
+	 */
2222
+	private function _post_payment_processing($payment = null)
2223
+	{
2224
+		// Off-Line payment?
2225
+		if ($payment === true) {
2226
+			//$this->_setup_redirect_for_next_step();
2227
+			return true;
2228
+			// On-Site payment?
2229
+		} else if ($this->checkout->payment_method->is_on_site()) {
2230
+			if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2231
+				//$this->_setup_redirect_for_next_step();
2232
+				$this->checkout->continue_reg = false;
2233
+			}
2234
+			// Off-Site payment?
2235
+		} else if ($this->checkout->payment_method->is_off_site()) {
2236
+			// if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2237
+			if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2238
+				do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2239
+				$this->checkout->redirect      = true;
2240
+				$this->checkout->redirect_form = $payment->redirect_form();
2241
+				$this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2242
+				// set JSON response
2243
+				$this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2244
+				// set cron job for finalizing the TXN
2245
+				// in case the user does not return from the off-site gateway
2246
+				EE_Cron_Tasks::schedule_finalize_abandoned_transactions_check(
2247
+					EE_Registry::instance()->SSN->expiration() + 1,
2248
+					$this->checkout->transaction->ID()
2249
+				);
2250
+				// and lastly, let's bump the payment status to pending
2251
+				$payment->set_status(EEM_Payment::status_id_pending);
2252
+				$payment->save();
2253
+			} else {
2254
+				// not a payment
2255
+				$this->checkout->continue_reg = false;
2256
+				EE_Error::add_error(
2257
+					sprintf(
2258
+						__(
2259
+							'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2260
+							'event_espresso'
2261
+						),
2262
+						'<br/>',
2263
+						EE_Registry::instance()->CFG->organization->get_pretty('email')
2264
+					),
2265
+					__FILE__,
2266
+					__FUNCTION__,
2267
+					__LINE__
2268
+				);
2269
+			}
2270
+		} else {
2271
+			// ummm ya... not Off-Line, not On-Site, not off-Site ????
2272
+			$this->checkout->continue_reg = false;
2273
+			return false;
2274
+		}
2275
+		return $payment;
2276
+	}
2277
+
2278
+
2279
+
2280
+	/**
2281
+	 *    _setup_redirect_for_next_step
2282
+	 *
2283
+	 * @access private
2284
+	 * @return    void
2285
+	 */
2286
+	//private function _setup_redirect_for_next_step() {
2287
+	//$this->checkout->redirect = TRUE;
2288
+	//$this->checkout->redirect_url = $this->checkout->next_step->reg_step_url();
2289
+	// set JSON response
2290
+	//$this->checkout->json_response->set_redirect_url( $this->checkout->redirect_url );
2291
+	//}
2292
+	/**
2293
+	 *    _process_payment_status
2294
+	 *
2295
+	 * @access private
2296
+	 * @type    EE_Payment $payment
2297
+	 * @param string       $payment_occurs
2298
+	 * @return bool
2299
+	 * @throws \EE_Error
2300
+	 */
2301
+	private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2302
+	{
2303
+		// off-line payment? carry on
2304
+		if ($payment_occurs === EE_PMT_Base::offline) {
2305
+			return true;
2306
+		}
2307
+		// verify payment validity
2308
+		if ($payment instanceof EE_Payment) {
2309
+			do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2310
+			$msg = $payment->gateway_response();
2311
+			// check results
2312
+			switch ($payment->status()) {
2313
+				// good payment
2314
+				case EEM_Payment::status_id_approved :
2315
+					EE_Error::add_success(
2316
+						__('Your payment was processed successfully.', 'event_espresso'),
2317
+						__FILE__,
2318
+						__FUNCTION__,
2319
+						__LINE__
2320
+					);
2321
+					return true;
2322
+					break;
2323
+				// slow payment
2324
+				case EEM_Payment::status_id_pending :
2325
+					if (empty($msg)) {
2326
+						$msg = __(
2327
+							'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2328
+							'event_espresso'
2329
+						);
2330
+					}
2331
+					EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2332
+					return true;
2333
+					break;
2334
+				// don't wanna payment
2335
+				case EEM_Payment::status_id_cancelled :
2336
+					if (empty($msg)) {
2337
+						$msg = _n(
2338
+							'Payment cancelled. Please try again.',
2339
+							'Payment cancelled. Please try again or select another method of payment.',
2340
+							count($this->checkout->available_payment_methods),
2341
+							'event_espresso'
2342
+						);
2343
+					}
2344
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2345
+					return false;
2346
+					break;
2347
+				// not enough payment
2348
+				case EEM_Payment::status_id_declined :
2349
+					if (empty($msg)) {
2350
+						$msg = _n(
2351
+							'We\'re sorry but your payment was declined. Please try again.',
2352
+							'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2353
+							count($this->checkout->available_payment_methods),
2354
+							'event_espresso'
2355
+						);
2356
+					}
2357
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2358
+					return false;
2359
+					break;
2360
+				// bad payment
2361
+				case EEM_Payment::status_id_failed :
2362
+					if (! empty($msg)) {
2363
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2364
+						return false;
2365
+					}
2366
+					// default to error below
2367
+					break;
2368
+			}
2369
+		}
2370
+		// off-site payment gateway responses are too unreliable, so let's just assume that
2371
+		// the payment processing is just running slower than the registrant's request
2372
+		if ($payment_occurs === EE_PMT_Base::offsite) {
2373
+			return true;
2374
+		}
2375
+		EE_Error::add_error(
2376
+			sprintf(
2377
+				__(
2378
+					'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2379
+					'event_espresso'
2380
+				),
2381
+				'<br/>',
2382
+				EE_Registry::instance()->CFG->organization->get_pretty('email')
2383
+			),
2384
+			__FILE__,
2385
+			__FUNCTION__,
2386
+			__LINE__
2387
+		);
2388
+		return false;
2389
+	}
2390
+
2391
+
2392
+
2393
+
2394
+
2395
+
2396
+	/********************************************************************************************************/
2397
+	/**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2398
+	/********************************************************************************************************/
2399
+	/**
2400
+	 * process_gateway_response
2401
+	 * this is the return point for Off-Site Payment Methods
2402
+	 * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2403
+	 * otherwise, it will load up the last payment made for the TXN.
2404
+	 * If the payment retrieved looks good, it will then either:
2405
+	 *    complete the current step and allow advancement to the next reg step
2406
+	 *        or present the payment options again
2407
+	 *
2408
+	 * @access private
2409
+	 * @return EE_Payment | FALSE
2410
+	 * @throws \EE_Error
2411
+	 */
2412
+	public function process_gateway_response()
2413
+	{
2414
+		$payment = null;
2415
+		// how have they chosen to pay?
2416
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2417
+		// get EE_Payment_Method object
2418
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2419
+			$this->checkout->continue_reg = false;
2420
+			return false;
2421
+		}
2422
+		if (! $this->checkout->payment_method->is_off_site()) {
2423
+			return false;
2424
+		}
2425
+		$this->_validate_offsite_return();
2426
+		// DEBUG LOG
2427
+		//$this->checkout->log(
2428
+		//	__CLASS__, __FUNCTION__, __LINE__,
2429
+		//	array(
2430
+		//		'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2431
+		//		'payment_method' => $this->checkout->payment_method,
2432
+		//	),
2433
+		//	true
2434
+		//);
2435
+		// verify TXN
2436
+		if ($this->checkout->transaction instanceof EE_Transaction) {
2437
+			$gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2438
+			if (! $gateway instanceof EE_Offsite_Gateway) {
2439
+				$this->checkout->continue_reg = false;
2440
+				return false;
2441
+			}
2442
+			$payment = $this->_process_off_site_payment($gateway);
2443
+			$payment = $this->_process_cancelled_payments($payment);
2444
+			$payment = $this->_validate_payment($payment);
2445
+			// if payment was not declined by the payment gateway or cancelled by the registrant
2446
+			if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2447
+				//$this->_setup_redirect_for_next_step();
2448
+				// store that for later
2449
+				$this->checkout->payment = $payment;
2450
+				// mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2451
+				// because we will complete this step during the IPN processing then
2452
+				if ($gateway instanceof EE_Offsite_Gateway && ! $this->handle_IPN_in_this_request()) {
2453
+					$this->set_completed();
2454
+				}
2455
+				return true;
2456
+			}
2457
+		}
2458
+		// DEBUG LOG
2459
+		//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2460
+		//	array( 'payment' => $payment )
2461
+		//);
2462
+		$this->checkout->continue_reg = false;
2463
+		return false;
2464
+	}
2465
+
2466
+
2467
+	/**
2468
+	 * _validate_return
2469
+	 *
2470
+	 * @access private
2471
+	 * @return void
2472
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2473
+	 * @throws \EE_Error
2474
+	 */
2475
+	private function _validate_offsite_return()
2476
+	{
2477
+		$TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2478
+		if ($TXN_ID !== $this->checkout->transaction->ID()) {
2479
+			// Houston... we might have a problem
2480
+			$invalid_TXN = false;
2481
+			// first gather some info
2482
+			$valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2483
+			$primary_registrant = $valid_TXN instanceof EE_Transaction
2484
+				? $valid_TXN->primary_registration()
2485
+				: null;
2486
+			// let's start by retrieving the cart for this TXN
2487
+			$cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2488
+			if ($cart instanceof EE_Cart) {
2489
+				// verify that the current cart has tickets
2490
+				$tickets = $cart->get_tickets();
2491
+				if (empty($tickets)) {
2492
+					$invalid_TXN = true;
2493
+				}
2494
+			} else {
2495
+				$invalid_TXN = true;
2496
+			}
2497
+			$valid_TXN_SID = $primary_registrant instanceof EE_Registration
2498
+				? $primary_registrant->session_ID()
2499
+				: null;
2500
+			// validate current Session ID and compare against valid TXN session ID
2501
+			if (
2502
+				$invalid_TXN // if this is already true, then skip other checks
2503
+				|| EE_Session::instance()->id() === null
2504
+				|| (
2505
+					// WARNING !!!
2506
+					// this could be PayPal sending back duplicate requests (ya they do that)
2507
+					// or it **could** mean someone is simply registering AGAIN after having just done so
2508
+					// so now we need to determine if this current TXN looks valid or not
2509
+					// and whether this reg step has even been started ?
2510
+					EE_Session::instance()->id() === $valid_TXN_SID
2511
+					// really? you're half way through this reg step, but you never started it ?
2512
+					&& $this->checkout->transaction->reg_step_completed($this->slug()) === false
2513
+				)
2514
+			) {
2515
+				$invalid_TXN = true;
2516
+			}
2517
+			if ($invalid_TXN) {
2518
+				// is the valid TXN completed ?
2519
+				if ($valid_TXN instanceof EE_Transaction) {
2520
+					// has this step even been started ?
2521
+					$reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2522
+					if ($reg_step_completed !== false && $reg_step_completed !== true) {
2523
+						// so it **looks** like this is a double request from PayPal
2524
+						// so let's try to pick up where we left off
2525
+						$this->checkout->transaction = $valid_TXN;
2526
+						$this->checkout->refresh_all_entities(true);
2527
+						return;
2528
+					}
2529
+				}
2530
+				// you appear to be lost?
2531
+				$this->_redirect_wayward_request($primary_registrant);
2532
+			}
2533
+		}
2534
+	}
2535
+
2536
+
2537
+	/**
2538
+	 * _redirect_wayward_request
2539
+	 *
2540
+	 * @access private
2541
+	 * @param \EE_Registration|null $primary_registrant
2542
+	 * @return bool
2543
+	 * @throws \EE_Error
2544
+	 */
2545
+	private function _redirect_wayward_request(EE_Registration $primary_registrant)
2546
+	{
2547
+		if (! $primary_registrant instanceof EE_Registration) {
2548
+			// try redirecting based on the current TXN
2549
+			$primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2550
+				? $this->checkout->transaction->primary_registration()
2551
+				: null;
2552
+		}
2553
+		if (! $primary_registrant instanceof EE_Registration) {
2554
+			EE_Error::add_error(
2555
+				sprintf(
2556
+					__(
2557
+						'Invalid information was received from the Off-Site Payment Processor and your Transaction details could not be retrieved from the database.%1$sPlease try again or contact %2$s for assistance.',
2558
+						'event_espresso'
2559
+					),
2560
+					'<br/>',
2561
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2562
+				),
2563
+				__FILE__,
2564
+				__FUNCTION__,
2565
+				__LINE__
2566
+			);
2567
+			return false;
2568
+		}
2569
+		// make sure transaction is not locked
2570
+		$this->checkout->transaction->unlock();
2571
+		wp_safe_redirect(
2572
+			add_query_arg(
2573
+				array(
2574
+					'e_reg_url_link' => $primary_registrant->reg_url_link(),
2575
+				),
2576
+				$this->checkout->thank_you_page_url
2577
+			)
2578
+		);
2579
+		exit();
2580
+	}
2581
+
2582
+
2583
+	/**
2584
+	 * _process_off_site_payment
2585
+	 *
2586
+	 * @access private
2587
+	 * @param \EE_Offsite_Gateway $gateway
2588
+	 * @return \EE_Payment
2589
+	 * @throws \EE_Error
2590
+	 */
2591
+	private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2592
+	{
2593
+		try {
2594
+			$request_data = \EE_Registry::instance()->REQ->params();
2595
+			// if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2596
+			$this->set_handle_IPN_in_this_request(
2597
+				$gateway->handle_IPN_in_this_request($request_data, false)
2598
+			);
2599
+			if ($this->handle_IPN_in_this_request()) {
2600
+				// get payment details and process results
2601
+				/** @type EE_Payment_Processor $payment_processor */
2602
+				$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2603
+				$payment           = $payment_processor->process_ipn(
2604
+					$request_data,
2605
+					$this->checkout->transaction,
2606
+					$this->checkout->payment_method,
2607
+					true,
2608
+					false
2609
+				);
2610
+				//$payment_source = 'process_ipn';
2611
+			} else {
2612
+				$payment = $this->checkout->transaction->last_payment();
2613
+				//$payment_source = 'last_payment';
2614
+			}
2615
+		} catch (Exception $e) {
2616
+			// let's just eat the exception and try to move on using any previously set payment info
2617
+			$payment = $this->checkout->transaction->last_payment();
2618
+			//$payment_source = 'last_payment after Exception';
2619
+			// but if we STILL don't have a payment object
2620
+			if (! $payment instanceof EE_Payment) {
2621
+				// then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2622
+				$this->_handle_payment_processor_exception($e);
2623
+			}
2624
+		}
2625
+		// DEBUG LOG
2626
+		//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2627
+		//	array(
2628
+		//		'process_ipn_payment' => $payment,
2629
+		//		'payment_source'      => $payment_source,
2630
+		//	)
2631
+		//);
2632
+		return $payment;
2633
+	}
2634
+
2635
+
2636
+	/**
2637
+	 * _process_cancelled_payments
2638
+	 * just makes sure that the payment status gets updated correctly
2639
+	 * so tha tan error isn't generated during payment validation
2640
+	 *
2641
+	 * @access private
2642
+	 * @param EE_Payment $payment
2643
+	 * @return EE_Payment | FALSE
2644
+	 * @throws \EE_Error
2645
+	 */
2646
+	private function _process_cancelled_payments($payment = null)
2647
+	{
2648
+		if (
2649
+			$payment instanceof EE_Payment
2650
+			&& isset($_REQUEST['ee_cancel_payment'])
2651
+			&& $payment->status() === EEM_Payment::status_id_failed
2652
+		) {
2653
+			$payment->set_status(EEM_Payment::status_id_cancelled);
2654
+		}
2655
+		return $payment;
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 *    get_transaction_details_for_gateways
2661
+	 *
2662
+	 * @access    public
2663
+	 * @return    int
2664
+	 * @throws \EE_Error
2665
+	 */
2666
+	public function get_transaction_details_for_gateways()
2667
+	{
2668
+		$txn_details = array();
2669
+		// ya gotta make a choice man
2670
+		if (empty($this->checkout->selected_method_of_payment)) {
2671
+			$txn_details = array(
2672
+				'error' => __('Please select a method of payment before proceeding.', 'event_espresso'),
2673
+			);
2674
+		}
2675
+		// get EE_Payment_Method object
2676
+		if (
2677
+			empty($txn_details)
2678
+			&&
2679
+			! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2680
+		) {
2681
+			$txn_details = array(
2682
+				'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2683
+				'error'                      => __(
2684
+					'A valid Payment Method could not be determined.',
2685
+					'event_espresso'
2686
+				),
2687
+			);
2688
+		}
2689
+		if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2690
+			$return_url  = $this->_get_return_url($this->checkout->payment_method);
2691
+			$txn_details = array(
2692
+				'TXN_ID'         => $this->checkout->transaction->ID(),
2693
+				'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2694
+				'TXN_total'      => $this->checkout->transaction->total(),
2695
+				'TXN_paid'       => $this->checkout->transaction->paid(),
2696
+				'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2697
+				'STS_ID'         => $this->checkout->transaction->status_ID(),
2698
+				'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2699
+				'payment_amount' => $this->checkout->amount_owing,
2700
+				'return_url'     => $return_url,
2701
+				'cancel_url'     => add_query_arg(array('ee_cancel_payment' => true), $return_url),
2702
+				'notify_url'     => EE_Config::instance()->core->txn_page_url(
2703
+					array(
2704
+						'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2705
+						'ee_payment_method' => $this->checkout->payment_method->slug(),
2706
+					)
2707
+				),
2708
+			);
2709
+		}
2710
+		echo wp_json_encode($txn_details);
2711
+		exit();
2712
+	}
2713
+
2714
+
2715
+	/**
2716
+	 *    __sleep
2717
+	 * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2718
+	 * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2719
+	 * reg form, because if needed, it will be regenerated anyways
2720
+	 *
2721
+	 * @return array
2722
+	 */
2723
+	public function __sleep()
2724
+	{
2725
+		// remove the reg form and the checkout
2726
+		return array_diff(array_keys(get_object_vars($this)), array('reg_form', 'checkout', 'line_item_display'));
2727
+	}
2728 2728
 
2729 2729
 
2730 2730
 }
Please login to merge, or discard this patch.
Spacing   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -1,4 +1,4 @@  discard block
 block discarded – undo
1
-<?php if (! defined('EVENT_ESPRESSO_VERSION')) {
1
+<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2 2
     exit('No direct script access allowed');
3 3
 }
4 4
 
@@ -129,7 +129,7 @@  discard block
 block discarded – undo
129 129
     {
130 130
         $this->_slug     = 'payment_options';
131 131
         $this->_name     = __('Payment Options', 'event_espresso');
132
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
132
+        $this->_template = SPCO_REG_STEPS_PATH.$this->_slug.DS.'payment_options_main.template.php';
133 133
         $this->checkout  = $checkout;
134 134
         $this->_reset_success_message();
135 135
         $this->set_instructions(
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
      */
185 185
     public function translate_js_strings()
186 186
     {
187
-        EE_Registry::$i18n_js_strings['no_payment_method']      = __(
187
+        EE_Registry::$i18n_js_strings['no_payment_method'] = __(
188 188
             'Please select a method of payment in order to continue.',
189 189
             'event_espresso'
190 190
         );
@@ -192,7 +192,7 @@  discard block
 block discarded – undo
192 192
             'A valid method of payment could not be determined. Please refresh the page and try again.',
193 193
             'event_espresso'
194 194
         );
195
-        EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = __(
195
+        EE_Registry::$i18n_js_strings['forwarding_to_offsite'] = __(
196 196
             'Forwarding to Secure Payment Provider.',
197 197
             'event_espresso'
198 198
         );
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
     {
209 209
         $transaction = $this->checkout->transaction;
210 210
         //if the transaction isn't set or nothing is owed on it, don't enqueue any JS
211
-        if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
211
+        if ( ! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
212 212
             return;
213 213
         }
214 214
         foreach (
@@ -343,23 +343,23 @@  discard block
 block discarded – undo
343 343
         }
344 344
         $subsections = array();
345 345
         // now decide which template to load
346
-        if (! empty($sold_out_events)) {
346
+        if ( ! empty($sold_out_events)) {
347 347
             $subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
348 348
         }
349
-        if (! empty($insufficient_spaces_available)) {
349
+        if ( ! empty($insufficient_spaces_available)) {
350 350
             $subsections['insufficient_space'] = $this->_insufficient_spaces_available(
351 351
                 $insufficient_spaces_available
352 352
             );
353 353
         }
354
-        if (! empty($registrations_requiring_pre_approval)) {
354
+        if ( ! empty($registrations_requiring_pre_approval)) {
355 355
             $subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
356 356
                 $registrations_requiring_pre_approval
357 357
             );
358 358
         }
359
-        if (! empty($registrations_for_free_events)) {
359
+        if ( ! empty($registrations_for_free_events)) {
360 360
             $subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
361 361
         }
362
-        if (! empty($registrations_requiring_payment)) {
362
+        if ( ! empty($registrations_requiring_payment)) {
363 363
             if ($this->checkout->amount_owing > 0) {
364 364
                 // autoload Line_Item_Display classes
365 365
                 EEH_Autoloader::register_line_item_filter_autoloaders();
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
                         array('registrations' => $registrations)
381 381
                     )
382 382
                 );
383
-                $this->checkout->amount_owing   = $filtered_line_item_tree->total();
383
+                $this->checkout->amount_owing = $filtered_line_item_tree->total();
384 384
                 $this->_apply_registration_payments_to_amount_owing($registrations);
385 385
             }
386 386
             $no_payment_required = false;
@@ -418,13 +418,13 @@  discard block
 block discarded – undo
418 418
      */
419 419
     public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
420 420
     {
421
-        if (! EE_Registry::instance()->SSN instanceof EE_Session) {
421
+        if ( ! EE_Registry::instance()->SSN instanceof EE_Session) {
422 422
             return $line_item_filter_collection;
423 423
         }
424
-        if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
424
+        if ( ! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
425 425
             return $line_item_filter_collection;
426 426
         }
427
-        if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
427
+        if ( ! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
428 428
             return $line_item_filter_collection;
429 429
         }
430 430
         $line_item_filter_collection->add(
@@ -504,15 +504,15 @@  discard block
 block discarded – undo
504 504
             }
505 505
             $EVT_ID = $registration->event_ID();
506 506
             $ticket = $registration->ticket();
507
-            if (! isset($tickets_remaining[$ticket->ID()])) {
507
+            if ( ! isset($tickets_remaining[$ticket->ID()])) {
508 508
                 $tickets_remaining[$ticket->ID()] = $ticket->remaining();
509 509
             }
510 510
             if ($tickets_remaining[$ticket->ID()] > 0) {
511
-                if (! isset($event_reg_count[$EVT_ID])) {
511
+                if ( ! isset($event_reg_count[$EVT_ID])) {
512 512
                     $event_reg_count[$EVT_ID] = 0;
513 513
                 }
514 514
                 $event_reg_count[$EVT_ID]++;
515
-                if (! isset($event_spaces_remaining[$EVT_ID])) {
515
+                if ( ! isset($event_spaces_remaining[$EVT_ID])) {
516 516
                     $event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
517 517
                 }
518 518
             }
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
         $sold_out_events                            = '';
583 583
         foreach ($sold_out_events_array as $sold_out_event) {
584 584
             $sold_out_events .= EEH_HTML::li(
585
-                EEH_HTML::span('  ' . $sold_out_event->name(), '',
585
+                EEH_HTML::span('  '.$sold_out_event->name(), '',
586 586
                     'dashicons dashicons-marker ee-icon-size-16 pink-text')
587 587
             );
588 588
         }
@@ -634,7 +634,7 @@  discard block
 block discarded – undo
634 634
         foreach ($insufficient_spaces_events_array as $event) {
635 635
             if ($event instanceof EE_Event) {
636 636
                 $insufficient_space_events .= EEH_HTML::li(
637
-                    EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
637
+                    EEH_HTML::span(' '.$event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
638 638
                 );
639 639
             }
640 640
         }
@@ -820,7 +820,7 @@  discard block
 block discarded – undo
820 820
     {
821 821
         return new EE_Form_Section_Proper(
822 822
             array(
823
-                'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
823
+                'html_id'         => 'ee-'.$this->slug().'-extra-hidden-inputs',
824 824
                 'layout_strategy' => new EE_Div_Per_Section_Layout(),
825 825
                 'subsections'     => array(
826 826
                     'spco_no_payment_required' => new EE_Hidden_Input(
@@ -859,7 +859,7 @@  discard block
 block discarded – undo
859 859
                 $payments += $registration->registration_payments();
860 860
             }
861 861
         }
862
-        if (! empty($payments)) {
862
+        if ( ! empty($payments)) {
863 863
             foreach ($payments as $payment) {
864 864
                 if ($payment instanceof EE_Registration_Payment) {
865 865
                     $this->checkout->amount_owing -= $payment->amount();
@@ -921,7 +921,7 @@  discard block
 block discarded – undo
921 921
         // load payment method classes
922 922
         $this->checkout->available_payment_methods = $this->_get_available_payment_methods();
923 923
         // switch up header depending on number of available payment methods
924
-        $payment_method_header     = count($this->checkout->available_payment_methods) > 1
924
+        $payment_method_header = count($this->checkout->available_payment_methods) > 1
925 925
             ? apply_filters(
926 926
                 'FHEE__registration_page_payment_options__method_of_payment_hdr',
927 927
                 __('Please Select Your Method of Payment', 'event_espresso')
@@ -951,14 +951,14 @@  discard block
 block discarded – undo
951 951
                 $payment_method_button = EEH_HTML::img(
952 952
                     $payment_method->button_url(),
953 953
                     $payment_method->name(),
954
-                    'spco-payment-method-' . $payment_method->slug() . '-btn-img',
954
+                    'spco-payment-method-'.$payment_method->slug().'-btn-img',
955 955
                     'spco-payment-method-btn-img'
956 956
                 );
957 957
                 // check if any payment methods are set as default
958 958
                 // if payment method is already selected OR nothing is selected and this payment method should be open_by_default
959 959
                 if (
960 960
                     ($this->checkout->selected_method_of_payment === $payment_method->slug())
961
-                    || (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
961
+                    || ( ! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
962 962
                 ) {
963 963
                     $this->checkout->selected_method_of_payment = $payment_method->slug();
964 964
                     $this->_save_selected_method_of_payment();
@@ -978,7 +978,7 @@  discard block
 block discarded – undo
978 978
         $available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
979 979
             $available_payment_method_options
980 980
         );
981
-        $available_payment_methods                              += $payment_methods_billing_info;
981
+        $available_payment_methods += $payment_methods_billing_info;
982 982
         // build the available payment methods form
983 983
         return new EE_Form_Section_Proper(
984 984
             array(
@@ -997,7 +997,7 @@  discard block
 block discarded – undo
997 997
      */
998 998
     protected function _get_available_payment_methods()
999 999
     {
1000
-        if (! empty($this->checkout->available_payment_methods)) {
1000
+        if ( ! empty($this->checkout->available_payment_methods)) {
1001 1001
             return $this->checkout->available_payment_methods;
1002 1002
         }
1003 1003
         $available_payment_methods = array();
@@ -1034,7 +1034,7 @@  discard block
 block discarded – undo
1034 1034
                 'html_id'         => 'ee-available-payment-method-inputs',
1035 1035
                 'layout_strategy' => new EE_Div_Per_Section_Layout(),
1036 1036
                 'subsections'     => array(
1037
-                    '' => new EE_Radio_Button_Input (
1037
+                    '' => new EE_Radio_Button_Input(
1038 1038
                         $available_payment_method_options,
1039 1039
                         array(
1040 1040
                             'html_name'          => 'selected_method_of_payment',
@@ -1104,7 +1104,7 @@  discard block
 block discarded – undo
1104 1104
         );
1105 1105
         return new EE_Form_Section_Proper(
1106 1106
             array(
1107
-                'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1107
+                'html_id'         => 'spco-payment-method-info-'.$payment_method->slug(),
1108 1108
                 'html_class'      => 'spco-payment-method-info-dv',
1109 1109
                 // only display the selected or default PM
1110 1110
                 'html_style'      => $currently_selected ? '' : 'display:none;',
@@ -1130,7 +1130,7 @@  discard block
 block discarded – undo
1130 1130
         // how have they chosen to pay?
1131 1131
         $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1132 1132
         $this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1133
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1133
+        if ( ! $this->checkout->payment_method instanceof EE_Payment_Method) {
1134 1134
             return false;
1135 1135
         }
1136 1136
         if (apply_filters(
@@ -1295,7 +1295,7 @@  discard block
 block discarded – undo
1295 1295
      */
1296 1296
     public function switch_payment_method()
1297 1297
     {
1298
-        if (! $this->_verify_payment_method_is_set()) {
1298
+        if ( ! $this->_verify_payment_method_is_set()) {
1299 1299
             return false;
1300 1300
         }
1301 1301
         if (apply_filters(
@@ -1414,7 +1414,7 @@  discard block
 block discarded – undo
1414 1414
             }
1415 1415
         }
1416 1416
         // verify payment method
1417
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1417
+        if ( ! $this->checkout->payment_method instanceof EE_Payment_Method) {
1418 1418
             // get payment method for selected method of payment
1419 1419
             $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1420 1420
         }
@@ -1434,7 +1434,7 @@  discard block
 block discarded – undo
1434 1434
      */
1435 1435
     public function save_payer_details_via_ajax()
1436 1436
     {
1437
-        if (! $this->_verify_payment_method_is_set()) {
1437
+        if ( ! $this->_verify_payment_method_is_set()) {
1438 1438
             return;
1439 1439
         }
1440 1440
         // generate billing form for selected method of payment if it hasn't been done already
@@ -1444,7 +1444,7 @@  discard block
 block discarded – undo
1444 1444
             );
1445 1445
         }
1446 1446
         // generate primary attendee from payer info if applicable
1447
-        if (! $this->checkout->transaction_has_primary_registrant()) {
1447
+        if ( ! $this->checkout->transaction_has_primary_registrant()) {
1448 1448
             $attendee = $this->_create_attendee_from_request_data();
1449 1449
             if ($attendee instanceof EE_Attendee) {
1450 1450
                 foreach ($this->checkout->transaction->registrations() as $registration) {
@@ -1471,7 +1471,7 @@  discard block
 block discarded – undo
1471 1471
     {
1472 1472
         // get State ID
1473 1473
         $STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1474
-        if (! empty($STA_ID)) {
1474
+        if ( ! empty($STA_ID)) {
1475 1475
             // can we get state object from name ?
1476 1476
             EE_Registry::instance()->load_model('State');
1477 1477
             $state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
@@ -1479,7 +1479,7 @@  discard block
 block discarded – undo
1479 1479
         }
1480 1480
         // get Country ISO
1481 1481
         $CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1482
-        if (! empty($CNT_ISO)) {
1482
+        if ( ! empty($CNT_ISO)) {
1483 1483
             // can we get country object from name ?
1484 1484
             EE_Registry::instance()->load_model('Country');
1485 1485
             $country = EEM_Country::instance()->get_col(
@@ -1511,7 +1511,7 @@  discard block
 block discarded – undo
1511 1511
             );
1512 1512
         }
1513 1513
         // does this attendee already exist in the db ? we're searching using a combination of first name, last name, AND email address
1514
-        if (! empty($attendee_data['ATT_fname'])
1514
+        if ( ! empty($attendee_data['ATT_fname'])
1515 1515
             && ! empty($attendee_data['ATT_lname'])
1516 1516
             && ! empty($attendee_data['ATT_email'])
1517 1517
         ) {
@@ -1710,7 +1710,7 @@  discard block
 block discarded – undo
1710 1710
     private function _process_payment()
1711 1711
     {
1712 1712
         // basically confirm that the event hasn't sold out since they hit the page
1713
-        if (! $this->_last_second_ticket_verifications()) {
1713
+        if ( ! $this->_last_second_ticket_verifications()) {
1714 1714
             return false;
1715 1715
         }
1716 1716
         // ya gotta make a choice man
@@ -1721,7 +1721,7 @@  discard block
 block discarded – undo
1721 1721
             return false;
1722 1722
         }
1723 1723
         // get EE_Payment_Method object
1724
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1724
+        if ( ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1725 1725
             return false;
1726 1726
         }
1727 1727
         // setup billing form
@@ -1730,12 +1730,12 @@  discard block
 block discarded – undo
1730 1730
                 $this->checkout->payment_method
1731 1731
             );
1732 1732
             // bad billing form ?
1733
-            if (! $this->_billing_form_is_valid()) {
1733
+            if ( ! $this->_billing_form_is_valid()) {
1734 1734
                 return false;
1735 1735
             }
1736 1736
         }
1737 1737
         // ensure primary registrant has been fully processed
1738
-        if (! $this->_setup_primary_registrant_prior_to_payment()) {
1738
+        if ( ! $this->_setup_primary_registrant_prior_to_payment()) {
1739 1739
             return false;
1740 1740
         }
1741 1741
         // if session is close to expiring (under 10 minutes by default)
@@ -1787,7 +1787,7 @@  discard block
 block discarded – undo
1787 1787
     protected function _last_second_ticket_verifications()
1788 1788
     {
1789 1789
         // don't bother re-validating if not a return visit
1790
-        if (! $this->checkout->revisit) {
1790
+        if ( ! $this->checkout->revisit) {
1791 1791
             return true;
1792 1792
         }
1793 1793
         $registrations = $this->checkout->transaction->registrations();
@@ -1832,7 +1832,7 @@  discard block
 block discarded – undo
1832 1832
             $this->_get_payment_method_for_selected_method_of_payment()
1833 1833
         );
1834 1834
         $html                        = $payment_method_billing_info->get_html();
1835
-        $html                        .= $this->checkout->redirect_form;
1835
+        $html .= $this->checkout->redirect_form;
1836 1836
         EE_Registry::instance()->REQ->add_output($html);
1837 1837
         return true;
1838 1838
     }
@@ -1847,7 +1847,7 @@  discard block
 block discarded – undo
1847 1847
      */
1848 1848
     private function _billing_form_is_valid()
1849 1849
     {
1850
-        if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1850
+        if ( ! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1851 1851
             return true;
1852 1852
         }
1853 1853
         if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
@@ -1955,7 +1955,7 @@  discard block
 block discarded – undo
1955 1955
     {
1956 1956
         // convert billing form data into an attendee
1957 1957
         $this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
1958
-        if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
1958
+        if ( ! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
1959 1959
             EE_Error::add_error(
1960 1960
                 sprintf(
1961 1961
                     __(
@@ -1972,7 +1972,7 @@  discard block
 block discarded – undo
1972 1972
             return false;
1973 1973
         }
1974 1974
         $primary_registration = $this->checkout->transaction->primary_registration();
1975
-        if (! $primary_registration instanceof EE_Registration) {
1975
+        if ( ! $primary_registration instanceof EE_Registration) {
1976 1976
             EE_Error::add_error(
1977 1977
                 sprintf(
1978 1978
                     __(
@@ -1988,7 +1988,7 @@  discard block
 block discarded – undo
1988 1988
             );
1989 1989
             return false;
1990 1990
         }
1991
-        if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
1991
+        if ( ! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
1992 1992
               instanceof
1993 1993
               EE_Attendee
1994 1994
         ) {
@@ -2040,7 +2040,7 @@  discard block
 block discarded – undo
2040 2040
             $payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2041 2041
         }
2042 2042
         // verify $payment_method
2043
-        if (! $payment_method instanceof EE_Payment_Method) {
2043
+        if ( ! $payment_method instanceof EE_Payment_Method) {
2044 2044
             // not a payment
2045 2045
             EE_Error::add_error(
2046 2046
                 sprintf(
@@ -2058,7 +2058,7 @@  discard block
 block discarded – undo
2058 2058
             return null;
2059 2059
         }
2060 2060
         // and verify it has a valid Payment_Method Type object
2061
-        if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2061
+        if ( ! $payment_method->type_obj() instanceof EE_PMT_Base) {
2062 2062
             // not a payment
2063 2063
             EE_Error::add_error(
2064 2064
                 sprintf(
@@ -2092,7 +2092,7 @@  discard block
 block discarded – undo
2092 2092
         $payment = null;
2093 2093
         $this->checkout->transaction->save();
2094 2094
         $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2095
-        if (! $payment_processor instanceof EE_Payment_Processor) {
2095
+        if ( ! $payment_processor instanceof EE_Payment_Processor) {
2096 2096
             return false;
2097 2097
         }
2098 2098
         try {
@@ -2190,7 +2190,7 @@  discard block
 block discarded – undo
2190 2190
             return true;
2191 2191
         }
2192 2192
         // verify payment object
2193
-        if (! $payment instanceof EE_Payment) {
2193
+        if ( ! $payment instanceof EE_Payment) {
2194 2194
             // not a payment
2195 2195
             EE_Error::add_error(
2196 2196
                 sprintf(
@@ -2227,7 +2227,7 @@  discard block
 block discarded – undo
2227 2227
             return true;
2228 2228
             // On-Site payment?
2229 2229
         } else if ($this->checkout->payment_method->is_on_site()) {
2230
-            if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2230
+            if ( ! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2231 2231
                 //$this->_setup_redirect_for_next_step();
2232 2232
                 $this->checkout->continue_reg = false;
2233 2233
             }
@@ -2359,7 +2359,7 @@  discard block
 block discarded – undo
2359 2359
                     break;
2360 2360
                 // bad payment
2361 2361
                 case EEM_Payment::status_id_failed :
2362
-                    if (! empty($msg)) {
2362
+                    if ( ! empty($msg)) {
2363 2363
                         EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2364 2364
                         return false;
2365 2365
                     }
@@ -2415,11 +2415,11 @@  discard block
 block discarded – undo
2415 2415
         // how have they chosen to pay?
2416 2416
         $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2417 2417
         // get EE_Payment_Method object
2418
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2418
+        if ( ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2419 2419
             $this->checkout->continue_reg = false;
2420 2420
             return false;
2421 2421
         }
2422
-        if (! $this->checkout->payment_method->is_off_site()) {
2422
+        if ( ! $this->checkout->payment_method->is_off_site()) {
2423 2423
             return false;
2424 2424
         }
2425 2425
         $this->_validate_offsite_return();
@@ -2435,7 +2435,7 @@  discard block
 block discarded – undo
2435 2435
         // verify TXN
2436 2436
         if ($this->checkout->transaction instanceof EE_Transaction) {
2437 2437
             $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2438
-            if (! $gateway instanceof EE_Offsite_Gateway) {
2438
+            if ( ! $gateway instanceof EE_Offsite_Gateway) {
2439 2439
                 $this->checkout->continue_reg = false;
2440 2440
                 return false;
2441 2441
             }
@@ -2474,7 +2474,7 @@  discard block
 block discarded – undo
2474 2474
      */
2475 2475
     private function _validate_offsite_return()
2476 2476
     {
2477
-        $TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2477
+        $TXN_ID = (int) EE_Registry::instance()->REQ->get('spco_txn', 0);
2478 2478
         if ($TXN_ID !== $this->checkout->transaction->ID()) {
2479 2479
             // Houston... we might have a problem
2480 2480
             $invalid_TXN = false;
@@ -2544,13 +2544,13 @@  discard block
 block discarded – undo
2544 2544
      */
2545 2545
     private function _redirect_wayward_request(EE_Registration $primary_registrant)
2546 2546
     {
2547
-        if (! $primary_registrant instanceof EE_Registration) {
2547
+        if ( ! $primary_registrant instanceof EE_Registration) {
2548 2548
             // try redirecting based on the current TXN
2549 2549
             $primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2550 2550
                 ? $this->checkout->transaction->primary_registration()
2551 2551
                 : null;
2552 2552
         }
2553
-        if (! $primary_registrant instanceof EE_Registration) {
2553
+        if ( ! $primary_registrant instanceof EE_Registration) {
2554 2554
             EE_Error::add_error(
2555 2555
                 sprintf(
2556 2556
                     __(
@@ -2617,7 +2617,7 @@  discard block
 block discarded – undo
2617 2617
             $payment = $this->checkout->transaction->last_payment();
2618 2618
             //$payment_source = 'last_payment after Exception';
2619 2619
             // but if we STILL don't have a payment object
2620
-            if (! $payment instanceof EE_Payment) {
2620
+            if ( ! $payment instanceof EE_Payment) {
2621 2621
                 // then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2622 2622
                 $this->_handle_payment_processor_exception($e);
2623 2623
             }
Please login to merge, or discard this patch.
modules/ticket_selector/DisplayTicketSelector.php 2 patches
Indentation   +705 added lines, -705 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
 use WP_Post;
18 18
 
19 19
 if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
20
-    exit( 'No direct script access allowed' );
20
+	exit( 'No direct script access allowed' );
21 21
 }
22 22
 
23 23
 
@@ -34,713 +34,713 @@  discard block
 block discarded – undo
34 34
 class DisplayTicketSelector
35 35
 {
36 36
 
37
-    /**
38
-     * event that ticket selector is being generated for
39
-     *
40
-     * @access protected
41
-     * @var EE_Event $event
42
-     */
43
-    protected $event;
44
-
45
-    /**
46
-     * Used to flag when the ticket selector is being called from an external iframe.
47
-     *
48
-     * @var bool $iframe
49
-     */
50
-    protected $iframe = false;
51
-
52
-    /**
53
-     * max attendees that can register for event at one time
54
-     *
55
-     * @var int $max_attendees
56
-     */
57
-    private $max_attendees = EE_INF;
58
-
59
-    /**
60
-     *@var string $date_format
61
-     */
62
-    private $date_format;
63
-
64
-    /**
65
-     *@var string $time_format
66
-     */
67
-    private $time_format;
68
-
69
-    /**
70
-     *@var boolean $display_full_ui
71
-     */
72
-    private $display_full_ui;
73
-
74
-
75
-
76
-    /**
77
-     * DisplayTicketSelector constructor.
78
-     */
79
-    public function __construct()
80
-    {
81
-        $this->date_format = apply_filters(
82
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
83
-            get_option('date_format')
84
-        );
85
-        $this->time_format = apply_filters(
86
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
87
-            get_option('time_format')
88
-        );
89
-    }
90
-
91
-
92
-
93
-    /**
94
-     * @param boolean $iframe
95
-     */
96
-    public function setIframe( $iframe = true )
97
-    {
98
-        $this->iframe = filter_var( $iframe, FILTER_VALIDATE_BOOLEAN );
99
-    }
100
-
101
-
102
-    /**
103
-     * finds and sets the \EE_Event object for use throughout class
104
-     *
105
-     * @param mixed $event
106
-     * @return bool
107
-     * @throws EE_Error
108
-     */
109
-    protected function setEvent( $event = null )
110
-    {
111
-        if ( $event === null ) {
112
-            global $post;
113
-            $event = $post;
114
-        }
115
-        if ( $event instanceof EE_Event ) {
116
-            $this->event = $event;
117
-        } elseif ( $event instanceof WP_Post ) {
118
-            if ( isset( $event->EE_Event ) && $event->EE_Event instanceof EE_Event ) {
119
-                $this->event = $event->EE_Event;
120
-            } elseif ( $event->post_type === 'espresso_events' ) {
121
-                $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object( $event );
122
-                $this->event = $event->EE_Event;
123
-            }
124
-        } else {
125
-            $user_msg = __( 'No Event object or an invalid Event object was supplied.', 'event_espresso' );
126
-            $dev_msg = $user_msg . __(
127
-                    'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
128
-                    'event_espresso'
129
-                );
130
-            EE_Error::add_error( $user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__ );
131
-            return false;
132
-        }
133
-        return true;
134
-    }
135
-
136
-
137
-
138
-    /**
139
-     * @return int
140
-     */
141
-    public function getMaxAttendees()
142
-    {
143
-        return $this->max_attendees;
144
-    }
145
-
146
-
147
-
148
-    /**
149
-     * @param int $max_attendees
150
-     */
151
-    public function setMaxAttendees($max_attendees)
152
-    {
153
-        $this->max_attendees = absint(
154
-            apply_filters(
155
-                'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
156
-                $max_attendees
157
-            )
158
-        );
159
-    }
160
-
161
-
162
-
163
-    /**
164
-     * Returns whether or not the full ticket selector should be shown or not.
165
-     * Currently, it displays on the frontend (including ajax requests) but not the backend
166
-     * @return bool
167
-     */
168
-    private function display_full_ui()
169
-    {
170
-        if ($this->display_full_ui === null) {
171
-            $this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
172
-        }
173
-        return $this->display_full_ui;
174
-    }
175
-
176
-
177
-    /**
178
-     * creates buttons for selecting number of attendees for an event
179
-     *
180
-     * @param WP_Post|int $event
181
-     * @param bool         $view_details
182
-     * @return string
183
-     * @throws EE_Error
184
-     */
185
-    public function display( $event = null, $view_details = false )
186
-    {
187
-        // reset filter for displaying submit button
188
-        remove_filter( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true' );
189
-        // poke and prod incoming event till it tells us what it is
190
-        if ( ! $this->setEvent( $event ) ) {
191
-            return false;
192
-        }
193
-        // begin gathering template arguments by getting event status
194
-        $template_args = array( 'event_status' => $this->event->get_active_status() );
195
-        if (
196
-            $this->activeEventAndShowTicketSelector(
197
-                $event,
198
-                $template_args['event_status'],
199
-                $view_details
200
-            )
201
-        ) {
202
-            return ! is_single() ? $this->displayViewDetailsButton() : '';
203
-        }
204
-        // filter the maximum qty that can appear in the Ticket Selector qty dropdowns
205
-        $this->setMaxAttendees($this->event->additional_limit());
206
-        if ($this->getMaxAttendees() < 1) {
207
-            return $this->ticketSalesClosedMessage();
208
-        }
209
-        // is the event expired ?
210
-        $template_args['event_is_expired'] = $this->event->is_expired();
211
-        if ( $template_args[ 'event_is_expired' ] ) {
212
-            return $this->expiredEventMessage();
213
-        }
214
-        // get all tickets for this event ordered by the datetime
215
-        $tickets = $this->getTickets();
216
-        if (count($tickets) < 1) {
217
-            return $this->noTicketAvailableMessage();
218
-        }
219
-        if (EED_Events_Archive::is_iframe()){
220
-            $this->setIframe();
221
-        }
222
-        // redirecting to another site for registration ??
223
-        $external_url = (string) $this->event->external_url();
224
-        // if redirecting to another site for registration, then we don't load the TS
225
-        $ticket_selector = $external_url
226
-            ? $this->externalEventRegistration()
227
-            : $this->loadTicketSelector($tickets,$template_args);
228
-        // now set up the form (but not for the admin)
229
-        $ticket_selector = $this->display_full_ui()
230
-            ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
231
-            : $ticket_selector;
232
-        // submit button and form close tag
233
-        $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
234
-        return $ticket_selector;
235
-    }
236
-
237
-
238
-
239
-    /**
240
-     * displayTicketSelector
241
-     * examines the event properties and determines whether a Ticket Selector should be displayed
242
-     *
243
-     * @param WP_Post|int $event
244
-     * @param string       $_event_active_status
245
-     * @param bool         $view_details
246
-     * @return bool
247
-     * @throws EE_Error
248
-     */
249
-    protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details)
250
-    {
251
-        $event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
252
-        return $this->display_full_ui()
253
-               && (
254
-                   ! $this->event->display_ticket_selector()
255
-                   || $view_details
256
-                   || post_password_required($event_post)
257
-                   || (
258
-                       $_event_active_status !== EE_Datetime::active
259
-                       && $_event_active_status !== EE_Datetime::upcoming
260
-                       && $_event_active_status !== EE_Datetime::sold_out
261
-                       && ! (
262
-                           $_event_active_status === EE_Datetime::inactive
263
-                           && is_user_logged_in()
264
-                       )
265
-                   )
266
-               );
267
-    }
268
-
269
-
270
-
271
-    /**
272
-     * noTicketAvailableMessage
273
-     * notice displayed if event is expired
274
-     *
275
-     * @return string
276
-     * @throws EE_Error
277
-     */
278
-    protected function expiredEventMessage()
279
-    {
280
-        return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__(
281
-            'We\'re sorry, but all tickets sales have ended because the event is expired.',
282
-            'event_espresso'
283
-        ) . '</span></div><!-- .ee-event-expired-notice -->';
284
-    }
285
-
286
-
287
-
288
-    /**
289
-     * noTicketAvailableMessage
290
-     * notice displayed if event has no more tickets available
291
-     *
292
-     * @return string
293
-     * @throws EE_Error
294
-     */
295
-    protected function noTicketAvailableMessage()
296
-    {
297
-        $no_ticket_available_msg = esc_html__( 'We\'re sorry, but all ticket sales have ended.', 'event_espresso' );
298
-        if (current_user_can('edit_post', $this->event->ID())) {
299
-            $no_ticket_available_msg .= sprintf(
300
-                esc_html__(
301
-                    '%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
302
-                    'event_espresso'
303
-                ),
304
-                '<div class="ee-attention" style="text-align: left;"><b>',
305
-                '</b><br />',
306
-                '<span class="edit-link"><a class="post-edit-link" href="'.get_edit_post_link($this->event->ID()).'">',
307
-                '</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
308
-            );
309
-        }
310
-        return '
37
+	/**
38
+	 * event that ticket selector is being generated for
39
+	 *
40
+	 * @access protected
41
+	 * @var EE_Event $event
42
+	 */
43
+	protected $event;
44
+
45
+	/**
46
+	 * Used to flag when the ticket selector is being called from an external iframe.
47
+	 *
48
+	 * @var bool $iframe
49
+	 */
50
+	protected $iframe = false;
51
+
52
+	/**
53
+	 * max attendees that can register for event at one time
54
+	 *
55
+	 * @var int $max_attendees
56
+	 */
57
+	private $max_attendees = EE_INF;
58
+
59
+	/**
60
+	 *@var string $date_format
61
+	 */
62
+	private $date_format;
63
+
64
+	/**
65
+	 *@var string $time_format
66
+	 */
67
+	private $time_format;
68
+
69
+	/**
70
+	 *@var boolean $display_full_ui
71
+	 */
72
+	private $display_full_ui;
73
+
74
+
75
+
76
+	/**
77
+	 * DisplayTicketSelector constructor.
78
+	 */
79
+	public function __construct()
80
+	{
81
+		$this->date_format = apply_filters(
82
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
83
+			get_option('date_format')
84
+		);
85
+		$this->time_format = apply_filters(
86
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
87
+			get_option('time_format')
88
+		);
89
+	}
90
+
91
+
92
+
93
+	/**
94
+	 * @param boolean $iframe
95
+	 */
96
+	public function setIframe( $iframe = true )
97
+	{
98
+		$this->iframe = filter_var( $iframe, FILTER_VALIDATE_BOOLEAN );
99
+	}
100
+
101
+
102
+	/**
103
+	 * finds and sets the \EE_Event object for use throughout class
104
+	 *
105
+	 * @param mixed $event
106
+	 * @return bool
107
+	 * @throws EE_Error
108
+	 */
109
+	protected function setEvent( $event = null )
110
+	{
111
+		if ( $event === null ) {
112
+			global $post;
113
+			$event = $post;
114
+		}
115
+		if ( $event instanceof EE_Event ) {
116
+			$this->event = $event;
117
+		} elseif ( $event instanceof WP_Post ) {
118
+			if ( isset( $event->EE_Event ) && $event->EE_Event instanceof EE_Event ) {
119
+				$this->event = $event->EE_Event;
120
+			} elseif ( $event->post_type === 'espresso_events' ) {
121
+				$event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object( $event );
122
+				$this->event = $event->EE_Event;
123
+			}
124
+		} else {
125
+			$user_msg = __( 'No Event object or an invalid Event object was supplied.', 'event_espresso' );
126
+			$dev_msg = $user_msg . __(
127
+					'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
128
+					'event_espresso'
129
+				);
130
+			EE_Error::add_error( $user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__ );
131
+			return false;
132
+		}
133
+		return true;
134
+	}
135
+
136
+
137
+
138
+	/**
139
+	 * @return int
140
+	 */
141
+	public function getMaxAttendees()
142
+	{
143
+		return $this->max_attendees;
144
+	}
145
+
146
+
147
+
148
+	/**
149
+	 * @param int $max_attendees
150
+	 */
151
+	public function setMaxAttendees($max_attendees)
152
+	{
153
+		$this->max_attendees = absint(
154
+			apply_filters(
155
+				'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
156
+				$max_attendees
157
+			)
158
+		);
159
+	}
160
+
161
+
162
+
163
+	/**
164
+	 * Returns whether or not the full ticket selector should be shown or not.
165
+	 * Currently, it displays on the frontend (including ajax requests) but not the backend
166
+	 * @return bool
167
+	 */
168
+	private function display_full_ui()
169
+	{
170
+		if ($this->display_full_ui === null) {
171
+			$this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
172
+		}
173
+		return $this->display_full_ui;
174
+	}
175
+
176
+
177
+	/**
178
+	 * creates buttons for selecting number of attendees for an event
179
+	 *
180
+	 * @param WP_Post|int $event
181
+	 * @param bool         $view_details
182
+	 * @return string
183
+	 * @throws EE_Error
184
+	 */
185
+	public function display( $event = null, $view_details = false )
186
+	{
187
+		// reset filter for displaying submit button
188
+		remove_filter( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true' );
189
+		// poke and prod incoming event till it tells us what it is
190
+		if ( ! $this->setEvent( $event ) ) {
191
+			return false;
192
+		}
193
+		// begin gathering template arguments by getting event status
194
+		$template_args = array( 'event_status' => $this->event->get_active_status() );
195
+		if (
196
+			$this->activeEventAndShowTicketSelector(
197
+				$event,
198
+				$template_args['event_status'],
199
+				$view_details
200
+			)
201
+		) {
202
+			return ! is_single() ? $this->displayViewDetailsButton() : '';
203
+		}
204
+		// filter the maximum qty that can appear in the Ticket Selector qty dropdowns
205
+		$this->setMaxAttendees($this->event->additional_limit());
206
+		if ($this->getMaxAttendees() < 1) {
207
+			return $this->ticketSalesClosedMessage();
208
+		}
209
+		// is the event expired ?
210
+		$template_args['event_is_expired'] = $this->event->is_expired();
211
+		if ( $template_args[ 'event_is_expired' ] ) {
212
+			return $this->expiredEventMessage();
213
+		}
214
+		// get all tickets for this event ordered by the datetime
215
+		$tickets = $this->getTickets();
216
+		if (count($tickets) < 1) {
217
+			return $this->noTicketAvailableMessage();
218
+		}
219
+		if (EED_Events_Archive::is_iframe()){
220
+			$this->setIframe();
221
+		}
222
+		// redirecting to another site for registration ??
223
+		$external_url = (string) $this->event->external_url();
224
+		// if redirecting to another site for registration, then we don't load the TS
225
+		$ticket_selector = $external_url
226
+			? $this->externalEventRegistration()
227
+			: $this->loadTicketSelector($tickets,$template_args);
228
+		// now set up the form (but not for the admin)
229
+		$ticket_selector = $this->display_full_ui()
230
+			? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
231
+			: $ticket_selector;
232
+		// submit button and form close tag
233
+		$ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
234
+		return $ticket_selector;
235
+	}
236
+
237
+
238
+
239
+	/**
240
+	 * displayTicketSelector
241
+	 * examines the event properties and determines whether a Ticket Selector should be displayed
242
+	 *
243
+	 * @param WP_Post|int $event
244
+	 * @param string       $_event_active_status
245
+	 * @param bool         $view_details
246
+	 * @return bool
247
+	 * @throws EE_Error
248
+	 */
249
+	protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details)
250
+	{
251
+		$event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
252
+		return $this->display_full_ui()
253
+			   && (
254
+				   ! $this->event->display_ticket_selector()
255
+				   || $view_details
256
+				   || post_password_required($event_post)
257
+				   || (
258
+					   $_event_active_status !== EE_Datetime::active
259
+					   && $_event_active_status !== EE_Datetime::upcoming
260
+					   && $_event_active_status !== EE_Datetime::sold_out
261
+					   && ! (
262
+						   $_event_active_status === EE_Datetime::inactive
263
+						   && is_user_logged_in()
264
+					   )
265
+				   )
266
+			   );
267
+	}
268
+
269
+
270
+
271
+	/**
272
+	 * noTicketAvailableMessage
273
+	 * notice displayed if event is expired
274
+	 *
275
+	 * @return string
276
+	 * @throws EE_Error
277
+	 */
278
+	protected function expiredEventMessage()
279
+	{
280
+		return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__(
281
+			'We\'re sorry, but all tickets sales have ended because the event is expired.',
282
+			'event_espresso'
283
+		) . '</span></div><!-- .ee-event-expired-notice -->';
284
+	}
285
+
286
+
287
+
288
+	/**
289
+	 * noTicketAvailableMessage
290
+	 * notice displayed if event has no more tickets available
291
+	 *
292
+	 * @return string
293
+	 * @throws EE_Error
294
+	 */
295
+	protected function noTicketAvailableMessage()
296
+	{
297
+		$no_ticket_available_msg = esc_html__( 'We\'re sorry, but all ticket sales have ended.', 'event_espresso' );
298
+		if (current_user_can('edit_post', $this->event->ID())) {
299
+			$no_ticket_available_msg .= sprintf(
300
+				esc_html__(
301
+					'%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
302
+					'event_espresso'
303
+				),
304
+				'<div class="ee-attention" style="text-align: left;"><b>',
305
+				'</b><br />',
306
+				'<span class="edit-link"><a class="post-edit-link" href="'.get_edit_post_link($this->event->ID()).'">',
307
+				'</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
308
+			);
309
+		}
310
+		return '
311 311
             <div class="ee-event-expired-notice">
312 312
                 <span class="important-notice">' . $no_ticket_available_msg . '</span>
313 313
             </div><!-- .ee-event-expired-notice -->';
314
-    }
315
-
316
-
317
-
318
-    /**
319
-     * ticketSalesClosed
320
-     * notice displayed if event ticket sales are turned off
321
-     *
322
-     * @return string
323
-     * @throws EE_Error
324
-     */
325
-    protected function ticketSalesClosedMessage()
326
-    {
327
-        $sales_closed_msg = esc_html__(
328
-            'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
329
-            'event_espresso'
330
-        );
331
-        if (current_user_can('edit_post', $this->event->ID())) {
332
-            $sales_closed_msg .= sprintf(
333
-                esc_html__(
334
-                    '%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
335
-                    'event_espresso'
336
-                ),
337
-                '<div class="ee-attention" style="text-align: left;"><b>',
338
-                '</b><br />',
339
-                '<span class="edit-link"><a class="post-edit-link" href="'.get_edit_post_link($this->event->ID()).'">',
340
-                '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
341
-            );
342
-        }
343
-        return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
344
-    }
345
-
346
-
347
-
348
-    /**
349
-     * getTickets
350
-     *
351
-     * @return \EE_Base_Class[]|\EE_Ticket[]
352
-     * @throws EE_Error
353
-     */
354
-    protected function getTickets()
355
-    {
356
-        $ticket_query_args = array(
357
-            array('Datetime.EVT_ID' => $this->event->ID()),
358
-            'order_by' => array(
359
-                'TKT_order'              => 'ASC',
360
-                'TKT_required'           => 'DESC',
361
-                'TKT_start_date'         => 'ASC',
362
-                'TKT_end_date'           => 'ASC',
363
-                'Datetime.DTT_EVT_start' => 'DESC',
364
-            ),
365
-        );
366
-        if (
367
-            ! (
368
-                EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config
369
-                && EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets
370
-            )
371
-        ) {
372
-            //use the correct applicable time query depending on what version of core is being run.
373
-            $current_time = method_exists('EEM_Datetime', 'current_time_for_query')
374
-                ? time()
375
-                : current_time('timestamp');
376
-            $ticket_query_args[0]['TKT_end_date'] = array('>', $current_time);
377
-        }
378
-        return EEM_Ticket::instance()->get_all($ticket_query_args);
379
-    }
380
-
381
-
382
-
383
-    /**
384
-     * loadTicketSelector
385
-     * begins to assemble template arguments
386
-     * and decides whether to load a "simple" ticket selector, or the standard
387
-     *
388
-     * @param \EE_Ticket[] $tickets
389
-     * @param array $template_args
390
-     * @return string
391
-     * @throws EE_Error
392
-     */
393
-    protected function loadTicketSelector(array $tickets, array $template_args)
394
-    {
395
-        $template_args['event'] = $this->event;
396
-        $template_args['EVT_ID'] = $this->event->ID();
397
-        $template_args['event_is_expired'] = $this->event->is_expired();
398
-        $template_args['max_atndz'] = $this->getMaxAttendees();
399
-        $template_args['date_format'] = $this->date_format;
400
-        $template_args['time_format'] = $this->time_format;
401
-        /**
402
-         * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
403
-         *
404
-         * @since 4.9.13
405
-         * @param     string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
406
-         * @param int $EVT_ID The Event ID
407
-         */
408
-        $template_args['anchor_id'] = apply_filters(
409
-            'FHEE__EE_Ticket_Selector__redirect_anchor_id',
410
-            '#tkt-slctr-tbl-' . $this->event->ID(),
411
-            $this->event->ID()
412
-        );
413
-        $template_args['tickets'] = $tickets;
414
-        $template_args['ticket_count'] = count($tickets);
415
-        $ticket_selector = $this->simpleTicketSelector( $tickets, $template_args);
416
-        return $ticket_selector instanceof TicketSelectorSimple
417
-            ? $ticket_selector
418
-            : new TicketSelectorStandard(
419
-                $this->event,
420
-                $tickets,
421
-                $this->getMaxAttendees(),
422
-                $template_args,
423
-                $this->date_format,
424
-                $this->time_format
425
-            );
426
-    }
427
-
428
-
429
-
430
-    /**
431
-     * simpleTicketSelector
432
-     * there's one ticket, and max attendees is set to one,
433
-     * so if the event is free, then this is a "simple" ticket selector
434
-     * a.k.a. "Dude Where's my Ticket Selector?"
435
-     *
436
-     * @param \EE_Ticket[] $tickets
437
-     * @param array  $template_args
438
-     * @return string
439
-     * @throws EE_Error
440
-     */
441
-    protected function simpleTicketSelector($tickets, array $template_args)
442
-    {
443
-        // if there is only ONE ticket with a max qty of ONE
444
-        if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
445
-            return '';
446
-        }
447
-        /** @var \EE_Ticket $ticket */
448
-        $ticket = reset($tickets);
449
-        // if the ticket is free... then not much need for the ticket selector
450
-        if (
451
-            apply_filters(
452
-                'FHEE__ticket_selector_chart_template__hide_ticket_selector',
453
-                $ticket->is_free(),
454
-                $this->event->ID()
455
-            )
456
-        ) {
457
-            return new TicketSelectorSimple(
458
-                $this->event,
459
-                $ticket,
460
-                $this->getMaxAttendees(),
461
-                $template_args
462
-            );
463
-        }
464
-        return '';
465
-    }
466
-
467
-
468
-
469
-    /**
470
-     * externalEventRegistration
471
-     *
472
-     * @return string
473
-     */
474
-    public function externalEventRegistration()
475
-    {
476
-        // if not we still need to trigger the display of the submit button
477
-        add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
478
-        //display notice to admin that registration is external
479
-        return $this->display_full_ui()
480
-            ? esc_html__(
481
-                'Registration is at an external URL for this event.',
482
-                'event_espresso'
483
-            )
484
-            : '';
485
-    }
486
-
487
-
488
-
489
-    /**
490
-     * formOpen
491
-     *
492
-     * @param        int    $ID
493
-     * @param        string $external_url
494
-     * @return        string
495
-     */
496
-    public function formOpen( $ID = 0, $external_url = '' )
497
-    {
498
-        // if redirecting, we don't need any anything else
499
-        if ( $external_url ) {
500
-            $html = '<form method="GET" action="' . EEH_URL::refactor_url($external_url) . '"';
501
-            // open link in new window ?
502
-            $html .= apply_filters(
503
-                'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
504
-                EED_Events_Archive::is_iframe()
505
-            )
506
-                ? ' target="_blank"'
507
-                : '';
508
-            $html .= '>';
509
-            $query_args = EEH_URL::get_query_string( $external_url );
510
-            foreach ( (array)$query_args as $query_arg => $value ) {
511
-                $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
512
-            }
513
-            return $html;
514
-        }
515
-        // if there is no submit button, then don't start building a form
516
-        // because the "View Details" button will build its own form
517
-        if ( ! apply_filters( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false ) ) {
518
-            return '';
519
-        }
520
-        $checkout_url = EEH_Event_View::event_link_url( $ID );
521
-        if ( ! $checkout_url ) {
522
-            EE_Error::add_error(
523
-                esc_html__( 'The URL for the Event Details page could not be retrieved.', 'event_espresso' ),
524
-                __FILE__,
525
-                __FUNCTION__,
526
-                __LINE__
527
-            );
528
-        }
529
-        // set no cache headers and constants
530
-        EE_System::do_not_cache();
531
-        $extra_params = $this->iframe ? ' target="_blank"' : '';
532
-        $html = '<form method="POST" action="' . $checkout_url . '"' . $extra_params . '>';
533
-        $html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
534
-        $html = apply_filters( 'FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event );
535
-        return $html;
536
-    }
537
-
538
-
539
-
540
-    /**
541
-     * displaySubmitButton
542
-     *
543
-     * @param  string $external_url
544
-     * @return string
545
-     * @throws EE_Error
546
-     */
547
-    public function displaySubmitButton($external_url = '')
548
-    {
549
-        $html = '';
550
-        if ($this->display_full_ui()) {
551
-            // standard TS displayed with submit button, ie: "Register Now"
552
-            if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
553
-                $html .= $this->displayRegisterNowButton();
554
-                $html .= empty($external_url)
555
-                    ? $this->ticketSelectorEndDiv()
556
-                    : $this->clearTicketSelector();
557
-                $html .= '<br/>' . $this->formClose();
558
-            } elseif ($this->getMaxAttendees() === 1) {
559
-                // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
560
-                if ($this->event->is_sold_out()) {
561
-                    // then instead of a View Details or Submit button, just display a "Sold Out" message
562
-                    $html .= apply_filters(
563
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
564
-                        sprintf(
565
-                            __(
566
-                                '%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
567
-                                'event_espresso'
568
-                            ),
569
-                            '<p class="no-ticket-selector-msg clear-float">',
570
-                            $this->event->name(),
571
-                            '</p>',
572
-                            '<br />'
573
-                        ),
574
-                        $this->event
575
-                    );
576
-                    if (
577
-                        apply_filters(
578
-                            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
579
-                            false,
580
-                            $this->event
581
-                        )
582
-                    ) {
583
-                        $html .= $this->displayRegisterNowButton();
584
-                    }
585
-                    // sold out DWMTS event, no TS, no submit or view details button, but has additional content
586
-                    $html .=  $this->ticketSelectorEndDiv();
587
-                } elseif (
588
-                    apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
589
-                    && ! is_single()
590
-                ) {
591
-                    // this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
592
-                    // but no tickets are available, so display event's "View Details" button.
593
-                    // it is being viewed via somewhere other than a single post
594
-                    $html .= $this->displayViewDetailsButton(true);
595
-                } else {
596
-                    $html .= $this->ticketSelectorEndDiv();
597
-                }
598
-            } elseif (is_archive()) {
599
-                // event list, no tickets available so display event's "View Details" button
600
-                $html .= $this->ticketSelectorEndDiv();
601
-                $html .= $this->displayViewDetailsButton();
602
-            } else {
603
-                if (
604
-                    apply_filters(
605
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
606
-                        false,
607
-                        $this->event
608
-                    )
609
-                ) {
610
-                    $html .= $this->displayRegisterNowButton();
611
-                }
612
-                // no submit or view details button, and no additional content
613
-                $html .= $this->ticketSelectorEndDiv();
614
-            }
615
-            if ( ! $this->iframe && ! is_archive()) {
616
-                $html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector'));
617
-            }
618
-        }
619
-	    return apply_filters(
620
-		    'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
621
-		    $html,
622
-		    $this->event
623
-	    );
624
-    }
625
-
626
-
627
-
628
-    /**
629
-     * @return string
630
-     * @throws EE_Error
631
-     */
632
-    public function displayRegisterNowButton()
633
-    {
634
-        $btn_text = apply_filters(
635
-            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
636
-            __('Register Now', 'event_espresso'),
637
-            $this->event
638
-        );
639
-        $external_url = $this->event->external_url();
640
-        $html = EEH_HTML::div(
641
-            '', 'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap', 'ticket-selector-submit-btn-wrap'
642
-        );
643
-        $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
644
-        $html .= ' class="ticket-selector-submit-btn ';
645
-        $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
646
-        $html .= ' type="submit" value="' . $btn_text . '" />';
647
-        $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
648
-        $html .= apply_filters(
649
-            'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
650
-            '',
651
-            $this->event
652
-        );
653
-        return $html;
654
-    }
655
-
656
-
657
-    /**
658
-     * displayViewDetailsButton
659
-     *
660
-     * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
661
-     *                    (ie: $_max_atndz === 1) where there are no available tickets,
662
-     *                    either because they are sold out, expired, or not yet on sale.
663
-     *                    In this case, we need to close the form BEFORE adding any closing divs
664
-     * @return string
665
-     * @throws EE_Error
666
-     */
667
-    public function displayViewDetailsButton( $DWMTS = false )
668
-    {
669
-        if ( ! $this->event->get_permalink() ) {
670
-            EE_Error::add_error(
671
-                esc_html__( 'The URL for the Event Details page could not be retrieved.', 'event_espresso' ),
672
-                __FILE__, __FUNCTION__, __LINE__
673
-            );
674
-        }
675
-        $view_details_btn = '<form method="POST" action="';
676
-        $view_details_btn .= apply_filters(
677
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
678
-            $this->event->get_permalink(),
679
-            $this->event
680
-        );
681
-        $view_details_btn .= '"';
682
-        // open link in new window ?
683
-        $view_details_btn .= apply_filters(
684
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
685
-            EED_Events_Archive::is_iframe()
686
-        )
687
-            ? ' target="_blank"'
688
-            : '';
689
-        $view_details_btn .='>';
690
-        $btn_text = apply_filters(
691
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
692
-            esc_html__('View Details', 'event_espresso'),
693
-            $this->event
694
-        );
695
-        $view_details_btn .= '<input id="ticket-selector-submit-'
696
-                             . $this->event->ID()
697
-                             . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
698
-                             . $btn_text
699
-                             . '" />';
700
-        $view_details_btn .= apply_filters( 'FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event );
701
-        if ($DWMTS) {
702
-            $view_details_btn .= $this->formClose();
703
-            $view_details_btn .= $this->ticketSelectorEndDiv();
704
-            $view_details_btn .= '<br/>';
705
-        } else {
706
-            $view_details_btn .= $this->clearTicketSelector();
707
-            $view_details_btn .= '<br/>';
708
-            $view_details_btn .= $this->formClose();
709
-        }
710
-        return $view_details_btn;
711
-    }
712
-
713
-
714
-
715
-    /**
716
-     * @return string
717
-     */
718
-    public function ticketSelectorEndDiv()
719
-    {
720
-        return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
721
-    }
722
-
723
-
724
-
725
-    /**
726
-     * @return string
727
-     */
728
-    public function clearTicketSelector()
729
-    {
730
-        // standard TS displayed, appears after a "Register Now" or "view Details" button
731
-        return '<div class="clear"></div><!-- clearTicketSelector -->';
732
-    }
733
-
734
-
735
-
736
-    /**
737
-     * @access        public
738
-     * @return        string
739
-     */
740
-    public function formClose()
741
-    {
742
-        return '</form>';
743
-    }
314
+	}
315
+
316
+
317
+
318
+	/**
319
+	 * ticketSalesClosed
320
+	 * notice displayed if event ticket sales are turned off
321
+	 *
322
+	 * @return string
323
+	 * @throws EE_Error
324
+	 */
325
+	protected function ticketSalesClosedMessage()
326
+	{
327
+		$sales_closed_msg = esc_html__(
328
+			'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
329
+			'event_espresso'
330
+		);
331
+		if (current_user_can('edit_post', $this->event->ID())) {
332
+			$sales_closed_msg .= sprintf(
333
+				esc_html__(
334
+					'%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
335
+					'event_espresso'
336
+				),
337
+				'<div class="ee-attention" style="text-align: left;"><b>',
338
+				'</b><br />',
339
+				'<span class="edit-link"><a class="post-edit-link" href="'.get_edit_post_link($this->event->ID()).'">',
340
+				'</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
341
+			);
342
+		}
343
+		return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
344
+	}
345
+
346
+
347
+
348
+	/**
349
+	 * getTickets
350
+	 *
351
+	 * @return \EE_Base_Class[]|\EE_Ticket[]
352
+	 * @throws EE_Error
353
+	 */
354
+	protected function getTickets()
355
+	{
356
+		$ticket_query_args = array(
357
+			array('Datetime.EVT_ID' => $this->event->ID()),
358
+			'order_by' => array(
359
+				'TKT_order'              => 'ASC',
360
+				'TKT_required'           => 'DESC',
361
+				'TKT_start_date'         => 'ASC',
362
+				'TKT_end_date'           => 'ASC',
363
+				'Datetime.DTT_EVT_start' => 'DESC',
364
+			),
365
+		);
366
+		if (
367
+			! (
368
+				EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config
369
+				&& EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets
370
+			)
371
+		) {
372
+			//use the correct applicable time query depending on what version of core is being run.
373
+			$current_time = method_exists('EEM_Datetime', 'current_time_for_query')
374
+				? time()
375
+				: current_time('timestamp');
376
+			$ticket_query_args[0]['TKT_end_date'] = array('>', $current_time);
377
+		}
378
+		return EEM_Ticket::instance()->get_all($ticket_query_args);
379
+	}
380
+
381
+
382
+
383
+	/**
384
+	 * loadTicketSelector
385
+	 * begins to assemble template arguments
386
+	 * and decides whether to load a "simple" ticket selector, or the standard
387
+	 *
388
+	 * @param \EE_Ticket[] $tickets
389
+	 * @param array $template_args
390
+	 * @return string
391
+	 * @throws EE_Error
392
+	 */
393
+	protected function loadTicketSelector(array $tickets, array $template_args)
394
+	{
395
+		$template_args['event'] = $this->event;
396
+		$template_args['EVT_ID'] = $this->event->ID();
397
+		$template_args['event_is_expired'] = $this->event->is_expired();
398
+		$template_args['max_atndz'] = $this->getMaxAttendees();
399
+		$template_args['date_format'] = $this->date_format;
400
+		$template_args['time_format'] = $this->time_format;
401
+		/**
402
+		 * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
403
+		 *
404
+		 * @since 4.9.13
405
+		 * @param     string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
406
+		 * @param int $EVT_ID The Event ID
407
+		 */
408
+		$template_args['anchor_id'] = apply_filters(
409
+			'FHEE__EE_Ticket_Selector__redirect_anchor_id',
410
+			'#tkt-slctr-tbl-' . $this->event->ID(),
411
+			$this->event->ID()
412
+		);
413
+		$template_args['tickets'] = $tickets;
414
+		$template_args['ticket_count'] = count($tickets);
415
+		$ticket_selector = $this->simpleTicketSelector( $tickets, $template_args);
416
+		return $ticket_selector instanceof TicketSelectorSimple
417
+			? $ticket_selector
418
+			: new TicketSelectorStandard(
419
+				$this->event,
420
+				$tickets,
421
+				$this->getMaxAttendees(),
422
+				$template_args,
423
+				$this->date_format,
424
+				$this->time_format
425
+			);
426
+	}
427
+
428
+
429
+
430
+	/**
431
+	 * simpleTicketSelector
432
+	 * there's one ticket, and max attendees is set to one,
433
+	 * so if the event is free, then this is a "simple" ticket selector
434
+	 * a.k.a. "Dude Where's my Ticket Selector?"
435
+	 *
436
+	 * @param \EE_Ticket[] $tickets
437
+	 * @param array  $template_args
438
+	 * @return string
439
+	 * @throws EE_Error
440
+	 */
441
+	protected function simpleTicketSelector($tickets, array $template_args)
442
+	{
443
+		// if there is only ONE ticket with a max qty of ONE
444
+		if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
445
+			return '';
446
+		}
447
+		/** @var \EE_Ticket $ticket */
448
+		$ticket = reset($tickets);
449
+		// if the ticket is free... then not much need for the ticket selector
450
+		if (
451
+			apply_filters(
452
+				'FHEE__ticket_selector_chart_template__hide_ticket_selector',
453
+				$ticket->is_free(),
454
+				$this->event->ID()
455
+			)
456
+		) {
457
+			return new TicketSelectorSimple(
458
+				$this->event,
459
+				$ticket,
460
+				$this->getMaxAttendees(),
461
+				$template_args
462
+			);
463
+		}
464
+		return '';
465
+	}
466
+
467
+
468
+
469
+	/**
470
+	 * externalEventRegistration
471
+	 *
472
+	 * @return string
473
+	 */
474
+	public function externalEventRegistration()
475
+	{
476
+		// if not we still need to trigger the display of the submit button
477
+		add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
478
+		//display notice to admin that registration is external
479
+		return $this->display_full_ui()
480
+			? esc_html__(
481
+				'Registration is at an external URL for this event.',
482
+				'event_espresso'
483
+			)
484
+			: '';
485
+	}
486
+
487
+
488
+
489
+	/**
490
+	 * formOpen
491
+	 *
492
+	 * @param        int    $ID
493
+	 * @param        string $external_url
494
+	 * @return        string
495
+	 */
496
+	public function formOpen( $ID = 0, $external_url = '' )
497
+	{
498
+		// if redirecting, we don't need any anything else
499
+		if ( $external_url ) {
500
+			$html = '<form method="GET" action="' . EEH_URL::refactor_url($external_url) . '"';
501
+			// open link in new window ?
502
+			$html .= apply_filters(
503
+				'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
504
+				EED_Events_Archive::is_iframe()
505
+			)
506
+				? ' target="_blank"'
507
+				: '';
508
+			$html .= '>';
509
+			$query_args = EEH_URL::get_query_string( $external_url );
510
+			foreach ( (array)$query_args as $query_arg => $value ) {
511
+				$html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
512
+			}
513
+			return $html;
514
+		}
515
+		// if there is no submit button, then don't start building a form
516
+		// because the "View Details" button will build its own form
517
+		if ( ! apply_filters( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false ) ) {
518
+			return '';
519
+		}
520
+		$checkout_url = EEH_Event_View::event_link_url( $ID );
521
+		if ( ! $checkout_url ) {
522
+			EE_Error::add_error(
523
+				esc_html__( 'The URL for the Event Details page could not be retrieved.', 'event_espresso' ),
524
+				__FILE__,
525
+				__FUNCTION__,
526
+				__LINE__
527
+			);
528
+		}
529
+		// set no cache headers and constants
530
+		EE_System::do_not_cache();
531
+		$extra_params = $this->iframe ? ' target="_blank"' : '';
532
+		$html = '<form method="POST" action="' . $checkout_url . '"' . $extra_params . '>';
533
+		$html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
534
+		$html = apply_filters( 'FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event );
535
+		return $html;
536
+	}
537
+
538
+
539
+
540
+	/**
541
+	 * displaySubmitButton
542
+	 *
543
+	 * @param  string $external_url
544
+	 * @return string
545
+	 * @throws EE_Error
546
+	 */
547
+	public function displaySubmitButton($external_url = '')
548
+	{
549
+		$html = '';
550
+		if ($this->display_full_ui()) {
551
+			// standard TS displayed with submit button, ie: "Register Now"
552
+			if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
553
+				$html .= $this->displayRegisterNowButton();
554
+				$html .= empty($external_url)
555
+					? $this->ticketSelectorEndDiv()
556
+					: $this->clearTicketSelector();
557
+				$html .= '<br/>' . $this->formClose();
558
+			} elseif ($this->getMaxAttendees() === 1) {
559
+				// its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
560
+				if ($this->event->is_sold_out()) {
561
+					// then instead of a View Details or Submit button, just display a "Sold Out" message
562
+					$html .= apply_filters(
563
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
564
+						sprintf(
565
+							__(
566
+								'%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
567
+								'event_espresso'
568
+							),
569
+							'<p class="no-ticket-selector-msg clear-float">',
570
+							$this->event->name(),
571
+							'</p>',
572
+							'<br />'
573
+						),
574
+						$this->event
575
+					);
576
+					if (
577
+						apply_filters(
578
+							'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
579
+							false,
580
+							$this->event
581
+						)
582
+					) {
583
+						$html .= $this->displayRegisterNowButton();
584
+					}
585
+					// sold out DWMTS event, no TS, no submit or view details button, but has additional content
586
+					$html .=  $this->ticketSelectorEndDiv();
587
+				} elseif (
588
+					apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
589
+					&& ! is_single()
590
+				) {
591
+					// this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
592
+					// but no tickets are available, so display event's "View Details" button.
593
+					// it is being viewed via somewhere other than a single post
594
+					$html .= $this->displayViewDetailsButton(true);
595
+				} else {
596
+					$html .= $this->ticketSelectorEndDiv();
597
+				}
598
+			} elseif (is_archive()) {
599
+				// event list, no tickets available so display event's "View Details" button
600
+				$html .= $this->ticketSelectorEndDiv();
601
+				$html .= $this->displayViewDetailsButton();
602
+			} else {
603
+				if (
604
+					apply_filters(
605
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
606
+						false,
607
+						$this->event
608
+					)
609
+				) {
610
+					$html .= $this->displayRegisterNowButton();
611
+				}
612
+				// no submit or view details button, and no additional content
613
+				$html .= $this->ticketSelectorEndDiv();
614
+			}
615
+			if ( ! $this->iframe && ! is_archive()) {
616
+				$html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector'));
617
+			}
618
+		}
619
+		return apply_filters(
620
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
621
+			$html,
622
+			$this->event
623
+		);
624
+	}
625
+
626
+
627
+
628
+	/**
629
+	 * @return string
630
+	 * @throws EE_Error
631
+	 */
632
+	public function displayRegisterNowButton()
633
+	{
634
+		$btn_text = apply_filters(
635
+			'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
636
+			__('Register Now', 'event_espresso'),
637
+			$this->event
638
+		);
639
+		$external_url = $this->event->external_url();
640
+		$html = EEH_HTML::div(
641
+			'', 'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap', 'ticket-selector-submit-btn-wrap'
642
+		);
643
+		$html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
644
+		$html .= ' class="ticket-selector-submit-btn ';
645
+		$html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
646
+		$html .= ' type="submit" value="' . $btn_text . '" />';
647
+		$html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
648
+		$html .= apply_filters(
649
+			'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
650
+			'',
651
+			$this->event
652
+		);
653
+		return $html;
654
+	}
655
+
656
+
657
+	/**
658
+	 * displayViewDetailsButton
659
+	 *
660
+	 * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
661
+	 *                    (ie: $_max_atndz === 1) where there are no available tickets,
662
+	 *                    either because they are sold out, expired, or not yet on sale.
663
+	 *                    In this case, we need to close the form BEFORE adding any closing divs
664
+	 * @return string
665
+	 * @throws EE_Error
666
+	 */
667
+	public function displayViewDetailsButton( $DWMTS = false )
668
+	{
669
+		if ( ! $this->event->get_permalink() ) {
670
+			EE_Error::add_error(
671
+				esc_html__( 'The URL for the Event Details page could not be retrieved.', 'event_espresso' ),
672
+				__FILE__, __FUNCTION__, __LINE__
673
+			);
674
+		}
675
+		$view_details_btn = '<form method="POST" action="';
676
+		$view_details_btn .= apply_filters(
677
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
678
+			$this->event->get_permalink(),
679
+			$this->event
680
+		);
681
+		$view_details_btn .= '"';
682
+		// open link in new window ?
683
+		$view_details_btn .= apply_filters(
684
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
685
+			EED_Events_Archive::is_iframe()
686
+		)
687
+			? ' target="_blank"'
688
+			: '';
689
+		$view_details_btn .='>';
690
+		$btn_text = apply_filters(
691
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
692
+			esc_html__('View Details', 'event_espresso'),
693
+			$this->event
694
+		);
695
+		$view_details_btn .= '<input id="ticket-selector-submit-'
696
+							 . $this->event->ID()
697
+							 . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
698
+							 . $btn_text
699
+							 . '" />';
700
+		$view_details_btn .= apply_filters( 'FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event );
701
+		if ($DWMTS) {
702
+			$view_details_btn .= $this->formClose();
703
+			$view_details_btn .= $this->ticketSelectorEndDiv();
704
+			$view_details_btn .= '<br/>';
705
+		} else {
706
+			$view_details_btn .= $this->clearTicketSelector();
707
+			$view_details_btn .= '<br/>';
708
+			$view_details_btn .= $this->formClose();
709
+		}
710
+		return $view_details_btn;
711
+	}
712
+
713
+
714
+
715
+	/**
716
+	 * @return string
717
+	 */
718
+	public function ticketSelectorEndDiv()
719
+	{
720
+		return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
721
+	}
722
+
723
+
724
+
725
+	/**
726
+	 * @return string
727
+	 */
728
+	public function clearTicketSelector()
729
+	{
730
+		// standard TS displayed, appears after a "Register Now" or "view Details" button
731
+		return '<div class="clear"></div><!-- clearTicketSelector -->';
732
+	}
733
+
734
+
735
+
736
+	/**
737
+	 * @access        public
738
+	 * @return        string
739
+	 */
740
+	public function formClose()
741
+	{
742
+		return '</form>';
743
+	}
744 744
 
745 745
 
746 746
 
Please login to merge, or discard this patch.
Spacing   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -16,8 +16,8 @@  discard block
 block discarded – undo
16 16
 use EEM_Ticket;
17 17
 use WP_Post;
18 18
 
19
-if ( ! defined( 'EVENT_ESPRESSO_VERSION' ) ) {
20
-    exit( 'No direct script access allowed' );
19
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
20
+    exit('No direct script access allowed');
21 21
 }
22 22
 
23 23
 
@@ -93,9 +93,9 @@  discard block
 block discarded – undo
93 93
     /**
94 94
      * @param boolean $iframe
95 95
      */
96
-    public function setIframe( $iframe = true )
96
+    public function setIframe($iframe = true)
97 97
     {
98
-        $this->iframe = filter_var( $iframe, FILTER_VALIDATE_BOOLEAN );
98
+        $this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
99 99
     }
100 100
 
101 101
 
@@ -106,28 +106,28 @@  discard block
 block discarded – undo
106 106
      * @return bool
107 107
      * @throws EE_Error
108 108
      */
109
-    protected function setEvent( $event = null )
109
+    protected function setEvent($event = null)
110 110
     {
111
-        if ( $event === null ) {
111
+        if ($event === null) {
112 112
             global $post;
113 113
             $event = $post;
114 114
         }
115
-        if ( $event instanceof EE_Event ) {
115
+        if ($event instanceof EE_Event) {
116 116
             $this->event = $event;
117
-        } elseif ( $event instanceof WP_Post ) {
118
-            if ( isset( $event->EE_Event ) && $event->EE_Event instanceof EE_Event ) {
117
+        } elseif ($event instanceof WP_Post) {
118
+            if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
119 119
                 $this->event = $event->EE_Event;
120
-            } elseif ( $event->post_type === 'espresso_events' ) {
121
-                $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object( $event );
120
+            } elseif ($event->post_type === 'espresso_events') {
121
+                $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
122 122
                 $this->event = $event->EE_Event;
123 123
             }
124 124
         } else {
125
-            $user_msg = __( 'No Event object or an invalid Event object was supplied.', 'event_espresso' );
126
-            $dev_msg = $user_msg . __(
125
+            $user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso');
126
+            $dev_msg = $user_msg.__(
127 127
                     'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
128 128
                     'event_espresso'
129 129
                 );
130
-            EE_Error::add_error( $user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__ );
130
+            EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__);
131 131
             return false;
132 132
         }
133 133
         return true;
@@ -182,16 +182,16 @@  discard block
 block discarded – undo
182 182
      * @return string
183 183
      * @throws EE_Error
184 184
      */
185
-    public function display( $event = null, $view_details = false )
185
+    public function display($event = null, $view_details = false)
186 186
     {
187 187
         // reset filter for displaying submit button
188
-        remove_filter( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true' );
188
+        remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
189 189
         // poke and prod incoming event till it tells us what it is
190
-        if ( ! $this->setEvent( $event ) ) {
190
+        if ( ! $this->setEvent($event)) {
191 191
             return false;
192 192
         }
193 193
         // begin gathering template arguments by getting event status
194
-        $template_args = array( 'event_status' => $this->event->get_active_status() );
194
+        $template_args = array('event_status' => $this->event->get_active_status());
195 195
         if (
196 196
             $this->activeEventAndShowTicketSelector(
197 197
                 $event,
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
         }
209 209
         // is the event expired ?
210 210
         $template_args['event_is_expired'] = $this->event->is_expired();
211
-        if ( $template_args[ 'event_is_expired' ] ) {
211
+        if ($template_args['event_is_expired']) {
212 212
             return $this->expiredEventMessage();
213 213
         }
214 214
         // get all tickets for this event ordered by the datetime
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
         if (count($tickets) < 1) {
217 217
             return $this->noTicketAvailableMessage();
218 218
         }
219
-        if (EED_Events_Archive::is_iframe()){
219
+        if (EED_Events_Archive::is_iframe()) {
220 220
             $this->setIframe();
221 221
         }
222 222
         // redirecting to another site for registration ??
@@ -224,10 +224,10 @@  discard block
 block discarded – undo
224 224
         // if redirecting to another site for registration, then we don't load the TS
225 225
         $ticket_selector = $external_url
226 226
             ? $this->externalEventRegistration()
227
-            : $this->loadTicketSelector($tickets,$template_args);
227
+            : $this->loadTicketSelector($tickets, $template_args);
228 228
         // now set up the form (but not for the admin)
229 229
         $ticket_selector = $this->display_full_ui()
230
-            ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
230
+            ? $this->formOpen($this->event->ID(), $external_url).$ticket_selector
231 231
             : $ticket_selector;
232 232
         // submit button and form close tag
233 233
         $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
@@ -277,10 +277,10 @@  discard block
 block discarded – undo
277 277
      */
278 278
     protected function expiredEventMessage()
279 279
     {
280
-        return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__(
280
+        return '<div class="ee-event-expired-notice"><span class="important-notice">'.esc_html__(
281 281
             'We\'re sorry, but all tickets sales have ended because the event is expired.',
282 282
             'event_espresso'
283
-        ) . '</span></div><!-- .ee-event-expired-notice -->';
283
+        ).'</span></div><!-- .ee-event-expired-notice -->';
284 284
     }
285 285
 
286 286
 
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
      */
295 295
     protected function noTicketAvailableMessage()
296 296
     {
297
-        $no_ticket_available_msg = esc_html__( 'We\'re sorry, but all ticket sales have ended.', 'event_espresso' );
297
+        $no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
298 298
         if (current_user_can('edit_post', $this->event->ID())) {
299 299
             $no_ticket_available_msg .= sprintf(
300 300
                 esc_html__(
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
         }
310 310
         return '
311 311
             <div class="ee-event-expired-notice">
312
-                <span class="important-notice">' . $no_ticket_available_msg . '</span>
312
+                <span class="important-notice">' . $no_ticket_available_msg.'</span>
313 313
             </div><!-- .ee-event-expired-notice -->';
314 314
     }
315 315
 
@@ -340,7 +340,7 @@  discard block
 block discarded – undo
340 340
                 '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
341 341
             );
342 342
         }
343
-        return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
343
+        return '<p><span class="important-notice">'.$sales_closed_msg.'</span></p>';
344 344
     }
345 345
 
346 346
 
@@ -407,12 +407,12 @@  discard block
 block discarded – undo
407 407
          */
408 408
         $template_args['anchor_id'] = apply_filters(
409 409
             'FHEE__EE_Ticket_Selector__redirect_anchor_id',
410
-            '#tkt-slctr-tbl-' . $this->event->ID(),
410
+            '#tkt-slctr-tbl-'.$this->event->ID(),
411 411
             $this->event->ID()
412 412
         );
413 413
         $template_args['tickets'] = $tickets;
414 414
         $template_args['ticket_count'] = count($tickets);
415
-        $ticket_selector = $this->simpleTicketSelector( $tickets, $template_args);
415
+        $ticket_selector = $this->simpleTicketSelector($tickets, $template_args);
416 416
         return $ticket_selector instanceof TicketSelectorSimple
417 417
             ? $ticket_selector
418 418
             : new TicketSelectorStandard(
@@ -493,11 +493,11 @@  discard block
 block discarded – undo
493 493
      * @param        string $external_url
494 494
      * @return        string
495 495
      */
496
-    public function formOpen( $ID = 0, $external_url = '' )
496
+    public function formOpen($ID = 0, $external_url = '')
497 497
     {
498 498
         // if redirecting, we don't need any anything else
499
-        if ( $external_url ) {
500
-            $html = '<form method="GET" action="' . EEH_URL::refactor_url($external_url) . '"';
499
+        if ($external_url) {
500
+            $html = '<form method="GET" action="'.EEH_URL::refactor_url($external_url).'"';
501 501
             // open link in new window ?
502 502
             $html .= apply_filters(
503 503
                 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
@@ -506,21 +506,21 @@  discard block
 block discarded – undo
506 506
                 ? ' target="_blank"'
507 507
                 : '';
508 508
             $html .= '>';
509
-            $query_args = EEH_URL::get_query_string( $external_url );
510
-            foreach ( (array)$query_args as $query_arg => $value ) {
511
-                $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
509
+            $query_args = EEH_URL::get_query_string($external_url);
510
+            foreach ((array) $query_args as $query_arg => $value) {
511
+                $html .= '<input type="hidden" name="'.$query_arg.'" value="'.$value.'">';
512 512
             }
513 513
             return $html;
514 514
         }
515 515
         // if there is no submit button, then don't start building a form
516 516
         // because the "View Details" button will build its own form
517
-        if ( ! apply_filters( 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false ) ) {
517
+        if ( ! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
518 518
             return '';
519 519
         }
520
-        $checkout_url = EEH_Event_View::event_link_url( $ID );
521
-        if ( ! $checkout_url ) {
520
+        $checkout_url = EEH_Event_View::event_link_url($ID);
521
+        if ( ! $checkout_url) {
522 522
             EE_Error::add_error(
523
-                esc_html__( 'The URL for the Event Details page could not be retrieved.', 'event_espresso' ),
523
+                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
524 524
                 __FILE__,
525 525
                 __FUNCTION__,
526 526
                 __LINE__
@@ -529,9 +529,9 @@  discard block
 block discarded – undo
529 529
         // set no cache headers and constants
530 530
         EE_System::do_not_cache();
531 531
         $extra_params = $this->iframe ? ' target="_blank"' : '';
532
-        $html = '<form method="POST" action="' . $checkout_url . '"' . $extra_params . '>';
532
+        $html = '<form method="POST" action="'.$checkout_url.'"'.$extra_params.'>';
533 533
         $html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
534
-        $html = apply_filters( 'FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event );
534
+        $html = apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
535 535
         return $html;
536 536
     }
537 537
 
@@ -554,7 +554,7 @@  discard block
 block discarded – undo
554 554
                 $html .= empty($external_url)
555 555
                     ? $this->ticketSelectorEndDiv()
556 556
                     : $this->clearTicketSelector();
557
-                $html .= '<br/>' . $this->formClose();
557
+                $html .= '<br/>'.$this->formClose();
558 558
             } elseif ($this->getMaxAttendees() === 1) {
559 559
                 // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
560 560
                 if ($this->event->is_sold_out()) {
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
                         $html .= $this->displayRegisterNowButton();
584 584
                     }
585 585
                     // sold out DWMTS event, no TS, no submit or view details button, but has additional content
586
-                    $html .=  $this->ticketSelectorEndDiv();
586
+                    $html .= $this->ticketSelectorEndDiv();
587 587
                 } elseif (
588 588
                     apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
589 589
                     && ! is_single()
@@ -638,13 +638,13 @@  discard block
 block discarded – undo
638 638
         );
639 639
         $external_url = $this->event->external_url();
640 640
         $html = EEH_HTML::div(
641
-            '', 'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap', 'ticket-selector-submit-btn-wrap'
641
+            '', 'ticket-selector-submit-'.$this->event->ID().'-btn-wrap', 'ticket-selector-submit-btn-wrap'
642 642
         );
643
-        $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
643
+        $html .= '<input id="ticket-selector-submit-'.$this->event->ID().'-btn"';
644 644
         $html .= ' class="ticket-selector-submit-btn ';
645 645
         $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
646
-        $html .= ' type="submit" value="' . $btn_text . '" />';
647
-        $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
646
+        $html .= ' type="submit" value="'.$btn_text.'" />';
647
+        $html .= EEH_HTML::divx().'<!-- .ticket-selector-submit-btn-wrap -->';
648 648
         $html .= apply_filters(
649 649
             'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
650 650
             '',
@@ -664,11 +664,11 @@  discard block
 block discarded – undo
664 664
      * @return string
665 665
      * @throws EE_Error
666 666
      */
667
-    public function displayViewDetailsButton( $DWMTS = false )
667
+    public function displayViewDetailsButton($DWMTS = false)
668 668
     {
669
-        if ( ! $this->event->get_permalink() ) {
669
+        if ( ! $this->event->get_permalink()) {
670 670
             EE_Error::add_error(
671
-                esc_html__( 'The URL for the Event Details page could not be retrieved.', 'event_espresso' ),
671
+                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
672 672
                 __FILE__, __FUNCTION__, __LINE__
673 673
             );
674 674
         }
@@ -686,7 +686,7 @@  discard block
 block discarded – undo
686 686
         )
687 687
             ? ' target="_blank"'
688 688
             : '';
689
-        $view_details_btn .='>';
689
+        $view_details_btn .= '>';
690 690
         $btn_text = apply_filters(
691 691
             'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
692 692
             esc_html__('View Details', 'event_espresso'),
@@ -697,7 +697,7 @@  discard block
 block discarded – undo
697 697
                              . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
698 698
                              . $btn_text
699 699
                              . '" />';
700
-        $view_details_btn .= apply_filters( 'FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event );
700
+        $view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
701 701
         if ($DWMTS) {
702 702
             $view_details_btn .= $this->formClose();
703 703
             $view_details_btn .= $this->ticketSelectorEndDiv();
@@ -717,7 +717,7 @@  discard block
 block discarded – undo
717 717
      */
718 718
     public function ticketSelectorEndDiv()
719 719
     {
720
-        return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
720
+        return $this->clearTicketSelector().'</div><!-- ticketSelectorEndDiv -->';
721 721
     }
722 722
 
723 723
 
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_Init.core.php 2 patches
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -153,18 +153,18 @@
 block discarded – undo
153 153
 
154 154
 
155 155
 	/**
156
-     * This loads scripts and styles for the EE_Admin system
157
-     * that must be available on ALL WP admin pages (i.e. EE_menu items)
158
-     *
156
+	 * This loads scripts and styles for the EE_Admin system
157
+	 * that must be available on ALL WP admin pages (i.e. EE_menu items)
158
+	 *
159 159
 	 * @return void
160 160
 	 */
161 161
 	public function load_wp_global_scripts_styles() {
162 162
 		wp_register_style(
163
-		    'espresso_menu',
164
-            EE_ADMIN_URL . 'assets/admin-menu-styles.css',
165
-            array('dashicons'),
166
-            EVENT_ESPRESSO_VERSION
167
-        );
163
+			'espresso_menu',
164
+			EE_ADMIN_URL . 'assets/admin-menu-styles.css',
165
+			array('dashicons'),
166
+			EVENT_ESPRESSO_VERSION
167
+		);
168 168
 		wp_enqueue_style('espresso_menu');
169 169
 	}
170 170
 
Please login to merge, or discard this patch.
Spacing   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -88,16 +88,16 @@  discard block
 block discarded – undo
88 88
 		$this->_set_init_properties();
89 89
 
90 90
 		//global styles/scripts across all wp admin pages
91
-		add_action('admin_enqueue_scripts', array($this, 'load_wp_global_scripts_styles'), 5 );
91
+		add_action('admin_enqueue_scripts', array($this, 'load_wp_global_scripts_styles'), 5);
92 92
 
93 93
 		//load initial stuff.
94 94
 		$this->_set_file_and_folder_name();
95 95
 
96 96
 		$this->_set_menu_map();
97 97
 
98
-		if ( empty( $this->_menu_map ) || is_array( $this->_menu_map ) )
98
+		if (empty($this->_menu_map) || is_array($this->_menu_map))
99 99
 			 {
100
-			 	EE_Error::doing_it_wrong( get_class( $this ) . '::$_menu_map', sprintf( __('The EE4 addon with the class %s is setting up the _menu_map property incorrectly for this version of EE core.  Please see Admin_Page_Init class examples in core for the new way of setting this property up.', 'event_espresso' ), get_class( $this ) ), '4.4.0' );
100
+			 	EE_Error::doing_it_wrong(get_class($this).'::$_menu_map', sprintf(__('The EE4 addon with the class %s is setting up the _menu_map property incorrectly for this version of EE core.  Please see Admin_Page_Init class examples in core for the new way of setting this property up.', 'event_espresso'), get_class($this)), '4.4.0');
101 101
 			 	return;
102 102
 			 }
103 103
 
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
 	public function load_wp_global_scripts_styles() {
162 162
 		wp_register_style(
163 163
 		    'espresso_menu',
164
-            EE_ADMIN_URL . 'assets/admin-menu-styles.css',
164
+            EE_ADMIN_URL.'assets/admin-menu-styles.css',
165 165
             array('dashicons'),
166 166
             EVENT_ESPRESSO_VERSION
167 167
         );
@@ -193,8 +193,8 @@  discard block
 block discarded – undo
193 193
 
194 194
 
195 195
 	protected function _set_capability() {
196
-		$capability = empty($this->capability) ?  $this->_menu_map->capability : $this->capability;
197
-		$this->capability = apply_filters( 'FHEE_' . $this->_menu_map->menu_slug . '_capability', $capability );
196
+		$capability = empty($this->capability) ? $this->_menu_map->capability : $this->capability;
197
+		$this->capability = apply_filters('FHEE_'.$this->_menu_map->menu_slug.'_capability', $capability);
198 198
 	}
199 199
 
200 200
 
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
 	public function initialize_admin_page() {
213 213
 		//let's check user access first
214 214
 		$this->_check_user_access();
215
-		if ( !is_object( $this->_loaded_page_object) ) return;
215
+		if ( ! is_object($this->_loaded_page_object)) return;
216 216
 		$this->_loaded_page_object->route_admin_request();
217 217
 		return;
218 218
 	}
@@ -224,25 +224,25 @@  discard block
 block discarded – undo
224 224
 
225 225
 
226 226
 	public function set_page_dependencies($wp_page_slug) {
227
-		if ( !$this->_load_page ) return;
227
+		if ( ! $this->_load_page) return;
228 228
 
229
-		if ( !is_object($this->_loaded_page_object) ) {
229
+		if ( ! is_object($this->_loaded_page_object)) {
230 230
 			$msg[] = __('We can\'t load the page because we\'re missing a valid page object that tells us what to load', 'event_espresso');
231
-			$msg[] = $msg[0] . "\r\n" . sprintf(
231
+			$msg[] = $msg[0]."\r\n".sprintf(
232 232
 				__('The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory', 'event_espresso'),
233 233
 				 $this->_file_name,
234 234
 				 $this->_file_name,
235
-				 $this->_folder_path . $this->_file_name,
235
+				 $this->_folder_path.$this->_file_name,
236 236
 				 $this->_menu_map->menu_slug
237 237
 			);
238
-			throw new EE_Error( implode( '||', $msg) );
238
+			throw new EE_Error(implode('||', $msg));
239 239
 		}
240 240
 
241 241
 		$this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
242
-		$page_hook = 'load-' . $wp_page_slug;
242
+		$page_hook = 'load-'.$wp_page_slug;
243 243
 		//hook into page load hook so all page specific stuff get's loaded.
244
-		if ( !empty($wp_page_slug) )
245
-			add_action($page_hook, array($this->_loaded_page_object, 'load_page_dependencies') );
244
+		if ( ! empty($wp_page_slug))
245
+			add_action($page_hook, array($this->_loaded_page_object, 'load_page_dependencies'));
246 246
 	}
247 247
 
248 248
 
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
 	 */
254 254
 	public function do_initial_loads() {
255 255
 		//no loading or initializing if menu map is setup incorrectly.
256
-		if ( empty( $this->_menu_map ) || is_array( $this->_menu_map ) ) {
256
+		if (empty($this->_menu_map) || is_array($this->_menu_map)) {
257 257
 			return;
258 258
 		}
259 259
 		$this->_initialize_admin_page();
@@ -270,19 +270,19 @@  discard block
 block discarded – undo
270 270
 		$bt = debug_backtrace();
271 271
 		//for more reliable determination of folder name
272 272
 		//we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this).  Why?  Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins)
273
-		$class = get_class( $this );
274
-		foreach ( $bt as $index => $values ) {
275
-			if ( isset( $values['class'] ) && $values['class'] == $class ) {
273
+		$class = get_class($this);
274
+		foreach ($bt as $index => $values) {
275
+			if (isset($values['class']) && $values['class'] == $class) {
276 276
 				$file_index = $index - 1;
277
-				$this->_folder_name = basename(dirname($bt[$file_index]['file']) );
278
-				if ( !empty( $this->_folder_name ) ) break;
277
+				$this->_folder_name = basename(dirname($bt[$file_index]['file']));
278
+				if ( ! empty($this->_folder_name)) break;
279 279
 			}
280 280
 		}
281 281
 
282
-		$this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . DS;
282
+		$this->_folder_path = EE_ADMIN_PAGES.$this->_folder_name.DS;
283 283
 
284
-		$this->_file_name = preg_replace( '/^ee/' , 'EE', $this->_folder_name );
285
-		$this->_file_name = ucwords( str_replace('_', ' ', $this->_file_name) );
284
+		$this->_file_name = preg_replace('/^ee/', 'EE', $this->_folder_name);
285
+		$this->_file_name = ucwords(str_replace('_', ' ', $this->_file_name));
286 286
 		$this->_file_name = str_replace(' ', '_', $this->_file_name);
287 287
 	}
288 288
 
@@ -294,19 +294,19 @@  discard block
 block discarded – undo
294 294
 	 * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks files/classes
295 295
 	 * @return array
296 296
 	 */
297
-	public function register_hooks( $extend = FALSE ) {
297
+	public function register_hooks($extend = FALSE) {
298 298
 
299 299
 		//get a list of files in the directory that have the "Hook" in their name an
300 300
 
301 301
 		//if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property.  Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf.
302
-		if ( $extend ) {
303
-			$hook_files_glob_path = apply_filters( 'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend', EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . DS . '*' . $this->_file_name . '_Hooks_Extend.class.php' );
304
-			$this->_hook_paths = $this->_register_hook_files( $hook_files_glob_path, $extend );
302
+		if ($extend) {
303
+			$hook_files_glob_path = apply_filters('FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend', EE_CORE_CAF_ADMIN_EXTEND.$this->_folder_name.DS.'*'.$this->_file_name.'_Hooks_Extend.class.php');
304
+			$this->_hook_paths = $this->_register_hook_files($hook_files_glob_path, $extend);
305 305
 		}
306 306
 
307 307
 		//loop through decaf folders
308
-		$hook_files_glob_path = apply_filters( 'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path', $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php' );
309
-		$this->_hook_paths = array_merge( $this->_register_hook_files( $hook_files_glob_path ), $this->_hook_paths );  //making sure any extended hook paths are later in the array than the core hook paths!
308
+		$hook_files_glob_path = apply_filters('FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path', $this->_folder_path.'*'.$this->_file_name.'_Hooks.class.php');
309
+		$this->_hook_paths = array_merge($this->_register_hook_files($hook_files_glob_path), $this->_hook_paths); //making sure any extended hook paths are later in the array than the core hook paths!
310 310
 
311 311
 		return $this->_hook_paths;
312 312
 
@@ -314,27 +314,27 @@  discard block
 block discarded – undo
314 314
 
315 315
 
316 316
 
317
-	protected function _register_hook_files( $hook_files_glob_path, $extend = FALSE ) {
317
+	protected function _register_hook_files($hook_files_glob_path, $extend = FALSE) {
318 318
 		$hook_paths = array();
319
-		if ( $hook_files = glob( $hook_files_glob_path ) ) {
320
-			if ( empty( $hook_files ) ) {
319
+		if ($hook_files = glob($hook_files_glob_path)) {
320
+			if (empty($hook_files)) {
321 321
 				return array();
322 322
 			}
323
-			foreach ( $hook_files as $file ) {
323
+			foreach ($hook_files as $file) {
324 324
 				//lets get the linked admin.
325
-				$hook_file = $extend ? str_replace( EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . DS, '', $file ) : str_replace($this->_folder_path, '', $file );
326
-				$replace = $extend ? '_' . $this->_file_name . '_Hooks_Extend.class.php' : '_' . $this->_file_name . '_Hooks.class.php';
327
-				$rel_admin = str_replace( $replace, '', $hook_file);
325
+				$hook_file = $extend ? str_replace(EE_CORE_CAF_ADMIN_EXTEND.$this->_folder_name.DS, '', $file) : str_replace($this->_folder_path, '', $file);
326
+				$replace = $extend ? '_'.$this->_file_name.'_Hooks_Extend.class.php' : '_'.$this->_file_name.'_Hooks.class.php';
327
+				$rel_admin = str_replace($replace, '', $hook_file);
328 328
 				$rel_admin = strtolower($rel_admin);
329 329
 				$hook_paths[] = $file;
330 330
 
331 331
 				//make sure we haven't already got a hook setup for this page path
332
-				if ( in_array( $rel_admin, $this->_files_hooked ) )
332
+				if (in_array($rel_admin, $this->_files_hooked))
333 333
 					continue;
334 334
 
335 335
 				$this->hook_file = $hook_file;
336
-				$rel_admin_hook = 'FHEE_do_other_page_hooks_' . $rel_admin;
337
-				$filter = add_filter( $rel_admin_hook, array($this, 'load_admin_hook') );
336
+				$rel_admin_hook = 'FHEE_do_other_page_hooks_'.$rel_admin;
337
+				$filter = add_filter($rel_admin_hook, array($this, 'load_admin_hook'));
338 338
 				$this->_files_hooked[] = $rel_admin;
339 339
 			}
340 340
 		}
@@ -359,7 +359,7 @@  discard block
 block discarded – undo
359 359
 	protected function _initialize_admin_page() {
360 360
 
361 361
 		//JUST CHECK WE'RE ON RIGHT PAGE.
362
-		if ( (!isset( $_REQUEST['page'] ) || $_REQUEST['page'] != $this->_menu_map->menu_slug) && $this->_routing )
362
+		if (( ! isset($_REQUEST['page']) || $_REQUEST['page'] != $this->_menu_map->menu_slug) && $this->_routing)
363 363
 			return; //not on the right page so let's get out.
364 364
 		$this->_load_page = TRUE;
365 365
 
@@ -367,30 +367,30 @@  discard block
 block discarded – undo
367 367
 //		spl_autoload_register(array( $this, 'set_autoloaders') );
368 368
 
369 369
 		//we don't need to do a page_request check here because it's only called via WP menu system.
370
-		$admin_page = $this->_file_name . '_Admin_Page';
371
-		$hook_suffix = $this->_menu_map->menu_slug . '_' . $admin_page;
370
+		$admin_page = $this->_file_name.'_Admin_Page';
371
+		$hook_suffix = $this->_menu_map->menu_slug.'_'.$admin_page;
372 372
 		$admin_page = apply_filters("FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$hook_suffix}", $admin_page);
373 373
 
374 374
 		// define requested admin page class name then load the file and instantiate
375
-		$path_to_file = str_replace( array( '\\', '/' ), DS, $this->_folder_path . $admin_page . '.core.php' );
376
-		$path_to_file=apply_filters("FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$hook_suffix}",$path_to_file );//so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
375
+		$path_to_file = str_replace(array('\\', '/'), DS, $this->_folder_path.$admin_page.'.core.php');
376
+		$path_to_file = apply_filters("FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$hook_suffix}", $path_to_file); //so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
377 377
 
378
-		if ( is_readable( $path_to_file )) {
378
+		if (is_readable($path_to_file)) {
379 379
 			// This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
380
-			do_action( 'AHEE__EE_Admin_Page___initialize_admin_page__before_initialization' );
381
-			do_action( 'AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_' . $this->_menu_map->menu_slug );
382
-			require_once( $path_to_file );
383
-			$a = new ReflectionClass( $admin_page );
384
-			$this->_loaded_page_object = $a->newInstance( $this->_routing );
380
+			do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization');
381
+			do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_'.$this->_menu_map->menu_slug);
382
+			require_once($path_to_file);
383
+			$a = new ReflectionClass($admin_page);
384
+			$this->_loaded_page_object = $a->newInstance($this->_routing);
385 385
 		}
386
-		do_action( 'AHEE__EE_Admin_Page___initialize_admin_page__after_initialization' );
387
-		do_action( 'AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_' . $this->_menu_map->menu_slug );
386
+		do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization');
387
+		do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_'.$this->_menu_map->menu_slug);
388 388
 	}
389 389
 
390 390
 
391 391
 
392 392
 	public function get_admin_page_name() {
393
-		return $this->_file_name . '_Admin_Page';
393
+		return $this->_file_name.'_Admin_Page';
394 394
 	}
395 395
 
396 396
 
@@ -422,8 +422,8 @@  discard block
 block discarded – undo
422 422
 	 * @return bool|die true if pass (or admin) wp_die if fail
423 423
 	 */
424 424
 	private function _check_user_access() {
425
-		if ( ! EE_Registry::instance()->CAP->current_user_can( $this->_menu_map->capability, $this->_menu_map->menu_slug ) ) {
426
-			wp_die( __('You don\'t have access to this page.'), '', array( 'back_link' => true ) );
425
+		if ( ! EE_Registry::instance()->CAP->current_user_can($this->_menu_map->capability, $this->_menu_map->menu_slug)) {
426
+			wp_die(__('You don\'t have access to this page.'), '', array('back_link' => true));
427 427
 		}
428 428
 		return true;
429 429
 	}
Please login to merge, or discard this patch.
form_sections/strategies/layout/EE_Div_Per_Section_Layout.strategy.php 2 patches
Indentation   +126 added lines, -126 removed lines patch added patch discarded remove patch
@@ -14,132 +14,132 @@
 block discarded – undo
14 14
 class EE_Div_Per_Section_Layout extends EE_Form_Section_Layout_Base
15 15
 {
16 16
 
17
-    /**
18
-     * opening div tag for a form
19
-     *
20
-     * @return string
21
-     */
22
-    public function layout_form_begin()
23
-    {
24
-        return EEH_HTML::div(
25
-            '',
26
-            $this->_form_section->html_id(),
27
-            $this->_form_section->html_class(),
28
-            $this->_form_section->html_style()
29
-        );
30
-    }
31
-
32
-
33
-
34
-    /**
35
-     * Lays out the row for the input, including label and errors
36
-     *
37
-     * @param EE_Form_Input_Base $input
38
-     * @return string
39
-     * @throws \EE_Error
40
-     */
41
-    public function layout_input($input)
42
-    {
43
-        $html = '';
44
-        // set something unique for the id
45
-        $html_id = (string)$input->html_id() !== ''
46
-            ? (string)$input->html_id()
47
-            : spl_object_hash($input);
48
-        // and add a generic input type class
49
-        $html_class = sanitize_key(str_replace('_', '-', get_class($input))) . '-dv';
50
-        if ($input instanceof EE_Hidden_Input) {
51
-            $html .= EEH_HTML::nl() . $input->get_html_for_input();
52
-        } else if ($input instanceof EE_Submit_Input) {
53
-            $html .= EEH_HTML::div(
54
-                $input->get_html_for_input(),
55
-                $html_id . '-submit-dv',
56
-                "{$input->html_class()}-submit-dv {$html_class}"
57
-            );
58
-        } else if ($input instanceof EE_Select_Input) {
59
-            $html .= EEH_HTML::div(
60
-                EEH_HTML::nl(1) . $input->get_html_for_label() .
61
-                EEH_HTML::nl() . $input->get_html_for_errors() .
62
-                EEH_HTML::nl() . $input->get_html_for_input() .
63
-                EEH_HTML::nl() . $input->get_html_for_help(),
64
-                $html_id . '-input-dv',
65
-                "{$input->html_class()}-input-dv {$html_class}"
66
-            );
67
-        } else if ($input instanceof EE_Form_Input_With_Options_Base) {
68
-            $html .= EEH_HTML::div(
69
-                EEH_HTML::nl() . $this->_display_label_for_option_type_question($input) .
70
-                EEH_HTML::nl() . $input->get_html_for_errors() .
71
-                EEH_HTML::nl() . $input->get_html_for_input() .
72
-                EEH_HTML::nl() . $input->get_html_for_help(),
73
-                $html_id . '-input-dv',
74
-                "{$input->html_class()}-input-dv {$html_class}"
75
-            );
76
-        } else {
77
-            $html .= EEH_HTML::div(
78
-                EEH_HTML::nl(1) . $input->get_html_for_label() .
79
-                EEH_HTML::nl() . $input->get_html_for_errors() .
80
-                EEH_HTML::nl() . $input->get_html_for_input() .
81
-                EEH_HTML::nl() . $input->get_html_for_help(),
82
-                $html_id . '-input-dv',
83
-                "{$input->html_class()}-input-dv {$html_class}"
84
-            );
85
-        }
86
-        return $html;
87
-    }
88
-
89
-
90
-
91
-    /**
92
-     *
93
-     * _display_label_for_option_type_question
94
-     * Gets the HTML for the 'label', which is just text for this (because labels
95
-     * should be for each input)
96
-     *
97
-     * @param EE_Form_Input_With_Options_Base $input
98
-     * @return string
99
-     */
100
-    protected function _display_label_for_option_type_question(EE_Form_Input_With_Options_Base $input)
101
-    {
102
-        if ($input->display_html_label_text() !== '') {
103
-            return EEH_HTML::div(
104
-                $input->required()
105
-                    ? $input->html_label_text() . EEH_HTML::span('*', '', 'ee-asterisk')
106
-                    : $input->html_label_text(),
107
-                $input->html_label_id(),
108
-                $input->required()
109
-                    ? 'ee-required-label ' . $input->html_label_class()
110
-                    : $input->html_label_class(),
111
-                $input->html_label_style(),
112
-                $input->html_other_attributes()
113
-            );
114
-        }
115
-        return '';
116
-    }
117
-
118
-
119
-
120
-    /**
121
-     * Lays out a row for the subsection
122
-     *
123
-     * @param EE_Form_Section_Proper $form_section
124
-     * @return string
125
-     */
126
-    public function layout_subsection($form_section)
127
-    {
128
-        //		d( $form_section );
129
-        return EEH_HTML::nl(1) . $form_section->get_html() . EEH_HTML::nl(-1);
130
-    }
131
-
132
-
133
-
134
-    /**
135
-     * closing div tag for a form
136
-     *
137
-     * @return string
138
-     */
139
-    public function layout_form_end()
140
-    {
141
-        return EEH_HTML::divx($this->_form_section->html_id(), $this->_form_section->html_class());
142
-    }
17
+	/**
18
+	 * opening div tag for a form
19
+	 *
20
+	 * @return string
21
+	 */
22
+	public function layout_form_begin()
23
+	{
24
+		return EEH_HTML::div(
25
+			'',
26
+			$this->_form_section->html_id(),
27
+			$this->_form_section->html_class(),
28
+			$this->_form_section->html_style()
29
+		);
30
+	}
31
+
32
+
33
+
34
+	/**
35
+	 * Lays out the row for the input, including label and errors
36
+	 *
37
+	 * @param EE_Form_Input_Base $input
38
+	 * @return string
39
+	 * @throws \EE_Error
40
+	 */
41
+	public function layout_input($input)
42
+	{
43
+		$html = '';
44
+		// set something unique for the id
45
+		$html_id = (string)$input->html_id() !== ''
46
+			? (string)$input->html_id()
47
+			: spl_object_hash($input);
48
+		// and add a generic input type class
49
+		$html_class = sanitize_key(str_replace('_', '-', get_class($input))) . '-dv';
50
+		if ($input instanceof EE_Hidden_Input) {
51
+			$html .= EEH_HTML::nl() . $input->get_html_for_input();
52
+		} else if ($input instanceof EE_Submit_Input) {
53
+			$html .= EEH_HTML::div(
54
+				$input->get_html_for_input(),
55
+				$html_id . '-submit-dv',
56
+				"{$input->html_class()}-submit-dv {$html_class}"
57
+			);
58
+		} else if ($input instanceof EE_Select_Input) {
59
+			$html .= EEH_HTML::div(
60
+				EEH_HTML::nl(1) . $input->get_html_for_label() .
61
+				EEH_HTML::nl() . $input->get_html_for_errors() .
62
+				EEH_HTML::nl() . $input->get_html_for_input() .
63
+				EEH_HTML::nl() . $input->get_html_for_help(),
64
+				$html_id . '-input-dv',
65
+				"{$input->html_class()}-input-dv {$html_class}"
66
+			);
67
+		} else if ($input instanceof EE_Form_Input_With_Options_Base) {
68
+			$html .= EEH_HTML::div(
69
+				EEH_HTML::nl() . $this->_display_label_for_option_type_question($input) .
70
+				EEH_HTML::nl() . $input->get_html_for_errors() .
71
+				EEH_HTML::nl() . $input->get_html_for_input() .
72
+				EEH_HTML::nl() . $input->get_html_for_help(),
73
+				$html_id . '-input-dv',
74
+				"{$input->html_class()}-input-dv {$html_class}"
75
+			);
76
+		} else {
77
+			$html .= EEH_HTML::div(
78
+				EEH_HTML::nl(1) . $input->get_html_for_label() .
79
+				EEH_HTML::nl() . $input->get_html_for_errors() .
80
+				EEH_HTML::nl() . $input->get_html_for_input() .
81
+				EEH_HTML::nl() . $input->get_html_for_help(),
82
+				$html_id . '-input-dv',
83
+				"{$input->html_class()}-input-dv {$html_class}"
84
+			);
85
+		}
86
+		return $html;
87
+	}
88
+
89
+
90
+
91
+	/**
92
+	 *
93
+	 * _display_label_for_option_type_question
94
+	 * Gets the HTML for the 'label', which is just text for this (because labels
95
+	 * should be for each input)
96
+	 *
97
+	 * @param EE_Form_Input_With_Options_Base $input
98
+	 * @return string
99
+	 */
100
+	protected function _display_label_for_option_type_question(EE_Form_Input_With_Options_Base $input)
101
+	{
102
+		if ($input->display_html_label_text() !== '') {
103
+			return EEH_HTML::div(
104
+				$input->required()
105
+					? $input->html_label_text() . EEH_HTML::span('*', '', 'ee-asterisk')
106
+					: $input->html_label_text(),
107
+				$input->html_label_id(),
108
+				$input->required()
109
+					? 'ee-required-label ' . $input->html_label_class()
110
+					: $input->html_label_class(),
111
+				$input->html_label_style(),
112
+				$input->html_other_attributes()
113
+			);
114
+		}
115
+		return '';
116
+	}
117
+
118
+
119
+
120
+	/**
121
+	 * Lays out a row for the subsection
122
+	 *
123
+	 * @param EE_Form_Section_Proper $form_section
124
+	 * @return string
125
+	 */
126
+	public function layout_subsection($form_section)
127
+	{
128
+		//		d( $form_section );
129
+		return EEH_HTML::nl(1) . $form_section->get_html() . EEH_HTML::nl(-1);
130
+	}
131
+
132
+
133
+
134
+	/**
135
+	 * closing div tag for a form
136
+	 *
137
+	 * @return string
138
+	 */
139
+	public function layout_form_end()
140
+	{
141
+		return EEH_HTML::divx($this->_form_section->html_id(), $this->_form_section->html_class());
142
+	}
143 143
 
144 144
 
145 145
 
Please login to merge, or discard this patch.
Spacing   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -42,44 +42,44 @@  discard block
 block discarded – undo
42 42
     {
43 43
         $html = '';
44 44
         // set something unique for the id
45
-        $html_id = (string)$input->html_id() !== ''
46
-            ? (string)$input->html_id()
45
+        $html_id = (string) $input->html_id() !== ''
46
+            ? (string) $input->html_id()
47 47
             : spl_object_hash($input);
48 48
         // and add a generic input type class
49
-        $html_class = sanitize_key(str_replace('_', '-', get_class($input))) . '-dv';
49
+        $html_class = sanitize_key(str_replace('_', '-', get_class($input))).'-dv';
50 50
         if ($input instanceof EE_Hidden_Input) {
51
-            $html .= EEH_HTML::nl() . $input->get_html_for_input();
51
+            $html .= EEH_HTML::nl().$input->get_html_for_input();
52 52
         } else if ($input instanceof EE_Submit_Input) {
53 53
             $html .= EEH_HTML::div(
54 54
                 $input->get_html_for_input(),
55
-                $html_id . '-submit-dv',
55
+                $html_id.'-submit-dv',
56 56
                 "{$input->html_class()}-submit-dv {$html_class}"
57 57
             );
58 58
         } else if ($input instanceof EE_Select_Input) {
59 59
             $html .= EEH_HTML::div(
60
-                EEH_HTML::nl(1) . $input->get_html_for_label() .
61
-                EEH_HTML::nl() . $input->get_html_for_errors() .
62
-                EEH_HTML::nl() . $input->get_html_for_input() .
63
-                EEH_HTML::nl() . $input->get_html_for_help(),
64
-                $html_id . '-input-dv',
60
+                EEH_HTML::nl(1).$input->get_html_for_label().
61
+                EEH_HTML::nl().$input->get_html_for_errors().
62
+                EEH_HTML::nl().$input->get_html_for_input().
63
+                EEH_HTML::nl().$input->get_html_for_help(),
64
+                $html_id.'-input-dv',
65 65
                 "{$input->html_class()}-input-dv {$html_class}"
66 66
             );
67 67
         } else if ($input instanceof EE_Form_Input_With_Options_Base) {
68 68
             $html .= EEH_HTML::div(
69
-                EEH_HTML::nl() . $this->_display_label_for_option_type_question($input) .
70
-                EEH_HTML::nl() . $input->get_html_for_errors() .
71
-                EEH_HTML::nl() . $input->get_html_for_input() .
72
-                EEH_HTML::nl() . $input->get_html_for_help(),
73
-                $html_id . '-input-dv',
69
+                EEH_HTML::nl().$this->_display_label_for_option_type_question($input).
70
+                EEH_HTML::nl().$input->get_html_for_errors().
71
+                EEH_HTML::nl().$input->get_html_for_input().
72
+                EEH_HTML::nl().$input->get_html_for_help(),
73
+                $html_id.'-input-dv',
74 74
                 "{$input->html_class()}-input-dv {$html_class}"
75 75
             );
76 76
         } else {
77 77
             $html .= EEH_HTML::div(
78
-                EEH_HTML::nl(1) . $input->get_html_for_label() .
79
-                EEH_HTML::nl() . $input->get_html_for_errors() .
80
-                EEH_HTML::nl() . $input->get_html_for_input() .
81
-                EEH_HTML::nl() . $input->get_html_for_help(),
82
-                $html_id . '-input-dv',
78
+                EEH_HTML::nl(1).$input->get_html_for_label().
79
+                EEH_HTML::nl().$input->get_html_for_errors().
80
+                EEH_HTML::nl().$input->get_html_for_input().
81
+                EEH_HTML::nl().$input->get_html_for_help(),
82
+                $html_id.'-input-dv',
83 83
                 "{$input->html_class()}-input-dv {$html_class}"
84 84
             );
85 85
         }
@@ -102,11 +102,11 @@  discard block
 block discarded – undo
102 102
         if ($input->display_html_label_text() !== '') {
103 103
             return EEH_HTML::div(
104 104
                 $input->required()
105
-                    ? $input->html_label_text() . EEH_HTML::span('*', '', 'ee-asterisk')
105
+                    ? $input->html_label_text().EEH_HTML::span('*', '', 'ee-asterisk')
106 106
                     : $input->html_label_text(),
107 107
                 $input->html_label_id(),
108 108
                 $input->required()
109
-                    ? 'ee-required-label ' . $input->html_label_class()
109
+                    ? 'ee-required-label '.$input->html_label_class()
110 110
                     : $input->html_label_class(),
111 111
                 $input->html_label_style(),
112 112
                 $input->html_other_attributes()
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
     public function layout_subsection($form_section)
127 127
     {
128 128
         //		d( $form_section );
129
-        return EEH_HTML::nl(1) . $form_section->get_html() . EEH_HTML::nl(-1);
129
+        return EEH_HTML::nl(1).$form_section->get_html().EEH_HTML::nl(-1);
130 130
     }
131 131
 
132 132
 
Please login to merge, or discard this patch.
core/domain/services/event/EventSpacesCalculator.php 2 patches
Indentation   +555 added lines, -555 removed lines patch added patch discarded remove patch
@@ -31,561 +31,561 @@
 block discarded – undo
31 31
 class EventSpacesCalculator
32 32
 {
33 33
 
34
-    /**
35
-     * @var EE_Event $event
36
-     */
37
-    private $event;
38
-
39
-    /**
40
-     * @var array $datetime_query_params
41
-     */
42
-    private $datetime_query_params;
43
-
44
-    /**
45
-     * @var EE_Ticket[] $active_tickets
46
-     */
47
-    private $active_tickets = array();
48
-
49
-    /**
50
-     * @var EE_Datetime[] $datetimes
51
-     */
52
-    private $datetimes = array();
53
-
54
-    /**
55
-     * Array of Ticket IDs grouped by Datetime
56
-     *
57
-     * @var array $datetimes
58
-     */
59
-    private $datetime_tickets = array();
60
-
61
-    /**
62
-     * Max spaces for each Datetime (reg limit - previous sold)
63
-     *
64
-     * @var array $datetime_spaces
65
-     */
66
-    private $datetime_spaces = array();
67
-
68
-    /**
69
-     * Array of Datetime IDs grouped by Ticket
70
-     *
71
-     * @var array $ticket_datetimes
72
-     */
73
-    private $ticket_datetimes = array();
74
-
75
-    /**
76
-     * maximum ticket quantities for each ticket (adjusted for reg limit)
77
-     *
78
-     * @var array $ticket_quantities
79
-     */
80
-    private $ticket_quantities = array();
81
-
82
-    /**
83
-     * total quantity of sold and reserved for each ticket
84
-     *
85
-     * @var array $tickets_sold
86
-     */
87
-    private $tickets_sold = array();
88
-
89
-    /**
90
-     * total spaces available across all datetimes
91
-     *
92
-     * @var array $total_spaces
93
-     */
94
-    private $total_spaces = array();
95
-
96
-    /**
97
-     * @var boolean $debug
98
-     */
99
-    private $debug = false;
100
-
101
-
102
-
103
-    /**
104
-     * EventSpacesCalculator constructor.
105
-     *
106
-     * @param EE_Event $event
107
-     * @param array    $datetime_query_params
108
-     * @throws EE_Error
109
-     */
110
-    public function __construct(EE_Event $event, array $datetime_query_params = array())
111
-    {
112
-        $this->event                 = $event;
113
-        $this->datetime_query_params = $datetime_query_params + array('order_by' => array('DTT_reg_limit' => 'ASC'));
114
-    }
115
-
116
-
117
-
118
-    /**
119
-     * @return EE_Ticket[]
120
-     * @throws EE_Error
121
-     * @throws InvalidDataTypeException
122
-     * @throws InvalidInterfaceException
123
-     * @throws InvalidArgumentException
124
-     */
125
-    public function getActiveTickets()
126
-    {
127
-        if (empty($this->active_tickets)) {
128
-            $this->active_tickets = $this->event->tickets(
129
-                array(
130
-                    array(
131
-                        'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
132
-                        'TKT_deleted'  => false,
133
-                    ),
134
-                    'order_by' => array('TKT_qty' => 'ASC'),
135
-                )
136
-            );
137
-        }
138
-        return $this->active_tickets;
139
-    }
140
-
141
-
142
-
143
-    /**
144
-     * @param EE_Ticket[] $active_tickets
145
-     * @throws EE_Error
146
-     * @throws DomainException
147
-     * @throws UnexpectedEntityException
148
-     */
149
-    public function setActiveTickets(array $active_tickets = array())
150
-    {
151
-        if ( ! empty($active_tickets)) {
152
-            foreach ($active_tickets as $active_ticket) {
153
-                $this->validateTicket($active_ticket);
154
-            }
155
-            // sort incoming array by ticket quantity (asc)
156
-            usort(
157
-                $active_tickets,
158
-                function (EE_Ticket $a, EE_Ticket $b) {
159
-                    if ($a->qty() === $b->qty()) {
160
-                        return 0;
161
-                    }
162
-                    return ($a->qty() < $b->qty())
163
-                        ? -1
164
-                        : 1;
165
-                }
166
-            );
167
-        }
168
-        $this->active_tickets = $active_tickets;
169
-    }
170
-
171
-
172
-
173
-    /**
174
-     * @param $ticket
175
-     * @throws DomainException
176
-     * @throws EE_Error
177
-     * @throws UnexpectedEntityException
178
-     */
179
-    private function validateTicket($ticket)
180
-    {
181
-        if ( ! $ticket instanceof EE_Ticket) {
182
-            throw new DomainException(
183
-                esc_html__(
184
-                    'Invalid Ticket. Only EE_Ticket objects can be used to calculate event space availability.',
185
-                    'event_espresso'
186
-                )
187
-            );
188
-        }
189
-        if ($ticket->get_event_ID() !== $this->event->ID()) {
190
-            throw new DomainException(
191
-                sprintf(
192
-                    esc_html__(
193
-                        'An EE_Ticket for Event %1$d was supplied while calculating event space availability for Event %2$d.',
194
-                        'event_espresso'
195
-                    ),
196
-                    $ticket->get_event_ID(),
197
-                    $this->event->ID()
198
-                )
199
-            );
200
-        }
201
-    }
202
-
203
-
204
-
205
-    /**
206
-     * @return EE_Datetime[]
207
-     */
208
-    public function getDatetimes()
209
-    {
210
-        return $this->datetimes;
211
-    }
212
-
213
-
214
-
215
-    /**
216
-     * @param EE_Datetime $datetime
217
-     * @throws EE_Error
218
-     * @throws DomainException
219
-     */
220
-    public function setDatetime(EE_Datetime $datetime)
221
-    {
222
-        if ($datetime->event()->ID() !== $this->event->ID()) {
223
-            throw new DomainException(
224
-                sprintf(
225
-                    esc_html__(
226
-                        'An EE_Datetime for Event %1$d was supplied while calculating event space availability for Event %2$d.',
227
-                        'event_espresso'
228
-                    ),
229
-                    $datetime->event()->ID(),
230
-                    $this->event->ID()
231
-                )
232
-            );
233
-        }
234
-        $this->datetimes[ $datetime->ID() ] = $datetime;
235
-    }
236
-
237
-
238
-
239
-    /**
240
-     * calculate spaces remaining based on "saleable" tickets
241
-     *
242
-     * @return float|int
243
-     * @throws EE_Error
244
-     * @throws DomainException
245
-     * @throws UnexpectedEntityException
246
-     * @throws InvalidDataTypeException
247
-     * @throws InvalidInterfaceException
248
-     * @throws InvalidArgumentException
249
-     */
250
-    public function spacesRemaining()
251
-    {
252
-        $this->initialize();
253
-        return $this->calculate();
254
-    }
255
-
256
-
257
-
258
-    /**
259
-     * calculates total available spaces for an event with no regard for sold tickets
260
-     *
261
-     * @return int|float
262
-     * @throws EE_Error
263
-     * @throws DomainException
264
-     * @throws UnexpectedEntityException
265
-     * @throws InvalidDataTypeException
266
-     * @throws InvalidInterfaceException
267
-     * @throws InvalidArgumentException
268
-     */
269
-    public function totalSpacesAvailable()
270
-    {
271
-        $this->initialize();
272
-        return $this->calculate(false);
273
-    }
274
-
275
-
276
-
277
-    /**
278
-     * Loops through the active tickets for the event
279
-     * and builds a series of data arrays that will be used for calculating
280
-     * the total maximum available spaces, as well as the spaces remaining.
281
-     * Because ticket quantities affect datetime spaces and vice versa,
282
-     * we need to be constantly updating these data arrays as things change,
283
-     * which is the entire reason for their existence.
284
-     *
285
-     * @throws EE_Error
286
-     * @throws DomainException
287
-     * @throws UnexpectedEntityException
288
-     * @throws InvalidDataTypeException
289
-     * @throws InvalidInterfaceException
290
-     * @throws InvalidArgumentException
291
-     */
292
-    private function initialize()
293
-    {
294
-        if ($this->debug) {
295
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
296
-        }
297
-        $this->datetime_tickets  = array();
298
-        $this->datetime_spaces   = array();
299
-        $this->ticket_datetimes  = array();
300
-        $this->ticket_quantities = array();
301
-        $this->tickets_sold      = array();
302
-        $this->total_spaces      = array();
303
-        $active_tickets          = $this->getActiveTickets();
304
-        if ( ! empty($active_tickets)) {
305
-            foreach ($active_tickets as $ticket) {
306
-                $this->validateTicket($ticket);
307
-                // we need to index our data arrays using strings for the purpose of sorting,
308
-                // but we also need them to be unique, so  we'll just prepend a letter T to the ID
309
-                $ticket_identifier = "T{$ticket->ID()}";
310
-                // to start, we'll just consider the raw qty to be the maximum availability for this ticket
311
-                $max_tickets = $ticket->qty();
312
-                // but we'll adjust that after looping over each datetime for the ticket and checking reg limits
313
-                $ticket_datetimes = $ticket->datetimes($this->datetime_query_params);
314
-                foreach ($ticket_datetimes as $datetime) {
315
-                    // save all datetimes
316
-                    $this->setDatetime($datetime);
317
-                    $datetime_identifier = "D{$datetime->ID()}";
318
-                    $reg_limit           = $datetime->reg_limit();
319
-                    // ticket quantity can not exceed datetime reg limit
320
-                    $max_tickets = min($max_tickets, $reg_limit);
321
-                    // as described earlier, because we need to be able to constantly adjust numbers for things,
322
-                    // we are going to move all of our data into the following arrays:
323
-                    // datetime spaces initially represents the reg limit for each datetime,
324
-                    // but this will get adjusted as tickets are accounted for
325
-                    $this->datetime_spaces[ $datetime_identifier ] = $reg_limit;
326
-                    // just an array of ticket IDs grouped by datetime
327
-                    $this->datetime_tickets[ $datetime_identifier ][] = $ticket_identifier;
328
-                    // and an array of datetime IDs grouped by ticket
329
-                    $this->ticket_datetimes[ $ticket_identifier ][] = $datetime_identifier;
330
-                }
331
-                // total quantity of sold and reserved for each ticket
332
-                $this->tickets_sold[ $ticket_identifier ] = $ticket->sold() + $ticket->reserved();
333
-                // and the maximum ticket quantities for each ticket (adjusted for reg limit)
334
-                $this->ticket_quantities[ $ticket_identifier ] = $max_tickets;
335
-            }
336
-        }
337
-        // sort datetime spaces by reg limit, but maintain our string indexes
338
-        asort($this->datetime_spaces, SORT_NUMERIC);
339
-        // datetime tickets need to be sorted in the SAME order as the above array...
340
-        // so we'll just use array_merge() to take the structure of datetime_spaces
341
-        // but overwrite all of the data with that from datetime_tickets
342
-        $this->datetime_tickets = array_merge(
343
-            $this->datetime_spaces,
344
-            $this->datetime_tickets
345
-        );
346
-        if ($this->debug) {
347
-            \EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
348
-            \EEH_Debug_Tools::printr($this->datetime_tickets, 'datetime_tickets', __FILE__, __LINE__);
349
-            \EEH_Debug_Tools::printr($this->ticket_quantities, 'ticket_quantities', __FILE__, __LINE__);
350
-        }
351
-    }
352
-
353
-
354
-
355
-    /**
356
-     * performs calculations on initialized data
357
-     *
358
-     * @param bool $consider_sold
359
-     * @return int|float
360
-     */
361
-    private function calculate($consider_sold = true)
362
-    {
363
-        if ($this->debug) {
364
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
365
-        }
366
-        foreach ($this->datetime_tickets as $datetime_identifier => $tickets) {
367
-            $this->trackAvailableSpacesForDatetimes($datetime_identifier, $tickets);
368
-        }
369
-        // total spaces available is just the sum of the spaces available for each datetime
370
-        $spaces_remaining = array_sum($this->total_spaces);
371
-        if ($consider_sold) {
372
-            // less the sum of all tickets sold for these datetimes
373
-            $spaces_remaining -= array_sum($this->tickets_sold);
374
-        }
375
-        if ($this->debug) {
376
-            \EEH_Debug_Tools::printr($this->total_spaces, '$this->total_spaces', __FILE__, __LINE__);
377
-            \EEH_Debug_Tools::printr($this->tickets_sold, '$this->tickets_sold', __FILE__, __LINE__);
378
-            \EEH_Debug_Tools::printr($spaces_remaining, '$spaces_remaining', __FILE__, __LINE__);
379
-        }
380
-        return $spaces_remaining;
381
-    }
382
-
383
-
384
-
385
-    /**
386
-     * @param string $datetime_identifier
387
-     * @param array  $tickets
388
-     */
389
-    private function trackAvailableSpacesForDatetimes($datetime_identifier, array $tickets)
390
-    {
391
-        // make sure a reg limit is set for the datetime
392
-        $reg_limit = isset($this->datetime_spaces[ $datetime_identifier ])
393
-            ? $this->datetime_spaces[ $datetime_identifier ]
394
-            : 0;
395
-        // and bail if it is not
396
-        if ( ! $reg_limit) {
397
-            if ($this->debug) {
398
-                \EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__);
399
-            }
400
-            return;
401
-        }
402
-        if ($this->debug) {
403
-            \EEH_Debug_Tools::printr($datetime_identifier, '$datetime_identifier', __FILE__, __LINE__, 1);
404
-            \EEH_Debug_Tools::printr((string)$reg_limit, 'REG LIMIT', __FILE__, __LINE__);
405
-        }
406
-        // set default number of available spaces
407
-        $available_spaces                           = 0;
408
-        $this->total_spaces[ $datetime_identifier ] = 0;
409
-        foreach ($tickets as $ticket_identifier) {
410
-            $available_spaces = $this->calculateAvailableSpacesForTicket(
411
-                $datetime_identifier,
412
-                $reg_limit,
413
-                $ticket_identifier,
414
-                $available_spaces
415
-            );
416
-        }
417
-        // spaces can't be negative
418
-        $available_spaces = max($available_spaces, 0);
419
-        if ($available_spaces) {
420
-            // track any non-zero values
421
-            $this->total_spaces[ $datetime_identifier ] += $available_spaces;
422
-            if ($this->debug) {
423
-                \EEH_Debug_Tools::printr((string)$available_spaces, ' . spaces: ', __FILE__, __LINE__);
424
-            }
425
-        } else {
426
-            if ($this->debug) {
427
-                \EEH_Debug_Tools::printr(' ', ' . NO TICKETS AVAILABLE FOR DATETIME', __FILE__, __LINE__);
428
-            }
429
-        }
430
-        if ($this->debug) {
431
-            \EEH_Debug_Tools::printr($this->total_spaces[ $datetime_identifier ], '$spaces_remaining', __FILE__,
432
-                __LINE__);
433
-            \EEH_Debug_Tools::printr($this->ticket_quantities, '$ticket_quantities', __FILE__, __LINE__);
434
-            \EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
435
-        }
436
-    }
437
-
438
-
439
-
440
-    /**
441
-     * @param string $datetime_identifier
442
-     * @param int    $reg_limit
443
-     * @param string $ticket_identifier
444
-     * @param int    $available_spaces
445
-     * @return int
446
-     */
447
-    private function calculateAvailableSpacesForTicket(
448
-        $datetime_identifier,
449
-        $reg_limit,
450
-        $ticket_identifier,
451
-        $available_spaces
452
-    ) {
453
-        // make sure ticket quantity is set
454
-        $ticket_quantity = isset($this->ticket_quantities[ $ticket_identifier ])
455
-            ? $this->ticket_quantities[ $ticket_identifier ]
456
-            : 0;
457
-        if ($this->debug) {
458
-            \EEH_Debug_Tools::printr("{$ticket_quantity}", "ticket $ticket_identifier quantity: ",
459
-                __FILE__, __LINE__, 2);
460
-        }
461
-        if ($ticket_quantity) {
462
-            if ($this->debug) {
463
-                \EEH_Debug_Tools::printr(
464
-                    ($available_spaces <= $reg_limit)
465
-                        ? 'true'
466
-                        : 'false',
467
-                    ' . available_spaces({$available_spaces}) <= reg_limit ({$reg_limit}) = ',
468
-                    __FILE__, __LINE__
469
-                );
470
-            }
471
-            // if the datetime is NOT at full capacity yet
472
-            if ($available_spaces <= $reg_limit) {
473
-                // then the maximum ticket quantity we can allocate is the lowest value of either:
474
-                //  the number of remaining spaces for the datetime, which is the limit - spaces already taken
475
-                //  or the maximum ticket quantity
476
-                $ticket_quantity = min($reg_limit - $available_spaces, $ticket_quantity);
477
-                // adjust the available quantity in our tracking array
478
-                $this->ticket_quantities[ $ticket_identifier ] -= $ticket_quantity;
479
-                // and increment spaces allocated for this datetime
480
-                $available_spaces += $ticket_quantity;
481
-                if ($this->debug) {
482
-                    \EEH_Debug_Tools::printr("{$ticket_quantity} tickets ({$ticket_identifier})", ' . . allocate ',
483
-                        __FILE__, __LINE__);
484
-                    if ($available_spaces >= $reg_limit) {
485
-                        \EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__, 3);
486
-                    }
487
-                }
488
-                // now adjust all other datetimes that allow access to this ticket
489
-                $this->adjustDatetimes(
490
-                    $datetime_identifier,
491
-                    $available_spaces,
492
-                    $reg_limit,
493
-                    $ticket_identifier,
494
-                    $ticket_quantity
495
-                );
496
-            }
497
-        }
498
-        return $available_spaces;
499
-    }
500
-
501
-
502
-
503
-    /**
504
-     * subtracts ticket amounts from all datetime reg limits
505
-     * that allow access to the ticket specified,
506
-     * because that ticket could be used
507
-     * to attend any of the datetimes it has access to
508
-     *
509
-     * @param string $datetime_identifier
510
-     * @param int    $available_spaces
511
-     * @param int    $reg_limit
512
-     * @param string $ticket_identifier
513
-     * @param int    $ticket_quantity
514
-     */
515
-    private function adjustDatetimes(
516
-        $datetime_identifier,
517
-        $available_spaces,
518
-        $reg_limit,
519
-        $ticket_identifier,
520
-        $ticket_quantity
521
-    ) {
522
-        foreach ($this->datetime_tickets as $datetime_ID => $datetime_tickets) {
523
-            // if the supplied ticket has access to this datetime
524
-            if (in_array($ticket_identifier, $datetime_tickets, true)) {
525
-                $datetime_at_capacity = $datetime_ID === $datetime_identifier && $available_spaces >= $reg_limit;
526
-                // and datetime has spaces available
527
-                $this->adjustDatetimeSpaces(
528
-                    $datetime_identifier,
529
-                    $ticket_quantity,
530
-                    $ticket_identifier
531
-                );
532
-                // if this datetime is at full capacity
533
-                if ($datetime_at_capacity) {
534
-                    // then all of it's tickets are now unavailable
535
-                    foreach ($datetime_tickets as $datetime_ticket) {
536
-                        if ($this->debug) {
537
-                            \EEH_Debug_Tools::printr($datetime_ticket, ' . . . $datetime_ticket', __FILE__, __LINE__);
538
-                        }
539
-                        // so  set any tracked available quantities to zero
540
-                        if (isset($this->ticket_quantities[ $datetime_ticket ])) {
541
-                            $this->ticket_quantities[ $datetime_ticket ] = 0;
542
-                        }
543
-                        // but we also need to adjust spaces for any other datetimes this ticket has access to
544
-                        if ($datetime_ticket !== $ticket_identifier) {
545
-                            if (isset($this->ticket_datetimes[ $datetime_ticket ])
546
-                                && is_array($this->ticket_datetimes[ $datetime_ticket ])
547
-                            ) {
548
-                                foreach ($this->ticket_datetimes[ $datetime_ticket ] as $datetime) {
549
-                                    // don't adjust the current datetime twice
550
-                                    if ($datetime !== $datetime_identifier) {
551
-                                        $this->adjustDatetimeSpaces(
552
-                                            $datetime,
553
-                                            $ticket_quantity,
554
-                                            $datetime_ticket
555
-                                        );
556
-                                    }
557
-                                }
558
-                            }
559
-                        }
560
-                        if ($this->debug) {
561
-                            \EEH_Debug_Tools::printr("quantity set to 0 because Datetime {$datetime_identifier} is at capacity",
562
-                                " . . . . datetime ticket {$datetime_ticket}", __FILE__, __LINE__);
563
-                        }
564
-                    }
565
-                }
566
-            }
567
-        }
568
-    }
569
-
570
-    private function adjustDatetimeSpaces($datetime_identifier, $ticket_quantity = 0, $ticket_identifier = '')
571
-    {
572
-        if (isset($this->datetime_spaces[ $datetime_identifier ])) {
573
-            if ($this->debug) {
574
-                \EEH_Debug_Tools::printr($datetime_identifier, ' . . adjust Datetime Spaces for', __FILE__, __LINE__);
575
-            }
576
-            // then decrement the available spaces for the datetime
577
-            $this->datetime_spaces[ $datetime_identifier ] -= $ticket_quantity;
578
-            // but don't let quantities go below zero
579
-            $this->datetime_spaces[ $datetime_identifier ] = max(
580
-                $this->datetime_spaces[ $datetime_identifier ],
581
-                0
582
-            );
583
-            if ($this->debug) {
584
-                \EEH_Debug_Tools::printr($ticket_quantity . " because it allows access to {$ticket_identifier}",
585
-                    " . . . {$datetime_identifier} capacity reduced by", __FILE__, __LINE__);
586
-            }
587
-        }
588
-    }
34
+	/**
35
+	 * @var EE_Event $event
36
+	 */
37
+	private $event;
38
+
39
+	/**
40
+	 * @var array $datetime_query_params
41
+	 */
42
+	private $datetime_query_params;
43
+
44
+	/**
45
+	 * @var EE_Ticket[] $active_tickets
46
+	 */
47
+	private $active_tickets = array();
48
+
49
+	/**
50
+	 * @var EE_Datetime[] $datetimes
51
+	 */
52
+	private $datetimes = array();
53
+
54
+	/**
55
+	 * Array of Ticket IDs grouped by Datetime
56
+	 *
57
+	 * @var array $datetimes
58
+	 */
59
+	private $datetime_tickets = array();
60
+
61
+	/**
62
+	 * Max spaces for each Datetime (reg limit - previous sold)
63
+	 *
64
+	 * @var array $datetime_spaces
65
+	 */
66
+	private $datetime_spaces = array();
67
+
68
+	/**
69
+	 * Array of Datetime IDs grouped by Ticket
70
+	 *
71
+	 * @var array $ticket_datetimes
72
+	 */
73
+	private $ticket_datetimes = array();
74
+
75
+	/**
76
+	 * maximum ticket quantities for each ticket (adjusted for reg limit)
77
+	 *
78
+	 * @var array $ticket_quantities
79
+	 */
80
+	private $ticket_quantities = array();
81
+
82
+	/**
83
+	 * total quantity of sold and reserved for each ticket
84
+	 *
85
+	 * @var array $tickets_sold
86
+	 */
87
+	private $tickets_sold = array();
88
+
89
+	/**
90
+	 * total spaces available across all datetimes
91
+	 *
92
+	 * @var array $total_spaces
93
+	 */
94
+	private $total_spaces = array();
95
+
96
+	/**
97
+	 * @var boolean $debug
98
+	 */
99
+	private $debug = false;
100
+
101
+
102
+
103
+	/**
104
+	 * EventSpacesCalculator constructor.
105
+	 *
106
+	 * @param EE_Event $event
107
+	 * @param array    $datetime_query_params
108
+	 * @throws EE_Error
109
+	 */
110
+	public function __construct(EE_Event $event, array $datetime_query_params = array())
111
+	{
112
+		$this->event                 = $event;
113
+		$this->datetime_query_params = $datetime_query_params + array('order_by' => array('DTT_reg_limit' => 'ASC'));
114
+	}
115
+
116
+
117
+
118
+	/**
119
+	 * @return EE_Ticket[]
120
+	 * @throws EE_Error
121
+	 * @throws InvalidDataTypeException
122
+	 * @throws InvalidInterfaceException
123
+	 * @throws InvalidArgumentException
124
+	 */
125
+	public function getActiveTickets()
126
+	{
127
+		if (empty($this->active_tickets)) {
128
+			$this->active_tickets = $this->event->tickets(
129
+				array(
130
+					array(
131
+						'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
132
+						'TKT_deleted'  => false,
133
+					),
134
+					'order_by' => array('TKT_qty' => 'ASC'),
135
+				)
136
+			);
137
+		}
138
+		return $this->active_tickets;
139
+	}
140
+
141
+
142
+
143
+	/**
144
+	 * @param EE_Ticket[] $active_tickets
145
+	 * @throws EE_Error
146
+	 * @throws DomainException
147
+	 * @throws UnexpectedEntityException
148
+	 */
149
+	public function setActiveTickets(array $active_tickets = array())
150
+	{
151
+		if ( ! empty($active_tickets)) {
152
+			foreach ($active_tickets as $active_ticket) {
153
+				$this->validateTicket($active_ticket);
154
+			}
155
+			// sort incoming array by ticket quantity (asc)
156
+			usort(
157
+				$active_tickets,
158
+				function (EE_Ticket $a, EE_Ticket $b) {
159
+					if ($a->qty() === $b->qty()) {
160
+						return 0;
161
+					}
162
+					return ($a->qty() < $b->qty())
163
+						? -1
164
+						: 1;
165
+				}
166
+			);
167
+		}
168
+		$this->active_tickets = $active_tickets;
169
+	}
170
+
171
+
172
+
173
+	/**
174
+	 * @param $ticket
175
+	 * @throws DomainException
176
+	 * @throws EE_Error
177
+	 * @throws UnexpectedEntityException
178
+	 */
179
+	private function validateTicket($ticket)
180
+	{
181
+		if ( ! $ticket instanceof EE_Ticket) {
182
+			throw new DomainException(
183
+				esc_html__(
184
+					'Invalid Ticket. Only EE_Ticket objects can be used to calculate event space availability.',
185
+					'event_espresso'
186
+				)
187
+			);
188
+		}
189
+		if ($ticket->get_event_ID() !== $this->event->ID()) {
190
+			throw new DomainException(
191
+				sprintf(
192
+					esc_html__(
193
+						'An EE_Ticket for Event %1$d was supplied while calculating event space availability for Event %2$d.',
194
+						'event_espresso'
195
+					),
196
+					$ticket->get_event_ID(),
197
+					$this->event->ID()
198
+				)
199
+			);
200
+		}
201
+	}
202
+
203
+
204
+
205
+	/**
206
+	 * @return EE_Datetime[]
207
+	 */
208
+	public function getDatetimes()
209
+	{
210
+		return $this->datetimes;
211
+	}
212
+
213
+
214
+
215
+	/**
216
+	 * @param EE_Datetime $datetime
217
+	 * @throws EE_Error
218
+	 * @throws DomainException
219
+	 */
220
+	public function setDatetime(EE_Datetime $datetime)
221
+	{
222
+		if ($datetime->event()->ID() !== $this->event->ID()) {
223
+			throw new DomainException(
224
+				sprintf(
225
+					esc_html__(
226
+						'An EE_Datetime for Event %1$d was supplied while calculating event space availability for Event %2$d.',
227
+						'event_espresso'
228
+					),
229
+					$datetime->event()->ID(),
230
+					$this->event->ID()
231
+				)
232
+			);
233
+		}
234
+		$this->datetimes[ $datetime->ID() ] = $datetime;
235
+	}
236
+
237
+
238
+
239
+	/**
240
+	 * calculate spaces remaining based on "saleable" tickets
241
+	 *
242
+	 * @return float|int
243
+	 * @throws EE_Error
244
+	 * @throws DomainException
245
+	 * @throws UnexpectedEntityException
246
+	 * @throws InvalidDataTypeException
247
+	 * @throws InvalidInterfaceException
248
+	 * @throws InvalidArgumentException
249
+	 */
250
+	public function spacesRemaining()
251
+	{
252
+		$this->initialize();
253
+		return $this->calculate();
254
+	}
255
+
256
+
257
+
258
+	/**
259
+	 * calculates total available spaces for an event with no regard for sold tickets
260
+	 *
261
+	 * @return int|float
262
+	 * @throws EE_Error
263
+	 * @throws DomainException
264
+	 * @throws UnexpectedEntityException
265
+	 * @throws InvalidDataTypeException
266
+	 * @throws InvalidInterfaceException
267
+	 * @throws InvalidArgumentException
268
+	 */
269
+	public function totalSpacesAvailable()
270
+	{
271
+		$this->initialize();
272
+		return $this->calculate(false);
273
+	}
274
+
275
+
276
+
277
+	/**
278
+	 * Loops through the active tickets for the event
279
+	 * and builds a series of data arrays that will be used for calculating
280
+	 * the total maximum available spaces, as well as the spaces remaining.
281
+	 * Because ticket quantities affect datetime spaces and vice versa,
282
+	 * we need to be constantly updating these data arrays as things change,
283
+	 * which is the entire reason for their existence.
284
+	 *
285
+	 * @throws EE_Error
286
+	 * @throws DomainException
287
+	 * @throws UnexpectedEntityException
288
+	 * @throws InvalidDataTypeException
289
+	 * @throws InvalidInterfaceException
290
+	 * @throws InvalidArgumentException
291
+	 */
292
+	private function initialize()
293
+	{
294
+		if ($this->debug) {
295
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
296
+		}
297
+		$this->datetime_tickets  = array();
298
+		$this->datetime_spaces   = array();
299
+		$this->ticket_datetimes  = array();
300
+		$this->ticket_quantities = array();
301
+		$this->tickets_sold      = array();
302
+		$this->total_spaces      = array();
303
+		$active_tickets          = $this->getActiveTickets();
304
+		if ( ! empty($active_tickets)) {
305
+			foreach ($active_tickets as $ticket) {
306
+				$this->validateTicket($ticket);
307
+				// we need to index our data arrays using strings for the purpose of sorting,
308
+				// but we also need them to be unique, so  we'll just prepend a letter T to the ID
309
+				$ticket_identifier = "T{$ticket->ID()}";
310
+				// to start, we'll just consider the raw qty to be the maximum availability for this ticket
311
+				$max_tickets = $ticket->qty();
312
+				// but we'll adjust that after looping over each datetime for the ticket and checking reg limits
313
+				$ticket_datetimes = $ticket->datetimes($this->datetime_query_params);
314
+				foreach ($ticket_datetimes as $datetime) {
315
+					// save all datetimes
316
+					$this->setDatetime($datetime);
317
+					$datetime_identifier = "D{$datetime->ID()}";
318
+					$reg_limit           = $datetime->reg_limit();
319
+					// ticket quantity can not exceed datetime reg limit
320
+					$max_tickets = min($max_tickets, $reg_limit);
321
+					// as described earlier, because we need to be able to constantly adjust numbers for things,
322
+					// we are going to move all of our data into the following arrays:
323
+					// datetime spaces initially represents the reg limit for each datetime,
324
+					// but this will get adjusted as tickets are accounted for
325
+					$this->datetime_spaces[ $datetime_identifier ] = $reg_limit;
326
+					// just an array of ticket IDs grouped by datetime
327
+					$this->datetime_tickets[ $datetime_identifier ][] = $ticket_identifier;
328
+					// and an array of datetime IDs grouped by ticket
329
+					$this->ticket_datetimes[ $ticket_identifier ][] = $datetime_identifier;
330
+				}
331
+				// total quantity of sold and reserved for each ticket
332
+				$this->tickets_sold[ $ticket_identifier ] = $ticket->sold() + $ticket->reserved();
333
+				// and the maximum ticket quantities for each ticket (adjusted for reg limit)
334
+				$this->ticket_quantities[ $ticket_identifier ] = $max_tickets;
335
+			}
336
+		}
337
+		// sort datetime spaces by reg limit, but maintain our string indexes
338
+		asort($this->datetime_spaces, SORT_NUMERIC);
339
+		// datetime tickets need to be sorted in the SAME order as the above array...
340
+		// so we'll just use array_merge() to take the structure of datetime_spaces
341
+		// but overwrite all of the data with that from datetime_tickets
342
+		$this->datetime_tickets = array_merge(
343
+			$this->datetime_spaces,
344
+			$this->datetime_tickets
345
+		);
346
+		if ($this->debug) {
347
+			\EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
348
+			\EEH_Debug_Tools::printr($this->datetime_tickets, 'datetime_tickets', __FILE__, __LINE__);
349
+			\EEH_Debug_Tools::printr($this->ticket_quantities, 'ticket_quantities', __FILE__, __LINE__);
350
+		}
351
+	}
352
+
353
+
354
+
355
+	/**
356
+	 * performs calculations on initialized data
357
+	 *
358
+	 * @param bool $consider_sold
359
+	 * @return int|float
360
+	 */
361
+	private function calculate($consider_sold = true)
362
+	{
363
+		if ($this->debug) {
364
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
365
+		}
366
+		foreach ($this->datetime_tickets as $datetime_identifier => $tickets) {
367
+			$this->trackAvailableSpacesForDatetimes($datetime_identifier, $tickets);
368
+		}
369
+		// total spaces available is just the sum of the spaces available for each datetime
370
+		$spaces_remaining = array_sum($this->total_spaces);
371
+		if ($consider_sold) {
372
+			// less the sum of all tickets sold for these datetimes
373
+			$spaces_remaining -= array_sum($this->tickets_sold);
374
+		}
375
+		if ($this->debug) {
376
+			\EEH_Debug_Tools::printr($this->total_spaces, '$this->total_spaces', __FILE__, __LINE__);
377
+			\EEH_Debug_Tools::printr($this->tickets_sold, '$this->tickets_sold', __FILE__, __LINE__);
378
+			\EEH_Debug_Tools::printr($spaces_remaining, '$spaces_remaining', __FILE__, __LINE__);
379
+		}
380
+		return $spaces_remaining;
381
+	}
382
+
383
+
384
+
385
+	/**
386
+	 * @param string $datetime_identifier
387
+	 * @param array  $tickets
388
+	 */
389
+	private function trackAvailableSpacesForDatetimes($datetime_identifier, array $tickets)
390
+	{
391
+		// make sure a reg limit is set for the datetime
392
+		$reg_limit = isset($this->datetime_spaces[ $datetime_identifier ])
393
+			? $this->datetime_spaces[ $datetime_identifier ]
394
+			: 0;
395
+		// and bail if it is not
396
+		if ( ! $reg_limit) {
397
+			if ($this->debug) {
398
+				\EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__);
399
+			}
400
+			return;
401
+		}
402
+		if ($this->debug) {
403
+			\EEH_Debug_Tools::printr($datetime_identifier, '$datetime_identifier', __FILE__, __LINE__, 1);
404
+			\EEH_Debug_Tools::printr((string)$reg_limit, 'REG LIMIT', __FILE__, __LINE__);
405
+		}
406
+		// set default number of available spaces
407
+		$available_spaces                           = 0;
408
+		$this->total_spaces[ $datetime_identifier ] = 0;
409
+		foreach ($tickets as $ticket_identifier) {
410
+			$available_spaces = $this->calculateAvailableSpacesForTicket(
411
+				$datetime_identifier,
412
+				$reg_limit,
413
+				$ticket_identifier,
414
+				$available_spaces
415
+			);
416
+		}
417
+		// spaces can't be negative
418
+		$available_spaces = max($available_spaces, 0);
419
+		if ($available_spaces) {
420
+			// track any non-zero values
421
+			$this->total_spaces[ $datetime_identifier ] += $available_spaces;
422
+			if ($this->debug) {
423
+				\EEH_Debug_Tools::printr((string)$available_spaces, ' . spaces: ', __FILE__, __LINE__);
424
+			}
425
+		} else {
426
+			if ($this->debug) {
427
+				\EEH_Debug_Tools::printr(' ', ' . NO TICKETS AVAILABLE FOR DATETIME', __FILE__, __LINE__);
428
+			}
429
+		}
430
+		if ($this->debug) {
431
+			\EEH_Debug_Tools::printr($this->total_spaces[ $datetime_identifier ], '$spaces_remaining', __FILE__,
432
+				__LINE__);
433
+			\EEH_Debug_Tools::printr($this->ticket_quantities, '$ticket_quantities', __FILE__, __LINE__);
434
+			\EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
435
+		}
436
+	}
437
+
438
+
439
+
440
+	/**
441
+	 * @param string $datetime_identifier
442
+	 * @param int    $reg_limit
443
+	 * @param string $ticket_identifier
444
+	 * @param int    $available_spaces
445
+	 * @return int
446
+	 */
447
+	private function calculateAvailableSpacesForTicket(
448
+		$datetime_identifier,
449
+		$reg_limit,
450
+		$ticket_identifier,
451
+		$available_spaces
452
+	) {
453
+		// make sure ticket quantity is set
454
+		$ticket_quantity = isset($this->ticket_quantities[ $ticket_identifier ])
455
+			? $this->ticket_quantities[ $ticket_identifier ]
456
+			: 0;
457
+		if ($this->debug) {
458
+			\EEH_Debug_Tools::printr("{$ticket_quantity}", "ticket $ticket_identifier quantity: ",
459
+				__FILE__, __LINE__, 2);
460
+		}
461
+		if ($ticket_quantity) {
462
+			if ($this->debug) {
463
+				\EEH_Debug_Tools::printr(
464
+					($available_spaces <= $reg_limit)
465
+						? 'true'
466
+						: 'false',
467
+					' . available_spaces({$available_spaces}) <= reg_limit ({$reg_limit}) = ',
468
+					__FILE__, __LINE__
469
+				);
470
+			}
471
+			// if the datetime is NOT at full capacity yet
472
+			if ($available_spaces <= $reg_limit) {
473
+				// then the maximum ticket quantity we can allocate is the lowest value of either:
474
+				//  the number of remaining spaces for the datetime, which is the limit - spaces already taken
475
+				//  or the maximum ticket quantity
476
+				$ticket_quantity = min($reg_limit - $available_spaces, $ticket_quantity);
477
+				// adjust the available quantity in our tracking array
478
+				$this->ticket_quantities[ $ticket_identifier ] -= $ticket_quantity;
479
+				// and increment spaces allocated for this datetime
480
+				$available_spaces += $ticket_quantity;
481
+				if ($this->debug) {
482
+					\EEH_Debug_Tools::printr("{$ticket_quantity} tickets ({$ticket_identifier})", ' . . allocate ',
483
+						__FILE__, __LINE__);
484
+					if ($available_spaces >= $reg_limit) {
485
+						\EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__, 3);
486
+					}
487
+				}
488
+				// now adjust all other datetimes that allow access to this ticket
489
+				$this->adjustDatetimes(
490
+					$datetime_identifier,
491
+					$available_spaces,
492
+					$reg_limit,
493
+					$ticket_identifier,
494
+					$ticket_quantity
495
+				);
496
+			}
497
+		}
498
+		return $available_spaces;
499
+	}
500
+
501
+
502
+
503
+	/**
504
+	 * subtracts ticket amounts from all datetime reg limits
505
+	 * that allow access to the ticket specified,
506
+	 * because that ticket could be used
507
+	 * to attend any of the datetimes it has access to
508
+	 *
509
+	 * @param string $datetime_identifier
510
+	 * @param int    $available_spaces
511
+	 * @param int    $reg_limit
512
+	 * @param string $ticket_identifier
513
+	 * @param int    $ticket_quantity
514
+	 */
515
+	private function adjustDatetimes(
516
+		$datetime_identifier,
517
+		$available_spaces,
518
+		$reg_limit,
519
+		$ticket_identifier,
520
+		$ticket_quantity
521
+	) {
522
+		foreach ($this->datetime_tickets as $datetime_ID => $datetime_tickets) {
523
+			// if the supplied ticket has access to this datetime
524
+			if (in_array($ticket_identifier, $datetime_tickets, true)) {
525
+				$datetime_at_capacity = $datetime_ID === $datetime_identifier && $available_spaces >= $reg_limit;
526
+				// and datetime has spaces available
527
+				$this->adjustDatetimeSpaces(
528
+					$datetime_identifier,
529
+					$ticket_quantity,
530
+					$ticket_identifier
531
+				);
532
+				// if this datetime is at full capacity
533
+				if ($datetime_at_capacity) {
534
+					// then all of it's tickets are now unavailable
535
+					foreach ($datetime_tickets as $datetime_ticket) {
536
+						if ($this->debug) {
537
+							\EEH_Debug_Tools::printr($datetime_ticket, ' . . . $datetime_ticket', __FILE__, __LINE__);
538
+						}
539
+						// so  set any tracked available quantities to zero
540
+						if (isset($this->ticket_quantities[ $datetime_ticket ])) {
541
+							$this->ticket_quantities[ $datetime_ticket ] = 0;
542
+						}
543
+						// but we also need to adjust spaces for any other datetimes this ticket has access to
544
+						if ($datetime_ticket !== $ticket_identifier) {
545
+							if (isset($this->ticket_datetimes[ $datetime_ticket ])
546
+								&& is_array($this->ticket_datetimes[ $datetime_ticket ])
547
+							) {
548
+								foreach ($this->ticket_datetimes[ $datetime_ticket ] as $datetime) {
549
+									// don't adjust the current datetime twice
550
+									if ($datetime !== $datetime_identifier) {
551
+										$this->adjustDatetimeSpaces(
552
+											$datetime,
553
+											$ticket_quantity,
554
+											$datetime_ticket
555
+										);
556
+									}
557
+								}
558
+							}
559
+						}
560
+						if ($this->debug) {
561
+							\EEH_Debug_Tools::printr("quantity set to 0 because Datetime {$datetime_identifier} is at capacity",
562
+								" . . . . datetime ticket {$datetime_ticket}", __FILE__, __LINE__);
563
+						}
564
+					}
565
+				}
566
+			}
567
+		}
568
+	}
569
+
570
+	private function adjustDatetimeSpaces($datetime_identifier, $ticket_quantity = 0, $ticket_identifier = '')
571
+	{
572
+		if (isset($this->datetime_spaces[ $datetime_identifier ])) {
573
+			if ($this->debug) {
574
+				\EEH_Debug_Tools::printr($datetime_identifier, ' . . adjust Datetime Spaces for', __FILE__, __LINE__);
575
+			}
576
+			// then decrement the available spaces for the datetime
577
+			$this->datetime_spaces[ $datetime_identifier ] -= $ticket_quantity;
578
+			// but don't let quantities go below zero
579
+			$this->datetime_spaces[ $datetime_identifier ] = max(
580
+				$this->datetime_spaces[ $datetime_identifier ],
581
+				0
582
+			);
583
+			if ($this->debug) {
584
+				\EEH_Debug_Tools::printr($ticket_quantity . " because it allows access to {$ticket_identifier}",
585
+					" . . . {$datetime_identifier} capacity reduced by", __FILE__, __LINE__);
586
+			}
587
+		}
588
+	}
589 589
 
590 590
 }
591 591
 // Location: EventSpacesCalculator.php
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
             // sort incoming array by ticket quantity (asc)
156 156
             usort(
157 157
                 $active_tickets,
158
-                function (EE_Ticket $a, EE_Ticket $b) {
158
+                function(EE_Ticket $a, EE_Ticket $b) {
159 159
                     if ($a->qty() === $b->qty()) {
160 160
                         return 0;
161 161
                     }
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
                 )
232 232
             );
233 233
         }
234
-        $this->datetimes[ $datetime->ID() ] = $datetime;
234
+        $this->datetimes[$datetime->ID()] = $datetime;
235 235
     }
236 236
 
237 237
 
@@ -322,16 +322,16 @@  discard block
 block discarded – undo
322 322
                     // we are going to move all of our data into the following arrays:
323 323
                     // datetime spaces initially represents the reg limit for each datetime,
324 324
                     // but this will get adjusted as tickets are accounted for
325
-                    $this->datetime_spaces[ $datetime_identifier ] = $reg_limit;
325
+                    $this->datetime_spaces[$datetime_identifier] = $reg_limit;
326 326
                     // just an array of ticket IDs grouped by datetime
327
-                    $this->datetime_tickets[ $datetime_identifier ][] = $ticket_identifier;
327
+                    $this->datetime_tickets[$datetime_identifier][] = $ticket_identifier;
328 328
                     // and an array of datetime IDs grouped by ticket
329
-                    $this->ticket_datetimes[ $ticket_identifier ][] = $datetime_identifier;
329
+                    $this->ticket_datetimes[$ticket_identifier][] = $datetime_identifier;
330 330
                 }
331 331
                 // total quantity of sold and reserved for each ticket
332
-                $this->tickets_sold[ $ticket_identifier ] = $ticket->sold() + $ticket->reserved();
332
+                $this->tickets_sold[$ticket_identifier] = $ticket->sold() + $ticket->reserved();
333 333
                 // and the maximum ticket quantities for each ticket (adjusted for reg limit)
334
-                $this->ticket_quantities[ $ticket_identifier ] = $max_tickets;
334
+                $this->ticket_quantities[$ticket_identifier] = $max_tickets;
335 335
             }
336 336
         }
337 337
         // sort datetime spaces by reg limit, but maintain our string indexes
@@ -389,8 +389,8 @@  discard block
 block discarded – undo
389 389
     private function trackAvailableSpacesForDatetimes($datetime_identifier, array $tickets)
390 390
     {
391 391
         // make sure a reg limit is set for the datetime
392
-        $reg_limit = isset($this->datetime_spaces[ $datetime_identifier ])
393
-            ? $this->datetime_spaces[ $datetime_identifier ]
392
+        $reg_limit = isset($this->datetime_spaces[$datetime_identifier])
393
+            ? $this->datetime_spaces[$datetime_identifier]
394 394
             : 0;
395 395
         // and bail if it is not
396 396
         if ( ! $reg_limit) {
@@ -401,11 +401,11 @@  discard block
 block discarded – undo
401 401
         }
402 402
         if ($this->debug) {
403 403
             \EEH_Debug_Tools::printr($datetime_identifier, '$datetime_identifier', __FILE__, __LINE__, 1);
404
-            \EEH_Debug_Tools::printr((string)$reg_limit, 'REG LIMIT', __FILE__, __LINE__);
404
+            \EEH_Debug_Tools::printr((string) $reg_limit, 'REG LIMIT', __FILE__, __LINE__);
405 405
         }
406 406
         // set default number of available spaces
407 407
         $available_spaces                           = 0;
408
-        $this->total_spaces[ $datetime_identifier ] = 0;
408
+        $this->total_spaces[$datetime_identifier] = 0;
409 409
         foreach ($tickets as $ticket_identifier) {
410 410
             $available_spaces = $this->calculateAvailableSpacesForTicket(
411 411
                 $datetime_identifier,
@@ -418,9 +418,9 @@  discard block
 block discarded – undo
418 418
         $available_spaces = max($available_spaces, 0);
419 419
         if ($available_spaces) {
420 420
             // track any non-zero values
421
-            $this->total_spaces[ $datetime_identifier ] += $available_spaces;
421
+            $this->total_spaces[$datetime_identifier] += $available_spaces;
422 422
             if ($this->debug) {
423
-                \EEH_Debug_Tools::printr((string)$available_spaces, ' . spaces: ', __FILE__, __LINE__);
423
+                \EEH_Debug_Tools::printr((string) $available_spaces, ' . spaces: ', __FILE__, __LINE__);
424 424
             }
425 425
         } else {
426 426
             if ($this->debug) {
@@ -428,7 +428,7 @@  discard block
 block discarded – undo
428 428
             }
429 429
         }
430 430
         if ($this->debug) {
431
-            \EEH_Debug_Tools::printr($this->total_spaces[ $datetime_identifier ], '$spaces_remaining', __FILE__,
431
+            \EEH_Debug_Tools::printr($this->total_spaces[$datetime_identifier], '$spaces_remaining', __FILE__,
432 432
                 __LINE__);
433 433
             \EEH_Debug_Tools::printr($this->ticket_quantities, '$ticket_quantities', __FILE__, __LINE__);
434 434
             \EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
@@ -451,8 +451,8 @@  discard block
 block discarded – undo
451 451
         $available_spaces
452 452
     ) {
453 453
         // make sure ticket quantity is set
454
-        $ticket_quantity = isset($this->ticket_quantities[ $ticket_identifier ])
455
-            ? $this->ticket_quantities[ $ticket_identifier ]
454
+        $ticket_quantity = isset($this->ticket_quantities[$ticket_identifier])
455
+            ? $this->ticket_quantities[$ticket_identifier]
456 456
             : 0;
457 457
         if ($this->debug) {
458 458
             \EEH_Debug_Tools::printr("{$ticket_quantity}", "ticket $ticket_identifier quantity: ",
@@ -475,7 +475,7 @@  discard block
 block discarded – undo
475 475
                 //  or the maximum ticket quantity
476 476
                 $ticket_quantity = min($reg_limit - $available_spaces, $ticket_quantity);
477 477
                 // adjust the available quantity in our tracking array
478
-                $this->ticket_quantities[ $ticket_identifier ] -= $ticket_quantity;
478
+                $this->ticket_quantities[$ticket_identifier] -= $ticket_quantity;
479 479
                 // and increment spaces allocated for this datetime
480 480
                 $available_spaces += $ticket_quantity;
481 481
                 if ($this->debug) {
@@ -537,15 +537,15 @@  discard block
 block discarded – undo
537 537
                             \EEH_Debug_Tools::printr($datetime_ticket, ' . . . $datetime_ticket', __FILE__, __LINE__);
538 538
                         }
539 539
                         // so  set any tracked available quantities to zero
540
-                        if (isset($this->ticket_quantities[ $datetime_ticket ])) {
541
-                            $this->ticket_quantities[ $datetime_ticket ] = 0;
540
+                        if (isset($this->ticket_quantities[$datetime_ticket])) {
541
+                            $this->ticket_quantities[$datetime_ticket] = 0;
542 542
                         }
543 543
                         // but we also need to adjust spaces for any other datetimes this ticket has access to
544 544
                         if ($datetime_ticket !== $ticket_identifier) {
545
-                            if (isset($this->ticket_datetimes[ $datetime_ticket ])
546
-                                && is_array($this->ticket_datetimes[ $datetime_ticket ])
545
+                            if (isset($this->ticket_datetimes[$datetime_ticket])
546
+                                && is_array($this->ticket_datetimes[$datetime_ticket])
547 547
                             ) {
548
-                                foreach ($this->ticket_datetimes[ $datetime_ticket ] as $datetime) {
548
+                                foreach ($this->ticket_datetimes[$datetime_ticket] as $datetime) {
549 549
                                     // don't adjust the current datetime twice
550 550
                                     if ($datetime !== $datetime_identifier) {
551 551
                                         $this->adjustDatetimeSpaces(
@@ -569,19 +569,19 @@  discard block
 block discarded – undo
569 569
 
570 570
     private function adjustDatetimeSpaces($datetime_identifier, $ticket_quantity = 0, $ticket_identifier = '')
571 571
     {
572
-        if (isset($this->datetime_spaces[ $datetime_identifier ])) {
572
+        if (isset($this->datetime_spaces[$datetime_identifier])) {
573 573
             if ($this->debug) {
574 574
                 \EEH_Debug_Tools::printr($datetime_identifier, ' . . adjust Datetime Spaces for', __FILE__, __LINE__);
575 575
             }
576 576
             // then decrement the available spaces for the datetime
577
-            $this->datetime_spaces[ $datetime_identifier ] -= $ticket_quantity;
577
+            $this->datetime_spaces[$datetime_identifier] -= $ticket_quantity;
578 578
             // but don't let quantities go below zero
579
-            $this->datetime_spaces[ $datetime_identifier ] = max(
580
-                $this->datetime_spaces[ $datetime_identifier ],
579
+            $this->datetime_spaces[$datetime_identifier] = max(
580
+                $this->datetime_spaces[$datetime_identifier],
581 581
                 0
582 582
             );
583 583
             if ($this->debug) {
584
-                \EEH_Debug_Tools::printr($ticket_quantity . " because it allows access to {$ticket_identifier}",
584
+                \EEH_Debug_Tools::printr($ticket_quantity." because it allows access to {$ticket_identifier}",
585 585
                     " . . . {$datetime_identifier} capacity reduced by", __FILE__, __LINE__);
586 586
             }
587 587
         }
Please login to merge, or discard this patch.