Completed
Branch BUG/3575-event-deletion-previe... (bbeda1)
by
unknown
06:40 queued 04:49
created
core/db_classes/EE_Attendee.class.php 2 patches
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -36,16 +36,16 @@  discard block
 block discarded – undo
36 36
      */
37 37
     protected function __construct($fieldValues = null, $bydb = false, $timezone = null, $date_formats = array())
38 38
     {
39
-        if (! isset($fieldValues['ATT_full_name'])) {
40
-            $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'] . ' ' : '';
39
+        if ( ! isset($fieldValues['ATT_full_name'])) {
40
+            $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'].' ' : '';
41 41
             $lname = isset($fieldValues['ATT_lname']) ? $fieldValues['ATT_lname'] : '';
42
-            $fieldValues['ATT_full_name'] = $fname . $lname;
42
+            $fieldValues['ATT_full_name'] = $fname.$lname;
43 43
         }
44
-        if (! isset($fieldValues['ATT_slug'])) {
44
+        if ( ! isset($fieldValues['ATT_slug'])) {
45 45
             // $fieldValues['ATT_slug'] = sanitize_key(wp_generate_password(20));
46 46
             $fieldValues['ATT_slug'] = sanitize_title($fieldValues['ATT_full_name']);
47 47
         }
48
-        if (! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) {
48
+        if ( ! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) {
49 49
             $fieldValues['ATT_short_bio'] = substr($fieldValues['ATT_bio'], 0, 50);
50 50
         }
51 51
         parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
@@ -325,7 +325,7 @@  discard block
 block discarded – undo
325 325
         $initial_address_fields = array('ATT_address', 'ATT_address2', 'ATT_city',);
326 326
         foreach ($initial_address_fields as $address_field_name) {
327 327
             $address_fields_value = $this->get($address_field_name);
328
-            if (! empty($address_fields_value)) {
328
+            if ( ! empty($address_fields_value)) {
329 329
                 $full_address_array[] = $address_fields_value;
330 330
             }
331 331
         }
@@ -340,7 +340,7 @@  discard block
 block discarded – undo
340 340
         }
341 341
         // lastly get the xip
342 342
         $zip_value = $this->zip();
343
-        if (! empty($zip_value)) {
343
+        if ( ! empty($zip_value)) {
344 344
             $full_address_array[] = $zip_value;
345 345
         }
346 346
         return $full_address_array;
@@ -622,18 +622,18 @@  discard block
 block discarded – undo
622 622
     public function billing_info_for_payment_method($payment_method)
623 623
     {
624 624
         $pm_type = $payment_method->type_obj();
625
-        if (! $pm_type instanceof EE_PMT_Base) {
625
+        if ( ! $pm_type instanceof EE_PMT_Base) {
626 626
             return null;
627 627
         }
628 628
         $billing_info = $this->get_post_meta($this->get_billing_info_postmeta_name($payment_method), true);
629
-        if (! $billing_info) {
629
+        if ( ! $billing_info) {
630 630
             return null;
631 631
         }
632 632
         $billing_form = $pm_type->billing_form();
633 633
         // double-check the form isn't totally hidden, in which case pretend there is no form
634 634
         $form_totally_hidden = true;
635 635
         foreach ($billing_form->inputs_in_subsections() as $input) {
636
-            if (! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) {
636
+            if ( ! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) {
637 637
                 $form_totally_hidden = false;
638 638
                 break;
639 639
             }
@@ -660,7 +660,7 @@  discard block
 block discarded – undo
660 660
     public function get_billing_info_postmeta_name($payment_method)
661 661
     {
662 662
         if ($payment_method->type_obj() instanceof EE_PMT_Base) {
663
-            return 'billing_info_' . $payment_method->type_obj()->system_name();
663
+            return 'billing_info_'.$payment_method->type_obj()->system_name();
664 664
         }
665 665
         return null;
666 666
     }
@@ -677,7 +677,7 @@  discard block
 block discarded – undo
677 677
      */
678 678
     public function save_and_clean_billing_info_for_payment_method($billing_form, $payment_method)
679 679
     {
680
-        if (! $billing_form instanceof EE_Billing_Attendee_Info_Form) {
680
+        if ( ! $billing_form instanceof EE_Billing_Attendee_Info_Form) {
681 681
             EE_Error::add_error(esc_html__('Cannot save billing info because there is none.', 'event_espresso'));
682 682
             return false;
683 683
         }
Please login to merge, or discard this patch.
Indentation   +742 added lines, -742 removed lines patch added patch discarded remove patch
@@ -25,746 +25,746 @@
 block discarded – undo
25 25
 class EE_Attendee extends EE_CPT_Base implements EEI_Contact, EEI_Address, EEI_Admin_Links, EEI_Attendee
26 26
 {
27 27
 
28
-    /**
29
-     * Sets some dynamic defaults
30
-     *
31
-     * @param array  $fieldValues
32
-     * @param bool   $bydb
33
-     * @param string $timezone
34
-     * @param array  $date_formats
35
-     * @throws EE_Error
36
-     */
37
-    protected function __construct($fieldValues = null, $bydb = false, $timezone = null, $date_formats = array())
38
-    {
39
-        if (! isset($fieldValues['ATT_full_name'])) {
40
-            $fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'] . ' ' : '';
41
-            $lname = isset($fieldValues['ATT_lname']) ? $fieldValues['ATT_lname'] : '';
42
-            $fieldValues['ATT_full_name'] = $fname . $lname;
43
-        }
44
-        if (! isset($fieldValues['ATT_slug'])) {
45
-            // $fieldValues['ATT_slug'] = sanitize_key(wp_generate_password(20));
46
-            $fieldValues['ATT_slug'] = sanitize_title($fieldValues['ATT_full_name']);
47
-        }
48
-        if (! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) {
49
-            $fieldValues['ATT_short_bio'] = substr($fieldValues['ATT_bio'], 0, 50);
50
-        }
51
-        parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
52
-    }
53
-
54
-
55
-    /**
56
-     * @param array  $props_n_values          incoming values
57
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
58
-     *                                        used.)
59
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
60
-     *                                        date_format and the second value is the time format
61
-     * @return EE_Attendee
62
-     * @throws EE_Error
63
-     */
64
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
65
-    {
66
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
67
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
68
-    }
69
-
70
-
71
-    /**
72
-     * @param array  $props_n_values  incoming values from the database
73
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
74
-     *                                the website will be used.
75
-     * @return EE_Attendee
76
-     */
77
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
78
-    {
79
-        return new self($props_n_values, true, $timezone);
80
-    }
81
-
82
-
83
-    /**
84
-     *        Set Attendee First Name
85
-     *
86
-     * @access        public
87
-     * @param string $fname
88
-     * @throws EE_Error
89
-     */
90
-    public function set_fname($fname = '')
91
-    {
92
-        $this->set('ATT_fname', $fname);
93
-    }
94
-
95
-
96
-    /**
97
-     *        Set Attendee Last Name
98
-     *
99
-     * @access        public
100
-     * @param string $lname
101
-     * @throws EE_Error
102
-     */
103
-    public function set_lname($lname = '')
104
-    {
105
-        $this->set('ATT_lname', $lname);
106
-    }
107
-
108
-
109
-    /**
110
-     *        Set Attendee Address
111
-     *
112
-     * @access        public
113
-     * @param string $address
114
-     * @throws EE_Error
115
-     */
116
-    public function set_address($address = '')
117
-    {
118
-        $this->set('ATT_address', $address);
119
-    }
120
-
121
-
122
-    /**
123
-     *        Set Attendee Address2
124
-     *
125
-     * @access        public
126
-     * @param        string $address2
127
-     * @throws EE_Error
128
-     */
129
-    public function set_address2($address2 = '')
130
-    {
131
-        $this->set('ATT_address2', $address2);
132
-    }
133
-
134
-
135
-    /**
136
-     *        Set Attendee City
137
-     *
138
-     * @access        public
139
-     * @param        string $city
140
-     * @throws EE_Error
141
-     */
142
-    public function set_city($city = '')
143
-    {
144
-        $this->set('ATT_city', $city);
145
-    }
146
-
147
-
148
-    /**
149
-     *        Set Attendee State ID
150
-     *
151
-     * @access        public
152
-     * @param        int $STA_ID
153
-     * @throws EE_Error
154
-     */
155
-    public function set_state($STA_ID = 0)
156
-    {
157
-        $this->set('STA_ID', $STA_ID);
158
-    }
159
-
160
-
161
-    /**
162
-     *        Set Attendee Country ISO Code
163
-     *
164
-     * @access        public
165
-     * @param        string $CNT_ISO
166
-     * @throws EE_Error
167
-     */
168
-    public function set_country($CNT_ISO = '')
169
-    {
170
-        $this->set('CNT_ISO', $CNT_ISO);
171
-    }
172
-
173
-
174
-    /**
175
-     *        Set Attendee Zip/Postal Code
176
-     *
177
-     * @access        public
178
-     * @param        string $zip
179
-     * @throws EE_Error
180
-     */
181
-    public function set_zip($zip = '')
182
-    {
183
-        $this->set('ATT_zip', $zip);
184
-    }
185
-
186
-
187
-    /**
188
-     *        Set Attendee Email Address
189
-     *
190
-     * @access        public
191
-     * @param        string $email
192
-     * @throws EE_Error
193
-     */
194
-    public function set_email($email = '')
195
-    {
196
-        $this->set('ATT_email', $email);
197
-    }
198
-
199
-
200
-    /**
201
-     *        Set Attendee Phone
202
-     *
203
-     * @access        public
204
-     * @param        string $phone
205
-     * @throws EE_Error
206
-     */
207
-    public function set_phone($phone = '')
208
-    {
209
-        $this->set('ATT_phone', $phone);
210
-    }
211
-
212
-
213
-    /**
214
-     *        set deleted
215
-     *
216
-     * @access        public
217
-     * @param        bool $ATT_deleted
218
-     * @throws EE_Error
219
-     */
220
-    public function set_deleted($ATT_deleted = false)
221
-    {
222
-        $this->set('ATT_deleted', $ATT_deleted);
223
-    }
224
-
225
-
226
-    /**
227
-     * Returns the value for the post_author id saved with the cpt
228
-     *
229
-     * @since 4.5.0
230
-     * @return int
231
-     * @throws EE_Error
232
-     */
233
-    public function wp_user()
234
-    {
235
-        return $this->get('ATT_author');
236
-    }
237
-
238
-
239
-    /**
240
-     *        get Attendee First Name
241
-     *
242
-     * @access        public
243
-     * @return string
244
-     * @throws EE_Error
245
-     */
246
-    public function fname()
247
-    {
248
-        return $this->get('ATT_fname');
249
-    }
250
-
251
-
252
-    /**
253
-     * echoes out the attendee's first name
254
-     *
255
-     * @return void
256
-     * @throws EE_Error
257
-     */
258
-    public function e_full_name()
259
-    {
260
-        echo $this->full_name(); // sanitized
261
-    }
262
-
263
-
264
-    /**
265
-     * Returns the first and last name concatenated together with a space.
266
-     *
267
-     * @param bool $apply_html_entities
268
-     * @return string
269
-     * @throws EE_Error
270
-     */
271
-    public function full_name($apply_html_entities = false)
272
-    {
273
-        $full_name = array(
274
-            $this->fname(),
275
-            $this->lname(),
276
-        );
277
-        $full_name = array_filter($full_name);
278
-        $full_name = implode(' ', $full_name);
279
-        return $apply_html_entities ? htmlentities($full_name, ENT_QUOTES, 'UTF-8') : $full_name;
280
-    }
281
-
282
-
283
-    /**
284
-     * This returns the value of the `ATT_full_name` field which is usually equivalent to calling `full_name()` unless
285
-     * the post_title field has been directly modified in the db for the post (espresso_attendees post type) for this
286
-     * attendee.
287
-     *
288
-     * @param bool $apply_html_entities
289
-     * @return string
290
-     * @throws EE_Error
291
-     */
292
-    public function ATT_full_name($apply_html_entities = false)
293
-    {
294
-        return $apply_html_entities
295
-            ? htmlentities($this->get('ATT_full_name'), ENT_QUOTES, 'UTF-8')
296
-            : $this->get('ATT_full_name');
297
-    }
298
-
299
-
300
-    /**
301
-     *        get Attendee Last Name
302
-     *
303
-     * @access        public
304
-     * @return string
305
-     * @throws EE_Error
306
-     */
307
-    public function lname()
308
-    {
309
-        return $this->get('ATT_lname');
310
-    }
311
-
312
-
313
-    /**
314
-     * Gets the attendee's full address as an array so client code can decide hwo to display it
315
-     *
316
-     * @return array numerically indexed, with each part of the address that is known.
317
-     * Eg, if the user only responded to state and country,
318
-     * it would be array(0=>'Alabama',1=>'USA')
319
-     * @return array
320
-     * @throws EE_Error
321
-     */
322
-    public function full_address_as_array()
323
-    {
324
-        $full_address_array = array();
325
-        $initial_address_fields = array('ATT_address', 'ATT_address2', 'ATT_city',);
326
-        foreach ($initial_address_fields as $address_field_name) {
327
-            $address_fields_value = $this->get($address_field_name);
328
-            if (! empty($address_fields_value)) {
329
-                $full_address_array[] = $address_fields_value;
330
-            }
331
-        }
332
-        // now handle state and country
333
-        $state_obj = $this->state_obj();
334
-        if ($state_obj instanceof EE_State) {
335
-            $full_address_array[] = $state_obj->name();
336
-        }
337
-        $country_obj = $this->country_obj();
338
-        if ($country_obj instanceof EE_Country) {
339
-            $full_address_array[] = $country_obj->name();
340
-        }
341
-        // lastly get the xip
342
-        $zip_value = $this->zip();
343
-        if (! empty($zip_value)) {
344
-            $full_address_array[] = $zip_value;
345
-        }
346
-        return $full_address_array;
347
-    }
348
-
349
-
350
-    /**
351
-     *        get Attendee Address
352
-     *
353
-     * @return string
354
-     * @throws EE_Error
355
-     */
356
-    public function address()
357
-    {
358
-        return $this->get('ATT_address');
359
-    }
360
-
361
-
362
-    /**
363
-     *        get Attendee Address2
364
-     *
365
-     * @return string
366
-     * @throws EE_Error
367
-     */
368
-    public function address2()
369
-    {
370
-        return $this->get('ATT_address2');
371
-    }
372
-
373
-
374
-    /**
375
-     *        get Attendee City
376
-     *
377
-     * @return string
378
-     * @throws EE_Error
379
-     */
380
-    public function city()
381
-    {
382
-        return $this->get('ATT_city');
383
-    }
384
-
385
-
386
-    /**
387
-     *        get Attendee State ID
388
-     *
389
-     * @return string
390
-     * @throws EE_Error
391
-     */
392
-    public function state_ID()
393
-    {
394
-        return $this->get('STA_ID');
395
-    }
396
-
397
-
398
-    /**
399
-     * @return string
400
-     * @throws EE_Error
401
-     */
402
-    public function state_abbrev()
403
-    {
404
-        return $this->state_obj() instanceof EE_State ? $this->state_obj()->abbrev() : '';
405
-    }
406
-
407
-
408
-    /**
409
-     * Gets the state set to this attendee
410
-     *
411
-     * @return EE_State
412
-     * @throws EE_Error
413
-     */
414
-    public function state_obj()
415
-    {
416
-        return $this->get_first_related('State');
417
-    }
418
-
419
-
420
-    /**
421
-     * Returns the state's name, otherwise 'Unknown'
422
-     *
423
-     * @return string
424
-     * @throws EE_Error
425
-     */
426
-    public function state_name()
427
-    {
428
-        if ($this->state_obj()) {
429
-            return $this->state_obj()->name();
430
-        } else {
431
-            return '';
432
-        }
433
-    }
434
-
435
-
436
-    /**
437
-     * either displays the state abbreviation or the state name, as determined
438
-     * by the "FHEE__EEI_Address__state__use_abbreviation" filter.
439
-     * defaults to abbreviation
440
-     *
441
-     * @return string
442
-     * @throws EE_Error
443
-     */
444
-    public function state()
445
-    {
446
-        if (apply_filters('FHEE__EEI_Address__state__use_abbreviation', true, $this->state_obj())) {
447
-            return $this->state_abbrev();
448
-        }
449
-        return $this->state_name();
450
-    }
451
-
452
-
453
-    /**
454
-     *    get Attendee Country ISO Code
455
-     *
456
-     * @return string
457
-     * @throws EE_Error
458
-     */
459
-    public function country_ID()
460
-    {
461
-        return $this->get('CNT_ISO');
462
-    }
463
-
464
-
465
-    /**
466
-     * Gets country set for this attendee
467
-     *
468
-     * @return EE_Country
469
-     * @throws EE_Error
470
-     */
471
-    public function country_obj()
472
-    {
473
-        return $this->get_first_related('Country');
474
-    }
475
-
476
-
477
-    /**
478
-     * Returns the country's name if known, otherwise 'Unknown'
479
-     *
480
-     * @return string
481
-     * @throws EE_Error
482
-     */
483
-    public function country_name()
484
-    {
485
-        if ($this->country_obj()) {
486
-            return $this->country_obj()->name();
487
-        }
488
-        return '';
489
-    }
490
-
491
-
492
-    /**
493
-     * either displays the country ISO2 code or the country name, as determined
494
-     * by the "FHEE__EEI_Address__country__use_abbreviation" filter.
495
-     * defaults to abbreviation
496
-     *
497
-     * @return string
498
-     * @throws EE_Error
499
-     */
500
-    public function country()
501
-    {
502
-        if (apply_filters('FHEE__EEI_Address__country__use_abbreviation', true, $this->country_obj())) {
503
-            return $this->country_ID();
504
-        }
505
-        return $this->country_name();
506
-    }
507
-
508
-
509
-    /**
510
-     *        get Attendee Zip/Postal Code
511
-     *
512
-     * @return string
513
-     * @throws EE_Error
514
-     */
515
-    public function zip()
516
-    {
517
-        return $this->get('ATT_zip');
518
-    }
519
-
520
-
521
-    /**
522
-     *        get Attendee Email Address
523
-     *
524
-     * @return string
525
-     * @throws EE_Error
526
-     */
527
-    public function email()
528
-    {
529
-        return $this->get('ATT_email');
530
-    }
531
-
532
-
533
-    /**
534
-     *        get Attendee Phone #
535
-     *
536
-     * @return string
537
-     * @throws EE_Error
538
-     */
539
-    public function phone()
540
-    {
541
-        return $this->get('ATT_phone');
542
-    }
543
-
544
-
545
-    /**
546
-     *    get deleted
547
-     *
548
-     * @return        bool
549
-     * @throws EE_Error
550
-     */
551
-    public function deleted()
552
-    {
553
-        return $this->get('ATT_deleted');
554
-    }
555
-
556
-
557
-    /**
558
-     * Gets registrations of this attendee
559
-     *
560
-     * @param array $query_params
561
-     * @return EE_Registration[]
562
-     * @throws EE_Error
563
-     */
564
-    public function get_registrations($query_params = array())
565
-    {
566
-        return $this->get_many_related('Registration', $query_params);
567
-    }
568
-
569
-
570
-    /**
571
-     * Gets the most recent registration of this attendee
572
-     *
573
-     * @return EE_Registration
574
-     * @throws EE_Error
575
-     */
576
-    public function get_most_recent_registration()
577
-    {
578
-        return $this->get_first_related(
579
-            'Registration',
580
-            array('order_by' => array('REG_date' => 'DESC'))
581
-        ); // null, 'REG_date', 'DESC', '=', 'OBJECT_K');
582
-    }
583
-
584
-
585
-    /**
586
-     * Gets the most recent registration for this attend at this event
587
-     *
588
-     * @param int $event_id
589
-     * @return EE_Registration
590
-     * @throws EE_Error
591
-     */
592
-    public function get_most_recent_registration_for_event($event_id)
593
-    {
594
-        return $this->get_first_related(
595
-            'Registration',
596
-            array(array('EVT_ID' => $event_id), 'order_by' => array('REG_date' => 'DESC'))
597
-        );
598
-    }
599
-
600
-
601
-    /**
602
-     * returns any events attached to this attendee ($_Event property);
603
-     *
604
-     * @return array
605
-     * @throws EE_Error
606
-     */
607
-    public function events()
608
-    {
609
-        return $this->get_many_related('Event');
610
-    }
611
-
612
-
613
-    /**
614
-     * Gets the billing info array where keys match espresso_reg_page_billing_inputs(),
615
-     * and keys are their cleaned values. @see EE_Attendee::save_and_clean_billing_info_for_payment_method() which was
616
-     * used to save the billing info
617
-     *
618
-     * @param EE_Payment_Method $payment_method the _gateway_name property on the gateway class
619
-     * @return EE_Form_Section_Proper|null
620
-     * @throws EE_Error
621
-     */
622
-    public function billing_info_for_payment_method($payment_method)
623
-    {
624
-        $pm_type = $payment_method->type_obj();
625
-        if (! $pm_type instanceof EE_PMT_Base) {
626
-            return null;
627
-        }
628
-        $billing_info = $this->get_post_meta($this->get_billing_info_postmeta_name($payment_method), true);
629
-        if (! $billing_info) {
630
-            return null;
631
-        }
632
-        $billing_form = $pm_type->billing_form();
633
-        // double-check the form isn't totally hidden, in which case pretend there is no form
634
-        $form_totally_hidden = true;
635
-        foreach ($billing_form->inputs_in_subsections() as $input) {
636
-            if (! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) {
637
-                $form_totally_hidden = false;
638
-                break;
639
-            }
640
-        }
641
-        if ($form_totally_hidden) {
642
-            return null;
643
-        }
644
-        if ($billing_form instanceof EE_Form_Section_Proper) {
645
-            $billing_form->receive_form_submission(array($billing_form->name() => $billing_info), false);
646
-        }
647
-
648
-        return $billing_form;
649
-    }
650
-
651
-
652
-    /**
653
-     * Gets the postmeta key that holds this attendee's billing info for the
654
-     * specified payment method
655
-     *
656
-     * @param EE_Payment_Method $payment_method
657
-     * @return string
658
-     * @throws EE_Error
659
-     */
660
-    public function get_billing_info_postmeta_name($payment_method)
661
-    {
662
-        if ($payment_method->type_obj() instanceof EE_PMT_Base) {
663
-            return 'billing_info_' . $payment_method->type_obj()->system_name();
664
-        }
665
-        return null;
666
-    }
667
-
668
-
669
-    /**
670
-     * Saves the billing info to the attendee. @see EE_Attendee::billing_info_for_payment_method() which is used to
671
-     * retrieve it
672
-     *
673
-     * @param EE_Billing_Attendee_Info_Form $billing_form
674
-     * @param EE_Payment_Method             $payment_method
675
-     * @return boolean
676
-     * @throws EE_Error
677
-     */
678
-    public function save_and_clean_billing_info_for_payment_method($billing_form, $payment_method)
679
-    {
680
-        if (! $billing_form instanceof EE_Billing_Attendee_Info_Form) {
681
-            EE_Error::add_error(esc_html__('Cannot save billing info because there is none.', 'event_espresso'));
682
-            return false;
683
-        }
684
-        $billing_form->clean_sensitive_data();
685
-        return update_post_meta(
686
-            $this->ID(),
687
-            $this->get_billing_info_postmeta_name($payment_method),
688
-            $billing_form->input_values(true)
689
-        );
690
-    }
691
-
692
-
693
-    /**
694
-     * Return the link to the admin details for the object.
695
-     *
696
-     * @return string
697
-     * @throws EE_Error
698
-     * @throws InvalidArgumentException
699
-     * @throws InvalidDataTypeException
700
-     * @throws InvalidInterfaceException
701
-     * @throws ReflectionException
702
-     */
703
-    public function get_admin_details_link()
704
-    {
705
-        return $this->get_admin_edit_link();
706
-    }
707
-
708
-
709
-    /**
710
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
711
-     *
712
-     * @return string
713
-     * @throws EE_Error
714
-     * @throws InvalidArgumentException
715
-     * @throws ReflectionException
716
-     * @throws InvalidDataTypeException
717
-     * @throws InvalidInterfaceException
718
-     */
719
-    public function get_admin_edit_link()
720
-    {
721
-        EE_Registry::instance()->load_helper('URL');
722
-        return EEH_URL::add_query_args_and_nonce(
723
-            array(
724
-                'page'   => 'espresso_registrations',
725
-                'action' => 'edit_attendee',
726
-                'post'   => $this->ID(),
727
-            ),
728
-            admin_url('admin.php')
729
-        );
730
-    }
731
-
732
-
733
-    /**
734
-     * Returns the link to a settings page for the object.
735
-     *
736
-     * @return string
737
-     * @throws EE_Error
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @throws ReflectionException
742
-     */
743
-    public function get_admin_settings_link()
744
-    {
745
-        return $this->get_admin_edit_link();
746
-    }
747
-
748
-
749
-    /**
750
-     * Returns the link to the "overview" for the object (typically the "list table" view).
751
-     *
752
-     * @return string
753
-     * @throws EE_Error
754
-     * @throws InvalidArgumentException
755
-     * @throws ReflectionException
756
-     * @throws InvalidDataTypeException
757
-     * @throws InvalidInterfaceException
758
-     */
759
-    public function get_admin_overview_link()
760
-    {
761
-        EE_Registry::instance()->load_helper('URL');
762
-        return EEH_URL::add_query_args_and_nonce(
763
-            array(
764
-                'page'   => 'espresso_registrations',
765
-                'action' => 'contact_list',
766
-            ),
767
-            admin_url('admin.php')
768
-        );
769
-    }
28
+	/**
29
+	 * Sets some dynamic defaults
30
+	 *
31
+	 * @param array  $fieldValues
32
+	 * @param bool   $bydb
33
+	 * @param string $timezone
34
+	 * @param array  $date_formats
35
+	 * @throws EE_Error
36
+	 */
37
+	protected function __construct($fieldValues = null, $bydb = false, $timezone = null, $date_formats = array())
38
+	{
39
+		if (! isset($fieldValues['ATT_full_name'])) {
40
+			$fname = isset($fieldValues['ATT_fname']) ? $fieldValues['ATT_fname'] . ' ' : '';
41
+			$lname = isset($fieldValues['ATT_lname']) ? $fieldValues['ATT_lname'] : '';
42
+			$fieldValues['ATT_full_name'] = $fname . $lname;
43
+		}
44
+		if (! isset($fieldValues['ATT_slug'])) {
45
+			// $fieldValues['ATT_slug'] = sanitize_key(wp_generate_password(20));
46
+			$fieldValues['ATT_slug'] = sanitize_title($fieldValues['ATT_full_name']);
47
+		}
48
+		if (! isset($fieldValues['ATT_short_bio']) && isset($fieldValues['ATT_bio'])) {
49
+			$fieldValues['ATT_short_bio'] = substr($fieldValues['ATT_bio'], 0, 50);
50
+		}
51
+		parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
52
+	}
53
+
54
+
55
+	/**
56
+	 * @param array  $props_n_values          incoming values
57
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
58
+	 *                                        used.)
59
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
60
+	 *                                        date_format and the second value is the time format
61
+	 * @return EE_Attendee
62
+	 * @throws EE_Error
63
+	 */
64
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
65
+	{
66
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
67
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
68
+	}
69
+
70
+
71
+	/**
72
+	 * @param array  $props_n_values  incoming values from the database
73
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
74
+	 *                                the website will be used.
75
+	 * @return EE_Attendee
76
+	 */
77
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
78
+	{
79
+		return new self($props_n_values, true, $timezone);
80
+	}
81
+
82
+
83
+	/**
84
+	 *        Set Attendee First Name
85
+	 *
86
+	 * @access        public
87
+	 * @param string $fname
88
+	 * @throws EE_Error
89
+	 */
90
+	public function set_fname($fname = '')
91
+	{
92
+		$this->set('ATT_fname', $fname);
93
+	}
94
+
95
+
96
+	/**
97
+	 *        Set Attendee Last Name
98
+	 *
99
+	 * @access        public
100
+	 * @param string $lname
101
+	 * @throws EE_Error
102
+	 */
103
+	public function set_lname($lname = '')
104
+	{
105
+		$this->set('ATT_lname', $lname);
106
+	}
107
+
108
+
109
+	/**
110
+	 *        Set Attendee Address
111
+	 *
112
+	 * @access        public
113
+	 * @param string $address
114
+	 * @throws EE_Error
115
+	 */
116
+	public function set_address($address = '')
117
+	{
118
+		$this->set('ATT_address', $address);
119
+	}
120
+
121
+
122
+	/**
123
+	 *        Set Attendee Address2
124
+	 *
125
+	 * @access        public
126
+	 * @param        string $address2
127
+	 * @throws EE_Error
128
+	 */
129
+	public function set_address2($address2 = '')
130
+	{
131
+		$this->set('ATT_address2', $address2);
132
+	}
133
+
134
+
135
+	/**
136
+	 *        Set Attendee City
137
+	 *
138
+	 * @access        public
139
+	 * @param        string $city
140
+	 * @throws EE_Error
141
+	 */
142
+	public function set_city($city = '')
143
+	{
144
+		$this->set('ATT_city', $city);
145
+	}
146
+
147
+
148
+	/**
149
+	 *        Set Attendee State ID
150
+	 *
151
+	 * @access        public
152
+	 * @param        int $STA_ID
153
+	 * @throws EE_Error
154
+	 */
155
+	public function set_state($STA_ID = 0)
156
+	{
157
+		$this->set('STA_ID', $STA_ID);
158
+	}
159
+
160
+
161
+	/**
162
+	 *        Set Attendee Country ISO Code
163
+	 *
164
+	 * @access        public
165
+	 * @param        string $CNT_ISO
166
+	 * @throws EE_Error
167
+	 */
168
+	public function set_country($CNT_ISO = '')
169
+	{
170
+		$this->set('CNT_ISO', $CNT_ISO);
171
+	}
172
+
173
+
174
+	/**
175
+	 *        Set Attendee Zip/Postal Code
176
+	 *
177
+	 * @access        public
178
+	 * @param        string $zip
179
+	 * @throws EE_Error
180
+	 */
181
+	public function set_zip($zip = '')
182
+	{
183
+		$this->set('ATT_zip', $zip);
184
+	}
185
+
186
+
187
+	/**
188
+	 *        Set Attendee Email Address
189
+	 *
190
+	 * @access        public
191
+	 * @param        string $email
192
+	 * @throws EE_Error
193
+	 */
194
+	public function set_email($email = '')
195
+	{
196
+		$this->set('ATT_email', $email);
197
+	}
198
+
199
+
200
+	/**
201
+	 *        Set Attendee Phone
202
+	 *
203
+	 * @access        public
204
+	 * @param        string $phone
205
+	 * @throws EE_Error
206
+	 */
207
+	public function set_phone($phone = '')
208
+	{
209
+		$this->set('ATT_phone', $phone);
210
+	}
211
+
212
+
213
+	/**
214
+	 *        set deleted
215
+	 *
216
+	 * @access        public
217
+	 * @param        bool $ATT_deleted
218
+	 * @throws EE_Error
219
+	 */
220
+	public function set_deleted($ATT_deleted = false)
221
+	{
222
+		$this->set('ATT_deleted', $ATT_deleted);
223
+	}
224
+
225
+
226
+	/**
227
+	 * Returns the value for the post_author id saved with the cpt
228
+	 *
229
+	 * @since 4.5.0
230
+	 * @return int
231
+	 * @throws EE_Error
232
+	 */
233
+	public function wp_user()
234
+	{
235
+		return $this->get('ATT_author');
236
+	}
237
+
238
+
239
+	/**
240
+	 *        get Attendee First Name
241
+	 *
242
+	 * @access        public
243
+	 * @return string
244
+	 * @throws EE_Error
245
+	 */
246
+	public function fname()
247
+	{
248
+		return $this->get('ATT_fname');
249
+	}
250
+
251
+
252
+	/**
253
+	 * echoes out the attendee's first name
254
+	 *
255
+	 * @return void
256
+	 * @throws EE_Error
257
+	 */
258
+	public function e_full_name()
259
+	{
260
+		echo $this->full_name(); // sanitized
261
+	}
262
+
263
+
264
+	/**
265
+	 * Returns the first and last name concatenated together with a space.
266
+	 *
267
+	 * @param bool $apply_html_entities
268
+	 * @return string
269
+	 * @throws EE_Error
270
+	 */
271
+	public function full_name($apply_html_entities = false)
272
+	{
273
+		$full_name = array(
274
+			$this->fname(),
275
+			$this->lname(),
276
+		);
277
+		$full_name = array_filter($full_name);
278
+		$full_name = implode(' ', $full_name);
279
+		return $apply_html_entities ? htmlentities($full_name, ENT_QUOTES, 'UTF-8') : $full_name;
280
+	}
281
+
282
+
283
+	/**
284
+	 * This returns the value of the `ATT_full_name` field which is usually equivalent to calling `full_name()` unless
285
+	 * the post_title field has been directly modified in the db for the post (espresso_attendees post type) for this
286
+	 * attendee.
287
+	 *
288
+	 * @param bool $apply_html_entities
289
+	 * @return string
290
+	 * @throws EE_Error
291
+	 */
292
+	public function ATT_full_name($apply_html_entities = false)
293
+	{
294
+		return $apply_html_entities
295
+			? htmlentities($this->get('ATT_full_name'), ENT_QUOTES, 'UTF-8')
296
+			: $this->get('ATT_full_name');
297
+	}
298
+
299
+
300
+	/**
301
+	 *        get Attendee Last Name
302
+	 *
303
+	 * @access        public
304
+	 * @return string
305
+	 * @throws EE_Error
306
+	 */
307
+	public function lname()
308
+	{
309
+		return $this->get('ATT_lname');
310
+	}
311
+
312
+
313
+	/**
314
+	 * Gets the attendee's full address as an array so client code can decide hwo to display it
315
+	 *
316
+	 * @return array numerically indexed, with each part of the address that is known.
317
+	 * Eg, if the user only responded to state and country,
318
+	 * it would be array(0=>'Alabama',1=>'USA')
319
+	 * @return array
320
+	 * @throws EE_Error
321
+	 */
322
+	public function full_address_as_array()
323
+	{
324
+		$full_address_array = array();
325
+		$initial_address_fields = array('ATT_address', 'ATT_address2', 'ATT_city',);
326
+		foreach ($initial_address_fields as $address_field_name) {
327
+			$address_fields_value = $this->get($address_field_name);
328
+			if (! empty($address_fields_value)) {
329
+				$full_address_array[] = $address_fields_value;
330
+			}
331
+		}
332
+		// now handle state and country
333
+		$state_obj = $this->state_obj();
334
+		if ($state_obj instanceof EE_State) {
335
+			$full_address_array[] = $state_obj->name();
336
+		}
337
+		$country_obj = $this->country_obj();
338
+		if ($country_obj instanceof EE_Country) {
339
+			$full_address_array[] = $country_obj->name();
340
+		}
341
+		// lastly get the xip
342
+		$zip_value = $this->zip();
343
+		if (! empty($zip_value)) {
344
+			$full_address_array[] = $zip_value;
345
+		}
346
+		return $full_address_array;
347
+	}
348
+
349
+
350
+	/**
351
+	 *        get Attendee Address
352
+	 *
353
+	 * @return string
354
+	 * @throws EE_Error
355
+	 */
356
+	public function address()
357
+	{
358
+		return $this->get('ATT_address');
359
+	}
360
+
361
+
362
+	/**
363
+	 *        get Attendee Address2
364
+	 *
365
+	 * @return string
366
+	 * @throws EE_Error
367
+	 */
368
+	public function address2()
369
+	{
370
+		return $this->get('ATT_address2');
371
+	}
372
+
373
+
374
+	/**
375
+	 *        get Attendee City
376
+	 *
377
+	 * @return string
378
+	 * @throws EE_Error
379
+	 */
380
+	public function city()
381
+	{
382
+		return $this->get('ATT_city');
383
+	}
384
+
385
+
386
+	/**
387
+	 *        get Attendee State ID
388
+	 *
389
+	 * @return string
390
+	 * @throws EE_Error
391
+	 */
392
+	public function state_ID()
393
+	{
394
+		return $this->get('STA_ID');
395
+	}
396
+
397
+
398
+	/**
399
+	 * @return string
400
+	 * @throws EE_Error
401
+	 */
402
+	public function state_abbrev()
403
+	{
404
+		return $this->state_obj() instanceof EE_State ? $this->state_obj()->abbrev() : '';
405
+	}
406
+
407
+
408
+	/**
409
+	 * Gets the state set to this attendee
410
+	 *
411
+	 * @return EE_State
412
+	 * @throws EE_Error
413
+	 */
414
+	public function state_obj()
415
+	{
416
+		return $this->get_first_related('State');
417
+	}
418
+
419
+
420
+	/**
421
+	 * Returns the state's name, otherwise 'Unknown'
422
+	 *
423
+	 * @return string
424
+	 * @throws EE_Error
425
+	 */
426
+	public function state_name()
427
+	{
428
+		if ($this->state_obj()) {
429
+			return $this->state_obj()->name();
430
+		} else {
431
+			return '';
432
+		}
433
+	}
434
+
435
+
436
+	/**
437
+	 * either displays the state abbreviation or the state name, as determined
438
+	 * by the "FHEE__EEI_Address__state__use_abbreviation" filter.
439
+	 * defaults to abbreviation
440
+	 *
441
+	 * @return string
442
+	 * @throws EE_Error
443
+	 */
444
+	public function state()
445
+	{
446
+		if (apply_filters('FHEE__EEI_Address__state__use_abbreviation', true, $this->state_obj())) {
447
+			return $this->state_abbrev();
448
+		}
449
+		return $this->state_name();
450
+	}
451
+
452
+
453
+	/**
454
+	 *    get Attendee Country ISO Code
455
+	 *
456
+	 * @return string
457
+	 * @throws EE_Error
458
+	 */
459
+	public function country_ID()
460
+	{
461
+		return $this->get('CNT_ISO');
462
+	}
463
+
464
+
465
+	/**
466
+	 * Gets country set for this attendee
467
+	 *
468
+	 * @return EE_Country
469
+	 * @throws EE_Error
470
+	 */
471
+	public function country_obj()
472
+	{
473
+		return $this->get_first_related('Country');
474
+	}
475
+
476
+
477
+	/**
478
+	 * Returns the country's name if known, otherwise 'Unknown'
479
+	 *
480
+	 * @return string
481
+	 * @throws EE_Error
482
+	 */
483
+	public function country_name()
484
+	{
485
+		if ($this->country_obj()) {
486
+			return $this->country_obj()->name();
487
+		}
488
+		return '';
489
+	}
490
+
491
+
492
+	/**
493
+	 * either displays the country ISO2 code or the country name, as determined
494
+	 * by the "FHEE__EEI_Address__country__use_abbreviation" filter.
495
+	 * defaults to abbreviation
496
+	 *
497
+	 * @return string
498
+	 * @throws EE_Error
499
+	 */
500
+	public function country()
501
+	{
502
+		if (apply_filters('FHEE__EEI_Address__country__use_abbreviation', true, $this->country_obj())) {
503
+			return $this->country_ID();
504
+		}
505
+		return $this->country_name();
506
+	}
507
+
508
+
509
+	/**
510
+	 *        get Attendee Zip/Postal Code
511
+	 *
512
+	 * @return string
513
+	 * @throws EE_Error
514
+	 */
515
+	public function zip()
516
+	{
517
+		return $this->get('ATT_zip');
518
+	}
519
+
520
+
521
+	/**
522
+	 *        get Attendee Email Address
523
+	 *
524
+	 * @return string
525
+	 * @throws EE_Error
526
+	 */
527
+	public function email()
528
+	{
529
+		return $this->get('ATT_email');
530
+	}
531
+
532
+
533
+	/**
534
+	 *        get Attendee Phone #
535
+	 *
536
+	 * @return string
537
+	 * @throws EE_Error
538
+	 */
539
+	public function phone()
540
+	{
541
+		return $this->get('ATT_phone');
542
+	}
543
+
544
+
545
+	/**
546
+	 *    get deleted
547
+	 *
548
+	 * @return        bool
549
+	 * @throws EE_Error
550
+	 */
551
+	public function deleted()
552
+	{
553
+		return $this->get('ATT_deleted');
554
+	}
555
+
556
+
557
+	/**
558
+	 * Gets registrations of this attendee
559
+	 *
560
+	 * @param array $query_params
561
+	 * @return EE_Registration[]
562
+	 * @throws EE_Error
563
+	 */
564
+	public function get_registrations($query_params = array())
565
+	{
566
+		return $this->get_many_related('Registration', $query_params);
567
+	}
568
+
569
+
570
+	/**
571
+	 * Gets the most recent registration of this attendee
572
+	 *
573
+	 * @return EE_Registration
574
+	 * @throws EE_Error
575
+	 */
576
+	public function get_most_recent_registration()
577
+	{
578
+		return $this->get_first_related(
579
+			'Registration',
580
+			array('order_by' => array('REG_date' => 'DESC'))
581
+		); // null, 'REG_date', 'DESC', '=', 'OBJECT_K');
582
+	}
583
+
584
+
585
+	/**
586
+	 * Gets the most recent registration for this attend at this event
587
+	 *
588
+	 * @param int $event_id
589
+	 * @return EE_Registration
590
+	 * @throws EE_Error
591
+	 */
592
+	public function get_most_recent_registration_for_event($event_id)
593
+	{
594
+		return $this->get_first_related(
595
+			'Registration',
596
+			array(array('EVT_ID' => $event_id), 'order_by' => array('REG_date' => 'DESC'))
597
+		);
598
+	}
599
+
600
+
601
+	/**
602
+	 * returns any events attached to this attendee ($_Event property);
603
+	 *
604
+	 * @return array
605
+	 * @throws EE_Error
606
+	 */
607
+	public function events()
608
+	{
609
+		return $this->get_many_related('Event');
610
+	}
611
+
612
+
613
+	/**
614
+	 * Gets the billing info array where keys match espresso_reg_page_billing_inputs(),
615
+	 * and keys are their cleaned values. @see EE_Attendee::save_and_clean_billing_info_for_payment_method() which was
616
+	 * used to save the billing info
617
+	 *
618
+	 * @param EE_Payment_Method $payment_method the _gateway_name property on the gateway class
619
+	 * @return EE_Form_Section_Proper|null
620
+	 * @throws EE_Error
621
+	 */
622
+	public function billing_info_for_payment_method($payment_method)
623
+	{
624
+		$pm_type = $payment_method->type_obj();
625
+		if (! $pm_type instanceof EE_PMT_Base) {
626
+			return null;
627
+		}
628
+		$billing_info = $this->get_post_meta($this->get_billing_info_postmeta_name($payment_method), true);
629
+		if (! $billing_info) {
630
+			return null;
631
+		}
632
+		$billing_form = $pm_type->billing_form();
633
+		// double-check the form isn't totally hidden, in which case pretend there is no form
634
+		$form_totally_hidden = true;
635
+		foreach ($billing_form->inputs_in_subsections() as $input) {
636
+			if (! $input->get_display_strategy() instanceof EE_Hidden_Display_Strategy) {
637
+				$form_totally_hidden = false;
638
+				break;
639
+			}
640
+		}
641
+		if ($form_totally_hidden) {
642
+			return null;
643
+		}
644
+		if ($billing_form instanceof EE_Form_Section_Proper) {
645
+			$billing_form->receive_form_submission(array($billing_form->name() => $billing_info), false);
646
+		}
647
+
648
+		return $billing_form;
649
+	}
650
+
651
+
652
+	/**
653
+	 * Gets the postmeta key that holds this attendee's billing info for the
654
+	 * specified payment method
655
+	 *
656
+	 * @param EE_Payment_Method $payment_method
657
+	 * @return string
658
+	 * @throws EE_Error
659
+	 */
660
+	public function get_billing_info_postmeta_name($payment_method)
661
+	{
662
+		if ($payment_method->type_obj() instanceof EE_PMT_Base) {
663
+			return 'billing_info_' . $payment_method->type_obj()->system_name();
664
+		}
665
+		return null;
666
+	}
667
+
668
+
669
+	/**
670
+	 * Saves the billing info to the attendee. @see EE_Attendee::billing_info_for_payment_method() which is used to
671
+	 * retrieve it
672
+	 *
673
+	 * @param EE_Billing_Attendee_Info_Form $billing_form
674
+	 * @param EE_Payment_Method             $payment_method
675
+	 * @return boolean
676
+	 * @throws EE_Error
677
+	 */
678
+	public function save_and_clean_billing_info_for_payment_method($billing_form, $payment_method)
679
+	{
680
+		if (! $billing_form instanceof EE_Billing_Attendee_Info_Form) {
681
+			EE_Error::add_error(esc_html__('Cannot save billing info because there is none.', 'event_espresso'));
682
+			return false;
683
+		}
684
+		$billing_form->clean_sensitive_data();
685
+		return update_post_meta(
686
+			$this->ID(),
687
+			$this->get_billing_info_postmeta_name($payment_method),
688
+			$billing_form->input_values(true)
689
+		);
690
+	}
691
+
692
+
693
+	/**
694
+	 * Return the link to the admin details for the object.
695
+	 *
696
+	 * @return string
697
+	 * @throws EE_Error
698
+	 * @throws InvalidArgumentException
699
+	 * @throws InvalidDataTypeException
700
+	 * @throws InvalidInterfaceException
701
+	 * @throws ReflectionException
702
+	 */
703
+	public function get_admin_details_link()
704
+	{
705
+		return $this->get_admin_edit_link();
706
+	}
707
+
708
+
709
+	/**
710
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
711
+	 *
712
+	 * @return string
713
+	 * @throws EE_Error
714
+	 * @throws InvalidArgumentException
715
+	 * @throws ReflectionException
716
+	 * @throws InvalidDataTypeException
717
+	 * @throws InvalidInterfaceException
718
+	 */
719
+	public function get_admin_edit_link()
720
+	{
721
+		EE_Registry::instance()->load_helper('URL');
722
+		return EEH_URL::add_query_args_and_nonce(
723
+			array(
724
+				'page'   => 'espresso_registrations',
725
+				'action' => 'edit_attendee',
726
+				'post'   => $this->ID(),
727
+			),
728
+			admin_url('admin.php')
729
+		);
730
+	}
731
+
732
+
733
+	/**
734
+	 * Returns the link to a settings page for the object.
735
+	 *
736
+	 * @return string
737
+	 * @throws EE_Error
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @throws ReflectionException
742
+	 */
743
+	public function get_admin_settings_link()
744
+	{
745
+		return $this->get_admin_edit_link();
746
+	}
747
+
748
+
749
+	/**
750
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
751
+	 *
752
+	 * @return string
753
+	 * @throws EE_Error
754
+	 * @throws InvalidArgumentException
755
+	 * @throws ReflectionException
756
+	 * @throws InvalidDataTypeException
757
+	 * @throws InvalidInterfaceException
758
+	 */
759
+	public function get_admin_overview_link()
760
+	{
761
+		EE_Registry::instance()->load_helper('URL');
762
+		return EEH_URL::add_query_args_and_nonce(
763
+			array(
764
+				'page'   => 'espresso_registrations',
765
+				'action' => 'contact_list',
766
+			),
767
+			admin_url('admin.php')
768
+		);
769
+	}
770 770
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Ticket.class.php 2 patches
Indentation   +1724 added lines, -1724 removed lines patch added patch discarded remove patch
@@ -14,1732 +14,1732 @@
 block discarded – undo
14 14
 class EE_Ticket extends EE_Soft_Delete_Base_Class implements EEI_Line_Item_Object, EEI_Event_Relation, EEI_Has_Icon
15 15
 {
16 16
 
17
-    /**
18
-     * The following constants are used by the ticket_status() method to indicate whether a ticket is on sale or not.
19
-     */
20
-    const sold_out = 'TKS';
21
-
22
-    /**
23
-     *
24
-     */
25
-    const expired = 'TKE';
26
-
27
-    /**
28
-     *
29
-     */
30
-    const archived = 'TKA';
31
-
32
-    /**
33
-     *
34
-     */
35
-    const pending = 'TKP';
36
-
37
-    /**
38
-     *
39
-     */
40
-    const onsale = 'TKO';
41
-
42
-    /**
43
-     * extra meta key for tracking ticket reservations
44
-     *
45
-     * @type string
46
-     */
47
-    const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
48
-
49
-    /**
50
-     * cached result from method of the same name
51
-     *
52
-     * @var float $_ticket_total_with_taxes
53
-     */
54
-    private $_ticket_total_with_taxes;
55
-
56
-
57
-    /**
58
-     * @param array  $props_n_values          incoming values
59
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
60
-     *                                        used.)
61
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
62
-     *                                        date_format and the second value is the time format
63
-     * @return EE_Ticket
64
-     * @throws EE_Error
65
-     */
66
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
67
-    {
68
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
69
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
70
-    }
71
-
72
-
73
-    /**
74
-     * @param array  $props_n_values  incoming values from the database
75
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
76
-     *                                the website will be used.
77
-     * @return EE_Ticket
78
-     * @throws EE_Error
79
-     */
80
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
81
-    {
82
-        return new self($props_n_values, true, $timezone);
83
-    }
84
-
85
-
86
-    /**
87
-     * @return bool
88
-     * @throws EE_Error
89
-     */
90
-    public function parent()
91
-    {
92
-        return $this->get('TKT_parent');
93
-    }
94
-
95
-
96
-    /**
97
-     * return if a ticket has quantities available for purchase
98
-     *
99
-     * @param  int $DTT_ID the primary key for a particular datetime
100
-     * @return boolean
101
-     * @throws EE_Error
102
-     */
103
-    public function available($DTT_ID = 0)
104
-    {
105
-        // are we checking availability for a particular datetime ?
106
-        if ($DTT_ID) {
107
-            // get that datetime object
108
-            $datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
109
-            // if  ticket sales for this datetime have exceeded the reg limit...
110
-            if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
111
-                return false;
112
-            }
113
-        }
114
-        // datetime is still open for registration, but is this ticket sold out ?
115
-        return $this->qty() < 1 || $this->qty() > $this->sold() ? true : false;
116
-    }
117
-
118
-
119
-    /**
120
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
121
-     *
122
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
123
-     *                               relevant status const
124
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
125
-     *               further processing
126
-     * @return mixed status int if the display string isn't requested
127
-     * @throws EE_Error
128
-     */
129
-    public function ticket_status($display = false, $remaining = null)
130
-    {
131
-        $remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
132
-        if (! $remaining) {
133
-            return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
134
-        }
135
-        if ($this->get('TKT_deleted')) {
136
-            return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
137
-        }
138
-        if ($this->is_expired()) {
139
-            return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
140
-        }
141
-        if ($this->is_pending()) {
142
-            return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
143
-        }
144
-        if ($this->is_on_sale()) {
145
-            return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
146
-        }
147
-        return '';
148
-    }
149
-
150
-
151
-    /**
152
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
153
-     * considering ALL the factors used for figuring that out.
154
-     *
155
-     * @access public
156
-     * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
157
-     * @return boolean         true = tickets remaining, false not.
158
-     * @throws EE_Error
159
-     */
160
-    public function is_remaining($DTT_ID = 0)
161
-    {
162
-        $num_remaining = $this->remaining($DTT_ID);
163
-        if ($num_remaining === 0) {
164
-            return false;
165
-        }
166
-        if ($num_remaining > 0 && $num_remaining < $this->min()) {
167
-            return false;
168
-        }
169
-        return true;
170
-    }
171
-
172
-
173
-    /**
174
-     * return the total number of tickets available for purchase
175
-     *
176
-     * @param  int $DTT_ID the primary key for a particular datetime.
177
-     *                     set to 0 for all related datetimes
178
-     * @return int
179
-     * @throws EE_Error
180
-     */
181
-    public function remaining($DTT_ID = 0)
182
-    {
183
-        return $this->real_quantity_on_ticket('saleable', $DTT_ID);
184
-    }
185
-
186
-
187
-    /**
188
-     * Gets min
189
-     *
190
-     * @return int
191
-     * @throws EE_Error
192
-     */
193
-    public function min()
194
-    {
195
-        return $this->get('TKT_min');
196
-    }
197
-
198
-
199
-    /**
200
-     * return if a ticket is no longer available cause its available dates have expired.
201
-     *
202
-     * @return boolean
203
-     * @throws EE_Error
204
-     */
205
-    public function is_expired()
206
-    {
207
-        return ($this->get_raw('TKT_end_date') < time());
208
-    }
209
-
210
-
211
-    /**
212
-     * Return if a ticket is yet to go on sale or not
213
-     *
214
-     * @return boolean
215
-     * @throws EE_Error
216
-     */
217
-    public function is_pending()
218
-    {
219
-        return ($this->get_raw('TKT_start_date') > time());
220
-    }
221
-
222
-
223
-    /**
224
-     * Return if a ticket is on sale or not
225
-     *
226
-     * @return boolean
227
-     * @throws EE_Error
228
-     */
229
-    public function is_on_sale()
230
-    {
231
-        return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
232
-    }
233
-
234
-
235
-    /**
236
-     * This returns the chronologically last datetime that this ticket is associated with
237
-     *
238
-     * @param string $dt_frmt
239
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
240
-     *                            the end date ie: Jan 01 "to" Dec 31
241
-     * @return string
242
-     * @throws EE_Error
243
-     */
244
-    public function date_range($dt_frmt = '', $conjunction = ' - ')
245
-    {
246
-        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
247
-        $first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
248
-            : '';
249
-        $last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
250
-
251
-        return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
252
-    }
253
-
254
-
255
-    /**
256
-     * This returns the chronologically first datetime that this ticket is associated with
257
-     *
258
-     * @return EE_Datetime
259
-     * @throws EE_Error
260
-     */
261
-    public function first_datetime()
262
-    {
263
-        $datetimes = $this->datetimes(array('limit' => 1));
264
-        return reset($datetimes);
265
-    }
266
-
267
-
268
-    /**
269
-     * Gets all the datetimes this ticket can be used for attending.
270
-     * Unless otherwise specified, orders datetimes by start date.
271
-     *
272
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
273
-     * @return EE_Datetime[]|EE_Base_Class[]
274
-     * @throws EE_Error
275
-     */
276
-    public function datetimes($query_params = array())
277
-    {
278
-        if (! isset($query_params['order_by'])) {
279
-            $query_params['order_by']['DTT_order'] = 'ASC';
280
-        }
281
-        return $this->get_many_related('Datetime', $query_params);
282
-    }
283
-
284
-
285
-    /**
286
-     * This returns the chronologically last datetime that this ticket is associated with
287
-     *
288
-     * @return EE_Datetime
289
-     * @throws EE_Error
290
-     */
291
-    public function last_datetime()
292
-    {
293
-        $datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
294
-        return end($datetimes);
295
-    }
296
-
297
-
298
-    /**
299
-     * This returns the total tickets sold depending on the given parameters.
300
-     *
301
-     * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
302
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
303
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
304
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
305
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
306
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
307
-     * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
308
-     * @return mixed (array|int)          how many tickets have sold
309
-     * @throws EE_Error
310
-     */
311
-    public function tickets_sold($what = 'ticket', $dtt_id = null)
312
-    {
313
-        $total = 0;
314
-        $tickets_sold = $this->_all_tickets_sold();
315
-        switch ($what) {
316
-            case 'ticket':
317
-                return $tickets_sold['ticket'];
318
-                break;
319
-            case 'datetime':
320
-                if (empty($tickets_sold['datetime'])) {
321
-                    return $total;
322
-                }
323
-                if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
324
-                    EE_Error::add_error(
325
-                        esc_html__(
326
-                            'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
327
-                            'event_espresso'
328
-                        ),
329
-                        __FILE__,
330
-                        __FUNCTION__,
331
-                        __LINE__
332
-                    );
333
-                    return $total;
334
-                }
335
-                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
336
-                break;
337
-            default:
338
-                return $total;
339
-        }
340
-    }
341
-
342
-
343
-    /**
344
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
345
-     *
346
-     * @return EE_Ticket[]
347
-     * @throws EE_Error
348
-     */
349
-    protected function _all_tickets_sold()
350
-    {
351
-        $datetimes = $this->get_many_related('Datetime');
352
-        $tickets_sold = array();
353
-        if (! empty($datetimes)) {
354
-            foreach ($datetimes as $datetime) {
355
-                $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
356
-            }
357
-        }
358
-        // Tickets sold
359
-        $tickets_sold['ticket'] = $this->sold();
360
-        return $tickets_sold;
361
-    }
362
-
363
-
364
-    /**
365
-     * This returns the base price object for the ticket.
366
-     *
367
-     * @param  bool $return_array whether to return as an array indexed by price id or just the object.
368
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
369
-     * @throws EE_Error
370
-     */
371
-    public function base_price($return_array = false)
372
-    {
373
-        $_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
374
-        return $return_array
375
-            ? $this->get_many_related('Price', array($_where))
376
-            : $this->get_first_related('Price', array($_where));
377
-    }
378
-
379
-
380
-    /**
381
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
382
-     *
383
-     * @access public
384
-     * @return EE_Price[]
385
-     * @throws EE_Error
386
-     */
387
-    public function price_modifiers()
388
-    {
389
-        $query_params = array(
390
-            0 => array(
391
-                'Price_Type.PBT_ID' => array(
392
-                    'NOT IN',
393
-                    array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax),
394
-                ),
395
-            ),
396
-        );
397
-        return $this->prices($query_params);
398
-    }
399
-
400
-
401
-    /**
402
-     * Gets all the prices that combine to form the final price of this ticket
403
-     *
404
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
405
-     * @return EE_Price[]|EE_Base_Class[]
406
-     * @throws EE_Error
407
-     */
408
-    public function prices($query_params = array())
409
-    {
410
-        return $this->get_many_related('Price', $query_params);
411
-    }
412
-
413
-
414
-    /**
415
-     * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
416
-     *
417
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
418
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
419
-     * @throws EE_Error
420
-     */
421
-    public function datetime_tickets($query_params = array())
422
-    {
423
-        return $this->get_many_related('Datetime_Ticket', $query_params);
424
-    }
425
-
426
-
427
-    /**
428
-     * Gets all the datetimes from the db ordered by DTT_order
429
-     *
430
-     * @param boolean $show_expired
431
-     * @param boolean $show_deleted
432
-     * @return EE_Datetime[]
433
-     * @throws EE_Error
434
-     */
435
-    public function datetimes_ordered($show_expired = true, $show_deleted = false)
436
-    {
437
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
438
-            $this->ID(),
439
-            $show_expired,
440
-            $show_deleted
441
-        );
442
-    }
443
-
444
-
445
-    /**
446
-     * Gets ID
447
-     *
448
-     * @return string
449
-     * @throws EE_Error
450
-     */
451
-    public function ID()
452
-    {
453
-        return $this->get('TKT_ID');
454
-    }
455
-
456
-
457
-    /**
458
-     * get the author of the ticket.
459
-     *
460
-     * @since 4.5.0
461
-     * @return int
462
-     * @throws EE_Error
463
-     */
464
-    public function wp_user()
465
-    {
466
-        return $this->get('TKT_wp_user');
467
-    }
468
-
469
-
470
-    /**
471
-     * Gets the template for the ticket
472
-     *
473
-     * @return EE_Ticket_Template|EE_Base_Class
474
-     * @throws EE_Error
475
-     */
476
-    public function template()
477
-    {
478
-        return $this->get_first_related('Ticket_Template');
479
-    }
480
-
481
-
482
-    /**
483
-     * Simply returns an array of EE_Price objects that are taxes.
484
-     *
485
-     * @return EE_Price[]
486
-     * @throws EE_Error
487
-     */
488
-    public function get_ticket_taxes_for_admin()
489
-    {
490
-        return EE_Taxes::get_taxes_for_admin();
491
-    }
492
-
493
-
494
-    /**
495
-     * @return float
496
-     * @throws EE_Error
497
-     */
498
-    public function ticket_price()
499
-    {
500
-        return $this->get('TKT_price');
501
-    }
502
-
503
-
504
-    /**
505
-     * @return mixed
506
-     * @throws EE_Error
507
-     */
508
-    public function pretty_price()
509
-    {
510
-        return $this->get_pretty('TKT_price');
511
-    }
512
-
513
-
514
-    /**
515
-     * @return bool
516
-     * @throws EE_Error
517
-     */
518
-    public function is_free()
519
-    {
520
-        return $this->get_ticket_total_with_taxes() === (float) 0;
521
-    }
522
-
523
-
524
-    /**
525
-     * get_ticket_total_with_taxes
526
-     *
527
-     * @param bool $no_cache
528
-     * @return float
529
-     * @throws EE_Error
530
-     */
531
-    public function get_ticket_total_with_taxes($no_cache = false)
532
-    {
533
-        if ($this->_ticket_total_with_taxes === null || $no_cache) {
534
-            $this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
535
-        }
536
-        return (float) $this->_ticket_total_with_taxes;
537
-    }
538
-
539
-
540
-    public function ensure_TKT_Price_correct()
541
-    {
542
-        $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
543
-        $this->save();
544
-    }
545
-
546
-
547
-    /**
548
-     * @return float
549
-     * @throws EE_Error
550
-     */
551
-    public function get_ticket_subtotal()
552
-    {
553
-        return EE_Taxes::get_subtotal_for_admin($this);
554
-    }
555
-
556
-
557
-    /**
558
-     * Returns the total taxes applied to this ticket
559
-     *
560
-     * @return float
561
-     * @throws EE_Error
562
-     */
563
-    public function get_ticket_taxes_total_for_admin()
564
-    {
565
-        return EE_Taxes::get_total_taxes_for_admin($this);
566
-    }
567
-
568
-
569
-    /**
570
-     * Sets name
571
-     *
572
-     * @param string $name
573
-     * @throws EE_Error
574
-     */
575
-    public function set_name($name)
576
-    {
577
-        $this->set('TKT_name', $name);
578
-    }
579
-
580
-
581
-    /**
582
-     * Gets description
583
-     *
584
-     * @return string
585
-     * @throws EE_Error
586
-     */
587
-    public function description()
588
-    {
589
-        return $this->get('TKT_description');
590
-    }
591
-
592
-
593
-    /**
594
-     * Sets description
595
-     *
596
-     * @param string $description
597
-     * @throws EE_Error
598
-     */
599
-    public function set_description($description)
600
-    {
601
-        $this->set('TKT_description', $description);
602
-    }
603
-
604
-
605
-    /**
606
-     * Gets start_date
607
-     *
608
-     * @param string $dt_frmt
609
-     * @param string $tm_frmt
610
-     * @return string
611
-     * @throws EE_Error
612
-     */
613
-    public function start_date($dt_frmt = '', $tm_frmt = '')
614
-    {
615
-        return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
616
-    }
617
-
618
-
619
-    /**
620
-     * Sets start_date
621
-     *
622
-     * @param string $start_date
623
-     * @return void
624
-     * @throws EE_Error
625
-     */
626
-    public function set_start_date($start_date)
627
-    {
628
-        $this->_set_date_time('B', $start_date, 'TKT_start_date');
629
-    }
630
-
631
-
632
-    /**
633
-     * Gets end_date
634
-     *
635
-     * @param string $dt_frmt
636
-     * @param string $tm_frmt
637
-     * @return string
638
-     * @throws EE_Error
639
-     */
640
-    public function end_date($dt_frmt = '', $tm_frmt = '')
641
-    {
642
-        return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
643
-    }
644
-
645
-
646
-    /**
647
-     * Sets end_date
648
-     *
649
-     * @param string $end_date
650
-     * @return void
651
-     * @throws EE_Error
652
-     */
653
-    public function set_end_date($end_date)
654
-    {
655
-        $this->_set_date_time('B', $end_date, 'TKT_end_date');
656
-    }
657
-
658
-
659
-    /**
660
-     * Sets sell until time
661
-     *
662
-     * @since 4.5.0
663
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
664
-     * @throws EE_Error
665
-     */
666
-    public function set_end_time($time)
667
-    {
668
-        $this->_set_time_for($time, 'TKT_end_date');
669
-    }
670
-
671
-
672
-    /**
673
-     * Sets min
674
-     *
675
-     * @param int $min
676
-     * @return void
677
-     * @throws EE_Error
678
-     */
679
-    public function set_min($min)
680
-    {
681
-        $this->set('TKT_min', $min);
682
-    }
683
-
684
-
685
-    /**
686
-     * Gets max
687
-     *
688
-     * @return int
689
-     * @throws EE_Error
690
-     */
691
-    public function max()
692
-    {
693
-        return $this->get('TKT_max');
694
-    }
695
-
696
-
697
-    /**
698
-     * Sets max
699
-     *
700
-     * @param int $max
701
-     * @return void
702
-     * @throws EE_Error
703
-     */
704
-    public function set_max($max)
705
-    {
706
-        $this->set('TKT_max', $max);
707
-    }
708
-
709
-
710
-    /**
711
-     * Sets price
712
-     *
713
-     * @param float $price
714
-     * @return void
715
-     * @throws EE_Error
716
-     */
717
-    public function set_price($price)
718
-    {
719
-        $this->set('TKT_price', $price);
720
-    }
721
-
722
-
723
-    /**
724
-     * Gets sold
725
-     *
726
-     * @return int
727
-     * @throws EE_Error
728
-     */
729
-    public function sold()
730
-    {
731
-        return $this->get_raw('TKT_sold');
732
-    }
733
-
734
-
735
-    /**
736
-     * Sets sold
737
-     *
738
-     * @param int $sold
739
-     * @return void
740
-     * @throws EE_Error
741
-     */
742
-    public function set_sold($sold)
743
-    {
744
-        // sold can not go below zero
745
-        $sold = max(0, $sold);
746
-        $this->set('TKT_sold', $sold);
747
-    }
748
-
749
-
750
-    /**
751
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
752
-     * associated datetimes.
753
-     *
754
-     * @since 4.9.80.p
755
-     * @param int $qty
756
-     * @return boolean
757
-     * @throws EE_Error
758
-     * @throws InvalidArgumentException
759
-     * @throws InvalidDataTypeException
760
-     * @throws InvalidInterfaceException
761
-     * @throws ReflectionException
762
-     */
763
-    public function increaseSold($qty = 1)
764
-    {
765
-        $qty = absint($qty);
766
-        // increment sold and decrement reserved datetime quantities simultaneously
767
-        // don't worry about failures, because they must have already had a spot reserved
768
-        $this->increaseSoldForDatetimes($qty);
769
-        // Increment and decrement ticket quantities simultaneously
770
-        $success = $this->adjustNumericFieldsInDb(
771
-            [
772
-                'TKT_reserved' => $qty * -1,
773
-                'TKT_sold' => $qty
774
-            ]
775
-        );
776
-        do_action(
777
-            'AHEE__EE_Ticket__increase_sold',
778
-            $this,
779
-            $qty,
780
-            $this->sold(),
781
-            $success
782
-        );
783
-        return $success;
784
-    }
785
-
786
-    /**
787
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
788
-     *
789
-     * @since 4.9.80.p
790
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
791
-     *             Negative means to decreases old counts (and increase reserved counts).
792
-     * @param EE_Datetime[] $datetimes
793
-     * @throws EE_Error
794
-     * @throws InvalidArgumentException
795
-     * @throws InvalidDataTypeException
796
-     * @throws InvalidInterfaceException
797
-     * @throws ReflectionException
798
-     */
799
-    protected function increaseSoldForDatetimes($qty, array $datetimes = [])
800
-    {
801
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
802
-        foreach ($datetimes as $datetime) {
803
-            $datetime->increaseSold($qty);
804
-        }
805
-    }
806
-
807
-
808
-
809
-    /**
810
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
811
-     * DB and then updates the model objects.
812
-     * Does not affect the reserved counts.
813
-     *
814
-     * @since 4.9.80.p
815
-     * @param int $qty
816
-     * @return boolean
817
-     * @throws EE_Error
818
-     * @throws InvalidArgumentException
819
-     * @throws InvalidDataTypeException
820
-     * @throws InvalidInterfaceException
821
-     * @throws ReflectionException
822
-     */
823
-    public function decreaseSold($qty = 1)
824
-    {
825
-        $qty = absint($qty);
826
-        $this->decreaseSoldForDatetimes($qty);
827
-        $success = $this->adjustNumericFieldsInDb(
828
-            [
829
-                'TKT_sold' => $qty * -1
830
-            ]
831
-        );
832
-        do_action(
833
-            'AHEE__EE_Ticket__decrease_sold',
834
-            $this,
835
-            $qty,
836
-            $this->sold(),
837
-            $success
838
-        );
839
-        return $success;
840
-    }
841
-
842
-
843
-    /**
844
-     * Decreases sold on related datetimes
845
-     *
846
-     * @since 4.9.80.p
847
-     * @param int $qty
848
-     * @param EE_Datetime[] $datetimes
849
-     * @return void
850
-     * @throws EE_Error
851
-     * @throws InvalidArgumentException
852
-     * @throws InvalidDataTypeException
853
-     * @throws InvalidInterfaceException
854
-     * @throws ReflectionException
855
-     */
856
-    protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
857
-    {
858
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
859
-        if (is_array($datetimes)) {
860
-            foreach ($datetimes as $datetime) {
861
-                if ($datetime instanceof EE_Datetime) {
862
-                    $datetime->decreaseSold($qty);
863
-                }
864
-            }
865
-        }
866
-    }
867
-
868
-
869
-    /**
870
-     * Gets qty of reserved tickets
871
-     *
872
-     * @return int
873
-     * @throws EE_Error
874
-     */
875
-    public function reserved()
876
-    {
877
-        return $this->get_raw('TKT_reserved');
878
-    }
879
-
880
-
881
-    /**
882
-     * Sets reserved
883
-     *
884
-     * @param int $reserved
885
-     * @return void
886
-     * @throws EE_Error
887
-     */
888
-    public function set_reserved($reserved)
889
-    {
890
-        // reserved can not go below zero
891
-        $reserved = max(0, (int) $reserved);
892
-        $this->set('TKT_reserved', $reserved);
893
-    }
894
-
895
-
896
-    /**
897
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
898
-     *
899
-     * @since 4.9.80.p
900
-     * @param int    $qty
901
-     * @param string $source
902
-     * @return bool whether we successfully reserved the ticket or not.
903
-     * @throws EE_Error
904
-     * @throws InvalidArgumentException
905
-     * @throws ReflectionException
906
-     * @throws InvalidDataTypeException
907
-     * @throws InvalidInterfaceException
908
-     */
909
-    public function increaseReserved($qty = 1, $source = 'unknown')
910
-    {
911
-        $qty = absint($qty);
912
-        do_action(
913
-            'AHEE__EE_Ticket__increase_reserved__begin',
914
-            $this,
915
-            $qty,
916
-            $source
917
-        );
918
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
919
-        $success = false;
920
-        $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
921
-        if ($datetimes_adjusted_successfully) {
922
-            $success = $this->incrementFieldConditionallyInDb(
923
-                'TKT_reserved',
924
-                'TKT_sold',
925
-                'TKT_qty',
926
-                $qty
927
-            );
928
-            if (! $success) {
929
-                // The datetimes were successfully bumped, but not the
930
-                // ticket. So we need to manually rollback the datetimes.
931
-                $this->decreaseReservedForDatetimes($qty);
932
-            }
933
-        }
934
-        do_action(
935
-            'AHEE__EE_Ticket__increase_reserved',
936
-            $this,
937
-            $qty,
938
-            $this->reserved(),
939
-            $success
940
-        );
941
-        return $success;
942
-    }
943
-
944
-
945
-    /**
946
-     * Increases reserved counts on related datetimes
947
-     *
948
-     * @since 4.9.80.p
949
-     * @param int $qty
950
-     * @param EE_Datetime[] $datetimes
951
-     * @return boolean indicating success
952
-     * @throws EE_Error
953
-     * @throws InvalidArgumentException
954
-     * @throws InvalidDataTypeException
955
-     * @throws InvalidInterfaceException
956
-     * @throws ReflectionException
957
-     */
958
-    protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
959
-    {
960
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
961
-        $datetimes_updated = [];
962
-        $limit_exceeded = false;
963
-        if (is_array($datetimes)) {
964
-            foreach ($datetimes as $datetime) {
965
-                if ($datetime instanceof EE_Datetime) {
966
-                    if ($datetime->increaseReserved($qty)) {
967
-                        $datetimes_updated[] = $datetime;
968
-                    } else {
969
-                        $limit_exceeded = true;
970
-                        break;
971
-                    }
972
-                }
973
-            }
974
-            // If somewhere along the way we detected a datetime whose
975
-            // limit was exceeded, do a manual rollback.
976
-            if ($limit_exceeded) {
977
-                $this->decreaseReservedForDatetimes($qty, $datetimes_updated);
978
-                return false;
979
-            }
980
-        }
981
-        return true;
982
-    }
983
-
984
-
985
-    /**
986
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
987
-     *
988
-     * @since 4.9.80.p
989
-     * @param int    $qty
990
-     * @param bool   $adjust_datetimes
991
-     * @param string $source
992
-     * @return boolean
993
-     * @throws EE_Error
994
-     * @throws InvalidArgumentException
995
-     * @throws ReflectionException
996
-     * @throws InvalidDataTypeException
997
-     * @throws InvalidInterfaceException
998
-     */
999
-    public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1000
-    {
1001
-        $qty = absint($qty);
1002
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1003
-        if ($adjust_datetimes) {
1004
-            $this->decreaseReservedForDatetimes($qty);
1005
-        }
1006
-        $success = $this->adjustNumericFieldsInDb(
1007
-            [
1008
-                'TKT_reserved' => $qty * -1
1009
-            ]
1010
-        );
1011
-        do_action(
1012
-            'AHEE__EE_Ticket__decrease_reserved',
1013
-            $this,
1014
-            $qty,
1015
-            $this->reserved(),
1016
-            $success
1017
-        );
1018
-        return $success;
1019
-    }
1020
-
1021
-
1022
-    /**
1023
-     * Decreases the reserved count on the specified datetimes.
1024
-     *
1025
-     * @since 4.9.80.p
1026
-     * @param int           $qty
1027
-     * @param EE_Datetime[] $datetimes
1028
-     * @throws EE_Error
1029
-     * @throws InvalidArgumentException
1030
-     * @throws ReflectionException
1031
-     * @throws InvalidDataTypeException
1032
-     * @throws InvalidInterfaceException
1033
-     */
1034
-    protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1035
-    {
1036
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1037
-        foreach ($datetimes as $datetime) {
1038
-            if ($datetime instanceof EE_Datetime) {
1039
-                $datetime->decreaseReserved($qty);
1040
-            }
1041
-        }
1042
-    }
1043
-
1044
-
1045
-    /**
1046
-     * Gets ticket quantity
1047
-     *
1048
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1049
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1050
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1051
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1052
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1053
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1054
-     * @return int
1055
-     * @throws EE_Error
1056
-     */
1057
-    public function qty($context = '')
1058
-    {
1059
-        switch ($context) {
1060
-            case 'reg_limit':
1061
-                return $this->real_quantity_on_ticket();
1062
-            case 'saleable':
1063
-                return $this->real_quantity_on_ticket('saleable');
1064
-            default:
1065
-                return $this->get_raw('TKT_qty');
1066
-        }
1067
-    }
1068
-
1069
-
1070
-    /**
1071
-     * Gets ticket quantity
1072
-     *
1073
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1074
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1075
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1076
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1077
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1078
-     * @param  int   $DTT_ID      the primary key for a particular datetime.
1079
-     *                            set to 0 for all related datetimes
1080
-     * @return int
1081
-     * @throws EE_Error
1082
-     */
1083
-    public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1084
-    {
1085
-        $raw = $this->get_raw('TKT_qty');
1086
-        // return immediately if it's zero
1087
-        if ($raw === 0) {
1088
-            return $raw;
1089
-        }
1090
-        // echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1091
-        // ensure qty doesn't exceed raw value for THIS ticket
1092
-        $qty = min(EE_INF, $raw);
1093
-        // echo "\n . qty: " . $qty . '<br />';
1094
-        // calculate this ticket's total sales and reservations
1095
-        $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1096
-        // echo "\n . sold: " . $this->sold() . '<br />';
1097
-        // echo "\n . reserved: " . $this->reserved() . '<br />';
1098
-        // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1099
-        // first we need to calculate the maximum number of tickets available for the datetime
1100
-        // do we want data for one datetime or all of them ?
1101
-        $query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1102
-        $datetimes = $this->datetimes($query_params);
1103
-        if (is_array($datetimes) && ! empty($datetimes)) {
1104
-            foreach ($datetimes as $datetime) {
1105
-                if ($datetime instanceof EE_Datetime) {
1106
-                    $datetime->refresh_from_db();
1107
-                    // echo "\n . . datetime name: " . $datetime->name() . '<br />';
1108
-                    // echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1109
-                    // initialize with no restrictions for each datetime
1110
-                    // but adjust datetime qty based on datetime reg limit
1111
-                    $datetime_qty = min(EE_INF, $datetime->reg_limit());
1112
-                    // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1113
-                    // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1114
-                    // if we want the actual saleable amount, then we need to consider OTHER ticket sales
1115
-                    // and reservations for this datetime, that do NOT include sales and reservations
1116
-                    // for this ticket (so we add $this->sold() and $this->reserved() back in)
1117
-                    if ($context === 'saleable') {
1118
-                        $datetime_qty = max(
1119
-                            $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1120
-                            0
1121
-                        );
1122
-                        // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1123
-                        // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1124
-                        // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1125
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1126
-                        $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1127
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1128
-                    }
1129
-                    $qty = min($datetime_qty, $qty);
1130
-                    // echo "\n . . qty: " . $qty . '<br />';
1131
-                }
1132
-            }
1133
-        }
1134
-        // NOW that we know the  maximum number of tickets available for the datetime
1135
-        // we can finally factor in the details for this specific ticket
1136
-        if ($qty > 0 && $context === 'saleable') {
1137
-            // and subtract the sales for THIS ticket
1138
-            $qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1139
-            // echo "\n . qty: " . $qty . '<br />';
1140
-        }
1141
-        // echo "\nFINAL QTY: " . $qty . "<br /><br />";
1142
-        return $qty;
1143
-    }
1144
-
1145
-
1146
-    /**
1147
-     * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1148
-     *
1149
-     * @param int $qty
1150
-     * @return void
1151
-     * @throws EE_Error
1152
-     */
1153
-    public function set_qty($qty)
1154
-    {
1155
-        $datetimes = $this->datetimes();
1156
-        foreach ($datetimes as $datetime) {
1157
-            if ($datetime instanceof EE_Datetime) {
1158
-                $qty = min($qty, $datetime->reg_limit());
1159
-            }
1160
-        }
1161
-        $this->set('TKT_qty', $qty);
1162
-    }
1163
-
1164
-
1165
-    /**
1166
-     * Gets uses
1167
-     *
1168
-     * @return int
1169
-     * @throws EE_Error
1170
-     */
1171
-    public function uses()
1172
-    {
1173
-        return $this->get('TKT_uses');
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * Sets uses
1179
-     *
1180
-     * @param int $uses
1181
-     * @return void
1182
-     * @throws EE_Error
1183
-     */
1184
-    public function set_uses($uses)
1185
-    {
1186
-        $this->set('TKT_uses', $uses);
1187
-    }
1188
-
1189
-
1190
-    /**
1191
-     * returns whether ticket is required or not.
1192
-     *
1193
-     * @return boolean
1194
-     * @throws EE_Error
1195
-     */
1196
-    public function required()
1197
-    {
1198
-        return $this->get('TKT_required');
1199
-    }
1200
-
1201
-
1202
-    /**
1203
-     * sets the TKT_required property
1204
-     *
1205
-     * @param boolean $required
1206
-     * @return void
1207
-     * @throws EE_Error
1208
-     */
1209
-    public function set_required($required)
1210
-    {
1211
-        $this->set('TKT_required', $required);
1212
-    }
1213
-
1214
-
1215
-    /**
1216
-     * Gets taxable
1217
-     *
1218
-     * @return boolean
1219
-     * @throws EE_Error
1220
-     */
1221
-    public function taxable()
1222
-    {
1223
-        return $this->get('TKT_taxable');
1224
-    }
1225
-
1226
-
1227
-    /**
1228
-     * Sets taxable
1229
-     *
1230
-     * @param boolean $taxable
1231
-     * @return void
1232
-     * @throws EE_Error
1233
-     */
1234
-    public function set_taxable($taxable)
1235
-    {
1236
-        $this->set('TKT_taxable', $taxable);
1237
-    }
1238
-
1239
-
1240
-    /**
1241
-     * Gets is_default
1242
-     *
1243
-     * @return boolean
1244
-     * @throws EE_Error
1245
-     */
1246
-    public function is_default()
1247
-    {
1248
-        return $this->get('TKT_is_default');
1249
-    }
1250
-
1251
-
1252
-    /**
1253
-     * Sets is_default
1254
-     *
1255
-     * @param boolean $is_default
1256
-     * @return void
1257
-     * @throws EE_Error
1258
-     */
1259
-    public function set_is_default($is_default)
1260
-    {
1261
-        $this->set('TKT_is_default', $is_default);
1262
-    }
1263
-
1264
-
1265
-    /**
1266
-     * Gets order
1267
-     *
1268
-     * @return int
1269
-     * @throws EE_Error
1270
-     */
1271
-    public function order()
1272
-    {
1273
-        return $this->get('TKT_order');
1274
-    }
1275
-
1276
-
1277
-    /**
1278
-     * Sets order
1279
-     *
1280
-     * @param int $order
1281
-     * @return void
1282
-     * @throws EE_Error
1283
-     */
1284
-    public function set_order($order)
1285
-    {
1286
-        $this->set('TKT_order', $order);
1287
-    }
1288
-
1289
-
1290
-    /**
1291
-     * Gets row
1292
-     *
1293
-     * @return int
1294
-     * @throws EE_Error
1295
-     */
1296
-    public function row()
1297
-    {
1298
-        return $this->get('TKT_row');
1299
-    }
1300
-
1301
-
1302
-    /**
1303
-     * Sets row
1304
-     *
1305
-     * @param int $row
1306
-     * @return void
1307
-     * @throws EE_Error
1308
-     */
1309
-    public function set_row($row)
1310
-    {
1311
-        $this->set('TKT_row', $row);
1312
-    }
1313
-
1314
-
1315
-    /**
1316
-     * Gets deleted
1317
-     *
1318
-     * @return boolean
1319
-     * @throws EE_Error
1320
-     */
1321
-    public function deleted()
1322
-    {
1323
-        return $this->get('TKT_deleted');
1324
-    }
1325
-
1326
-
1327
-    /**
1328
-     * Sets deleted
1329
-     *
1330
-     * @param boolean $deleted
1331
-     * @return void
1332
-     * @throws EE_Error
1333
-     */
1334
-    public function set_deleted($deleted)
1335
-    {
1336
-        $this->set('TKT_deleted', $deleted);
1337
-    }
1338
-
1339
-
1340
-    /**
1341
-     * Gets parent
1342
-     *
1343
-     * @return int
1344
-     * @throws EE_Error
1345
-     */
1346
-    public function parent_ID()
1347
-    {
1348
-        return $this->get('TKT_parent');
1349
-    }
1350
-
1351
-
1352
-    /**
1353
-     * Sets parent
1354
-     *
1355
-     * @param int $parent
1356
-     * @return void
1357
-     * @throws EE_Error
1358
-     */
1359
-    public function set_parent_ID($parent)
1360
-    {
1361
-        $this->set('TKT_parent', $parent);
1362
-    }
1363
-
1364
-
1365
-    /**
1366
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1367
-     *
1368
-     * @return string
1369
-     * @throws EE_Error
1370
-     */
1371
-    public function name_and_info()
1372
-    {
1373
-        $times = array();
1374
-        foreach ($this->datetimes() as $datetime) {
1375
-            $times[] = $datetime->start_date_and_time();
1376
-        }
1377
-        return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1378
-    }
1379
-
1380
-
1381
-    /**
1382
-     * Gets name
1383
-     *
1384
-     * @return string
1385
-     * @throws EE_Error
1386
-     */
1387
-    public function name()
1388
-    {
1389
-        return $this->get('TKT_name');
1390
-    }
1391
-
1392
-
1393
-    /**
1394
-     * Gets price
1395
-     *
1396
-     * @return float
1397
-     * @throws EE_Error
1398
-     */
1399
-    public function price()
1400
-    {
1401
-        return $this->get('TKT_price');
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * Gets all the registrations for this ticket
1407
-     *
1408
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1409
-     * @return EE_Registration[]|EE_Base_Class[]
1410
-     * @throws EE_Error
1411
-     */
1412
-    public function registrations($query_params = array())
1413
-    {
1414
-        return $this->get_many_related('Registration', $query_params);
1415
-    }
1416
-
1417
-
1418
-    /**
1419
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1420
-     *
1421
-     * @return int
1422
-     * @throws EE_Error
1423
-     */
1424
-    public function update_tickets_sold()
1425
-    {
1426
-        $count_regs_for_this_ticket = $this->count_registrations(
1427
-            array(
1428
-                array(
1429
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1430
-                    'REG_deleted' => 0,
1431
-                ),
1432
-            )
1433
-        );
1434
-        $this->set_sold($count_regs_for_this_ticket);
1435
-        $this->save();
1436
-        return $count_regs_for_this_ticket;
1437
-    }
1438
-
1439
-
1440
-    /**
1441
-     * Counts the registrations for this ticket
1442
-     *
1443
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1444
-     * @return int
1445
-     */
1446
-    public function count_registrations($query_params = array())
1447
-    {
1448
-        return $this->count_related('Registration', $query_params);
1449
-    }
1450
-
1451
-
1452
-    /**
1453
-     * Implementation for EEI_Has_Icon interface method.
1454
-     *
1455
-     * @see EEI_Visual_Representation for comments
1456
-     * @return string
1457
-     */
1458
-    public function get_icon()
1459
-    {
1460
-        return '<span class="dashicons dashicons-tickets-alt"></span>';
1461
-    }
1462
-
1463
-
1464
-    /**
1465
-     * Implementation of the EEI_Event_Relation interface method
1466
-     *
1467
-     * @see EEI_Event_Relation for comments
1468
-     * @return EE_Event
1469
-     * @throws EE_Error
1470
-     * @throws UnexpectedEntityException
1471
-     */
1472
-    public function get_related_event()
1473
-    {
1474
-        // get one datetime to use for getting the event
1475
-        $datetime = $this->first_datetime();
1476
-        if (! $datetime instanceof \EE_Datetime) {
1477
-            throw new UnexpectedEntityException(
1478
-                $datetime,
1479
-                'EE_Datetime',
1480
-                sprintf(
1481
-                    esc_html__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1482
-                    $this->name()
1483
-                )
1484
-            );
1485
-        }
1486
-        $event = $datetime->event();
1487
-        if (! $event instanceof \EE_Event) {
1488
-            throw new UnexpectedEntityException(
1489
-                $event,
1490
-                'EE_Event',
1491
-                sprintf(
1492
-                    esc_html__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1493
-                    $this->name()
1494
-                )
1495
-            );
1496
-        }
1497
-        return $event;
1498
-    }
1499
-
1500
-
1501
-    /**
1502
-     * Implementation of the EEI_Event_Relation interface method
1503
-     *
1504
-     * @see EEI_Event_Relation for comments
1505
-     * @return string
1506
-     * @throws UnexpectedEntityException
1507
-     * @throws EE_Error
1508
-     */
1509
-    public function get_event_name()
1510
-    {
1511
-        $event = $this->get_related_event();
1512
-        return $event instanceof EE_Event ? $event->name() : '';
1513
-    }
1514
-
1515
-
1516
-    /**
1517
-     * Implementation of the EEI_Event_Relation interface method
1518
-     *
1519
-     * @see EEI_Event_Relation for comments
1520
-     * @return int
1521
-     * @throws UnexpectedEntityException
1522
-     * @throws EE_Error
1523
-     */
1524
-    public function get_event_ID()
1525
-    {
1526
-        $event = $this->get_related_event();
1527
-        return $event instanceof EE_Event ? $event->ID() : 0;
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * This simply returns whether a ticket can be permanently deleted or not.
1533
-     * The criteria for determining this is whether the ticket has any related registrations.
1534
-     * If there are none then it can be permanently deleted.
1535
-     *
1536
-     * @return bool
1537
-     */
1538
-    public function is_permanently_deleteable()
1539
-    {
1540
-        return $this->count_registrations() === 0;
1541
-    }
1542
-
1543
-
1544
-    /*******************************************************************
17
+	/**
18
+	 * The following constants are used by the ticket_status() method to indicate whether a ticket is on sale or not.
19
+	 */
20
+	const sold_out = 'TKS';
21
+
22
+	/**
23
+	 *
24
+	 */
25
+	const expired = 'TKE';
26
+
27
+	/**
28
+	 *
29
+	 */
30
+	const archived = 'TKA';
31
+
32
+	/**
33
+	 *
34
+	 */
35
+	const pending = 'TKP';
36
+
37
+	/**
38
+	 *
39
+	 */
40
+	const onsale = 'TKO';
41
+
42
+	/**
43
+	 * extra meta key for tracking ticket reservations
44
+	 *
45
+	 * @type string
46
+	 */
47
+	const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
48
+
49
+	/**
50
+	 * cached result from method of the same name
51
+	 *
52
+	 * @var float $_ticket_total_with_taxes
53
+	 */
54
+	private $_ticket_total_with_taxes;
55
+
56
+
57
+	/**
58
+	 * @param array  $props_n_values          incoming values
59
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
60
+	 *                                        used.)
61
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
62
+	 *                                        date_format and the second value is the time format
63
+	 * @return EE_Ticket
64
+	 * @throws EE_Error
65
+	 */
66
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
67
+	{
68
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
69
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
70
+	}
71
+
72
+
73
+	/**
74
+	 * @param array  $props_n_values  incoming values from the database
75
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
76
+	 *                                the website will be used.
77
+	 * @return EE_Ticket
78
+	 * @throws EE_Error
79
+	 */
80
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
81
+	{
82
+		return new self($props_n_values, true, $timezone);
83
+	}
84
+
85
+
86
+	/**
87
+	 * @return bool
88
+	 * @throws EE_Error
89
+	 */
90
+	public function parent()
91
+	{
92
+		return $this->get('TKT_parent');
93
+	}
94
+
95
+
96
+	/**
97
+	 * return if a ticket has quantities available for purchase
98
+	 *
99
+	 * @param  int $DTT_ID the primary key for a particular datetime
100
+	 * @return boolean
101
+	 * @throws EE_Error
102
+	 */
103
+	public function available($DTT_ID = 0)
104
+	{
105
+		// are we checking availability for a particular datetime ?
106
+		if ($DTT_ID) {
107
+			// get that datetime object
108
+			$datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
109
+			// if  ticket sales for this datetime have exceeded the reg limit...
110
+			if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
111
+				return false;
112
+			}
113
+		}
114
+		// datetime is still open for registration, but is this ticket sold out ?
115
+		return $this->qty() < 1 || $this->qty() > $this->sold() ? true : false;
116
+	}
117
+
118
+
119
+	/**
120
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
121
+	 *
122
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
123
+	 *                               relevant status const
124
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
125
+	 *               further processing
126
+	 * @return mixed status int if the display string isn't requested
127
+	 * @throws EE_Error
128
+	 */
129
+	public function ticket_status($display = false, $remaining = null)
130
+	{
131
+		$remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
132
+		if (! $remaining) {
133
+			return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
134
+		}
135
+		if ($this->get('TKT_deleted')) {
136
+			return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
137
+		}
138
+		if ($this->is_expired()) {
139
+			return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
140
+		}
141
+		if ($this->is_pending()) {
142
+			return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
143
+		}
144
+		if ($this->is_on_sale()) {
145
+			return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
146
+		}
147
+		return '';
148
+	}
149
+
150
+
151
+	/**
152
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
153
+	 * considering ALL the factors used for figuring that out.
154
+	 *
155
+	 * @access public
156
+	 * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
157
+	 * @return boolean         true = tickets remaining, false not.
158
+	 * @throws EE_Error
159
+	 */
160
+	public function is_remaining($DTT_ID = 0)
161
+	{
162
+		$num_remaining = $this->remaining($DTT_ID);
163
+		if ($num_remaining === 0) {
164
+			return false;
165
+		}
166
+		if ($num_remaining > 0 && $num_remaining < $this->min()) {
167
+			return false;
168
+		}
169
+		return true;
170
+	}
171
+
172
+
173
+	/**
174
+	 * return the total number of tickets available for purchase
175
+	 *
176
+	 * @param  int $DTT_ID the primary key for a particular datetime.
177
+	 *                     set to 0 for all related datetimes
178
+	 * @return int
179
+	 * @throws EE_Error
180
+	 */
181
+	public function remaining($DTT_ID = 0)
182
+	{
183
+		return $this->real_quantity_on_ticket('saleable', $DTT_ID);
184
+	}
185
+
186
+
187
+	/**
188
+	 * Gets min
189
+	 *
190
+	 * @return int
191
+	 * @throws EE_Error
192
+	 */
193
+	public function min()
194
+	{
195
+		return $this->get('TKT_min');
196
+	}
197
+
198
+
199
+	/**
200
+	 * return if a ticket is no longer available cause its available dates have expired.
201
+	 *
202
+	 * @return boolean
203
+	 * @throws EE_Error
204
+	 */
205
+	public function is_expired()
206
+	{
207
+		return ($this->get_raw('TKT_end_date') < time());
208
+	}
209
+
210
+
211
+	/**
212
+	 * Return if a ticket is yet to go on sale or not
213
+	 *
214
+	 * @return boolean
215
+	 * @throws EE_Error
216
+	 */
217
+	public function is_pending()
218
+	{
219
+		return ($this->get_raw('TKT_start_date') > time());
220
+	}
221
+
222
+
223
+	/**
224
+	 * Return if a ticket is on sale or not
225
+	 *
226
+	 * @return boolean
227
+	 * @throws EE_Error
228
+	 */
229
+	public function is_on_sale()
230
+	{
231
+		return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
232
+	}
233
+
234
+
235
+	/**
236
+	 * This returns the chronologically last datetime that this ticket is associated with
237
+	 *
238
+	 * @param string $dt_frmt
239
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
240
+	 *                            the end date ie: Jan 01 "to" Dec 31
241
+	 * @return string
242
+	 * @throws EE_Error
243
+	 */
244
+	public function date_range($dt_frmt = '', $conjunction = ' - ')
245
+	{
246
+		$dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
247
+		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
248
+			: '';
249
+		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
250
+
251
+		return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
252
+	}
253
+
254
+
255
+	/**
256
+	 * This returns the chronologically first datetime that this ticket is associated with
257
+	 *
258
+	 * @return EE_Datetime
259
+	 * @throws EE_Error
260
+	 */
261
+	public function first_datetime()
262
+	{
263
+		$datetimes = $this->datetimes(array('limit' => 1));
264
+		return reset($datetimes);
265
+	}
266
+
267
+
268
+	/**
269
+	 * Gets all the datetimes this ticket can be used for attending.
270
+	 * Unless otherwise specified, orders datetimes by start date.
271
+	 *
272
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
273
+	 * @return EE_Datetime[]|EE_Base_Class[]
274
+	 * @throws EE_Error
275
+	 */
276
+	public function datetimes($query_params = array())
277
+	{
278
+		if (! isset($query_params['order_by'])) {
279
+			$query_params['order_by']['DTT_order'] = 'ASC';
280
+		}
281
+		return $this->get_many_related('Datetime', $query_params);
282
+	}
283
+
284
+
285
+	/**
286
+	 * This returns the chronologically last datetime that this ticket is associated with
287
+	 *
288
+	 * @return EE_Datetime
289
+	 * @throws EE_Error
290
+	 */
291
+	public function last_datetime()
292
+	{
293
+		$datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
294
+		return end($datetimes);
295
+	}
296
+
297
+
298
+	/**
299
+	 * This returns the total tickets sold depending on the given parameters.
300
+	 *
301
+	 * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
302
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
303
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
304
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
305
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
306
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
307
+	 * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
308
+	 * @return mixed (array|int)          how many tickets have sold
309
+	 * @throws EE_Error
310
+	 */
311
+	public function tickets_sold($what = 'ticket', $dtt_id = null)
312
+	{
313
+		$total = 0;
314
+		$tickets_sold = $this->_all_tickets_sold();
315
+		switch ($what) {
316
+			case 'ticket':
317
+				return $tickets_sold['ticket'];
318
+				break;
319
+			case 'datetime':
320
+				if (empty($tickets_sold['datetime'])) {
321
+					return $total;
322
+				}
323
+				if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
324
+					EE_Error::add_error(
325
+						esc_html__(
326
+							'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
327
+							'event_espresso'
328
+						),
329
+						__FILE__,
330
+						__FUNCTION__,
331
+						__LINE__
332
+					);
333
+					return $total;
334
+				}
335
+				return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
336
+				break;
337
+			default:
338
+				return $total;
339
+		}
340
+	}
341
+
342
+
343
+	/**
344
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
345
+	 *
346
+	 * @return EE_Ticket[]
347
+	 * @throws EE_Error
348
+	 */
349
+	protected function _all_tickets_sold()
350
+	{
351
+		$datetimes = $this->get_many_related('Datetime');
352
+		$tickets_sold = array();
353
+		if (! empty($datetimes)) {
354
+			foreach ($datetimes as $datetime) {
355
+				$tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
356
+			}
357
+		}
358
+		// Tickets sold
359
+		$tickets_sold['ticket'] = $this->sold();
360
+		return $tickets_sold;
361
+	}
362
+
363
+
364
+	/**
365
+	 * This returns the base price object for the ticket.
366
+	 *
367
+	 * @param  bool $return_array whether to return as an array indexed by price id or just the object.
368
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
369
+	 * @throws EE_Error
370
+	 */
371
+	public function base_price($return_array = false)
372
+	{
373
+		$_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
374
+		return $return_array
375
+			? $this->get_many_related('Price', array($_where))
376
+			: $this->get_first_related('Price', array($_where));
377
+	}
378
+
379
+
380
+	/**
381
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
382
+	 *
383
+	 * @access public
384
+	 * @return EE_Price[]
385
+	 * @throws EE_Error
386
+	 */
387
+	public function price_modifiers()
388
+	{
389
+		$query_params = array(
390
+			0 => array(
391
+				'Price_Type.PBT_ID' => array(
392
+					'NOT IN',
393
+					array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax),
394
+				),
395
+			),
396
+		);
397
+		return $this->prices($query_params);
398
+	}
399
+
400
+
401
+	/**
402
+	 * Gets all the prices that combine to form the final price of this ticket
403
+	 *
404
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
405
+	 * @return EE_Price[]|EE_Base_Class[]
406
+	 * @throws EE_Error
407
+	 */
408
+	public function prices($query_params = array())
409
+	{
410
+		return $this->get_many_related('Price', $query_params);
411
+	}
412
+
413
+
414
+	/**
415
+	 * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
416
+	 *
417
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
418
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
419
+	 * @throws EE_Error
420
+	 */
421
+	public function datetime_tickets($query_params = array())
422
+	{
423
+		return $this->get_many_related('Datetime_Ticket', $query_params);
424
+	}
425
+
426
+
427
+	/**
428
+	 * Gets all the datetimes from the db ordered by DTT_order
429
+	 *
430
+	 * @param boolean $show_expired
431
+	 * @param boolean $show_deleted
432
+	 * @return EE_Datetime[]
433
+	 * @throws EE_Error
434
+	 */
435
+	public function datetimes_ordered($show_expired = true, $show_deleted = false)
436
+	{
437
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
438
+			$this->ID(),
439
+			$show_expired,
440
+			$show_deleted
441
+		);
442
+	}
443
+
444
+
445
+	/**
446
+	 * Gets ID
447
+	 *
448
+	 * @return string
449
+	 * @throws EE_Error
450
+	 */
451
+	public function ID()
452
+	{
453
+		return $this->get('TKT_ID');
454
+	}
455
+
456
+
457
+	/**
458
+	 * get the author of the ticket.
459
+	 *
460
+	 * @since 4.5.0
461
+	 * @return int
462
+	 * @throws EE_Error
463
+	 */
464
+	public function wp_user()
465
+	{
466
+		return $this->get('TKT_wp_user');
467
+	}
468
+
469
+
470
+	/**
471
+	 * Gets the template for the ticket
472
+	 *
473
+	 * @return EE_Ticket_Template|EE_Base_Class
474
+	 * @throws EE_Error
475
+	 */
476
+	public function template()
477
+	{
478
+		return $this->get_first_related('Ticket_Template');
479
+	}
480
+
481
+
482
+	/**
483
+	 * Simply returns an array of EE_Price objects that are taxes.
484
+	 *
485
+	 * @return EE_Price[]
486
+	 * @throws EE_Error
487
+	 */
488
+	public function get_ticket_taxes_for_admin()
489
+	{
490
+		return EE_Taxes::get_taxes_for_admin();
491
+	}
492
+
493
+
494
+	/**
495
+	 * @return float
496
+	 * @throws EE_Error
497
+	 */
498
+	public function ticket_price()
499
+	{
500
+		return $this->get('TKT_price');
501
+	}
502
+
503
+
504
+	/**
505
+	 * @return mixed
506
+	 * @throws EE_Error
507
+	 */
508
+	public function pretty_price()
509
+	{
510
+		return $this->get_pretty('TKT_price');
511
+	}
512
+
513
+
514
+	/**
515
+	 * @return bool
516
+	 * @throws EE_Error
517
+	 */
518
+	public function is_free()
519
+	{
520
+		return $this->get_ticket_total_with_taxes() === (float) 0;
521
+	}
522
+
523
+
524
+	/**
525
+	 * get_ticket_total_with_taxes
526
+	 *
527
+	 * @param bool $no_cache
528
+	 * @return float
529
+	 * @throws EE_Error
530
+	 */
531
+	public function get_ticket_total_with_taxes($no_cache = false)
532
+	{
533
+		if ($this->_ticket_total_with_taxes === null || $no_cache) {
534
+			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
535
+		}
536
+		return (float) $this->_ticket_total_with_taxes;
537
+	}
538
+
539
+
540
+	public function ensure_TKT_Price_correct()
541
+	{
542
+		$this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
543
+		$this->save();
544
+	}
545
+
546
+
547
+	/**
548
+	 * @return float
549
+	 * @throws EE_Error
550
+	 */
551
+	public function get_ticket_subtotal()
552
+	{
553
+		return EE_Taxes::get_subtotal_for_admin($this);
554
+	}
555
+
556
+
557
+	/**
558
+	 * Returns the total taxes applied to this ticket
559
+	 *
560
+	 * @return float
561
+	 * @throws EE_Error
562
+	 */
563
+	public function get_ticket_taxes_total_for_admin()
564
+	{
565
+		return EE_Taxes::get_total_taxes_for_admin($this);
566
+	}
567
+
568
+
569
+	/**
570
+	 * Sets name
571
+	 *
572
+	 * @param string $name
573
+	 * @throws EE_Error
574
+	 */
575
+	public function set_name($name)
576
+	{
577
+		$this->set('TKT_name', $name);
578
+	}
579
+
580
+
581
+	/**
582
+	 * Gets description
583
+	 *
584
+	 * @return string
585
+	 * @throws EE_Error
586
+	 */
587
+	public function description()
588
+	{
589
+		return $this->get('TKT_description');
590
+	}
591
+
592
+
593
+	/**
594
+	 * Sets description
595
+	 *
596
+	 * @param string $description
597
+	 * @throws EE_Error
598
+	 */
599
+	public function set_description($description)
600
+	{
601
+		$this->set('TKT_description', $description);
602
+	}
603
+
604
+
605
+	/**
606
+	 * Gets start_date
607
+	 *
608
+	 * @param string $dt_frmt
609
+	 * @param string $tm_frmt
610
+	 * @return string
611
+	 * @throws EE_Error
612
+	 */
613
+	public function start_date($dt_frmt = '', $tm_frmt = '')
614
+	{
615
+		return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
616
+	}
617
+
618
+
619
+	/**
620
+	 * Sets start_date
621
+	 *
622
+	 * @param string $start_date
623
+	 * @return void
624
+	 * @throws EE_Error
625
+	 */
626
+	public function set_start_date($start_date)
627
+	{
628
+		$this->_set_date_time('B', $start_date, 'TKT_start_date');
629
+	}
630
+
631
+
632
+	/**
633
+	 * Gets end_date
634
+	 *
635
+	 * @param string $dt_frmt
636
+	 * @param string $tm_frmt
637
+	 * @return string
638
+	 * @throws EE_Error
639
+	 */
640
+	public function end_date($dt_frmt = '', $tm_frmt = '')
641
+	{
642
+		return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
643
+	}
644
+
645
+
646
+	/**
647
+	 * Sets end_date
648
+	 *
649
+	 * @param string $end_date
650
+	 * @return void
651
+	 * @throws EE_Error
652
+	 */
653
+	public function set_end_date($end_date)
654
+	{
655
+		$this->_set_date_time('B', $end_date, 'TKT_end_date');
656
+	}
657
+
658
+
659
+	/**
660
+	 * Sets sell until time
661
+	 *
662
+	 * @since 4.5.0
663
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
664
+	 * @throws EE_Error
665
+	 */
666
+	public function set_end_time($time)
667
+	{
668
+		$this->_set_time_for($time, 'TKT_end_date');
669
+	}
670
+
671
+
672
+	/**
673
+	 * Sets min
674
+	 *
675
+	 * @param int $min
676
+	 * @return void
677
+	 * @throws EE_Error
678
+	 */
679
+	public function set_min($min)
680
+	{
681
+		$this->set('TKT_min', $min);
682
+	}
683
+
684
+
685
+	/**
686
+	 * Gets max
687
+	 *
688
+	 * @return int
689
+	 * @throws EE_Error
690
+	 */
691
+	public function max()
692
+	{
693
+		return $this->get('TKT_max');
694
+	}
695
+
696
+
697
+	/**
698
+	 * Sets max
699
+	 *
700
+	 * @param int $max
701
+	 * @return void
702
+	 * @throws EE_Error
703
+	 */
704
+	public function set_max($max)
705
+	{
706
+		$this->set('TKT_max', $max);
707
+	}
708
+
709
+
710
+	/**
711
+	 * Sets price
712
+	 *
713
+	 * @param float $price
714
+	 * @return void
715
+	 * @throws EE_Error
716
+	 */
717
+	public function set_price($price)
718
+	{
719
+		$this->set('TKT_price', $price);
720
+	}
721
+
722
+
723
+	/**
724
+	 * Gets sold
725
+	 *
726
+	 * @return int
727
+	 * @throws EE_Error
728
+	 */
729
+	public function sold()
730
+	{
731
+		return $this->get_raw('TKT_sold');
732
+	}
733
+
734
+
735
+	/**
736
+	 * Sets sold
737
+	 *
738
+	 * @param int $sold
739
+	 * @return void
740
+	 * @throws EE_Error
741
+	 */
742
+	public function set_sold($sold)
743
+	{
744
+		// sold can not go below zero
745
+		$sold = max(0, $sold);
746
+		$this->set('TKT_sold', $sold);
747
+	}
748
+
749
+
750
+	/**
751
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
752
+	 * associated datetimes.
753
+	 *
754
+	 * @since 4.9.80.p
755
+	 * @param int $qty
756
+	 * @return boolean
757
+	 * @throws EE_Error
758
+	 * @throws InvalidArgumentException
759
+	 * @throws InvalidDataTypeException
760
+	 * @throws InvalidInterfaceException
761
+	 * @throws ReflectionException
762
+	 */
763
+	public function increaseSold($qty = 1)
764
+	{
765
+		$qty = absint($qty);
766
+		// increment sold and decrement reserved datetime quantities simultaneously
767
+		// don't worry about failures, because they must have already had a spot reserved
768
+		$this->increaseSoldForDatetimes($qty);
769
+		// Increment and decrement ticket quantities simultaneously
770
+		$success = $this->adjustNumericFieldsInDb(
771
+			[
772
+				'TKT_reserved' => $qty * -1,
773
+				'TKT_sold' => $qty
774
+			]
775
+		);
776
+		do_action(
777
+			'AHEE__EE_Ticket__increase_sold',
778
+			$this,
779
+			$qty,
780
+			$this->sold(),
781
+			$success
782
+		);
783
+		return $success;
784
+	}
785
+
786
+	/**
787
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
788
+	 *
789
+	 * @since 4.9.80.p
790
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
791
+	 *             Negative means to decreases old counts (and increase reserved counts).
792
+	 * @param EE_Datetime[] $datetimes
793
+	 * @throws EE_Error
794
+	 * @throws InvalidArgumentException
795
+	 * @throws InvalidDataTypeException
796
+	 * @throws InvalidInterfaceException
797
+	 * @throws ReflectionException
798
+	 */
799
+	protected function increaseSoldForDatetimes($qty, array $datetimes = [])
800
+	{
801
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
802
+		foreach ($datetimes as $datetime) {
803
+			$datetime->increaseSold($qty);
804
+		}
805
+	}
806
+
807
+
808
+
809
+	/**
810
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
811
+	 * DB and then updates the model objects.
812
+	 * Does not affect the reserved counts.
813
+	 *
814
+	 * @since 4.9.80.p
815
+	 * @param int $qty
816
+	 * @return boolean
817
+	 * @throws EE_Error
818
+	 * @throws InvalidArgumentException
819
+	 * @throws InvalidDataTypeException
820
+	 * @throws InvalidInterfaceException
821
+	 * @throws ReflectionException
822
+	 */
823
+	public function decreaseSold($qty = 1)
824
+	{
825
+		$qty = absint($qty);
826
+		$this->decreaseSoldForDatetimes($qty);
827
+		$success = $this->adjustNumericFieldsInDb(
828
+			[
829
+				'TKT_sold' => $qty * -1
830
+			]
831
+		);
832
+		do_action(
833
+			'AHEE__EE_Ticket__decrease_sold',
834
+			$this,
835
+			$qty,
836
+			$this->sold(),
837
+			$success
838
+		);
839
+		return $success;
840
+	}
841
+
842
+
843
+	/**
844
+	 * Decreases sold on related datetimes
845
+	 *
846
+	 * @since 4.9.80.p
847
+	 * @param int $qty
848
+	 * @param EE_Datetime[] $datetimes
849
+	 * @return void
850
+	 * @throws EE_Error
851
+	 * @throws InvalidArgumentException
852
+	 * @throws InvalidDataTypeException
853
+	 * @throws InvalidInterfaceException
854
+	 * @throws ReflectionException
855
+	 */
856
+	protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
857
+	{
858
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
859
+		if (is_array($datetimes)) {
860
+			foreach ($datetimes as $datetime) {
861
+				if ($datetime instanceof EE_Datetime) {
862
+					$datetime->decreaseSold($qty);
863
+				}
864
+			}
865
+		}
866
+	}
867
+
868
+
869
+	/**
870
+	 * Gets qty of reserved tickets
871
+	 *
872
+	 * @return int
873
+	 * @throws EE_Error
874
+	 */
875
+	public function reserved()
876
+	{
877
+		return $this->get_raw('TKT_reserved');
878
+	}
879
+
880
+
881
+	/**
882
+	 * Sets reserved
883
+	 *
884
+	 * @param int $reserved
885
+	 * @return void
886
+	 * @throws EE_Error
887
+	 */
888
+	public function set_reserved($reserved)
889
+	{
890
+		// reserved can not go below zero
891
+		$reserved = max(0, (int) $reserved);
892
+		$this->set('TKT_reserved', $reserved);
893
+	}
894
+
895
+
896
+	/**
897
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
898
+	 *
899
+	 * @since 4.9.80.p
900
+	 * @param int    $qty
901
+	 * @param string $source
902
+	 * @return bool whether we successfully reserved the ticket or not.
903
+	 * @throws EE_Error
904
+	 * @throws InvalidArgumentException
905
+	 * @throws ReflectionException
906
+	 * @throws InvalidDataTypeException
907
+	 * @throws InvalidInterfaceException
908
+	 */
909
+	public function increaseReserved($qty = 1, $source = 'unknown')
910
+	{
911
+		$qty = absint($qty);
912
+		do_action(
913
+			'AHEE__EE_Ticket__increase_reserved__begin',
914
+			$this,
915
+			$qty,
916
+			$source
917
+		);
918
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
919
+		$success = false;
920
+		$datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
921
+		if ($datetimes_adjusted_successfully) {
922
+			$success = $this->incrementFieldConditionallyInDb(
923
+				'TKT_reserved',
924
+				'TKT_sold',
925
+				'TKT_qty',
926
+				$qty
927
+			);
928
+			if (! $success) {
929
+				// The datetimes were successfully bumped, but not the
930
+				// ticket. So we need to manually rollback the datetimes.
931
+				$this->decreaseReservedForDatetimes($qty);
932
+			}
933
+		}
934
+		do_action(
935
+			'AHEE__EE_Ticket__increase_reserved',
936
+			$this,
937
+			$qty,
938
+			$this->reserved(),
939
+			$success
940
+		);
941
+		return $success;
942
+	}
943
+
944
+
945
+	/**
946
+	 * Increases reserved counts on related datetimes
947
+	 *
948
+	 * @since 4.9.80.p
949
+	 * @param int $qty
950
+	 * @param EE_Datetime[] $datetimes
951
+	 * @return boolean indicating success
952
+	 * @throws EE_Error
953
+	 * @throws InvalidArgumentException
954
+	 * @throws InvalidDataTypeException
955
+	 * @throws InvalidInterfaceException
956
+	 * @throws ReflectionException
957
+	 */
958
+	protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
959
+	{
960
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
961
+		$datetimes_updated = [];
962
+		$limit_exceeded = false;
963
+		if (is_array($datetimes)) {
964
+			foreach ($datetimes as $datetime) {
965
+				if ($datetime instanceof EE_Datetime) {
966
+					if ($datetime->increaseReserved($qty)) {
967
+						$datetimes_updated[] = $datetime;
968
+					} else {
969
+						$limit_exceeded = true;
970
+						break;
971
+					}
972
+				}
973
+			}
974
+			// If somewhere along the way we detected a datetime whose
975
+			// limit was exceeded, do a manual rollback.
976
+			if ($limit_exceeded) {
977
+				$this->decreaseReservedForDatetimes($qty, $datetimes_updated);
978
+				return false;
979
+			}
980
+		}
981
+		return true;
982
+	}
983
+
984
+
985
+	/**
986
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
987
+	 *
988
+	 * @since 4.9.80.p
989
+	 * @param int    $qty
990
+	 * @param bool   $adjust_datetimes
991
+	 * @param string $source
992
+	 * @return boolean
993
+	 * @throws EE_Error
994
+	 * @throws InvalidArgumentException
995
+	 * @throws ReflectionException
996
+	 * @throws InvalidDataTypeException
997
+	 * @throws InvalidInterfaceException
998
+	 */
999
+	public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1000
+	{
1001
+		$qty = absint($qty);
1002
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1003
+		if ($adjust_datetimes) {
1004
+			$this->decreaseReservedForDatetimes($qty);
1005
+		}
1006
+		$success = $this->adjustNumericFieldsInDb(
1007
+			[
1008
+				'TKT_reserved' => $qty * -1
1009
+			]
1010
+		);
1011
+		do_action(
1012
+			'AHEE__EE_Ticket__decrease_reserved',
1013
+			$this,
1014
+			$qty,
1015
+			$this->reserved(),
1016
+			$success
1017
+		);
1018
+		return $success;
1019
+	}
1020
+
1021
+
1022
+	/**
1023
+	 * Decreases the reserved count on the specified datetimes.
1024
+	 *
1025
+	 * @since 4.9.80.p
1026
+	 * @param int           $qty
1027
+	 * @param EE_Datetime[] $datetimes
1028
+	 * @throws EE_Error
1029
+	 * @throws InvalidArgumentException
1030
+	 * @throws ReflectionException
1031
+	 * @throws InvalidDataTypeException
1032
+	 * @throws InvalidInterfaceException
1033
+	 */
1034
+	protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1035
+	{
1036
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1037
+		foreach ($datetimes as $datetime) {
1038
+			if ($datetime instanceof EE_Datetime) {
1039
+				$datetime->decreaseReserved($qty);
1040
+			}
1041
+		}
1042
+	}
1043
+
1044
+
1045
+	/**
1046
+	 * Gets ticket quantity
1047
+	 *
1048
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1049
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1050
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1051
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1052
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1053
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1054
+	 * @return int
1055
+	 * @throws EE_Error
1056
+	 */
1057
+	public function qty($context = '')
1058
+	{
1059
+		switch ($context) {
1060
+			case 'reg_limit':
1061
+				return $this->real_quantity_on_ticket();
1062
+			case 'saleable':
1063
+				return $this->real_quantity_on_ticket('saleable');
1064
+			default:
1065
+				return $this->get_raw('TKT_qty');
1066
+		}
1067
+	}
1068
+
1069
+
1070
+	/**
1071
+	 * Gets ticket quantity
1072
+	 *
1073
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1074
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1075
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1076
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1077
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1078
+	 * @param  int   $DTT_ID      the primary key for a particular datetime.
1079
+	 *                            set to 0 for all related datetimes
1080
+	 * @return int
1081
+	 * @throws EE_Error
1082
+	 */
1083
+	public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1084
+	{
1085
+		$raw = $this->get_raw('TKT_qty');
1086
+		// return immediately if it's zero
1087
+		if ($raw === 0) {
1088
+			return $raw;
1089
+		}
1090
+		// echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1091
+		// ensure qty doesn't exceed raw value for THIS ticket
1092
+		$qty = min(EE_INF, $raw);
1093
+		// echo "\n . qty: " . $qty . '<br />';
1094
+		// calculate this ticket's total sales and reservations
1095
+		$sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1096
+		// echo "\n . sold: " . $this->sold() . '<br />';
1097
+		// echo "\n . reserved: " . $this->reserved() . '<br />';
1098
+		// echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1099
+		// first we need to calculate the maximum number of tickets available for the datetime
1100
+		// do we want data for one datetime or all of them ?
1101
+		$query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1102
+		$datetimes = $this->datetimes($query_params);
1103
+		if (is_array($datetimes) && ! empty($datetimes)) {
1104
+			foreach ($datetimes as $datetime) {
1105
+				if ($datetime instanceof EE_Datetime) {
1106
+					$datetime->refresh_from_db();
1107
+					// echo "\n . . datetime name: " . $datetime->name() . '<br />';
1108
+					// echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1109
+					// initialize with no restrictions for each datetime
1110
+					// but adjust datetime qty based on datetime reg limit
1111
+					$datetime_qty = min(EE_INF, $datetime->reg_limit());
1112
+					// echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1113
+					// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1114
+					// if we want the actual saleable amount, then we need to consider OTHER ticket sales
1115
+					// and reservations for this datetime, that do NOT include sales and reservations
1116
+					// for this ticket (so we add $this->sold() and $this->reserved() back in)
1117
+					if ($context === 'saleable') {
1118
+						$datetime_qty = max(
1119
+							$datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1120
+							0
1121
+						);
1122
+						// echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1123
+						// echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1124
+						// echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1125
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1126
+						$datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1127
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1128
+					}
1129
+					$qty = min($datetime_qty, $qty);
1130
+					// echo "\n . . qty: " . $qty . '<br />';
1131
+				}
1132
+			}
1133
+		}
1134
+		// NOW that we know the  maximum number of tickets available for the datetime
1135
+		// we can finally factor in the details for this specific ticket
1136
+		if ($qty > 0 && $context === 'saleable') {
1137
+			// and subtract the sales for THIS ticket
1138
+			$qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1139
+			// echo "\n . qty: " . $qty . '<br />';
1140
+		}
1141
+		// echo "\nFINAL QTY: " . $qty . "<br /><br />";
1142
+		return $qty;
1143
+	}
1144
+
1145
+
1146
+	/**
1147
+	 * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1148
+	 *
1149
+	 * @param int $qty
1150
+	 * @return void
1151
+	 * @throws EE_Error
1152
+	 */
1153
+	public function set_qty($qty)
1154
+	{
1155
+		$datetimes = $this->datetimes();
1156
+		foreach ($datetimes as $datetime) {
1157
+			if ($datetime instanceof EE_Datetime) {
1158
+				$qty = min($qty, $datetime->reg_limit());
1159
+			}
1160
+		}
1161
+		$this->set('TKT_qty', $qty);
1162
+	}
1163
+
1164
+
1165
+	/**
1166
+	 * Gets uses
1167
+	 *
1168
+	 * @return int
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	public function uses()
1172
+	{
1173
+		return $this->get('TKT_uses');
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * Sets uses
1179
+	 *
1180
+	 * @param int $uses
1181
+	 * @return void
1182
+	 * @throws EE_Error
1183
+	 */
1184
+	public function set_uses($uses)
1185
+	{
1186
+		$this->set('TKT_uses', $uses);
1187
+	}
1188
+
1189
+
1190
+	/**
1191
+	 * returns whether ticket is required or not.
1192
+	 *
1193
+	 * @return boolean
1194
+	 * @throws EE_Error
1195
+	 */
1196
+	public function required()
1197
+	{
1198
+		return $this->get('TKT_required');
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * sets the TKT_required property
1204
+	 *
1205
+	 * @param boolean $required
1206
+	 * @return void
1207
+	 * @throws EE_Error
1208
+	 */
1209
+	public function set_required($required)
1210
+	{
1211
+		$this->set('TKT_required', $required);
1212
+	}
1213
+
1214
+
1215
+	/**
1216
+	 * Gets taxable
1217
+	 *
1218
+	 * @return boolean
1219
+	 * @throws EE_Error
1220
+	 */
1221
+	public function taxable()
1222
+	{
1223
+		return $this->get('TKT_taxable');
1224
+	}
1225
+
1226
+
1227
+	/**
1228
+	 * Sets taxable
1229
+	 *
1230
+	 * @param boolean $taxable
1231
+	 * @return void
1232
+	 * @throws EE_Error
1233
+	 */
1234
+	public function set_taxable($taxable)
1235
+	{
1236
+		$this->set('TKT_taxable', $taxable);
1237
+	}
1238
+
1239
+
1240
+	/**
1241
+	 * Gets is_default
1242
+	 *
1243
+	 * @return boolean
1244
+	 * @throws EE_Error
1245
+	 */
1246
+	public function is_default()
1247
+	{
1248
+		return $this->get('TKT_is_default');
1249
+	}
1250
+
1251
+
1252
+	/**
1253
+	 * Sets is_default
1254
+	 *
1255
+	 * @param boolean $is_default
1256
+	 * @return void
1257
+	 * @throws EE_Error
1258
+	 */
1259
+	public function set_is_default($is_default)
1260
+	{
1261
+		$this->set('TKT_is_default', $is_default);
1262
+	}
1263
+
1264
+
1265
+	/**
1266
+	 * Gets order
1267
+	 *
1268
+	 * @return int
1269
+	 * @throws EE_Error
1270
+	 */
1271
+	public function order()
1272
+	{
1273
+		return $this->get('TKT_order');
1274
+	}
1275
+
1276
+
1277
+	/**
1278
+	 * Sets order
1279
+	 *
1280
+	 * @param int $order
1281
+	 * @return void
1282
+	 * @throws EE_Error
1283
+	 */
1284
+	public function set_order($order)
1285
+	{
1286
+		$this->set('TKT_order', $order);
1287
+	}
1288
+
1289
+
1290
+	/**
1291
+	 * Gets row
1292
+	 *
1293
+	 * @return int
1294
+	 * @throws EE_Error
1295
+	 */
1296
+	public function row()
1297
+	{
1298
+		return $this->get('TKT_row');
1299
+	}
1300
+
1301
+
1302
+	/**
1303
+	 * Sets row
1304
+	 *
1305
+	 * @param int $row
1306
+	 * @return void
1307
+	 * @throws EE_Error
1308
+	 */
1309
+	public function set_row($row)
1310
+	{
1311
+		$this->set('TKT_row', $row);
1312
+	}
1313
+
1314
+
1315
+	/**
1316
+	 * Gets deleted
1317
+	 *
1318
+	 * @return boolean
1319
+	 * @throws EE_Error
1320
+	 */
1321
+	public function deleted()
1322
+	{
1323
+		return $this->get('TKT_deleted');
1324
+	}
1325
+
1326
+
1327
+	/**
1328
+	 * Sets deleted
1329
+	 *
1330
+	 * @param boolean $deleted
1331
+	 * @return void
1332
+	 * @throws EE_Error
1333
+	 */
1334
+	public function set_deleted($deleted)
1335
+	{
1336
+		$this->set('TKT_deleted', $deleted);
1337
+	}
1338
+
1339
+
1340
+	/**
1341
+	 * Gets parent
1342
+	 *
1343
+	 * @return int
1344
+	 * @throws EE_Error
1345
+	 */
1346
+	public function parent_ID()
1347
+	{
1348
+		return $this->get('TKT_parent');
1349
+	}
1350
+
1351
+
1352
+	/**
1353
+	 * Sets parent
1354
+	 *
1355
+	 * @param int $parent
1356
+	 * @return void
1357
+	 * @throws EE_Error
1358
+	 */
1359
+	public function set_parent_ID($parent)
1360
+	{
1361
+		$this->set('TKT_parent', $parent);
1362
+	}
1363
+
1364
+
1365
+	/**
1366
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1367
+	 *
1368
+	 * @return string
1369
+	 * @throws EE_Error
1370
+	 */
1371
+	public function name_and_info()
1372
+	{
1373
+		$times = array();
1374
+		foreach ($this->datetimes() as $datetime) {
1375
+			$times[] = $datetime->start_date_and_time();
1376
+		}
1377
+		return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1378
+	}
1379
+
1380
+
1381
+	/**
1382
+	 * Gets name
1383
+	 *
1384
+	 * @return string
1385
+	 * @throws EE_Error
1386
+	 */
1387
+	public function name()
1388
+	{
1389
+		return $this->get('TKT_name');
1390
+	}
1391
+
1392
+
1393
+	/**
1394
+	 * Gets price
1395
+	 *
1396
+	 * @return float
1397
+	 * @throws EE_Error
1398
+	 */
1399
+	public function price()
1400
+	{
1401
+		return $this->get('TKT_price');
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * Gets all the registrations for this ticket
1407
+	 *
1408
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1409
+	 * @return EE_Registration[]|EE_Base_Class[]
1410
+	 * @throws EE_Error
1411
+	 */
1412
+	public function registrations($query_params = array())
1413
+	{
1414
+		return $this->get_many_related('Registration', $query_params);
1415
+	}
1416
+
1417
+
1418
+	/**
1419
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1420
+	 *
1421
+	 * @return int
1422
+	 * @throws EE_Error
1423
+	 */
1424
+	public function update_tickets_sold()
1425
+	{
1426
+		$count_regs_for_this_ticket = $this->count_registrations(
1427
+			array(
1428
+				array(
1429
+					'STS_ID'      => EEM_Registration::status_id_approved,
1430
+					'REG_deleted' => 0,
1431
+				),
1432
+			)
1433
+		);
1434
+		$this->set_sold($count_regs_for_this_ticket);
1435
+		$this->save();
1436
+		return $count_regs_for_this_ticket;
1437
+	}
1438
+
1439
+
1440
+	/**
1441
+	 * Counts the registrations for this ticket
1442
+	 *
1443
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1444
+	 * @return int
1445
+	 */
1446
+	public function count_registrations($query_params = array())
1447
+	{
1448
+		return $this->count_related('Registration', $query_params);
1449
+	}
1450
+
1451
+
1452
+	/**
1453
+	 * Implementation for EEI_Has_Icon interface method.
1454
+	 *
1455
+	 * @see EEI_Visual_Representation for comments
1456
+	 * @return string
1457
+	 */
1458
+	public function get_icon()
1459
+	{
1460
+		return '<span class="dashicons dashicons-tickets-alt"></span>';
1461
+	}
1462
+
1463
+
1464
+	/**
1465
+	 * Implementation of the EEI_Event_Relation interface method
1466
+	 *
1467
+	 * @see EEI_Event_Relation for comments
1468
+	 * @return EE_Event
1469
+	 * @throws EE_Error
1470
+	 * @throws UnexpectedEntityException
1471
+	 */
1472
+	public function get_related_event()
1473
+	{
1474
+		// get one datetime to use for getting the event
1475
+		$datetime = $this->first_datetime();
1476
+		if (! $datetime instanceof \EE_Datetime) {
1477
+			throw new UnexpectedEntityException(
1478
+				$datetime,
1479
+				'EE_Datetime',
1480
+				sprintf(
1481
+					esc_html__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1482
+					$this->name()
1483
+				)
1484
+			);
1485
+		}
1486
+		$event = $datetime->event();
1487
+		if (! $event instanceof \EE_Event) {
1488
+			throw new UnexpectedEntityException(
1489
+				$event,
1490
+				'EE_Event',
1491
+				sprintf(
1492
+					esc_html__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1493
+					$this->name()
1494
+				)
1495
+			);
1496
+		}
1497
+		return $event;
1498
+	}
1499
+
1500
+
1501
+	/**
1502
+	 * Implementation of the EEI_Event_Relation interface method
1503
+	 *
1504
+	 * @see EEI_Event_Relation for comments
1505
+	 * @return string
1506
+	 * @throws UnexpectedEntityException
1507
+	 * @throws EE_Error
1508
+	 */
1509
+	public function get_event_name()
1510
+	{
1511
+		$event = $this->get_related_event();
1512
+		return $event instanceof EE_Event ? $event->name() : '';
1513
+	}
1514
+
1515
+
1516
+	/**
1517
+	 * Implementation of the EEI_Event_Relation interface method
1518
+	 *
1519
+	 * @see EEI_Event_Relation for comments
1520
+	 * @return int
1521
+	 * @throws UnexpectedEntityException
1522
+	 * @throws EE_Error
1523
+	 */
1524
+	public function get_event_ID()
1525
+	{
1526
+		$event = $this->get_related_event();
1527
+		return $event instanceof EE_Event ? $event->ID() : 0;
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * This simply returns whether a ticket can be permanently deleted or not.
1533
+	 * The criteria for determining this is whether the ticket has any related registrations.
1534
+	 * If there are none then it can be permanently deleted.
1535
+	 *
1536
+	 * @return bool
1537
+	 */
1538
+	public function is_permanently_deleteable()
1539
+	{
1540
+		return $this->count_registrations() === 0;
1541
+	}
1542
+
1543
+
1544
+	/*******************************************************************
1545 1545
      ***********************  DEPRECATED METHODS  **********************
1546 1546
      *******************************************************************/
1547 1547
 
1548 1548
 
1549
-    /**
1550
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1551
-     * associated datetimes.
1552
-     *
1553
-     * @deprecated 4.9.80.p
1554
-     * @param int $qty
1555
-     * @return void
1556
-     * @throws EE_Error
1557
-     * @throws InvalidArgumentException
1558
-     * @throws InvalidDataTypeException
1559
-     * @throws InvalidInterfaceException
1560
-     * @throws ReflectionException
1561
-     */
1562
-    public function increase_sold($qty = 1)
1563
-    {
1564
-        EE_Error::doing_it_wrong(
1565
-            __FUNCTION__,
1566
-            esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1567
-            '4.9.80.p',
1568
-            '5.0.0.p'
1569
-        );
1570
-        $this->increaseSold($qty);
1571
-    }
1572
-
1573
-
1574
-    /**
1575
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1576
-     *
1577
-     * @deprecated 4.9.80.p
1578
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1579
-     *                 Negative means to decreases old counts (and increase reserved counts).
1580
-     * @throws EE_Error
1581
-     * @throws InvalidArgumentException
1582
-     * @throws InvalidDataTypeException
1583
-     * @throws InvalidInterfaceException
1584
-     * @throws ReflectionException
1585
-     */
1586
-    protected function _increase_sold_for_datetimes($qty)
1587
-    {
1588
-        EE_Error::doing_it_wrong(
1589
-            __FUNCTION__,
1590
-            esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1591
-            '4.9.80.p',
1592
-            '5.0.0.p'
1593
-        );
1594
-        $this->increaseSoldForDatetimes($qty);
1595
-    }
1596
-
1597
-
1598
-    /**
1599
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1600
-     * DB and then updates the model objects.
1601
-     * Does not affect the reserved counts.
1602
-     *
1603
-     * @deprecated 4.9.80.p
1604
-     * @param int $qty
1605
-     * @return void
1606
-     * @throws EE_Error
1607
-     * @throws InvalidArgumentException
1608
-     * @throws InvalidDataTypeException
1609
-     * @throws InvalidInterfaceException
1610
-     * @throws ReflectionException
1611
-     */
1612
-    public function decrease_sold($qty = 1)
1613
-    {
1614
-        EE_Error::doing_it_wrong(
1615
-            __FUNCTION__,
1616
-            esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1617
-            '4.9.80.p',
1618
-            '5.0.0.p'
1619
-        );
1620
-        $this->decreaseSold($qty);
1621
-    }
1622
-
1623
-
1624
-    /**
1625
-     * Decreases sold on related datetimes
1626
-     *
1627
-     * @deprecated 4.9.80.p
1628
-     * @param int $qty
1629
-     * @return void
1630
-     * @throws EE_Error
1631
-     * @throws InvalidArgumentException
1632
-     * @throws InvalidDataTypeException
1633
-     * @throws InvalidInterfaceException
1634
-     * @throws ReflectionException
1635
-     */
1636
-    protected function _decrease_sold_for_datetimes($qty = 1)
1637
-    {
1638
-        EE_Error::doing_it_wrong(
1639
-            __FUNCTION__,
1640
-            esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1641
-            '4.9.80.p',
1642
-            '5.0.0.p'
1643
-        );
1644
-        $this->decreaseSoldForDatetimes($qty);
1645
-    }
1646
-
1647
-
1648
-    /**
1649
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1650
-     *
1651
-     * @deprecated 4.9.80.p
1652
-     * @param int    $qty
1653
-     * @param string $source
1654
-     * @return bool whether we successfully reserved the ticket or not.
1655
-     * @throws EE_Error
1656
-     * @throws InvalidArgumentException
1657
-     * @throws ReflectionException
1658
-     * @throws InvalidDataTypeException
1659
-     * @throws InvalidInterfaceException
1660
-     */
1661
-    public function increase_reserved($qty = 1, $source = 'unknown')
1662
-    {
1663
-        EE_Error::doing_it_wrong(
1664
-            __FUNCTION__,
1665
-            esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1666
-            '4.9.80.p',
1667
-            '5.0.0.p'
1668
-        );
1669
-        return $this->increaseReserved($qty);
1670
-    }
1671
-
1672
-
1673
-    /**
1674
-     * Increases sold on related datetimes
1675
-     *
1676
-     * @deprecated 4.9.80.p
1677
-     * @param int $qty
1678
-     * @return boolean indicating success
1679
-     * @throws EE_Error
1680
-     * @throws InvalidArgumentException
1681
-     * @throws InvalidDataTypeException
1682
-     * @throws InvalidInterfaceException
1683
-     * @throws ReflectionException
1684
-     */
1685
-    protected function _increase_reserved_for_datetimes($qty = 1)
1686
-    {
1687
-        EE_Error::doing_it_wrong(
1688
-            __FUNCTION__,
1689
-            esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1690
-            '4.9.80.p',
1691
-            '5.0.0.p'
1692
-        );
1693
-        return $this->increaseReservedForDatetimes($qty);
1694
-    }
1695
-
1696
-
1697
-    /**
1698
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1699
-     *
1700
-     * @deprecated 4.9.80.p
1701
-     * @param int    $qty
1702
-     * @param bool   $adjust_datetimes
1703
-     * @param string $source
1704
-     * @return void
1705
-     * @throws EE_Error
1706
-     * @throws InvalidArgumentException
1707
-     * @throws ReflectionException
1708
-     * @throws InvalidDataTypeException
1709
-     * @throws InvalidInterfaceException
1710
-     */
1711
-    public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1712
-    {
1713
-        EE_Error::doing_it_wrong(
1714
-            __FUNCTION__,
1715
-            esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1716
-            '4.9.80.p',
1717
-            '5.0.0.p'
1718
-        );
1719
-        $this->decreaseReserved($qty);
1720
-    }
1721
-
1722
-
1723
-    /**
1724
-     * Decreases reserved on related datetimes
1725
-     *
1726
-     * @deprecated 4.9.80.p
1727
-     * @param int $qty
1728
-     * @return void
1729
-     * @throws EE_Error
1730
-     * @throws InvalidArgumentException
1731
-     * @throws ReflectionException
1732
-     * @throws InvalidDataTypeException
1733
-     * @throws InvalidInterfaceException
1734
-     */
1735
-    protected function _decrease_reserved_for_datetimes($qty = 1)
1736
-    {
1737
-        EE_Error::doing_it_wrong(
1738
-            __FUNCTION__,
1739
-            esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1740
-            '4.9.80.p',
1741
-            '5.0.0.p'
1742
-        );
1743
-        $this->decreaseReservedForDatetimes($qty);
1744
-    }
1549
+	/**
1550
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1551
+	 * associated datetimes.
1552
+	 *
1553
+	 * @deprecated 4.9.80.p
1554
+	 * @param int $qty
1555
+	 * @return void
1556
+	 * @throws EE_Error
1557
+	 * @throws InvalidArgumentException
1558
+	 * @throws InvalidDataTypeException
1559
+	 * @throws InvalidInterfaceException
1560
+	 * @throws ReflectionException
1561
+	 */
1562
+	public function increase_sold($qty = 1)
1563
+	{
1564
+		EE_Error::doing_it_wrong(
1565
+			__FUNCTION__,
1566
+			esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1567
+			'4.9.80.p',
1568
+			'5.0.0.p'
1569
+		);
1570
+		$this->increaseSold($qty);
1571
+	}
1572
+
1573
+
1574
+	/**
1575
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1576
+	 *
1577
+	 * @deprecated 4.9.80.p
1578
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1579
+	 *                 Negative means to decreases old counts (and increase reserved counts).
1580
+	 * @throws EE_Error
1581
+	 * @throws InvalidArgumentException
1582
+	 * @throws InvalidDataTypeException
1583
+	 * @throws InvalidInterfaceException
1584
+	 * @throws ReflectionException
1585
+	 */
1586
+	protected function _increase_sold_for_datetimes($qty)
1587
+	{
1588
+		EE_Error::doing_it_wrong(
1589
+			__FUNCTION__,
1590
+			esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1591
+			'4.9.80.p',
1592
+			'5.0.0.p'
1593
+		);
1594
+		$this->increaseSoldForDatetimes($qty);
1595
+	}
1596
+
1597
+
1598
+	/**
1599
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1600
+	 * DB and then updates the model objects.
1601
+	 * Does not affect the reserved counts.
1602
+	 *
1603
+	 * @deprecated 4.9.80.p
1604
+	 * @param int $qty
1605
+	 * @return void
1606
+	 * @throws EE_Error
1607
+	 * @throws InvalidArgumentException
1608
+	 * @throws InvalidDataTypeException
1609
+	 * @throws InvalidInterfaceException
1610
+	 * @throws ReflectionException
1611
+	 */
1612
+	public function decrease_sold($qty = 1)
1613
+	{
1614
+		EE_Error::doing_it_wrong(
1615
+			__FUNCTION__,
1616
+			esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1617
+			'4.9.80.p',
1618
+			'5.0.0.p'
1619
+		);
1620
+		$this->decreaseSold($qty);
1621
+	}
1622
+
1623
+
1624
+	/**
1625
+	 * Decreases sold on related datetimes
1626
+	 *
1627
+	 * @deprecated 4.9.80.p
1628
+	 * @param int $qty
1629
+	 * @return void
1630
+	 * @throws EE_Error
1631
+	 * @throws InvalidArgumentException
1632
+	 * @throws InvalidDataTypeException
1633
+	 * @throws InvalidInterfaceException
1634
+	 * @throws ReflectionException
1635
+	 */
1636
+	protected function _decrease_sold_for_datetimes($qty = 1)
1637
+	{
1638
+		EE_Error::doing_it_wrong(
1639
+			__FUNCTION__,
1640
+			esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1641
+			'4.9.80.p',
1642
+			'5.0.0.p'
1643
+		);
1644
+		$this->decreaseSoldForDatetimes($qty);
1645
+	}
1646
+
1647
+
1648
+	/**
1649
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1650
+	 *
1651
+	 * @deprecated 4.9.80.p
1652
+	 * @param int    $qty
1653
+	 * @param string $source
1654
+	 * @return bool whether we successfully reserved the ticket or not.
1655
+	 * @throws EE_Error
1656
+	 * @throws InvalidArgumentException
1657
+	 * @throws ReflectionException
1658
+	 * @throws InvalidDataTypeException
1659
+	 * @throws InvalidInterfaceException
1660
+	 */
1661
+	public function increase_reserved($qty = 1, $source = 'unknown')
1662
+	{
1663
+		EE_Error::doing_it_wrong(
1664
+			__FUNCTION__,
1665
+			esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1666
+			'4.9.80.p',
1667
+			'5.0.0.p'
1668
+		);
1669
+		return $this->increaseReserved($qty);
1670
+	}
1671
+
1672
+
1673
+	/**
1674
+	 * Increases sold on related datetimes
1675
+	 *
1676
+	 * @deprecated 4.9.80.p
1677
+	 * @param int $qty
1678
+	 * @return boolean indicating success
1679
+	 * @throws EE_Error
1680
+	 * @throws InvalidArgumentException
1681
+	 * @throws InvalidDataTypeException
1682
+	 * @throws InvalidInterfaceException
1683
+	 * @throws ReflectionException
1684
+	 */
1685
+	protected function _increase_reserved_for_datetimes($qty = 1)
1686
+	{
1687
+		EE_Error::doing_it_wrong(
1688
+			__FUNCTION__,
1689
+			esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1690
+			'4.9.80.p',
1691
+			'5.0.0.p'
1692
+		);
1693
+		return $this->increaseReservedForDatetimes($qty);
1694
+	}
1695
+
1696
+
1697
+	/**
1698
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1699
+	 *
1700
+	 * @deprecated 4.9.80.p
1701
+	 * @param int    $qty
1702
+	 * @param bool   $adjust_datetimes
1703
+	 * @param string $source
1704
+	 * @return void
1705
+	 * @throws EE_Error
1706
+	 * @throws InvalidArgumentException
1707
+	 * @throws ReflectionException
1708
+	 * @throws InvalidDataTypeException
1709
+	 * @throws InvalidInterfaceException
1710
+	 */
1711
+	public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1712
+	{
1713
+		EE_Error::doing_it_wrong(
1714
+			__FUNCTION__,
1715
+			esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1716
+			'4.9.80.p',
1717
+			'5.0.0.p'
1718
+		);
1719
+		$this->decreaseReserved($qty);
1720
+	}
1721
+
1722
+
1723
+	/**
1724
+	 * Decreases reserved on related datetimes
1725
+	 *
1726
+	 * @deprecated 4.9.80.p
1727
+	 * @param int $qty
1728
+	 * @return void
1729
+	 * @throws EE_Error
1730
+	 * @throws InvalidArgumentException
1731
+	 * @throws ReflectionException
1732
+	 * @throws InvalidDataTypeException
1733
+	 * @throws InvalidInterfaceException
1734
+	 */
1735
+	protected function _decrease_reserved_for_datetimes($qty = 1)
1736
+	{
1737
+		EE_Error::doing_it_wrong(
1738
+			__FUNCTION__,
1739
+			esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1740
+			'4.9.80.p',
1741
+			'5.0.0.p'
1742
+		);
1743
+		$this->decreaseReservedForDatetimes($qty);
1744
+	}
1745 1745
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -129,7 +129,7 @@  discard block
 block discarded – undo
129 129
     public function ticket_status($display = false, $remaining = null)
130 130
     {
131 131
         $remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
132
-        if (! $remaining) {
132
+        if ( ! $remaining) {
133 133
             return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
134 134
         }
135 135
         if ($this->get('TKT_deleted')) {
@@ -248,7 +248,7 @@  discard block
 block discarded – undo
248 248
             : '';
249 249
         $last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
250 250
 
251
-        return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
251
+        return $first_date && $last_date ? $first_date.$conjunction.$last_date : '';
252 252
     }
253 253
 
254 254
 
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
      */
276 276
     public function datetimes($query_params = array())
277 277
     {
278
-        if (! isset($query_params['order_by'])) {
278
+        if ( ! isset($query_params['order_by'])) {
279 279
             $query_params['order_by']['DTT_order'] = 'ASC';
280 280
         }
281 281
         return $this->get_many_related('Datetime', $query_params);
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
                 if (empty($tickets_sold['datetime'])) {
321 321
                     return $total;
322 322
                 }
323
-                if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
323
+                if ( ! empty($dtt_id) && ! isset($tickets_sold['datetime'][$dtt_id])) {
324 324
                     EE_Error::add_error(
325 325
                         esc_html__(
326 326
                             'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
                     );
333 333
                     return $total;
334 334
                 }
335
-                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
335
+                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][$dtt_id];
336 336
                 break;
337 337
             default:
338 338
                 return $total;
@@ -350,9 +350,9 @@  discard block
 block discarded – undo
350 350
     {
351 351
         $datetimes = $this->get_many_related('Datetime');
352 352
         $tickets_sold = array();
353
-        if (! empty($datetimes)) {
353
+        if ( ! empty($datetimes)) {
354 354
             foreach ($datetimes as $datetime) {
355
-                $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
355
+                $tickets_sold['datetime'][$datetime->ID()] = $datetime->get('DTT_sold');
356 356
             }
357 357
         }
358 358
         // Tickets sold
@@ -925,7 +925,7 @@  discard block
 block discarded – undo
925 925
                 'TKT_qty',
926 926
                 $qty
927 927
             );
928
-            if (! $success) {
928
+            if ( ! $success) {
929 929
                 // The datetimes were successfully bumped, but not the
930 930
                 // ticket. So we need to manually rollback the datetimes.
931 931
                 $this->decreaseReservedForDatetimes($qty);
@@ -1374,7 +1374,7 @@  discard block
 block discarded – undo
1374 1374
         foreach ($this->datetimes() as $datetime) {
1375 1375
             $times[] = $datetime->start_date_and_time();
1376 1376
         }
1377
-        return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1377
+        return $this->name().' @ '.implode(', ', $times).' for '.$this->pretty_price();
1378 1378
     }
1379 1379
 
1380 1380
 
@@ -1473,7 +1473,7 @@  discard block
 block discarded – undo
1473 1473
     {
1474 1474
         // get one datetime to use for getting the event
1475 1475
         $datetime = $this->first_datetime();
1476
-        if (! $datetime instanceof \EE_Datetime) {
1476
+        if ( ! $datetime instanceof \EE_Datetime) {
1477 1477
             throw new UnexpectedEntityException(
1478 1478
                 $datetime,
1479 1479
                 'EE_Datetime',
@@ -1484,7 +1484,7 @@  discard block
 block discarded – undo
1484 1484
             );
1485 1485
         }
1486 1486
         $event = $datetime->event();
1487
-        if (! $event instanceof \EE_Event) {
1487
+        if ( ! $event instanceof \EE_Event) {
1488 1488
             throw new UnexpectedEntityException(
1489 1489
                 $event,
1490 1490
                 'EE_Event',
Please login to merge, or discard this patch.
core/EE_Payment_Processor.core.php 2 patches
Indentation   +842 added lines, -842 removed lines patch added patch discarded remove patch
@@ -18,846 +18,846 @@
 block discarded – undo
18 18
 class EE_Payment_Processor extends EE_Processor_Base implements ResettableInterface
19 19
 {
20 20
 
21
-    /**
22
-     * @var EE_Payment_Processor $_instance
23
-     * @access    private
24
-     */
25
-    private static $_instance;
26
-
27
-
28
-    /**
29
-     * @singleton method used to instantiate class object
30
-     * @access    public
31
-     * @return EE_Payment_Processor instance
32
-     */
33
-    public static function instance()
34
-    {
35
-        // check if class object is instantiated
36
-        if (! self::$_instance instanceof EE_Payment_Processor) {
37
-            self::$_instance = new self();
38
-        }
39
-        return self::$_instance;
40
-    }
41
-
42
-
43
-    /**
44
-     * @return EE_Payment_Processor
45
-     */
46
-    public static function reset()
47
-    {
48
-        self::$_instance = null;
49
-        return self::instance();
50
-    }
51
-
52
-
53
-    /**
54
-     *private constructor to prevent direct creation
55
-     *
56
-     * @Constructor
57
-     * @access private
58
-     */
59
-    private function __construct()
60
-    {
61
-        do_action('AHEE__EE_Payment_Processor__construct');
62
-        add_action('http_api_curl', array($this, '_curl_requests_to_paypal_use_tls'), 10, 3);
63
-    }
64
-
65
-
66
-    /**
67
-     * Using the selected gateway, processes the payment for that transaction, and updates the transaction
68
-     * appropriately. Saves the payment that is generated
69
-     *
70
-     * @param EE_Payment_Method    $payment_method
71
-     * @param EE_Transaction       $transaction
72
-     * @param float                $amount       if only part of the transaction is to be paid for, how much.
73
-     *                                           Leave null if payment is for the full amount owing
74
-     * @param EE_Billing_Info_Form $billing_form (or probably null, if it's an offline or offsite payment method).
75
-     *                                           Receive_form_submission() should have
76
-     *                                           already been called on the billing form
77
-     *                                           (ie, its inputs should have their normalized values set).
78
-     * @param string               $return_url   string used mostly by offsite gateways to specify
79
-     *                                           where to go AFTER the offsite gateway
80
-     * @param string               $method       like 'CART', indicates who the client who called this was
81
-     * @param bool                 $by_admin     TRUE if payment is being attempted from the admin
82
-     * @param boolean              $update_txn   whether or not to call
83
-     *                                           EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
84
-     * @param string               $cancel_url   URL to return to if off-site payments are cancelled
85
-     * @return EE_Payment
86
-     * @throws EE_Error
87
-     * @throws InvalidArgumentException
88
-     * @throws ReflectionException
89
-     * @throws RuntimeException
90
-     * @throws InvalidDataTypeException
91
-     * @throws InvalidInterfaceException
92
-     */
93
-    public function process_payment(
94
-        EE_Payment_Method $payment_method,
95
-        EE_Transaction $transaction,
96
-        $amount = null,
97
-        $billing_form = null,
98
-        $return_url = null,
99
-        $method = 'CART',
100
-        $by_admin = false,
101
-        $update_txn = true,
102
-        $cancel_url = ''
103
-    ) {
104
-        if ((float) $amount < 0) {
105
-            throw new EE_Error(
106
-                sprintf(
107
-                    esc_html__(
108
-                        'Attempting to make a payment for a negative amount of %1$d for transaction %2$d. That should be a refund',
109
-                        'event_espresso'
110
-                    ),
111
-                    $amount,
112
-                    $transaction->ID()
113
-                )
114
-            );
115
-        }
116
-        // verify payment method
117
-        $payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
118
-            $payment_method,
119
-            true
120
-        );
121
-        // verify transaction
122
-        EEM_Transaction::instance()->ensure_is_obj($transaction);
123
-        $transaction->set_payment_method_ID($payment_method->ID());
124
-        // verify payment method type
125
-        if ($payment_method->type_obj() instanceof EE_PMT_Base) {
126
-            $payment = $payment_method->type_obj()->process_payment(
127
-                $transaction,
128
-                min($amount, $transaction->remaining()), // make sure we don't overcharge
129
-                $billing_form,
130
-                $return_url,
131
-                add_query_arg(array('ee_cancel_payment' => true), $cancel_url),
132
-                $method,
133
-                $by_admin
134
-            );
135
-            // check if payment method uses an off-site gateway
136
-            if ($payment_method->type_obj()->payment_occurs() !== EE_PMT_Base::offsite) {
137
-                // don't process payments for off-site gateways yet because no payment has occurred yet
138
-                $this->update_txn_based_on_payment($transaction, $payment, $update_txn);
139
-            }
140
-            return $payment;
141
-        }
142
-        EE_Error::add_error(
143
-            sprintf(
144
-                esc_html__(
145
-                    'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
146
-                    'event_espresso'
147
-                ),
148
-                '<br/>',
149
-                EE_Registry::instance()->CFG->organization->get_pretty('email')
150
-            ),
151
-            __FILE__,
152
-            __FUNCTION__,
153
-            __LINE__
154
-        );
155
-        return null;
156
-    }
157
-
158
-
159
-    /**
160
-     * @param EE_Transaction|int $transaction
161
-     * @param EE_Payment_Method  $payment_method
162
-     * @return string
163
-     * @throws EE_Error
164
-     * @throws InvalidArgumentException
165
-     * @throws InvalidDataTypeException
166
-     * @throws InvalidInterfaceException
167
-     */
168
-    public function get_ipn_url_for_payment_method($transaction, $payment_method)
169
-    {
170
-        /** @type \EE_Transaction $transaction */
171
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
172
-        $primary_reg = $transaction->primary_registration();
173
-        if (! $primary_reg instanceof EE_Registration) {
174
-            throw new EE_Error(
175
-                sprintf(
176
-                    esc_html__(
177
-                        'Cannot get IPN URL for transaction with ID %d because it has no primary registration',
178
-                        'event_espresso'
179
-                    ),
180
-                    $transaction->ID()
181
-                )
182
-            );
183
-        }
184
-        $payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
185
-            $payment_method,
186
-            true
187
-        );
188
-        $url = add_query_arg(
189
-            array(
190
-                'e_reg_url_link'    => $primary_reg->reg_url_link(),
191
-                'ee_payment_method' => $payment_method->slug(),
192
-            ),
193
-            EE_Registry::instance()->CFG->core->txn_page_url()
194
-        );
195
-        return $url;
196
-    }
197
-
198
-
199
-    /**
200
-     * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so
201
-     * we can easily find what registration the IPN is for and what payment method.
202
-     * However, if not, we'll give all payment methods a chance to claim it and process it.
203
-     * If a payment is found for the IPN info, it is saved.
204
-     *
205
-     * @param array              $_req_data            form post data
206
-     * @param EE_Transaction|int $transaction          optional (or a transactions id)
207
-     * @param EE_Payment_Method  $payment_method       (or a slug or id of one)
208
-     * @param boolean            $update_txn           whether or not to call
209
-     *                                                 EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
210
-     * @param bool               $separate_IPN_request whether the IPN uses a separate request (true, like PayPal)
211
-     *                                                 or is processed manually (false, like Authorize.net)
212
-     * @throws EE_Error
213
-     * @throws Exception
214
-     * @return EE_Payment
215
-     * @throws \RuntimeException
216
-     * @throws \ReflectionException
217
-     * @throws \InvalidArgumentException
218
-     * @throws InvalidInterfaceException
219
-     * @throws InvalidDataTypeException
220
-     */
221
-    public function process_ipn(
222
-        $_req_data,
223
-        $transaction = null,
224
-        $payment_method = null,
225
-        $update_txn = true,
226
-        $separate_IPN_request = true
227
-    ) {
228
-        EE_Registry::instance()->load_model('Change_Log');
229
-        $_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data);
230
-        EE_Processor_Base::set_IPN($separate_IPN_request);
231
-        $obj_for_log = null;
232
-        if ($transaction instanceof EE_Transaction) {
233
-            $obj_for_log = $transaction;
234
-            if ($payment_method instanceof EE_Payment_Method) {
235
-                $obj_for_log = EEM_Payment::instance()->get_one(
236
-                    array(
237
-                        array('TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()),
238
-                        'order_by' => array('PAY_timestamp' => 'desc'),
239
-                    )
240
-                );
241
-            }
242
-        } elseif ($payment_method instanceof EE_Payment) {
243
-            $obj_for_log = $payment_method;
244
-        }
245
-        $log = EEM_Change_Log::instance()->log(
246
-            EEM_Change_Log::type_gateway,
247
-            array('IPN data received' => $_req_data),
248
-            $obj_for_log
249
-        );
250
-        try {
251
-            /**
252
-             * @var EE_Payment $payment
253
-             */
254
-            $payment = null;
255
-            if ($transaction && $payment_method) {
256
-                /** @type EE_Transaction $transaction */
257
-                $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
258
-                /** @type EE_Payment_Method $payment_method */
259
-                $payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method);
260
-                if ($payment_method->type_obj() instanceof EE_PMT_Base) {
261
-                    try {
262
-                        $payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction);
263
-                        $log->set_object($payment);
264
-                    } catch (EventEspresso\core\exceptions\IpnException $e) {
265
-                        EEM_Change_Log::instance()->log(
266
-                            EEM_Change_Log::type_gateway,
267
-                            array(
268
-                                'message'     => 'IPN Exception: ' . $e->getMessage(),
269
-                                'current_url' => EEH_URL::current_url(),
270
-                                'payment'     => $e->getPaymentProperties(),
271
-                                'IPN_data'    => $e->getIpnData(),
272
-                            ),
273
-                            $obj_for_log
274
-                        );
275
-                        return $e->getPayment();
276
-                    }
277
-                } else {
278
-                    // not a payment
279
-                    EE_Error::add_error(
280
-                        sprintf(
281
-                            esc_html__(
282
-                                'A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.',
283
-                                'event_espresso'
284
-                            ),
285
-                            '<br/>',
286
-                            EE_Registry::instance()->CFG->organization->get_pretty('email')
287
-                        ),
288
-                        __FILE__,
289
-                        __FUNCTION__,
290
-                        __LINE__
291
-                    );
292
-                }
293
-            } else {
294
-                // that's actually pretty ok. The IPN just wasn't able
295
-                // to identify which transaction or payment method this was for
296
-                // give all active payment methods a chance to claim it
297
-                $active_payment_methods = EEM_Payment_Method::instance()->get_all_active();
298
-                foreach ($active_payment_methods as $active_payment_method) {
299
-                    try {
300
-                        $payment = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data);
301
-                        $payment_method = $active_payment_method;
302
-                        EEM_Change_Log::instance()->log(
303
-                            EEM_Change_Log::type_gateway,
304
-                            array('IPN data' => $_req_data),
305
-                            $payment
306
-                        );
307
-                        break;
308
-                    } catch (EventEspresso\core\exceptions\IpnException $e) {
309
-                        EEM_Change_Log::instance()->log(
310
-                            EEM_Change_Log::type_gateway,
311
-                            array(
312
-                                'message'     => 'IPN Exception: ' . $e->getMessage(),
313
-                                'current_url' => EEH_URL::current_url(),
314
-                                'payment'     => $e->getPaymentProperties(),
315
-                                'IPN_data'    => $e->getIpnData(),
316
-                            ),
317
-                            $obj_for_log
318
-                        );
319
-                        return $e->getPayment();
320
-                    } catch (EE_Error $e) {
321
-                        // that's fine- it apparently couldn't handle the IPN
322
-                    }
323
-                }
324
-            }
325
-            // EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method);
326
-            if ($payment instanceof EE_Payment) {
327
-                $payment->save();
328
-                //  update the TXN
329
-                $this->update_txn_based_on_payment(
330
-                    $transaction,
331
-                    $payment,
332
-                    $update_txn,
333
-                    $separate_IPN_request
334
-                );
335
-            } else {
336
-                // we couldn't find the payment for this IPN... let's try and log at least SOMETHING
337
-                if ($payment_method) {
338
-                    EEM_Change_Log::instance()->log(
339
-                        EEM_Change_Log::type_gateway,
340
-                        array('IPN data' => $_req_data),
341
-                        $payment_method
342
-                    );
343
-                } elseif ($transaction) {
344
-                    EEM_Change_Log::instance()->log(
345
-                        EEM_Change_Log::type_gateway,
346
-                        array('IPN data' => $_req_data),
347
-                        $transaction
348
-                    );
349
-                }
350
-            }
351
-            return $payment;
352
-        } catch (EE_Error $e) {
353
-            do_action(
354
-                'AHEE__log',
355
-                __FILE__,
356
-                __FUNCTION__,
357
-                sprintf(
358
-                    esc_html__(
359
-                        'Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"',
360
-                        'event_espresso'
361
-                    ),
362
-                    print_r($transaction, true),
363
-                    print_r($_req_data, true),
364
-                    $e->getMessage()
365
-                )
366
-            );
367
-            throw $e;
368
-        }
369
-    }
370
-
371
-
372
-    /**
373
-     * Removes any non-printable illegal characters from the input,
374
-     * which might cause a raucous when trying to insert into the database
375
-     *
376
-     * @param  array $request_data
377
-     * @return array
378
-     */
379
-    protected function _remove_unusable_characters_from_array(array $request_data)
380
-    {
381
-        $return_data = array();
382
-        foreach ($request_data as $key => $value) {
383
-            $return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters(
384
-                $value
385
-            );
386
-        }
387
-        return $return_data;
388
-    }
389
-
390
-
391
-    /**
392
-     * Removes any non-printable illegal characters from the input,
393
-     * which might cause a raucous when trying to insert into the database
394
-     *
395
-     * @param string $request_data
396
-     * @return string
397
-     */
398
-    protected function _remove_unusable_characters($request_data)
399
-    {
400
-        return preg_replace('/[^[:print:]]/', '', $request_data);
401
-    }
402
-
403
-
404
-    /**
405
-     * Should be called just before displaying the payment attempt results to the user,
406
-     * when the payment attempt has finished. Some payment methods may have special
407
-     * logic to perform here. For example, if process_payment() happens on a special request
408
-     * and then the user is redirected to a page that displays the payment's status, this
409
-     * should be called while loading the page that displays the payment's status. If the user is
410
-     * sent to an offsite payment provider, this should be called upon returning from that offsite payment
411
-     * provider.
412
-     *
413
-     * @param EE_Transaction|int $transaction
414
-     * @param bool               $update_txn whether or not to call
415
-     *                                       EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
416
-     * @return EE_Payment
417
-     * @throws EE_Error
418
-     * @throws InvalidArgumentException
419
-     * @throws ReflectionException
420
-     * @throws RuntimeException
421
-     * @throws InvalidDataTypeException
422
-     * @throws InvalidInterfaceException
423
-     * @deprecated 4.6.24 method is no longer used. Instead it is up to client code, like SPCO,
424
-     *                                       to call handle_ipn() for offsite gateways that don't receive separate IPNs
425
-     */
426
-    public function finalize_payment_for($transaction, $update_txn = true)
427
-    {
428
-        /** @var $transaction EE_Transaction */
429
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
430
-        $last_payment_method = $transaction->payment_method();
431
-        if ($last_payment_method instanceof EE_Payment_Method) {
432
-            $payment = $last_payment_method->type_obj()->finalize_payment_for($transaction);
433
-            $this->update_txn_based_on_payment($transaction, $payment, $update_txn);
434
-            return $payment;
435
-        }
436
-        return null;
437
-    }
438
-
439
-
440
-    /**
441
-     * Processes a direct refund request, saves the payment, and updates the transaction appropriately.
442
-     *
443
-     * @param EE_Payment_Method $payment_method
444
-     * @param EE_Payment        $payment_to_refund
445
-     * @param array             $refund_info
446
-     * @return EE_Payment
447
-     * @throws EE_Error
448
-     * @throws InvalidArgumentException
449
-     * @throws ReflectionException
450
-     * @throws RuntimeException
451
-     * @throws InvalidDataTypeException
452
-     * @throws InvalidInterfaceException
453
-     */
454
-    public function process_refund(
455
-        EE_Payment_Method $payment_method,
456
-        EE_Payment $payment_to_refund,
457
-        array $refund_info = array()
458
-    ) {
459
-        if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj()->supports_sending_refunds()) {
460
-            $payment_method->type_obj()->process_refund($payment_to_refund, $refund_info);
461
-            $this->update_txn_based_on_payment($payment_to_refund->transaction(), $payment_to_refund);
462
-        }
463
-        return $payment_to_refund;
464
-    }
465
-
466
-
467
-    /**
468
-     * This should be called each time there may have been an update to a
469
-     * payment on a transaction (ie, we asked for a payment to process a
470
-     * payment for a transaction, or we told a payment method about an IPN, or
471
-     * we told a payment method to
472
-     * "finalize_payment_for" (a transaction), or we told a payment method to
473
-     * process a refund. This should handle firing the correct hooks to
474
-     * indicate
475
-     * what exactly happened and updating the transaction appropriately). This
476
-     * could be integrated directly into EE_Transaction upon save, but we want
477
-     * this logic to be separate from 'normal' plain-jane saving and updating
478
-     * of transactions and payments, and to be tied to payment processing.
479
-     * Note: this method DOES NOT save the payment passed into it. It is the responsibility
480
-     * of previous code to decide whether or not to save (because the payment passed into
481
-     * this method might be a temporary, never-to-be-saved payment from an offline gateway,
482
-     * in which case we only want that payment object for some temporary usage during this request,
483
-     * but we don't want it to be saved).
484
-     *
485
-     * @param EE_Transaction|int $transaction
486
-     * @param EE_Payment         $payment
487
-     * @param boolean            $update_txn
488
-     *                        whether or not to call
489
-     *                        EE_Transaction_Processor::
490
-     *                        update_transaction_and_registrations_after_checkout_or_payment()
491
-     *                        (you can save 1 DB query if you know you're going
492
-     *                        to save it later instead)
493
-     * @param bool               $IPN
494
-     *                        if processing IPNs or other similar payment
495
-     *                        related activities that occur in alternate
496
-     *                        requests than the main one that is processing the
497
-     *                        TXN, then set this to true to check whether the
498
-     *                        TXN is locked before updating
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws ReflectionException
502
-     * @throws RuntimeException
503
-     * @throws InvalidDataTypeException
504
-     * @throws InvalidInterfaceException
505
-     */
506
-    public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false)
507
-    {
508
-        $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful';
509
-        /** @type EE_Transaction $transaction */
510
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
511
-        // can we freely update the TXN at this moment?
512
-        if ($IPN && $transaction->is_locked()) {
513
-            // don't update the transaction at this exact moment
514
-            // because the TXN is active in another request
515
-            EE_Cron_Tasks::schedule_update_transaction_with_payment(
516
-                time(),
517
-                $transaction->ID(),
518
-                $payment->ID()
519
-            );
520
-        } else {
521
-            // verify payment and that it has been saved
522
-            if ($payment instanceof EE_Payment && $payment->ID()) {
523
-                if (
524
-                    $payment->payment_method() instanceof EE_Payment_Method
525
-                    && $payment->payment_method()->type_obj() instanceof EE_PMT_Base
526
-                ) {
527
-                    $payment->payment_method()->type_obj()->update_txn_based_on_payment($payment);
528
-                    // update TXN registrations with payment info
529
-                    $this->process_registration_payments($transaction, $payment);
530
-                }
531
-                $do_action = $payment->just_approved()
532
-                    ? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful'
533
-                    : $do_action;
534
-            } else {
535
-                // send out notifications
536
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
537
-                $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made';
538
-            }
539
-            if ($payment instanceof EE_Payment && $payment->status() !== EEM_Payment::status_id_failed) {
540
-                /** @type EE_Transaction_Payments $transaction_payments */
541
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
542
-                // set new value for total paid
543
-                $transaction_payments->calculate_total_payments_and_update_status($transaction);
544
-                // call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ???
545
-                if ($update_txn) {
546
-                    $this->_post_payment_processing($transaction, $payment, $IPN);
547
-                }
548
-            }
549
-            // granular hook for others to use.
550
-            do_action($do_action, $transaction, $payment);
551
-            do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action');
552
-            // global hook for others to use.
553
-            do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment);
554
-        }
555
-    }
556
-
557
-
558
-    /**
559
-     * update registrations REG_paid field after successful payment and link registrations with payment
560
-     *
561
-     * @param EE_Transaction    $transaction
562
-     * @param EE_Payment        $payment
563
-     * @param EE_Registration[] $registrations
564
-     * @throws EE_Error
565
-     * @throws InvalidArgumentException
566
-     * @throws RuntimeException
567
-     * @throws InvalidDataTypeException
568
-     * @throws InvalidInterfaceException
569
-     */
570
-    public function process_registration_payments(
571
-        EE_Transaction $transaction,
572
-        EE_Payment $payment,
573
-        array $registrations = array()
574
-    ) {
575
-        // only process if payment was successful
576
-        if ($payment->status() !== EEM_Payment::status_id_approved) {
577
-            return;
578
-        }
579
-        // EEM_Registration::instance()->show_next_x_db_queries();
580
-        if (empty($registrations)) {
581
-            // find registrations with monies owing that can receive a payment
582
-            $registrations = $transaction->registrations(
583
-                array(
584
-                    array(
585
-                        // only these reg statuses can receive payments
586
-                        'STS_ID'           => array('IN', EEM_Registration::reg_statuses_that_allow_payment()),
587
-                        'REG_final_price'  => array('!=', 0),
588
-                        'REG_final_price*' => array('!=', 'REG_paid', true),
589
-                    ),
590
-                )
591
-            );
592
-        }
593
-        // still nothing ??!??
594
-        if (empty($registrations)) {
595
-            return;
596
-        }
597
-        // todo: break out the following logic into a separate strategy class
598
-        // todo: named something like "Sequential_Reg_Payment_Strategy"
599
-        // todo: which would apply payments using the capitalist "first come first paid" approach
600
-        // todo: then have another strategy class like "Distributed_Reg_Payment_Strategy"
601
-        // todo: which would be the socialist "everybody gets a piece of pie" approach,
602
-        // todo: which would be better for deposits, where you want a bit of the payment applied to each registration
603
-        $refund = $payment->is_a_refund();
604
-        // how much is available to apply to registrations?
605
-        $available_payment_amount = abs($payment->amount());
606
-        foreach ($registrations as $registration) {
607
-            if ($registration instanceof EE_Registration) {
608
-                // nothing left?
609
-                if ($available_payment_amount <= 0) {
610
-                    break;
611
-                }
612
-                if ($refund) {
613
-                    $available_payment_amount = $this->process_registration_refund(
614
-                        $registration,
615
-                        $payment,
616
-                        $available_payment_amount
617
-                    );
618
-                } else {
619
-                    $available_payment_amount = $this->process_registration_payment(
620
-                        $registration,
621
-                        $payment,
622
-                        $available_payment_amount
623
-                    );
624
-                }
625
-            }
626
-        }
627
-        if (
628
-            $available_payment_amount > 0
629
-            && apply_filters(
630
-                'FHEE__EE_Payment_Processor__process_registration_payments__display_notifications',
631
-                false
632
-            )
633
-        ) {
634
-            EE_Error::add_attention(
635
-                sprintf(
636
-                    esc_html__(
637
-                        'A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).',
638
-                        'event_espresso'
639
-                    ),
640
-                    EEH_Template::format_currency($available_payment_amount),
641
-                    implode(', ', array_keys($registrations)),
642
-                    '<br/>',
643
-                    EEH_Template::format_currency($payment->amount())
644
-                ),
645
-                __FILE__,
646
-                __FUNCTION__,
647
-                __LINE__
648
-            );
649
-        }
650
-    }
651
-
652
-
653
-    /**
654
-     * update registration REG_paid field after successful payment and link registration with payment
655
-     *
656
-     * @param EE_Registration $registration
657
-     * @param EE_Payment      $payment
658
-     * @param float           $available_payment_amount
659
-     * @return float
660
-     * @throws EE_Error
661
-     * @throws InvalidArgumentException
662
-     * @throws RuntimeException
663
-     * @throws InvalidDataTypeException
664
-     * @throws InvalidInterfaceException
665
-     */
666
-    public function process_registration_payment(
667
-        EE_Registration $registration,
668
-        EE_Payment $payment,
669
-        $available_payment_amount = 0.00
670
-    ) {
671
-        $owing = $registration->final_price() - $registration->paid();
672
-        if ($owing > 0) {
673
-            // don't allow payment amount to exceed the available payment amount, OR the amount owing
674
-            $payment_amount = min($available_payment_amount, $owing);
675
-            // update $available_payment_amount
676
-            $available_payment_amount -= $payment_amount;
677
-            // calculate and set new REG_paid
678
-            $registration->set_paid($registration->paid() + $payment_amount);
679
-            // now save it
680
-            $this->_apply_registration_payment($registration, $payment, $payment_amount);
681
-        }
682
-        return $available_payment_amount;
683
-    }
684
-
685
-
686
-    /**
687
-     * update registration REG_paid field after successful payment and link registration with payment
688
-     *
689
-     * @param EE_Registration $registration
690
-     * @param EE_Payment      $payment
691
-     * @param float           $payment_amount
692
-     * @return void
693
-     * @throws EE_Error
694
-     * @throws InvalidArgumentException
695
-     * @throws InvalidDataTypeException
696
-     * @throws InvalidInterfaceException
697
-     */
698
-    protected function _apply_registration_payment(
699
-        EE_Registration $registration,
700
-        EE_Payment $payment,
701
-        $payment_amount = 0.00
702
-    ) {
703
-        // find any existing reg payment records for this registration and payment
704
-        $existing_reg_payment = EEM_Registration_Payment::instance()->get_one(
705
-            array(array('REG_ID' => $registration->ID(), 'PAY_ID' => $payment->ID()))
706
-        );
707
-        // if existing registration payment exists
708
-        if ($existing_reg_payment instanceof EE_Registration_Payment) {
709
-            // then update that record
710
-            $existing_reg_payment->set_amount($payment_amount);
711
-            $existing_reg_payment->save();
712
-        } else {
713
-            // or add new relation between registration and payment and set amount
714
-            $registration->_add_relation_to(
715
-                $payment,
716
-                'Payment',
717
-                array('RPY_amount' => $payment_amount)
718
-            );
719
-            // make it stick
720
-            $registration->save();
721
-        }
722
-    }
723
-
724
-
725
-    /**
726
-     * update registration REG_paid field after refund and link registration with payment
727
-     *
728
-     * @param EE_Registration $registration
729
-     * @param EE_Payment      $payment
730
-     * @param float           $available_refund_amount - IMPORTANT !!! SEND AVAILABLE REFUND AMOUNT AS A POSITIVE NUMBER
731
-     * @return float
732
-     * @throws EE_Error
733
-     * @throws InvalidArgumentException
734
-     * @throws RuntimeException
735
-     * @throws InvalidDataTypeException
736
-     * @throws InvalidInterfaceException
737
-     */
738
-    public function process_registration_refund(
739
-        EE_Registration $registration,
740
-        EE_Payment $payment,
741
-        $available_refund_amount = 0.00
742
-    ) {
743
-        // EEH_Debug_Tools::printr( $payment->amount(), '$payment->amount()', __FILE__, __LINE__ );
744
-        if ($registration->paid() > 0) {
745
-            // ensure $available_refund_amount is NOT negative
746
-            $available_refund_amount = (float) abs($available_refund_amount);
747
-            // don't allow refund amount to exceed the available payment amount, OR the amount paid
748
-            $refund_amount = min($available_refund_amount, (float) $registration->paid());
749
-            // update $available_payment_amount
750
-            $available_refund_amount -= $refund_amount;
751
-            // calculate and set new REG_paid
752
-            $registration->set_paid($registration->paid() - $refund_amount);
753
-            // convert payment amount back to a negative value for storage in the db
754
-            $refund_amount = (float) abs($refund_amount) * -1;
755
-            // now save it
756
-            $this->_apply_registration_payment($registration, $payment, $refund_amount);
757
-        }
758
-        return $available_refund_amount;
759
-    }
760
-
761
-
762
-    /**
763
-     * Process payments and transaction after payment process completed.
764
-     * ultimately this will send the TXN and payment details off so that notifications can be sent out.
765
-     * if this request happens to be processing an IPN,
766
-     * then we will also set the Payment Options Reg Step to completed,
767
-     * and attempt to completely finalize the TXN if all of the other Reg Steps are completed as well.
768
-     *
769
-     * @param EE_Transaction $transaction
770
-     * @param EE_Payment     $payment
771
-     * @param bool           $IPN
772
-     * @throws EE_Error
773
-     * @throws InvalidArgumentException
774
-     * @throws ReflectionException
775
-     * @throws RuntimeException
776
-     * @throws InvalidDataTypeException
777
-     * @throws InvalidInterfaceException
778
-     */
779
-    protected function _post_payment_processing(EE_Transaction $transaction, EE_Payment $payment, $IPN = false)
780
-    {
781
-        /** @type EE_Transaction_Processor $transaction_processor */
782
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
783
-        // is the Payment Options Reg Step completed ?
784
-        $payment_options_step_completed = $transaction->reg_step_completed('payment_options');
785
-        // if the Payment Options Reg Step is completed...
786
-        $revisit = $payment_options_step_completed === true;
787
-        // then this is kinda sorta a revisit with regards to payments at least
788
-        $transaction_processor->set_revisit($revisit);
789
-        // if this is an IPN, let's consider the Payment Options Reg Step completed if not already
790
-        if (
791
-            $IPN
792
-            && $payment_options_step_completed !== true
793
-            && ($payment->is_approved() || $payment->is_pending())
794
-        ) {
795
-            $payment_options_step_completed = $transaction->set_reg_step_completed(
796
-                'payment_options'
797
-            );
798
-        }
799
-        // maybe update status, but don't save transaction just yet
800
-        $transaction->update_status_based_on_total_paid(false);
801
-        // check if 'finalize_registration' step has been completed...
802
-        $finalized = $transaction->reg_step_completed('finalize_registration');
803
-        //  if this is an IPN and the final step has not been initiated
804
-        if ($IPN && $payment_options_step_completed && $finalized === false) {
805
-            // and if it hasn't already been set as being started...
806
-            $finalized = $transaction->set_reg_step_initiated('finalize_registration');
807
-        }
808
-        $transaction->save();
809
-        // because the above will return false if the final step was not fully completed, we need to check again...
810
-        if ($IPN && $finalized !== false) {
811
-            // and if we are all good to go, then send out notifications
812
-            add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
813
-            // ok, now process the transaction according to the payment
814
-            $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
815
-                $transaction,
816
-                $payment
817
-            );
818
-        }
819
-        // DEBUG LOG
820
-        $payment_method = $payment->payment_method();
821
-        if ($payment_method instanceof EE_Payment_Method) {
822
-            $payment_method_type_obj = $payment_method->type_obj();
823
-            if ($payment_method_type_obj instanceof EE_PMT_Base) {
824
-                $gateway = $payment_method_type_obj->get_gateway();
825
-                if ($gateway instanceof EE_Gateway) {
826
-                    $gateway->log(
827
-                        array(
828
-                            'message'               => (string) esc_html__('Post Payment Transaction Details', 'event_espresso'),
829
-                            'transaction'           => $transaction->model_field_array(),
830
-                            'finalized'             => $finalized,
831
-                            'IPN'                   => $IPN,
832
-                            'deliver_notifications' => has_filter(
833
-                                'FHEE__EED_Messages___maybe_registration__deliver_notifications'
834
-                            ),
835
-                        ),
836
-                        $payment
837
-                    );
838
-                }
839
-            }
840
-        }
841
-    }
842
-
843
-
844
-    /**
845
-     * Force posts to PayPal to use TLS v1.2. See:
846
-     * https://core.trac.wordpress.org/ticket/36320
847
-     * https://core.trac.wordpress.org/ticket/34924#comment:15
848
-     * https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1914&viewlocale=en_US
849
-     * This will affect PayPal standard, pro, express, and Payflow.
850
-     *
851
-     * @param $handle
852
-     * @param $r
853
-     * @param $url
854
-     */
855
-    public static function _curl_requests_to_paypal_use_tls($handle, $r, $url)
856
-    {
857
-        if (strpos($url, 'https://') !== false && strpos($url, '.paypal.com') !== false) {
858
-            // Use the value of the constant CURL_SSLVERSION_TLSv1 = 1
859
-            // instead of the constant because it might not be defined
860
-            curl_setopt($handle, CURLOPT_SSLVERSION, 6);
861
-        }
862
-    }
21
+	/**
22
+	 * @var EE_Payment_Processor $_instance
23
+	 * @access    private
24
+	 */
25
+	private static $_instance;
26
+
27
+
28
+	/**
29
+	 * @singleton method used to instantiate class object
30
+	 * @access    public
31
+	 * @return EE_Payment_Processor instance
32
+	 */
33
+	public static function instance()
34
+	{
35
+		// check if class object is instantiated
36
+		if (! self::$_instance instanceof EE_Payment_Processor) {
37
+			self::$_instance = new self();
38
+		}
39
+		return self::$_instance;
40
+	}
41
+
42
+
43
+	/**
44
+	 * @return EE_Payment_Processor
45
+	 */
46
+	public static function reset()
47
+	{
48
+		self::$_instance = null;
49
+		return self::instance();
50
+	}
51
+
52
+
53
+	/**
54
+	 *private constructor to prevent direct creation
55
+	 *
56
+	 * @Constructor
57
+	 * @access private
58
+	 */
59
+	private function __construct()
60
+	{
61
+		do_action('AHEE__EE_Payment_Processor__construct');
62
+		add_action('http_api_curl', array($this, '_curl_requests_to_paypal_use_tls'), 10, 3);
63
+	}
64
+
65
+
66
+	/**
67
+	 * Using the selected gateway, processes the payment for that transaction, and updates the transaction
68
+	 * appropriately. Saves the payment that is generated
69
+	 *
70
+	 * @param EE_Payment_Method    $payment_method
71
+	 * @param EE_Transaction       $transaction
72
+	 * @param float                $amount       if only part of the transaction is to be paid for, how much.
73
+	 *                                           Leave null if payment is for the full amount owing
74
+	 * @param EE_Billing_Info_Form $billing_form (or probably null, if it's an offline or offsite payment method).
75
+	 *                                           Receive_form_submission() should have
76
+	 *                                           already been called on the billing form
77
+	 *                                           (ie, its inputs should have their normalized values set).
78
+	 * @param string               $return_url   string used mostly by offsite gateways to specify
79
+	 *                                           where to go AFTER the offsite gateway
80
+	 * @param string               $method       like 'CART', indicates who the client who called this was
81
+	 * @param bool                 $by_admin     TRUE if payment is being attempted from the admin
82
+	 * @param boolean              $update_txn   whether or not to call
83
+	 *                                           EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
84
+	 * @param string               $cancel_url   URL to return to if off-site payments are cancelled
85
+	 * @return EE_Payment
86
+	 * @throws EE_Error
87
+	 * @throws InvalidArgumentException
88
+	 * @throws ReflectionException
89
+	 * @throws RuntimeException
90
+	 * @throws InvalidDataTypeException
91
+	 * @throws InvalidInterfaceException
92
+	 */
93
+	public function process_payment(
94
+		EE_Payment_Method $payment_method,
95
+		EE_Transaction $transaction,
96
+		$amount = null,
97
+		$billing_form = null,
98
+		$return_url = null,
99
+		$method = 'CART',
100
+		$by_admin = false,
101
+		$update_txn = true,
102
+		$cancel_url = ''
103
+	) {
104
+		if ((float) $amount < 0) {
105
+			throw new EE_Error(
106
+				sprintf(
107
+					esc_html__(
108
+						'Attempting to make a payment for a negative amount of %1$d for transaction %2$d. That should be a refund',
109
+						'event_espresso'
110
+					),
111
+					$amount,
112
+					$transaction->ID()
113
+				)
114
+			);
115
+		}
116
+		// verify payment method
117
+		$payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
118
+			$payment_method,
119
+			true
120
+		);
121
+		// verify transaction
122
+		EEM_Transaction::instance()->ensure_is_obj($transaction);
123
+		$transaction->set_payment_method_ID($payment_method->ID());
124
+		// verify payment method type
125
+		if ($payment_method->type_obj() instanceof EE_PMT_Base) {
126
+			$payment = $payment_method->type_obj()->process_payment(
127
+				$transaction,
128
+				min($amount, $transaction->remaining()), // make sure we don't overcharge
129
+				$billing_form,
130
+				$return_url,
131
+				add_query_arg(array('ee_cancel_payment' => true), $cancel_url),
132
+				$method,
133
+				$by_admin
134
+			);
135
+			// check if payment method uses an off-site gateway
136
+			if ($payment_method->type_obj()->payment_occurs() !== EE_PMT_Base::offsite) {
137
+				// don't process payments for off-site gateways yet because no payment has occurred yet
138
+				$this->update_txn_based_on_payment($transaction, $payment, $update_txn);
139
+			}
140
+			return $payment;
141
+		}
142
+		EE_Error::add_error(
143
+			sprintf(
144
+				esc_html__(
145
+					'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
146
+					'event_espresso'
147
+				),
148
+				'<br/>',
149
+				EE_Registry::instance()->CFG->organization->get_pretty('email')
150
+			),
151
+			__FILE__,
152
+			__FUNCTION__,
153
+			__LINE__
154
+		);
155
+		return null;
156
+	}
157
+
158
+
159
+	/**
160
+	 * @param EE_Transaction|int $transaction
161
+	 * @param EE_Payment_Method  $payment_method
162
+	 * @return string
163
+	 * @throws EE_Error
164
+	 * @throws InvalidArgumentException
165
+	 * @throws InvalidDataTypeException
166
+	 * @throws InvalidInterfaceException
167
+	 */
168
+	public function get_ipn_url_for_payment_method($transaction, $payment_method)
169
+	{
170
+		/** @type \EE_Transaction $transaction */
171
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
172
+		$primary_reg = $transaction->primary_registration();
173
+		if (! $primary_reg instanceof EE_Registration) {
174
+			throw new EE_Error(
175
+				sprintf(
176
+					esc_html__(
177
+						'Cannot get IPN URL for transaction with ID %d because it has no primary registration',
178
+						'event_espresso'
179
+					),
180
+					$transaction->ID()
181
+				)
182
+			);
183
+		}
184
+		$payment_method = EEM_Payment_Method::instance()->ensure_is_obj(
185
+			$payment_method,
186
+			true
187
+		);
188
+		$url = add_query_arg(
189
+			array(
190
+				'e_reg_url_link'    => $primary_reg->reg_url_link(),
191
+				'ee_payment_method' => $payment_method->slug(),
192
+			),
193
+			EE_Registry::instance()->CFG->core->txn_page_url()
194
+		);
195
+		return $url;
196
+	}
197
+
198
+
199
+	/**
200
+	 * Process the IPN. Firstly, we'll hope we put the standard args into the IPN URL so
201
+	 * we can easily find what registration the IPN is for and what payment method.
202
+	 * However, if not, we'll give all payment methods a chance to claim it and process it.
203
+	 * If a payment is found for the IPN info, it is saved.
204
+	 *
205
+	 * @param array              $_req_data            form post data
206
+	 * @param EE_Transaction|int $transaction          optional (or a transactions id)
207
+	 * @param EE_Payment_Method  $payment_method       (or a slug or id of one)
208
+	 * @param boolean            $update_txn           whether or not to call
209
+	 *                                                 EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
210
+	 * @param bool               $separate_IPN_request whether the IPN uses a separate request (true, like PayPal)
211
+	 *                                                 or is processed manually (false, like Authorize.net)
212
+	 * @throws EE_Error
213
+	 * @throws Exception
214
+	 * @return EE_Payment
215
+	 * @throws \RuntimeException
216
+	 * @throws \ReflectionException
217
+	 * @throws \InvalidArgumentException
218
+	 * @throws InvalidInterfaceException
219
+	 * @throws InvalidDataTypeException
220
+	 */
221
+	public function process_ipn(
222
+		$_req_data,
223
+		$transaction = null,
224
+		$payment_method = null,
225
+		$update_txn = true,
226
+		$separate_IPN_request = true
227
+	) {
228
+		EE_Registry::instance()->load_model('Change_Log');
229
+		$_req_data = $this->_remove_unusable_characters_from_array((array) $_req_data);
230
+		EE_Processor_Base::set_IPN($separate_IPN_request);
231
+		$obj_for_log = null;
232
+		if ($transaction instanceof EE_Transaction) {
233
+			$obj_for_log = $transaction;
234
+			if ($payment_method instanceof EE_Payment_Method) {
235
+				$obj_for_log = EEM_Payment::instance()->get_one(
236
+					array(
237
+						array('TXN_ID' => $transaction->ID(), 'PMD_ID' => $payment_method->ID()),
238
+						'order_by' => array('PAY_timestamp' => 'desc'),
239
+					)
240
+				);
241
+			}
242
+		} elseif ($payment_method instanceof EE_Payment) {
243
+			$obj_for_log = $payment_method;
244
+		}
245
+		$log = EEM_Change_Log::instance()->log(
246
+			EEM_Change_Log::type_gateway,
247
+			array('IPN data received' => $_req_data),
248
+			$obj_for_log
249
+		);
250
+		try {
251
+			/**
252
+			 * @var EE_Payment $payment
253
+			 */
254
+			$payment = null;
255
+			if ($transaction && $payment_method) {
256
+				/** @type EE_Transaction $transaction */
257
+				$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
258
+				/** @type EE_Payment_Method $payment_method */
259
+				$payment_method = EEM_Payment_Method::instance()->ensure_is_obj($payment_method);
260
+				if ($payment_method->type_obj() instanceof EE_PMT_Base) {
261
+					try {
262
+						$payment = $payment_method->type_obj()->handle_ipn($_req_data, $transaction);
263
+						$log->set_object($payment);
264
+					} catch (EventEspresso\core\exceptions\IpnException $e) {
265
+						EEM_Change_Log::instance()->log(
266
+							EEM_Change_Log::type_gateway,
267
+							array(
268
+								'message'     => 'IPN Exception: ' . $e->getMessage(),
269
+								'current_url' => EEH_URL::current_url(),
270
+								'payment'     => $e->getPaymentProperties(),
271
+								'IPN_data'    => $e->getIpnData(),
272
+							),
273
+							$obj_for_log
274
+						);
275
+						return $e->getPayment();
276
+					}
277
+				} else {
278
+					// not a payment
279
+					EE_Error::add_error(
280
+						sprintf(
281
+							esc_html__(
282
+								'A valid payment method could not be determined due to a technical issue.%sPlease refresh your browser and try again or contact %s for assistance.',
283
+								'event_espresso'
284
+							),
285
+							'<br/>',
286
+							EE_Registry::instance()->CFG->organization->get_pretty('email')
287
+						),
288
+						__FILE__,
289
+						__FUNCTION__,
290
+						__LINE__
291
+					);
292
+				}
293
+			} else {
294
+				// that's actually pretty ok. The IPN just wasn't able
295
+				// to identify which transaction or payment method this was for
296
+				// give all active payment methods a chance to claim it
297
+				$active_payment_methods = EEM_Payment_Method::instance()->get_all_active();
298
+				foreach ($active_payment_methods as $active_payment_method) {
299
+					try {
300
+						$payment = $active_payment_method->type_obj()->handle_unclaimed_ipn($_req_data);
301
+						$payment_method = $active_payment_method;
302
+						EEM_Change_Log::instance()->log(
303
+							EEM_Change_Log::type_gateway,
304
+							array('IPN data' => $_req_data),
305
+							$payment
306
+						);
307
+						break;
308
+					} catch (EventEspresso\core\exceptions\IpnException $e) {
309
+						EEM_Change_Log::instance()->log(
310
+							EEM_Change_Log::type_gateway,
311
+							array(
312
+								'message'     => 'IPN Exception: ' . $e->getMessage(),
313
+								'current_url' => EEH_URL::current_url(),
314
+								'payment'     => $e->getPaymentProperties(),
315
+								'IPN_data'    => $e->getIpnData(),
316
+							),
317
+							$obj_for_log
318
+						);
319
+						return $e->getPayment();
320
+					} catch (EE_Error $e) {
321
+						// that's fine- it apparently couldn't handle the IPN
322
+					}
323
+				}
324
+			}
325
+			// EEM_Payment_Log::instance()->log("got to 7",$transaction,$payment_method);
326
+			if ($payment instanceof EE_Payment) {
327
+				$payment->save();
328
+				//  update the TXN
329
+				$this->update_txn_based_on_payment(
330
+					$transaction,
331
+					$payment,
332
+					$update_txn,
333
+					$separate_IPN_request
334
+				);
335
+			} else {
336
+				// we couldn't find the payment for this IPN... let's try and log at least SOMETHING
337
+				if ($payment_method) {
338
+					EEM_Change_Log::instance()->log(
339
+						EEM_Change_Log::type_gateway,
340
+						array('IPN data' => $_req_data),
341
+						$payment_method
342
+					);
343
+				} elseif ($transaction) {
344
+					EEM_Change_Log::instance()->log(
345
+						EEM_Change_Log::type_gateway,
346
+						array('IPN data' => $_req_data),
347
+						$transaction
348
+					);
349
+				}
350
+			}
351
+			return $payment;
352
+		} catch (EE_Error $e) {
353
+			do_action(
354
+				'AHEE__log',
355
+				__FILE__,
356
+				__FUNCTION__,
357
+				sprintf(
358
+					esc_html__(
359
+						'Error occurred while receiving IPN. Transaction: %1$s, req data: %2$s. The error was "%3$s"',
360
+						'event_espresso'
361
+					),
362
+					print_r($transaction, true),
363
+					print_r($_req_data, true),
364
+					$e->getMessage()
365
+				)
366
+			);
367
+			throw $e;
368
+		}
369
+	}
370
+
371
+
372
+	/**
373
+	 * Removes any non-printable illegal characters from the input,
374
+	 * which might cause a raucous when trying to insert into the database
375
+	 *
376
+	 * @param  array $request_data
377
+	 * @return array
378
+	 */
379
+	protected function _remove_unusable_characters_from_array(array $request_data)
380
+	{
381
+		$return_data = array();
382
+		foreach ($request_data as $key => $value) {
383
+			$return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters(
384
+				$value
385
+			);
386
+		}
387
+		return $return_data;
388
+	}
389
+
390
+
391
+	/**
392
+	 * Removes any non-printable illegal characters from the input,
393
+	 * which might cause a raucous when trying to insert into the database
394
+	 *
395
+	 * @param string $request_data
396
+	 * @return string
397
+	 */
398
+	protected function _remove_unusable_characters($request_data)
399
+	{
400
+		return preg_replace('/[^[:print:]]/', '', $request_data);
401
+	}
402
+
403
+
404
+	/**
405
+	 * Should be called just before displaying the payment attempt results to the user,
406
+	 * when the payment attempt has finished. Some payment methods may have special
407
+	 * logic to perform here. For example, if process_payment() happens on a special request
408
+	 * and then the user is redirected to a page that displays the payment's status, this
409
+	 * should be called while loading the page that displays the payment's status. If the user is
410
+	 * sent to an offsite payment provider, this should be called upon returning from that offsite payment
411
+	 * provider.
412
+	 *
413
+	 * @param EE_Transaction|int $transaction
414
+	 * @param bool               $update_txn whether or not to call
415
+	 *                                       EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()
416
+	 * @return EE_Payment
417
+	 * @throws EE_Error
418
+	 * @throws InvalidArgumentException
419
+	 * @throws ReflectionException
420
+	 * @throws RuntimeException
421
+	 * @throws InvalidDataTypeException
422
+	 * @throws InvalidInterfaceException
423
+	 * @deprecated 4.6.24 method is no longer used. Instead it is up to client code, like SPCO,
424
+	 *                                       to call handle_ipn() for offsite gateways that don't receive separate IPNs
425
+	 */
426
+	public function finalize_payment_for($transaction, $update_txn = true)
427
+	{
428
+		/** @var $transaction EE_Transaction */
429
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
430
+		$last_payment_method = $transaction->payment_method();
431
+		if ($last_payment_method instanceof EE_Payment_Method) {
432
+			$payment = $last_payment_method->type_obj()->finalize_payment_for($transaction);
433
+			$this->update_txn_based_on_payment($transaction, $payment, $update_txn);
434
+			return $payment;
435
+		}
436
+		return null;
437
+	}
438
+
439
+
440
+	/**
441
+	 * Processes a direct refund request, saves the payment, and updates the transaction appropriately.
442
+	 *
443
+	 * @param EE_Payment_Method $payment_method
444
+	 * @param EE_Payment        $payment_to_refund
445
+	 * @param array             $refund_info
446
+	 * @return EE_Payment
447
+	 * @throws EE_Error
448
+	 * @throws InvalidArgumentException
449
+	 * @throws ReflectionException
450
+	 * @throws RuntimeException
451
+	 * @throws InvalidDataTypeException
452
+	 * @throws InvalidInterfaceException
453
+	 */
454
+	public function process_refund(
455
+		EE_Payment_Method $payment_method,
456
+		EE_Payment $payment_to_refund,
457
+		array $refund_info = array()
458
+	) {
459
+		if ($payment_method instanceof EE_Payment_Method && $payment_method->type_obj()->supports_sending_refunds()) {
460
+			$payment_method->type_obj()->process_refund($payment_to_refund, $refund_info);
461
+			$this->update_txn_based_on_payment($payment_to_refund->transaction(), $payment_to_refund);
462
+		}
463
+		return $payment_to_refund;
464
+	}
465
+
466
+
467
+	/**
468
+	 * This should be called each time there may have been an update to a
469
+	 * payment on a transaction (ie, we asked for a payment to process a
470
+	 * payment for a transaction, or we told a payment method about an IPN, or
471
+	 * we told a payment method to
472
+	 * "finalize_payment_for" (a transaction), or we told a payment method to
473
+	 * process a refund. This should handle firing the correct hooks to
474
+	 * indicate
475
+	 * what exactly happened and updating the transaction appropriately). This
476
+	 * could be integrated directly into EE_Transaction upon save, but we want
477
+	 * this logic to be separate from 'normal' plain-jane saving and updating
478
+	 * of transactions and payments, and to be tied to payment processing.
479
+	 * Note: this method DOES NOT save the payment passed into it. It is the responsibility
480
+	 * of previous code to decide whether or not to save (because the payment passed into
481
+	 * this method might be a temporary, never-to-be-saved payment from an offline gateway,
482
+	 * in which case we only want that payment object for some temporary usage during this request,
483
+	 * but we don't want it to be saved).
484
+	 *
485
+	 * @param EE_Transaction|int $transaction
486
+	 * @param EE_Payment         $payment
487
+	 * @param boolean            $update_txn
488
+	 *                        whether or not to call
489
+	 *                        EE_Transaction_Processor::
490
+	 *                        update_transaction_and_registrations_after_checkout_or_payment()
491
+	 *                        (you can save 1 DB query if you know you're going
492
+	 *                        to save it later instead)
493
+	 * @param bool               $IPN
494
+	 *                        if processing IPNs or other similar payment
495
+	 *                        related activities that occur in alternate
496
+	 *                        requests than the main one that is processing the
497
+	 *                        TXN, then set this to true to check whether the
498
+	 *                        TXN is locked before updating
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws ReflectionException
502
+	 * @throws RuntimeException
503
+	 * @throws InvalidDataTypeException
504
+	 * @throws InvalidInterfaceException
505
+	 */
506
+	public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false)
507
+	{
508
+		$do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful';
509
+		/** @type EE_Transaction $transaction */
510
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
511
+		// can we freely update the TXN at this moment?
512
+		if ($IPN && $transaction->is_locked()) {
513
+			// don't update the transaction at this exact moment
514
+			// because the TXN is active in another request
515
+			EE_Cron_Tasks::schedule_update_transaction_with_payment(
516
+				time(),
517
+				$transaction->ID(),
518
+				$payment->ID()
519
+			);
520
+		} else {
521
+			// verify payment and that it has been saved
522
+			if ($payment instanceof EE_Payment && $payment->ID()) {
523
+				if (
524
+					$payment->payment_method() instanceof EE_Payment_Method
525
+					&& $payment->payment_method()->type_obj() instanceof EE_PMT_Base
526
+				) {
527
+					$payment->payment_method()->type_obj()->update_txn_based_on_payment($payment);
528
+					// update TXN registrations with payment info
529
+					$this->process_registration_payments($transaction, $payment);
530
+				}
531
+				$do_action = $payment->just_approved()
532
+					? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful'
533
+					: $do_action;
534
+			} else {
535
+				// send out notifications
536
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
537
+				$do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made';
538
+			}
539
+			if ($payment instanceof EE_Payment && $payment->status() !== EEM_Payment::status_id_failed) {
540
+				/** @type EE_Transaction_Payments $transaction_payments */
541
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
542
+				// set new value for total paid
543
+				$transaction_payments->calculate_total_payments_and_update_status($transaction);
544
+				// call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ???
545
+				if ($update_txn) {
546
+					$this->_post_payment_processing($transaction, $payment, $IPN);
547
+				}
548
+			}
549
+			// granular hook for others to use.
550
+			do_action($do_action, $transaction, $payment);
551
+			do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action');
552
+			// global hook for others to use.
553
+			do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment);
554
+		}
555
+	}
556
+
557
+
558
+	/**
559
+	 * update registrations REG_paid field after successful payment and link registrations with payment
560
+	 *
561
+	 * @param EE_Transaction    $transaction
562
+	 * @param EE_Payment        $payment
563
+	 * @param EE_Registration[] $registrations
564
+	 * @throws EE_Error
565
+	 * @throws InvalidArgumentException
566
+	 * @throws RuntimeException
567
+	 * @throws InvalidDataTypeException
568
+	 * @throws InvalidInterfaceException
569
+	 */
570
+	public function process_registration_payments(
571
+		EE_Transaction $transaction,
572
+		EE_Payment $payment,
573
+		array $registrations = array()
574
+	) {
575
+		// only process if payment was successful
576
+		if ($payment->status() !== EEM_Payment::status_id_approved) {
577
+			return;
578
+		}
579
+		// EEM_Registration::instance()->show_next_x_db_queries();
580
+		if (empty($registrations)) {
581
+			// find registrations with monies owing that can receive a payment
582
+			$registrations = $transaction->registrations(
583
+				array(
584
+					array(
585
+						// only these reg statuses can receive payments
586
+						'STS_ID'           => array('IN', EEM_Registration::reg_statuses_that_allow_payment()),
587
+						'REG_final_price'  => array('!=', 0),
588
+						'REG_final_price*' => array('!=', 'REG_paid', true),
589
+					),
590
+				)
591
+			);
592
+		}
593
+		// still nothing ??!??
594
+		if (empty($registrations)) {
595
+			return;
596
+		}
597
+		// todo: break out the following logic into a separate strategy class
598
+		// todo: named something like "Sequential_Reg_Payment_Strategy"
599
+		// todo: which would apply payments using the capitalist "first come first paid" approach
600
+		// todo: then have another strategy class like "Distributed_Reg_Payment_Strategy"
601
+		// todo: which would be the socialist "everybody gets a piece of pie" approach,
602
+		// todo: which would be better for deposits, where you want a bit of the payment applied to each registration
603
+		$refund = $payment->is_a_refund();
604
+		// how much is available to apply to registrations?
605
+		$available_payment_amount = abs($payment->amount());
606
+		foreach ($registrations as $registration) {
607
+			if ($registration instanceof EE_Registration) {
608
+				// nothing left?
609
+				if ($available_payment_amount <= 0) {
610
+					break;
611
+				}
612
+				if ($refund) {
613
+					$available_payment_amount = $this->process_registration_refund(
614
+						$registration,
615
+						$payment,
616
+						$available_payment_amount
617
+					);
618
+				} else {
619
+					$available_payment_amount = $this->process_registration_payment(
620
+						$registration,
621
+						$payment,
622
+						$available_payment_amount
623
+					);
624
+				}
625
+			}
626
+		}
627
+		if (
628
+			$available_payment_amount > 0
629
+			&& apply_filters(
630
+				'FHEE__EE_Payment_Processor__process_registration_payments__display_notifications',
631
+				false
632
+			)
633
+		) {
634
+			EE_Error::add_attention(
635
+				sprintf(
636
+					esc_html__(
637
+						'A remainder of %1$s exists after applying this payment to Registration(s) %2$s.%3$sPlease verify that the original payment amount of %4$s is correct. If so, you should edit this payment and select at least one additional registration in the "Registrations to Apply Payment to" section, so that the remainder of this payment can be applied to the additional registration(s).',
638
+						'event_espresso'
639
+					),
640
+					EEH_Template::format_currency($available_payment_amount),
641
+					implode(', ', array_keys($registrations)),
642
+					'<br/>',
643
+					EEH_Template::format_currency($payment->amount())
644
+				),
645
+				__FILE__,
646
+				__FUNCTION__,
647
+				__LINE__
648
+			);
649
+		}
650
+	}
651
+
652
+
653
+	/**
654
+	 * update registration REG_paid field after successful payment and link registration with payment
655
+	 *
656
+	 * @param EE_Registration $registration
657
+	 * @param EE_Payment      $payment
658
+	 * @param float           $available_payment_amount
659
+	 * @return float
660
+	 * @throws EE_Error
661
+	 * @throws InvalidArgumentException
662
+	 * @throws RuntimeException
663
+	 * @throws InvalidDataTypeException
664
+	 * @throws InvalidInterfaceException
665
+	 */
666
+	public function process_registration_payment(
667
+		EE_Registration $registration,
668
+		EE_Payment $payment,
669
+		$available_payment_amount = 0.00
670
+	) {
671
+		$owing = $registration->final_price() - $registration->paid();
672
+		if ($owing > 0) {
673
+			// don't allow payment amount to exceed the available payment amount, OR the amount owing
674
+			$payment_amount = min($available_payment_amount, $owing);
675
+			// update $available_payment_amount
676
+			$available_payment_amount -= $payment_amount;
677
+			// calculate and set new REG_paid
678
+			$registration->set_paid($registration->paid() + $payment_amount);
679
+			// now save it
680
+			$this->_apply_registration_payment($registration, $payment, $payment_amount);
681
+		}
682
+		return $available_payment_amount;
683
+	}
684
+
685
+
686
+	/**
687
+	 * update registration REG_paid field after successful payment and link registration with payment
688
+	 *
689
+	 * @param EE_Registration $registration
690
+	 * @param EE_Payment      $payment
691
+	 * @param float           $payment_amount
692
+	 * @return void
693
+	 * @throws EE_Error
694
+	 * @throws InvalidArgumentException
695
+	 * @throws InvalidDataTypeException
696
+	 * @throws InvalidInterfaceException
697
+	 */
698
+	protected function _apply_registration_payment(
699
+		EE_Registration $registration,
700
+		EE_Payment $payment,
701
+		$payment_amount = 0.00
702
+	) {
703
+		// find any existing reg payment records for this registration and payment
704
+		$existing_reg_payment = EEM_Registration_Payment::instance()->get_one(
705
+			array(array('REG_ID' => $registration->ID(), 'PAY_ID' => $payment->ID()))
706
+		);
707
+		// if existing registration payment exists
708
+		if ($existing_reg_payment instanceof EE_Registration_Payment) {
709
+			// then update that record
710
+			$existing_reg_payment->set_amount($payment_amount);
711
+			$existing_reg_payment->save();
712
+		} else {
713
+			// or add new relation between registration and payment and set amount
714
+			$registration->_add_relation_to(
715
+				$payment,
716
+				'Payment',
717
+				array('RPY_amount' => $payment_amount)
718
+			);
719
+			// make it stick
720
+			$registration->save();
721
+		}
722
+	}
723
+
724
+
725
+	/**
726
+	 * update registration REG_paid field after refund and link registration with payment
727
+	 *
728
+	 * @param EE_Registration $registration
729
+	 * @param EE_Payment      $payment
730
+	 * @param float           $available_refund_amount - IMPORTANT !!! SEND AVAILABLE REFUND AMOUNT AS A POSITIVE NUMBER
731
+	 * @return float
732
+	 * @throws EE_Error
733
+	 * @throws InvalidArgumentException
734
+	 * @throws RuntimeException
735
+	 * @throws InvalidDataTypeException
736
+	 * @throws InvalidInterfaceException
737
+	 */
738
+	public function process_registration_refund(
739
+		EE_Registration $registration,
740
+		EE_Payment $payment,
741
+		$available_refund_amount = 0.00
742
+	) {
743
+		// EEH_Debug_Tools::printr( $payment->amount(), '$payment->amount()', __FILE__, __LINE__ );
744
+		if ($registration->paid() > 0) {
745
+			// ensure $available_refund_amount is NOT negative
746
+			$available_refund_amount = (float) abs($available_refund_amount);
747
+			// don't allow refund amount to exceed the available payment amount, OR the amount paid
748
+			$refund_amount = min($available_refund_amount, (float) $registration->paid());
749
+			// update $available_payment_amount
750
+			$available_refund_amount -= $refund_amount;
751
+			// calculate and set new REG_paid
752
+			$registration->set_paid($registration->paid() - $refund_amount);
753
+			// convert payment amount back to a negative value for storage in the db
754
+			$refund_amount = (float) abs($refund_amount) * -1;
755
+			// now save it
756
+			$this->_apply_registration_payment($registration, $payment, $refund_amount);
757
+		}
758
+		return $available_refund_amount;
759
+	}
760
+
761
+
762
+	/**
763
+	 * Process payments and transaction after payment process completed.
764
+	 * ultimately this will send the TXN and payment details off so that notifications can be sent out.
765
+	 * if this request happens to be processing an IPN,
766
+	 * then we will also set the Payment Options Reg Step to completed,
767
+	 * and attempt to completely finalize the TXN if all of the other Reg Steps are completed as well.
768
+	 *
769
+	 * @param EE_Transaction $transaction
770
+	 * @param EE_Payment     $payment
771
+	 * @param bool           $IPN
772
+	 * @throws EE_Error
773
+	 * @throws InvalidArgumentException
774
+	 * @throws ReflectionException
775
+	 * @throws RuntimeException
776
+	 * @throws InvalidDataTypeException
777
+	 * @throws InvalidInterfaceException
778
+	 */
779
+	protected function _post_payment_processing(EE_Transaction $transaction, EE_Payment $payment, $IPN = false)
780
+	{
781
+		/** @type EE_Transaction_Processor $transaction_processor */
782
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
783
+		// is the Payment Options Reg Step completed ?
784
+		$payment_options_step_completed = $transaction->reg_step_completed('payment_options');
785
+		// if the Payment Options Reg Step is completed...
786
+		$revisit = $payment_options_step_completed === true;
787
+		// then this is kinda sorta a revisit with regards to payments at least
788
+		$transaction_processor->set_revisit($revisit);
789
+		// if this is an IPN, let's consider the Payment Options Reg Step completed if not already
790
+		if (
791
+			$IPN
792
+			&& $payment_options_step_completed !== true
793
+			&& ($payment->is_approved() || $payment->is_pending())
794
+		) {
795
+			$payment_options_step_completed = $transaction->set_reg_step_completed(
796
+				'payment_options'
797
+			);
798
+		}
799
+		// maybe update status, but don't save transaction just yet
800
+		$transaction->update_status_based_on_total_paid(false);
801
+		// check if 'finalize_registration' step has been completed...
802
+		$finalized = $transaction->reg_step_completed('finalize_registration');
803
+		//  if this is an IPN and the final step has not been initiated
804
+		if ($IPN && $payment_options_step_completed && $finalized === false) {
805
+			// and if it hasn't already been set as being started...
806
+			$finalized = $transaction->set_reg_step_initiated('finalize_registration');
807
+		}
808
+		$transaction->save();
809
+		// because the above will return false if the final step was not fully completed, we need to check again...
810
+		if ($IPN && $finalized !== false) {
811
+			// and if we are all good to go, then send out notifications
812
+			add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
813
+			// ok, now process the transaction according to the payment
814
+			$transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
815
+				$transaction,
816
+				$payment
817
+			);
818
+		}
819
+		// DEBUG LOG
820
+		$payment_method = $payment->payment_method();
821
+		if ($payment_method instanceof EE_Payment_Method) {
822
+			$payment_method_type_obj = $payment_method->type_obj();
823
+			if ($payment_method_type_obj instanceof EE_PMT_Base) {
824
+				$gateway = $payment_method_type_obj->get_gateway();
825
+				if ($gateway instanceof EE_Gateway) {
826
+					$gateway->log(
827
+						array(
828
+							'message'               => (string) esc_html__('Post Payment Transaction Details', 'event_espresso'),
829
+							'transaction'           => $transaction->model_field_array(),
830
+							'finalized'             => $finalized,
831
+							'IPN'                   => $IPN,
832
+							'deliver_notifications' => has_filter(
833
+								'FHEE__EED_Messages___maybe_registration__deliver_notifications'
834
+							),
835
+						),
836
+						$payment
837
+					);
838
+				}
839
+			}
840
+		}
841
+	}
842
+
843
+
844
+	/**
845
+	 * Force posts to PayPal to use TLS v1.2. See:
846
+	 * https://core.trac.wordpress.org/ticket/36320
847
+	 * https://core.trac.wordpress.org/ticket/34924#comment:15
848
+	 * https://www.paypal-knowledge.com/infocenter/index?page=content&widgetview=true&id=FAQ1914&viewlocale=en_US
849
+	 * This will affect PayPal standard, pro, express, and Payflow.
850
+	 *
851
+	 * @param $handle
852
+	 * @param $r
853
+	 * @param $url
854
+	 */
855
+	public static function _curl_requests_to_paypal_use_tls($handle, $r, $url)
856
+	{
857
+		if (strpos($url, 'https://') !== false && strpos($url, '.paypal.com') !== false) {
858
+			// Use the value of the constant CURL_SSLVERSION_TLSv1 = 1
859
+			// instead of the constant because it might not be defined
860
+			curl_setopt($handle, CURLOPT_SSLVERSION, 6);
861
+		}
862
+	}
863 863
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -33,7 +33,7 @@  discard block
 block discarded – undo
33 33
     public static function instance()
34 34
     {
35 35
         // check if class object is instantiated
36
-        if (! self::$_instance instanceof EE_Payment_Processor) {
36
+        if ( ! self::$_instance instanceof EE_Payment_Processor) {
37 37
             self::$_instance = new self();
38 38
         }
39 39
         return self::$_instance;
@@ -170,7 +170,7 @@  discard block
 block discarded – undo
170 170
         /** @type \EE_Transaction $transaction */
171 171
         $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
172 172
         $primary_reg = $transaction->primary_registration();
173
-        if (! $primary_reg instanceof EE_Registration) {
173
+        if ( ! $primary_reg instanceof EE_Registration) {
174 174
             throw new EE_Error(
175 175
                 sprintf(
176 176
                     esc_html__(
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
                         EEM_Change_Log::instance()->log(
266 266
                             EEM_Change_Log::type_gateway,
267 267
                             array(
268
-                                'message'     => 'IPN Exception: ' . $e->getMessage(),
268
+                                'message'     => 'IPN Exception: '.$e->getMessage(),
269 269
                                 'current_url' => EEH_URL::current_url(),
270 270
                                 'payment'     => $e->getPaymentProperties(),
271 271
                                 'IPN_data'    => $e->getIpnData(),
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
                         EEM_Change_Log::instance()->log(
310 310
                             EEM_Change_Log::type_gateway,
311 311
                             array(
312
-                                'message'     => 'IPN Exception: ' . $e->getMessage(),
312
+                                'message'     => 'IPN Exception: '.$e->getMessage(),
313 313
                                 'current_url' => EEH_URL::current_url(),
314 314
                                 'payment'     => $e->getPaymentProperties(),
315 315
                                 'IPN_data'    => $e->getIpnData(),
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
     {
381 381
         $return_data = array();
382 382
         foreach ($request_data as $key => $value) {
383
-            $return_data[ $this->_remove_unusable_characters($key) ] = $this->_remove_unusable_characters(
383
+            $return_data[$this->_remove_unusable_characters($key)] = $this->_remove_unusable_characters(
384 384
                 $value
385 385
             );
386 386
         }
Please login to merge, or discard this patch.
core/services/assets/Registry.php 2 patches
Indentation   +773 added lines, -773 removed lines patch added patch discarded remove patch
@@ -26,784 +26,784 @@
 block discarded – undo
26 26
 class Registry
27 27
 {
28 28
 
29
-    const FILE_NAME_BUILD_MANIFEST = 'build-manifest.json';
30
-
31
-    /**
32
-     * @var AssetCollection $assets
33
-     */
34
-    protected $assets;
35
-
36
-    /**
37
-     * @var I18nRegistry
38
-     */
39
-    private $i18n_registry;
40
-
41
-    /**
42
-     * This holds the jsdata data object that will be exposed on pages that enqueue the `eejs-core` script.
43
-     *
44
-     * @var array
45
-     */
46
-    protected $jsdata = array();
47
-
48
-    /**
49
-     * This keeps track of all scripts with registered data.  It is used to prevent duplicate data objects setup in the
50
-     * page source.
51
-     *
52
-     * @var array
53
-     */
54
-    private $script_handles_with_data = array();
55
-
56
-
57
-    /**
58
-     * Holds the manifest data obtained from registered manifest files.
59
-     * Manifests are maps of asset chunk name to actual built asset file names.
60
-     * Shape of this array is:
61
-     * array(
62
-     *  'some_namespace_slug' => array(
63
-     *      'some_chunk_name' => array(
64
-     *          'js' => 'filename.js'
65
-     *          'css' => 'filename.js'
66
-     *      ),
67
-     *      'url_base' => 'https://baseurl.com/to/assets
68
-     *  )
69
-     * )
70
-     *
71
-     * @var array
72
-     */
73
-    private $manifest_data = array();
74
-
75
-
76
-    /**
77
-     * Holds any dependency data obtained from registered dependency map json.
78
-     * Dependency map json is generated via the @wordpress/dependency-extraction-webpack-plugin via the webpack config.
79
-     * @see https://github.com/WordPress/gutenberg/tree/master/packages/dependency-extraction-webpack-plugin
80
-     *
81
-     * @var array
82
-     */
83
-    private $dependencies_data = [];
84
-
85
-
86
-    /**
87
-     * This is a known array of possible wp css handles that correspond to what may be exposed as dependencies in our
88
-     * build process.  Currently the dependency export process in webpack does not consider css imports, so we derive
89
-     * them via the js dependencies (WP uses the same handle for both js and css). This is a list of known handles that
90
-     * are used for both js and css.
91
-     * @var array
92
-     */
93
-    private $wp_css_handle_dependencies = [
94
-        'wp-components',
95
-        'wp-block-editor',
96
-        'wp-block-library',
97
-        'wp-edit-post',
98
-        'wp-edit-widgets',
99
-        'wp-editor',
100
-        'wp-format-library',
101
-        'wp-list-reusable-blocks',
102
-        'wp-nux',
103
-    ];
104
-
105
-
106
-    /**
107
-     * Registry constructor.
108
-     * Hooking into WP actions for script registry.
109
-     *
110
-     * @param AssetCollection      $assets
111
-     * @param I18nRegistry         $i18n_registry
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     */
116
-    public function __construct(AssetCollection $assets, I18nRegistry $i18n_registry)
117
-    {
118
-        $this->assets = $assets;
119
-        $this->i18n_registry = $i18n_registry;
120
-        add_action('wp_enqueue_scripts', array($this, 'registerManifestFiles'), 1);
121
-        add_action('admin_enqueue_scripts', array($this, 'registerManifestFiles'), 1);
122
-        add_action('wp_enqueue_scripts', array($this, 'registerScriptsAndStyles'), 3);
123
-        add_action('admin_enqueue_scripts', array($this, 'registerScriptsAndStyles'), 3);
124
-        add_action('wp_enqueue_scripts', array($this, 'enqueueData'), 4);
125
-        add_action('admin_enqueue_scripts', array($this, 'enqueueData'), 4);
126
-        add_action('wp_print_footer_scripts', array($this, 'enqueueData'), 1);
127
-        add_action('admin_print_footer_scripts', array($this, 'enqueueData'), 1);
128
-    }
129
-
130
-
131
-    /**
132
-     * For classes that have Registry as a dependency, this provides a handy way to register script handles for i18n
133
-     * translation handling.
134
-     *
135
-     * @return I18nRegistry
136
-     */
137
-    public function getI18nRegistry()
138
-    {
139
-        return $this->i18n_registry;
140
-    }
141
-
142
-
143
-    /**
144
-     * Callback for the wp_enqueue_scripts actions used to register assets.
145
-     *
146
-     * @since 4.9.62.p
147
-     * @throws Exception
148
-     */
149
-    public function registerScriptsAndStyles()
150
-    {
151
-        try {
152
-            $this->registerScripts($this->assets->getJavascriptAssets());
153
-            $this->registerStyles($this->assets->getStylesheetAssets());
154
-        } catch (Exception $exception) {
155
-            new ExceptionStackTraceDisplay($exception);
156
-        }
157
-    }
158
-
159
-
160
-    /**
161
-     * Registers JS assets with WP core
162
-     *
163
-     * @param JavascriptAsset[] $scripts
164
-     * @throws AssetRegistrationException
165
-     * @throws InvalidDataTypeException
166
-     * @throws DomainException
167
-     * @since 4.9.62.p
168
-     */
169
-    public function registerScripts(array $scripts)
170
-    {
171
-        foreach ($scripts as $script) {
172
-            // skip to next script if this has already been done
173
-            if ($script->isRegistered()) {
174
-                continue;
175
-            }
176
-            do_action(
177
-                'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__before_script',
178
-                $script
179
-            );
180
-            $registered = wp_register_script(
181
-                $script->handle(),
182
-                $script->source(),
183
-                $script->dependencies(),
184
-                $script->version(),
185
-                $script->loadInFooter()
186
-            );
187
-            if (! $registered && $this->debug()) {
188
-                throw new AssetRegistrationException($script->handle());
189
-            }
190
-            $script->setRegistered($registered);
191
-            if ($script->requiresTranslation()) {
192
-                $this->registerTranslation($script->handle());
193
-            }
194
-            do_action(
195
-                'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__after_script',
196
-                $script
197
-            );
198
-        }
199
-    }
200
-
201
-
202
-    /**
203
-     * Registers CSS assets with WP core
204
-     *
205
-     * @param StylesheetAsset[] $styles
206
-     * @throws InvalidDataTypeException
207
-     * @throws DomainException
208
-     * @since 4.9.62.p
209
-     */
210
-    public function registerStyles(array $styles)
211
-    {
212
-        foreach ($styles as $style) {
213
-            // skip to next style if this has already been done
214
-            if ($style->isRegistered()) {
215
-                continue;
216
-            }
217
-            do_action(
218
-                'AHEE__EventEspresso_core_services_assets_Registry__registerStyles__before_style',
219
-                $style
220
-            );
221
-            wp_register_style(
222
-                $style->handle(),
223
-                $style->source(),
224
-                $style->dependencies(),
225
-                $style->version(),
226
-                $style->media()
227
-            );
228
-            $style->setRegistered();
229
-            do_action(
230
-                'AHEE__EventEspresso_core_services_assets_Registry__registerStyles__after_style',
231
-                $style
232
-            );
233
-        }
234
-    }
235
-
236
-
237
-    /**
238
-     * Call back for the script print in frontend and backend.
239
-     * Used to call wp_localize_scripts so that data can be added throughout the runtime until this later hook point.
240
-     *
241
-     * @since 4.9.31.rc.015
242
-     */
243
-    public function enqueueData()
244
-    {
245
-        $this->removeAlreadyRegisteredDataForScriptHandles();
246
-        wp_add_inline_script(
247
-            'eejs-core',
248
-            'var eejsdata=' . wp_json_encode(array('data' => $this->jsdata)),
249
-            'before'
250
-        );
251
-        $scripts = $this->assets->getJavascriptAssetsWithData();
252
-        foreach ($scripts as $script) {
253
-            $this->addRegisteredScriptHandlesWithData($script->handle());
254
-            if ($script->hasInlineDataCallback()) {
255
-                $localize = $script->inlineDataCallback();
256
-                $localize();
257
-            }
258
-        }
259
-    }
260
-
261
-
262
-    /**
263
-     * Used to add data to eejs.data object.
264
-     * Note:  Overriding existing data is not allowed.
265
-     * Data will be accessible as a javascript object when you list `eejs-core` as a dependency for your javascript.
266
-     * If the data you add is something like this:
267
-     *  $this->addData( 'my_plugin_data', array( 'foo' => 'gar' ) );
268
-     * It will be exposed in the page source as:
269
-     *  eejs.data.my_plugin_data.foo == gar
270
-     *
271
-     * @param string       $key   Key used to access your data
272
-     * @param string|array $value Value to attach to key
273
-     * @throws InvalidArgumentException
274
-     */
275
-    public function addData($key, $value)
276
-    {
277
-        if ($this->verifyDataNotExisting($key)) {
278
-            $this->jsdata[ $key ] = $value;
279
-        }
280
-    }
281
-
282
-
283
-    /**
284
-     * Similar to addData except this allows for users to push values to an existing key where the values on key are
285
-     * elements in an array.
286
-     *
287
-     * When you use this method, the value you include will be merged with the array on $key.
288
-     * So if the $key was 'test' and you added a value of ['my_data'] then it would be represented in the javascript
289
-     * object like this, eejs.data.test = [ my_data,
290
-     * ]
291
-     * If there has already been a scalar value attached to the data object given key (via addData for instance), then
292
-     * this will throw an exception.
293
-     *
294
-     * Caution: Only add data using this method if you are okay with the potential for additional data added on the same
295
-     * key potentially overriding the existing data on merge (specifically with associative arrays).
296
-     *
297
-     * @param string       $key   Key to attach data to.
298
-     * @param string|array $value Value being registered.
299
-     * @throws InvalidArgumentException
300
-     */
301
-    public function pushData($key, $value)
302
-    {
303
-        if (isset($this->jsdata[ $key ])
304
-            && ! is_array($this->jsdata[ $key ])
305
-        ) {
306
-            if (! $this->debug()) {
307
-                return;
308
-            }
309
-            throw new InvalidArgumentException(
310
-                sprintf(
311
-                    esc_html__(
312
-                        'The value for %1$s is already set and it is not an array. The %2$s method can only be used to
29
+	const FILE_NAME_BUILD_MANIFEST = 'build-manifest.json';
30
+
31
+	/**
32
+	 * @var AssetCollection $assets
33
+	 */
34
+	protected $assets;
35
+
36
+	/**
37
+	 * @var I18nRegistry
38
+	 */
39
+	private $i18n_registry;
40
+
41
+	/**
42
+	 * This holds the jsdata data object that will be exposed on pages that enqueue the `eejs-core` script.
43
+	 *
44
+	 * @var array
45
+	 */
46
+	protected $jsdata = array();
47
+
48
+	/**
49
+	 * This keeps track of all scripts with registered data.  It is used to prevent duplicate data objects setup in the
50
+	 * page source.
51
+	 *
52
+	 * @var array
53
+	 */
54
+	private $script_handles_with_data = array();
55
+
56
+
57
+	/**
58
+	 * Holds the manifest data obtained from registered manifest files.
59
+	 * Manifests are maps of asset chunk name to actual built asset file names.
60
+	 * Shape of this array is:
61
+	 * array(
62
+	 *  'some_namespace_slug' => array(
63
+	 *      'some_chunk_name' => array(
64
+	 *          'js' => 'filename.js'
65
+	 *          'css' => 'filename.js'
66
+	 *      ),
67
+	 *      'url_base' => 'https://baseurl.com/to/assets
68
+	 *  )
69
+	 * )
70
+	 *
71
+	 * @var array
72
+	 */
73
+	private $manifest_data = array();
74
+
75
+
76
+	/**
77
+	 * Holds any dependency data obtained from registered dependency map json.
78
+	 * Dependency map json is generated via the @wordpress/dependency-extraction-webpack-plugin via the webpack config.
79
+	 * @see https://github.com/WordPress/gutenberg/tree/master/packages/dependency-extraction-webpack-plugin
80
+	 *
81
+	 * @var array
82
+	 */
83
+	private $dependencies_data = [];
84
+
85
+
86
+	/**
87
+	 * This is a known array of possible wp css handles that correspond to what may be exposed as dependencies in our
88
+	 * build process.  Currently the dependency export process in webpack does not consider css imports, so we derive
89
+	 * them via the js dependencies (WP uses the same handle for both js and css). This is a list of known handles that
90
+	 * are used for both js and css.
91
+	 * @var array
92
+	 */
93
+	private $wp_css_handle_dependencies = [
94
+		'wp-components',
95
+		'wp-block-editor',
96
+		'wp-block-library',
97
+		'wp-edit-post',
98
+		'wp-edit-widgets',
99
+		'wp-editor',
100
+		'wp-format-library',
101
+		'wp-list-reusable-blocks',
102
+		'wp-nux',
103
+	];
104
+
105
+
106
+	/**
107
+	 * Registry constructor.
108
+	 * Hooking into WP actions for script registry.
109
+	 *
110
+	 * @param AssetCollection      $assets
111
+	 * @param I18nRegistry         $i18n_registry
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 */
116
+	public function __construct(AssetCollection $assets, I18nRegistry $i18n_registry)
117
+	{
118
+		$this->assets = $assets;
119
+		$this->i18n_registry = $i18n_registry;
120
+		add_action('wp_enqueue_scripts', array($this, 'registerManifestFiles'), 1);
121
+		add_action('admin_enqueue_scripts', array($this, 'registerManifestFiles'), 1);
122
+		add_action('wp_enqueue_scripts', array($this, 'registerScriptsAndStyles'), 3);
123
+		add_action('admin_enqueue_scripts', array($this, 'registerScriptsAndStyles'), 3);
124
+		add_action('wp_enqueue_scripts', array($this, 'enqueueData'), 4);
125
+		add_action('admin_enqueue_scripts', array($this, 'enqueueData'), 4);
126
+		add_action('wp_print_footer_scripts', array($this, 'enqueueData'), 1);
127
+		add_action('admin_print_footer_scripts', array($this, 'enqueueData'), 1);
128
+	}
129
+
130
+
131
+	/**
132
+	 * For classes that have Registry as a dependency, this provides a handy way to register script handles for i18n
133
+	 * translation handling.
134
+	 *
135
+	 * @return I18nRegistry
136
+	 */
137
+	public function getI18nRegistry()
138
+	{
139
+		return $this->i18n_registry;
140
+	}
141
+
142
+
143
+	/**
144
+	 * Callback for the wp_enqueue_scripts actions used to register assets.
145
+	 *
146
+	 * @since 4.9.62.p
147
+	 * @throws Exception
148
+	 */
149
+	public function registerScriptsAndStyles()
150
+	{
151
+		try {
152
+			$this->registerScripts($this->assets->getJavascriptAssets());
153
+			$this->registerStyles($this->assets->getStylesheetAssets());
154
+		} catch (Exception $exception) {
155
+			new ExceptionStackTraceDisplay($exception);
156
+		}
157
+	}
158
+
159
+
160
+	/**
161
+	 * Registers JS assets with WP core
162
+	 *
163
+	 * @param JavascriptAsset[] $scripts
164
+	 * @throws AssetRegistrationException
165
+	 * @throws InvalidDataTypeException
166
+	 * @throws DomainException
167
+	 * @since 4.9.62.p
168
+	 */
169
+	public function registerScripts(array $scripts)
170
+	{
171
+		foreach ($scripts as $script) {
172
+			// skip to next script if this has already been done
173
+			if ($script->isRegistered()) {
174
+				continue;
175
+			}
176
+			do_action(
177
+				'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__before_script',
178
+				$script
179
+			);
180
+			$registered = wp_register_script(
181
+				$script->handle(),
182
+				$script->source(),
183
+				$script->dependencies(),
184
+				$script->version(),
185
+				$script->loadInFooter()
186
+			);
187
+			if (! $registered && $this->debug()) {
188
+				throw new AssetRegistrationException($script->handle());
189
+			}
190
+			$script->setRegistered($registered);
191
+			if ($script->requiresTranslation()) {
192
+				$this->registerTranslation($script->handle());
193
+			}
194
+			do_action(
195
+				'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__after_script',
196
+				$script
197
+			);
198
+		}
199
+	}
200
+
201
+
202
+	/**
203
+	 * Registers CSS assets with WP core
204
+	 *
205
+	 * @param StylesheetAsset[] $styles
206
+	 * @throws InvalidDataTypeException
207
+	 * @throws DomainException
208
+	 * @since 4.9.62.p
209
+	 */
210
+	public function registerStyles(array $styles)
211
+	{
212
+		foreach ($styles as $style) {
213
+			// skip to next style if this has already been done
214
+			if ($style->isRegistered()) {
215
+				continue;
216
+			}
217
+			do_action(
218
+				'AHEE__EventEspresso_core_services_assets_Registry__registerStyles__before_style',
219
+				$style
220
+			);
221
+			wp_register_style(
222
+				$style->handle(),
223
+				$style->source(),
224
+				$style->dependencies(),
225
+				$style->version(),
226
+				$style->media()
227
+			);
228
+			$style->setRegistered();
229
+			do_action(
230
+				'AHEE__EventEspresso_core_services_assets_Registry__registerStyles__after_style',
231
+				$style
232
+			);
233
+		}
234
+	}
235
+
236
+
237
+	/**
238
+	 * Call back for the script print in frontend and backend.
239
+	 * Used to call wp_localize_scripts so that data can be added throughout the runtime until this later hook point.
240
+	 *
241
+	 * @since 4.9.31.rc.015
242
+	 */
243
+	public function enqueueData()
244
+	{
245
+		$this->removeAlreadyRegisteredDataForScriptHandles();
246
+		wp_add_inline_script(
247
+			'eejs-core',
248
+			'var eejsdata=' . wp_json_encode(array('data' => $this->jsdata)),
249
+			'before'
250
+		);
251
+		$scripts = $this->assets->getJavascriptAssetsWithData();
252
+		foreach ($scripts as $script) {
253
+			$this->addRegisteredScriptHandlesWithData($script->handle());
254
+			if ($script->hasInlineDataCallback()) {
255
+				$localize = $script->inlineDataCallback();
256
+				$localize();
257
+			}
258
+		}
259
+	}
260
+
261
+
262
+	/**
263
+	 * Used to add data to eejs.data object.
264
+	 * Note:  Overriding existing data is not allowed.
265
+	 * Data will be accessible as a javascript object when you list `eejs-core` as a dependency for your javascript.
266
+	 * If the data you add is something like this:
267
+	 *  $this->addData( 'my_plugin_data', array( 'foo' => 'gar' ) );
268
+	 * It will be exposed in the page source as:
269
+	 *  eejs.data.my_plugin_data.foo == gar
270
+	 *
271
+	 * @param string       $key   Key used to access your data
272
+	 * @param string|array $value Value to attach to key
273
+	 * @throws InvalidArgumentException
274
+	 */
275
+	public function addData($key, $value)
276
+	{
277
+		if ($this->verifyDataNotExisting($key)) {
278
+			$this->jsdata[ $key ] = $value;
279
+		}
280
+	}
281
+
282
+
283
+	/**
284
+	 * Similar to addData except this allows for users to push values to an existing key where the values on key are
285
+	 * elements in an array.
286
+	 *
287
+	 * When you use this method, the value you include will be merged with the array on $key.
288
+	 * So if the $key was 'test' and you added a value of ['my_data'] then it would be represented in the javascript
289
+	 * object like this, eejs.data.test = [ my_data,
290
+	 * ]
291
+	 * If there has already been a scalar value attached to the data object given key (via addData for instance), then
292
+	 * this will throw an exception.
293
+	 *
294
+	 * Caution: Only add data using this method if you are okay with the potential for additional data added on the same
295
+	 * key potentially overriding the existing data on merge (specifically with associative arrays).
296
+	 *
297
+	 * @param string       $key   Key to attach data to.
298
+	 * @param string|array $value Value being registered.
299
+	 * @throws InvalidArgumentException
300
+	 */
301
+	public function pushData($key, $value)
302
+	{
303
+		if (isset($this->jsdata[ $key ])
304
+			&& ! is_array($this->jsdata[ $key ])
305
+		) {
306
+			if (! $this->debug()) {
307
+				return;
308
+			}
309
+			throw new InvalidArgumentException(
310
+				sprintf(
311
+					esc_html__(
312
+						'The value for %1$s is already set and it is not an array. The %2$s method can only be used to
313 313
                          push values to this data element when it is an array.',
314
-                        'event_espresso'
315
-                    ),
316
-                    $key,
317
-                    __METHOD__
318
-                )
319
-            );
320
-        }
321
-        if ( ! isset( $this->jsdata[ $key ] ) ) {
322
-            $this->jsdata[ $key ] = is_array($value) ? $value : [$value];
323
-        } else {
324
-            $this->jsdata[ $key ] = array_merge( $this->jsdata[$key], (array) $value);
325
-        }
326
-    }
327
-
328
-
329
-    /**
330
-     * Used to set content used by javascript for a template.
331
-     * Note: Overrides of existing registered templates are not allowed.
332
-     *
333
-     * @param string $template_reference
334
-     * @param string $template_content
335
-     * @throws InvalidArgumentException
336
-     */
337
-    public function addTemplate($template_reference, $template_content)
338
-    {
339
-        if (! isset($this->jsdata['templates'])) {
340
-            $this->jsdata['templates'] = array();
341
-        }
342
-        //no overrides allowed.
343
-        if (isset($this->jsdata['templates'][ $template_reference ])) {
344
-            if (! $this->debug()) {
345
-                return;
346
-            }
347
-            throw new InvalidArgumentException(
348
-                sprintf(
349
-                    esc_html__(
350
-                        'The %1$s key already exists for the templates array in the js data array.  No overrides are allowed.',
351
-                        'event_espresso'
352
-                    ),
353
-                    $template_reference
354
-                )
355
-            );
356
-        }
357
-        $this->jsdata['templates'][ $template_reference ] = $template_content;
358
-    }
359
-
360
-
361
-    /**
362
-     * Retrieve the template content already registered for the given reference.
363
-     *
364
-     * @param string $template_reference
365
-     * @return string
366
-     */
367
-    public function getTemplate($template_reference)
368
-    {
369
-        return isset($this->jsdata['templates'][ $template_reference ])
370
-            ? $this->jsdata['templates'][ $template_reference ]
371
-            : '';
372
-    }
373
-
374
-
375
-    /**
376
-     * Retrieve registered data.
377
-     *
378
-     * @param string $key Name of key to attach data to.
379
-     * @return mixed                If there is no for the given key, then false is returned.
380
-     */
381
-    public function getData($key)
382
-    {
383
-        return isset($this->jsdata[ $key ])
384
-            ? $this->jsdata[ $key ]
385
-            : false;
386
-    }
387
-
388
-
389
-    /**
390
-     * Verifies whether the given data exists already on the jsdata array.
391
-     * Overriding data is not allowed.
392
-     *
393
-     * @param string $key Index for data.
394
-     * @return bool        If valid then return true.
395
-     * @throws InvalidArgumentException if data already exists.
396
-     */
397
-    protected function verifyDataNotExisting($key)
398
-    {
399
-        if (isset($this->jsdata[ $key ])) {
400
-            if (! $this->debug()) {
401
-                return false;
402
-            }
403
-            if (is_array($this->jsdata[ $key ])) {
404
-                throw new InvalidArgumentException(
405
-                    sprintf(
406
-                        esc_html__(
407
-                            'The value for %1$s already exists in the Registry::eejs object.
314
+						'event_espresso'
315
+					),
316
+					$key,
317
+					__METHOD__
318
+				)
319
+			);
320
+		}
321
+		if ( ! isset( $this->jsdata[ $key ] ) ) {
322
+			$this->jsdata[ $key ] = is_array($value) ? $value : [$value];
323
+		} else {
324
+			$this->jsdata[ $key ] = array_merge( $this->jsdata[$key], (array) $value);
325
+		}
326
+	}
327
+
328
+
329
+	/**
330
+	 * Used to set content used by javascript for a template.
331
+	 * Note: Overrides of existing registered templates are not allowed.
332
+	 *
333
+	 * @param string $template_reference
334
+	 * @param string $template_content
335
+	 * @throws InvalidArgumentException
336
+	 */
337
+	public function addTemplate($template_reference, $template_content)
338
+	{
339
+		if (! isset($this->jsdata['templates'])) {
340
+			$this->jsdata['templates'] = array();
341
+		}
342
+		//no overrides allowed.
343
+		if (isset($this->jsdata['templates'][ $template_reference ])) {
344
+			if (! $this->debug()) {
345
+				return;
346
+			}
347
+			throw new InvalidArgumentException(
348
+				sprintf(
349
+					esc_html__(
350
+						'The %1$s key already exists for the templates array in the js data array.  No overrides are allowed.',
351
+						'event_espresso'
352
+					),
353
+					$template_reference
354
+				)
355
+			);
356
+		}
357
+		$this->jsdata['templates'][ $template_reference ] = $template_content;
358
+	}
359
+
360
+
361
+	/**
362
+	 * Retrieve the template content already registered for the given reference.
363
+	 *
364
+	 * @param string $template_reference
365
+	 * @return string
366
+	 */
367
+	public function getTemplate($template_reference)
368
+	{
369
+		return isset($this->jsdata['templates'][ $template_reference ])
370
+			? $this->jsdata['templates'][ $template_reference ]
371
+			: '';
372
+	}
373
+
374
+
375
+	/**
376
+	 * Retrieve registered data.
377
+	 *
378
+	 * @param string $key Name of key to attach data to.
379
+	 * @return mixed                If there is no for the given key, then false is returned.
380
+	 */
381
+	public function getData($key)
382
+	{
383
+		return isset($this->jsdata[ $key ])
384
+			? $this->jsdata[ $key ]
385
+			: false;
386
+	}
387
+
388
+
389
+	/**
390
+	 * Verifies whether the given data exists already on the jsdata array.
391
+	 * Overriding data is not allowed.
392
+	 *
393
+	 * @param string $key Index for data.
394
+	 * @return bool        If valid then return true.
395
+	 * @throws InvalidArgumentException if data already exists.
396
+	 */
397
+	protected function verifyDataNotExisting($key)
398
+	{
399
+		if (isset($this->jsdata[ $key ])) {
400
+			if (! $this->debug()) {
401
+				return false;
402
+			}
403
+			if (is_array($this->jsdata[ $key ])) {
404
+				throw new InvalidArgumentException(
405
+					sprintf(
406
+						esc_html__(
407
+							'The value for %1$s already exists in the Registry::eejs object.
408 408
                             Overrides are not allowed. Since the value of this data is an array, you may want to use the
409 409
                             %2$s method to push your value to the array.',
410
-                            'event_espresso'
411
-                        ),
412
-                        $key,
413
-                        'pushData()'
414
-                    )
415
-                );
416
-            }
417
-            throw new InvalidArgumentException(
418
-                sprintf(
419
-                    esc_html__(
420
-                        'The value for %1$s already exists in the Registry::eejs object. Overrides are not
410
+							'event_espresso'
411
+						),
412
+						$key,
413
+						'pushData()'
414
+					)
415
+				);
416
+			}
417
+			throw new InvalidArgumentException(
418
+				sprintf(
419
+					esc_html__(
420
+						'The value for %1$s already exists in the Registry::eejs object. Overrides are not
421 421
                         allowed.  Consider attaching your value to a different key',
422
-                        'event_espresso'
423
-                    ),
424
-                    $key
425
-                )
426
-            );
427
-        }
428
-        return true;
429
-    }
430
-
431
-
432
-    /**
433
-     * Get the actual asset path for asset manifests.
434
-     * If there is no asset path found for the given $chunk_name, then the $chunk_name is returned.
435
-     *
436
-     * @param string $namespace  The namespace associated with the manifest file hosting the map of chunk_name to actual
437
-     *                           asset file location.
438
-     * @param string $chunk_name
439
-     * @param string $asset_type
440
-     * @return string
441
-     * @since 4.9.59.p
442
-     */
443
-    public function getAssetUrl($namespace, $chunk_name, $asset_type)
444
-    {
445
-        $url = isset(
446
-            $this->manifest_data[ $namespace ][ $chunk_name . '.' . $asset_type ],
447
-            $this->manifest_data[ $namespace ]['url_base']
448
-        )
449
-            ? $this->manifest_data[ $namespace ]['url_base']
450
-              . $this->manifest_data[ $namespace ][ $chunk_name . '.' . $asset_type ]
451
-            : $chunk_name;
452
-
453
-        return apply_filters(
454
-            'FHEE__EventEspresso_core_services_assets_Registry__getAssetUrl',
455
-            $url,
456
-            $namespace,
457
-            $chunk_name,
458
-            $asset_type
459
-        );
460
-    }
461
-
462
-
463
-
464
-    /**
465
-     * Return the url to a js file for the given namespace and chunk name.
466
-     *
467
-     * @param string $namespace
468
-     * @param string $chunk_name
469
-     * @return string
470
-     */
471
-    public function getJsUrl($namespace, $chunk_name)
472
-    {
473
-        return $this->getAssetUrl($namespace, $chunk_name, Asset::TYPE_JS);
474
-    }
475
-
476
-
477
-    /**
478
-     * Return the url to a css file for the given namespace and chunk name.
479
-     *
480
-     * @param string $namespace
481
-     * @param string $chunk_name
482
-     * @return string
483
-     */
484
-    public function getCssUrl($namespace, $chunk_name)
485
-    {
486
-        return $this->getAssetUrl($namespace, $chunk_name, Asset::TYPE_CSS);
487
-    }
488
-
489
-
490
-    /**
491
-     * Return the dependencies array and version string for a given asset $chunk_name
492
-     *
493
-     * @param string $namespace
494
-     * @param string $chunk_name
495
-     * @param string $asset_type
496
-     * @return array
497
-     * @since 4.9.82.p
498
-     */
499
-    private function getDetailsForAsset($namespace, $chunk_name, $asset_type)
500
-    {
501
-        $asset_index = $chunk_name . '.' . $asset_type;
502
-        if (! isset( $this->dependencies_data[ $namespace ][ $asset_index ])) {
503
-            $path = isset($this->manifest_data[ $namespace ]['path'])
504
-                ? $this->manifest_data[ $namespace ]['path']
505
-                : '';
506
-            $dependencies_index = $chunk_name . '.' . Asset::TYPE_PHP;
507
-            $file_path = isset($this->manifest_data[ $namespace ][ $dependencies_index ])
508
-                ? $path . $this->manifest_data[ $namespace ][ $dependencies_index ]
509
-                :
510
-                '';
511
-            $this->dependencies_data[ $namespace ][ $asset_index ] = $file_path !== '' && file_exists($file_path)
512
-                ? $this->getDetailsForAssetType($namespace, $asset_type, $file_path, $chunk_name)
513
-                : [];
514
-        }
515
-        $details = $this->dependencies_data[ $namespace ][ $asset_index ];
516
-        return $details;
517
-    }
518
-
519
-
520
-    /**
521
-     * Return dependencies array and version string according to asset type.
522
-     * For css assets, this filters the auto generated dependencies by css type.
523
-     *
524
-     * @param string $namespace
525
-     * @param string $asset_type
526
-     * @param string $file_path
527
-     * @param string $chunk_name
528
-     * @return array
529
-     * @since 4.9.82.p
530
-     */
531
-    private function getDetailsForAssetType($namespace, $asset_type, $file_path, $chunk_name)
532
-    {
533
-        // $asset_dependencies = json_decode(file_get_contents($file_path), true);
534
-        $asset_details = require($file_path);
535
-        $asset_details['dependencies'] = isset($asset_details['dependencies'])
536
-            ? $asset_details['dependencies']
537
-            : [];
538
-        $asset_details['version'] = isset($asset_details['version'])
539
-            ? $asset_details['version']
540
-            : '';
541
-        if ($asset_type === Asset::TYPE_JS) {
542
-            $asset_details['dependencies'] =  $chunk_name === 'eejs-core'
543
-                ? $asset_details['dependencies']
544
-                : $asset_details['dependencies'] + [ CoreAssetManager::JS_HANDLE_JS_CORE ];
545
-            return $asset_details;
546
-        }
547
-        // for css we need to make sure there is actually a css file related to this chunk.
548
-        if (isset($this->manifest_data[ $namespace ])) {
549
-            // array of css chunk files for ee.
550
-            $css_chunks = array_map(
551
-                static function ($value) {
552
-                    return str_replace('.css', '', $value);
553
-                },
554
-                array_filter(
555
-                    array_keys($this->manifest_data[ $namespace ]),
556
-                    static function ($value) {
557
-                        return strpos($value, '.css') !== false;
558
-                    }
559
-                )
560
-            );
561
-            // add known wp chunks with css
562
-            $css_chunks = array_merge( $css_chunks, $this->wp_css_handle_dependencies);
563
-            // flip for easier search
564
-            $css_chunks = array_flip($css_chunks);
565
-            // now let's filter the dependencies for the incoming chunk to actual chunks that have styles
566
-            $asset_details['dependencies'] = array_filter(
567
-                $asset_details['dependencies'],
568
-                static function ($chunk_name) use ($css_chunks) {
569
-                    return isset($css_chunks[ $chunk_name ]);
570
-                }
571
-            );
572
-            return $asset_details;
573
-        }
574
-        return ['dependencies' => [], 'version' => ''];
575
-    }
576
-
577
-
578
-    /**
579
-     * Get the dependencies array and version string for the given js asset chunk name
580
-     *
581
-     * @param string $namespace
582
-     * @param string $chunk_name
583
-     * @return array
584
-     * @since 4.10.2.p
585
-     */
586
-    public function getJsAssetDetails($namespace, $chunk_name)
587
-    {
588
-        return $this->getDetailsForAsset($namespace, $chunk_name, Asset::TYPE_JS);
589
-    }
590
-
591
-
592
-    /**
593
-     * Get the dependencies array and version string for the given css asset chunk name
594
-     *
595
-     * @param string $namespace
596
-     * @param string $chunk_name
597
-     * @return array
598
-     * @since 4.10.2.p
599
-     */
600
-    public function getCssAssetDetails($namespace, $chunk_name)
601
-    {
602
-        return $this->getDetailsForAsset($namespace, $chunk_name, Asset::TYPE_CSS);
603
-    }
604
-
605
-
606
-    /**
607
-     * @since 4.9.62.p
608
-     * @throws InvalidArgumentException
609
-     * @throws InvalidFilePathException
610
-     */
611
-    public function registerManifestFiles()
612
-    {
613
-        $manifest_files = $this->assets->getManifestFiles();
614
-        foreach ($manifest_files as $manifest_file) {
615
-            $this->registerManifestFile(
616
-                $manifest_file->assetNamespace(),
617
-                $manifest_file->urlBase(),
618
-                $manifest_file->filepath() . Registry::FILE_NAME_BUILD_MANIFEST,
619
-                $manifest_file->filepath()
620
-            );
621
-        }
622
-    }
623
-
624
-
625
-    /**
626
-     * Used to register a js/css manifest file with the registered_manifest_files property.
627
-     *
628
-     * @param string $namespace     Provided to associate the manifest file with a specific namespace.
629
-     * @param string $url_base      The url base for the manifest file location.
630
-     * @param string $manifest_file The absolute path to the manifest file.
631
-     * @param string $manifest_file_path  The path to the folder containing the manifest file. If not provided will be
632
-     *                                    default to `plugin_root/assets/dist`.
633
-     * @throws InvalidArgumentException
634
-     * @throws InvalidFilePathException
635
-     * @since 4.9.59.p
636
-     */
637
-    public function registerManifestFile($namespace, $url_base, $manifest_file, $manifest_file_path = '')
638
-    {
639
-        if (isset($this->manifest_data[ $namespace ])) {
640
-            if (! $this->debug()) {
641
-                return;
642
-            }
643
-            throw new InvalidArgumentException(
644
-                sprintf(
645
-                    esc_html__(
646
-                        'The namespace for this manifest file has already been registered, choose a namespace other than %s',
647
-                        'event_espresso'
648
-                    ),
649
-                    $namespace
650
-                )
651
-            );
652
-        }
653
-        if (filter_var($url_base, FILTER_VALIDATE_URL) === false) {
654
-            if (is_admin()) {
655
-                EE_Error::add_error(
656
-                    sprintf(
657
-                        esc_html__(
658
-                            'The url given for %1$s assets is invalid.  The url provided was: "%2$s". This usually happens when another plugin or theme on a site is using the "%3$s" filter or has an invalid url set for the "%4$s" constant',
659
-                            'event_espresso'
660
-                        ),
661
-                        'Event Espresso',
662
-                        $url_base,
663
-                        'plugins_url',
664
-                        'WP_PLUGIN_URL'
665
-                    ),
666
-                    __FILE__,
667
-                    __FUNCTION__,
668
-                    __LINE__
669
-                );
670
-            }
671
-            return;
672
-        }
673
-        $this->manifest_data[ $namespace ] = $this->decodeManifestFile($manifest_file);
674
-        if (! isset($this->manifest_data[ $namespace ]['url_base'])) {
675
-            $this->manifest_data[ $namespace ]['url_base'] = trailingslashit($url_base);
676
-        }
677
-        if (! isset($this->manifest_data[ $namespace ]['path'])) {
678
-            $this->manifest_data[ $namespace ]['path'] = $manifest_file_path;
679
-        }
680
-    }
681
-
682
-
683
-    /**
684
-     * Decodes json from the provided manifest file.
685
-     *
686
-     * @since 4.9.59.p
687
-     * @param string $manifest_file Path to manifest file.
688
-     * @return array
689
-     * @throws InvalidFilePathException
690
-     */
691
-    private function decodeManifestFile($manifest_file)
692
-    {
693
-        if (! file_exists($manifest_file)) {
694
-            throw new InvalidFilePathException($manifest_file);
695
-        }
696
-        return json_decode(file_get_contents($manifest_file), true);
697
-    }
698
-
699
-
700
-    /**
701
-     * This is used to set registered script handles that have data.
702
-     *
703
-     * @param string $script_handle
704
-     */
705
-    private function addRegisteredScriptHandlesWithData($script_handle)
706
-    {
707
-        $this->script_handles_with_data[ $script_handle ] = $script_handle;
708
-    }
709
-
710
-
711
-    /**i
422
+						'event_espresso'
423
+					),
424
+					$key
425
+				)
426
+			);
427
+		}
428
+		return true;
429
+	}
430
+
431
+
432
+	/**
433
+	 * Get the actual asset path for asset manifests.
434
+	 * If there is no asset path found for the given $chunk_name, then the $chunk_name is returned.
435
+	 *
436
+	 * @param string $namespace  The namespace associated with the manifest file hosting the map of chunk_name to actual
437
+	 *                           asset file location.
438
+	 * @param string $chunk_name
439
+	 * @param string $asset_type
440
+	 * @return string
441
+	 * @since 4.9.59.p
442
+	 */
443
+	public function getAssetUrl($namespace, $chunk_name, $asset_type)
444
+	{
445
+		$url = isset(
446
+			$this->manifest_data[ $namespace ][ $chunk_name . '.' . $asset_type ],
447
+			$this->manifest_data[ $namespace ]['url_base']
448
+		)
449
+			? $this->manifest_data[ $namespace ]['url_base']
450
+			  . $this->manifest_data[ $namespace ][ $chunk_name . '.' . $asset_type ]
451
+			: $chunk_name;
452
+
453
+		return apply_filters(
454
+			'FHEE__EventEspresso_core_services_assets_Registry__getAssetUrl',
455
+			$url,
456
+			$namespace,
457
+			$chunk_name,
458
+			$asset_type
459
+		);
460
+	}
461
+
462
+
463
+
464
+	/**
465
+	 * Return the url to a js file for the given namespace and chunk name.
466
+	 *
467
+	 * @param string $namespace
468
+	 * @param string $chunk_name
469
+	 * @return string
470
+	 */
471
+	public function getJsUrl($namespace, $chunk_name)
472
+	{
473
+		return $this->getAssetUrl($namespace, $chunk_name, Asset::TYPE_JS);
474
+	}
475
+
476
+
477
+	/**
478
+	 * Return the url to a css file for the given namespace and chunk name.
479
+	 *
480
+	 * @param string $namespace
481
+	 * @param string $chunk_name
482
+	 * @return string
483
+	 */
484
+	public function getCssUrl($namespace, $chunk_name)
485
+	{
486
+		return $this->getAssetUrl($namespace, $chunk_name, Asset::TYPE_CSS);
487
+	}
488
+
489
+
490
+	/**
491
+	 * Return the dependencies array and version string for a given asset $chunk_name
492
+	 *
493
+	 * @param string $namespace
494
+	 * @param string $chunk_name
495
+	 * @param string $asset_type
496
+	 * @return array
497
+	 * @since 4.9.82.p
498
+	 */
499
+	private function getDetailsForAsset($namespace, $chunk_name, $asset_type)
500
+	{
501
+		$asset_index = $chunk_name . '.' . $asset_type;
502
+		if (! isset( $this->dependencies_data[ $namespace ][ $asset_index ])) {
503
+			$path = isset($this->manifest_data[ $namespace ]['path'])
504
+				? $this->manifest_data[ $namespace ]['path']
505
+				: '';
506
+			$dependencies_index = $chunk_name . '.' . Asset::TYPE_PHP;
507
+			$file_path = isset($this->manifest_data[ $namespace ][ $dependencies_index ])
508
+				? $path . $this->manifest_data[ $namespace ][ $dependencies_index ]
509
+				:
510
+				'';
511
+			$this->dependencies_data[ $namespace ][ $asset_index ] = $file_path !== '' && file_exists($file_path)
512
+				? $this->getDetailsForAssetType($namespace, $asset_type, $file_path, $chunk_name)
513
+				: [];
514
+		}
515
+		$details = $this->dependencies_data[ $namespace ][ $asset_index ];
516
+		return $details;
517
+	}
518
+
519
+
520
+	/**
521
+	 * Return dependencies array and version string according to asset type.
522
+	 * For css assets, this filters the auto generated dependencies by css type.
523
+	 *
524
+	 * @param string $namespace
525
+	 * @param string $asset_type
526
+	 * @param string $file_path
527
+	 * @param string $chunk_name
528
+	 * @return array
529
+	 * @since 4.9.82.p
530
+	 */
531
+	private function getDetailsForAssetType($namespace, $asset_type, $file_path, $chunk_name)
532
+	{
533
+		// $asset_dependencies = json_decode(file_get_contents($file_path), true);
534
+		$asset_details = require($file_path);
535
+		$asset_details['dependencies'] = isset($asset_details['dependencies'])
536
+			? $asset_details['dependencies']
537
+			: [];
538
+		$asset_details['version'] = isset($asset_details['version'])
539
+			? $asset_details['version']
540
+			: '';
541
+		if ($asset_type === Asset::TYPE_JS) {
542
+			$asset_details['dependencies'] =  $chunk_name === 'eejs-core'
543
+				? $asset_details['dependencies']
544
+				: $asset_details['dependencies'] + [ CoreAssetManager::JS_HANDLE_JS_CORE ];
545
+			return $asset_details;
546
+		}
547
+		// for css we need to make sure there is actually a css file related to this chunk.
548
+		if (isset($this->manifest_data[ $namespace ])) {
549
+			// array of css chunk files for ee.
550
+			$css_chunks = array_map(
551
+				static function ($value) {
552
+					return str_replace('.css', '', $value);
553
+				},
554
+				array_filter(
555
+					array_keys($this->manifest_data[ $namespace ]),
556
+					static function ($value) {
557
+						return strpos($value, '.css') !== false;
558
+					}
559
+				)
560
+			);
561
+			// add known wp chunks with css
562
+			$css_chunks = array_merge( $css_chunks, $this->wp_css_handle_dependencies);
563
+			// flip for easier search
564
+			$css_chunks = array_flip($css_chunks);
565
+			// now let's filter the dependencies for the incoming chunk to actual chunks that have styles
566
+			$asset_details['dependencies'] = array_filter(
567
+				$asset_details['dependencies'],
568
+				static function ($chunk_name) use ($css_chunks) {
569
+					return isset($css_chunks[ $chunk_name ]);
570
+				}
571
+			);
572
+			return $asset_details;
573
+		}
574
+		return ['dependencies' => [], 'version' => ''];
575
+	}
576
+
577
+
578
+	/**
579
+	 * Get the dependencies array and version string for the given js asset chunk name
580
+	 *
581
+	 * @param string $namespace
582
+	 * @param string $chunk_name
583
+	 * @return array
584
+	 * @since 4.10.2.p
585
+	 */
586
+	public function getJsAssetDetails($namespace, $chunk_name)
587
+	{
588
+		return $this->getDetailsForAsset($namespace, $chunk_name, Asset::TYPE_JS);
589
+	}
590
+
591
+
592
+	/**
593
+	 * Get the dependencies array and version string for the given css asset chunk name
594
+	 *
595
+	 * @param string $namespace
596
+	 * @param string $chunk_name
597
+	 * @return array
598
+	 * @since 4.10.2.p
599
+	 */
600
+	public function getCssAssetDetails($namespace, $chunk_name)
601
+	{
602
+		return $this->getDetailsForAsset($namespace, $chunk_name, Asset::TYPE_CSS);
603
+	}
604
+
605
+
606
+	/**
607
+	 * @since 4.9.62.p
608
+	 * @throws InvalidArgumentException
609
+	 * @throws InvalidFilePathException
610
+	 */
611
+	public function registerManifestFiles()
612
+	{
613
+		$manifest_files = $this->assets->getManifestFiles();
614
+		foreach ($manifest_files as $manifest_file) {
615
+			$this->registerManifestFile(
616
+				$manifest_file->assetNamespace(),
617
+				$manifest_file->urlBase(),
618
+				$manifest_file->filepath() . Registry::FILE_NAME_BUILD_MANIFEST,
619
+				$manifest_file->filepath()
620
+			);
621
+		}
622
+	}
623
+
624
+
625
+	/**
626
+	 * Used to register a js/css manifest file with the registered_manifest_files property.
627
+	 *
628
+	 * @param string $namespace     Provided to associate the manifest file with a specific namespace.
629
+	 * @param string $url_base      The url base for the manifest file location.
630
+	 * @param string $manifest_file The absolute path to the manifest file.
631
+	 * @param string $manifest_file_path  The path to the folder containing the manifest file. If not provided will be
632
+	 *                                    default to `plugin_root/assets/dist`.
633
+	 * @throws InvalidArgumentException
634
+	 * @throws InvalidFilePathException
635
+	 * @since 4.9.59.p
636
+	 */
637
+	public function registerManifestFile($namespace, $url_base, $manifest_file, $manifest_file_path = '')
638
+	{
639
+		if (isset($this->manifest_data[ $namespace ])) {
640
+			if (! $this->debug()) {
641
+				return;
642
+			}
643
+			throw new InvalidArgumentException(
644
+				sprintf(
645
+					esc_html__(
646
+						'The namespace for this manifest file has already been registered, choose a namespace other than %s',
647
+						'event_espresso'
648
+					),
649
+					$namespace
650
+				)
651
+			);
652
+		}
653
+		if (filter_var($url_base, FILTER_VALIDATE_URL) === false) {
654
+			if (is_admin()) {
655
+				EE_Error::add_error(
656
+					sprintf(
657
+						esc_html__(
658
+							'The url given for %1$s assets is invalid.  The url provided was: "%2$s". This usually happens when another plugin or theme on a site is using the "%3$s" filter or has an invalid url set for the "%4$s" constant',
659
+							'event_espresso'
660
+						),
661
+						'Event Espresso',
662
+						$url_base,
663
+						'plugins_url',
664
+						'WP_PLUGIN_URL'
665
+					),
666
+					__FILE__,
667
+					__FUNCTION__,
668
+					__LINE__
669
+				);
670
+			}
671
+			return;
672
+		}
673
+		$this->manifest_data[ $namespace ] = $this->decodeManifestFile($manifest_file);
674
+		if (! isset($this->manifest_data[ $namespace ]['url_base'])) {
675
+			$this->manifest_data[ $namespace ]['url_base'] = trailingslashit($url_base);
676
+		}
677
+		if (! isset($this->manifest_data[ $namespace ]['path'])) {
678
+			$this->manifest_data[ $namespace ]['path'] = $manifest_file_path;
679
+		}
680
+	}
681
+
682
+
683
+	/**
684
+	 * Decodes json from the provided manifest file.
685
+	 *
686
+	 * @since 4.9.59.p
687
+	 * @param string $manifest_file Path to manifest file.
688
+	 * @return array
689
+	 * @throws InvalidFilePathException
690
+	 */
691
+	private function decodeManifestFile($manifest_file)
692
+	{
693
+		if (! file_exists($manifest_file)) {
694
+			throw new InvalidFilePathException($manifest_file);
695
+		}
696
+		return json_decode(file_get_contents($manifest_file), true);
697
+	}
698
+
699
+
700
+	/**
701
+	 * This is used to set registered script handles that have data.
702
+	 *
703
+	 * @param string $script_handle
704
+	 */
705
+	private function addRegisteredScriptHandlesWithData($script_handle)
706
+	{
707
+		$this->script_handles_with_data[ $script_handle ] = $script_handle;
708
+	}
709
+
710
+
711
+	/**i
712 712
      * Checks WP_Scripts for all of each script handle registered internally as having data and unsets from the
713 713
      * Dependency stored in WP_Scripts if its set.
714 714
      */
715
-    private function removeAlreadyRegisteredDataForScriptHandles()
716
-    {
717
-        if (empty($this->script_handles_with_data)) {
718
-            return;
719
-        }
720
-        foreach ($this->script_handles_with_data as $script_handle) {
721
-            $this->removeAlreadyRegisteredDataForScriptHandle($script_handle);
722
-        }
723
-    }
724
-
725
-
726
-    /**
727
-     * Removes any data dependency registered in WP_Scripts if its set.
728
-     *
729
-     * @param string $script_handle
730
-     */
731
-    private function removeAlreadyRegisteredDataForScriptHandle($script_handle)
732
-    {
733
-        if (isset($this->script_handles_with_data[ $script_handle ])) {
734
-            global $wp_scripts;
735
-            $unset_handle = false;
736
-            if ($wp_scripts->get_data($script_handle, 'data')) {
737
-                unset($wp_scripts->registered[ $script_handle ]->extra['data']);
738
-                $unset_handle = true;
739
-            }
740
-            //deal with inline_scripts
741
-            if ($wp_scripts->get_data($script_handle, 'before')) {
742
-                unset($wp_scripts->registered[ $script_handle ]->extra['before']);
743
-                $unset_handle = true;
744
-            }
745
-            if ($wp_scripts->get_data($script_handle, 'after')) {
746
-                unset($wp_scripts->registered[ $script_handle ]->extra['after']);
747
-            }
748
-            if ($unset_handle) {
749
-                unset($this->script_handles_with_data[ $script_handle ]);
750
-            }
751
-        }
752
-    }
753
-
754
-
755
-    /**
756
-     * register translations for a registered script
757
-     *
758
-     * @param string $handle
759
-     */
760
-    public function registerTranslation($handle)
761
-    {
762
-        $this->i18n_registry->registerScriptI18n($handle);
763
-    }
764
-
765
-
766
-    /**
767
-     * @since 4.9.63.p
768
-     * @return bool
769
-     */
770
-    private function debug()
771
-    {
772
-        return apply_filters(
773
-            'FHEE__EventEspresso_core_services_assets_Registry__debug',
774
-            defined('EE_DEBUG') && EE_DEBUG
775
-        );
776
-    }
777
-
778
-
779
-    /**
780
-     * Get the dependencies array for the given js asset chunk name
781
-     *
782
-     * @param string $namespace
783
-     * @param string $chunk_name
784
-     * @return array
785
-     * @deprecated 4.10.2.p
786
-     * @since 4.9.82.p
787
-     */
788
-    public function getJsDependencies($namespace, $chunk_name)
789
-    {
790
-        $details = $this->getJsAssetDetails($namespace, $chunk_name);
791
-        return isset($details['dependencies']) ? $details['dependencies'] : [];
792
-    }
793
-
794
-
795
-    /**
796
-     * Get the dependencies array for the given css asset chunk name
797
-     *
798
-     * @param string $namespace
799
-     * @param string $chunk_name
800
-     * @return array
801
-     * @deprecated 4.10.2.p
802
-     * @since      4.9.82.p
803
-     */
804
-    public function getCssDependencies($namespace, $chunk_name)
805
-    {
806
-        $details = $this->getCssAssetDetails($namespace, $chunk_name);
807
-        return isset($details['dependencies']) ? $details['dependencies'] : [];
808
-    }
715
+	private function removeAlreadyRegisteredDataForScriptHandles()
716
+	{
717
+		if (empty($this->script_handles_with_data)) {
718
+			return;
719
+		}
720
+		foreach ($this->script_handles_with_data as $script_handle) {
721
+			$this->removeAlreadyRegisteredDataForScriptHandle($script_handle);
722
+		}
723
+	}
724
+
725
+
726
+	/**
727
+	 * Removes any data dependency registered in WP_Scripts if its set.
728
+	 *
729
+	 * @param string $script_handle
730
+	 */
731
+	private function removeAlreadyRegisteredDataForScriptHandle($script_handle)
732
+	{
733
+		if (isset($this->script_handles_with_data[ $script_handle ])) {
734
+			global $wp_scripts;
735
+			$unset_handle = false;
736
+			if ($wp_scripts->get_data($script_handle, 'data')) {
737
+				unset($wp_scripts->registered[ $script_handle ]->extra['data']);
738
+				$unset_handle = true;
739
+			}
740
+			//deal with inline_scripts
741
+			if ($wp_scripts->get_data($script_handle, 'before')) {
742
+				unset($wp_scripts->registered[ $script_handle ]->extra['before']);
743
+				$unset_handle = true;
744
+			}
745
+			if ($wp_scripts->get_data($script_handle, 'after')) {
746
+				unset($wp_scripts->registered[ $script_handle ]->extra['after']);
747
+			}
748
+			if ($unset_handle) {
749
+				unset($this->script_handles_with_data[ $script_handle ]);
750
+			}
751
+		}
752
+	}
753
+
754
+
755
+	/**
756
+	 * register translations for a registered script
757
+	 *
758
+	 * @param string $handle
759
+	 */
760
+	public function registerTranslation($handle)
761
+	{
762
+		$this->i18n_registry->registerScriptI18n($handle);
763
+	}
764
+
765
+
766
+	/**
767
+	 * @since 4.9.63.p
768
+	 * @return bool
769
+	 */
770
+	private function debug()
771
+	{
772
+		return apply_filters(
773
+			'FHEE__EventEspresso_core_services_assets_Registry__debug',
774
+			defined('EE_DEBUG') && EE_DEBUG
775
+		);
776
+	}
777
+
778
+
779
+	/**
780
+	 * Get the dependencies array for the given js asset chunk name
781
+	 *
782
+	 * @param string $namespace
783
+	 * @param string $chunk_name
784
+	 * @return array
785
+	 * @deprecated 4.10.2.p
786
+	 * @since 4.9.82.p
787
+	 */
788
+	public function getJsDependencies($namespace, $chunk_name)
789
+	{
790
+		$details = $this->getJsAssetDetails($namespace, $chunk_name);
791
+		return isset($details['dependencies']) ? $details['dependencies'] : [];
792
+	}
793
+
794
+
795
+	/**
796
+	 * Get the dependencies array for the given css asset chunk name
797
+	 *
798
+	 * @param string $namespace
799
+	 * @param string $chunk_name
800
+	 * @return array
801
+	 * @deprecated 4.10.2.p
802
+	 * @since      4.9.82.p
803
+	 */
804
+	public function getCssDependencies($namespace, $chunk_name)
805
+	{
806
+		$details = $this->getCssAssetDetails($namespace, $chunk_name);
807
+		return isset($details['dependencies']) ? $details['dependencies'] : [];
808
+	}
809 809
 }
Please login to merge, or discard this patch.
Spacing   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
                 $script->version(),
185 185
                 $script->loadInFooter()
186 186
             );
187
-            if (! $registered && $this->debug()) {
187
+            if ( ! $registered && $this->debug()) {
188 188
                 throw new AssetRegistrationException($script->handle());
189 189
             }
190 190
             $script->setRegistered($registered);
@@ -245,7 +245,7 @@  discard block
 block discarded – undo
245 245
         $this->removeAlreadyRegisteredDataForScriptHandles();
246 246
         wp_add_inline_script(
247 247
             'eejs-core',
248
-            'var eejsdata=' . wp_json_encode(array('data' => $this->jsdata)),
248
+            'var eejsdata='.wp_json_encode(array('data' => $this->jsdata)),
249 249
             'before'
250 250
         );
251 251
         $scripts = $this->assets->getJavascriptAssetsWithData();
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
     public function addData($key, $value)
276 276
     {
277 277
         if ($this->verifyDataNotExisting($key)) {
278
-            $this->jsdata[ $key ] = $value;
278
+            $this->jsdata[$key] = $value;
279 279
         }
280 280
     }
281 281
 
@@ -300,10 +300,10 @@  discard block
 block discarded – undo
300 300
      */
301 301
     public function pushData($key, $value)
302 302
     {
303
-        if (isset($this->jsdata[ $key ])
304
-            && ! is_array($this->jsdata[ $key ])
303
+        if (isset($this->jsdata[$key])
304
+            && ! is_array($this->jsdata[$key])
305 305
         ) {
306
-            if (! $this->debug()) {
306
+            if ( ! $this->debug()) {
307 307
                 return;
308 308
             }
309 309
             throw new InvalidArgumentException(
@@ -318,10 +318,10 @@  discard block
 block discarded – undo
318 318
                 )
319 319
             );
320 320
         }
321
-        if ( ! isset( $this->jsdata[ $key ] ) ) {
322
-            $this->jsdata[ $key ] = is_array($value) ? $value : [$value];
321
+        if ( ! isset($this->jsdata[$key])) {
322
+            $this->jsdata[$key] = is_array($value) ? $value : [$value];
323 323
         } else {
324
-            $this->jsdata[ $key ] = array_merge( $this->jsdata[$key], (array) $value);
324
+            $this->jsdata[$key] = array_merge($this->jsdata[$key], (array) $value);
325 325
         }
326 326
     }
327 327
 
@@ -336,12 +336,12 @@  discard block
 block discarded – undo
336 336
      */
337 337
     public function addTemplate($template_reference, $template_content)
338 338
     {
339
-        if (! isset($this->jsdata['templates'])) {
339
+        if ( ! isset($this->jsdata['templates'])) {
340 340
             $this->jsdata['templates'] = array();
341 341
         }
342 342
         //no overrides allowed.
343
-        if (isset($this->jsdata['templates'][ $template_reference ])) {
344
-            if (! $this->debug()) {
343
+        if (isset($this->jsdata['templates'][$template_reference])) {
344
+            if ( ! $this->debug()) {
345 345
                 return;
346 346
             }
347 347
             throw new InvalidArgumentException(
@@ -354,7 +354,7 @@  discard block
 block discarded – undo
354 354
                 )
355 355
             );
356 356
         }
357
-        $this->jsdata['templates'][ $template_reference ] = $template_content;
357
+        $this->jsdata['templates'][$template_reference] = $template_content;
358 358
     }
359 359
 
360 360
 
@@ -366,8 +366,8 @@  discard block
 block discarded – undo
366 366
      */
367 367
     public function getTemplate($template_reference)
368 368
     {
369
-        return isset($this->jsdata['templates'][ $template_reference ])
370
-            ? $this->jsdata['templates'][ $template_reference ]
369
+        return isset($this->jsdata['templates'][$template_reference])
370
+            ? $this->jsdata['templates'][$template_reference]
371 371
             : '';
372 372
     }
373 373
 
@@ -380,8 +380,8 @@  discard block
 block discarded – undo
380 380
      */
381 381
     public function getData($key)
382 382
     {
383
-        return isset($this->jsdata[ $key ])
384
-            ? $this->jsdata[ $key ]
383
+        return isset($this->jsdata[$key])
384
+            ? $this->jsdata[$key]
385 385
             : false;
386 386
     }
387 387
 
@@ -396,11 +396,11 @@  discard block
 block discarded – undo
396 396
      */
397 397
     protected function verifyDataNotExisting($key)
398 398
     {
399
-        if (isset($this->jsdata[ $key ])) {
400
-            if (! $this->debug()) {
399
+        if (isset($this->jsdata[$key])) {
400
+            if ( ! $this->debug()) {
401 401
                 return false;
402 402
             }
403
-            if (is_array($this->jsdata[ $key ])) {
403
+            if (is_array($this->jsdata[$key])) {
404 404
                 throw new InvalidArgumentException(
405 405
                     sprintf(
406 406
                         esc_html__(
@@ -443,11 +443,11 @@  discard block
 block discarded – undo
443 443
     public function getAssetUrl($namespace, $chunk_name, $asset_type)
444 444
     {
445 445
         $url = isset(
446
-            $this->manifest_data[ $namespace ][ $chunk_name . '.' . $asset_type ],
447
-            $this->manifest_data[ $namespace ]['url_base']
446
+            $this->manifest_data[$namespace][$chunk_name.'.'.$asset_type],
447
+            $this->manifest_data[$namespace]['url_base']
448 448
         )
449
-            ? $this->manifest_data[ $namespace ]['url_base']
450
-              . $this->manifest_data[ $namespace ][ $chunk_name . '.' . $asset_type ]
449
+            ? $this->manifest_data[$namespace]['url_base']
450
+              . $this->manifest_data[$namespace][$chunk_name.'.'.$asset_type]
451 451
             : $chunk_name;
452 452
 
453 453
         return apply_filters(
@@ -498,21 +498,21 @@  discard block
 block discarded – undo
498 498
      */
499 499
     private function getDetailsForAsset($namespace, $chunk_name, $asset_type)
500 500
     {
501
-        $asset_index = $chunk_name . '.' . $asset_type;
502
-        if (! isset( $this->dependencies_data[ $namespace ][ $asset_index ])) {
503
-            $path = isset($this->manifest_data[ $namespace ]['path'])
504
-                ? $this->manifest_data[ $namespace ]['path']
501
+        $asset_index = $chunk_name.'.'.$asset_type;
502
+        if ( ! isset($this->dependencies_data[$namespace][$asset_index])) {
503
+            $path = isset($this->manifest_data[$namespace]['path'])
504
+                ? $this->manifest_data[$namespace]['path']
505 505
                 : '';
506
-            $dependencies_index = $chunk_name . '.' . Asset::TYPE_PHP;
507
-            $file_path = isset($this->manifest_data[ $namespace ][ $dependencies_index ])
508
-                ? $path . $this->manifest_data[ $namespace ][ $dependencies_index ]
506
+            $dependencies_index = $chunk_name.'.'.Asset::TYPE_PHP;
507
+            $file_path = isset($this->manifest_data[$namespace][$dependencies_index])
508
+                ? $path.$this->manifest_data[$namespace][$dependencies_index]
509 509
                 :
510 510
                 '';
511
-            $this->dependencies_data[ $namespace ][ $asset_index ] = $file_path !== '' && file_exists($file_path)
511
+            $this->dependencies_data[$namespace][$asset_index] = $file_path !== '' && file_exists($file_path)
512 512
                 ? $this->getDetailsForAssetType($namespace, $asset_type, $file_path, $chunk_name)
513 513
                 : [];
514 514
         }
515
-        $details = $this->dependencies_data[ $namespace ][ $asset_index ];
515
+        $details = $this->dependencies_data[$namespace][$asset_index];
516 516
         return $details;
517 517
     }
518 518
 
@@ -539,34 +539,34 @@  discard block
 block discarded – undo
539 539
             ? $asset_details['version']
540 540
             : '';
541 541
         if ($asset_type === Asset::TYPE_JS) {
542
-            $asset_details['dependencies'] =  $chunk_name === 'eejs-core'
542
+            $asset_details['dependencies'] = $chunk_name === 'eejs-core'
543 543
                 ? $asset_details['dependencies']
544
-                : $asset_details['dependencies'] + [ CoreAssetManager::JS_HANDLE_JS_CORE ];
544
+                : $asset_details['dependencies'] + [CoreAssetManager::JS_HANDLE_JS_CORE];
545 545
             return $asset_details;
546 546
         }
547 547
         // for css we need to make sure there is actually a css file related to this chunk.
548
-        if (isset($this->manifest_data[ $namespace ])) {
548
+        if (isset($this->manifest_data[$namespace])) {
549 549
             // array of css chunk files for ee.
550 550
             $css_chunks = array_map(
551
-                static function ($value) {
551
+                static function($value) {
552 552
                     return str_replace('.css', '', $value);
553 553
                 },
554 554
                 array_filter(
555
-                    array_keys($this->manifest_data[ $namespace ]),
556
-                    static function ($value) {
555
+                    array_keys($this->manifest_data[$namespace]),
556
+                    static function($value) {
557 557
                         return strpos($value, '.css') !== false;
558 558
                     }
559 559
                 )
560 560
             );
561 561
             // add known wp chunks with css
562
-            $css_chunks = array_merge( $css_chunks, $this->wp_css_handle_dependencies);
562
+            $css_chunks = array_merge($css_chunks, $this->wp_css_handle_dependencies);
563 563
             // flip for easier search
564 564
             $css_chunks = array_flip($css_chunks);
565 565
             // now let's filter the dependencies for the incoming chunk to actual chunks that have styles
566 566
             $asset_details['dependencies'] = array_filter(
567 567
                 $asset_details['dependencies'],
568
-                static function ($chunk_name) use ($css_chunks) {
569
-                    return isset($css_chunks[ $chunk_name ]);
568
+                static function($chunk_name) use ($css_chunks) {
569
+                    return isset($css_chunks[$chunk_name]);
570 570
                 }
571 571
             );
572 572
             return $asset_details;
@@ -615,7 +615,7 @@  discard block
 block discarded – undo
615 615
             $this->registerManifestFile(
616 616
                 $manifest_file->assetNamespace(),
617 617
                 $manifest_file->urlBase(),
618
-                $manifest_file->filepath() . Registry::FILE_NAME_BUILD_MANIFEST,
618
+                $manifest_file->filepath().Registry::FILE_NAME_BUILD_MANIFEST,
619 619
                 $manifest_file->filepath()
620 620
             );
621 621
         }
@@ -636,8 +636,8 @@  discard block
 block discarded – undo
636 636
      */
637 637
     public function registerManifestFile($namespace, $url_base, $manifest_file, $manifest_file_path = '')
638 638
     {
639
-        if (isset($this->manifest_data[ $namespace ])) {
640
-            if (! $this->debug()) {
639
+        if (isset($this->manifest_data[$namespace])) {
640
+            if ( ! $this->debug()) {
641 641
                 return;
642 642
             }
643 643
             throw new InvalidArgumentException(
@@ -670,12 +670,12 @@  discard block
 block discarded – undo
670 670
             }
671 671
             return;
672 672
         }
673
-        $this->manifest_data[ $namespace ] = $this->decodeManifestFile($manifest_file);
674
-        if (! isset($this->manifest_data[ $namespace ]['url_base'])) {
675
-            $this->manifest_data[ $namespace ]['url_base'] = trailingslashit($url_base);
673
+        $this->manifest_data[$namespace] = $this->decodeManifestFile($manifest_file);
674
+        if ( ! isset($this->manifest_data[$namespace]['url_base'])) {
675
+            $this->manifest_data[$namespace]['url_base'] = trailingslashit($url_base);
676 676
         }
677
-        if (! isset($this->manifest_data[ $namespace ]['path'])) {
678
-            $this->manifest_data[ $namespace ]['path'] = $manifest_file_path;
677
+        if ( ! isset($this->manifest_data[$namespace]['path'])) {
678
+            $this->manifest_data[$namespace]['path'] = $manifest_file_path;
679 679
         }
680 680
     }
681 681
 
@@ -690,7 +690,7 @@  discard block
 block discarded – undo
690 690
      */
691 691
     private function decodeManifestFile($manifest_file)
692 692
     {
693
-        if (! file_exists($manifest_file)) {
693
+        if ( ! file_exists($manifest_file)) {
694 694
             throw new InvalidFilePathException($manifest_file);
695 695
         }
696 696
         return json_decode(file_get_contents($manifest_file), true);
@@ -704,7 +704,7 @@  discard block
 block discarded – undo
704 704
      */
705 705
     private function addRegisteredScriptHandlesWithData($script_handle)
706 706
     {
707
-        $this->script_handles_with_data[ $script_handle ] = $script_handle;
707
+        $this->script_handles_with_data[$script_handle] = $script_handle;
708 708
     }
709 709
 
710 710
 
@@ -730,23 +730,23 @@  discard block
 block discarded – undo
730 730
      */
731 731
     private function removeAlreadyRegisteredDataForScriptHandle($script_handle)
732 732
     {
733
-        if (isset($this->script_handles_with_data[ $script_handle ])) {
733
+        if (isset($this->script_handles_with_data[$script_handle])) {
734 734
             global $wp_scripts;
735 735
             $unset_handle = false;
736 736
             if ($wp_scripts->get_data($script_handle, 'data')) {
737
-                unset($wp_scripts->registered[ $script_handle ]->extra['data']);
737
+                unset($wp_scripts->registered[$script_handle]->extra['data']);
738 738
                 $unset_handle = true;
739 739
             }
740 740
             //deal with inline_scripts
741 741
             if ($wp_scripts->get_data($script_handle, 'before')) {
742
-                unset($wp_scripts->registered[ $script_handle ]->extra['before']);
742
+                unset($wp_scripts->registered[$script_handle]->extra['before']);
743 743
                 $unset_handle = true;
744 744
             }
745 745
             if ($wp_scripts->get_data($script_handle, 'after')) {
746
-                unset($wp_scripts->registered[ $script_handle ]->extra['after']);
746
+                unset($wp_scripts->registered[$script_handle]->extra['after']);
747 747
             }
748 748
             if ($unset_handle) {
749
-                unset($this->script_handles_with_data[ $script_handle ]);
749
+                unset($this->script_handles_with_data[$script_handle]);
750 750
             }
751 751
         }
752 752
     }
Please login to merge, or discard this patch.
core/services/collections/CollectionLoaderException.php 1 patch
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -16,25 +16,25 @@
 block discarded – undo
16 16
 class CollectionLoaderException extends RuntimeException
17 17
 {
18 18
 
19
-    /**
20
-     * DuplicateCollectionIdentifierException constructor.
21
-     *
22
-     * @param Exception $previous
23
-     * @param string    $message
24
-     * @param int       $code
25
-     */
26
-    public function __construct(Exception $previous, $message = '', $code = 0)
27
-    {
28
-        if (empty($message)) {
29
-            $message = sprintf(
30
-                esc_html__(
31
-                    'The following error occurred during the creation and/or loading of this collection: %1$s %2$s',
32
-                    'event_espresso'
33
-                ),
34
-                '<br />',
35
-                $previous->getMessage()
36
-            );
37
-        }
38
-        parent::__construct($message, $code, $previous);
39
-    }
19
+	/**
20
+	 * DuplicateCollectionIdentifierException constructor.
21
+	 *
22
+	 * @param Exception $previous
23
+	 * @param string    $message
24
+	 * @param int       $code
25
+	 */
26
+	public function __construct(Exception $previous, $message = '', $code = 0)
27
+	{
28
+		if (empty($message)) {
29
+			$message = sprintf(
30
+				esc_html__(
31
+					'The following error occurred during the creation and/or loading of this collection: %1$s %2$s',
32
+					'event_espresso'
33
+				),
34
+				'<br />',
35
+				$previous->getMessage()
36
+			);
37
+		}
38
+		parent::__construct($message, $code, $previous);
39
+	}
40 40
 }
Please login to merge, or discard this patch.
core/services/collections/InvalidCollectionIdentifierException.php 1 patch
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -16,26 +16,26 @@
 block discarded – undo
16 16
 class InvalidCollectionIdentifierException extends OutOfBoundsException
17 17
 {
18 18
 
19
-    /**
20
-     * InvalidCollectionIdentifierException constructor.
21
-     *
22
-     * @param                $identifier
23
-     * @param string         $message
24
-     * @param int            $code
25
-     * @param Exception|null $previous
26
-     */
27
-    public function __construct($identifier, $message = '', $code = 0, Exception $previous = null)
28
-    {
29
-        if (empty($message)) {
30
-            $message = sprintf(
31
-                esc_html__(
32
-                    'The supplied identifier "%1$s" does not exist within this collection. 
19
+	/**
20
+	 * InvalidCollectionIdentifierException constructor.
21
+	 *
22
+	 * @param                $identifier
23
+	 * @param string         $message
24
+	 * @param int            $code
25
+	 * @param Exception|null $previous
26
+	 */
27
+	public function __construct($identifier, $message = '', $code = 0, Exception $previous = null)
28
+	{
29
+		if (empty($message)) {
30
+			$message = sprintf(
31
+				esc_html__(
32
+					'The supplied identifier "%1$s" does not exist within this collection. 
33 33
                     You may need to delay adding this asset until the required dependency has been added.',
34
-                    'event_espresso'
35
-                ),
36
-                $identifier
37
-            );
38
-        }
39
-        parent::__construct($message, $code, $previous);
40
-    }
34
+					'event_espresso'
35
+				),
36
+				$identifier
37
+			);
38
+		}
39
+		parent::__construct($message, $code, $previous);
40
+	}
41 41
 }
Please login to merge, or discard this patch.
core/services/collections/CollectionDetailsException.php 1 patch
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -16,25 +16,25 @@
 block discarded – undo
16 16
 class CollectionDetailsException extends RuntimeException
17 17
 {
18 18
 
19
-    /**
20
-     * DuplicateCollectionIdentifierException constructor.
21
-     *
22
-     * @param Exception $previous
23
-     * @param string    $message
24
-     * @param int       $code
25
-     */
26
-    public function __construct(Exception $previous, $message = '', $code = 0)
27
-    {
28
-        if (empty($message)) {
29
-            $message = sprintf(
30
-                esc_html__(
31
-                    'The following error occurred during the collection details generation: %1$s %2$s',
32
-                    'event_espresso'
33
-                ),
34
-                '<br />',
35
-                $previous->getMessage()
36
-            );
37
-        }
38
-        parent::__construct($message, $code, $previous);
39
-    }
19
+	/**
20
+	 * DuplicateCollectionIdentifierException constructor.
21
+	 *
22
+	 * @param Exception $previous
23
+	 * @param string    $message
24
+	 * @param int       $code
25
+	 */
26
+	public function __construct(Exception $previous, $message = '', $code = 0)
27
+	{
28
+		if (empty($message)) {
29
+			$message = sprintf(
30
+				esc_html__(
31
+					'The following error occurred during the collection details generation: %1$s %2$s',
32
+					'event_espresso'
33
+				),
34
+				'<br />',
35
+				$previous->getMessage()
36
+			);
37
+		}
38
+		parent::__construct($message, $code, $previous);
39
+	}
40 40
 }
Please login to merge, or discard this patch.
core/services/collections/DuplicateCollectionIdentifierException.php 1 patch
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -16,25 +16,25 @@
 block discarded – undo
16 16
 class DuplicateCollectionIdentifierException extends OutOfRangeException
17 17
 {
18 18
 
19
-    /**
20
-     * DuplicateCollectionIdentifierException constructor.
21
-     *
22
-     * @param                $identifier
23
-     * @param string         $message
24
-     * @param int            $code
25
-     * @param Exception|null $previous
26
-     */
27
-    public function __construct($identifier, $message = '', $code = 0, Exception $previous = null)
28
-    {
29
-        if (empty($message)) {
30
-            $message = sprintf(
31
-                esc_html__(
32
-                    'The supplied identifier "%1$s" already exists within this collection.',
33
-                    'event_espresso'
34
-                ),
35
-                $identifier
36
-            );
37
-        }
38
-        parent::__construct($message, $code, $previous);
39
-    }
19
+	/**
20
+	 * DuplicateCollectionIdentifierException constructor.
21
+	 *
22
+	 * @param                $identifier
23
+	 * @param string         $message
24
+	 * @param int            $code
25
+	 * @param Exception|null $previous
26
+	 */
27
+	public function __construct($identifier, $message = '', $code = 0, Exception $previous = null)
28
+	{
29
+		if (empty($message)) {
30
+			$message = sprintf(
31
+				esc_html__(
32
+					'The supplied identifier "%1$s" already exists within this collection.',
33
+					'event_espresso'
34
+				),
35
+				$identifier
36
+			);
37
+		}
38
+		parent::__construct($message, $code, $previous);
39
+	}
40 40
 }
Please login to merge, or discard this patch.
core/services/container/CoffeeMaker.php 2 patches
Indentation   +152 added lines, -152 removed lines patch added patch discarded remove patch
@@ -18,156 +18,156 @@
 block discarded – undo
18 18
 abstract class CoffeeMaker implements CoffeeMakerInterface
19 19
 {
20 20
 
21
-    /**
22
-     * Indicates that CoffeeMaker should construct a NEW entity instance from the provided arguments (if given)
23
-     */
24
-    const BREW_NEW = 'new';
25
-
26
-    /**
27
-     * Indicates that CoffeeMaker should always return a SHARED instance
28
-     */
29
-    const BREW_SHARED = 'shared';
30
-
31
-    /**
32
-     * Indicates that CoffeeMaker should only load the file/class/interface but NOT instantiate
33
-     */
34
-    const BREW_LOAD_ONLY = 'load_only';
35
-
36
-
37
-    /**
38
-     * @var CoffeePotInterface $coffee_pot
39
-     */
40
-    private $coffee_pot;
41
-
42
-    /**
43
-     * @var DependencyInjector $injector
44
-     */
45
-    private $injector;
46
-
47
-
48
-    /**
49
-     * @return array
50
-     */
51
-    public static function getTypes()
52
-    {
53
-        return (array) apply_filters(
54
-            'FHEE__EventEspresso\core\services\container\CoffeeMaker__getTypes',
55
-            array(
56
-                CoffeeMaker::BREW_NEW,
57
-                CoffeeMaker::BREW_SHARED,
58
-                CoffeeMaker::BREW_LOAD_ONLY,
59
-            )
60
-        );
61
-    }
62
-
63
-
64
-    /**
65
-     * @param $type
66
-     * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
67
-     */
68
-    public static function validateType($type)
69
-    {
70
-        $types = CoffeeMaker::getTypes();
71
-        if (! in_array($type, $types, true)) {
72
-            throw new InvalidIdentifierException(
73
-                is_object($type) ? get_class($type) : gettype($type),
74
-                esc_html__(
75
-                    'recipe type (one of the class constants on \EventEspresso\core\services\container\CoffeeMaker)',
76
-                    'event_espresso'
77
-                )
78
-            );
79
-        }
80
-        return $type;
81
-    }
82
-
83
-
84
-    /**
85
-     * CoffeeMaker constructor.
86
-     *
87
-     * @param CoffeePotInterface $coffee_pot
88
-     * @param InjectorInterface  $injector
89
-     */
90
-    public function __construct(CoffeePotInterface $coffee_pot, InjectorInterface $injector)
91
-    {
92
-        $this->coffee_pot = $coffee_pot;
93
-        $this->injector = $injector;
94
-    }
95
-
96
-
97
-    /**
98
-     * @return \EventEspresso\core\services\container\CoffeePotInterface
99
-     */
100
-    protected function coffeePot()
101
-    {
102
-        return $this->coffee_pot;
103
-    }
104
-
105
-
106
-    /**
107
-     * @return \EventEspresso\core\services\container\DependencyInjector
108
-     */
109
-    protected function injector()
110
-    {
111
-        return $this->injector;
112
-    }
113
-
114
-
115
-    /**
116
-     * Examines the constructor to determine which method should be used for instantiation
117
-     *
118
-     * @param \ReflectionClass $reflector
119
-     * @return mixed
120
-     * @throws InstantiationException
121
-     */
122
-    protected function resolveInstantiationMethod(\ReflectionClass $reflector)
123
-    {
124
-        if ($reflector->getConstructor() === null) {
125
-            return 'NewInstance';
126
-        }
127
-        if ($reflector->isInstantiable()) {
128
-            return 'NewInstanceArgs';
129
-        }
130
-        if (method_exists($reflector->getName(), 'instance')) {
131
-            return 'instance';
132
-        }
133
-        if (method_exists($reflector->getName(), 'new_instance')) {
134
-            return 'new_instance';
135
-        }
136
-        if (method_exists($reflector->getName(), 'new_instance_from_db')) {
137
-            return 'new_instance_from_db';
138
-        }
139
-        throw new InstantiationException($reflector->getName());
140
-    }
141
-
142
-
143
-    /**
144
-     * Ensures files for classes that are not PSR-4 compatible are loaded
145
-     * and then verifies that classes exist where applicable
146
-     *
147
-     * @param RecipeInterface $recipe
148
-     * @return bool
149
-     * @throws InvalidClassException
150
-     */
151
-    protected function resolveClassAndFilepath(RecipeInterface $recipe)
152
-    {
153
-        $paths = $recipe->paths();
154
-        if (! empty($paths)) {
155
-            foreach ($paths as $path) {
156
-                if (strpos($path, '*') === false && is_readable($path)) {
157
-                    require_once($path);
158
-                }
159
-            }
160
-        }
161
-        // re: using "false" for class_exists() second param:
162
-        // if a class name is not already known to PHP, then class_exists() will run through
163
-        // all of the registered spl_autoload functions until it either finds the class,
164
-        // or gets to the end of the registered spl_autoload functions.
165
-        // When the second parameter is true, it will also attempt to load the class file,
166
-        // but it will also trigger an error if the class can not be loaded.
167
-        // We don't want that extra error in the mix, so we have set the second param to "false"
168
-        if ($recipe->type() !== CoffeeMaker::BREW_LOAD_ONLY && ! class_exists($recipe->fqcn(), false)) {
169
-            throw new InvalidClassException($recipe->identifier());
170
-        }
171
-        return true;
172
-    }
21
+	/**
22
+	 * Indicates that CoffeeMaker should construct a NEW entity instance from the provided arguments (if given)
23
+	 */
24
+	const BREW_NEW = 'new';
25
+
26
+	/**
27
+	 * Indicates that CoffeeMaker should always return a SHARED instance
28
+	 */
29
+	const BREW_SHARED = 'shared';
30
+
31
+	/**
32
+	 * Indicates that CoffeeMaker should only load the file/class/interface but NOT instantiate
33
+	 */
34
+	const BREW_LOAD_ONLY = 'load_only';
35
+
36
+
37
+	/**
38
+	 * @var CoffeePotInterface $coffee_pot
39
+	 */
40
+	private $coffee_pot;
41
+
42
+	/**
43
+	 * @var DependencyInjector $injector
44
+	 */
45
+	private $injector;
46
+
47
+
48
+	/**
49
+	 * @return array
50
+	 */
51
+	public static function getTypes()
52
+	{
53
+		return (array) apply_filters(
54
+			'FHEE__EventEspresso\core\services\container\CoffeeMaker__getTypes',
55
+			array(
56
+				CoffeeMaker::BREW_NEW,
57
+				CoffeeMaker::BREW_SHARED,
58
+				CoffeeMaker::BREW_LOAD_ONLY,
59
+			)
60
+		);
61
+	}
62
+
63
+
64
+	/**
65
+	 * @param $type
66
+	 * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
67
+	 */
68
+	public static function validateType($type)
69
+	{
70
+		$types = CoffeeMaker::getTypes();
71
+		if (! in_array($type, $types, true)) {
72
+			throw new InvalidIdentifierException(
73
+				is_object($type) ? get_class($type) : gettype($type),
74
+				esc_html__(
75
+					'recipe type (one of the class constants on \EventEspresso\core\services\container\CoffeeMaker)',
76
+					'event_espresso'
77
+				)
78
+			);
79
+		}
80
+		return $type;
81
+	}
82
+
83
+
84
+	/**
85
+	 * CoffeeMaker constructor.
86
+	 *
87
+	 * @param CoffeePotInterface $coffee_pot
88
+	 * @param InjectorInterface  $injector
89
+	 */
90
+	public function __construct(CoffeePotInterface $coffee_pot, InjectorInterface $injector)
91
+	{
92
+		$this->coffee_pot = $coffee_pot;
93
+		$this->injector = $injector;
94
+	}
95
+
96
+
97
+	/**
98
+	 * @return \EventEspresso\core\services\container\CoffeePotInterface
99
+	 */
100
+	protected function coffeePot()
101
+	{
102
+		return $this->coffee_pot;
103
+	}
104
+
105
+
106
+	/**
107
+	 * @return \EventEspresso\core\services\container\DependencyInjector
108
+	 */
109
+	protected function injector()
110
+	{
111
+		return $this->injector;
112
+	}
113
+
114
+
115
+	/**
116
+	 * Examines the constructor to determine which method should be used for instantiation
117
+	 *
118
+	 * @param \ReflectionClass $reflector
119
+	 * @return mixed
120
+	 * @throws InstantiationException
121
+	 */
122
+	protected function resolveInstantiationMethod(\ReflectionClass $reflector)
123
+	{
124
+		if ($reflector->getConstructor() === null) {
125
+			return 'NewInstance';
126
+		}
127
+		if ($reflector->isInstantiable()) {
128
+			return 'NewInstanceArgs';
129
+		}
130
+		if (method_exists($reflector->getName(), 'instance')) {
131
+			return 'instance';
132
+		}
133
+		if (method_exists($reflector->getName(), 'new_instance')) {
134
+			return 'new_instance';
135
+		}
136
+		if (method_exists($reflector->getName(), 'new_instance_from_db')) {
137
+			return 'new_instance_from_db';
138
+		}
139
+		throw new InstantiationException($reflector->getName());
140
+	}
141
+
142
+
143
+	/**
144
+	 * Ensures files for classes that are not PSR-4 compatible are loaded
145
+	 * and then verifies that classes exist where applicable
146
+	 *
147
+	 * @param RecipeInterface $recipe
148
+	 * @return bool
149
+	 * @throws InvalidClassException
150
+	 */
151
+	protected function resolveClassAndFilepath(RecipeInterface $recipe)
152
+	{
153
+		$paths = $recipe->paths();
154
+		if (! empty($paths)) {
155
+			foreach ($paths as $path) {
156
+				if (strpos($path, '*') === false && is_readable($path)) {
157
+					require_once($path);
158
+				}
159
+			}
160
+		}
161
+		// re: using "false" for class_exists() second param:
162
+		// if a class name is not already known to PHP, then class_exists() will run through
163
+		// all of the registered spl_autoload functions until it either finds the class,
164
+		// or gets to the end of the registered spl_autoload functions.
165
+		// When the second parameter is true, it will also attempt to load the class file,
166
+		// but it will also trigger an error if the class can not be loaded.
167
+		// We don't want that extra error in the mix, so we have set the second param to "false"
168
+		if ($recipe->type() !== CoffeeMaker::BREW_LOAD_ONLY && ! class_exists($recipe->fqcn(), false)) {
169
+			throw new InvalidClassException($recipe->identifier());
170
+		}
171
+		return true;
172
+	}
173 173
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
     public static function validateType($type)
69 69
     {
70 70
         $types = CoffeeMaker::getTypes();
71
-        if (! in_array($type, $types, true)) {
71
+        if ( ! in_array($type, $types, true)) {
72 72
             throw new InvalidIdentifierException(
73 73
                 is_object($type) ? get_class($type) : gettype($type),
74 74
                 esc_html__(
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
     protected function resolveClassAndFilepath(RecipeInterface $recipe)
152 152
     {
153 153
         $paths = $recipe->paths();
154
-        if (! empty($paths)) {
154
+        if ( ! empty($paths)) {
155 155
             foreach ($paths as $path) {
156 156
                 if (strpos($path, '*') === false && is_readable($path)) {
157 157
                     require_once($path);
Please login to merge, or discard this patch.