Completed
Branch master (4bd299)
by
unknown
04:49
created
core/db_classes/EE_Line_Item.class.php 1 patch
Indentation   +1673 added lines, -1673 removed lines patch added patch discarded remove patch
@@ -16,1677 +16,1677 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Line_Item extends EE_Base_Class
18 18
 {
19
-    /**
20
-     * for children line items (currently not a normal relation)
21
-     *
22
-     * @var EE_Line_Item[]
23
-     */
24
-    protected array $_children = [];
25
-
26
-    /**
27
-     * query params used to obtain children line items above
28
-     *
29
-     * @var array
30
-     */
31
-    private array $children_query_params = [];
32
-
33
-    /**
34
-     * for the parent line item
35
-     *
36
-     * @var EE_Line_Item|null
37
-     */
38
-    protected ?EE_Line_Item $_parent = null;
39
-
40
-    /**
41
-     * @var LineItemCalculator
42
-     */
43
-    protected LineItemCalculator $calculator;
44
-
45
-
46
-    /**
47
-     * @param array       $props_n_values incoming values
48
-     * @param string|null $timezone       incoming timezone as set by the model.
49
-     *                                    If not set the timezone for the website will be used.
50
-     * @param array       $date_formats   incoming date_formats in an array where the first value is the
51
-     *                                    date_format and the second value is the time format
52
-     * @return EE_Line_Item
53
-     * @throws EE_Error
54
-     * @throws InvalidArgumentException
55
-     * @throws InvalidDataTypeException
56
-     * @throws InvalidInterfaceException
57
-     * @throws ReflectionException
58
-     */
59
-    public static function new_instance(
60
-        array $props_n_values = [],
61
-        ?string $timezone = '',
62
-        array $date_formats = []
63
-    ): EE_Line_Item {
64
-        $has_object = parent::_check_for_object(
65
-            $props_n_values,
66
-            __CLASS__,
67
-            $timezone,
68
-            $date_formats
69
-        );
70
-        return $has_object ?: new self($props_n_values, false, $timezone);
71
-    }
72
-
73
-
74
-    /**
75
-     * @param array       $props_n_values incoming values from the database
76
-     * @param string|null $timezone       incoming timezone as set by the model.
77
-     *                                    If not set the timezone for the website will be used.
78
-     * @return EE_Line_Item
79
-     * @throws EE_Error
80
-     * @throws InvalidArgumentException
81
-     * @throws InvalidDataTypeException
82
-     * @throws InvalidInterfaceException
83
-     * @throws ReflectionException
84
-     */
85
-    public static function new_instance_from_db(array $props_n_values = [], ?string $timezone = ''): EE_Line_Item
86
-    {
87
-        return new self($props_n_values, true, $timezone);
88
-    }
89
-
90
-
91
-    /**
92
-     * Adds some defaults if they're not specified
93
-     *
94
-     * @param array  $fieldValues
95
-     * @param bool   $bydb
96
-     * @param string $timezone
97
-     * @throws EE_Error
98
-     * @throws InvalidArgumentException
99
-     * @throws InvalidDataTypeException
100
-     * @throws InvalidInterfaceException
101
-     * @throws ReflectionException
102
-     */
103
-    protected function __construct($fieldValues = [], $bydb = false, $timezone = '')
104
-    {
105
-        $this->calculator = LoaderFactory::getShared(LineItemCalculator::class);
106
-        parent::__construct($fieldValues, $bydb, $timezone);
107
-        if (! $this->get('LIN_code')) {
108
-            $this->set_code($this->generate_code());
109
-        }
110
-    }
111
-
112
-
113
-    public function __wakeup()
114
-    {
115
-        $this->calculator = LoaderFactory::getShared(LineItemCalculator::class);
116
-        parent::__wakeup();
117
-    }
118
-
119
-
120
-    /**
121
-     * Gets ID
122
-     *
123
-     * @return int
124
-     * @throws EE_Error
125
-     * @throws InvalidArgumentException
126
-     * @throws InvalidDataTypeException
127
-     * @throws InvalidInterfaceException
128
-     * @throws ReflectionException
129
-     */
130
-    public function ID(): int
131
-    {
132
-        return (int) $this->get('LIN_ID');
133
-    }
134
-
135
-
136
-    /**
137
-     * Gets TXN_ID
138
-     *
139
-     * @return int
140
-     * @throws EE_Error
141
-     * @throws InvalidArgumentException
142
-     * @throws InvalidDataTypeException
143
-     * @throws InvalidInterfaceException
144
-     * @throws ReflectionException
145
-     */
146
-    public function TXN_ID(): int
147
-    {
148
-        return (int) $this->get('TXN_ID');
149
-    }
150
-
151
-
152
-    /**
153
-     * Sets TXN_ID
154
-     *
155
-     * @param int $TXN_ID
156
-     * @throws EE_Error
157
-     * @throws InvalidArgumentException
158
-     * @throws InvalidDataTypeException
159
-     * @throws InvalidInterfaceException
160
-     * @throws ReflectionException
161
-     */
162
-    public function set_TXN_ID(int $TXN_ID)
163
-    {
164
-        $this->set('TXN_ID', $TXN_ID);
165
-    }
166
-
167
-
168
-    /**
169
-     * Gets name
170
-     *
171
-     * @return string
172
-     * @throws EE_Error
173
-     * @throws InvalidArgumentException
174
-     * @throws InvalidDataTypeException
175
-     * @throws InvalidInterfaceException
176
-     * @throws ReflectionException
177
-     */
178
-    public function name(): string
179
-    {
180
-        $name = (string) $this->get('LIN_name');
181
-        if (! $name) {
182
-            $name = ucwords(str_replace('-', ' ', $this->type()));
183
-        }
184
-        return $name;
185
-    }
186
-
187
-
188
-    /**
189
-     * Sets name
190
-     *
191
-     * @param string $name
192
-     * @throws EE_Error
193
-     * @throws InvalidArgumentException
194
-     * @throws InvalidDataTypeException
195
-     * @throws InvalidInterfaceException
196
-     * @throws ReflectionException
197
-     */
198
-    public function set_name(string $name)
199
-    {
200
-        $this->set('LIN_name', $name);
201
-    }
202
-
203
-
204
-    /**
205
-     * Gets desc
206
-     *
207
-     * @return string
208
-     * @throws EE_Error
209
-     * @throws InvalidArgumentException
210
-     * @throws InvalidDataTypeException
211
-     * @throws InvalidInterfaceException
212
-     * @throws ReflectionException
213
-     */
214
-    public function desc(): string
215
-    {
216
-        return (string) $this->get('LIN_desc');
217
-    }
218
-
219
-
220
-    /**
221
-     * Sets desc
222
-     *
223
-     * @param string $desc
224
-     * @throws EE_Error
225
-     * @throws InvalidArgumentException
226
-     * @throws InvalidDataTypeException
227
-     * @throws InvalidInterfaceException
228
-     * @throws ReflectionException
229
-     */
230
-    public function set_desc(string $desc)
231
-    {
232
-        $this->set('LIN_desc', $desc);
233
-    }
234
-
235
-
236
-    /**
237
-     * Gets quantity
238
-     *
239
-     * @return int
240
-     * @throws EE_Error
241
-     * @throws InvalidArgumentException
242
-     * @throws InvalidDataTypeException
243
-     * @throws InvalidInterfaceException
244
-     * @throws ReflectionException
245
-     */
246
-    public function quantity(): int
247
-    {
248
-        return (int) $this->get('LIN_quantity');
249
-    }
250
-
251
-
252
-    /**
253
-     * Sets quantity
254
-     *
255
-     * @param int $quantity
256
-     * @throws EE_Error
257
-     * @throws InvalidArgumentException
258
-     * @throws InvalidDataTypeException
259
-     * @throws InvalidInterfaceException
260
-     * @throws ReflectionException
261
-     */
262
-    public function set_quantity(int $quantity)
263
-    {
264
-        $this->set('LIN_quantity', max($quantity, 0));
265
-    }
266
-
267
-
268
-    /**
269
-     * Gets item_id
270
-     *
271
-     * @return int
272
-     * @throws EE_Error
273
-     * @throws InvalidArgumentException
274
-     * @throws InvalidDataTypeException
275
-     * @throws InvalidInterfaceException
276
-     * @throws ReflectionException
277
-     */
278
-    public function OBJ_ID(): int
279
-    {
280
-        return (int) $this->get('OBJ_ID');
281
-    }
282
-
283
-
284
-    /**
285
-     * Sets item_id
286
-     *
287
-     * @param int $item_id
288
-     * @throws EE_Error
289
-     * @throws InvalidArgumentException
290
-     * @throws InvalidDataTypeException
291
-     * @throws InvalidInterfaceException
292
-     * @throws ReflectionException
293
-     */
294
-    public function set_OBJ_ID(int $item_id)
295
-    {
296
-        $this->set('OBJ_ID', $item_id);
297
-    }
298
-
299
-
300
-    /**
301
-     * Gets item_type
302
-     *
303
-     * @return string
304
-     * @throws EE_Error
305
-     * @throws InvalidArgumentException
306
-     * @throws InvalidDataTypeException
307
-     * @throws InvalidInterfaceException
308
-     * @throws ReflectionException
309
-     */
310
-    public function OBJ_type(): string
311
-    {
312
-        return (string) $this->get('OBJ_type');
313
-    }
314
-
315
-
316
-    /**
317
-     * Gets item_type
318
-     *
319
-     * @return string
320
-     * @throws EE_Error
321
-     * @throws InvalidArgumentException
322
-     * @throws InvalidDataTypeException
323
-     * @throws InvalidInterfaceException
324
-     * @throws ReflectionException
325
-     */
326
-    public function OBJ_type_i18n(): string
327
-    {
328
-        $obj_type = $this->OBJ_type();
329
-        switch ($obj_type) {
330
-            case EEM_Line_Item::OBJ_TYPE_EVENT:
331
-                $obj_type = esc_html__('Event', 'event_espresso');
332
-                break;
333
-            case EEM_Line_Item::OBJ_TYPE_PRICE:
334
-                $obj_type = esc_html__('Price', 'event_espresso');
335
-                break;
336
-            case EEM_Line_Item::OBJ_TYPE_PROMOTION:
337
-                $obj_type = esc_html__('Promotion', 'event_espresso');
338
-                break;
339
-            case EEM_Line_Item::OBJ_TYPE_TICKET:
340
-                $obj_type = esc_html__('Ticket', 'event_espresso');
341
-                break;
342
-            case EEM_Line_Item::OBJ_TYPE_TRANSACTION:
343
-                $obj_type = esc_html__('Transaction', 'event_espresso');
344
-                break;
345
-        }
346
-        return (string) apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this);
347
-    }
348
-
349
-
350
-    /**
351
-     * Sets item_type
352
-     *
353
-     * @param string $OBJ_type
354
-     * @throws EE_Error
355
-     * @throws InvalidArgumentException
356
-     * @throws InvalidDataTypeException
357
-     * @throws InvalidInterfaceException
358
-     * @throws ReflectionException
359
-     */
360
-    public function set_OBJ_type(string $OBJ_type)
361
-    {
362
-        $this->set('OBJ_type', $OBJ_type);
363
-    }
364
-
365
-
366
-    /**
367
-     * Gets unit_price
368
-     *
369
-     * @return float
370
-     * @throws EE_Error
371
-     * @throws InvalidArgumentException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidInterfaceException
374
-     * @throws ReflectionException
375
-     */
376
-    public function unit_price(): float
377
-    {
378
-        return (float) $this->get('LIN_unit_price');
379
-    }
380
-
381
-
382
-    /**
383
-     * Sets unit_price
384
-     *
385
-     * @param int|float $unit_price
386
-     * @throws EE_Error
387
-     * @throws InvalidArgumentException
388
-     * @throws InvalidDataTypeException
389
-     * @throws InvalidInterfaceException
390
-     * @throws ReflectionException
391
-     */
392
-    public function set_unit_price($unit_price)
393
-    {
394
-        $this->set('LIN_unit_price', (float) $unit_price);
395
-    }
396
-
397
-
398
-    /**
399
-     * Checks if this item is a percentage modifier or not
400
-     *
401
-     * @return bool
402
-     * @throws EE_Error
403
-     * @throws InvalidArgumentException
404
-     * @throws InvalidDataTypeException
405
-     * @throws InvalidInterfaceException
406
-     * @throws ReflectionException
407
-     */
408
-    public function is_percent(): bool
409
-    {
410
-        if ($this->is_tax_sub_total()) {
411
-            // tax subtotals HAVE a percent on them, that percentage only applies
412
-            // to taxable items, so it's an exception. Treat it like a flat line item
413
-            return false;
414
-        }
415
-        $unit_price = abs($this->get('LIN_unit_price'));
416
-        $percent    = abs($this->get('LIN_percent'));
417
-        if ($unit_price < .001 && $percent) {
418
-            return true;
419
-        }
420
-        if ($unit_price >= .001 && ! $percent) {
421
-            return false;
422
-        }
423
-        if ($unit_price >= .001 && $percent) {
424
-            throw new EE_Error(
425
-                sprintf(
426
-                    esc_html__(
427
-                        'A Line Item can not have a unit price of (%s) AND a percent (%s)!',
428
-                        'event_espresso'
429
-                    ),
430
-                    $unit_price,
431
-                    $percent
432
-                )
433
-            );
434
-        }
435
-        // if they're both 0, assume it's not a percent item
436
-        return false;
437
-    }
438
-
439
-
440
-    /**
441
-     * Gets percent (between 100-.001)
442
-     *
443
-     * @return float
444
-     * @throws EE_Error
445
-     * @throws InvalidArgumentException
446
-     * @throws InvalidDataTypeException
447
-     * @throws InvalidInterfaceException
448
-     * @throws ReflectionException
449
-     */
450
-    public function percent(): float
451
-    {
452
-        return (float) $this->get('LIN_percent');
453
-    }
454
-
455
-
456
-    /**
457
-     * @return string
458
-     * @throws EE_Error
459
-     * @throws ReflectionException
460
-     * @since 5.0.0.p
461
-     */
462
-    public function prettyPercent(): string
463
-    {
464
-        return (string) $this->get_pretty('LIN_percent');
465
-    }
466
-
467
-
468
-    /**
469
-     * Sets percent (between 100-0.01)
470
-     *
471
-     * @param int|float $percent
472
-     * @throws EE_Error
473
-     * @throws InvalidArgumentException
474
-     * @throws InvalidDataTypeException
475
-     * @throws InvalidInterfaceException
476
-     * @throws ReflectionException
477
-     */
478
-    public function set_percent($percent)
479
-    {
480
-        $this->set('LIN_percent', (float) $percent);
481
-    }
482
-
483
-
484
-    /**
485
-     * Gets total
486
-     *
487
-     * @return float
488
-     * @throws EE_Error
489
-     * @throws InvalidArgumentException
490
-     * @throws InvalidDataTypeException
491
-     * @throws InvalidInterfaceException
492
-     * @throws ReflectionException
493
-     */
494
-    public function pretaxTotal(): float
495
-    {
496
-        return (float) $this->get('LIN_pretax');
497
-    }
498
-
499
-
500
-    /**
501
-     * Sets total
502
-     *
503
-     * @param int|float $pretax_total
504
-     * @throws EE_Error
505
-     * @throws InvalidArgumentException
506
-     * @throws InvalidDataTypeException
507
-     * @throws InvalidInterfaceException
508
-     * @throws ReflectionException
509
-     */
510
-    public function setPretaxTotal($pretax_total)
511
-    {
512
-        $this->set('LIN_pretax', (float) $pretax_total);
513
-    }
514
-
515
-
516
-    /**
517
-     * @return float
518
-     * @throws EE_Error
519
-     * @throws ReflectionException
520
-     * @since  5.0.0.p
521
-     */
522
-    public function totalWithTax(): float
523
-    {
524
-        return (float) $this->get('LIN_total');
525
-    }
526
-
527
-
528
-    /**
529
-     * Sets total
530
-     *
531
-     * @param int|float $total
532
-     * @throws EE_Error
533
-     * @throws ReflectionException
534
-     * @since  5.0.0.p
535
-     */
536
-    public function setTotalWithTax($total)
537
-    {
538
-        $this->set('LIN_total', (float) $total);
539
-    }
540
-
541
-
542
-    /**
543
-     * Gets total
544
-     *
545
-     * @return float
546
-     * @throws EE_Error
547
-     * @throws ReflectionException
548
-     * @deprecatd 5.0.0.p
549
-     */
550
-    public function total(): float
551
-    {
552
-        return $this->totalWithTax();
553
-    }
554
-
555
-
556
-    /**
557
-     * Sets total
558
-     *
559
-     * @param int|float $total
560
-     * @throws EE_Error
561
-     * @throws ReflectionException
562
-     * @deprecatd 5.0.0.p
563
-     */
564
-    public function set_total($total)
565
-    {
566
-        $this->setTotalWithTax((float) $total);
567
-    }
568
-
569
-
570
-    /**
571
-     * Gets order
572
-     *
573
-     * @return int
574
-     * @throws EE_Error
575
-     * @throws InvalidArgumentException
576
-     * @throws InvalidDataTypeException
577
-     * @throws InvalidInterfaceException
578
-     * @throws ReflectionException
579
-     */
580
-    public function order(): int
581
-    {
582
-        return (int) $this->get('LIN_order');
583
-    }
584
-
585
-
586
-    /**
587
-     * Sets order
588
-     *
589
-     * @param int $order
590
-     * @throws EE_Error
591
-     * @throws InvalidArgumentException
592
-     * @throws InvalidDataTypeException
593
-     * @throws InvalidInterfaceException
594
-     * @throws ReflectionException
595
-     */
596
-    public function set_order(int $order)
597
-    {
598
-        $this->set('LIN_order', $order);
599
-    }
600
-
601
-
602
-    /**
603
-     * Gets parent
604
-     *
605
-     * @return int
606
-     * @throws EE_Error
607
-     * @throws InvalidArgumentException
608
-     * @throws InvalidDataTypeException
609
-     * @throws InvalidInterfaceException
610
-     * @throws ReflectionException
611
-     */
612
-    public function parent_ID(): int
613
-    {
614
-        return (int) $this->get('LIN_parent');
615
-    }
616
-
617
-
618
-    /**
619
-     * Sets parent
620
-     *
621
-     * @param int $parent
622
-     * @throws EE_Error
623
-     * @throws InvalidArgumentException
624
-     * @throws InvalidDataTypeException
625
-     * @throws InvalidInterfaceException
626
-     * @throws ReflectionException
627
-     */
628
-    public function set_parent_ID(int $parent)
629
-    {
630
-        $this->set('LIN_parent', $parent);
631
-    }
632
-
633
-
634
-    /**
635
-     * Gets type
636
-     *
637
-     * @return string
638
-     * @throws EE_Error
639
-     * @throws InvalidArgumentException
640
-     * @throws InvalidDataTypeException
641
-     * @throws InvalidInterfaceException
642
-     * @throws ReflectionException
643
-     */
644
-    public function type(): string
645
-    {
646
-        return (string) $this->get('LIN_type');
647
-    }
648
-
649
-
650
-    /**
651
-     * Sets type
652
-     *
653
-     * @param string $type
654
-     * @throws EE_Error
655
-     * @throws InvalidArgumentException
656
-     * @throws InvalidDataTypeException
657
-     * @throws InvalidInterfaceException
658
-     * @throws ReflectionException
659
-     */
660
-    public function set_type(string $type)
661
-    {
662
-        $this->set('LIN_type', $type);
663
-    }
664
-
665
-
666
-    /**
667
-     * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\
668
-     * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB
669
-     * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()`
670
-     * or indirectly by `EE_Line_item::add_child_line_item()`)
671
-     *
672
-     * @return EE_Line_Item|null
673
-     * @throws EE_Error
674
-     * @throws InvalidArgumentException
675
-     * @throws InvalidDataTypeException
676
-     * @throws InvalidInterfaceException
677
-     * @throws ReflectionException
678
-     */
679
-    public function parent(): ?EE_Line_Item
680
-    {
681
-        if (! $this->_parent instanceof EE_Line_Item) {
682
-            $this->_parent = $this->ID()
683
-                ? $this->get_model()->get_one_by_ID($this->parent_ID())
684
-                : $this->_parent;
685
-        }
686
-        return $this->_parent;
687
-    }
688
-
689
-
690
-    /**
691
-     * Gets ALL the children of this line item (ie, all the parts that contribute towards this total).
692
-     *
693
-     * @return EE_Line_Item[]
694
-     * @throws EE_Error
695
-     * @throws InvalidArgumentException
696
-     * @throws InvalidDataTypeException
697
-     * @throws InvalidInterfaceException
698
-     * @throws ReflectionException
699
-     */
700
-    public function children(array $query_params = []): array
701
-    {
702
-        // check if the query params have changed since the last time we ran this query
703
-        $new_params = ! empty(EEH_Array::array_diff_recursive($query_params, $this->children_query_params));
704
-        if (($new_params || empty($this->_children)) && $this->ID()) {
705
-            $this->children_query_params = $query_params;
706
-            // ensure where params are an array
707
-            $query_params[0] = isset($query_params[0]) && is_array($query_params[0]) ? $query_params[0] : [];
708
-            // add defaults for line item parent and orderby
709
-            $query_params[0] += ['LIN_parent' => $this->ID()];
710
-            $query_params    += ['order_by' => ['LIN_order' => 'ASC']];
711
-            $children = $this->get_model()->get_all($query_params);
712
-            foreach ($children as $child) {
713
-                if ($child instanceof EE_Line_Item) {
714
-                    $this->_children[ $child->code() ] = $child;
715
-                }
716
-            }
717
-        }
718
-        return $this->_children;
719
-    }
720
-
721
-
722
-    /**
723
-     * Gets code
724
-     *
725
-     * @return string
726
-     * @throws EE_Error
727
-     * @throws InvalidArgumentException
728
-     * @throws InvalidDataTypeException
729
-     * @throws InvalidInterfaceException
730
-     * @throws ReflectionException
731
-     */
732
-    public function code(): string
733
-    {
734
-        return (string) $this->get('LIN_code');
735
-    }
736
-
737
-
738
-    /**
739
-     * Sets code
740
-     *
741
-     * @param string $code
742
-     * @throws EE_Error
743
-     * @throws InvalidArgumentException
744
-     * @throws InvalidDataTypeException
745
-     * @throws InvalidInterfaceException
746
-     * @throws ReflectionException
747
-     */
748
-    public function set_code(string $code)
749
-    {
750
-        $this->set('LIN_code', $code);
751
-    }
752
-
753
-
754
-    /**
755
-     * Gets is_taxable
756
-     *
757
-     * @return bool
758
-     * @throws EE_Error
759
-     * @throws InvalidArgumentException
760
-     * @throws InvalidDataTypeException
761
-     * @throws InvalidInterfaceException
762
-     * @throws ReflectionException
763
-     */
764
-    public function is_taxable(): bool
765
-    {
766
-        return (bool) $this->get('LIN_is_taxable');
767
-    }
768
-
769
-
770
-    /**
771
-     * Sets is_taxable
772
-     *
773
-     * @param bool $is_taxable
774
-     * @throws EE_Error
775
-     * @throws InvalidArgumentException
776
-     * @throws InvalidDataTypeException
777
-     * @throws InvalidInterfaceException
778
-     * @throws ReflectionException
779
-     */
780
-    public function set_is_taxable(bool $is_taxable)
781
-    {
782
-        $this->set('LIN_is_taxable', $is_taxable);
783
-    }
784
-
785
-
786
-    /**
787
-     * @param int $timestamp
788
-     * @throws EE_Error
789
-     * @throws ReflectionException
790
-     * @since 5.0.0.p
791
-     */
792
-    public function setTimestamp(int $timestamp)
793
-    {
794
-        $this->set('LIN_timestamp', $timestamp);
795
-    }
796
-
797
-
798
-    /**
799
-     * Gets the object that this model-joins-to.
800
-     * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on
801
-     * EEM_Promotion_Object
802
-     *        Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object
803
-     *
804
-     * @return EE_Base_Class|null
805
-     * @throws EE_Error
806
-     * @throws InvalidArgumentException
807
-     * @throws InvalidDataTypeException
808
-     * @throws InvalidInterfaceException
809
-     * @throws ReflectionException
810
-     */
811
-    public function get_object(): ?EE_Base_Class
812
-    {
813
-        $model_name_of_related_obj = $this->OBJ_type();
814
-        return $this->get_model()->has_relation($model_name_of_related_obj)
815
-            ? $this->get_first_related($model_name_of_related_obj)
816
-            : null;
817
-    }
818
-
819
-
820
-    /**
821
-     * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket.
822
-     * (IE, if this line item is for a price or something else, will return NULL)
823
-     *
824
-     * @param array $query_params deprecated 5.0.12.p
825
-     * @return EE_Ticket|null
826
-     * @throws EE_Error
827
-     * @throws ReflectionException
828
-     */
829
-    public function ticket(array $query_params = []): ?EE_Ticket
830
-    {
831
-        // we're going to assume that when this method is called
832
-        // we always want to receive the attached ticket EVEN if that ticket is archived.
833
-        if(! $this->OBJ_ID() || $this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
834
-            return null;
835
-        }
836
-        if(empty($query_args)) {
837
-            return EEM_Ticket::instance()->get_one_by_ID($this->OBJ_ID());
838
-        }
839
-        // legacy usage
840
-        $query_params += ['default_where_conditions' => 'none'];
841
-        return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params);
842
-    }
843
-
844
-
845
-    /**
846
-     * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket
847
-     *
848
-     * @return EE_Datetime|null
849
-     * @throws EE_Error
850
-     * @throws InvalidArgumentException
851
-     * @throws InvalidDataTypeException
852
-     * @throws InvalidInterfaceException
853
-     * @throws ReflectionException
854
-     */
855
-    public function get_ticket_datetime(): ?EE_Datetime
856
-    {
857
-        if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
858
-            $ticket = $this->ticket();
859
-            if ($ticket instanceof EE_Ticket) {
860
-                $datetime = $ticket->first_datetime();
861
-                if ($datetime instanceof EE_Datetime) {
862
-                    return $datetime;
863
-                }
864
-            }
865
-        }
866
-        return null;
867
-    }
868
-
869
-
870
-    /**
871
-     * Gets the event's name that's related to the ticket, if this is for
872
-     * a ticket
873
-     *
874
-     * @return string
875
-     * @throws EE_Error
876
-     * @throws InvalidArgumentException
877
-     * @throws InvalidDataTypeException
878
-     * @throws InvalidInterfaceException
879
-     * @throws ReflectionException
880
-     */
881
-    public function ticket_event_name(): string
882
-    {
883
-        $event_name = esc_html__('Unknown', 'event_espresso');
884
-        $event      = $this->ticket_event();
885
-        if ($event instanceof EE_Event) {
886
-            $event_name = $event->name();
887
-        }
888
-        return $event_name;
889
-    }
890
-
891
-
892
-    /**
893
-     * Gets the event that's related to the ticket, if this line item represents a ticket.
894
-     *
895
-     * @return EE_Event|null
896
-     * @throws EE_Error
897
-     * @throws InvalidArgumentException
898
-     * @throws InvalidDataTypeException
899
-     * @throws InvalidInterfaceException
900
-     * @throws ReflectionException
901
-     */
902
-    public function ticket_event(): ?EE_Event
903
-    {
904
-        $event  = null;
905
-        $ticket = $this->ticket();
906
-        if ($ticket instanceof EE_Ticket) {
907
-            $datetime = $ticket->first_datetime();
908
-            if ($datetime instanceof EE_Datetime) {
909
-                $event = $datetime->event();
910
-            }
911
-        }
912
-        return $event;
913
-    }
914
-
915
-
916
-    /**
917
-     * Gets the first datetime for this lien item, assuming it's for a ticket
918
-     *
919
-     * @param string $date_format
920
-     * @param string $time_format
921
-     * @return string
922
-     * @throws EE_Error
923
-     * @throws InvalidArgumentException
924
-     * @throws InvalidDataTypeException
925
-     * @throws InvalidInterfaceException
926
-     * @throws ReflectionException
927
-     */
928
-    public function ticket_datetime_start(string $date_format = '', string $time_format = ''): string
929
-    {
930
-        $first_datetime_string = esc_html__('Unknown', 'event_espresso');
931
-        $datetime              = $this->get_ticket_datetime();
932
-        if ($datetime) {
933
-            $first_datetime_string = $datetime->start_date_and_time($date_format, $time_format);
934
-        }
935
-        return $first_datetime_string;
936
-    }
937
-
938
-
939
-    /**
940
-     * Adds the line item as a child to this line item. If there is another child line
941
-     * item with the same LIN_code, it is overwritten by this new one
942
-     *
943
-     * @param EE_Line_Item $line_item
944
-     * @param bool         $set_order
945
-     * @return bool success
946
-     * @throws EE_Error
947
-     * @throws InvalidArgumentException
948
-     * @throws InvalidDataTypeException
949
-     * @throws InvalidInterfaceException
950
-     * @throws ReflectionException
951
-     */
952
-    public function add_child_line_item(EE_Line_Item $line_item, bool $set_order = true): bool
953
-    {
954
-        // should we calculate the LIN_order for this line item ?
955
-        if ($set_order || $line_item->order() === null) {
956
-            $line_item->set_order(count($this->children()));
957
-        }
958
-        if ($this->ID()) {
959
-            // check for any duplicate line items (with the same code), if so, this replaces it
960
-            $line_item_with_same_code = $this->get_child_line_item($line_item->code());
961
-            if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
962
-                $this->delete_child_line_item($line_item_with_same_code->code());
963
-            }
964
-            $line_item->set_parent_ID($this->ID());
965
-            if ($this->TXN_ID()) {
966
-                $line_item->set_TXN_ID($this->TXN_ID());
967
-            }
968
-            return (bool) $line_item->save();
969
-        }
970
-        $this->_children[ $line_item->code() ] = $line_item;
971
-        if ($line_item->parent() !== $this) {
972
-            $line_item->set_parent($this);
973
-        }
974
-        return true;
975
-    }
976
-
977
-
978
-    /**
979
-     * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation.
980
-     * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save()
981
-     * However, if this line item is NOT saved to the DB, this just caches the parent on
982
-     * the EE_Line_Item::_parent property.
983
-     *
984
-     * @param EE_Line_Item $line_item
985
-     * @throws EE_Error
986
-     * @throws InvalidArgumentException
987
-     * @throws InvalidDataTypeException
988
-     * @throws InvalidInterfaceException
989
-     * @throws ReflectionException
990
-     */
991
-    public function set_parent(EE_Line_Item $line_item)
992
-    {
993
-        if ($this->ID()) {
994
-            if (! $line_item->ID()) {
995
-                $line_item->save();
996
-            }
997
-            $this->set_parent_ID($line_item->ID());
998
-            $this->save();
999
-        } else {
1000
-            $this->_parent = $line_item;
1001
-            $this->set_parent_ID($line_item->ID());
1002
-        }
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * Gets the child line item as specified by its code. Because this returns an object (by reference)
1008
-     * you can modify this child line item and the parent (this object) can know about them
1009
-     * because it also has a reference to that line item
1010
-     *
1011
-     * @param string $code
1012
-     * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
1013
-     * @throws EE_Error
1014
-     * @throws InvalidArgumentException
1015
-     * @throws InvalidDataTypeException
1016
-     * @throws InvalidInterfaceException
1017
-     * @throws ReflectionException
1018
-     */
1019
-    public function get_child_line_item(string $code)
1020
-    {
1021
-        if ($this->ID()) {
1022
-            return $this->get_model()->get_one(
1023
-                [['LIN_parent' => $this->ID(), 'LIN_code' => $code]]
1024
-            );
1025
-        }
1026
-        return $this->_children[ $code ] ?? null;
1027
-    }
1028
-
1029
-
1030
-    /**
1031
-     * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD
1032
-     * cached on it)
1033
-     *
1034
-     * @return int
1035
-     * @throws EE_Error
1036
-     * @throws InvalidArgumentException
1037
-     * @throws InvalidDataTypeException
1038
-     * @throws InvalidInterfaceException
1039
-     * @throws ReflectionException
1040
-     */
1041
-    public function delete_children_line_items(): int
1042
-    {
1043
-        if ($this->ID()) {
1044
-            return (int) $this->get_model()->delete([['LIN_parent' => $this->ID()]]);
1045
-        }
1046
-        $count           = count($this->_children);
1047
-        $this->_children = [];
1048
-        return $count;
1049
-    }
1050
-
1051
-
1052
-    /**
1053
-     * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line
1054
-     * HAS NOT been saved to the DB, removes the child line item with index $code.
1055
-     * Also searches through the child's children for a matching line item. However, once a line item has been found
1056
-     * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be
1057
-     * deleted)
1058
-     *
1059
-     * @param string $code
1060
-     * @param bool   $stop_search_once_found
1061
-     * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to
1062
-     *             the DB yet)
1063
-     * @throws EE_Error
1064
-     * @throws InvalidArgumentException
1065
-     * @throws InvalidDataTypeException
1066
-     * @throws InvalidInterfaceException
1067
-     * @throws ReflectionException
1068
-     */
1069
-    public function delete_child_line_item(string $code, bool $stop_search_once_found = true): int
1070
-    {
1071
-        if ($this->ID()) {
1072
-            $items_deleted = 0;
1073
-            if ($this->code() === $code) {
1074
-                $items_deleted += EEH_Line_Item::delete_all_child_items($this);
1075
-                $items_deleted += (int) $this->delete();
1076
-                if ($stop_search_once_found) {
1077
-                    return $items_deleted;
1078
-                }
1079
-            }
1080
-            foreach ($this->children() as $child_line_item) {
1081
-                $items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found);
1082
-            }
1083
-            return $items_deleted;
1084
-        }
1085
-        if (isset($this->_children[ $code ])) {
1086
-            unset($this->_children[ $code ]);
1087
-            return 1;
1088
-        }
1089
-        return 0;
1090
-    }
1091
-
1092
-
1093
-    /**
1094
-     * If this line item is in the database, is of the type subtotal, and
1095
-     * has no children, why do we have it? It should be deleted so this function
1096
-     * does that
1097
-     *
1098
-     * @return bool
1099
-     * @throws EE_Error
1100
-     * @throws InvalidArgumentException
1101
-     * @throws InvalidDataTypeException
1102
-     * @throws InvalidInterfaceException
1103
-     * @throws ReflectionException
1104
-     */
1105
-    public function delete_if_childless_subtotal(): bool
1106
-    {
1107
-        if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) {
1108
-            return $this->delete();
1109
-        }
1110
-        return false;
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     * Creates a code and returns a string. doesn't assign the code to this model object
1116
-     *
1117
-     * @return string
1118
-     * @throws EE_Error
1119
-     * @throws InvalidArgumentException
1120
-     * @throws InvalidDataTypeException
1121
-     * @throws InvalidInterfaceException
1122
-     * @throws ReflectionException
1123
-     */
1124
-    public function generate_code(): string
1125
-    {
1126
-        // each line item in the cart requires a unique identifier
1127
-        return $this->get('OBJ_type') . '-' . $this->get('OBJ_ID');
1128
-    }
1129
-
1130
-
1131
-    /**
1132
-     * @return bool
1133
-     * @throws EE_Error
1134
-     * @throws InvalidArgumentException
1135
-     * @throws InvalidDataTypeException
1136
-     * @throws InvalidInterfaceException
1137
-     * @throws ReflectionException
1138
-     */
1139
-    public function isGlobalTax(): bool
1140
-    {
1141
-        return $this->type() === EEM_Line_Item::type_tax;
1142
-    }
1143
-
1144
-
1145
-    /**
1146
-     * @return bool
1147
-     * @throws EE_Error
1148
-     * @throws InvalidArgumentException
1149
-     * @throws InvalidDataTypeException
1150
-     * @throws InvalidInterfaceException
1151
-     * @throws ReflectionException
1152
-     */
1153
-    public function isSubTax(): bool
1154
-    {
1155
-        return $this->type() === EEM_Line_Item::type_sub_tax;
1156
-    }
1157
-
1158
-
1159
-    /**
1160
-     * returns true if this is a line item with a direct descendent of the type sub-tax
1161
-     *
1162
-     * @return array
1163
-     * @throws EE_Error
1164
-     * @throws InvalidArgumentException
1165
-     * @throws InvalidDataTypeException
1166
-     * @throws InvalidInterfaceException
1167
-     * @throws ReflectionException
1168
-     */
1169
-    public function getSubTaxes(): array
1170
-    {
1171
-        if (! $this->is_line_item()) {
1172
-            return [];
1173
-        }
1174
-        return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_sub_tax);
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * returns true if this is a line item with a direct descendent of the type sub-tax
1180
-     *
1181
-     * @return bool
1182
-     * @throws EE_Error
1183
-     * @throws InvalidArgumentException
1184
-     * @throws InvalidDataTypeException
1185
-     * @throws InvalidInterfaceException
1186
-     * @throws ReflectionException
1187
-     */
1188
-    public function hasSubTaxes(): bool
1189
-    {
1190
-        if (! $this->is_line_item()) {
1191
-            return false;
1192
-        }
1193
-        $sub_taxes = $this->getSubTaxes();
1194
-        return ! empty($sub_taxes);
1195
-    }
1196
-
1197
-
1198
-    /**
1199
-     * @return bool
1200
-     * @throws EE_Error
1201
-     * @throws ReflectionException
1202
-     * @deprecated   5.0.0.p
1203
-     */
1204
-    public function is_tax(): bool
1205
-    {
1206
-        return $this->isGlobalTax();
1207
-    }
1208
-
1209
-
1210
-    /**
1211
-     * @return bool
1212
-     * @throws EE_Error
1213
-     * @throws InvalidArgumentException
1214
-     * @throws InvalidDataTypeException
1215
-     * @throws InvalidInterfaceException
1216
-     * @throws ReflectionException
1217
-     */
1218
-    public function is_tax_sub_total(): bool
1219
-    {
1220
-        return $this->type() === EEM_Line_Item::type_tax_sub_total;
1221
-    }
1222
-
1223
-
1224
-    /**
1225
-     * @return bool
1226
-     * @throws EE_Error
1227
-     * @throws InvalidArgumentException
1228
-     * @throws InvalidDataTypeException
1229
-     * @throws InvalidInterfaceException
1230
-     * @throws ReflectionException
1231
-     */
1232
-    public function is_line_item(): bool
1233
-    {
1234
-        return $this->type() === EEM_Line_Item::type_line_item;
1235
-    }
1236
-
1237
-
1238
-    /**
1239
-     * @return bool
1240
-     * @throws EE_Error
1241
-     * @throws InvalidArgumentException
1242
-     * @throws InvalidDataTypeException
1243
-     * @throws InvalidInterfaceException
1244
-     * @throws ReflectionException
1245
-     */
1246
-    public function is_sub_line_item(): bool
1247
-    {
1248
-        return $this->type() === EEM_Line_Item::type_sub_line_item;
1249
-    }
1250
-
1251
-
1252
-    /**
1253
-     * @return bool
1254
-     * @throws EE_Error
1255
-     * @throws InvalidArgumentException
1256
-     * @throws InvalidDataTypeException
1257
-     * @throws InvalidInterfaceException
1258
-     * @throws ReflectionException
1259
-     */
1260
-    public function is_sub_total(): bool
1261
-    {
1262
-        return $this->type() === EEM_Line_Item::type_sub_total;
1263
-    }
1264
-
1265
-
1266
-    /**
1267
-     * Whether this line item is a cancellation line item
1268
-     *
1269
-     * @return bool
1270
-     * @throws EE_Error
1271
-     * @throws InvalidArgumentException
1272
-     * @throws InvalidDataTypeException
1273
-     * @throws InvalidInterfaceException
1274
-     * @throws ReflectionException
1275
-     */
1276
-    public function is_cancellation(): bool
1277
-    {
1278
-        return EEM_Line_Item::type_cancellation === $this->type();
1279
-    }
1280
-
1281
-
1282
-    /**
1283
-     * @return bool
1284
-     * @throws EE_Error
1285
-     * @throws InvalidArgumentException
1286
-     * @throws InvalidDataTypeException
1287
-     * @throws InvalidInterfaceException
1288
-     * @throws ReflectionException
1289
-     */
1290
-    public function is_total(): bool
1291
-    {
1292
-        return $this->type() === EEM_Line_Item::type_total;
1293
-    }
1294
-
1295
-
1296
-    /**
1297
-     * @return bool
1298
-     * @throws EE_Error
1299
-     * @throws InvalidArgumentException
1300
-     * @throws InvalidDataTypeException
1301
-     * @throws InvalidInterfaceException
1302
-     * @throws ReflectionException
1303
-     */
1304
-    public function is_cancelled(): bool
1305
-    {
1306
-        return $this->type() === EEM_Line_Item::type_cancellation;
1307
-    }
1308
-
1309
-
1310
-    /**
1311
-     * @return string like '2, 004.00', formatted according to the localized currency
1312
-     * @throws EE_Error
1313
-     * @throws ReflectionException
1314
-     */
1315
-    public function unit_price_no_code(): string
1316
-    {
1317
-        return $this->prettyUnitPrice();
1318
-    }
1319
-
1320
-
1321
-    /**
1322
-     * @return string like '2, 004.00', formatted according to the localized currency
1323
-     * @throws EE_Error
1324
-     * @throws ReflectionException
1325
-     * @since 5.0.0.p
1326
-     */
1327
-    public function prettyUnitPrice(): string
1328
-    {
1329
-        return $this->get_pretty('LIN_unit_price', 'no_currency_code');
1330
-    }
1331
-
1332
-
1333
-    /**
1334
-     * @return string like '2, 004.00', formatted according to the localized currency
1335
-     * @throws EE_Error
1336
-     * @throws ReflectionException
1337
-     */
1338
-    public function total_no_code(): string
1339
-    {
1340
-        return $this->prettyTotal();
1341
-    }
1342
-
1343
-
1344
-    /**
1345
-     * @return string like '2, 004.00', formatted according to the localized currency
1346
-     * @throws EE_Error
1347
-     * @throws ReflectionException
1348
-     * @since 5.0.0.p
1349
-     */
1350
-    public function prettyTotal(): string
1351
-    {
1352
-        return $this->get_pretty('LIN_total', 'no_currency_code');
1353
-    }
1354
-
1355
-
1356
-    /**
1357
-     * Gets the final total on this item, taking taxes into account.
1358
-     * Has the side effect of setting the sub-total as it was just calculated.
1359
-     * If this is used on a grand-total line item, also updates the transaction's
1360
-     * TXN_total (provided this line item is allowed to persist, otherwise we don't
1361
-     * want to change a persistable transaction with info from a non-persistent line item)
1362
-     *
1363
-     * @param bool $update_txn_status
1364
-     * @return float
1365
-     * @throws EE_Error
1366
-     * @throws InvalidArgumentException
1367
-     * @throws InvalidDataTypeException
1368
-     * @throws InvalidInterfaceException
1369
-     * @throws ReflectionException
1370
-     * @throws RuntimeException
1371
-     */
1372
-    public function recalculate_total_including_taxes(bool $update_txn_status = false): float
1373
-    {
1374
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1375
-        return $this->calculator->recalculateTotalIncludingTaxes($grand_total_line_item, $update_txn_status);
1376
-    }
1377
-
1378
-
1379
-    /**
1380
-     * Recursively goes through all the children and recalculates sub-totals EXCEPT for
1381
-     * tax-sub-totals (they're an odd beast). Updates the 'total' on each line item according to either its
1382
-     * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
1383
-     * when this is called on the grand total
1384
-     *
1385
-     * @return float
1386
-     * @throws EE_Error
1387
-     * @throws InvalidArgumentException
1388
-     * @throws InvalidDataTypeException
1389
-     * @throws InvalidInterfaceException
1390
-     * @throws ReflectionException
1391
-     */
1392
-    public function recalculate_pre_tax_total(): float
1393
-    {
1394
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1395
-        [$total] = $this->calculator->recalculateLineItemTotals($grand_total_line_item);
1396
-        return (float) $total;
1397
-    }
1398
-
1399
-
1400
-    /**
1401
-     * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
1402
-     * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
1403
-     * and tax sub-total if already in the DB
1404
-     *
1405
-     * @return float
1406
-     * @throws EE_Error
1407
-     * @throws InvalidArgumentException
1408
-     * @throws InvalidDataTypeException
1409
-     * @throws InvalidInterfaceException
1410
-     * @throws ReflectionException
1411
-     */
1412
-    public function recalculate_taxes_and_tax_total(): float
1413
-    {
1414
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1415
-        return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item);
1416
-    }
1417
-
1418
-
1419
-    /**
1420
-     * Gets the total tax on this line item. Assumes taxes have already been calculated using
1421
-     * recalculate_taxes_and_total
1422
-     *
1423
-     * @return float
1424
-     * @throws EE_Error
1425
-     * @throws InvalidArgumentException
1426
-     * @throws InvalidDataTypeException
1427
-     * @throws InvalidInterfaceException
1428
-     * @throws ReflectionException
1429
-     */
1430
-    public function get_total_tax(): float
1431
-    {
1432
-        $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1433
-        return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item);
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * Gets the total for all the items purchased only
1439
-     *
1440
-     * @return float
1441
-     * @throws EE_Error
1442
-     * @throws InvalidArgumentException
1443
-     * @throws InvalidDataTypeException
1444
-     * @throws InvalidInterfaceException
1445
-     * @throws ReflectionException
1446
-     */
1447
-    public function get_items_total()
1448
-    {
1449
-        // by default, let's make sure we're consistent with the existing line item
1450
-        if ($this->is_total()) {
1451
-            return $this->pretaxTotal();
1452
-        }
1453
-        $total = 0;
1454
-        foreach ($this->get_items() as $item) {
1455
-            if ($item instanceof EE_Line_Item) {
1456
-                $total += $item->pretaxTotal();
1457
-            }
1458
-        }
1459
-        return $total;
1460
-    }
1461
-
1462
-
1463
-    /**
1464
-     * Gets all the descendants (ie, children or children of children etc.) that
1465
-     * are of the type 'tax'
1466
-     *
1467
-     * @return EE_Line_Item[]
1468
-     * @throws EE_Error
1469
-     * @throws ReflectionException
1470
-     */
1471
-    public function tax_descendants(): array
1472
-    {
1473
-        return EEH_Line_Item::get_tax_descendants($this);
1474
-    }
1475
-
1476
-
1477
-    /**
1478
-     * Gets all the real items purchased which are children of this item
1479
-     *
1480
-     * @return EE_Line_Item[]
1481
-     * @throws EE_Error
1482
-     * @throws ReflectionException
1483
-     */
1484
-    public function get_items(): array
1485
-    {
1486
-        return EEH_Line_Item::get_line_item_descendants($this);
1487
-    }
1488
-
1489
-
1490
-    /**
1491
-     * Returns the amount taxable among this line item's children (or if it has no children,
1492
-     * how much of it is taxable). Does not recalculate totals or subtotals.
1493
-     * If the taxable total is negative, (eg, if none of the tickets were taxable,
1494
-     * but there is a "Taxable" discount), returns 0.
1495
-     *
1496
-     * @return float
1497
-     * @throws EE_Error
1498
-     * @throws InvalidArgumentException
1499
-     * @throws InvalidDataTypeException
1500
-     * @throws InvalidInterfaceException
1501
-     * @throws ReflectionException
1502
-     */
1503
-    public function taxable_total(): float
1504
-    {
1505
-        return $this->calculator->taxableAmountForGlobalTaxes($this);
1506
-    }
1507
-
1508
-
1509
-    /**
1510
-     * Gets the transaction for this line item
1511
-     *
1512
-     * @return EE_Transaction|null
1513
-     * @throws EE_Error
1514
-     * @throws InvalidArgumentException
1515
-     * @throws InvalidDataTypeException
1516
-     * @throws InvalidInterfaceException
1517
-     * @throws ReflectionException
1518
-     */
1519
-    public function transaction(): ?EE_Transaction
1520
-    {
1521
-        return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION);
1522
-    }
1523
-
1524
-
1525
-    /**
1526
-     * Saves this line item to the DB, and recursively saves its descendants.
1527
-     * Because there currently is no proper parent-child relation on the model,
1528
-     * save_this_and_cached() will NOT save the descendants.
1529
-     * Also sets the transaction on this line item and all its descendants before saving
1530
-     *
1531
-     * @param int|null $txn_id if none is provided, assumes $this->TXN_ID()
1532
-     * @return int count of items saved
1533
-     * @throws EE_Error
1534
-     * @throws InvalidArgumentException
1535
-     * @throws InvalidDataTypeException
1536
-     * @throws InvalidInterfaceException
1537
-     * @throws ReflectionException
1538
-     */
1539
-    public function save_this_and_descendants_to_txn(int $txn_id = 0): int
1540
-    {
1541
-        $count = 0;
1542
-        if ($txn_id) {
1543
-            $this->set_TXN_ID($txn_id);
1544
-        }
1545
-        $children = $this->children();
1546
-        $count    += $this->save() ? 1 : 0;
1547
-        foreach ($children as $child_line_item) {
1548
-            if ($child_line_item instanceof EE_Line_Item) {
1549
-                $child_line_item->set_parent_ID($this->ID());
1550
-                $count += $child_line_item->save_this_and_descendants_to_txn($txn_id);
1551
-            }
1552
-        }
1553
-        return $count;
1554
-    }
1555
-
1556
-
1557
-    /**
1558
-     * Saves this line item to the DB, and recursively saves its descendants.
1559
-     *
1560
-     * @return int count of items saved
1561
-     * @throws EE_Error
1562
-     * @throws InvalidArgumentException
1563
-     * @throws InvalidDataTypeException
1564
-     * @throws InvalidInterfaceException
1565
-     * @throws ReflectionException
1566
-     */
1567
-    public function save_this_and_descendants(): int
1568
-    {
1569
-        $count    = 0;
1570
-        $children = $this->children();
1571
-        $count    += $this->save() ? 1 : 0;
1572
-        foreach ($children as $child_line_item) {
1573
-            if ($child_line_item instanceof EE_Line_Item) {
1574
-                $child_line_item->set_parent_ID($this->ID());
1575
-                $count += $child_line_item->save_this_and_descendants();
1576
-            }
1577
-        }
1578
-        return $count;
1579
-    }
1580
-
1581
-
1582
-    /**
1583
-     * returns the cancellation line item if this item was cancelled
1584
-     *
1585
-     * @return EE_Line_Item[]
1586
-     * @throws InvalidArgumentException
1587
-     * @throws InvalidInterfaceException
1588
-     * @throws InvalidDataTypeException
1589
-     * @throws ReflectionException
1590
-     * @throws EE_Error
1591
-     */
1592
-    public function get_cancellations(): array
1593
-    {
1594
-        return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation);
1595
-    }
1596
-
1597
-
1598
-    /**
1599
-     * If this item has an ID, then this saves it again to update the db
1600
-     *
1601
-     * @return bool|int count of items saved or false on error
1602
-     * @throws EE_Error
1603
-     * @throws InvalidArgumentException
1604
-     * @throws InvalidDataTypeException
1605
-     * @throws InvalidInterfaceException
1606
-     * @throws ReflectionException
1607
-     */
1608
-    public function maybe_save()
1609
-    {
1610
-        if ($this->ID()) {
1611
-            return $this->save();
1612
-        }
1613
-        return false;
1614
-    }
1615
-
1616
-
1617
-    /**
1618
-     * clears the cached children and parent from the line item
1619
-     *
1620
-     * @return void
1621
-     */
1622
-    public function clear_related_line_item_cache()
1623
-    {
1624
-        $this->_children = [];
1625
-        $this->_parent   = null;
1626
-    }
1627
-
1628
-
1629
-    /**
1630
-     * @param bool $raw
1631
-     * @return int|string
1632
-     * @throws EE_Error
1633
-     * @throws InvalidArgumentException
1634
-     * @throws InvalidDataTypeException
1635
-     * @throws InvalidInterfaceException
1636
-     * @throws ReflectionException
1637
-     */
1638
-    public function timestamp(bool $raw = false)
1639
-    {
1640
-        return $raw
1641
-            ? (int) $this->get_raw('LIN_timestamp')
1642
-            : (string) $this->get('LIN_timestamp');
1643
-    }
1644
-
1645
-
1646
-
1647
-
1648
-    /************************* DEPRECATED *************************/
1649
-    /**
1650
-     * @param string $type one of the constants on EEM_Line_Item
1651
-     * @return EE_Line_Item[]
1652
-     * @throws EE_Error
1653
-     * @throws ReflectionException
1654
-     * @deprecated 4.6.0
1655
-     */
1656
-    protected function _get_descendants_of_type(string $type): array
1657
-    {
1658
-        EE_Error::doing_it_wrong(
1659
-            'EE_Line_Item::_get_descendants_of_type()',
1660
-            sprintf(
1661
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
1662
-                'EEH_Line_Item::get_descendants_of_type()'
1663
-            ),
1664
-            '4.6.0'
1665
-        );
1666
-        return EEH_Line_Item::get_descendants_of_type($this, $type);
1667
-    }
1668
-
1669
-
1670
-    /**
1671
-     * @param string $type like one of the EEM_Line_Item::type_*
1672
-     * @return EE_Line_Item
1673
-     * @throws EE_Error
1674
-     * @throws InvalidArgumentException
1675
-     * @throws InvalidDataTypeException
1676
-     * @throws InvalidInterfaceException
1677
-     * @throws ReflectionException
1678
-     * @deprecated 4.6.0
1679
-     */
1680
-    public function get_nearest_descendant_of_type(string $type): EE_Line_Item
1681
-    {
1682
-        EE_Error::doing_it_wrong(
1683
-            'EE_Line_Item::get_nearest_descendant_of_type()',
1684
-            sprintf(
1685
-                esc_html__('Method replaced with %1$s', 'event_espresso'),
1686
-                'EEH_Line_Item::get_nearest_descendant_of_type()'
1687
-            ),
1688
-            '4.6.0'
1689
-        );
1690
-        return EEH_Line_Item::get_nearest_descendant_of_type($this, $type);
1691
-    }
19
+	/**
20
+	 * for children line items (currently not a normal relation)
21
+	 *
22
+	 * @var EE_Line_Item[]
23
+	 */
24
+	protected array $_children = [];
25
+
26
+	/**
27
+	 * query params used to obtain children line items above
28
+	 *
29
+	 * @var array
30
+	 */
31
+	private array $children_query_params = [];
32
+
33
+	/**
34
+	 * for the parent line item
35
+	 *
36
+	 * @var EE_Line_Item|null
37
+	 */
38
+	protected ?EE_Line_Item $_parent = null;
39
+
40
+	/**
41
+	 * @var LineItemCalculator
42
+	 */
43
+	protected LineItemCalculator $calculator;
44
+
45
+
46
+	/**
47
+	 * @param array       $props_n_values incoming values
48
+	 * @param string|null $timezone       incoming timezone as set by the model.
49
+	 *                                    If not set the timezone for the website will be used.
50
+	 * @param array       $date_formats   incoming date_formats in an array where the first value is the
51
+	 *                                    date_format and the second value is the time format
52
+	 * @return EE_Line_Item
53
+	 * @throws EE_Error
54
+	 * @throws InvalidArgumentException
55
+	 * @throws InvalidDataTypeException
56
+	 * @throws InvalidInterfaceException
57
+	 * @throws ReflectionException
58
+	 */
59
+	public static function new_instance(
60
+		array $props_n_values = [],
61
+		?string $timezone = '',
62
+		array $date_formats = []
63
+	): EE_Line_Item {
64
+		$has_object = parent::_check_for_object(
65
+			$props_n_values,
66
+			__CLASS__,
67
+			$timezone,
68
+			$date_formats
69
+		);
70
+		return $has_object ?: new self($props_n_values, false, $timezone);
71
+	}
72
+
73
+
74
+	/**
75
+	 * @param array       $props_n_values incoming values from the database
76
+	 * @param string|null $timezone       incoming timezone as set by the model.
77
+	 *                                    If not set the timezone for the website will be used.
78
+	 * @return EE_Line_Item
79
+	 * @throws EE_Error
80
+	 * @throws InvalidArgumentException
81
+	 * @throws InvalidDataTypeException
82
+	 * @throws InvalidInterfaceException
83
+	 * @throws ReflectionException
84
+	 */
85
+	public static function new_instance_from_db(array $props_n_values = [], ?string $timezone = ''): EE_Line_Item
86
+	{
87
+		return new self($props_n_values, true, $timezone);
88
+	}
89
+
90
+
91
+	/**
92
+	 * Adds some defaults if they're not specified
93
+	 *
94
+	 * @param array  $fieldValues
95
+	 * @param bool   $bydb
96
+	 * @param string $timezone
97
+	 * @throws EE_Error
98
+	 * @throws InvalidArgumentException
99
+	 * @throws InvalidDataTypeException
100
+	 * @throws InvalidInterfaceException
101
+	 * @throws ReflectionException
102
+	 */
103
+	protected function __construct($fieldValues = [], $bydb = false, $timezone = '')
104
+	{
105
+		$this->calculator = LoaderFactory::getShared(LineItemCalculator::class);
106
+		parent::__construct($fieldValues, $bydb, $timezone);
107
+		if (! $this->get('LIN_code')) {
108
+			$this->set_code($this->generate_code());
109
+		}
110
+	}
111
+
112
+
113
+	public function __wakeup()
114
+	{
115
+		$this->calculator = LoaderFactory::getShared(LineItemCalculator::class);
116
+		parent::__wakeup();
117
+	}
118
+
119
+
120
+	/**
121
+	 * Gets ID
122
+	 *
123
+	 * @return int
124
+	 * @throws EE_Error
125
+	 * @throws InvalidArgumentException
126
+	 * @throws InvalidDataTypeException
127
+	 * @throws InvalidInterfaceException
128
+	 * @throws ReflectionException
129
+	 */
130
+	public function ID(): int
131
+	{
132
+		return (int) $this->get('LIN_ID');
133
+	}
134
+
135
+
136
+	/**
137
+	 * Gets TXN_ID
138
+	 *
139
+	 * @return int
140
+	 * @throws EE_Error
141
+	 * @throws InvalidArgumentException
142
+	 * @throws InvalidDataTypeException
143
+	 * @throws InvalidInterfaceException
144
+	 * @throws ReflectionException
145
+	 */
146
+	public function TXN_ID(): int
147
+	{
148
+		return (int) $this->get('TXN_ID');
149
+	}
150
+
151
+
152
+	/**
153
+	 * Sets TXN_ID
154
+	 *
155
+	 * @param int $TXN_ID
156
+	 * @throws EE_Error
157
+	 * @throws InvalidArgumentException
158
+	 * @throws InvalidDataTypeException
159
+	 * @throws InvalidInterfaceException
160
+	 * @throws ReflectionException
161
+	 */
162
+	public function set_TXN_ID(int $TXN_ID)
163
+	{
164
+		$this->set('TXN_ID', $TXN_ID);
165
+	}
166
+
167
+
168
+	/**
169
+	 * Gets name
170
+	 *
171
+	 * @return string
172
+	 * @throws EE_Error
173
+	 * @throws InvalidArgumentException
174
+	 * @throws InvalidDataTypeException
175
+	 * @throws InvalidInterfaceException
176
+	 * @throws ReflectionException
177
+	 */
178
+	public function name(): string
179
+	{
180
+		$name = (string) $this->get('LIN_name');
181
+		if (! $name) {
182
+			$name = ucwords(str_replace('-', ' ', $this->type()));
183
+		}
184
+		return $name;
185
+	}
186
+
187
+
188
+	/**
189
+	 * Sets name
190
+	 *
191
+	 * @param string $name
192
+	 * @throws EE_Error
193
+	 * @throws InvalidArgumentException
194
+	 * @throws InvalidDataTypeException
195
+	 * @throws InvalidInterfaceException
196
+	 * @throws ReflectionException
197
+	 */
198
+	public function set_name(string $name)
199
+	{
200
+		$this->set('LIN_name', $name);
201
+	}
202
+
203
+
204
+	/**
205
+	 * Gets desc
206
+	 *
207
+	 * @return string
208
+	 * @throws EE_Error
209
+	 * @throws InvalidArgumentException
210
+	 * @throws InvalidDataTypeException
211
+	 * @throws InvalidInterfaceException
212
+	 * @throws ReflectionException
213
+	 */
214
+	public function desc(): string
215
+	{
216
+		return (string) $this->get('LIN_desc');
217
+	}
218
+
219
+
220
+	/**
221
+	 * Sets desc
222
+	 *
223
+	 * @param string $desc
224
+	 * @throws EE_Error
225
+	 * @throws InvalidArgumentException
226
+	 * @throws InvalidDataTypeException
227
+	 * @throws InvalidInterfaceException
228
+	 * @throws ReflectionException
229
+	 */
230
+	public function set_desc(string $desc)
231
+	{
232
+		$this->set('LIN_desc', $desc);
233
+	}
234
+
235
+
236
+	/**
237
+	 * Gets quantity
238
+	 *
239
+	 * @return int
240
+	 * @throws EE_Error
241
+	 * @throws InvalidArgumentException
242
+	 * @throws InvalidDataTypeException
243
+	 * @throws InvalidInterfaceException
244
+	 * @throws ReflectionException
245
+	 */
246
+	public function quantity(): int
247
+	{
248
+		return (int) $this->get('LIN_quantity');
249
+	}
250
+
251
+
252
+	/**
253
+	 * Sets quantity
254
+	 *
255
+	 * @param int $quantity
256
+	 * @throws EE_Error
257
+	 * @throws InvalidArgumentException
258
+	 * @throws InvalidDataTypeException
259
+	 * @throws InvalidInterfaceException
260
+	 * @throws ReflectionException
261
+	 */
262
+	public function set_quantity(int $quantity)
263
+	{
264
+		$this->set('LIN_quantity', max($quantity, 0));
265
+	}
266
+
267
+
268
+	/**
269
+	 * Gets item_id
270
+	 *
271
+	 * @return int
272
+	 * @throws EE_Error
273
+	 * @throws InvalidArgumentException
274
+	 * @throws InvalidDataTypeException
275
+	 * @throws InvalidInterfaceException
276
+	 * @throws ReflectionException
277
+	 */
278
+	public function OBJ_ID(): int
279
+	{
280
+		return (int) $this->get('OBJ_ID');
281
+	}
282
+
283
+
284
+	/**
285
+	 * Sets item_id
286
+	 *
287
+	 * @param int $item_id
288
+	 * @throws EE_Error
289
+	 * @throws InvalidArgumentException
290
+	 * @throws InvalidDataTypeException
291
+	 * @throws InvalidInterfaceException
292
+	 * @throws ReflectionException
293
+	 */
294
+	public function set_OBJ_ID(int $item_id)
295
+	{
296
+		$this->set('OBJ_ID', $item_id);
297
+	}
298
+
299
+
300
+	/**
301
+	 * Gets item_type
302
+	 *
303
+	 * @return string
304
+	 * @throws EE_Error
305
+	 * @throws InvalidArgumentException
306
+	 * @throws InvalidDataTypeException
307
+	 * @throws InvalidInterfaceException
308
+	 * @throws ReflectionException
309
+	 */
310
+	public function OBJ_type(): string
311
+	{
312
+		return (string) $this->get('OBJ_type');
313
+	}
314
+
315
+
316
+	/**
317
+	 * Gets item_type
318
+	 *
319
+	 * @return string
320
+	 * @throws EE_Error
321
+	 * @throws InvalidArgumentException
322
+	 * @throws InvalidDataTypeException
323
+	 * @throws InvalidInterfaceException
324
+	 * @throws ReflectionException
325
+	 */
326
+	public function OBJ_type_i18n(): string
327
+	{
328
+		$obj_type = $this->OBJ_type();
329
+		switch ($obj_type) {
330
+			case EEM_Line_Item::OBJ_TYPE_EVENT:
331
+				$obj_type = esc_html__('Event', 'event_espresso');
332
+				break;
333
+			case EEM_Line_Item::OBJ_TYPE_PRICE:
334
+				$obj_type = esc_html__('Price', 'event_espresso');
335
+				break;
336
+			case EEM_Line_Item::OBJ_TYPE_PROMOTION:
337
+				$obj_type = esc_html__('Promotion', 'event_espresso');
338
+				break;
339
+			case EEM_Line_Item::OBJ_TYPE_TICKET:
340
+				$obj_type = esc_html__('Ticket', 'event_espresso');
341
+				break;
342
+			case EEM_Line_Item::OBJ_TYPE_TRANSACTION:
343
+				$obj_type = esc_html__('Transaction', 'event_espresso');
344
+				break;
345
+		}
346
+		return (string) apply_filters('FHEE__EE_Line_Item__OBJ_type_i18n', $obj_type, $this);
347
+	}
348
+
349
+
350
+	/**
351
+	 * Sets item_type
352
+	 *
353
+	 * @param string $OBJ_type
354
+	 * @throws EE_Error
355
+	 * @throws InvalidArgumentException
356
+	 * @throws InvalidDataTypeException
357
+	 * @throws InvalidInterfaceException
358
+	 * @throws ReflectionException
359
+	 */
360
+	public function set_OBJ_type(string $OBJ_type)
361
+	{
362
+		$this->set('OBJ_type', $OBJ_type);
363
+	}
364
+
365
+
366
+	/**
367
+	 * Gets unit_price
368
+	 *
369
+	 * @return float
370
+	 * @throws EE_Error
371
+	 * @throws InvalidArgumentException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidInterfaceException
374
+	 * @throws ReflectionException
375
+	 */
376
+	public function unit_price(): float
377
+	{
378
+		return (float) $this->get('LIN_unit_price');
379
+	}
380
+
381
+
382
+	/**
383
+	 * Sets unit_price
384
+	 *
385
+	 * @param int|float $unit_price
386
+	 * @throws EE_Error
387
+	 * @throws InvalidArgumentException
388
+	 * @throws InvalidDataTypeException
389
+	 * @throws InvalidInterfaceException
390
+	 * @throws ReflectionException
391
+	 */
392
+	public function set_unit_price($unit_price)
393
+	{
394
+		$this->set('LIN_unit_price', (float) $unit_price);
395
+	}
396
+
397
+
398
+	/**
399
+	 * Checks if this item is a percentage modifier or not
400
+	 *
401
+	 * @return bool
402
+	 * @throws EE_Error
403
+	 * @throws InvalidArgumentException
404
+	 * @throws InvalidDataTypeException
405
+	 * @throws InvalidInterfaceException
406
+	 * @throws ReflectionException
407
+	 */
408
+	public function is_percent(): bool
409
+	{
410
+		if ($this->is_tax_sub_total()) {
411
+			// tax subtotals HAVE a percent on them, that percentage only applies
412
+			// to taxable items, so it's an exception. Treat it like a flat line item
413
+			return false;
414
+		}
415
+		$unit_price = abs($this->get('LIN_unit_price'));
416
+		$percent    = abs($this->get('LIN_percent'));
417
+		if ($unit_price < .001 && $percent) {
418
+			return true;
419
+		}
420
+		if ($unit_price >= .001 && ! $percent) {
421
+			return false;
422
+		}
423
+		if ($unit_price >= .001 && $percent) {
424
+			throw new EE_Error(
425
+				sprintf(
426
+					esc_html__(
427
+						'A Line Item can not have a unit price of (%s) AND a percent (%s)!',
428
+						'event_espresso'
429
+					),
430
+					$unit_price,
431
+					$percent
432
+				)
433
+			);
434
+		}
435
+		// if they're both 0, assume it's not a percent item
436
+		return false;
437
+	}
438
+
439
+
440
+	/**
441
+	 * Gets percent (between 100-.001)
442
+	 *
443
+	 * @return float
444
+	 * @throws EE_Error
445
+	 * @throws InvalidArgumentException
446
+	 * @throws InvalidDataTypeException
447
+	 * @throws InvalidInterfaceException
448
+	 * @throws ReflectionException
449
+	 */
450
+	public function percent(): float
451
+	{
452
+		return (float) $this->get('LIN_percent');
453
+	}
454
+
455
+
456
+	/**
457
+	 * @return string
458
+	 * @throws EE_Error
459
+	 * @throws ReflectionException
460
+	 * @since 5.0.0.p
461
+	 */
462
+	public function prettyPercent(): string
463
+	{
464
+		return (string) $this->get_pretty('LIN_percent');
465
+	}
466
+
467
+
468
+	/**
469
+	 * Sets percent (between 100-0.01)
470
+	 *
471
+	 * @param int|float $percent
472
+	 * @throws EE_Error
473
+	 * @throws InvalidArgumentException
474
+	 * @throws InvalidDataTypeException
475
+	 * @throws InvalidInterfaceException
476
+	 * @throws ReflectionException
477
+	 */
478
+	public function set_percent($percent)
479
+	{
480
+		$this->set('LIN_percent', (float) $percent);
481
+	}
482
+
483
+
484
+	/**
485
+	 * Gets total
486
+	 *
487
+	 * @return float
488
+	 * @throws EE_Error
489
+	 * @throws InvalidArgumentException
490
+	 * @throws InvalidDataTypeException
491
+	 * @throws InvalidInterfaceException
492
+	 * @throws ReflectionException
493
+	 */
494
+	public function pretaxTotal(): float
495
+	{
496
+		return (float) $this->get('LIN_pretax');
497
+	}
498
+
499
+
500
+	/**
501
+	 * Sets total
502
+	 *
503
+	 * @param int|float $pretax_total
504
+	 * @throws EE_Error
505
+	 * @throws InvalidArgumentException
506
+	 * @throws InvalidDataTypeException
507
+	 * @throws InvalidInterfaceException
508
+	 * @throws ReflectionException
509
+	 */
510
+	public function setPretaxTotal($pretax_total)
511
+	{
512
+		$this->set('LIN_pretax', (float) $pretax_total);
513
+	}
514
+
515
+
516
+	/**
517
+	 * @return float
518
+	 * @throws EE_Error
519
+	 * @throws ReflectionException
520
+	 * @since  5.0.0.p
521
+	 */
522
+	public function totalWithTax(): float
523
+	{
524
+		return (float) $this->get('LIN_total');
525
+	}
526
+
527
+
528
+	/**
529
+	 * Sets total
530
+	 *
531
+	 * @param int|float $total
532
+	 * @throws EE_Error
533
+	 * @throws ReflectionException
534
+	 * @since  5.0.0.p
535
+	 */
536
+	public function setTotalWithTax($total)
537
+	{
538
+		$this->set('LIN_total', (float) $total);
539
+	}
540
+
541
+
542
+	/**
543
+	 * Gets total
544
+	 *
545
+	 * @return float
546
+	 * @throws EE_Error
547
+	 * @throws ReflectionException
548
+	 * @deprecatd 5.0.0.p
549
+	 */
550
+	public function total(): float
551
+	{
552
+		return $this->totalWithTax();
553
+	}
554
+
555
+
556
+	/**
557
+	 * Sets total
558
+	 *
559
+	 * @param int|float $total
560
+	 * @throws EE_Error
561
+	 * @throws ReflectionException
562
+	 * @deprecatd 5.0.0.p
563
+	 */
564
+	public function set_total($total)
565
+	{
566
+		$this->setTotalWithTax((float) $total);
567
+	}
568
+
569
+
570
+	/**
571
+	 * Gets order
572
+	 *
573
+	 * @return int
574
+	 * @throws EE_Error
575
+	 * @throws InvalidArgumentException
576
+	 * @throws InvalidDataTypeException
577
+	 * @throws InvalidInterfaceException
578
+	 * @throws ReflectionException
579
+	 */
580
+	public function order(): int
581
+	{
582
+		return (int) $this->get('LIN_order');
583
+	}
584
+
585
+
586
+	/**
587
+	 * Sets order
588
+	 *
589
+	 * @param int $order
590
+	 * @throws EE_Error
591
+	 * @throws InvalidArgumentException
592
+	 * @throws InvalidDataTypeException
593
+	 * @throws InvalidInterfaceException
594
+	 * @throws ReflectionException
595
+	 */
596
+	public function set_order(int $order)
597
+	{
598
+		$this->set('LIN_order', $order);
599
+	}
600
+
601
+
602
+	/**
603
+	 * Gets parent
604
+	 *
605
+	 * @return int
606
+	 * @throws EE_Error
607
+	 * @throws InvalidArgumentException
608
+	 * @throws InvalidDataTypeException
609
+	 * @throws InvalidInterfaceException
610
+	 * @throws ReflectionException
611
+	 */
612
+	public function parent_ID(): int
613
+	{
614
+		return (int) $this->get('LIN_parent');
615
+	}
616
+
617
+
618
+	/**
619
+	 * Sets parent
620
+	 *
621
+	 * @param int $parent
622
+	 * @throws EE_Error
623
+	 * @throws InvalidArgumentException
624
+	 * @throws InvalidDataTypeException
625
+	 * @throws InvalidInterfaceException
626
+	 * @throws ReflectionException
627
+	 */
628
+	public function set_parent_ID(int $parent)
629
+	{
630
+		$this->set('LIN_parent', $parent);
631
+	}
632
+
633
+
634
+	/**
635
+	 * Gets type
636
+	 *
637
+	 * @return string
638
+	 * @throws EE_Error
639
+	 * @throws InvalidArgumentException
640
+	 * @throws InvalidDataTypeException
641
+	 * @throws InvalidInterfaceException
642
+	 * @throws ReflectionException
643
+	 */
644
+	public function type(): string
645
+	{
646
+		return (string) $this->get('LIN_type');
647
+	}
648
+
649
+
650
+	/**
651
+	 * Sets type
652
+	 *
653
+	 * @param string $type
654
+	 * @throws EE_Error
655
+	 * @throws InvalidArgumentException
656
+	 * @throws InvalidDataTypeException
657
+	 * @throws InvalidInterfaceException
658
+	 * @throws ReflectionException
659
+	 */
660
+	public function set_type(string $type)
661
+	{
662
+		$this->set('LIN_type', $type);
663
+	}
664
+
665
+
666
+	/**
667
+	 * Gets the line item of which this item is a composite. Eg, if this is a subtotal, the parent might be a total\
668
+	 * If this line item is saved to the DB, fetches the parent from the DB. However, if this line item isn't in the DB
669
+	 * it uses its cached reference to its parent line item (which would have been set by `EE_Line_Item::set_parent()`
670
+	 * or indirectly by `EE_Line_item::add_child_line_item()`)
671
+	 *
672
+	 * @return EE_Line_Item|null
673
+	 * @throws EE_Error
674
+	 * @throws InvalidArgumentException
675
+	 * @throws InvalidDataTypeException
676
+	 * @throws InvalidInterfaceException
677
+	 * @throws ReflectionException
678
+	 */
679
+	public function parent(): ?EE_Line_Item
680
+	{
681
+		if (! $this->_parent instanceof EE_Line_Item) {
682
+			$this->_parent = $this->ID()
683
+				? $this->get_model()->get_one_by_ID($this->parent_ID())
684
+				: $this->_parent;
685
+		}
686
+		return $this->_parent;
687
+	}
688
+
689
+
690
+	/**
691
+	 * Gets ALL the children of this line item (ie, all the parts that contribute towards this total).
692
+	 *
693
+	 * @return EE_Line_Item[]
694
+	 * @throws EE_Error
695
+	 * @throws InvalidArgumentException
696
+	 * @throws InvalidDataTypeException
697
+	 * @throws InvalidInterfaceException
698
+	 * @throws ReflectionException
699
+	 */
700
+	public function children(array $query_params = []): array
701
+	{
702
+		// check if the query params have changed since the last time we ran this query
703
+		$new_params = ! empty(EEH_Array::array_diff_recursive($query_params, $this->children_query_params));
704
+		if (($new_params || empty($this->_children)) && $this->ID()) {
705
+			$this->children_query_params = $query_params;
706
+			// ensure where params are an array
707
+			$query_params[0] = isset($query_params[0]) && is_array($query_params[0]) ? $query_params[0] : [];
708
+			// add defaults for line item parent and orderby
709
+			$query_params[0] += ['LIN_parent' => $this->ID()];
710
+			$query_params    += ['order_by' => ['LIN_order' => 'ASC']];
711
+			$children = $this->get_model()->get_all($query_params);
712
+			foreach ($children as $child) {
713
+				if ($child instanceof EE_Line_Item) {
714
+					$this->_children[ $child->code() ] = $child;
715
+				}
716
+			}
717
+		}
718
+		return $this->_children;
719
+	}
720
+
721
+
722
+	/**
723
+	 * Gets code
724
+	 *
725
+	 * @return string
726
+	 * @throws EE_Error
727
+	 * @throws InvalidArgumentException
728
+	 * @throws InvalidDataTypeException
729
+	 * @throws InvalidInterfaceException
730
+	 * @throws ReflectionException
731
+	 */
732
+	public function code(): string
733
+	{
734
+		return (string) $this->get('LIN_code');
735
+	}
736
+
737
+
738
+	/**
739
+	 * Sets code
740
+	 *
741
+	 * @param string $code
742
+	 * @throws EE_Error
743
+	 * @throws InvalidArgumentException
744
+	 * @throws InvalidDataTypeException
745
+	 * @throws InvalidInterfaceException
746
+	 * @throws ReflectionException
747
+	 */
748
+	public function set_code(string $code)
749
+	{
750
+		$this->set('LIN_code', $code);
751
+	}
752
+
753
+
754
+	/**
755
+	 * Gets is_taxable
756
+	 *
757
+	 * @return bool
758
+	 * @throws EE_Error
759
+	 * @throws InvalidArgumentException
760
+	 * @throws InvalidDataTypeException
761
+	 * @throws InvalidInterfaceException
762
+	 * @throws ReflectionException
763
+	 */
764
+	public function is_taxable(): bool
765
+	{
766
+		return (bool) $this->get('LIN_is_taxable');
767
+	}
768
+
769
+
770
+	/**
771
+	 * Sets is_taxable
772
+	 *
773
+	 * @param bool $is_taxable
774
+	 * @throws EE_Error
775
+	 * @throws InvalidArgumentException
776
+	 * @throws InvalidDataTypeException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws ReflectionException
779
+	 */
780
+	public function set_is_taxable(bool $is_taxable)
781
+	{
782
+		$this->set('LIN_is_taxable', $is_taxable);
783
+	}
784
+
785
+
786
+	/**
787
+	 * @param int $timestamp
788
+	 * @throws EE_Error
789
+	 * @throws ReflectionException
790
+	 * @since 5.0.0.p
791
+	 */
792
+	public function setTimestamp(int $timestamp)
793
+	{
794
+		$this->set('LIN_timestamp', $timestamp);
795
+	}
796
+
797
+
798
+	/**
799
+	 * Gets the object that this model-joins-to.
800
+	 * returns one of the model objects that the field OBJ_ID can point to... see the 'OBJ_ID' field on
801
+	 * EEM_Promotion_Object
802
+	 *        Eg, if this line item join model object is for a ticket, this will return the EE_Ticket object
803
+	 *
804
+	 * @return EE_Base_Class|null
805
+	 * @throws EE_Error
806
+	 * @throws InvalidArgumentException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws InvalidInterfaceException
809
+	 * @throws ReflectionException
810
+	 */
811
+	public function get_object(): ?EE_Base_Class
812
+	{
813
+		$model_name_of_related_obj = $this->OBJ_type();
814
+		return $this->get_model()->has_relation($model_name_of_related_obj)
815
+			? $this->get_first_related($model_name_of_related_obj)
816
+			: null;
817
+	}
818
+
819
+
820
+	/**
821
+	 * Like EE_Line_Item::get_object(), but can only ever actually return an EE_Ticket.
822
+	 * (IE, if this line item is for a price or something else, will return NULL)
823
+	 *
824
+	 * @param array $query_params deprecated 5.0.12.p
825
+	 * @return EE_Ticket|null
826
+	 * @throws EE_Error
827
+	 * @throws ReflectionException
828
+	 */
829
+	public function ticket(array $query_params = []): ?EE_Ticket
830
+	{
831
+		// we're going to assume that when this method is called
832
+		// we always want to receive the attached ticket EVEN if that ticket is archived.
833
+		if(! $this->OBJ_ID() || $this->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) {
834
+			return null;
835
+		}
836
+		if(empty($query_args)) {
837
+			return EEM_Ticket::instance()->get_one_by_ID($this->OBJ_ID());
838
+		}
839
+		// legacy usage
840
+		$query_params += ['default_where_conditions' => 'none'];
841
+		return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TICKET, $query_params);
842
+	}
843
+
844
+
845
+	/**
846
+	 * Gets the EE_Datetime that's related to the ticket, IF this is for a ticket
847
+	 *
848
+	 * @return EE_Datetime|null
849
+	 * @throws EE_Error
850
+	 * @throws InvalidArgumentException
851
+	 * @throws InvalidDataTypeException
852
+	 * @throws InvalidInterfaceException
853
+	 * @throws ReflectionException
854
+	 */
855
+	public function get_ticket_datetime(): ?EE_Datetime
856
+	{
857
+		if ($this->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) {
858
+			$ticket = $this->ticket();
859
+			if ($ticket instanceof EE_Ticket) {
860
+				$datetime = $ticket->first_datetime();
861
+				if ($datetime instanceof EE_Datetime) {
862
+					return $datetime;
863
+				}
864
+			}
865
+		}
866
+		return null;
867
+	}
868
+
869
+
870
+	/**
871
+	 * Gets the event's name that's related to the ticket, if this is for
872
+	 * a ticket
873
+	 *
874
+	 * @return string
875
+	 * @throws EE_Error
876
+	 * @throws InvalidArgumentException
877
+	 * @throws InvalidDataTypeException
878
+	 * @throws InvalidInterfaceException
879
+	 * @throws ReflectionException
880
+	 */
881
+	public function ticket_event_name(): string
882
+	{
883
+		$event_name = esc_html__('Unknown', 'event_espresso');
884
+		$event      = $this->ticket_event();
885
+		if ($event instanceof EE_Event) {
886
+			$event_name = $event->name();
887
+		}
888
+		return $event_name;
889
+	}
890
+
891
+
892
+	/**
893
+	 * Gets the event that's related to the ticket, if this line item represents a ticket.
894
+	 *
895
+	 * @return EE_Event|null
896
+	 * @throws EE_Error
897
+	 * @throws InvalidArgumentException
898
+	 * @throws InvalidDataTypeException
899
+	 * @throws InvalidInterfaceException
900
+	 * @throws ReflectionException
901
+	 */
902
+	public function ticket_event(): ?EE_Event
903
+	{
904
+		$event  = null;
905
+		$ticket = $this->ticket();
906
+		if ($ticket instanceof EE_Ticket) {
907
+			$datetime = $ticket->first_datetime();
908
+			if ($datetime instanceof EE_Datetime) {
909
+				$event = $datetime->event();
910
+			}
911
+		}
912
+		return $event;
913
+	}
914
+
915
+
916
+	/**
917
+	 * Gets the first datetime for this lien item, assuming it's for a ticket
918
+	 *
919
+	 * @param string $date_format
920
+	 * @param string $time_format
921
+	 * @return string
922
+	 * @throws EE_Error
923
+	 * @throws InvalidArgumentException
924
+	 * @throws InvalidDataTypeException
925
+	 * @throws InvalidInterfaceException
926
+	 * @throws ReflectionException
927
+	 */
928
+	public function ticket_datetime_start(string $date_format = '', string $time_format = ''): string
929
+	{
930
+		$first_datetime_string = esc_html__('Unknown', 'event_espresso');
931
+		$datetime              = $this->get_ticket_datetime();
932
+		if ($datetime) {
933
+			$first_datetime_string = $datetime->start_date_and_time($date_format, $time_format);
934
+		}
935
+		return $first_datetime_string;
936
+	}
937
+
938
+
939
+	/**
940
+	 * Adds the line item as a child to this line item. If there is another child line
941
+	 * item with the same LIN_code, it is overwritten by this new one
942
+	 *
943
+	 * @param EE_Line_Item $line_item
944
+	 * @param bool         $set_order
945
+	 * @return bool success
946
+	 * @throws EE_Error
947
+	 * @throws InvalidArgumentException
948
+	 * @throws InvalidDataTypeException
949
+	 * @throws InvalidInterfaceException
950
+	 * @throws ReflectionException
951
+	 */
952
+	public function add_child_line_item(EE_Line_Item $line_item, bool $set_order = true): bool
953
+	{
954
+		// should we calculate the LIN_order for this line item ?
955
+		if ($set_order || $line_item->order() === null) {
956
+			$line_item->set_order(count($this->children()));
957
+		}
958
+		if ($this->ID()) {
959
+			// check for any duplicate line items (with the same code), if so, this replaces it
960
+			$line_item_with_same_code = $this->get_child_line_item($line_item->code());
961
+			if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
962
+				$this->delete_child_line_item($line_item_with_same_code->code());
963
+			}
964
+			$line_item->set_parent_ID($this->ID());
965
+			if ($this->TXN_ID()) {
966
+				$line_item->set_TXN_ID($this->TXN_ID());
967
+			}
968
+			return (bool) $line_item->save();
969
+		}
970
+		$this->_children[ $line_item->code() ] = $line_item;
971
+		if ($line_item->parent() !== $this) {
972
+			$line_item->set_parent($this);
973
+		}
974
+		return true;
975
+	}
976
+
977
+
978
+	/**
979
+	 * Similar to EE_Base_Class::_add_relation_to, except this isn't a normal relation.
980
+	 * If this line item is saved to the DB, this is just a wrapper for set_parent_ID() and save()
981
+	 * However, if this line item is NOT saved to the DB, this just caches the parent on
982
+	 * the EE_Line_Item::_parent property.
983
+	 *
984
+	 * @param EE_Line_Item $line_item
985
+	 * @throws EE_Error
986
+	 * @throws InvalidArgumentException
987
+	 * @throws InvalidDataTypeException
988
+	 * @throws InvalidInterfaceException
989
+	 * @throws ReflectionException
990
+	 */
991
+	public function set_parent(EE_Line_Item $line_item)
992
+	{
993
+		if ($this->ID()) {
994
+			if (! $line_item->ID()) {
995
+				$line_item->save();
996
+			}
997
+			$this->set_parent_ID($line_item->ID());
998
+			$this->save();
999
+		} else {
1000
+			$this->_parent = $line_item;
1001
+			$this->set_parent_ID($line_item->ID());
1002
+		}
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * Gets the child line item as specified by its code. Because this returns an object (by reference)
1008
+	 * you can modify this child line item and the parent (this object) can know about them
1009
+	 * because it also has a reference to that line item
1010
+	 *
1011
+	 * @param string $code
1012
+	 * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL
1013
+	 * @throws EE_Error
1014
+	 * @throws InvalidArgumentException
1015
+	 * @throws InvalidDataTypeException
1016
+	 * @throws InvalidInterfaceException
1017
+	 * @throws ReflectionException
1018
+	 */
1019
+	public function get_child_line_item(string $code)
1020
+	{
1021
+		if ($this->ID()) {
1022
+			return $this->get_model()->get_one(
1023
+				[['LIN_parent' => $this->ID(), 'LIN_code' => $code]]
1024
+			);
1025
+		}
1026
+		return $this->_children[ $code ] ?? null;
1027
+	}
1028
+
1029
+
1030
+	/**
1031
+	 * Returns how many items are deleted (or, if this item has not been saved ot the DB yet, just how many it HAD
1032
+	 * cached on it)
1033
+	 *
1034
+	 * @return int
1035
+	 * @throws EE_Error
1036
+	 * @throws InvalidArgumentException
1037
+	 * @throws InvalidDataTypeException
1038
+	 * @throws InvalidInterfaceException
1039
+	 * @throws ReflectionException
1040
+	 */
1041
+	public function delete_children_line_items(): int
1042
+	{
1043
+		if ($this->ID()) {
1044
+			return (int) $this->get_model()->delete([['LIN_parent' => $this->ID()]]);
1045
+		}
1046
+		$count           = count($this->_children);
1047
+		$this->_children = [];
1048
+		return $count;
1049
+	}
1050
+
1051
+
1052
+	/**
1053
+	 * If this line item has been saved to the DB, deletes its child with LIN_code == $code. If this line
1054
+	 * HAS NOT been saved to the DB, removes the child line item with index $code.
1055
+	 * Also searches through the child's children for a matching line item. However, once a line item has been found
1056
+	 * and deleted, stops searching (so if there are line items with duplicate codes, only the first one found will be
1057
+	 * deleted)
1058
+	 *
1059
+	 * @param string $code
1060
+	 * @param bool   $stop_search_once_found
1061
+	 * @return int count of items deleted (or simply removed from the line item's cache, if not has not been saved to
1062
+	 *             the DB yet)
1063
+	 * @throws EE_Error
1064
+	 * @throws InvalidArgumentException
1065
+	 * @throws InvalidDataTypeException
1066
+	 * @throws InvalidInterfaceException
1067
+	 * @throws ReflectionException
1068
+	 */
1069
+	public function delete_child_line_item(string $code, bool $stop_search_once_found = true): int
1070
+	{
1071
+		if ($this->ID()) {
1072
+			$items_deleted = 0;
1073
+			if ($this->code() === $code) {
1074
+				$items_deleted += EEH_Line_Item::delete_all_child_items($this);
1075
+				$items_deleted += (int) $this->delete();
1076
+				if ($stop_search_once_found) {
1077
+					return $items_deleted;
1078
+				}
1079
+			}
1080
+			foreach ($this->children() as $child_line_item) {
1081
+				$items_deleted += $child_line_item->delete_child_line_item($code, $stop_search_once_found);
1082
+			}
1083
+			return $items_deleted;
1084
+		}
1085
+		if (isset($this->_children[ $code ])) {
1086
+			unset($this->_children[ $code ]);
1087
+			return 1;
1088
+		}
1089
+		return 0;
1090
+	}
1091
+
1092
+
1093
+	/**
1094
+	 * If this line item is in the database, is of the type subtotal, and
1095
+	 * has no children, why do we have it? It should be deleted so this function
1096
+	 * does that
1097
+	 *
1098
+	 * @return bool
1099
+	 * @throws EE_Error
1100
+	 * @throws InvalidArgumentException
1101
+	 * @throws InvalidDataTypeException
1102
+	 * @throws InvalidInterfaceException
1103
+	 * @throws ReflectionException
1104
+	 */
1105
+	public function delete_if_childless_subtotal(): bool
1106
+	{
1107
+		if ($this->ID() && $this->type() === EEM_Line_Item::type_sub_total && ! $this->children()) {
1108
+			return $this->delete();
1109
+		}
1110
+		return false;
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 * Creates a code and returns a string. doesn't assign the code to this model object
1116
+	 *
1117
+	 * @return string
1118
+	 * @throws EE_Error
1119
+	 * @throws InvalidArgumentException
1120
+	 * @throws InvalidDataTypeException
1121
+	 * @throws InvalidInterfaceException
1122
+	 * @throws ReflectionException
1123
+	 */
1124
+	public function generate_code(): string
1125
+	{
1126
+		// each line item in the cart requires a unique identifier
1127
+		return $this->get('OBJ_type') . '-' . $this->get('OBJ_ID');
1128
+	}
1129
+
1130
+
1131
+	/**
1132
+	 * @return bool
1133
+	 * @throws EE_Error
1134
+	 * @throws InvalidArgumentException
1135
+	 * @throws InvalidDataTypeException
1136
+	 * @throws InvalidInterfaceException
1137
+	 * @throws ReflectionException
1138
+	 */
1139
+	public function isGlobalTax(): bool
1140
+	{
1141
+		return $this->type() === EEM_Line_Item::type_tax;
1142
+	}
1143
+
1144
+
1145
+	/**
1146
+	 * @return bool
1147
+	 * @throws EE_Error
1148
+	 * @throws InvalidArgumentException
1149
+	 * @throws InvalidDataTypeException
1150
+	 * @throws InvalidInterfaceException
1151
+	 * @throws ReflectionException
1152
+	 */
1153
+	public function isSubTax(): bool
1154
+	{
1155
+		return $this->type() === EEM_Line_Item::type_sub_tax;
1156
+	}
1157
+
1158
+
1159
+	/**
1160
+	 * returns true if this is a line item with a direct descendent of the type sub-tax
1161
+	 *
1162
+	 * @return array
1163
+	 * @throws EE_Error
1164
+	 * @throws InvalidArgumentException
1165
+	 * @throws InvalidDataTypeException
1166
+	 * @throws InvalidInterfaceException
1167
+	 * @throws ReflectionException
1168
+	 */
1169
+	public function getSubTaxes(): array
1170
+	{
1171
+		if (! $this->is_line_item()) {
1172
+			return [];
1173
+		}
1174
+		return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_sub_tax);
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * returns true if this is a line item with a direct descendent of the type sub-tax
1180
+	 *
1181
+	 * @return bool
1182
+	 * @throws EE_Error
1183
+	 * @throws InvalidArgumentException
1184
+	 * @throws InvalidDataTypeException
1185
+	 * @throws InvalidInterfaceException
1186
+	 * @throws ReflectionException
1187
+	 */
1188
+	public function hasSubTaxes(): bool
1189
+	{
1190
+		if (! $this->is_line_item()) {
1191
+			return false;
1192
+		}
1193
+		$sub_taxes = $this->getSubTaxes();
1194
+		return ! empty($sub_taxes);
1195
+	}
1196
+
1197
+
1198
+	/**
1199
+	 * @return bool
1200
+	 * @throws EE_Error
1201
+	 * @throws ReflectionException
1202
+	 * @deprecated   5.0.0.p
1203
+	 */
1204
+	public function is_tax(): bool
1205
+	{
1206
+		return $this->isGlobalTax();
1207
+	}
1208
+
1209
+
1210
+	/**
1211
+	 * @return bool
1212
+	 * @throws EE_Error
1213
+	 * @throws InvalidArgumentException
1214
+	 * @throws InvalidDataTypeException
1215
+	 * @throws InvalidInterfaceException
1216
+	 * @throws ReflectionException
1217
+	 */
1218
+	public function is_tax_sub_total(): bool
1219
+	{
1220
+		return $this->type() === EEM_Line_Item::type_tax_sub_total;
1221
+	}
1222
+
1223
+
1224
+	/**
1225
+	 * @return bool
1226
+	 * @throws EE_Error
1227
+	 * @throws InvalidArgumentException
1228
+	 * @throws InvalidDataTypeException
1229
+	 * @throws InvalidInterfaceException
1230
+	 * @throws ReflectionException
1231
+	 */
1232
+	public function is_line_item(): bool
1233
+	{
1234
+		return $this->type() === EEM_Line_Item::type_line_item;
1235
+	}
1236
+
1237
+
1238
+	/**
1239
+	 * @return bool
1240
+	 * @throws EE_Error
1241
+	 * @throws InvalidArgumentException
1242
+	 * @throws InvalidDataTypeException
1243
+	 * @throws InvalidInterfaceException
1244
+	 * @throws ReflectionException
1245
+	 */
1246
+	public function is_sub_line_item(): bool
1247
+	{
1248
+		return $this->type() === EEM_Line_Item::type_sub_line_item;
1249
+	}
1250
+
1251
+
1252
+	/**
1253
+	 * @return bool
1254
+	 * @throws EE_Error
1255
+	 * @throws InvalidArgumentException
1256
+	 * @throws InvalidDataTypeException
1257
+	 * @throws InvalidInterfaceException
1258
+	 * @throws ReflectionException
1259
+	 */
1260
+	public function is_sub_total(): bool
1261
+	{
1262
+		return $this->type() === EEM_Line_Item::type_sub_total;
1263
+	}
1264
+
1265
+
1266
+	/**
1267
+	 * Whether this line item is a cancellation line item
1268
+	 *
1269
+	 * @return bool
1270
+	 * @throws EE_Error
1271
+	 * @throws InvalidArgumentException
1272
+	 * @throws InvalidDataTypeException
1273
+	 * @throws InvalidInterfaceException
1274
+	 * @throws ReflectionException
1275
+	 */
1276
+	public function is_cancellation(): bool
1277
+	{
1278
+		return EEM_Line_Item::type_cancellation === $this->type();
1279
+	}
1280
+
1281
+
1282
+	/**
1283
+	 * @return bool
1284
+	 * @throws EE_Error
1285
+	 * @throws InvalidArgumentException
1286
+	 * @throws InvalidDataTypeException
1287
+	 * @throws InvalidInterfaceException
1288
+	 * @throws ReflectionException
1289
+	 */
1290
+	public function is_total(): bool
1291
+	{
1292
+		return $this->type() === EEM_Line_Item::type_total;
1293
+	}
1294
+
1295
+
1296
+	/**
1297
+	 * @return bool
1298
+	 * @throws EE_Error
1299
+	 * @throws InvalidArgumentException
1300
+	 * @throws InvalidDataTypeException
1301
+	 * @throws InvalidInterfaceException
1302
+	 * @throws ReflectionException
1303
+	 */
1304
+	public function is_cancelled(): bool
1305
+	{
1306
+		return $this->type() === EEM_Line_Item::type_cancellation;
1307
+	}
1308
+
1309
+
1310
+	/**
1311
+	 * @return string like '2, 004.00', formatted according to the localized currency
1312
+	 * @throws EE_Error
1313
+	 * @throws ReflectionException
1314
+	 */
1315
+	public function unit_price_no_code(): string
1316
+	{
1317
+		return $this->prettyUnitPrice();
1318
+	}
1319
+
1320
+
1321
+	/**
1322
+	 * @return string like '2, 004.00', formatted according to the localized currency
1323
+	 * @throws EE_Error
1324
+	 * @throws ReflectionException
1325
+	 * @since 5.0.0.p
1326
+	 */
1327
+	public function prettyUnitPrice(): string
1328
+	{
1329
+		return $this->get_pretty('LIN_unit_price', 'no_currency_code');
1330
+	}
1331
+
1332
+
1333
+	/**
1334
+	 * @return string like '2, 004.00', formatted according to the localized currency
1335
+	 * @throws EE_Error
1336
+	 * @throws ReflectionException
1337
+	 */
1338
+	public function total_no_code(): string
1339
+	{
1340
+		return $this->prettyTotal();
1341
+	}
1342
+
1343
+
1344
+	/**
1345
+	 * @return string like '2, 004.00', formatted according to the localized currency
1346
+	 * @throws EE_Error
1347
+	 * @throws ReflectionException
1348
+	 * @since 5.0.0.p
1349
+	 */
1350
+	public function prettyTotal(): string
1351
+	{
1352
+		return $this->get_pretty('LIN_total', 'no_currency_code');
1353
+	}
1354
+
1355
+
1356
+	/**
1357
+	 * Gets the final total on this item, taking taxes into account.
1358
+	 * Has the side effect of setting the sub-total as it was just calculated.
1359
+	 * If this is used on a grand-total line item, also updates the transaction's
1360
+	 * TXN_total (provided this line item is allowed to persist, otherwise we don't
1361
+	 * want to change a persistable transaction with info from a non-persistent line item)
1362
+	 *
1363
+	 * @param bool $update_txn_status
1364
+	 * @return float
1365
+	 * @throws EE_Error
1366
+	 * @throws InvalidArgumentException
1367
+	 * @throws InvalidDataTypeException
1368
+	 * @throws InvalidInterfaceException
1369
+	 * @throws ReflectionException
1370
+	 * @throws RuntimeException
1371
+	 */
1372
+	public function recalculate_total_including_taxes(bool $update_txn_status = false): float
1373
+	{
1374
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1375
+		return $this->calculator->recalculateTotalIncludingTaxes($grand_total_line_item, $update_txn_status);
1376
+	}
1377
+
1378
+
1379
+	/**
1380
+	 * Recursively goes through all the children and recalculates sub-totals EXCEPT for
1381
+	 * tax-sub-totals (they're an odd beast). Updates the 'total' on each line item according to either its
1382
+	 * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
1383
+	 * when this is called on the grand total
1384
+	 *
1385
+	 * @return float
1386
+	 * @throws EE_Error
1387
+	 * @throws InvalidArgumentException
1388
+	 * @throws InvalidDataTypeException
1389
+	 * @throws InvalidInterfaceException
1390
+	 * @throws ReflectionException
1391
+	 */
1392
+	public function recalculate_pre_tax_total(): float
1393
+	{
1394
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1395
+		[$total] = $this->calculator->recalculateLineItemTotals($grand_total_line_item);
1396
+		return (float) $total;
1397
+	}
1398
+
1399
+
1400
+	/**
1401
+	 * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
1402
+	 * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
1403
+	 * and tax sub-total if already in the DB
1404
+	 *
1405
+	 * @return float
1406
+	 * @throws EE_Error
1407
+	 * @throws InvalidArgumentException
1408
+	 * @throws InvalidDataTypeException
1409
+	 * @throws InvalidInterfaceException
1410
+	 * @throws ReflectionException
1411
+	 */
1412
+	public function recalculate_taxes_and_tax_total(): float
1413
+	{
1414
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1415
+		return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item);
1416
+	}
1417
+
1418
+
1419
+	/**
1420
+	 * Gets the total tax on this line item. Assumes taxes have already been calculated using
1421
+	 * recalculate_taxes_and_total
1422
+	 *
1423
+	 * @return float
1424
+	 * @throws EE_Error
1425
+	 * @throws InvalidArgumentException
1426
+	 * @throws InvalidDataTypeException
1427
+	 * @throws InvalidInterfaceException
1428
+	 * @throws ReflectionException
1429
+	 */
1430
+	public function get_total_tax(): float
1431
+	{
1432
+		$grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($this);
1433
+		return $this->calculator->recalculateTaxesAndTaxTotal($grand_total_line_item);
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * Gets the total for all the items purchased only
1439
+	 *
1440
+	 * @return float
1441
+	 * @throws EE_Error
1442
+	 * @throws InvalidArgumentException
1443
+	 * @throws InvalidDataTypeException
1444
+	 * @throws InvalidInterfaceException
1445
+	 * @throws ReflectionException
1446
+	 */
1447
+	public function get_items_total()
1448
+	{
1449
+		// by default, let's make sure we're consistent with the existing line item
1450
+		if ($this->is_total()) {
1451
+			return $this->pretaxTotal();
1452
+		}
1453
+		$total = 0;
1454
+		foreach ($this->get_items() as $item) {
1455
+			if ($item instanceof EE_Line_Item) {
1456
+				$total += $item->pretaxTotal();
1457
+			}
1458
+		}
1459
+		return $total;
1460
+	}
1461
+
1462
+
1463
+	/**
1464
+	 * Gets all the descendants (ie, children or children of children etc.) that
1465
+	 * are of the type 'tax'
1466
+	 *
1467
+	 * @return EE_Line_Item[]
1468
+	 * @throws EE_Error
1469
+	 * @throws ReflectionException
1470
+	 */
1471
+	public function tax_descendants(): array
1472
+	{
1473
+		return EEH_Line_Item::get_tax_descendants($this);
1474
+	}
1475
+
1476
+
1477
+	/**
1478
+	 * Gets all the real items purchased which are children of this item
1479
+	 *
1480
+	 * @return EE_Line_Item[]
1481
+	 * @throws EE_Error
1482
+	 * @throws ReflectionException
1483
+	 */
1484
+	public function get_items(): array
1485
+	{
1486
+		return EEH_Line_Item::get_line_item_descendants($this);
1487
+	}
1488
+
1489
+
1490
+	/**
1491
+	 * Returns the amount taxable among this line item's children (or if it has no children,
1492
+	 * how much of it is taxable). Does not recalculate totals or subtotals.
1493
+	 * If the taxable total is negative, (eg, if none of the tickets were taxable,
1494
+	 * but there is a "Taxable" discount), returns 0.
1495
+	 *
1496
+	 * @return float
1497
+	 * @throws EE_Error
1498
+	 * @throws InvalidArgumentException
1499
+	 * @throws InvalidDataTypeException
1500
+	 * @throws InvalidInterfaceException
1501
+	 * @throws ReflectionException
1502
+	 */
1503
+	public function taxable_total(): float
1504
+	{
1505
+		return $this->calculator->taxableAmountForGlobalTaxes($this);
1506
+	}
1507
+
1508
+
1509
+	/**
1510
+	 * Gets the transaction for this line item
1511
+	 *
1512
+	 * @return EE_Transaction|null
1513
+	 * @throws EE_Error
1514
+	 * @throws InvalidArgumentException
1515
+	 * @throws InvalidDataTypeException
1516
+	 * @throws InvalidInterfaceException
1517
+	 * @throws ReflectionException
1518
+	 */
1519
+	public function transaction(): ?EE_Transaction
1520
+	{
1521
+		return $this->get_first_related(EEM_Line_Item::OBJ_TYPE_TRANSACTION);
1522
+	}
1523
+
1524
+
1525
+	/**
1526
+	 * Saves this line item to the DB, and recursively saves its descendants.
1527
+	 * Because there currently is no proper parent-child relation on the model,
1528
+	 * save_this_and_cached() will NOT save the descendants.
1529
+	 * Also sets the transaction on this line item and all its descendants before saving
1530
+	 *
1531
+	 * @param int|null $txn_id if none is provided, assumes $this->TXN_ID()
1532
+	 * @return int count of items saved
1533
+	 * @throws EE_Error
1534
+	 * @throws InvalidArgumentException
1535
+	 * @throws InvalidDataTypeException
1536
+	 * @throws InvalidInterfaceException
1537
+	 * @throws ReflectionException
1538
+	 */
1539
+	public function save_this_and_descendants_to_txn(int $txn_id = 0): int
1540
+	{
1541
+		$count = 0;
1542
+		if ($txn_id) {
1543
+			$this->set_TXN_ID($txn_id);
1544
+		}
1545
+		$children = $this->children();
1546
+		$count    += $this->save() ? 1 : 0;
1547
+		foreach ($children as $child_line_item) {
1548
+			if ($child_line_item instanceof EE_Line_Item) {
1549
+				$child_line_item->set_parent_ID($this->ID());
1550
+				$count += $child_line_item->save_this_and_descendants_to_txn($txn_id);
1551
+			}
1552
+		}
1553
+		return $count;
1554
+	}
1555
+
1556
+
1557
+	/**
1558
+	 * Saves this line item to the DB, and recursively saves its descendants.
1559
+	 *
1560
+	 * @return int count of items saved
1561
+	 * @throws EE_Error
1562
+	 * @throws InvalidArgumentException
1563
+	 * @throws InvalidDataTypeException
1564
+	 * @throws InvalidInterfaceException
1565
+	 * @throws ReflectionException
1566
+	 */
1567
+	public function save_this_and_descendants(): int
1568
+	{
1569
+		$count    = 0;
1570
+		$children = $this->children();
1571
+		$count    += $this->save() ? 1 : 0;
1572
+		foreach ($children as $child_line_item) {
1573
+			if ($child_line_item instanceof EE_Line_Item) {
1574
+				$child_line_item->set_parent_ID($this->ID());
1575
+				$count += $child_line_item->save_this_and_descendants();
1576
+			}
1577
+		}
1578
+		return $count;
1579
+	}
1580
+
1581
+
1582
+	/**
1583
+	 * returns the cancellation line item if this item was cancelled
1584
+	 *
1585
+	 * @return EE_Line_Item[]
1586
+	 * @throws InvalidArgumentException
1587
+	 * @throws InvalidInterfaceException
1588
+	 * @throws InvalidDataTypeException
1589
+	 * @throws ReflectionException
1590
+	 * @throws EE_Error
1591
+	 */
1592
+	public function get_cancellations(): array
1593
+	{
1594
+		return EEH_Line_Item::get_descendants_of_type($this, EEM_Line_Item::type_cancellation);
1595
+	}
1596
+
1597
+
1598
+	/**
1599
+	 * If this item has an ID, then this saves it again to update the db
1600
+	 *
1601
+	 * @return bool|int count of items saved or false on error
1602
+	 * @throws EE_Error
1603
+	 * @throws InvalidArgumentException
1604
+	 * @throws InvalidDataTypeException
1605
+	 * @throws InvalidInterfaceException
1606
+	 * @throws ReflectionException
1607
+	 */
1608
+	public function maybe_save()
1609
+	{
1610
+		if ($this->ID()) {
1611
+			return $this->save();
1612
+		}
1613
+		return false;
1614
+	}
1615
+
1616
+
1617
+	/**
1618
+	 * clears the cached children and parent from the line item
1619
+	 *
1620
+	 * @return void
1621
+	 */
1622
+	public function clear_related_line_item_cache()
1623
+	{
1624
+		$this->_children = [];
1625
+		$this->_parent   = null;
1626
+	}
1627
+
1628
+
1629
+	/**
1630
+	 * @param bool $raw
1631
+	 * @return int|string
1632
+	 * @throws EE_Error
1633
+	 * @throws InvalidArgumentException
1634
+	 * @throws InvalidDataTypeException
1635
+	 * @throws InvalidInterfaceException
1636
+	 * @throws ReflectionException
1637
+	 */
1638
+	public function timestamp(bool $raw = false)
1639
+	{
1640
+		return $raw
1641
+			? (int) $this->get_raw('LIN_timestamp')
1642
+			: (string) $this->get('LIN_timestamp');
1643
+	}
1644
+
1645
+
1646
+
1647
+
1648
+	/************************* DEPRECATED *************************/
1649
+	/**
1650
+	 * @param string $type one of the constants on EEM_Line_Item
1651
+	 * @return EE_Line_Item[]
1652
+	 * @throws EE_Error
1653
+	 * @throws ReflectionException
1654
+	 * @deprecated 4.6.0
1655
+	 */
1656
+	protected function _get_descendants_of_type(string $type): array
1657
+	{
1658
+		EE_Error::doing_it_wrong(
1659
+			'EE_Line_Item::_get_descendants_of_type()',
1660
+			sprintf(
1661
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
1662
+				'EEH_Line_Item::get_descendants_of_type()'
1663
+			),
1664
+			'4.6.0'
1665
+		);
1666
+		return EEH_Line_Item::get_descendants_of_type($this, $type);
1667
+	}
1668
+
1669
+
1670
+	/**
1671
+	 * @param string $type like one of the EEM_Line_Item::type_*
1672
+	 * @return EE_Line_Item
1673
+	 * @throws EE_Error
1674
+	 * @throws InvalidArgumentException
1675
+	 * @throws InvalidDataTypeException
1676
+	 * @throws InvalidInterfaceException
1677
+	 * @throws ReflectionException
1678
+	 * @deprecated 4.6.0
1679
+	 */
1680
+	public function get_nearest_descendant_of_type(string $type): EE_Line_Item
1681
+	{
1682
+		EE_Error::doing_it_wrong(
1683
+			'EE_Line_Item::get_nearest_descendant_of_type()',
1684
+			sprintf(
1685
+				esc_html__('Method replaced with %1$s', 'event_espresso'),
1686
+				'EEH_Line_Item::get_nearest_descendant_of_type()'
1687
+			),
1688
+			'4.6.0'
1689
+		);
1690
+		return EEH_Line_Item::get_nearest_descendant_of_type($this, $type);
1691
+	}
1692 1692
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Question_Option.class.php 1 patch
Indentation   +220 added lines, -220 removed lines patch added patch discarded remove patch
@@ -9,224 +9,224 @@
 block discarded – undo
9 9
  */
10 10
 class EE_Question_Option extends EE_Soft_Delete_Base_Class implements EEI_Duplicatable
11 11
 {
12
-    /**
13
-     * Question Option Opt Group Name
14
-     *
15
-     * @access protected
16
-     * @var string
17
-     */
18
-    protected $_QSO_opt_group = null;
19
-
20
-
21
-    /**
22
-     * @param array  $props_n_values          incoming values
23
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
24
-     *                                        used.)
25
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
26
-     *                                        date_format and the second value is the time format
27
-     * @return EE_Question_Option
28
-     */
29
-    public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
30
-    {
31
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
32
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
33
-    }
34
-
35
-
36
-    /**
37
-     * @param array  $props_n_values  incoming values from the database
38
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
39
-     *                                the website will be used.
40
-     * @return EE_Question_Option
41
-     */
42
-    public static function new_instance_from_db($props_n_values = [], $timezone = '')
43
-    {
44
-        return new self($props_n_values, true, $timezone);
45
-    }
46
-
47
-
48
-    /**
49
-     * Sets the option's key value
50
-     *
51
-     * @param string $value
52
-     * @return bool success
53
-     */
54
-    public function set_value($value)
55
-    {
56
-        $this->set('QSO_value', $value);
57
-    }
58
-
59
-
60
-    /**
61
-     * Sets the option's Display Text
62
-     *
63
-     * @param string $text
64
-     * @return bool success
65
-     */
66
-    public function set_desc($text)
67
-    {
68
-        $this->set('QSO_desc', $text);
69
-    }
70
-
71
-
72
-    /**
73
-     * Sets the order for this option
74
-     *
75
-     * @access public
76
-     * @param integer $order
77
-     * @return bool      $success
78
-     */
79
-    public function set_order($order)
80
-    {
81
-        $this->set('QSO_order', $order);
82
-    }
83
-
84
-
85
-    /**
86
-     * Sets the ID of the related question
87
-     *
88
-     * @param int $question_ID
89
-     * @return bool success
90
-     */
91
-    public function set_question_ID($question_ID)
92
-    {
93
-        $this->set('QST_ID', $question_ID);
94
-    }
95
-
96
-
97
-    /**
98
-     * Sets the option's opt_group
99
-     *
100
-     * @param string $text
101
-     * @return bool success
102
-     */
103
-    public function set_opt_group($text)
104
-    {
105
-        return $this->_QSO_opt_group = $text;
106
-    }
107
-
108
-
109
-    /**
110
-     * Gets the option's key value
111
-     *
112
-     * @return string
113
-     */
114
-    public function value()
115
-    {
116
-        return $this->get('QSO_value');
117
-    }
118
-
119
-
120
-    /**
121
-     * Gets the option's display text
122
-     *
123
-     * @return string
124
-     */
125
-    public function desc()
126
-    {
127
-        return $this->get('QSO_desc');
128
-    }
129
-
130
-
131
-    /**
132
-     * Returns whether this option has been deleted or not
133
-     *
134
-     * @return boolean
135
-     */
136
-    public function deleted()
137
-    {
138
-        return $this->get('QSO_deleted');
139
-    }
140
-
141
-
142
-    /**
143
-     * Returns the order or the Question Option
144
-     *
145
-     * @access public
146
-     * @return integer
147
-     */
148
-    public function order()
149
-    {
150
-        return $this->get('QSO_option');
151
-    }
152
-
153
-
154
-    /**
155
-     * Gets the related question's ID
156
-     *
157
-     * @return int
158
-     */
159
-    public function question_ID()
160
-    {
161
-        return $this->get('QST_ID');
162
-    }
163
-
164
-
165
-    /**
166
-     * Returns the question related to this question option
167
-     *
168
-     * @return EE_Question
169
-     */
170
-    public function question()
171
-    {
172
-        return $this->get_first_related('Question');
173
-    }
174
-
175
-
176
-    /**
177
-     * Gets the option's opt_group
178
-     *
179
-     * @return string
180
-     */
181
-    public function opt_group()
182
-    {
183
-        return $this->_QSO_opt_group;
184
-    }
185
-
186
-
187
-    /**
188
-     * Duplicates this question option. By default the new question option will be for the same question,
189
-     * but that can be overriden by setting the 'QST_ID' option
190
-     *
191
-     * @param array $options {
192
-     * @type int    $QST_ID  the QST_ID attribute of this question option, otherwise it will be for the same question
193
-     *                       as the original
194
-     */
195
-    public function duplicate($options = [])
196
-    {
197
-        $new_question_option = clone $this;
198
-        $new_question_option->set('QSO_ID', null);
199
-        if (
200
-            array_key_exists(
201
-                'QST_ID',
202
-                $options
203
-            )
204
-        ) {// use array_key_exists instead of isset because NULL might be a valid value
205
-            $new_question_option->set_question_ID($options['QST_ID']);
206
-        }
207
-        $new_question_option->save();
208
-    }
209
-
210
-
211
-    /**
212
-     * Gets the QSO_system value
213
-     *
214
-     * @return string|null
215
-     */
216
-    public function system()
217
-    {
218
-        return $this->get('QSO_system');
219
-    }
220
-
221
-
222
-    /**
223
-     * Sets QSO_system
224
-     *
225
-     * @param string $QSO_system
226
-     * @return bool
227
-     */
228
-    public function set_system($QSO_system)
229
-    {
230
-        return $this->set('QSO_system', $QSO_system);
231
-    }
12
+	/**
13
+	 * Question Option Opt Group Name
14
+	 *
15
+	 * @access protected
16
+	 * @var string
17
+	 */
18
+	protected $_QSO_opt_group = null;
19
+
20
+
21
+	/**
22
+	 * @param array  $props_n_values          incoming values
23
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
24
+	 *                                        used.)
25
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
26
+	 *                                        date_format and the second value is the time format
27
+	 * @return EE_Question_Option
28
+	 */
29
+	public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
30
+	{
31
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
32
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
33
+	}
34
+
35
+
36
+	/**
37
+	 * @param array  $props_n_values  incoming values from the database
38
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
39
+	 *                                the website will be used.
40
+	 * @return EE_Question_Option
41
+	 */
42
+	public static function new_instance_from_db($props_n_values = [], $timezone = '')
43
+	{
44
+		return new self($props_n_values, true, $timezone);
45
+	}
46
+
47
+
48
+	/**
49
+	 * Sets the option's key value
50
+	 *
51
+	 * @param string $value
52
+	 * @return bool success
53
+	 */
54
+	public function set_value($value)
55
+	{
56
+		$this->set('QSO_value', $value);
57
+	}
58
+
59
+
60
+	/**
61
+	 * Sets the option's Display Text
62
+	 *
63
+	 * @param string $text
64
+	 * @return bool success
65
+	 */
66
+	public function set_desc($text)
67
+	{
68
+		$this->set('QSO_desc', $text);
69
+	}
70
+
71
+
72
+	/**
73
+	 * Sets the order for this option
74
+	 *
75
+	 * @access public
76
+	 * @param integer $order
77
+	 * @return bool      $success
78
+	 */
79
+	public function set_order($order)
80
+	{
81
+		$this->set('QSO_order', $order);
82
+	}
83
+
84
+
85
+	/**
86
+	 * Sets the ID of the related question
87
+	 *
88
+	 * @param int $question_ID
89
+	 * @return bool success
90
+	 */
91
+	public function set_question_ID($question_ID)
92
+	{
93
+		$this->set('QST_ID', $question_ID);
94
+	}
95
+
96
+
97
+	/**
98
+	 * Sets the option's opt_group
99
+	 *
100
+	 * @param string $text
101
+	 * @return bool success
102
+	 */
103
+	public function set_opt_group($text)
104
+	{
105
+		return $this->_QSO_opt_group = $text;
106
+	}
107
+
108
+
109
+	/**
110
+	 * Gets the option's key value
111
+	 *
112
+	 * @return string
113
+	 */
114
+	public function value()
115
+	{
116
+		return $this->get('QSO_value');
117
+	}
118
+
119
+
120
+	/**
121
+	 * Gets the option's display text
122
+	 *
123
+	 * @return string
124
+	 */
125
+	public function desc()
126
+	{
127
+		return $this->get('QSO_desc');
128
+	}
129
+
130
+
131
+	/**
132
+	 * Returns whether this option has been deleted or not
133
+	 *
134
+	 * @return boolean
135
+	 */
136
+	public function deleted()
137
+	{
138
+		return $this->get('QSO_deleted');
139
+	}
140
+
141
+
142
+	/**
143
+	 * Returns the order or the Question Option
144
+	 *
145
+	 * @access public
146
+	 * @return integer
147
+	 */
148
+	public function order()
149
+	{
150
+		return $this->get('QSO_option');
151
+	}
152
+
153
+
154
+	/**
155
+	 * Gets the related question's ID
156
+	 *
157
+	 * @return int
158
+	 */
159
+	public function question_ID()
160
+	{
161
+		return $this->get('QST_ID');
162
+	}
163
+
164
+
165
+	/**
166
+	 * Returns the question related to this question option
167
+	 *
168
+	 * @return EE_Question
169
+	 */
170
+	public function question()
171
+	{
172
+		return $this->get_first_related('Question');
173
+	}
174
+
175
+
176
+	/**
177
+	 * Gets the option's opt_group
178
+	 *
179
+	 * @return string
180
+	 */
181
+	public function opt_group()
182
+	{
183
+		return $this->_QSO_opt_group;
184
+	}
185
+
186
+
187
+	/**
188
+	 * Duplicates this question option. By default the new question option will be for the same question,
189
+	 * but that can be overriden by setting the 'QST_ID' option
190
+	 *
191
+	 * @param array $options {
192
+	 * @type int    $QST_ID  the QST_ID attribute of this question option, otherwise it will be for the same question
193
+	 *                       as the original
194
+	 */
195
+	public function duplicate($options = [])
196
+	{
197
+		$new_question_option = clone $this;
198
+		$new_question_option->set('QSO_ID', null);
199
+		if (
200
+			array_key_exists(
201
+				'QST_ID',
202
+				$options
203
+			)
204
+		) {// use array_key_exists instead of isset because NULL might be a valid value
205
+			$new_question_option->set_question_ID($options['QST_ID']);
206
+		}
207
+		$new_question_option->save();
208
+	}
209
+
210
+
211
+	/**
212
+	 * Gets the QSO_system value
213
+	 *
214
+	 * @return string|null
215
+	 */
216
+	public function system()
217
+	{
218
+		return $this->get('QSO_system');
219
+	}
220
+
221
+
222
+	/**
223
+	 * Sets QSO_system
224
+	 *
225
+	 * @param string $QSO_system
226
+	 * @return bool
227
+	 */
228
+	public function set_system($QSO_system)
229
+	{
230
+		return $this->set('QSO_system', $QSO_system);
231
+	}
232 232
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Taxes.class.php 2 patches
Indentation   +133 added lines, -133 removed lines patch added patch discarded remove patch
@@ -11,148 +11,148 @@
 block discarded – undo
11 11
  */
12 12
 class EE_Taxes extends EE_Base
13 13
 {
14
-    /**
15
-     * This is used for when EE_Taxes is used statically by the admin
16
-     *
17
-     * @var array
18
-     */
19
-    private static array $_subtotal = [];
14
+	/**
15
+	 * This is used for when EE_Taxes is used statically by the admin
16
+	 *
17
+	 * @var array
18
+	 */
19
+	private static array $_subtotal = [];
20 20
 
21
-    /**
22
-     * This holds an array of EE_Price objects that are of PRT_ID == 4 (tax price types)
23
-     *
24
-     * @var EE_Price[]
25
-     */
26
-    private static array $_default_taxes = [];
21
+	/**
22
+	 * This holds an array of EE_Price objects that are of PRT_ID == 4 (tax price types)
23
+	 *
24
+	 * @var EE_Price[]
25
+	 */
26
+	private static array $_default_taxes = [];
27 27
 
28 28
 
29
-    /**
30
-     * This method simply calculates the total taxes for a given ticket (by pulling the prices attached to the ticket
31
-     * and applying default taxes to it). Note: this is just an intermediary helper method added to facilitate quick
32
-     * calc of taxes for tickets listed in the event editor.
33
-     *
34
-     * @param EE_Ticket $ticket incoming EE_Ticket
35
-     * @return float             total taxes to apply to ticket.
36
-     * @throws EE_Error
37
-     * @throws ReflectionException
38
-     */
39
-    public static function get_total_taxes_for_admin(EE_Ticket $ticket): float
40
-    {
41
-        $tax       = 0;
42
-        $total_tax = 0;
43
-        // This first checks to see if the given ticket is taxable.
44
-        if (! $ticket->taxable()) {
45
-            return (float) $tax;
46
-        }
47
-        // get subtotal (notice we're only retrieving a subtotal if there isn't one given)
48
-        $subtotal = EE_Taxes::get_subtotal_for_admin($ticket);
49
-        // get taxes
50
-        $taxes = EE_Taxes::get_taxes_for_admin();
51
-        // apply taxes to subtotal
52
-        foreach ($taxes as $tax) {
53
-            // assuming taxes are not cumulative
54
-            $total_tax += $subtotal * $tax->amount() / 100;
55
-        }
56
-        return (float) $total_tax;
57
-    }
29
+	/**
30
+	 * This method simply calculates the total taxes for a given ticket (by pulling the prices attached to the ticket
31
+	 * and applying default taxes to it). Note: this is just an intermediary helper method added to facilitate quick
32
+	 * calc of taxes for tickets listed in the event editor.
33
+	 *
34
+	 * @param EE_Ticket $ticket incoming EE_Ticket
35
+	 * @return float             total taxes to apply to ticket.
36
+	 * @throws EE_Error
37
+	 * @throws ReflectionException
38
+	 */
39
+	public static function get_total_taxes_for_admin(EE_Ticket $ticket): float
40
+	{
41
+		$tax       = 0;
42
+		$total_tax = 0;
43
+		// This first checks to see if the given ticket is taxable.
44
+		if (! $ticket->taxable()) {
45
+			return (float) $tax;
46
+		}
47
+		// get subtotal (notice we're only retrieving a subtotal if there isn't one given)
48
+		$subtotal = EE_Taxes::get_subtotal_for_admin($ticket);
49
+		// get taxes
50
+		$taxes = EE_Taxes::get_taxes_for_admin();
51
+		// apply taxes to subtotal
52
+		foreach ($taxes as $tax) {
53
+			// assuming taxes are not cumulative
54
+			$total_tax += $subtotal * $tax->amount() / 100;
55
+		}
56
+		return (float) $total_tax;
57
+	}
58 58
 
59 59
 
60
-    /**
61
-     * Gets the total percentage of tax that should be applied to taxable line items
62
-     *
63
-     * @return float the percentage of tax that should be added to taxable items
64
-     * @throws EE_Error
65
-     * @throws ReflectionException
66
-     * eg 20 for %20 tax (NOT 0.20, which
67
-     */
68
-    public static function get_total_taxes_percentage(): float
69
-    {
70
-        $total_tax_percent = 0;
71
-        foreach (EE_Taxes::get_taxes_for_admin() as $tax_price) {
72
-            $total_tax_percent += $tax_price->get('PRC_amount');
73
-        }
74
-        return (float) $total_tax_percent;
75
-    }
60
+	/**
61
+	 * Gets the total percentage of tax that should be applied to taxable line items
62
+	 *
63
+	 * @return float the percentage of tax that should be added to taxable items
64
+	 * @throws EE_Error
65
+	 * @throws ReflectionException
66
+	 * eg 20 for %20 tax (NOT 0.20, which
67
+	 */
68
+	public static function get_total_taxes_percentage(): float
69
+	{
70
+		$total_tax_percent = 0;
71
+		foreach (EE_Taxes::get_taxes_for_admin() as $tax_price) {
72
+			$total_tax_percent += $tax_price->get('PRC_amount');
73
+		}
74
+		return (float) $total_tax_percent;
75
+	}
76 76
 
77 77
 
78
-    /**
79
-     * @param EE_Ticket $ticket
80
-     * @return float
81
-     * @throws EE_Error
82
-     * @throws ReflectionException
83
-     */
84
-    public static function get_subtotal_for_admin(EE_Ticket $ticket): float
85
-    {
86
-        $TKT_ID = $ticket->ID();
87
-        return EE_Taxes::$_subtotal[ $TKT_ID ] ?? EE_Taxes::_get_subtotal_for_admin($ticket);
88
-    }
78
+	/**
79
+	 * @param EE_Ticket $ticket
80
+	 * @return float
81
+	 * @throws EE_Error
82
+	 * @throws ReflectionException
83
+	 */
84
+	public static function get_subtotal_for_admin(EE_Ticket $ticket): float
85
+	{
86
+		$TKT_ID = $ticket->ID();
87
+		return EE_Taxes::$_subtotal[ $TKT_ID ] ?? EE_Taxes::_get_subtotal_for_admin($ticket);
88
+	}
89 89
 
90 90
 
91
-    /**
92
-     * simply take an incoming ticket and calculate the subtotal for the ticket
93
-     *
94
-     * @param EE_Ticket $ticket
95
-     * @return float     subtotal calculated from all EE_Price[] on Ticket.
96
-     * @throws EE_Error
97
-     * @throws ReflectionException
98
-     */
99
-    private static function _get_subtotal_for_admin(EE_Ticket $ticket)
100
-    {
101
-        $subtotal = 0;
102
-        // get all prices
103
-        $prices = $ticket->get_many_related(
104
-            'Price',
105
-            [
106
-                0                          => [
107
-                    'Price_Type.PBT_ID' => ['!=', EEM_Price_Type::base_type_tax],
108
-                ],
109
-                'default_where_conditions' => 'none',
110
-                'order_by'                 => ['PRC_order' => 'ASC'],
111
-            ]
112
-        );
113
-        // let's loop through them (base price is always the first item)
114
-        foreach ($prices as $price) {
115
-            if ($price instanceof EE_Price) {
116
-                $price_type = $price->type_obj();
117
-                if ($price_type instanceof EE_Price_Type) {
118
-                    switch ($price->type_obj()->base_type()) {
119
-                        case 1: // base price
120
-                        case 3: // surcharges
121
-                            $subtotal += $price->is_percent()
122
-                                ? $subtotal * $price->get('PRC_amount') / 100
123
-                                : $price->get('PRC_amount');
124
-                            break;
125
-                        case 2: // discounts
126
-                            $subtotal -= $price->is_percent()
127
-                                ? $subtotal * $price->get('PRC_amount') / 100
128
-                                : $price->get('PRC_amount');
129
-                            break;
130
-                    }
131
-                }
132
-            }
133
-        }
134
-        $TKT_ID                         = $ticket->ID();
135
-        EE_Taxes::$_subtotal[ $TKT_ID ] = (float) $subtotal;
136
-        return $subtotal;
137
-    }
91
+	/**
92
+	 * simply take an incoming ticket and calculate the subtotal for the ticket
93
+	 *
94
+	 * @param EE_Ticket $ticket
95
+	 * @return float     subtotal calculated from all EE_Price[] on Ticket.
96
+	 * @throws EE_Error
97
+	 * @throws ReflectionException
98
+	 */
99
+	private static function _get_subtotal_for_admin(EE_Ticket $ticket)
100
+	{
101
+		$subtotal = 0;
102
+		// get all prices
103
+		$prices = $ticket->get_many_related(
104
+			'Price',
105
+			[
106
+				0                          => [
107
+					'Price_Type.PBT_ID' => ['!=', EEM_Price_Type::base_type_tax],
108
+				],
109
+				'default_where_conditions' => 'none',
110
+				'order_by'                 => ['PRC_order' => 'ASC'],
111
+			]
112
+		);
113
+		// let's loop through them (base price is always the first item)
114
+		foreach ($prices as $price) {
115
+			if ($price instanceof EE_Price) {
116
+				$price_type = $price->type_obj();
117
+				if ($price_type instanceof EE_Price_Type) {
118
+					switch ($price->type_obj()->base_type()) {
119
+						case 1: // base price
120
+						case 3: // surcharges
121
+							$subtotal += $price->is_percent()
122
+								? $subtotal * $price->get('PRC_amount') / 100
123
+								: $price->get('PRC_amount');
124
+							break;
125
+						case 2: // discounts
126
+							$subtotal -= $price->is_percent()
127
+								? $subtotal * $price->get('PRC_amount') / 100
128
+								: $price->get('PRC_amount');
129
+							break;
130
+					}
131
+				}
132
+			}
133
+		}
134
+		$TKT_ID                         = $ticket->ID();
135
+		EE_Taxes::$_subtotal[ $TKT_ID ] = (float) $subtotal;
136
+		return $subtotal;
137
+	}
138 138
 
139 139
 
140
-    /**
141
-     * get all default prices that are a Tax price type (PRT_ID = 4) and return
142
-     *
143
-     * @return EE_Price[] EE_Price objects that have PRT_ID == 4
144
-     * @throws EE_Error
145
-     * @throws ReflectionException
146
-     */
147
-    public static function get_taxes_for_admin(): array
148
-    {
149
-        if (empty(EE_Taxes::$_default_taxes)) {
150
-            /** @var EEM_Price $price_model */
151
-            $price_model              = LoaderFactory::getLoader()->getShared('EEM_Price');
152
-            EE_Taxes::$_default_taxes = $price_model->get_all(
153
-                [['PRC_is_default' => 1, 'Price_Type.PBT_ID' => 4]]
154
-            );
155
-        }
156
-        return EE_Taxes::$_default_taxes;
157
-    }
140
+	/**
141
+	 * get all default prices that are a Tax price type (PRT_ID = 4) and return
142
+	 *
143
+	 * @return EE_Price[] EE_Price objects that have PRT_ID == 4
144
+	 * @throws EE_Error
145
+	 * @throws ReflectionException
146
+	 */
147
+	public static function get_taxes_for_admin(): array
148
+	{
149
+		if (empty(EE_Taxes::$_default_taxes)) {
150
+			/** @var EEM_Price $price_model */
151
+			$price_model              = LoaderFactory::getLoader()->getShared('EEM_Price');
152
+			EE_Taxes::$_default_taxes = $price_model->get_all(
153
+				[['PRC_is_default' => 1, 'Price_Type.PBT_ID' => 4]]
154
+			);
155
+		}
156
+		return EE_Taxes::$_default_taxes;
157
+	}
158 158
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -41,7 +41,7 @@  discard block
 block discarded – undo
41 41
         $tax       = 0;
42 42
         $total_tax = 0;
43 43
         // This first checks to see if the given ticket is taxable.
44
-        if (! $ticket->taxable()) {
44
+        if ( ! $ticket->taxable()) {
45 45
             return (float) $tax;
46 46
         }
47 47
         // get subtotal (notice we're only retrieving a subtotal if there isn't one given)
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
     public static function get_subtotal_for_admin(EE_Ticket $ticket): float
85 85
     {
86 86
         $TKT_ID = $ticket->ID();
87
-        return EE_Taxes::$_subtotal[ $TKT_ID ] ?? EE_Taxes::_get_subtotal_for_admin($ticket);
87
+        return EE_Taxes::$_subtotal[$TKT_ID] ?? EE_Taxes::_get_subtotal_for_admin($ticket);
88 88
     }
89 89
 
90 90
 
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
             }
133 133
         }
134 134
         $TKT_ID                         = $ticket->ID();
135
-        EE_Taxes::$_subtotal[ $TKT_ID ] = (float) $subtotal;
135
+        EE_Taxes::$_subtotal[$TKT_ID] = (float) $subtotal;
136 136
         return $subtotal;
137 137
     }
138 138
 
Please login to merge, or discard this patch.
core/db_classes/EE_Ticket.class.php 1 patch
Indentation   +2146 added lines, -2146 removed lines patch added patch discarded remove patch
@@ -14,2154 +14,2154 @@
 block discarded – undo
14 14
  */
15 15
 class EE_Ticket extends EE_Soft_Delete_Base_Class implements EEI_Line_Item_Object, EEI_Event_Relation, EEI_Has_Icon
16 16
 {
17
-    /**
18
-     * TicKet Archived:
19
-     * constant used by ticket_status() to indicate that a ticket is archived
20
-     * and no longer available for purchase
21
-     */
22
-    const archived = 'TKA';
23
-
24
-    /**
25
-     * TicKet Expired:
26
-     * constant used by ticket_status() to indicate that a ticket is expired
27
-     * and no longer available for purchase
28
-     */
29
-    const expired = 'TKE';
30
-
31
-    /**
32
-     * TicKet On sale:
33
-     * constant used by ticket_status() to indicate that a ticket is On Sale
34
-     * and IS available for purchase
35
-     */
36
-    const onsale = 'TKO';
37
-
38
-    /**
39
-     * TicKet Pending:
40
-     * constant used by ticket_status() to indicate that a ticket is pending
41
-     * and is NOT YET available for purchase
42
-     */
43
-    const pending = 'TKP';
44
-
45
-    /**
46
-     * TicKet Sold out:
47
-     * constant used by ticket_status() to indicate that a ticket is sold out
48
-     * and no longer available for purchases
49
-     */
50
-    const sold_out = 'TKS';
51
-
52
-    /**
53
-     * extra meta key for tracking ticket reservations
54
-     *
55
-     * @type string
56
-     */
57
-    const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
58
-
59
-    /**
60
-     * override of parent property
61
-     *
62
-     * @var EEM_Ticket
63
-     */
64
-    protected $_model;
65
-
66
-    /**
67
-     * cached result from method of the same name
68
-     *
69
-     * @var float $_ticket_total_with_taxes
70
-     */
71
-    private $_ticket_total_with_taxes;
72
-
73
-    /**
74
-     * @var TicketPriceModifiers
75
-     */
76
-    protected $ticket_price_modifiers;
77
-
78
-
79
-    /**
80
-     * @param array  $props_n_values          incoming values
81
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
82
-     *                                        used.)
83
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
84
-     *                                        date_format and the second value is the time format
85
-     * @return EE_Ticket
86
-     * @throws EE_Error
87
-     * @throws ReflectionException
88
-     */
89
-    public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
90
-    {
91
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
92
-        return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
93
-    }
94
-
95
-
96
-    /**
97
-     * @param array  $props_n_values  incoming values from the database
98
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
99
-     *                                the website will be used.
100
-     * @return EE_Ticket
101
-     * @throws EE_Error
102
-     * @throws ReflectionException
103
-     */
104
-    public static function new_instance_from_db($props_n_values = [], $timezone = '')
105
-    {
106
-        return new self($props_n_values, true, $timezone);
107
-    }
108
-
109
-
110
-    /**
111
-     * @param array  $fieldValues
112
-     * @param false  $bydb
113
-     * @param string $timezone
114
-     * @param array  $date_formats
115
-     * @throws EE_Error
116
-     * @throws ReflectionException
117
-     */
118
-    public function __construct($fieldValues = [], $bydb = false, $timezone = '', $date_formats = [])
119
-    {
120
-        parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
121
-        $this->ticket_price_modifiers = new TicketPriceModifiers($this);
122
-    }
123
-
124
-
125
-    /**
126
-     * @return bool
127
-     * @throws EE_Error
128
-     * @throws ReflectionException
129
-     */
130
-    public function parent()
131
-    {
132
-        return $this->get('TKT_parent');
133
-    }
134
-
135
-
136
-    /**
137
-     * return if a ticket has quantities available for purchase
138
-     *
139
-     * @param int $DTT_ID the primary key for a particular datetime
140
-     * @return boolean
141
-     * @throws EE_Error
142
-     * @throws ReflectionException
143
-     */
144
-    public function available($DTT_ID = 0)
145
-    {
146
-        // are we checking availability for a particular datetime ?
147
-        if ($DTT_ID) {
148
-            // get that datetime object
149
-            $datetime = $this->get_first_related('Datetime', [['DTT_ID' => $DTT_ID]]);
150
-            // if  ticket sales for this datetime have exceeded the reg limit...
151
-            if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
152
-                return false;
153
-            }
154
-        }
155
-        // datetime is still open for registration, but is this ticket sold out ?
156
-        return $this->qty() < 1 || $this->qty() > $this->sold();
157
-    }
158
-
159
-
160
-    /**
161
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
162
-     *
163
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
164
-     *                               relevant status const
165
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
166
-     *                               further processing
167
-     * @return mixed status int if the display string isn't requested
168
-     * @throws EE_Error
169
-     * @throws ReflectionException
170
-     */
171
-    public function ticket_status($display = false, $remaining = null)
172
-    {
173
-        $remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
174
-        if (! $remaining) {
175
-            return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
176
-        }
177
-        if ($this->get('TKT_deleted')) {
178
-            return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
179
-        }
180
-        if ($this->is_expired()) {
181
-            return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
182
-        }
183
-        if ($this->is_pending()) {
184
-            return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
185
-        }
186
-        if ($this->is_on_sale()) {
187
-            return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
188
-        }
189
-        return '';
190
-    }
191
-
192
-
193
-    /**
194
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
195
-     * considering ALL the factors used for figuring that out.
196
-     *
197
-     * @param int $DTT_ID if an int above 0 is included here then we get a specific dtt.
198
-     * @return boolean         true = tickets remaining, false not.
199
-     * @throws EE_Error
200
-     * @throws ReflectionException
201
-     */
202
-    public function is_remaining($DTT_ID = 0)
203
-    {
204
-        $num_remaining = $this->remaining($DTT_ID);
205
-        if ($num_remaining === 0) {
206
-            return false;
207
-        }
208
-        if ($num_remaining > 0 && $num_remaining < $this->min()) {
209
-            return false;
210
-        }
211
-        return true;
212
-    }
213
-
214
-
215
-    /**
216
-     * return the total number of tickets available for purchase
217
-     *
218
-     * @param int $DTT_ID  the primary key for a particular datetime.
219
-     *                     set to 0 for all related datetimes
220
-     * @return int
221
-     * @throws EE_Error
222
-     * @throws ReflectionException
223
-     */
224
-    public function remaining($DTT_ID = 0)
225
-    {
226
-        return $this->real_quantity_on_ticket('saleable', $DTT_ID);
227
-    }
228
-
229
-
230
-    /**
231
-     * Gets min
232
-     *
233
-     * @return int
234
-     * @throws EE_Error
235
-     * @throws ReflectionException
236
-     */
237
-    public function min()
238
-    {
239
-        return $this->get('TKT_min');
240
-    }
241
-
242
-
243
-    /**
244
-     * return if a ticket is no longer available cause its available dates have expired.
245
-     *
246
-     * @return boolean
247
-     * @throws EE_Error
248
-     * @throws ReflectionException
249
-     */
250
-    public function is_expired()
251
-    {
252
-        return ($this->get_raw('TKT_end_date') < time());
253
-    }
254
-
255
-
256
-    /**
257
-     * Return if a ticket is yet to go on sale or not
258
-     *
259
-     * @return boolean
260
-     * @throws EE_Error
261
-     * @throws ReflectionException
262
-     */
263
-    public function is_pending()
264
-    {
265
-        return ($this->get_raw('TKT_start_date') >= time());
266
-    }
267
-
268
-
269
-    /**
270
-     * Return if a ticket is on sale or not
271
-     *
272
-     * @return boolean
273
-     * @throws EE_Error
274
-     * @throws ReflectionException
275
-     */
276
-    public function is_on_sale()
277
-    {
278
-        return ($this->get_raw('TKT_start_date') <= time() && $this->get_raw('TKT_end_date') >= time());
279
-    }
280
-
281
-
282
-    /**
283
-     * This returns the chronologically last datetime that this ticket is associated with
284
-     *
285
-     * @param string $date_format
286
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
287
-     *                            the end date ie: Jan 01 "to" Dec 31
288
-     * @return string
289
-     * @throws EE_Error
290
-     * @throws ReflectionException
291
-     */
292
-    public function date_range($date_format = '', $conjunction = ' - ')
293
-    {
294
-        $date_format = ! empty($date_format) ? $date_format : $this->_dt_frmt;
295
-        $first_date  = $this->first_datetime() instanceof EE_Datetime
296
-            ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $date_format)
297
-            : '';
298
-        $last_date   = $this->last_datetime() instanceof EE_Datetime
299
-            ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $date_format)
300
-            : '';
301
-
302
-        return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
303
-    }
304
-
305
-
306
-    /**
307
-     * This returns the chronologically first datetime that this ticket is associated with
308
-     *
309
-     * @return EE_Datetime
310
-     * @throws EE_Error
311
-     * @throws ReflectionException
312
-     */
313
-    public function first_datetime()
314
-    {
315
-        $datetimes = $this->datetimes(['limit' => 1]);
316
-        return reset($datetimes);
317
-    }
318
-
319
-
320
-    /**
321
-     * Gets all the datetimes this ticket can be used for attending.
322
-     * Unless otherwise specified, orders datetimes by start date.
323
-     *
324
-     * @param array $query_params
325
-     * @return EE_Datetime[]|EE_Base_Class[]
326
-     * @throws EE_Error
327
-     * @throws ReflectionException
328
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
329
-     */
330
-    public function datetimes($query_params = [])
331
-    {
332
-        if (! isset($query_params['order_by'])) {
333
-            $query_params['order_by']['DTT_order'] = 'ASC';
334
-        }
335
-        return $this->get_many_related('Datetime', $query_params);
336
-    }
337
-
338
-
339
-    /**
340
-     * This returns the chronologically last datetime that this ticket is associated with
341
-     *
342
-     * @return EE_Datetime
343
-     * @throws EE_Error
344
-     * @throws ReflectionException
345
-     */
346
-    public function last_datetime()
347
-    {
348
-        $datetimes = $this->datetimes(['limit' => 1, 'order_by' => ['DTT_EVT_start' => 'DESC']]);
349
-        return end($datetimes);
350
-    }
351
-
352
-
353
-    /**
354
-     * This returns the total tickets sold depending on the given parameters.
355
-     *
356
-     * @param string $what    Can be one of two options: 'ticket', 'datetime'.
357
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
358
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
359
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
360
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
361
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
362
-     * @param int    $dtt_id  [optional] include the dtt_id with $what = 'datetime'.
363
-     * @return mixed (array|int)          how many tickets have sold
364
-     * @throws EE_Error
365
-     * @throws ReflectionException
366
-     */
367
-    public function tickets_sold($what = 'ticket', $dtt_id = null)
368
-    {
369
-        $total        = 0;
370
-        $tickets_sold = $this->_all_tickets_sold();
371
-        switch ($what) {
372
-            case 'ticket':
373
-                return $tickets_sold['ticket'];
374
-
375
-            case 'datetime':
376
-                if (empty($tickets_sold['datetime'])) {
377
-                    return $total;
378
-                }
379
-                if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
380
-                    EE_Error::add_error(
381
-                        esc_html__(
382
-                            '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?',
383
-                            'event_espresso'
384
-                        ),
385
-                        __FILE__,
386
-                        __FUNCTION__,
387
-                        __LINE__
388
-                    );
389
-                    return $total;
390
-                }
391
-                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
392
-
393
-            default:
394
-                return $total;
395
-        }
396
-    }
397
-
398
-
399
-    /**
400
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
401
-     *
402
-     * @return EE_Ticket[]
403
-     * @throws EE_Error
404
-     * @throws ReflectionException
405
-     */
406
-    protected function _all_tickets_sold()
407
-    {
408
-        $datetimes    = $this->get_many_related('Datetime');
409
-        $tickets_sold = [];
410
-        if (! empty($datetimes)) {
411
-            foreach ($datetimes as $datetime) {
412
-                $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
413
-            }
414
-        }
415
-        // Tickets sold
416
-        $tickets_sold['ticket'] = $this->sold();
417
-        return $tickets_sold;
418
-    }
419
-
420
-
421
-    /**
422
-     * This returns the base price object for the ticket.
423
-     *
424
-     * @param bool $return_array whether to return as an array indexed by price id or just the object.
425
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
426
-     * @throws EE_Error
427
-     * @throws ReflectionException
428
-     */
429
-    public function base_price(bool $return_array = false)
430
-    {
431
-        $base_price = $this->ticket_price_modifiers->getBasePrice();
432
-        if (! empty($base_price)) {
433
-            return $return_array ? $base_price : reset($base_price);
434
-        }
435
-        $_where = ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price];
436
-        return $return_array
437
-            ? $this->get_many_related('Price', [$_where])
438
-            : $this->get_first_related('Price', [$_where]);
439
-    }
440
-
441
-
442
-    /**
443
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
444
-     *
445
-     * @return EE_Price[]
446
-     * @throws EE_Error
447
-     * @throws ReflectionException
448
-     */
449
-    public function price_modifiers(): array
450
-    {
451
-        $price_modifiers = $this->usesGlobalTaxes()
452
-            ? $this->ticket_price_modifiers->getAllDiscountAndSurchargeModifiersForTicket()
453
-            : $this->ticket_price_modifiers->getAllModifiersForTicket();
454
-        if (! empty($price_modifiers)) {
455
-            return $price_modifiers;
456
-        }
457
-        return $this->prices(
458
-            [
459
-                [
460
-                    'Price_Type.PBT_ID' => [
461
-                        'NOT IN',
462
-                        [EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax],
463
-                    ],
464
-                ],
465
-            ]
466
-        );
467
-    }
468
-
469
-
470
-    /**
471
-     * This returns ONLY the TAX price modifiers for the ticket
472
-     *
473
-     * @return EE_Price[]
474
-     * @throws EE_Error
475
-     * @throws ReflectionException
476
-     */
477
-    public function tax_price_modifiers(): array
478
-    {
479
-        $tax_price_modifiers = $this->ticket_price_modifiers->getAllTaxesForTicket();
480
-        if (! empty($tax_price_modifiers)) {
481
-            return $tax_price_modifiers;
482
-        }
483
-        return $this->prices([['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax]]);
484
-    }
485
-
486
-
487
-    /**
488
-     * Gets all the prices that combine to form the final price of this ticket
489
-     *
490
-     * @param array $query_params
491
-     * @return EE_Price[]|EE_Base_Class[]
492
-     * @throws EE_Error
493
-     * @throws ReflectionException
494
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
495
-     */
496
-    public function prices(array $query_params = []): array
497
-    {
498
-        if (! isset($query_params['order_by'])) {
499
-            $query_params['order_by']['PRC_order'] = 'ASC';
500
-        }
501
-        return $this->get_many_related('Price', $query_params);
502
-    }
503
-
504
-
505
-    /**
506
-     * Gets all the ticket datetimes (ie, relations between datetimes and tickets)
507
-     *
508
-     * @param array $query_params
509
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
510
-     * @throws EE_Error
511
-     * @throws ReflectionException
512
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
513
-     */
514
-    public function datetime_tickets($query_params = [])
515
-    {
516
-        return $this->get_many_related('Datetime_Ticket', $query_params);
517
-    }
518
-
519
-
520
-    /**
521
-     * Gets all the datetimes from the db ordered by DTT_order
522
-     *
523
-     * @param boolean $show_expired
524
-     * @param boolean $show_deleted
525
-     * @return EE_Datetime[]
526
-     * @throws EE_Error
527
-     * @throws ReflectionException
528
-     */
529
-    public function datetimes_ordered($show_expired = true, $show_deleted = false)
530
-    {
531
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
532
-            $this->ID(),
533
-            $show_expired,
534
-            $show_deleted
535
-        );
536
-    }
537
-
538
-
539
-    /**
540
-     * Gets ID
541
-     *
542
-     * @return int
543
-     * @throws EE_Error
544
-     * @throws ReflectionException
545
-     */
546
-    public function ID()
547
-    {
548
-        return (int) $this->get('TKT_ID');
549
-    }
550
-
551
-
552
-    /**
553
-     * get the author of the ticket.
554
-     *
555
-     * @return int
556
-     * @throws EE_Error
557
-     * @throws ReflectionException
558
-     * @since 4.5.0
559
-     */
560
-    public function wp_user()
561
-    {
562
-        return $this->get('TKT_wp_user');
563
-    }
564
-
565
-
566
-    /**
567
-     * Gets the template for the ticket
568
-     *
569
-     * @return EE_Ticket_Template|EE_Base_Class
570
-     * @throws EE_Error
571
-     * @throws ReflectionException
572
-     */
573
-    public function template()
574
-    {
575
-        return $this->get_first_related('Ticket_Template');
576
-    }
577
-
578
-
579
-    /**
580
-     * Simply returns an array of EE_Price objects that are taxes.
581
-     *
582
-     * @return EE_Price[]
583
-     * @throws EE_Error
584
-     * @throws ReflectionException
585
-     */
586
-    public function get_ticket_taxes_for_admin(): array
587
-    {
588
-        return $this->usesGlobalTaxes() ? EE_Taxes::get_taxes_for_admin() : $this->tax_price_modifiers();
589
-    }
590
-
591
-
592
-    /**
593
-     * alias of taxable() to better indicate that ticket uses the legacy method of applying default "global" taxes
594
-     * as opposed to having tax price modifiers added directly to each ticket
595
-     *
596
-     * @return bool
597
-     * @throws EE_Error
598
-     * @throws ReflectionException
599
-     * @since   5.0.0.p
600
-     */
601
-    public function usesGlobalTaxes(): bool
602
-    {
603
-        return $this->taxable();
604
-    }
605
-
606
-
607
-    /**
608
-     * @return float
609
-     * @throws EE_Error
610
-     * @throws ReflectionException
611
-     */
612
-    public function ticket_price()
613
-    {
614
-        return $this->get('TKT_price');
615
-    }
616
-
617
-
618
-    /**
619
-     * @return mixed
620
-     * @throws EE_Error
621
-     * @throws ReflectionException
622
-     */
623
-    public function pretty_price()
624
-    {
625
-        return $this->get_pretty('TKT_price');
626
-    }
627
-
628
-
629
-    /**
630
-     * @return bool
631
-     * @throws EE_Error
632
-     * @throws ReflectionException
633
-     */
634
-    public function is_free()
635
-    {
636
-        return $this->get_ticket_total_with_taxes() === (float) 0;
637
-    }
638
-
639
-
640
-    /**
641
-     * get_ticket_total_with_taxes
642
-     *
643
-     * @param bool $no_cache
644
-     * @return float
645
-     * @throws EE_Error
646
-     * @throws ReflectionException
647
-     */
648
-    public function get_ticket_total_with_taxes(bool $no_cache = false): float
649
-    {
650
-        if ($this->_ticket_total_with_taxes === null || $no_cache) {
651
-            $this->_ticket_total_with_taxes = $this->get_ticket_subtotal();
652
-            // add taxes
653
-            if ($this->usesGlobalTaxes()) {
654
-                $this->_ticket_total_with_taxes += $this->get_ticket_taxes_total_for_admin();
655
-            } else {
656
-                $subtotal = $this->_ticket_total_with_taxes;
657
-                foreach ($this->tax_price_modifiers() as $tax) {
658
-                    $this->_ticket_total_with_taxes += $subtotal * $tax->amount() / 100;
659
-                }
660
-            }
661
-        }
662
-        return (float) $this->_ticket_total_with_taxes;
663
-    }
664
-
665
-
666
-    /**
667
-     * @throws EE_Error
668
-     * @throws ReflectionException
669
-     */
670
-    public function ensure_TKT_Price_correct()
671
-    {
672
-        $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
673
-        $this->save();
674
-    }
675
-
676
-
677
-    /**
678
-     * @return float
679
-     * @throws EE_Error
680
-     * @throws ReflectionException
681
-     */
682
-    public function get_ticket_subtotal()
683
-    {
684
-        return EE_Taxes::get_subtotal_for_admin($this);
685
-    }
686
-
687
-
688
-    /**
689
-     * Returns the total taxes applied to this ticket
690
-     *
691
-     * @return float
692
-     * @throws EE_Error
693
-     * @throws ReflectionException
694
-     */
695
-    public function get_ticket_taxes_total_for_admin()
696
-    {
697
-        return EE_Taxes::get_total_taxes_for_admin($this);
698
-    }
699
-
700
-
701
-    /**
702
-     * Sets name
703
-     *
704
-     * @param string $name
705
-     * @throws EE_Error
706
-     * @throws ReflectionException
707
-     */
708
-    public function set_name($name)
709
-    {
710
-        $this->set('TKT_name', $name);
711
-    }
712
-
713
-
714
-    /**
715
-     * Gets description
716
-     *
717
-     * @return string
718
-     * @throws EE_Error
719
-     * @throws ReflectionException
720
-     */
721
-    public function description()
722
-    {
723
-        return $this->get('TKT_description');
724
-    }
725
-
726
-
727
-    /**
728
-     * Sets description
729
-     *
730
-     * @param string $description
731
-     * @throws EE_Error
732
-     * @throws ReflectionException
733
-     */
734
-    public function set_description($description)
735
-    {
736
-        $this->set('TKT_description', $description);
737
-    }
738
-
739
-
740
-    /**
741
-     * Gets start_date
742
-     *
743
-     * @param string|null $date_format
744
-     * @param string|null $time_format
745
-     * @return string
746
-     * @throws EE_Error
747
-     * @throws ReflectionException
748
-     */
749
-    public function start_date(?string $date_format = '', ?string $time_format = ''): string
750
-    {
751
-        return $this->_get_datetime('TKT_start_date', $date_format, $time_format);
752
-    }
753
-
754
-
755
-    /**
756
-     * Sets start_date
757
-     *
758
-     * @param string $start_date
759
-     * @return void
760
-     * @throws EE_Error
761
-     * @throws ReflectionException
762
-     */
763
-    public function set_start_date($start_date)
764
-    {
765
-        $this->_set_date_time('B', $start_date, 'TKT_start_date');
766
-    }
767
-
768
-
769
-    /**
770
-     * Gets end_date
771
-     *
772
-     * @param string|null $date_format
773
-     * @param string|null $time_format
774
-     * @return string
775
-     * @throws EE_Error
776
-     * @throws ReflectionException
777
-     */
778
-    public function end_date(?string $date_format = '', ?string $time_format = ''): string
779
-    {
780
-        return $this->_get_datetime('TKT_end_date', $date_format, $time_format);
781
-    }
782
-
783
-
784
-    /**
785
-     * Sets end_date
786
-     *
787
-     * @param string $end_date
788
-     * @return void
789
-     * @throws EE_Error
790
-     * @throws ReflectionException
791
-     */
792
-    public function set_end_date($end_date)
793
-    {
794
-        $this->_set_date_time('B', $end_date, 'TKT_end_date');
795
-    }
796
-
797
-
798
-    /**
799
-     * Sets sell until time
800
-     *
801
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
802
-     * @throws EE_Error
803
-     * @throws ReflectionException
804
-     * @since 4.5.0
805
-     */
806
-    public function set_end_time($time)
807
-    {
808
-        $this->_set_time_for($time, 'TKT_end_date');
809
-    }
810
-
811
-
812
-    /**
813
-     * Sets min
814
-     *
815
-     * @param int $min
816
-     * @return void
817
-     * @throws EE_Error
818
-     * @throws ReflectionException
819
-     */
820
-    public function set_min($min)
821
-    {
822
-        $this->set('TKT_min', $min);
823
-    }
824
-
825
-
826
-    /**
827
-     * Gets max
828
-     *
829
-     * @return int
830
-     * @throws EE_Error
831
-     * @throws ReflectionException
832
-     */
833
-    public function max()
834
-    {
835
-        return $this->get('TKT_max');
836
-    }
837
-
838
-
839
-    /**
840
-     * Sets max
841
-     *
842
-     * @param int $max
843
-     * @return void
844
-     * @throws EE_Error
845
-     * @throws ReflectionException
846
-     */
847
-    public function set_max($max)
848
-    {
849
-        $this->set('TKT_max', $max);
850
-    }
851
-
852
-
853
-    /**
854
-     * Sets price
855
-     *
856
-     * @param float $price
857
-     * @return void
858
-     * @throws EE_Error
859
-     * @throws ReflectionException
860
-     */
861
-    public function set_price($price)
862
-    {
863
-        $this->set('TKT_price', $price);
864
-    }
865
-
866
-
867
-    /**
868
-     * Gets sold
869
-     *
870
-     * @return int
871
-     * @throws EE_Error
872
-     * @throws ReflectionException
873
-     */
874
-    public function sold(): int
875
-    {
876
-        return (int) $this->get_raw('TKT_sold');
877
-    }
878
-
879
-
880
-    /**
881
-     * Sets sold
882
-     *
883
-     * @param int $sold
884
-     * @return void
885
-     * @throws EE_Error
886
-     * @throws ReflectionException
887
-     */
888
-    public function set_sold($sold)
889
-    {
890
-        // sold can not go below zero
891
-        $sold = max(0, $sold);
892
-        $this->set('TKT_sold', $sold);
893
-    }
894
-
895
-
896
-    /**
897
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
898
-     * associated datetimes.
899
-     *
900
-     * @param int $qty
901
-     * @return boolean
902
-     * @throws EE_Error
903
-     * @throws InvalidArgumentException
904
-     * @throws InvalidDataTypeException
905
-     * @throws InvalidInterfaceException
906
-     * @throws ReflectionException
907
-     * @since 4.9.80.p
908
-     */
909
-    public function increaseSold($qty = 1)
910
-    {
911
-        $qty = absint($qty);
912
-        // increment sold and decrement reserved datetime quantities simultaneously
913
-        // don't worry about failures, because they must have already had a spot reserved
914
-        $this->increaseSoldForDatetimes($qty);
915
-        // Increment and decrement ticket quantities simultaneously
916
-        $success = $this->adjustNumericFieldsInDb(
917
-            [
918
-                'TKT_reserved' => $qty * -1,
919
-                'TKT_sold'     => $qty,
920
-            ]
921
-        );
922
-        do_action(
923
-            'AHEE__EE_Ticket__increase_sold',
924
-            $this,
925
-            $qty,
926
-            $this->sold(),
927
-            $success
928
-        );
929
-        return $success;
930
-    }
931
-
932
-
933
-    /**
934
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
935
-     *
936
-     * @param int           $qty positive or negative. Positive means to increase sold counts (and decrease reserved
937
-     *                           counts), Negative means to decreases old counts (and increase reserved counts).
938
-     * @param EE_Datetime[] $datetimes
939
-     * @throws EE_Error
940
-     * @throws InvalidArgumentException
941
-     * @throws InvalidDataTypeException
942
-     * @throws InvalidInterfaceException
943
-     * @throws ReflectionException
944
-     * @since 4.9.80.p
945
-     */
946
-    protected function increaseSoldForDatetimes($qty, array $datetimes = [])
947
-    {
948
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
949
-        foreach ($datetimes as $datetime) {
950
-            $datetime->increaseSold($qty);
951
-        }
952
-    }
953
-
954
-
955
-    /**
956
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
957
-     * DB and then updates the model objects.
958
-     * Does not affect the reserved counts.
959
-     *
960
-     * @param int $qty
961
-     * @return boolean
962
-     * @throws EE_Error
963
-     * @throws InvalidArgumentException
964
-     * @throws InvalidDataTypeException
965
-     * @throws InvalidInterfaceException
966
-     * @throws ReflectionException
967
-     * @since 4.9.80.p
968
-     */
969
-    public function decreaseSold($qty = 1)
970
-    {
971
-        $qty = absint($qty);
972
-        $this->decreaseSoldForDatetimes($qty);
973
-        $success = $this->adjustNumericFieldsInDb(
974
-            [
975
-                'TKT_sold' => $qty * -1,
976
-            ]
977
-        );
978
-        do_action(
979
-            'AHEE__EE_Ticket__decrease_sold',
980
-            $this,
981
-            $qty,
982
-            $this->sold(),
983
-            $success
984
-        );
985
-        return $success;
986
-    }
987
-
988
-
989
-    /**
990
-     * Decreases sold on related datetimes
991
-     *
992
-     * @param int           $qty
993
-     * @param EE_Datetime[] $datetimes
994
-     * @return void
995
-     * @throws EE_Error
996
-     * @throws InvalidArgumentException
997
-     * @throws InvalidDataTypeException
998
-     * @throws InvalidInterfaceException
999
-     * @throws ReflectionException
1000
-     * @since 4.9.80.p
1001
-     */
1002
-    protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
1003
-    {
1004
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1005
-        if (is_array($datetimes)) {
1006
-            foreach ($datetimes as $datetime) {
1007
-                if ($datetime instanceof EE_Datetime) {
1008
-                    $datetime->decreaseSold($qty);
1009
-                }
1010
-            }
1011
-        }
1012
-    }
1013
-
1014
-
1015
-    /**
1016
-     * Gets qty of reserved tickets
1017
-     *
1018
-     * @return int
1019
-     * @throws EE_Error
1020
-     * @throws ReflectionException
1021
-     */
1022
-    public function reserved(): int
1023
-    {
1024
-        return (int) $this->get_raw('TKT_reserved');
1025
-    }
1026
-
1027
-
1028
-    /**
1029
-     * Sets reserved
1030
-     *
1031
-     * @param int $reserved
1032
-     * @return void
1033
-     * @throws EE_Error
1034
-     * @throws ReflectionException
1035
-     */
1036
-    public function set_reserved($reserved)
1037
-    {
1038
-        // reserved can not go below zero
1039
-        $reserved = max(0, (int) $reserved);
1040
-        $this->set('TKT_reserved', $reserved);
1041
-    }
1042
-
1043
-
1044
-    /**
1045
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1046
-     *
1047
-     * @param int    $qty
1048
-     * @param string $source
1049
-     * @return bool whether we successfully reserved the ticket or not.
1050
-     * @throws EE_Error
1051
-     * @throws InvalidArgumentException
1052
-     * @throws ReflectionException
1053
-     * @throws InvalidDataTypeException
1054
-     * @throws InvalidInterfaceException
1055
-     * @since 4.9.80.p
1056
-     */
1057
-    public function increaseReserved($qty = 1, $source = 'unknown')
1058
-    {
1059
-        $qty = absint($qty);
1060
-        do_action(
1061
-            'AHEE__EE_Ticket__increase_reserved__begin',
1062
-            $this,
1063
-            $qty,
1064
-            $source
1065
-        );
1066
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
1067
-        $success                         = false;
1068
-        $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
1069
-        if ($datetimes_adjusted_successfully) {
1070
-            $success = $this->incrementFieldConditionallyInDb(
1071
-                'TKT_reserved',
1072
-                'TKT_sold',
1073
-                'TKT_qty',
1074
-                $qty
1075
-            );
1076
-            if (! $success) {
1077
-                // The datetimes were successfully bumped, but not the
1078
-                // ticket. So we need to manually rollback the datetimes.
1079
-                $this->decreaseReservedForDatetimes($qty);
1080
-            }
1081
-        }
1082
-        do_action(
1083
-            'AHEE__EE_Ticket__increase_reserved',
1084
-            $this,
1085
-            $qty,
1086
-            $this->reserved(),
1087
-            $success
1088
-        );
1089
-        return $success;
1090
-    }
1091
-
1092
-
1093
-    /**
1094
-     * Increases reserved counts on related datetimes
1095
-     *
1096
-     * @param int           $qty
1097
-     * @param EE_Datetime[] $datetimes
1098
-     * @return boolean indicating success
1099
-     * @throws EE_Error
1100
-     * @throws InvalidArgumentException
1101
-     * @throws InvalidDataTypeException
1102
-     * @throws InvalidInterfaceException
1103
-     * @throws ReflectionException
1104
-     * @since 4.9.80.p
1105
-     */
1106
-    protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
1107
-    {
1108
-        $datetimes         = ! empty($datetimes) ? $datetimes : $this->datetimes();
1109
-        $datetimes_updated = [];
1110
-        $limit_exceeded    = false;
1111
-        if (is_array($datetimes)) {
1112
-            foreach ($datetimes as $datetime) {
1113
-                if ($datetime instanceof EE_Datetime) {
1114
-                    if ($datetime->increaseReserved($qty)) {
1115
-                        $datetimes_updated[] = $datetime;
1116
-                    } else {
1117
-                        $limit_exceeded = true;
1118
-                        break;
1119
-                    }
1120
-                }
1121
-            }
1122
-            // If somewhere along the way we detected a datetime whose
1123
-            // limit was exceeded, do a manual rollback.
1124
-            if ($limit_exceeded) {
1125
-                $this->decreaseReservedForDatetimes($qty, $datetimes_updated);
1126
-                return false;
1127
-            }
1128
-        }
1129
-        return true;
1130
-    }
1131
-
1132
-
1133
-    /**
1134
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1135
-     *
1136
-     * @param int    $qty
1137
-     * @param bool   $adjust_datetimes
1138
-     * @param string $source
1139
-     * @return boolean
1140
-     * @throws EE_Error
1141
-     * @throws InvalidArgumentException
1142
-     * @throws ReflectionException
1143
-     * @throws InvalidDataTypeException
1144
-     * @throws InvalidInterfaceException
1145
-     * @since 4.9.80.p
1146
-     */
1147
-    public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1148
-    {
1149
-        $qty = absint($qty);
1150
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1151
-        if ($adjust_datetimes) {
1152
-            $this->decreaseReservedForDatetimes($qty);
1153
-        }
1154
-        $success = $this->adjustNumericFieldsInDb(
1155
-            [
1156
-                'TKT_reserved' => $qty * -1,
1157
-            ]
1158
-        );
1159
-        do_action(
1160
-            'AHEE__EE_Ticket__decrease_reserved',
1161
-            $this,
1162
-            $qty,
1163
-            $this->reserved(),
1164
-            $success
1165
-        );
1166
-        return $success;
1167
-    }
1168
-
1169
-
1170
-    /**
1171
-     * Decreases the reserved count on the specified datetimes.
1172
-     *
1173
-     * @param int           $qty
1174
-     * @param EE_Datetime[] $datetimes
1175
-     * @throws EE_Error
1176
-     * @throws InvalidArgumentException
1177
-     * @throws ReflectionException
1178
-     * @throws InvalidDataTypeException
1179
-     * @throws InvalidInterfaceException
1180
-     * @since 4.9.80.p
1181
-     */
1182
-    protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1183
-    {
1184
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1185
-        foreach ($datetimes as $datetime) {
1186
-            if ($datetime instanceof EE_Datetime) {
1187
-                $datetime->decreaseReserved($qty);
1188
-            }
1189
-        }
1190
-    }
1191
-
1192
-
1193
-    /**
1194
-     * Gets ticket quantity
1195
-     *
1196
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1197
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1198
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1199
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1200
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1201
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1202
-     * @return int
1203
-     * @throws EE_Error
1204
-     * @throws ReflectionException
1205
-     */
1206
-    public function qty($context = '')
1207
-    {
1208
-        switch ($context) {
1209
-            case 'reg_limit':
1210
-                return $this->real_quantity_on_ticket();
1211
-            case 'saleable':
1212
-                return $this->real_quantity_on_ticket('saleable');
1213
-            default:
1214
-                return $this->get_raw('TKT_qty');
1215
-        }
1216
-    }
1217
-
1218
-
1219
-    /**
1220
-     * Gets ticket quantity
1221
-     *
1222
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1223
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1224
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1225
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1226
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1227
-     * @param int    $DTT_ID      the primary key for a particular datetime.
1228
-     *                            set to 0 for all related datetimes
1229
-     * @return int|float          int for finite quantity or float for INF
1230
-     * @throws EE_Error
1231
-     * @throws ReflectionException
1232
-     */
1233
-    public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1234
-    {
1235
-        $raw = $this->get_raw('TKT_qty');
1236
-        // return immediately if it's zero
1237
-        if ($raw === 0) {
1238
-            return $raw;
1239
-        }
1240
-        // echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1241
-        // ensure qty doesn't exceed raw value for THIS ticket
1242
-        $qty = min(EE_INF, $raw);
1243
-        // echo "\n . qty: " . $qty . '<br />';
1244
-        // calculate this ticket's total sales and reservations
1245
-        $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1246
-        // echo "\n . sold: " . $this->sold() . '<br />';
1247
-        // echo "\n . reserved: " . $this->reserved() . '<br />';
1248
-        // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1249
-        // first we need to calculate the maximum number of tickets available for the datetime
1250
-        // do we want data for one datetime or all of them ?
1251
-        $query_params = $DTT_ID ? [['DTT_ID' => $DTT_ID]] : [];
1252
-        $datetimes    = $this->get_many_related('Datetime', $query_params);
1253
-        if (is_array($datetimes) && ! empty($datetimes)) {
1254
-            foreach ($datetimes as $datetime) {
1255
-                if ($datetime instanceof EE_Datetime) {
1256
-                    // $datetime->refresh_from_db();
1257
-                    // echo "\n . . datetime name: " . $datetime->name() . '<br />';
1258
-                    // echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1259
-                    // initialize with no restrictions for each datetime
1260
-                    // but adjust datetime qty based on datetime reg limit
1261
-                    $datetime_qty = min(EE_INF, $datetime->reg_limit());
1262
-                    // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1263
-                    // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1264
-                    // if we want the actual saleable amount, then we need to consider OTHER ticket sales
1265
-                    // and reservations for this datetime, that do NOT include sales and reservations
1266
-                    // for this ticket (so we add $this->sold() and $this->reserved() back in)
1267
-                    if ($context === 'saleable') {
1268
-                        $datetime_qty = max(
1269
-                            $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1270
-                            0
1271
-                        );
1272
-                        // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1273
-                        // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1274
-                        // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1275
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1276
-                        $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1277
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1278
-                    }
1279
-                    $qty = min($datetime_qty, $qty);
1280
-                    // echo "\n . . qty: " . $qty . '<br />';
1281
-                }
1282
-            }
1283
-        }
1284
-        // NOW that we know the  maximum number of tickets available for the datetime
1285
-        // we can finally factor in the details for this specific ticket
1286
-        if ($qty > 0 && $context === 'saleable') {
1287
-            // and subtract the sales for THIS ticket
1288
-            $qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1289
-            // echo "\n . qty: " . $qty . '<br />';
1290
-        }
1291
-        // echo "\nFINAL QTY: " . $qty . "<br /><br />";
1292
-        return $qty;
1293
-    }
1294
-
1295
-
1296
-    /**
1297
-     * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1298
-     *
1299
-     * @param int $qty
1300
-     * @return void
1301
-     * @throws EE_Error
1302
-     * @throws ReflectionException
1303
-     */
1304
-    public function set_qty($qty)
1305
-    {
1306
-        $datetimes = $this->datetimes();
1307
-        foreach ($datetimes as $datetime) {
1308
-            if ($datetime instanceof EE_Datetime) {
1309
-                $qty = min($qty, $datetime->reg_limit());
1310
-            }
1311
-        }
1312
-        $this->set('TKT_qty', $qty);
1313
-    }
1314
-
1315
-
1316
-    /**
1317
-     * Gets uses
1318
-     *
1319
-     * @return int
1320
-     * @throws EE_Error
1321
-     * @throws ReflectionException
1322
-     */
1323
-    public function uses()
1324
-    {
1325
-        return $this->get('TKT_uses');
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     * Sets uses
1331
-     *
1332
-     * @param int $uses
1333
-     * @return void
1334
-     * @throws EE_Error
1335
-     * @throws ReflectionException
1336
-     */
1337
-    public function set_uses($uses)
1338
-    {
1339
-        $this->set('TKT_uses', $uses);
1340
-    }
1341
-
1342
-
1343
-    /**
1344
-     * returns whether ticket is required or not.
1345
-     *
1346
-     * @return boolean
1347
-     * @throws EE_Error
1348
-     * @throws ReflectionException
1349
-     */
1350
-    public function required()
1351
-    {
1352
-        return $this->get('TKT_required');
1353
-    }
1354
-
1355
-
1356
-    /**
1357
-     * sets the TKT_required property
1358
-     *
1359
-     * @param boolean $required
1360
-     * @return void
1361
-     * @throws EE_Error
1362
-     * @throws ReflectionException
1363
-     */
1364
-    public function set_required($required)
1365
-    {
1366
-        $this->set('TKT_required', $required);
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * Gets taxable
1372
-     *
1373
-     * @return boolean
1374
-     * @throws EE_Error
1375
-     * @throws ReflectionException
1376
-     */
1377
-    public function taxable()
1378
-    {
1379
-        return $this->get('TKT_taxable');
1380
-    }
1381
-
1382
-
1383
-    /**
1384
-     * Sets taxable
1385
-     *
1386
-     * @param boolean $taxable
1387
-     * @return void
1388
-     * @throws EE_Error
1389
-     * @throws ReflectionException
1390
-     */
1391
-    public function set_taxable($taxable)
1392
-    {
1393
-        $this->set('TKT_taxable', $taxable);
1394
-    }
1395
-
1396
-
1397
-    /**
1398
-     * Gets is_default
1399
-     *
1400
-     * @return boolean
1401
-     * @throws EE_Error
1402
-     * @throws ReflectionException
1403
-     */
1404
-    public function is_default()
1405
-    {
1406
-        return $this->get('TKT_is_default');
1407
-    }
1408
-
1409
-
1410
-    /**
1411
-     * Sets is_default
1412
-     *
1413
-     * @param boolean $is_default
1414
-     * @return void
1415
-     * @throws EE_Error
1416
-     * @throws ReflectionException
1417
-     */
1418
-    public function set_is_default($is_default)
1419
-    {
1420
-        $this->set('TKT_is_default', $is_default);
1421
-    }
1422
-
1423
-
1424
-    /**
1425
-     * Gets order
1426
-     *
1427
-     * @return int
1428
-     * @throws EE_Error
1429
-     * @throws ReflectionException
1430
-     */
1431
-    public function order()
1432
-    {
1433
-        return $this->get('TKT_order');
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * Sets order
1439
-     *
1440
-     * @param int $order
1441
-     * @return void
1442
-     * @throws EE_Error
1443
-     * @throws ReflectionException
1444
-     */
1445
-    public function set_order($order)
1446
-    {
1447
-        $this->set('TKT_order', $order);
1448
-    }
1449
-
1450
-
1451
-    /**
1452
-     * Gets row
1453
-     *
1454
-     * @return int
1455
-     * @throws EE_Error
1456
-     * @throws ReflectionException
1457
-     */
1458
-    public function row()
1459
-    {
1460
-        return $this->get('TKT_row');
1461
-    }
1462
-
1463
-
1464
-    /**
1465
-     * Sets row
1466
-     *
1467
-     * @param int $row
1468
-     * @return void
1469
-     * @throws EE_Error
1470
-     * @throws ReflectionException
1471
-     */
1472
-    public function set_row($row)
1473
-    {
1474
-        $this->set('TKT_row', $row);
1475
-    }
1476
-
1477
-
1478
-    /**
1479
-     * Gets deleted
1480
-     *
1481
-     * @return boolean
1482
-     * @throws EE_Error
1483
-     * @throws ReflectionException
1484
-     */
1485
-    public function deleted()
1486
-    {
1487
-        return $this->get('TKT_deleted');
1488
-    }
1489
-
1490
-
1491
-    /**
1492
-     * Sets deleted
1493
-     *
1494
-     * @param boolean $deleted
1495
-     * @return void
1496
-     * @throws EE_Error
1497
-     * @throws ReflectionException
1498
-     */
1499
-    public function set_deleted($deleted)
1500
-    {
1501
-        $this->set('TKT_deleted', $deleted);
1502
-    }
1503
-
1504
-
1505
-    /**
1506
-     * Gets parent
1507
-     *
1508
-     * @return int
1509
-     * @throws EE_Error
1510
-     * @throws ReflectionException
1511
-     */
1512
-    public function parent_ID()
1513
-    {
1514
-        return $this->get('TKT_parent');
1515
-    }
1516
-
1517
-
1518
-    /**
1519
-     * Sets parent
1520
-     *
1521
-     * @param int $parent
1522
-     * @return void
1523
-     * @throws EE_Error
1524
-     * @throws ReflectionException
1525
-     */
1526
-    public function set_parent_ID($parent)
1527
-    {
1528
-        $this->set('TKT_parent', $parent);
1529
-    }
1530
-
1531
-
1532
-    /**
1533
-     * @return boolean
1534
-     * @throws EE_Error
1535
-     * @throws InvalidArgumentException
1536
-     * @throws InvalidDataTypeException
1537
-     * @throws InvalidInterfaceException
1538
-     * @throws ReflectionException
1539
-     */
1540
-    public function reverse_calculate()
1541
-    {
1542
-        return $this->get('TKT_reverse_calculate');
1543
-    }
1544
-
1545
-
1546
-    /**
1547
-     * @param boolean $reverse_calculate
1548
-     * @throws EE_Error
1549
-     * @throws InvalidArgumentException
1550
-     * @throws InvalidDataTypeException
1551
-     * @throws InvalidInterfaceException
1552
-     * @throws ReflectionException
1553
-     */
1554
-    public function set_reverse_calculate($reverse_calculate)
1555
-    {
1556
-        $this->set('TKT_reverse_calculate', $reverse_calculate);
1557
-    }
1558
-
1559
-
1560
-    /**
1561
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1562
-     *
1563
-     * @return string
1564
-     * @throws EE_Error
1565
-     * @throws ReflectionException
1566
-     */
1567
-    public function name_and_info()
1568
-    {
1569
-        $times = [];
1570
-        foreach ($this->datetimes() as $datetime) {
1571
-            $times[] = $datetime->start_date_and_time();
1572
-        }
1573
-        /* translators: %1$s ticket name, %2$s start datetimes separated by comma, %3$s ticket price */
1574
-        return sprintf(
1575
-            esc_html__('%1$s @ %2$s for %3$s', 'event_espresso'),
1576
-            $this->name(),
1577
-            implode(', ', $times),
1578
-            $this->pretty_price()
1579
-        );
1580
-    }
1581
-
1582
-
1583
-    /**
1584
-     * Gets name
1585
-     *
1586
-     * @return string
1587
-     * @throws EE_Error
1588
-     * @throws ReflectionException
1589
-     */
1590
-    public function name()
1591
-    {
1592
-        return $this->get('TKT_name');
1593
-    }
1594
-
1595
-
1596
-    /**
1597
-     * Gets price
1598
-     *
1599
-     * @return float
1600
-     * @throws EE_Error
1601
-     * @throws ReflectionException
1602
-     */
1603
-    public function price()
1604
-    {
1605
-        return $this->get('TKT_price');
1606
-    }
1607
-
1608
-
1609
-    /**
1610
-     * Gets all the registrations for this ticket
1611
-     *
1612
-     * @param array $query_params
1613
-     * @return EE_Registration[]|EE_Base_Class[]
1614
-     * @throws EE_Error
1615
-     * @throws ReflectionException
1616
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1617
-     */
1618
-    public function registrations($query_params = [])
1619
-    {
1620
-        return $this->get_many_related('Registration', $query_params);
1621
-    }
1622
-
1623
-
1624
-    /**
1625
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1626
-     *
1627
-     * @return int
1628
-     * @throws EE_Error
1629
-     * @throws ReflectionException
1630
-     */
1631
-    public function update_tickets_sold()
1632
-    {
1633
-        $count_regs_for_this_ticket = $this->count_registrations(
1634
-            [
1635
-                [
1636
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1637
-                    'REG_deleted' => 0,
1638
-                ],
1639
-            ]
1640
-        );
1641
-        $this->set_sold($count_regs_for_this_ticket);
1642
-        $this->save();
1643
-        return $count_regs_for_this_ticket;
1644
-    }
1645
-
1646
-
1647
-    /**
1648
-     * Counts the registrations for this ticket
1649
-     *
1650
-     * @param array $query_params
1651
-     * @return int
1652
-     * @throws EE_Error
1653
-     * @throws ReflectionException
1654
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1655
-     */
1656
-    public function count_registrations($query_params = [])
1657
-    {
1658
-        return $this->count_related('Registration', $query_params);
1659
-    }
1660
-
1661
-
1662
-    /**
1663
-     * Implementation for EEI_Has_Icon interface method.
1664
-     *
1665
-     * @return string
1666
-     * @see EEI_Visual_Representation for comments
1667
-     */
1668
-    public function get_icon()
1669
-    {
1670
-        return '<span class="dashicons dashicons-tickets-alt"></span>';
1671
-    }
1672
-
1673
-
1674
-    /**
1675
-     * Implementation of the EEI_Event_Relation interface method
1676
-     *
1677
-     * @return EE_Event
1678
-     * @throws EE_Error
1679
-     * @throws UnexpectedEntityException
1680
-     * @throws ReflectionException
1681
-     * @see EEI_Event_Relation for comments
1682
-     */
1683
-    public function get_related_event()
1684
-    {
1685
-        // get one datetime to use for getting the event
1686
-        $datetime = $this->first_datetime();
1687
-        if (! $datetime instanceof EE_Datetime) {
1688
-            throw new UnexpectedEntityException(
1689
-                $datetime,
1690
-                'EE_Datetime',
1691
-                sprintf(
1692
-                    esc_html__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1693
-                    $this->name()
1694
-                )
1695
-            );
1696
-        }
1697
-        $event = $datetime->event();
1698
-        if (! $event instanceof EE_Event) {
1699
-            throw new UnexpectedEntityException(
1700
-                $event,
1701
-                'EE_Event',
1702
-                sprintf(
1703
-                    esc_html__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1704
-                    $this->name()
1705
-                )
1706
-            );
1707
-        }
1708
-        return $event;
1709
-    }
1710
-
1711
-
1712
-    /**
1713
-     * Implementation of the EEI_Event_Relation interface method
1714
-     *
1715
-     * @return string
1716
-     * @throws UnexpectedEntityException
1717
-     * @throws EE_Error
1718
-     * @throws ReflectionException
1719
-     * @see EEI_Event_Relation for comments
1720
-     */
1721
-    public function get_event_name()
1722
-    {
1723
-        $event = $this->get_related_event();
1724
-        return $event instanceof EE_Event ? $event->name() : '';
1725
-    }
1726
-
1727
-
1728
-    /**
1729
-     * Implementation of the EEI_Event_Relation interface method
1730
-     *
1731
-     * @return int
1732
-     * @throws UnexpectedEntityException
1733
-     * @throws EE_Error
1734
-     * @throws ReflectionException
1735
-     * @see EEI_Event_Relation for comments
1736
-     */
1737
-    public function get_event_ID()
1738
-    {
1739
-        $event = $this->get_related_event();
1740
-        return $event instanceof EE_Event ? $event->ID() : 0;
1741
-    }
1742
-
1743
-
1744
-    /**
1745
-     * This simply returns whether a ticket can be permanently deleted or not.
1746
-     * The criteria for determining this is whether the ticket has any related registrations.
1747
-     * If there are none then it can be permanently deleted.
1748
-     *
1749
-     * @return bool
1750
-     * @throws EE_Error
1751
-     * @throws ReflectionException
1752
-     */
1753
-    public function is_permanently_deleteable()
1754
-    {
1755
-        return $this->count_registrations() === 0;
1756
-    }
1757
-
1758
-
1759
-    /**
1760
-     * @return int
1761
-     * @throws EE_Error
1762
-     * @throws ReflectionException
1763
-     * @since   5.0.0.p
1764
-     */
1765
-    public function visibility(): int
1766
-    {
1767
-        return $this->get('TKT_visibility');
1768
-    }
1769
-
1770
-
1771
-    /**
1772
-     * @return bool
1773
-     * @throws EE_Error
1774
-     * @throws ReflectionException
1775
-     * @since   5.0.0.p
1776
-     */
1777
-    public function isHidden(): bool
1778
-    {
1779
-        return $this->visibility() === EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE;
1780
-    }
1781
-
1782
-
1783
-    /**
1784
-     * @return bool
1785
-     * @throws EE_Error
1786
-     * @throws ReflectionException
1787
-     * @since   5.0.0.p
1788
-     */
1789
-    public function isNotHidden(): bool
1790
-    {
1791
-        return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE;
1792
-    }
1793
-
1794
-
1795
-    /**
1796
-     * @return bool
1797
-     * @throws EE_Error
1798
-     * @throws ReflectionException
1799
-     * @since   5.0.0.p
1800
-     */
1801
-    public function isPublicOnly(): bool
1802
-    {
1803
-        return $this->isNotHidden() && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE;
1804
-    }
1805
-
1806
-
1807
-    /**
1808
-     * @return bool
1809
-     * @throws EE_Error
1810
-     * @throws ReflectionException
1811
-     * @since   5.0.0.p
1812
-     */
1813
-    public function isMembersOnly(): bool
1814
-    {
1815
-        return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE
1816
-               && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE;
1817
-    }
1818
-
1819
-
1820
-    /**
1821
-     * @return bool
1822
-     * @throws EE_Error
1823
-     * @throws ReflectionException
1824
-     * @since   5.0.0.p
1825
-     */
1826
-    public function isAdminsOnly(): bool
1827
-    {
1828
-        return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE
1829
-               && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE;
1830
-    }
1831
-
1832
-
1833
-    /**
1834
-     * @return bool
1835
-     * @throws EE_Error
1836
-     * @throws ReflectionException
1837
-     * @since   5.0.0.p
1838
-     */
1839
-    public function isAdminUiOnly(): bool
1840
-    {
1841
-        return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE
1842
-               && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMIN_UI_ONLY_VALUE;
1843
-    }
1844
-
1845
-
1846
-    /**
1847
-     * @param int $visibility
1848
-     * @throws EE_Error
1849
-     * @throws ReflectionException
1850
-     * @since   5.0.0.p
1851
-     */
1852
-    public function set_visibility(int $visibility)
1853
-    {
1854
-        $ticket_visibility_options = $this->_model->ticketVisibilityOptions();
1855
-        $ticket_visibility         = -1;
1856
-        foreach ($ticket_visibility_options as $ticket_visibility_option) {
1857
-            if ($visibility === $ticket_visibility_option) {
1858
-                $ticket_visibility = $visibility;
1859
-            }
1860
-        }
1861
-        if ($ticket_visibility === -1) {
1862
-            throw new DomainException(
1863
-                sprintf(
1864
-                    esc_html__(
1865
-                        'The supplied ticket visibility setting of "%1$s" is not valid. It needs to match one of the keys in the following array:%2$s %3$s ',
1866
-                        'event_espresso'
1867
-                    ),
1868
-                    $visibility,
1869
-                    '<br />',
1870
-                    var_export($ticket_visibility_options, true)
1871
-                )
1872
-            );
1873
-        }
1874
-        $this->set('TKT_visibility', $ticket_visibility);
1875
-    }
1876
-
1877
-
1878
-    /**
1879
-     * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1880
-     * @param string                   $relationName
1881
-     * @param array                    $extra_join_model_fields_n_values
1882
-     * @param string|null              $cache_id
1883
-     * @return EE_Base_Class
1884
-     * @throws EE_Error
1885
-     * @throws ReflectionException
1886
-     * @since   5.0.0.p
1887
-     */
1888
-    public function _add_relation_to(
1889
-        $otherObjectModelObjectOrID,
1890
-        $relationName,
1891
-        $extra_join_model_fields_n_values = [],
1892
-        $cache_id = null
1893
-    ) {
1894
-        if ($relationName === 'Datetime' && ! $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1895
-            /** @var EE_Datetime $datetime */
1896
-            $datetime = EEM_Datetime::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1897
-            $datetime->increaseSold($this->sold(), false);
1898
-            $datetime->increaseReserved($this->reserved());
1899
-            $datetime->save();
1900
-            $otherObjectModelObjectOrID = $datetime;
1901
-        }
1902
-        return parent::_add_relation_to(
1903
-            $otherObjectModelObjectOrID,
1904
-            $relationName,
1905
-            $extra_join_model_fields_n_values,
1906
-            $cache_id
1907
-        );
1908
-    }
1909
-
1910
-
1911
-    /**
1912
-     * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1913
-     * @param string                   $relationName
1914
-     * @param array                    $where_query
1915
-     * @return bool|EE_Base_Class|null
1916
-     * @throws EE_Error
1917
-     * @throws ReflectionException
1918
-     * @since   5.0.0.p
1919
-     */
1920
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = [])
1921
-    {
1922
-        // if we're adding a new relation to a datetime
1923
-        if ($relationName === 'Datetime' && $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1924
-            /** @var EE_Datetime $datetime */
1925
-            $datetime = EEM_Datetime::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1926
-            $datetime->decreaseSold($this->sold());
1927
-            $datetime->decreaseReserved($this->reserved());
1928
-            $datetime->save();
1929
-            $otherObjectModelObjectOrID = $datetime;
1930
-        }
1931
-        return parent::_remove_relation_to(
1932
-            $otherObjectModelObjectOrID,
1933
-            $relationName,
1934
-            $where_query
1935
-        );
1936
-    }
1937
-
1938
-
1939
-    /**
1940
-     * Removes ALL the related things for the $relationName.
1941
-     *
1942
-     * @param string $relationName
1943
-     * @param array  $where_query_params
1944
-     * @return EE_Base_Class
1945
-     * @throws ReflectionException
1946
-     * @throws InvalidArgumentException
1947
-     * @throws InvalidInterfaceException
1948
-     * @throws InvalidDataTypeException
1949
-     * @throws EE_Error
1950
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
1951
-     */
1952
-    public function _remove_relations($relationName, $where_query_params = [])
1953
-    {
1954
-        if ($relationName === 'Datetime') {
1955
-            $datetimes = $this->datetimes();
1956
-            foreach ($datetimes as $datetime) {
1957
-                $datetime->decreaseSold($this->sold());
1958
-                $datetime->decreaseReserved($this->reserved());
1959
-                $datetime->save();
1960
-            }
1961
-        }
1962
-        return parent::_remove_relations($relationName, $where_query_params);
1963
-    }
1964
-
1965
-
1966
-    /*******************************************************************
17
+	/**
18
+	 * TicKet Archived:
19
+	 * constant used by ticket_status() to indicate that a ticket is archived
20
+	 * and no longer available for purchase
21
+	 */
22
+	const archived = 'TKA';
23
+
24
+	/**
25
+	 * TicKet Expired:
26
+	 * constant used by ticket_status() to indicate that a ticket is expired
27
+	 * and no longer available for purchase
28
+	 */
29
+	const expired = 'TKE';
30
+
31
+	/**
32
+	 * TicKet On sale:
33
+	 * constant used by ticket_status() to indicate that a ticket is On Sale
34
+	 * and IS available for purchase
35
+	 */
36
+	const onsale = 'TKO';
37
+
38
+	/**
39
+	 * TicKet Pending:
40
+	 * constant used by ticket_status() to indicate that a ticket is pending
41
+	 * and is NOT YET available for purchase
42
+	 */
43
+	const pending = 'TKP';
44
+
45
+	/**
46
+	 * TicKet Sold out:
47
+	 * constant used by ticket_status() to indicate that a ticket is sold out
48
+	 * and no longer available for purchases
49
+	 */
50
+	const sold_out = 'TKS';
51
+
52
+	/**
53
+	 * extra meta key for tracking ticket reservations
54
+	 *
55
+	 * @type string
56
+	 */
57
+	const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
58
+
59
+	/**
60
+	 * override of parent property
61
+	 *
62
+	 * @var EEM_Ticket
63
+	 */
64
+	protected $_model;
65
+
66
+	/**
67
+	 * cached result from method of the same name
68
+	 *
69
+	 * @var float $_ticket_total_with_taxes
70
+	 */
71
+	private $_ticket_total_with_taxes;
72
+
73
+	/**
74
+	 * @var TicketPriceModifiers
75
+	 */
76
+	protected $ticket_price_modifiers;
77
+
78
+
79
+	/**
80
+	 * @param array  $props_n_values          incoming values
81
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
82
+	 *                                        used.)
83
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
84
+	 *                                        date_format and the second value is the time format
85
+	 * @return EE_Ticket
86
+	 * @throws EE_Error
87
+	 * @throws ReflectionException
88
+	 */
89
+	public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
90
+	{
91
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
92
+		return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
93
+	}
94
+
95
+
96
+	/**
97
+	 * @param array  $props_n_values  incoming values from the database
98
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
99
+	 *                                the website will be used.
100
+	 * @return EE_Ticket
101
+	 * @throws EE_Error
102
+	 * @throws ReflectionException
103
+	 */
104
+	public static function new_instance_from_db($props_n_values = [], $timezone = '')
105
+	{
106
+		return new self($props_n_values, true, $timezone);
107
+	}
108
+
109
+
110
+	/**
111
+	 * @param array  $fieldValues
112
+	 * @param false  $bydb
113
+	 * @param string $timezone
114
+	 * @param array  $date_formats
115
+	 * @throws EE_Error
116
+	 * @throws ReflectionException
117
+	 */
118
+	public function __construct($fieldValues = [], $bydb = false, $timezone = '', $date_formats = [])
119
+	{
120
+		parent::__construct($fieldValues, $bydb, $timezone, $date_formats);
121
+		$this->ticket_price_modifiers = new TicketPriceModifiers($this);
122
+	}
123
+
124
+
125
+	/**
126
+	 * @return bool
127
+	 * @throws EE_Error
128
+	 * @throws ReflectionException
129
+	 */
130
+	public function parent()
131
+	{
132
+		return $this->get('TKT_parent');
133
+	}
134
+
135
+
136
+	/**
137
+	 * return if a ticket has quantities available for purchase
138
+	 *
139
+	 * @param int $DTT_ID the primary key for a particular datetime
140
+	 * @return boolean
141
+	 * @throws EE_Error
142
+	 * @throws ReflectionException
143
+	 */
144
+	public function available($DTT_ID = 0)
145
+	{
146
+		// are we checking availability for a particular datetime ?
147
+		if ($DTT_ID) {
148
+			// get that datetime object
149
+			$datetime = $this->get_first_related('Datetime', [['DTT_ID' => $DTT_ID]]);
150
+			// if  ticket sales for this datetime have exceeded the reg limit...
151
+			if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
152
+				return false;
153
+			}
154
+		}
155
+		// datetime is still open for registration, but is this ticket sold out ?
156
+		return $this->qty() < 1 || $this->qty() > $this->sold();
157
+	}
158
+
159
+
160
+	/**
161
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
162
+	 *
163
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
164
+	 *                               relevant status const
165
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
166
+	 *                               further processing
167
+	 * @return mixed status int if the display string isn't requested
168
+	 * @throws EE_Error
169
+	 * @throws ReflectionException
170
+	 */
171
+	public function ticket_status($display = false, $remaining = null)
172
+	{
173
+		$remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
174
+		if (! $remaining) {
175
+			return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
176
+		}
177
+		if ($this->get('TKT_deleted')) {
178
+			return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
179
+		}
180
+		if ($this->is_expired()) {
181
+			return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
182
+		}
183
+		if ($this->is_pending()) {
184
+			return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
185
+		}
186
+		if ($this->is_on_sale()) {
187
+			return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
188
+		}
189
+		return '';
190
+	}
191
+
192
+
193
+	/**
194
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
195
+	 * considering ALL the factors used for figuring that out.
196
+	 *
197
+	 * @param int $DTT_ID if an int above 0 is included here then we get a specific dtt.
198
+	 * @return boolean         true = tickets remaining, false not.
199
+	 * @throws EE_Error
200
+	 * @throws ReflectionException
201
+	 */
202
+	public function is_remaining($DTT_ID = 0)
203
+	{
204
+		$num_remaining = $this->remaining($DTT_ID);
205
+		if ($num_remaining === 0) {
206
+			return false;
207
+		}
208
+		if ($num_remaining > 0 && $num_remaining < $this->min()) {
209
+			return false;
210
+		}
211
+		return true;
212
+	}
213
+
214
+
215
+	/**
216
+	 * return the total number of tickets available for purchase
217
+	 *
218
+	 * @param int $DTT_ID  the primary key for a particular datetime.
219
+	 *                     set to 0 for all related datetimes
220
+	 * @return int
221
+	 * @throws EE_Error
222
+	 * @throws ReflectionException
223
+	 */
224
+	public function remaining($DTT_ID = 0)
225
+	{
226
+		return $this->real_quantity_on_ticket('saleable', $DTT_ID);
227
+	}
228
+
229
+
230
+	/**
231
+	 * Gets min
232
+	 *
233
+	 * @return int
234
+	 * @throws EE_Error
235
+	 * @throws ReflectionException
236
+	 */
237
+	public function min()
238
+	{
239
+		return $this->get('TKT_min');
240
+	}
241
+
242
+
243
+	/**
244
+	 * return if a ticket is no longer available cause its available dates have expired.
245
+	 *
246
+	 * @return boolean
247
+	 * @throws EE_Error
248
+	 * @throws ReflectionException
249
+	 */
250
+	public function is_expired()
251
+	{
252
+		return ($this->get_raw('TKT_end_date') < time());
253
+	}
254
+
255
+
256
+	/**
257
+	 * Return if a ticket is yet to go on sale or not
258
+	 *
259
+	 * @return boolean
260
+	 * @throws EE_Error
261
+	 * @throws ReflectionException
262
+	 */
263
+	public function is_pending()
264
+	{
265
+		return ($this->get_raw('TKT_start_date') >= time());
266
+	}
267
+
268
+
269
+	/**
270
+	 * Return if a ticket is on sale or not
271
+	 *
272
+	 * @return boolean
273
+	 * @throws EE_Error
274
+	 * @throws ReflectionException
275
+	 */
276
+	public function is_on_sale()
277
+	{
278
+		return ($this->get_raw('TKT_start_date') <= time() && $this->get_raw('TKT_end_date') >= time());
279
+	}
280
+
281
+
282
+	/**
283
+	 * This returns the chronologically last datetime that this ticket is associated with
284
+	 *
285
+	 * @param string $date_format
286
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
287
+	 *                            the end date ie: Jan 01 "to" Dec 31
288
+	 * @return string
289
+	 * @throws EE_Error
290
+	 * @throws ReflectionException
291
+	 */
292
+	public function date_range($date_format = '', $conjunction = ' - ')
293
+	{
294
+		$date_format = ! empty($date_format) ? $date_format : $this->_dt_frmt;
295
+		$first_date  = $this->first_datetime() instanceof EE_Datetime
296
+			? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $date_format)
297
+			: '';
298
+		$last_date   = $this->last_datetime() instanceof EE_Datetime
299
+			? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $date_format)
300
+			: '';
301
+
302
+		return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
303
+	}
304
+
305
+
306
+	/**
307
+	 * This returns the chronologically first datetime that this ticket is associated with
308
+	 *
309
+	 * @return EE_Datetime
310
+	 * @throws EE_Error
311
+	 * @throws ReflectionException
312
+	 */
313
+	public function first_datetime()
314
+	{
315
+		$datetimes = $this->datetimes(['limit' => 1]);
316
+		return reset($datetimes);
317
+	}
318
+
319
+
320
+	/**
321
+	 * Gets all the datetimes this ticket can be used for attending.
322
+	 * Unless otherwise specified, orders datetimes by start date.
323
+	 *
324
+	 * @param array $query_params
325
+	 * @return EE_Datetime[]|EE_Base_Class[]
326
+	 * @throws EE_Error
327
+	 * @throws ReflectionException
328
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
329
+	 */
330
+	public function datetimes($query_params = [])
331
+	{
332
+		if (! isset($query_params['order_by'])) {
333
+			$query_params['order_by']['DTT_order'] = 'ASC';
334
+		}
335
+		return $this->get_many_related('Datetime', $query_params);
336
+	}
337
+
338
+
339
+	/**
340
+	 * This returns the chronologically last datetime that this ticket is associated with
341
+	 *
342
+	 * @return EE_Datetime
343
+	 * @throws EE_Error
344
+	 * @throws ReflectionException
345
+	 */
346
+	public function last_datetime()
347
+	{
348
+		$datetimes = $this->datetimes(['limit' => 1, 'order_by' => ['DTT_EVT_start' => 'DESC']]);
349
+		return end($datetimes);
350
+	}
351
+
352
+
353
+	/**
354
+	 * This returns the total tickets sold depending on the given parameters.
355
+	 *
356
+	 * @param string $what    Can be one of two options: 'ticket', 'datetime'.
357
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
358
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
359
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
360
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
361
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
362
+	 * @param int    $dtt_id  [optional] include the dtt_id with $what = 'datetime'.
363
+	 * @return mixed (array|int)          how many tickets have sold
364
+	 * @throws EE_Error
365
+	 * @throws ReflectionException
366
+	 */
367
+	public function tickets_sold($what = 'ticket', $dtt_id = null)
368
+	{
369
+		$total        = 0;
370
+		$tickets_sold = $this->_all_tickets_sold();
371
+		switch ($what) {
372
+			case 'ticket':
373
+				return $tickets_sold['ticket'];
374
+
375
+			case 'datetime':
376
+				if (empty($tickets_sold['datetime'])) {
377
+					return $total;
378
+				}
379
+				if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
380
+					EE_Error::add_error(
381
+						esc_html__(
382
+							'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?',
383
+							'event_espresso'
384
+						),
385
+						__FILE__,
386
+						__FUNCTION__,
387
+						__LINE__
388
+					);
389
+					return $total;
390
+				}
391
+				return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
392
+
393
+			default:
394
+				return $total;
395
+		}
396
+	}
397
+
398
+
399
+	/**
400
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
401
+	 *
402
+	 * @return EE_Ticket[]
403
+	 * @throws EE_Error
404
+	 * @throws ReflectionException
405
+	 */
406
+	protected function _all_tickets_sold()
407
+	{
408
+		$datetimes    = $this->get_many_related('Datetime');
409
+		$tickets_sold = [];
410
+		if (! empty($datetimes)) {
411
+			foreach ($datetimes as $datetime) {
412
+				$tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
413
+			}
414
+		}
415
+		// Tickets sold
416
+		$tickets_sold['ticket'] = $this->sold();
417
+		return $tickets_sold;
418
+	}
419
+
420
+
421
+	/**
422
+	 * This returns the base price object for the ticket.
423
+	 *
424
+	 * @param bool $return_array whether to return as an array indexed by price id or just the object.
425
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
426
+	 * @throws EE_Error
427
+	 * @throws ReflectionException
428
+	 */
429
+	public function base_price(bool $return_array = false)
430
+	{
431
+		$base_price = $this->ticket_price_modifiers->getBasePrice();
432
+		if (! empty($base_price)) {
433
+			return $return_array ? $base_price : reset($base_price);
434
+		}
435
+		$_where = ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price];
436
+		return $return_array
437
+			? $this->get_many_related('Price', [$_where])
438
+			: $this->get_first_related('Price', [$_where]);
439
+	}
440
+
441
+
442
+	/**
443
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
444
+	 *
445
+	 * @return EE_Price[]
446
+	 * @throws EE_Error
447
+	 * @throws ReflectionException
448
+	 */
449
+	public function price_modifiers(): array
450
+	{
451
+		$price_modifiers = $this->usesGlobalTaxes()
452
+			? $this->ticket_price_modifiers->getAllDiscountAndSurchargeModifiersForTicket()
453
+			: $this->ticket_price_modifiers->getAllModifiersForTicket();
454
+		if (! empty($price_modifiers)) {
455
+			return $price_modifiers;
456
+		}
457
+		return $this->prices(
458
+			[
459
+				[
460
+					'Price_Type.PBT_ID' => [
461
+						'NOT IN',
462
+						[EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax],
463
+					],
464
+				],
465
+			]
466
+		);
467
+	}
468
+
469
+
470
+	/**
471
+	 * This returns ONLY the TAX price modifiers for the ticket
472
+	 *
473
+	 * @return EE_Price[]
474
+	 * @throws EE_Error
475
+	 * @throws ReflectionException
476
+	 */
477
+	public function tax_price_modifiers(): array
478
+	{
479
+		$tax_price_modifiers = $this->ticket_price_modifiers->getAllTaxesForTicket();
480
+		if (! empty($tax_price_modifiers)) {
481
+			return $tax_price_modifiers;
482
+		}
483
+		return $this->prices([['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax]]);
484
+	}
485
+
486
+
487
+	/**
488
+	 * Gets all the prices that combine to form the final price of this ticket
489
+	 *
490
+	 * @param array $query_params
491
+	 * @return EE_Price[]|EE_Base_Class[]
492
+	 * @throws EE_Error
493
+	 * @throws ReflectionException
494
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
495
+	 */
496
+	public function prices(array $query_params = []): array
497
+	{
498
+		if (! isset($query_params['order_by'])) {
499
+			$query_params['order_by']['PRC_order'] = 'ASC';
500
+		}
501
+		return $this->get_many_related('Price', $query_params);
502
+	}
503
+
504
+
505
+	/**
506
+	 * Gets all the ticket datetimes (ie, relations between datetimes and tickets)
507
+	 *
508
+	 * @param array $query_params
509
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
510
+	 * @throws EE_Error
511
+	 * @throws ReflectionException
512
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
513
+	 */
514
+	public function datetime_tickets($query_params = [])
515
+	{
516
+		return $this->get_many_related('Datetime_Ticket', $query_params);
517
+	}
518
+
519
+
520
+	/**
521
+	 * Gets all the datetimes from the db ordered by DTT_order
522
+	 *
523
+	 * @param boolean $show_expired
524
+	 * @param boolean $show_deleted
525
+	 * @return EE_Datetime[]
526
+	 * @throws EE_Error
527
+	 * @throws ReflectionException
528
+	 */
529
+	public function datetimes_ordered($show_expired = true, $show_deleted = false)
530
+	{
531
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
532
+			$this->ID(),
533
+			$show_expired,
534
+			$show_deleted
535
+		);
536
+	}
537
+
538
+
539
+	/**
540
+	 * Gets ID
541
+	 *
542
+	 * @return int
543
+	 * @throws EE_Error
544
+	 * @throws ReflectionException
545
+	 */
546
+	public function ID()
547
+	{
548
+		return (int) $this->get('TKT_ID');
549
+	}
550
+
551
+
552
+	/**
553
+	 * get the author of the ticket.
554
+	 *
555
+	 * @return int
556
+	 * @throws EE_Error
557
+	 * @throws ReflectionException
558
+	 * @since 4.5.0
559
+	 */
560
+	public function wp_user()
561
+	{
562
+		return $this->get('TKT_wp_user');
563
+	}
564
+
565
+
566
+	/**
567
+	 * Gets the template for the ticket
568
+	 *
569
+	 * @return EE_Ticket_Template|EE_Base_Class
570
+	 * @throws EE_Error
571
+	 * @throws ReflectionException
572
+	 */
573
+	public function template()
574
+	{
575
+		return $this->get_first_related('Ticket_Template');
576
+	}
577
+
578
+
579
+	/**
580
+	 * Simply returns an array of EE_Price objects that are taxes.
581
+	 *
582
+	 * @return EE_Price[]
583
+	 * @throws EE_Error
584
+	 * @throws ReflectionException
585
+	 */
586
+	public function get_ticket_taxes_for_admin(): array
587
+	{
588
+		return $this->usesGlobalTaxes() ? EE_Taxes::get_taxes_for_admin() : $this->tax_price_modifiers();
589
+	}
590
+
591
+
592
+	/**
593
+	 * alias of taxable() to better indicate that ticket uses the legacy method of applying default "global" taxes
594
+	 * as opposed to having tax price modifiers added directly to each ticket
595
+	 *
596
+	 * @return bool
597
+	 * @throws EE_Error
598
+	 * @throws ReflectionException
599
+	 * @since   5.0.0.p
600
+	 */
601
+	public function usesGlobalTaxes(): bool
602
+	{
603
+		return $this->taxable();
604
+	}
605
+
606
+
607
+	/**
608
+	 * @return float
609
+	 * @throws EE_Error
610
+	 * @throws ReflectionException
611
+	 */
612
+	public function ticket_price()
613
+	{
614
+		return $this->get('TKT_price');
615
+	}
616
+
617
+
618
+	/**
619
+	 * @return mixed
620
+	 * @throws EE_Error
621
+	 * @throws ReflectionException
622
+	 */
623
+	public function pretty_price()
624
+	{
625
+		return $this->get_pretty('TKT_price');
626
+	}
627
+
628
+
629
+	/**
630
+	 * @return bool
631
+	 * @throws EE_Error
632
+	 * @throws ReflectionException
633
+	 */
634
+	public function is_free()
635
+	{
636
+		return $this->get_ticket_total_with_taxes() === (float) 0;
637
+	}
638
+
639
+
640
+	/**
641
+	 * get_ticket_total_with_taxes
642
+	 *
643
+	 * @param bool $no_cache
644
+	 * @return float
645
+	 * @throws EE_Error
646
+	 * @throws ReflectionException
647
+	 */
648
+	public function get_ticket_total_with_taxes(bool $no_cache = false): float
649
+	{
650
+		if ($this->_ticket_total_with_taxes === null || $no_cache) {
651
+			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal();
652
+			// add taxes
653
+			if ($this->usesGlobalTaxes()) {
654
+				$this->_ticket_total_with_taxes += $this->get_ticket_taxes_total_for_admin();
655
+			} else {
656
+				$subtotal = $this->_ticket_total_with_taxes;
657
+				foreach ($this->tax_price_modifiers() as $tax) {
658
+					$this->_ticket_total_with_taxes += $subtotal * $tax->amount() / 100;
659
+				}
660
+			}
661
+		}
662
+		return (float) $this->_ticket_total_with_taxes;
663
+	}
664
+
665
+
666
+	/**
667
+	 * @throws EE_Error
668
+	 * @throws ReflectionException
669
+	 */
670
+	public function ensure_TKT_Price_correct()
671
+	{
672
+		$this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
673
+		$this->save();
674
+	}
675
+
676
+
677
+	/**
678
+	 * @return float
679
+	 * @throws EE_Error
680
+	 * @throws ReflectionException
681
+	 */
682
+	public function get_ticket_subtotal()
683
+	{
684
+		return EE_Taxes::get_subtotal_for_admin($this);
685
+	}
686
+
687
+
688
+	/**
689
+	 * Returns the total taxes applied to this ticket
690
+	 *
691
+	 * @return float
692
+	 * @throws EE_Error
693
+	 * @throws ReflectionException
694
+	 */
695
+	public function get_ticket_taxes_total_for_admin()
696
+	{
697
+		return EE_Taxes::get_total_taxes_for_admin($this);
698
+	}
699
+
700
+
701
+	/**
702
+	 * Sets name
703
+	 *
704
+	 * @param string $name
705
+	 * @throws EE_Error
706
+	 * @throws ReflectionException
707
+	 */
708
+	public function set_name($name)
709
+	{
710
+		$this->set('TKT_name', $name);
711
+	}
712
+
713
+
714
+	/**
715
+	 * Gets description
716
+	 *
717
+	 * @return string
718
+	 * @throws EE_Error
719
+	 * @throws ReflectionException
720
+	 */
721
+	public function description()
722
+	{
723
+		return $this->get('TKT_description');
724
+	}
725
+
726
+
727
+	/**
728
+	 * Sets description
729
+	 *
730
+	 * @param string $description
731
+	 * @throws EE_Error
732
+	 * @throws ReflectionException
733
+	 */
734
+	public function set_description($description)
735
+	{
736
+		$this->set('TKT_description', $description);
737
+	}
738
+
739
+
740
+	/**
741
+	 * Gets start_date
742
+	 *
743
+	 * @param string|null $date_format
744
+	 * @param string|null $time_format
745
+	 * @return string
746
+	 * @throws EE_Error
747
+	 * @throws ReflectionException
748
+	 */
749
+	public function start_date(?string $date_format = '', ?string $time_format = ''): string
750
+	{
751
+		return $this->_get_datetime('TKT_start_date', $date_format, $time_format);
752
+	}
753
+
754
+
755
+	/**
756
+	 * Sets start_date
757
+	 *
758
+	 * @param string $start_date
759
+	 * @return void
760
+	 * @throws EE_Error
761
+	 * @throws ReflectionException
762
+	 */
763
+	public function set_start_date($start_date)
764
+	{
765
+		$this->_set_date_time('B', $start_date, 'TKT_start_date');
766
+	}
767
+
768
+
769
+	/**
770
+	 * Gets end_date
771
+	 *
772
+	 * @param string|null $date_format
773
+	 * @param string|null $time_format
774
+	 * @return string
775
+	 * @throws EE_Error
776
+	 * @throws ReflectionException
777
+	 */
778
+	public function end_date(?string $date_format = '', ?string $time_format = ''): string
779
+	{
780
+		return $this->_get_datetime('TKT_end_date', $date_format, $time_format);
781
+	}
782
+
783
+
784
+	/**
785
+	 * Sets end_date
786
+	 *
787
+	 * @param string $end_date
788
+	 * @return void
789
+	 * @throws EE_Error
790
+	 * @throws ReflectionException
791
+	 */
792
+	public function set_end_date($end_date)
793
+	{
794
+		$this->_set_date_time('B', $end_date, 'TKT_end_date');
795
+	}
796
+
797
+
798
+	/**
799
+	 * Sets sell until time
800
+	 *
801
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
802
+	 * @throws EE_Error
803
+	 * @throws ReflectionException
804
+	 * @since 4.5.0
805
+	 */
806
+	public function set_end_time($time)
807
+	{
808
+		$this->_set_time_for($time, 'TKT_end_date');
809
+	}
810
+
811
+
812
+	/**
813
+	 * Sets min
814
+	 *
815
+	 * @param int $min
816
+	 * @return void
817
+	 * @throws EE_Error
818
+	 * @throws ReflectionException
819
+	 */
820
+	public function set_min($min)
821
+	{
822
+		$this->set('TKT_min', $min);
823
+	}
824
+
825
+
826
+	/**
827
+	 * Gets max
828
+	 *
829
+	 * @return int
830
+	 * @throws EE_Error
831
+	 * @throws ReflectionException
832
+	 */
833
+	public function max()
834
+	{
835
+		return $this->get('TKT_max');
836
+	}
837
+
838
+
839
+	/**
840
+	 * Sets max
841
+	 *
842
+	 * @param int $max
843
+	 * @return void
844
+	 * @throws EE_Error
845
+	 * @throws ReflectionException
846
+	 */
847
+	public function set_max($max)
848
+	{
849
+		$this->set('TKT_max', $max);
850
+	}
851
+
852
+
853
+	/**
854
+	 * Sets price
855
+	 *
856
+	 * @param float $price
857
+	 * @return void
858
+	 * @throws EE_Error
859
+	 * @throws ReflectionException
860
+	 */
861
+	public function set_price($price)
862
+	{
863
+		$this->set('TKT_price', $price);
864
+	}
865
+
866
+
867
+	/**
868
+	 * Gets sold
869
+	 *
870
+	 * @return int
871
+	 * @throws EE_Error
872
+	 * @throws ReflectionException
873
+	 */
874
+	public function sold(): int
875
+	{
876
+		return (int) $this->get_raw('TKT_sold');
877
+	}
878
+
879
+
880
+	/**
881
+	 * Sets sold
882
+	 *
883
+	 * @param int $sold
884
+	 * @return void
885
+	 * @throws EE_Error
886
+	 * @throws ReflectionException
887
+	 */
888
+	public function set_sold($sold)
889
+	{
890
+		// sold can not go below zero
891
+		$sold = max(0, $sold);
892
+		$this->set('TKT_sold', $sold);
893
+	}
894
+
895
+
896
+	/**
897
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
898
+	 * associated datetimes.
899
+	 *
900
+	 * @param int $qty
901
+	 * @return boolean
902
+	 * @throws EE_Error
903
+	 * @throws InvalidArgumentException
904
+	 * @throws InvalidDataTypeException
905
+	 * @throws InvalidInterfaceException
906
+	 * @throws ReflectionException
907
+	 * @since 4.9.80.p
908
+	 */
909
+	public function increaseSold($qty = 1)
910
+	{
911
+		$qty = absint($qty);
912
+		// increment sold and decrement reserved datetime quantities simultaneously
913
+		// don't worry about failures, because they must have already had a spot reserved
914
+		$this->increaseSoldForDatetimes($qty);
915
+		// Increment and decrement ticket quantities simultaneously
916
+		$success = $this->adjustNumericFieldsInDb(
917
+			[
918
+				'TKT_reserved' => $qty * -1,
919
+				'TKT_sold'     => $qty,
920
+			]
921
+		);
922
+		do_action(
923
+			'AHEE__EE_Ticket__increase_sold',
924
+			$this,
925
+			$qty,
926
+			$this->sold(),
927
+			$success
928
+		);
929
+		return $success;
930
+	}
931
+
932
+
933
+	/**
934
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
935
+	 *
936
+	 * @param int           $qty positive or negative. Positive means to increase sold counts (and decrease reserved
937
+	 *                           counts), Negative means to decreases old counts (and increase reserved counts).
938
+	 * @param EE_Datetime[] $datetimes
939
+	 * @throws EE_Error
940
+	 * @throws InvalidArgumentException
941
+	 * @throws InvalidDataTypeException
942
+	 * @throws InvalidInterfaceException
943
+	 * @throws ReflectionException
944
+	 * @since 4.9.80.p
945
+	 */
946
+	protected function increaseSoldForDatetimes($qty, array $datetimes = [])
947
+	{
948
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
949
+		foreach ($datetimes as $datetime) {
950
+			$datetime->increaseSold($qty);
951
+		}
952
+	}
953
+
954
+
955
+	/**
956
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
957
+	 * DB and then updates the model objects.
958
+	 * Does not affect the reserved counts.
959
+	 *
960
+	 * @param int $qty
961
+	 * @return boolean
962
+	 * @throws EE_Error
963
+	 * @throws InvalidArgumentException
964
+	 * @throws InvalidDataTypeException
965
+	 * @throws InvalidInterfaceException
966
+	 * @throws ReflectionException
967
+	 * @since 4.9.80.p
968
+	 */
969
+	public function decreaseSold($qty = 1)
970
+	{
971
+		$qty = absint($qty);
972
+		$this->decreaseSoldForDatetimes($qty);
973
+		$success = $this->adjustNumericFieldsInDb(
974
+			[
975
+				'TKT_sold' => $qty * -1,
976
+			]
977
+		);
978
+		do_action(
979
+			'AHEE__EE_Ticket__decrease_sold',
980
+			$this,
981
+			$qty,
982
+			$this->sold(),
983
+			$success
984
+		);
985
+		return $success;
986
+	}
987
+
988
+
989
+	/**
990
+	 * Decreases sold on related datetimes
991
+	 *
992
+	 * @param int           $qty
993
+	 * @param EE_Datetime[] $datetimes
994
+	 * @return void
995
+	 * @throws EE_Error
996
+	 * @throws InvalidArgumentException
997
+	 * @throws InvalidDataTypeException
998
+	 * @throws InvalidInterfaceException
999
+	 * @throws ReflectionException
1000
+	 * @since 4.9.80.p
1001
+	 */
1002
+	protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
1003
+	{
1004
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1005
+		if (is_array($datetimes)) {
1006
+			foreach ($datetimes as $datetime) {
1007
+				if ($datetime instanceof EE_Datetime) {
1008
+					$datetime->decreaseSold($qty);
1009
+				}
1010
+			}
1011
+		}
1012
+	}
1013
+
1014
+
1015
+	/**
1016
+	 * Gets qty of reserved tickets
1017
+	 *
1018
+	 * @return int
1019
+	 * @throws EE_Error
1020
+	 * @throws ReflectionException
1021
+	 */
1022
+	public function reserved(): int
1023
+	{
1024
+		return (int) $this->get_raw('TKT_reserved');
1025
+	}
1026
+
1027
+
1028
+	/**
1029
+	 * Sets reserved
1030
+	 *
1031
+	 * @param int $reserved
1032
+	 * @return void
1033
+	 * @throws EE_Error
1034
+	 * @throws ReflectionException
1035
+	 */
1036
+	public function set_reserved($reserved)
1037
+	{
1038
+		// reserved can not go below zero
1039
+		$reserved = max(0, (int) $reserved);
1040
+		$this->set('TKT_reserved', $reserved);
1041
+	}
1042
+
1043
+
1044
+	/**
1045
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1046
+	 *
1047
+	 * @param int    $qty
1048
+	 * @param string $source
1049
+	 * @return bool whether we successfully reserved the ticket or not.
1050
+	 * @throws EE_Error
1051
+	 * @throws InvalidArgumentException
1052
+	 * @throws ReflectionException
1053
+	 * @throws InvalidDataTypeException
1054
+	 * @throws InvalidInterfaceException
1055
+	 * @since 4.9.80.p
1056
+	 */
1057
+	public function increaseReserved($qty = 1, $source = 'unknown')
1058
+	{
1059
+		$qty = absint($qty);
1060
+		do_action(
1061
+			'AHEE__EE_Ticket__increase_reserved__begin',
1062
+			$this,
1063
+			$qty,
1064
+			$source
1065
+		);
1066
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
1067
+		$success                         = false;
1068
+		$datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
1069
+		if ($datetimes_adjusted_successfully) {
1070
+			$success = $this->incrementFieldConditionallyInDb(
1071
+				'TKT_reserved',
1072
+				'TKT_sold',
1073
+				'TKT_qty',
1074
+				$qty
1075
+			);
1076
+			if (! $success) {
1077
+				// The datetimes were successfully bumped, but not the
1078
+				// ticket. So we need to manually rollback the datetimes.
1079
+				$this->decreaseReservedForDatetimes($qty);
1080
+			}
1081
+		}
1082
+		do_action(
1083
+			'AHEE__EE_Ticket__increase_reserved',
1084
+			$this,
1085
+			$qty,
1086
+			$this->reserved(),
1087
+			$success
1088
+		);
1089
+		return $success;
1090
+	}
1091
+
1092
+
1093
+	/**
1094
+	 * Increases reserved counts on related datetimes
1095
+	 *
1096
+	 * @param int           $qty
1097
+	 * @param EE_Datetime[] $datetimes
1098
+	 * @return boolean indicating success
1099
+	 * @throws EE_Error
1100
+	 * @throws InvalidArgumentException
1101
+	 * @throws InvalidDataTypeException
1102
+	 * @throws InvalidInterfaceException
1103
+	 * @throws ReflectionException
1104
+	 * @since 4.9.80.p
1105
+	 */
1106
+	protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
1107
+	{
1108
+		$datetimes         = ! empty($datetimes) ? $datetimes : $this->datetimes();
1109
+		$datetimes_updated = [];
1110
+		$limit_exceeded    = false;
1111
+		if (is_array($datetimes)) {
1112
+			foreach ($datetimes as $datetime) {
1113
+				if ($datetime instanceof EE_Datetime) {
1114
+					if ($datetime->increaseReserved($qty)) {
1115
+						$datetimes_updated[] = $datetime;
1116
+					} else {
1117
+						$limit_exceeded = true;
1118
+						break;
1119
+					}
1120
+				}
1121
+			}
1122
+			// If somewhere along the way we detected a datetime whose
1123
+			// limit was exceeded, do a manual rollback.
1124
+			if ($limit_exceeded) {
1125
+				$this->decreaseReservedForDatetimes($qty, $datetimes_updated);
1126
+				return false;
1127
+			}
1128
+		}
1129
+		return true;
1130
+	}
1131
+
1132
+
1133
+	/**
1134
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1135
+	 *
1136
+	 * @param int    $qty
1137
+	 * @param bool   $adjust_datetimes
1138
+	 * @param string $source
1139
+	 * @return boolean
1140
+	 * @throws EE_Error
1141
+	 * @throws InvalidArgumentException
1142
+	 * @throws ReflectionException
1143
+	 * @throws InvalidDataTypeException
1144
+	 * @throws InvalidInterfaceException
1145
+	 * @since 4.9.80.p
1146
+	 */
1147
+	public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1148
+	{
1149
+		$qty = absint($qty);
1150
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1151
+		if ($adjust_datetimes) {
1152
+			$this->decreaseReservedForDatetimes($qty);
1153
+		}
1154
+		$success = $this->adjustNumericFieldsInDb(
1155
+			[
1156
+				'TKT_reserved' => $qty * -1,
1157
+			]
1158
+		);
1159
+		do_action(
1160
+			'AHEE__EE_Ticket__decrease_reserved',
1161
+			$this,
1162
+			$qty,
1163
+			$this->reserved(),
1164
+			$success
1165
+		);
1166
+		return $success;
1167
+	}
1168
+
1169
+
1170
+	/**
1171
+	 * Decreases the reserved count on the specified datetimes.
1172
+	 *
1173
+	 * @param int           $qty
1174
+	 * @param EE_Datetime[] $datetimes
1175
+	 * @throws EE_Error
1176
+	 * @throws InvalidArgumentException
1177
+	 * @throws ReflectionException
1178
+	 * @throws InvalidDataTypeException
1179
+	 * @throws InvalidInterfaceException
1180
+	 * @since 4.9.80.p
1181
+	 */
1182
+	protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1183
+	{
1184
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1185
+		foreach ($datetimes as $datetime) {
1186
+			if ($datetime instanceof EE_Datetime) {
1187
+				$datetime->decreaseReserved($qty);
1188
+			}
1189
+		}
1190
+	}
1191
+
1192
+
1193
+	/**
1194
+	 * Gets ticket quantity
1195
+	 *
1196
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1197
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1198
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1199
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1200
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1201
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1202
+	 * @return int
1203
+	 * @throws EE_Error
1204
+	 * @throws ReflectionException
1205
+	 */
1206
+	public function qty($context = '')
1207
+	{
1208
+		switch ($context) {
1209
+			case 'reg_limit':
1210
+				return $this->real_quantity_on_ticket();
1211
+			case 'saleable':
1212
+				return $this->real_quantity_on_ticket('saleable');
1213
+			default:
1214
+				return $this->get_raw('TKT_qty');
1215
+		}
1216
+	}
1217
+
1218
+
1219
+	/**
1220
+	 * Gets ticket quantity
1221
+	 *
1222
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1223
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1224
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1225
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1226
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1227
+	 * @param int    $DTT_ID      the primary key for a particular datetime.
1228
+	 *                            set to 0 for all related datetimes
1229
+	 * @return int|float          int for finite quantity or float for INF
1230
+	 * @throws EE_Error
1231
+	 * @throws ReflectionException
1232
+	 */
1233
+	public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1234
+	{
1235
+		$raw = $this->get_raw('TKT_qty');
1236
+		// return immediately if it's zero
1237
+		if ($raw === 0) {
1238
+			return $raw;
1239
+		}
1240
+		// echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1241
+		// ensure qty doesn't exceed raw value for THIS ticket
1242
+		$qty = min(EE_INF, $raw);
1243
+		// echo "\n . qty: " . $qty . '<br />';
1244
+		// calculate this ticket's total sales and reservations
1245
+		$sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1246
+		// echo "\n . sold: " . $this->sold() . '<br />';
1247
+		// echo "\n . reserved: " . $this->reserved() . '<br />';
1248
+		// echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1249
+		// first we need to calculate the maximum number of tickets available for the datetime
1250
+		// do we want data for one datetime or all of them ?
1251
+		$query_params = $DTT_ID ? [['DTT_ID' => $DTT_ID]] : [];
1252
+		$datetimes    = $this->get_many_related('Datetime', $query_params);
1253
+		if (is_array($datetimes) && ! empty($datetimes)) {
1254
+			foreach ($datetimes as $datetime) {
1255
+				if ($datetime instanceof EE_Datetime) {
1256
+					// $datetime->refresh_from_db();
1257
+					// echo "\n . . datetime name: " . $datetime->name() . '<br />';
1258
+					// echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1259
+					// initialize with no restrictions for each datetime
1260
+					// but adjust datetime qty based on datetime reg limit
1261
+					$datetime_qty = min(EE_INF, $datetime->reg_limit());
1262
+					// echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1263
+					// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1264
+					// if we want the actual saleable amount, then we need to consider OTHER ticket sales
1265
+					// and reservations for this datetime, that do NOT include sales and reservations
1266
+					// for this ticket (so we add $this->sold() and $this->reserved() back in)
1267
+					if ($context === 'saleable') {
1268
+						$datetime_qty = max(
1269
+							$datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1270
+							0
1271
+						);
1272
+						// echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1273
+						// echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1274
+						// echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1275
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1276
+						$datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1277
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1278
+					}
1279
+					$qty = min($datetime_qty, $qty);
1280
+					// echo "\n . . qty: " . $qty . '<br />';
1281
+				}
1282
+			}
1283
+		}
1284
+		// NOW that we know the  maximum number of tickets available for the datetime
1285
+		// we can finally factor in the details for this specific ticket
1286
+		if ($qty > 0 && $context === 'saleable') {
1287
+			// and subtract the sales for THIS ticket
1288
+			$qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1289
+			// echo "\n . qty: " . $qty . '<br />';
1290
+		}
1291
+		// echo "\nFINAL QTY: " . $qty . "<br /><br />";
1292
+		return $qty;
1293
+	}
1294
+
1295
+
1296
+	/**
1297
+	 * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1298
+	 *
1299
+	 * @param int $qty
1300
+	 * @return void
1301
+	 * @throws EE_Error
1302
+	 * @throws ReflectionException
1303
+	 */
1304
+	public function set_qty($qty)
1305
+	{
1306
+		$datetimes = $this->datetimes();
1307
+		foreach ($datetimes as $datetime) {
1308
+			if ($datetime instanceof EE_Datetime) {
1309
+				$qty = min($qty, $datetime->reg_limit());
1310
+			}
1311
+		}
1312
+		$this->set('TKT_qty', $qty);
1313
+	}
1314
+
1315
+
1316
+	/**
1317
+	 * Gets uses
1318
+	 *
1319
+	 * @return int
1320
+	 * @throws EE_Error
1321
+	 * @throws ReflectionException
1322
+	 */
1323
+	public function uses()
1324
+	{
1325
+		return $this->get('TKT_uses');
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 * Sets uses
1331
+	 *
1332
+	 * @param int $uses
1333
+	 * @return void
1334
+	 * @throws EE_Error
1335
+	 * @throws ReflectionException
1336
+	 */
1337
+	public function set_uses($uses)
1338
+	{
1339
+		$this->set('TKT_uses', $uses);
1340
+	}
1341
+
1342
+
1343
+	/**
1344
+	 * returns whether ticket is required or not.
1345
+	 *
1346
+	 * @return boolean
1347
+	 * @throws EE_Error
1348
+	 * @throws ReflectionException
1349
+	 */
1350
+	public function required()
1351
+	{
1352
+		return $this->get('TKT_required');
1353
+	}
1354
+
1355
+
1356
+	/**
1357
+	 * sets the TKT_required property
1358
+	 *
1359
+	 * @param boolean $required
1360
+	 * @return void
1361
+	 * @throws EE_Error
1362
+	 * @throws ReflectionException
1363
+	 */
1364
+	public function set_required($required)
1365
+	{
1366
+		$this->set('TKT_required', $required);
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * Gets taxable
1372
+	 *
1373
+	 * @return boolean
1374
+	 * @throws EE_Error
1375
+	 * @throws ReflectionException
1376
+	 */
1377
+	public function taxable()
1378
+	{
1379
+		return $this->get('TKT_taxable');
1380
+	}
1381
+
1382
+
1383
+	/**
1384
+	 * Sets taxable
1385
+	 *
1386
+	 * @param boolean $taxable
1387
+	 * @return void
1388
+	 * @throws EE_Error
1389
+	 * @throws ReflectionException
1390
+	 */
1391
+	public function set_taxable($taxable)
1392
+	{
1393
+		$this->set('TKT_taxable', $taxable);
1394
+	}
1395
+
1396
+
1397
+	/**
1398
+	 * Gets is_default
1399
+	 *
1400
+	 * @return boolean
1401
+	 * @throws EE_Error
1402
+	 * @throws ReflectionException
1403
+	 */
1404
+	public function is_default()
1405
+	{
1406
+		return $this->get('TKT_is_default');
1407
+	}
1408
+
1409
+
1410
+	/**
1411
+	 * Sets is_default
1412
+	 *
1413
+	 * @param boolean $is_default
1414
+	 * @return void
1415
+	 * @throws EE_Error
1416
+	 * @throws ReflectionException
1417
+	 */
1418
+	public function set_is_default($is_default)
1419
+	{
1420
+		$this->set('TKT_is_default', $is_default);
1421
+	}
1422
+
1423
+
1424
+	/**
1425
+	 * Gets order
1426
+	 *
1427
+	 * @return int
1428
+	 * @throws EE_Error
1429
+	 * @throws ReflectionException
1430
+	 */
1431
+	public function order()
1432
+	{
1433
+		return $this->get('TKT_order');
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * Sets order
1439
+	 *
1440
+	 * @param int $order
1441
+	 * @return void
1442
+	 * @throws EE_Error
1443
+	 * @throws ReflectionException
1444
+	 */
1445
+	public function set_order($order)
1446
+	{
1447
+		$this->set('TKT_order', $order);
1448
+	}
1449
+
1450
+
1451
+	/**
1452
+	 * Gets row
1453
+	 *
1454
+	 * @return int
1455
+	 * @throws EE_Error
1456
+	 * @throws ReflectionException
1457
+	 */
1458
+	public function row()
1459
+	{
1460
+		return $this->get('TKT_row');
1461
+	}
1462
+
1463
+
1464
+	/**
1465
+	 * Sets row
1466
+	 *
1467
+	 * @param int $row
1468
+	 * @return void
1469
+	 * @throws EE_Error
1470
+	 * @throws ReflectionException
1471
+	 */
1472
+	public function set_row($row)
1473
+	{
1474
+		$this->set('TKT_row', $row);
1475
+	}
1476
+
1477
+
1478
+	/**
1479
+	 * Gets deleted
1480
+	 *
1481
+	 * @return boolean
1482
+	 * @throws EE_Error
1483
+	 * @throws ReflectionException
1484
+	 */
1485
+	public function deleted()
1486
+	{
1487
+		return $this->get('TKT_deleted');
1488
+	}
1489
+
1490
+
1491
+	/**
1492
+	 * Sets deleted
1493
+	 *
1494
+	 * @param boolean $deleted
1495
+	 * @return void
1496
+	 * @throws EE_Error
1497
+	 * @throws ReflectionException
1498
+	 */
1499
+	public function set_deleted($deleted)
1500
+	{
1501
+		$this->set('TKT_deleted', $deleted);
1502
+	}
1503
+
1504
+
1505
+	/**
1506
+	 * Gets parent
1507
+	 *
1508
+	 * @return int
1509
+	 * @throws EE_Error
1510
+	 * @throws ReflectionException
1511
+	 */
1512
+	public function parent_ID()
1513
+	{
1514
+		return $this->get('TKT_parent');
1515
+	}
1516
+
1517
+
1518
+	/**
1519
+	 * Sets parent
1520
+	 *
1521
+	 * @param int $parent
1522
+	 * @return void
1523
+	 * @throws EE_Error
1524
+	 * @throws ReflectionException
1525
+	 */
1526
+	public function set_parent_ID($parent)
1527
+	{
1528
+		$this->set('TKT_parent', $parent);
1529
+	}
1530
+
1531
+
1532
+	/**
1533
+	 * @return boolean
1534
+	 * @throws EE_Error
1535
+	 * @throws InvalidArgumentException
1536
+	 * @throws InvalidDataTypeException
1537
+	 * @throws InvalidInterfaceException
1538
+	 * @throws ReflectionException
1539
+	 */
1540
+	public function reverse_calculate()
1541
+	{
1542
+		return $this->get('TKT_reverse_calculate');
1543
+	}
1544
+
1545
+
1546
+	/**
1547
+	 * @param boolean $reverse_calculate
1548
+	 * @throws EE_Error
1549
+	 * @throws InvalidArgumentException
1550
+	 * @throws InvalidDataTypeException
1551
+	 * @throws InvalidInterfaceException
1552
+	 * @throws ReflectionException
1553
+	 */
1554
+	public function set_reverse_calculate($reverse_calculate)
1555
+	{
1556
+		$this->set('TKT_reverse_calculate', $reverse_calculate);
1557
+	}
1558
+
1559
+
1560
+	/**
1561
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1562
+	 *
1563
+	 * @return string
1564
+	 * @throws EE_Error
1565
+	 * @throws ReflectionException
1566
+	 */
1567
+	public function name_and_info()
1568
+	{
1569
+		$times = [];
1570
+		foreach ($this->datetimes() as $datetime) {
1571
+			$times[] = $datetime->start_date_and_time();
1572
+		}
1573
+		/* translators: %1$s ticket name, %2$s start datetimes separated by comma, %3$s ticket price */
1574
+		return sprintf(
1575
+			esc_html__('%1$s @ %2$s for %3$s', 'event_espresso'),
1576
+			$this->name(),
1577
+			implode(', ', $times),
1578
+			$this->pretty_price()
1579
+		);
1580
+	}
1581
+
1582
+
1583
+	/**
1584
+	 * Gets name
1585
+	 *
1586
+	 * @return string
1587
+	 * @throws EE_Error
1588
+	 * @throws ReflectionException
1589
+	 */
1590
+	public function name()
1591
+	{
1592
+		return $this->get('TKT_name');
1593
+	}
1594
+
1595
+
1596
+	/**
1597
+	 * Gets price
1598
+	 *
1599
+	 * @return float
1600
+	 * @throws EE_Error
1601
+	 * @throws ReflectionException
1602
+	 */
1603
+	public function price()
1604
+	{
1605
+		return $this->get('TKT_price');
1606
+	}
1607
+
1608
+
1609
+	/**
1610
+	 * Gets all the registrations for this ticket
1611
+	 *
1612
+	 * @param array $query_params
1613
+	 * @return EE_Registration[]|EE_Base_Class[]
1614
+	 * @throws EE_Error
1615
+	 * @throws ReflectionException
1616
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1617
+	 */
1618
+	public function registrations($query_params = [])
1619
+	{
1620
+		return $this->get_many_related('Registration', $query_params);
1621
+	}
1622
+
1623
+
1624
+	/**
1625
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1626
+	 *
1627
+	 * @return int
1628
+	 * @throws EE_Error
1629
+	 * @throws ReflectionException
1630
+	 */
1631
+	public function update_tickets_sold()
1632
+	{
1633
+		$count_regs_for_this_ticket = $this->count_registrations(
1634
+			[
1635
+				[
1636
+					'STS_ID'      => EEM_Registration::status_id_approved,
1637
+					'REG_deleted' => 0,
1638
+				],
1639
+			]
1640
+		);
1641
+		$this->set_sold($count_regs_for_this_ticket);
1642
+		$this->save();
1643
+		return $count_regs_for_this_ticket;
1644
+	}
1645
+
1646
+
1647
+	/**
1648
+	 * Counts the registrations for this ticket
1649
+	 *
1650
+	 * @param array $query_params
1651
+	 * @return int
1652
+	 * @throws EE_Error
1653
+	 * @throws ReflectionException
1654
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1655
+	 */
1656
+	public function count_registrations($query_params = [])
1657
+	{
1658
+		return $this->count_related('Registration', $query_params);
1659
+	}
1660
+
1661
+
1662
+	/**
1663
+	 * Implementation for EEI_Has_Icon interface method.
1664
+	 *
1665
+	 * @return string
1666
+	 * @see EEI_Visual_Representation for comments
1667
+	 */
1668
+	public function get_icon()
1669
+	{
1670
+		return '<span class="dashicons dashicons-tickets-alt"></span>';
1671
+	}
1672
+
1673
+
1674
+	/**
1675
+	 * Implementation of the EEI_Event_Relation interface method
1676
+	 *
1677
+	 * @return EE_Event
1678
+	 * @throws EE_Error
1679
+	 * @throws UnexpectedEntityException
1680
+	 * @throws ReflectionException
1681
+	 * @see EEI_Event_Relation for comments
1682
+	 */
1683
+	public function get_related_event()
1684
+	{
1685
+		// get one datetime to use for getting the event
1686
+		$datetime = $this->first_datetime();
1687
+		if (! $datetime instanceof EE_Datetime) {
1688
+			throw new UnexpectedEntityException(
1689
+				$datetime,
1690
+				'EE_Datetime',
1691
+				sprintf(
1692
+					esc_html__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1693
+					$this->name()
1694
+				)
1695
+			);
1696
+		}
1697
+		$event = $datetime->event();
1698
+		if (! $event instanceof EE_Event) {
1699
+			throw new UnexpectedEntityException(
1700
+				$event,
1701
+				'EE_Event',
1702
+				sprintf(
1703
+					esc_html__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1704
+					$this->name()
1705
+				)
1706
+			);
1707
+		}
1708
+		return $event;
1709
+	}
1710
+
1711
+
1712
+	/**
1713
+	 * Implementation of the EEI_Event_Relation interface method
1714
+	 *
1715
+	 * @return string
1716
+	 * @throws UnexpectedEntityException
1717
+	 * @throws EE_Error
1718
+	 * @throws ReflectionException
1719
+	 * @see EEI_Event_Relation for comments
1720
+	 */
1721
+	public function get_event_name()
1722
+	{
1723
+		$event = $this->get_related_event();
1724
+		return $event instanceof EE_Event ? $event->name() : '';
1725
+	}
1726
+
1727
+
1728
+	/**
1729
+	 * Implementation of the EEI_Event_Relation interface method
1730
+	 *
1731
+	 * @return int
1732
+	 * @throws UnexpectedEntityException
1733
+	 * @throws EE_Error
1734
+	 * @throws ReflectionException
1735
+	 * @see EEI_Event_Relation for comments
1736
+	 */
1737
+	public function get_event_ID()
1738
+	{
1739
+		$event = $this->get_related_event();
1740
+		return $event instanceof EE_Event ? $event->ID() : 0;
1741
+	}
1742
+
1743
+
1744
+	/**
1745
+	 * This simply returns whether a ticket can be permanently deleted or not.
1746
+	 * The criteria for determining this is whether the ticket has any related registrations.
1747
+	 * If there are none then it can be permanently deleted.
1748
+	 *
1749
+	 * @return bool
1750
+	 * @throws EE_Error
1751
+	 * @throws ReflectionException
1752
+	 */
1753
+	public function is_permanently_deleteable()
1754
+	{
1755
+		return $this->count_registrations() === 0;
1756
+	}
1757
+
1758
+
1759
+	/**
1760
+	 * @return int
1761
+	 * @throws EE_Error
1762
+	 * @throws ReflectionException
1763
+	 * @since   5.0.0.p
1764
+	 */
1765
+	public function visibility(): int
1766
+	{
1767
+		return $this->get('TKT_visibility');
1768
+	}
1769
+
1770
+
1771
+	/**
1772
+	 * @return bool
1773
+	 * @throws EE_Error
1774
+	 * @throws ReflectionException
1775
+	 * @since   5.0.0.p
1776
+	 */
1777
+	public function isHidden(): bool
1778
+	{
1779
+		return $this->visibility() === EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE;
1780
+	}
1781
+
1782
+
1783
+	/**
1784
+	 * @return bool
1785
+	 * @throws EE_Error
1786
+	 * @throws ReflectionException
1787
+	 * @since   5.0.0.p
1788
+	 */
1789
+	public function isNotHidden(): bool
1790
+	{
1791
+		return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE;
1792
+	}
1793
+
1794
+
1795
+	/**
1796
+	 * @return bool
1797
+	 * @throws EE_Error
1798
+	 * @throws ReflectionException
1799
+	 * @since   5.0.0.p
1800
+	 */
1801
+	public function isPublicOnly(): bool
1802
+	{
1803
+		return $this->isNotHidden() && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE;
1804
+	}
1805
+
1806
+
1807
+	/**
1808
+	 * @return bool
1809
+	 * @throws EE_Error
1810
+	 * @throws ReflectionException
1811
+	 * @since   5.0.0.p
1812
+	 */
1813
+	public function isMembersOnly(): bool
1814
+	{
1815
+		return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_PUBLIC_VALUE
1816
+			   && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE;
1817
+	}
1818
+
1819
+
1820
+	/**
1821
+	 * @return bool
1822
+	 * @throws EE_Error
1823
+	 * @throws ReflectionException
1824
+	 * @since   5.0.0.p
1825
+	 */
1826
+	public function isAdminsOnly(): bool
1827
+	{
1828
+		return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_MEMBERS_ONLY_VALUE
1829
+			   && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE;
1830
+	}
1831
+
1832
+
1833
+	/**
1834
+	 * @return bool
1835
+	 * @throws EE_Error
1836
+	 * @throws ReflectionException
1837
+	 * @since   5.0.0.p
1838
+	 */
1839
+	public function isAdminUiOnly(): bool
1840
+	{
1841
+		return $this->visibility() > EEM_Ticket::TICKET_VISIBILITY_ADMINS_ONLY_VALUE
1842
+			   && $this->visibility() <= EEM_Ticket::TICKET_VISIBILITY_ADMIN_UI_ONLY_VALUE;
1843
+	}
1844
+
1845
+
1846
+	/**
1847
+	 * @param int $visibility
1848
+	 * @throws EE_Error
1849
+	 * @throws ReflectionException
1850
+	 * @since   5.0.0.p
1851
+	 */
1852
+	public function set_visibility(int $visibility)
1853
+	{
1854
+		$ticket_visibility_options = $this->_model->ticketVisibilityOptions();
1855
+		$ticket_visibility         = -1;
1856
+		foreach ($ticket_visibility_options as $ticket_visibility_option) {
1857
+			if ($visibility === $ticket_visibility_option) {
1858
+				$ticket_visibility = $visibility;
1859
+			}
1860
+		}
1861
+		if ($ticket_visibility === -1) {
1862
+			throw new DomainException(
1863
+				sprintf(
1864
+					esc_html__(
1865
+						'The supplied ticket visibility setting of "%1$s" is not valid. It needs to match one of the keys in the following array:%2$s %3$s ',
1866
+						'event_espresso'
1867
+					),
1868
+					$visibility,
1869
+					'<br />',
1870
+					var_export($ticket_visibility_options, true)
1871
+				)
1872
+			);
1873
+		}
1874
+		$this->set('TKT_visibility', $ticket_visibility);
1875
+	}
1876
+
1877
+
1878
+	/**
1879
+	 * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1880
+	 * @param string                   $relationName
1881
+	 * @param array                    $extra_join_model_fields_n_values
1882
+	 * @param string|null              $cache_id
1883
+	 * @return EE_Base_Class
1884
+	 * @throws EE_Error
1885
+	 * @throws ReflectionException
1886
+	 * @since   5.0.0.p
1887
+	 */
1888
+	public function _add_relation_to(
1889
+		$otherObjectModelObjectOrID,
1890
+		$relationName,
1891
+		$extra_join_model_fields_n_values = [],
1892
+		$cache_id = null
1893
+	) {
1894
+		if ($relationName === 'Datetime' && ! $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1895
+			/** @var EE_Datetime $datetime */
1896
+			$datetime = EEM_Datetime::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1897
+			$datetime->increaseSold($this->sold(), false);
1898
+			$datetime->increaseReserved($this->reserved());
1899
+			$datetime->save();
1900
+			$otherObjectModelObjectOrID = $datetime;
1901
+		}
1902
+		return parent::_add_relation_to(
1903
+			$otherObjectModelObjectOrID,
1904
+			$relationName,
1905
+			$extra_join_model_fields_n_values,
1906
+			$cache_id
1907
+		);
1908
+	}
1909
+
1910
+
1911
+	/**
1912
+	 * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1913
+	 * @param string                   $relationName
1914
+	 * @param array                    $where_query
1915
+	 * @return bool|EE_Base_Class|null
1916
+	 * @throws EE_Error
1917
+	 * @throws ReflectionException
1918
+	 * @since   5.0.0.p
1919
+	 */
1920
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = [])
1921
+	{
1922
+		// if we're adding a new relation to a datetime
1923
+		if ($relationName === 'Datetime' && $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1924
+			/** @var EE_Datetime $datetime */
1925
+			$datetime = EEM_Datetime::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1926
+			$datetime->decreaseSold($this->sold());
1927
+			$datetime->decreaseReserved($this->reserved());
1928
+			$datetime->save();
1929
+			$otherObjectModelObjectOrID = $datetime;
1930
+		}
1931
+		return parent::_remove_relation_to(
1932
+			$otherObjectModelObjectOrID,
1933
+			$relationName,
1934
+			$where_query
1935
+		);
1936
+	}
1937
+
1938
+
1939
+	/**
1940
+	 * Removes ALL the related things for the $relationName.
1941
+	 *
1942
+	 * @param string $relationName
1943
+	 * @param array  $where_query_params
1944
+	 * @return EE_Base_Class
1945
+	 * @throws ReflectionException
1946
+	 * @throws InvalidArgumentException
1947
+	 * @throws InvalidInterfaceException
1948
+	 * @throws InvalidDataTypeException
1949
+	 * @throws EE_Error
1950
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
1951
+	 */
1952
+	public function _remove_relations($relationName, $where_query_params = [])
1953
+	{
1954
+		if ($relationName === 'Datetime') {
1955
+			$datetimes = $this->datetimes();
1956
+			foreach ($datetimes as $datetime) {
1957
+				$datetime->decreaseSold($this->sold());
1958
+				$datetime->decreaseReserved($this->reserved());
1959
+				$datetime->save();
1960
+			}
1961
+		}
1962
+		return parent::_remove_relations($relationName, $where_query_params);
1963
+	}
1964
+
1965
+
1966
+	/*******************************************************************
1967 1967
      ***********************  DEPRECATED METHODS  **********************
1968 1968
      *******************************************************************/
1969 1969
 
1970 1970
 
1971
-    /**
1972
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1973
-     * associated datetimes.
1974
-     *
1975
-     * @param int $qty
1976
-     * @return void
1977
-     * @throws EE_Error
1978
-     * @throws InvalidArgumentException
1979
-     * @throws InvalidDataTypeException
1980
-     * @throws InvalidInterfaceException
1981
-     * @throws ReflectionException
1982
-     * @deprecated 4.9.80.p
1983
-     */
1984
-    public function increase_sold($qty = 1)
1985
-    {
1986
-        EE_Error::doing_it_wrong(
1987
-            __FUNCTION__,
1988
-            esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1989
-            '4.9.80.p',
1990
-            '5.0.0.p'
1991
-        );
1992
-        $this->increaseSold($qty);
1993
-    }
1994
-
1995
-
1996
-    /**
1997
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1998
-     *
1999
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
2000
-     *                 Negative means to decreases old counts (and increase reserved counts).
2001
-     * @throws EE_Error
2002
-     * @throws InvalidArgumentException
2003
-     * @throws InvalidDataTypeException
2004
-     * @throws InvalidInterfaceException
2005
-     * @throws ReflectionException
2006
-     * @deprecated 4.9.80.p
2007
-     */
2008
-    protected function _increase_sold_for_datetimes($qty)
2009
-    {
2010
-        EE_Error::doing_it_wrong(
2011
-            __FUNCTION__,
2012
-            esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
2013
-            '4.9.80.p',
2014
-            '5.0.0.p'
2015
-        );
2016
-        $this->increaseSoldForDatetimes($qty);
2017
-    }
2018
-
2019
-
2020
-    /**
2021
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
2022
-     * DB and then updates the model objects.
2023
-     * Does not affect the reserved counts.
2024
-     *
2025
-     * @param int $qty
2026
-     * @return void
2027
-     * @throws EE_Error
2028
-     * @throws InvalidArgumentException
2029
-     * @throws InvalidDataTypeException
2030
-     * @throws InvalidInterfaceException
2031
-     * @throws ReflectionException
2032
-     * @deprecated 4.9.80.p
2033
-     */
2034
-    public function decrease_sold($qty = 1)
2035
-    {
2036
-        EE_Error::doing_it_wrong(
2037
-            __FUNCTION__,
2038
-            esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
2039
-            '4.9.80.p',
2040
-            '5.0.0.p'
2041
-        );
2042
-        $this->decreaseSold($qty);
2043
-    }
2044
-
2045
-
2046
-    /**
2047
-     * Decreases sold on related datetimes
2048
-     *
2049
-     * @param int $qty
2050
-     * @return void
2051
-     * @throws EE_Error
2052
-     * @throws InvalidArgumentException
2053
-     * @throws InvalidDataTypeException
2054
-     * @throws InvalidInterfaceException
2055
-     * @throws ReflectionException
2056
-     * @deprecated 4.9.80.p
2057
-     */
2058
-    protected function _decrease_sold_for_datetimes($qty = 1)
2059
-    {
2060
-        EE_Error::doing_it_wrong(
2061
-            __FUNCTION__,
2062
-            esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
2063
-            '4.9.80.p',
2064
-            '5.0.0.p'
2065
-        );
2066
-        $this->decreaseSoldForDatetimes($qty);
2067
-    }
2068
-
2069
-
2070
-    /**
2071
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
2072
-     *
2073
-     * @param int    $qty
2074
-     * @param string $source
2075
-     * @return bool whether we successfully reserved the ticket or not.
2076
-     * @throws EE_Error
2077
-     * @throws InvalidArgumentException
2078
-     * @throws ReflectionException
2079
-     * @throws InvalidDataTypeException
2080
-     * @throws InvalidInterfaceException
2081
-     * @deprecated 4.9.80.p
2082
-     */
2083
-    public function increase_reserved($qty = 1, $source = 'unknown')
2084
-    {
2085
-        EE_Error::doing_it_wrong(
2086
-            __FUNCTION__,
2087
-            esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
2088
-            '4.9.80.p',
2089
-            '5.0.0.p'
2090
-        );
2091
-        return $this->increaseReserved($qty);
2092
-    }
2093
-
2094
-
2095
-    /**
2096
-     * Increases sold on related datetimes
2097
-     *
2098
-     * @param int $qty
2099
-     * @return boolean indicating success
2100
-     * @throws EE_Error
2101
-     * @throws InvalidArgumentException
2102
-     * @throws InvalidDataTypeException
2103
-     * @throws InvalidInterfaceException
2104
-     * @throws ReflectionException
2105
-     * @deprecated 4.9.80.p
2106
-     */
2107
-    protected function _increase_reserved_for_datetimes($qty = 1)
2108
-    {
2109
-        EE_Error::doing_it_wrong(
2110
-            __FUNCTION__,
2111
-            esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
2112
-            '4.9.80.p',
2113
-            '5.0.0.p'
2114
-        );
2115
-        return $this->increaseReservedForDatetimes($qty);
2116
-    }
2117
-
2118
-
2119
-    /**
2120
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
2121
-     *
2122
-     * @param int    $qty
2123
-     * @param bool   $adjust_datetimes
2124
-     * @param string $source
2125
-     * @return void
2126
-     * @throws EE_Error
2127
-     * @throws InvalidArgumentException
2128
-     * @throws ReflectionException
2129
-     * @throws InvalidDataTypeException
2130
-     * @throws InvalidInterfaceException
2131
-     * @deprecated 4.9.80.p
2132
-     */
2133
-    public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
2134
-    {
2135
-        EE_Error::doing_it_wrong(
2136
-            __FUNCTION__,
2137
-            esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
2138
-            '4.9.80.p',
2139
-            '5.0.0.p'
2140
-        );
2141
-        $this->decreaseReserved($qty);
2142
-    }
2143
-
2144
-
2145
-    /**
2146
-     * Decreases reserved on related datetimes
2147
-     *
2148
-     * @param int $qty
2149
-     * @return void
2150
-     * @throws EE_Error
2151
-     * @throws InvalidArgumentException
2152
-     * @throws ReflectionException
2153
-     * @throws InvalidDataTypeException
2154
-     * @throws InvalidInterfaceException
2155
-     * @deprecated 4.9.80.p
2156
-     */
2157
-    protected function _decrease_reserved_for_datetimes($qty = 1)
2158
-    {
2159
-        EE_Error::doing_it_wrong(
2160
-            __FUNCTION__,
2161
-            esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
2162
-            '4.9.80.p',
2163
-            '5.0.0.p'
2164
-        );
2165
-        $this->decreaseReservedForDatetimes($qty);
2166
-    }
1971
+	/**
1972
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1973
+	 * associated datetimes.
1974
+	 *
1975
+	 * @param int $qty
1976
+	 * @return void
1977
+	 * @throws EE_Error
1978
+	 * @throws InvalidArgumentException
1979
+	 * @throws InvalidDataTypeException
1980
+	 * @throws InvalidInterfaceException
1981
+	 * @throws ReflectionException
1982
+	 * @deprecated 4.9.80.p
1983
+	 */
1984
+	public function increase_sold($qty = 1)
1985
+	{
1986
+		EE_Error::doing_it_wrong(
1987
+			__FUNCTION__,
1988
+			esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1989
+			'4.9.80.p',
1990
+			'5.0.0.p'
1991
+		);
1992
+		$this->increaseSold($qty);
1993
+	}
1994
+
1995
+
1996
+	/**
1997
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1998
+	 *
1999
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
2000
+	 *                 Negative means to decreases old counts (and increase reserved counts).
2001
+	 * @throws EE_Error
2002
+	 * @throws InvalidArgumentException
2003
+	 * @throws InvalidDataTypeException
2004
+	 * @throws InvalidInterfaceException
2005
+	 * @throws ReflectionException
2006
+	 * @deprecated 4.9.80.p
2007
+	 */
2008
+	protected function _increase_sold_for_datetimes($qty)
2009
+	{
2010
+		EE_Error::doing_it_wrong(
2011
+			__FUNCTION__,
2012
+			esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
2013
+			'4.9.80.p',
2014
+			'5.0.0.p'
2015
+		);
2016
+		$this->increaseSoldForDatetimes($qty);
2017
+	}
2018
+
2019
+
2020
+	/**
2021
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
2022
+	 * DB and then updates the model objects.
2023
+	 * Does not affect the reserved counts.
2024
+	 *
2025
+	 * @param int $qty
2026
+	 * @return void
2027
+	 * @throws EE_Error
2028
+	 * @throws InvalidArgumentException
2029
+	 * @throws InvalidDataTypeException
2030
+	 * @throws InvalidInterfaceException
2031
+	 * @throws ReflectionException
2032
+	 * @deprecated 4.9.80.p
2033
+	 */
2034
+	public function decrease_sold($qty = 1)
2035
+	{
2036
+		EE_Error::doing_it_wrong(
2037
+			__FUNCTION__,
2038
+			esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
2039
+			'4.9.80.p',
2040
+			'5.0.0.p'
2041
+		);
2042
+		$this->decreaseSold($qty);
2043
+	}
2044
+
2045
+
2046
+	/**
2047
+	 * Decreases sold on related datetimes
2048
+	 *
2049
+	 * @param int $qty
2050
+	 * @return void
2051
+	 * @throws EE_Error
2052
+	 * @throws InvalidArgumentException
2053
+	 * @throws InvalidDataTypeException
2054
+	 * @throws InvalidInterfaceException
2055
+	 * @throws ReflectionException
2056
+	 * @deprecated 4.9.80.p
2057
+	 */
2058
+	protected function _decrease_sold_for_datetimes($qty = 1)
2059
+	{
2060
+		EE_Error::doing_it_wrong(
2061
+			__FUNCTION__,
2062
+			esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
2063
+			'4.9.80.p',
2064
+			'5.0.0.p'
2065
+		);
2066
+		$this->decreaseSoldForDatetimes($qty);
2067
+	}
2068
+
2069
+
2070
+	/**
2071
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
2072
+	 *
2073
+	 * @param int    $qty
2074
+	 * @param string $source
2075
+	 * @return bool whether we successfully reserved the ticket or not.
2076
+	 * @throws EE_Error
2077
+	 * @throws InvalidArgumentException
2078
+	 * @throws ReflectionException
2079
+	 * @throws InvalidDataTypeException
2080
+	 * @throws InvalidInterfaceException
2081
+	 * @deprecated 4.9.80.p
2082
+	 */
2083
+	public function increase_reserved($qty = 1, $source = 'unknown')
2084
+	{
2085
+		EE_Error::doing_it_wrong(
2086
+			__FUNCTION__,
2087
+			esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
2088
+			'4.9.80.p',
2089
+			'5.0.0.p'
2090
+		);
2091
+		return $this->increaseReserved($qty);
2092
+	}
2093
+
2094
+
2095
+	/**
2096
+	 * Increases sold on related datetimes
2097
+	 *
2098
+	 * @param int $qty
2099
+	 * @return boolean indicating success
2100
+	 * @throws EE_Error
2101
+	 * @throws InvalidArgumentException
2102
+	 * @throws InvalidDataTypeException
2103
+	 * @throws InvalidInterfaceException
2104
+	 * @throws ReflectionException
2105
+	 * @deprecated 4.9.80.p
2106
+	 */
2107
+	protected function _increase_reserved_for_datetimes($qty = 1)
2108
+	{
2109
+		EE_Error::doing_it_wrong(
2110
+			__FUNCTION__,
2111
+			esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
2112
+			'4.9.80.p',
2113
+			'5.0.0.p'
2114
+		);
2115
+		return $this->increaseReservedForDatetimes($qty);
2116
+	}
2117
+
2118
+
2119
+	/**
2120
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
2121
+	 *
2122
+	 * @param int    $qty
2123
+	 * @param bool   $adjust_datetimes
2124
+	 * @param string $source
2125
+	 * @return void
2126
+	 * @throws EE_Error
2127
+	 * @throws InvalidArgumentException
2128
+	 * @throws ReflectionException
2129
+	 * @throws InvalidDataTypeException
2130
+	 * @throws InvalidInterfaceException
2131
+	 * @deprecated 4.9.80.p
2132
+	 */
2133
+	public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
2134
+	{
2135
+		EE_Error::doing_it_wrong(
2136
+			__FUNCTION__,
2137
+			esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
2138
+			'4.9.80.p',
2139
+			'5.0.0.p'
2140
+		);
2141
+		$this->decreaseReserved($qty);
2142
+	}
2143
+
2144
+
2145
+	/**
2146
+	 * Decreases reserved on related datetimes
2147
+	 *
2148
+	 * @param int $qty
2149
+	 * @return void
2150
+	 * @throws EE_Error
2151
+	 * @throws InvalidArgumentException
2152
+	 * @throws ReflectionException
2153
+	 * @throws InvalidDataTypeException
2154
+	 * @throws InvalidInterfaceException
2155
+	 * @deprecated 4.9.80.p
2156
+	 */
2157
+	protected function _decrease_reserved_for_datetimes($qty = 1)
2158
+	{
2159
+		EE_Error::doing_it_wrong(
2160
+			__FUNCTION__,
2161
+			esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
2162
+			'4.9.80.p',
2163
+			'5.0.0.p'
2164
+		);
2165
+		$this->decreaseReservedForDatetimes($qty);
2166
+	}
2167 2167
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Question_Form_Input.class.php 2 patches
Indentation   +376 added lines, -376 removed lines patch added patch discarded remove patch
@@ -15,380 +15,380 @@
 block discarded – undo
15 15
  */
16 16
 class EE_Question_Form_Input
17 17
 {
18
-    protected RequestInterface $request;
19
-
20
-    protected array $form_data;
21
-
22
-    private ?EE_Question $_QST = null;
23
-
24
-
25
-    private ?EE_Answer $_ANS = null;
26
-
27
-    /**
28
-     * $_QST_meta
29
-     * @var array
30
-     */
31
-    private array $_QST_meta = [];
32
-
33
-    /**
34
-     * $QST_input_name
35
-     * @var string
36
-     */
37
-    private string $QST_input_name = '';
38
-
39
-    /**
40
-     * $QST_input_id
41
-     * @var string
42
-     */
43
-    private string $QST_input_id = '';
44
-
45
-    /**
46
-     * $QST_input_class
47
-     * @var string
48
-     */
49
-    private string $QST_input_class = '';
50
-
51
-    private bool $QST_disabled = false;
52
-
53
-
54
-    /**
55
-     * @param EE_Question|null $QST EE_Question object
56
-     * @param EE_Answer|null   $ANS EE_Answer object
57
-     * @param array            $q_meta
58
-     * @throws EE_Error
59
-     * @throws ReflectionException
60
-     */
61
-    public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, array $q_meta = [])
62
-    {
63
-        $this->request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
64
-        $this->form_data = $this->request->requestParams();
65
-        if (empty($QST) || empty($ANS)) {
66
-            EE_Error::add_error(
67
-                esc_html__(
68
-                    'An error occurred. A valid EE_Question or EE_Answer object was not received.',
69
-                    'event_espresso'
70
-                ),
71
-                __FILE__,
72
-                __FUNCTION__,
73
-                __LINE__
74
-            );
75
-            return null;
76
-        }
77
-        $this->_QST = $QST;
78
-        $this->_ANS = $ANS;
79
-        $this->set_question_form_input_meta($q_meta);
80
-        $this->set_question_form_input_init();
81
-    }
82
-
83
-
84
-    /**
85
-     * sets meta data for the question form input
86
-     *
87
-     * @param array $q_meta
88
-     * @return void
89
-     */
90
-    public function set_question_form_input_meta(array $q_meta = [])
91
-    {
92
-        $default_q_meta  = [
93
-            'att_nmbr'       => 1,
94
-            'ticket_id'      => '',
95
-            'date'           => '',
96
-            'time'           => '',
97
-            'input_name'     => '',
98
-            'input_id'       => '',
99
-            'input_class'    => '',
100
-            'label_class'    => '',
101
-            'input_prefix'   => 'qstn',
102
-            'append_qstn_id' => true,
103
-            'htmlentities'   => true,
104
-            'allow_null'     => false,
105
-        ];
106
-        $this->_QST_meta = array_merge($default_q_meta, $q_meta);
107
-    }
108
-
109
-
110
-    /**
111
-     * @return void
112
-     * @throws EE_Error
113
-     * @throws ReflectionException
114
-     */
115
-    public function set_question_form_input_init()
116
-    {
117
-        $qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID();
118
-        $this->_set_input_name($qstn_id);
119
-        $this->_set_input_id($qstn_id);
120
-        $this->_set_input_class();
121
-        $this->set_question_form_input_answer($qstn_id);
122
-    }
123
-
124
-
125
-    /**
126
-     * @param $qstn_id
127
-     * @return void
128
-     * @throws EE_Error
129
-     * @throws ReflectionException
130
-     */
131
-    private function _set_input_name($qstn_id)
132
-    {
133
-        if (! empty($qstn_id)) {
134
-            $ANS_ID  = $this->get('ANS_ID');
135
-            $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
136
-        }
137
-        $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
138
-            ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
139
-            : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
140
-    }
141
-
142
-
143
-    /**
144
-     * get property values for question form input
145
-     *
146
-     * @param string $property
147
-     * @return mixed
148
-     * @throws EE_Error
149
-     * @throws ReflectionException
150
-     */
151
-    public function get(string $property = '')
152
-    {
153
-        if (empty($property)) {
154
-            return null;
155
-        }
156
-        if (EEM_Question::instance()->has_field($property)) {
157
-            return $this->_QST->get($property);
158
-        }
159
-        if (EEM_Answer::instance()->has_field($property)) {
160
-            return $this->_ANS->get($property);
161
-        }
162
-        if (property_exists($this, $property)) {
163
-            return $this->{$property};
164
-        }
165
-        return null;
166
-    }
167
-
168
-
169
-    /**
170
-     * set property values for question form input
171
-     *
172
-     * @param string $property
173
-     * @param mixed  $value
174
-     * @return void
175
-     * @throws EE_Error
176
-     * @throws ReflectionException
177
-     */
178
-    public function set(string $property = '', $value = null)
179
-    {
180
-        if (empty($property)) {
181
-            return;
182
-        }
183
-        if (EEM_Question::instance()->has_field($property)) {
184
-            $this->_QST->set($property, $value);
185
-        }
186
-        if (EEM_Answer::instance()->has_field($property)) {
187
-            $this->_ANS->set($property, $value);
188
-        }
189
-        if (property_exists($this, $property)) {
190
-            $this->{$property} = $value;
191
-        }
192
-    }
193
-
194
-
195
-    /**
196
-     * @param $qstn_id
197
-     * @return void
198
-     * @throws EE_Error
199
-     * @throws ReflectionException
200
-     */
201
-    private function _set_input_id($qstn_id)
202
-    {
203
-        $input_id           = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id'])
204
-            ? $this->_QST_meta['input_id']
205
-            : sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
206
-        $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
207
-            ? $input_id . '-' . $qstn_id
208
-            : $input_id;
209
-    }
210
-
211
-
212
-    /**
213
-     * @return void
214
-     */
215
-    private function _set_input_class()
216
-    {
217
-        $this->QST_input_class = $this->_QST_meta['input_class'] ?? '';
218
-    }
219
-
220
-
221
-    /**
222
-     * @param int|string $qstn_id
223
-     * @return void
224
-     * @throws EE_Error
225
-     * @throws ReflectionException
226
-     */
227
-    public function set_question_form_input_answer($qstn_id)
228
-    {
229
-        // check for answer in $this->form_data in case we are reprocessing a form after an error
230
-        if (
231
-            isset($this->_QST_meta['EVT_ID'])
232
-            && isset($this->_QST_meta['att_nmbr'])
233
-            && isset($this->_QST_meta['date'])
234
-            && isset($this->_QST_meta['time'])
235
-            && isset($this->_QST_meta['price_id'])
236
-        ) {
237
-            $EVT_ID   = $this->_QST_meta['EVT_ID'];
238
-            $att_nmbr = $this->_QST_meta['att_nmbr'];
239
-            $date     = $this->_QST_meta['date'];
240
-            $time     = $this->_QST_meta['time'];
241
-            $price_id = $this->_QST_meta['price_id'];
242
-            if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
243
-                $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
244
-                $this->_ANS->set('ANS_value', $answer);
245
-            }
246
-        }
247
-    }
248
-
249
-
250
-    /**
251
-     * @param EE_Base_class $object $object
252
-     * @param array         $input_types
253
-     * @return array
254
-     * @throws EE_Error
255
-     * @throws ReflectionException
256
-     */
257
-    public static function generate_question_form_inputs_for_object(
258
-        EE_Base_class $object,
259
-        array $input_types = []
260
-    ): array {
261
-        $inputs = [];
262
-        $fields = $object->get_model()->field_settings();
263
-        foreach ($fields as $field_ID => $field) {
264
-            if ($field instanceof EE_Model_Field_Base) {
265
-                if (isset($input_types[ $field_ID ])) {
266
-                    // label to display
267
-                    $label = $input_types[ $field_ID ]['label'] ?? $field->get_nicename();
268
-                    // get saved value for field
269
-                    $value = $object->get($field_ID);
270
-                    // if no saved value, then use default
271
-                    $value = $value ?? $field->get_default_value();
272
-                    // determine question type
273
-                    $type = $input_types[ $field_ID ]['type'] ?? 'TEXT';
274
-                    // input name
275
-                    $input_name = isset($input_types[ $field_ID ]['input_name'])
276
-                        ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
277
-                        : $field_ID;
278
-                    // css class for input
279
-                    $class = $input_types[ $field_ID ]['class'] ?? '';
280
-                    // css class for label
281
-                    $label_class = $input_types[ $field_ID ]['label_class'] ?? '';
282
-                    // whether to apply htmlentities to answer
283
-                    $htmlentities = $input_types[ $field_ID ]['htmlentities'] ?? true;
284
-                    // whether to apply htmlentities to answer
285
-                    $label_b4 = $input_types[ $field_ID ]['label_b4'] ?? false;
286
-                    // whether to apply htmlentities to answer
287
-                    $use_desc_4_label = $input_types[ $field_ID ]['use_desc_4_label'] ?? false;
288
-                    // whether input is disabled
289
-                    $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
290
-                    // use a different label on mobile devices
291
-                    $add_mobile_label = isset($input_types[ $field_ID ]['add_mobile_label'])
292
-                        && $input_types[ $field_ID ]['add_mobile_label'];
293
-
294
-                    // create EE_Question_Form_Input object
295
-                    $QFI = new EE_Question_Form_Input(
296
-                        EE_Question::new_instance(
297
-                            [
298
-                                'QST_ID'           => 0,
299
-                                'QST_display_text' => $label,
300
-                                'QST_type'         => $type,
301
-                            ]
302
-                        ),
303
-                        EE_Answer::new_instance(
304
-                            [
305
-                                'ANS_ID'    => 0,
306
-                                'QST_ID'    => 0,
307
-                                'REG_ID'    => 0,
308
-                                'ANS_value' => $value,
309
-                            ]
310
-                        ),
311
-                        [
312
-                            'input_id'         => "$field_ID-{$object->ID()}",
313
-                            'input_name'       => $input_name,
314
-                            'input_class'      => "$field_ID $class",
315
-                            'label_class'      => $label_class,
316
-                            'input_prefix'     => '',
317
-                            'append_qstn_id'   => false,
318
-                            'htmlentities'     => $htmlentities,
319
-                            'label_b4'         => $label_b4,
320
-                            'use_desc_4_label' => $use_desc_4_label,
321
-                            'add_mobile_label' => $add_mobile_label,
322
-                        ]
323
-                    );
324
-                    // does question type have options ?
325
-                    if (
326
-                        in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
327
-                        && isset($input_types[ $field_ID ]['options'])
328
-                    ) {
329
-                        foreach ($input_types[ $field_ID ]['options'] as $option) {
330
-                            $option    = stripslashes_deep($option);
331
-                            $option_id = $option['id'] ?? null;
332
-                            $QSO       = EE_Question_Option::new_instance(
333
-                                [
334
-                                    'QSO_value'   => (string) $option_id,
335
-                                    'QSO_desc'    => $option['text'],
336
-                                    'QSO_deleted' => false,
337
-                                ]
338
-                            );
339
-                            // all QST (and ANS) properties can be accessed indirectly thru QFI
340
-                            $QFI->add_temp_option($QSO);
341
-                        }
342
-                    }
343
-                    // we don't want ppl manually changing primary keys cuz that would just lead to total craziness man
344
-                    if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
345
-                        $QFI->QST_disabled = true;
346
-                    }
347
-                    $inputs[ $field_ID ] = $QFI;
348
-                }
349
-            }
350
-        }
351
-        return $inputs;
352
-    }
353
-
354
-
355
-    /**
356
-     * @param EE_Question_Option $QSO EE_Question_Option
357
-     * @return void
358
-     */
359
-    public function add_temp_option(EE_Question_Option $QSO)
360
-    {
361
-        $this->_QST->add_temp_option($QSO);
362
-    }
363
-
364
-
365
-    /**
366
-     * @param boolean           $notDeletedOptionsOnly            whether to return ALL options, or only the ones which
367
-     *                                                            have not yet been deleted
368
-     * @param string|array|null $selected_value_to_always_include when retrieving options to an ANSWERED question,
369
-     *                                                            we want to usually only show non-deleted options AND
370
-     *                                                            the value that was selected for the answer, whether
371
-     *                                                            it was trashed or not.
372
-     * @return EE_Question_Option[]
373
-     */
374
-    public function options(bool $notDeletedOptionsOnly = true, $selected_value_to_always_include = null): array
375
-    {
376
-        $temp_options = $this->_QST->temp_options();
377
-        return ! empty($temp_options)
378
-            ? $temp_options
379
-            : $this->_QST->options(
380
-                $notDeletedOptionsOnly,
381
-                $selected_value_to_always_include
382
-            );
383
-    }
384
-
385
-
386
-    /**
387
-     * @param mixed $key
388
-     * @return mixed
389
-     */
390
-    public function get_meta($key = false)
391
-    {
392
-        return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
393
-    }
18
+	protected RequestInterface $request;
19
+
20
+	protected array $form_data;
21
+
22
+	private ?EE_Question $_QST = null;
23
+
24
+
25
+	private ?EE_Answer $_ANS = null;
26
+
27
+	/**
28
+	 * $_QST_meta
29
+	 * @var array
30
+	 */
31
+	private array $_QST_meta = [];
32
+
33
+	/**
34
+	 * $QST_input_name
35
+	 * @var string
36
+	 */
37
+	private string $QST_input_name = '';
38
+
39
+	/**
40
+	 * $QST_input_id
41
+	 * @var string
42
+	 */
43
+	private string $QST_input_id = '';
44
+
45
+	/**
46
+	 * $QST_input_class
47
+	 * @var string
48
+	 */
49
+	private string $QST_input_class = '';
50
+
51
+	private bool $QST_disabled = false;
52
+
53
+
54
+	/**
55
+	 * @param EE_Question|null $QST EE_Question object
56
+	 * @param EE_Answer|null   $ANS EE_Answer object
57
+	 * @param array            $q_meta
58
+	 * @throws EE_Error
59
+	 * @throws ReflectionException
60
+	 */
61
+	public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, array $q_meta = [])
62
+	{
63
+		$this->request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
64
+		$this->form_data = $this->request->requestParams();
65
+		if (empty($QST) || empty($ANS)) {
66
+			EE_Error::add_error(
67
+				esc_html__(
68
+					'An error occurred. A valid EE_Question or EE_Answer object was not received.',
69
+					'event_espresso'
70
+				),
71
+				__FILE__,
72
+				__FUNCTION__,
73
+				__LINE__
74
+			);
75
+			return null;
76
+		}
77
+		$this->_QST = $QST;
78
+		$this->_ANS = $ANS;
79
+		$this->set_question_form_input_meta($q_meta);
80
+		$this->set_question_form_input_init();
81
+	}
82
+
83
+
84
+	/**
85
+	 * sets meta data for the question form input
86
+	 *
87
+	 * @param array $q_meta
88
+	 * @return void
89
+	 */
90
+	public function set_question_form_input_meta(array $q_meta = [])
91
+	{
92
+		$default_q_meta  = [
93
+			'att_nmbr'       => 1,
94
+			'ticket_id'      => '',
95
+			'date'           => '',
96
+			'time'           => '',
97
+			'input_name'     => '',
98
+			'input_id'       => '',
99
+			'input_class'    => '',
100
+			'label_class'    => '',
101
+			'input_prefix'   => 'qstn',
102
+			'append_qstn_id' => true,
103
+			'htmlentities'   => true,
104
+			'allow_null'     => false,
105
+		];
106
+		$this->_QST_meta = array_merge($default_q_meta, $q_meta);
107
+	}
108
+
109
+
110
+	/**
111
+	 * @return void
112
+	 * @throws EE_Error
113
+	 * @throws ReflectionException
114
+	 */
115
+	public function set_question_form_input_init()
116
+	{
117
+		$qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID();
118
+		$this->_set_input_name($qstn_id);
119
+		$this->_set_input_id($qstn_id);
120
+		$this->_set_input_class();
121
+		$this->set_question_form_input_answer($qstn_id);
122
+	}
123
+
124
+
125
+	/**
126
+	 * @param $qstn_id
127
+	 * @return void
128
+	 * @throws EE_Error
129
+	 * @throws ReflectionException
130
+	 */
131
+	private function _set_input_name($qstn_id)
132
+	{
133
+		if (! empty($qstn_id)) {
134
+			$ANS_ID  = $this->get('ANS_ID');
135
+			$qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
136
+		}
137
+		$this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
138
+			? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
139
+			: $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
140
+	}
141
+
142
+
143
+	/**
144
+	 * get property values for question form input
145
+	 *
146
+	 * @param string $property
147
+	 * @return mixed
148
+	 * @throws EE_Error
149
+	 * @throws ReflectionException
150
+	 */
151
+	public function get(string $property = '')
152
+	{
153
+		if (empty($property)) {
154
+			return null;
155
+		}
156
+		if (EEM_Question::instance()->has_field($property)) {
157
+			return $this->_QST->get($property);
158
+		}
159
+		if (EEM_Answer::instance()->has_field($property)) {
160
+			return $this->_ANS->get($property);
161
+		}
162
+		if (property_exists($this, $property)) {
163
+			return $this->{$property};
164
+		}
165
+		return null;
166
+	}
167
+
168
+
169
+	/**
170
+	 * set property values for question form input
171
+	 *
172
+	 * @param string $property
173
+	 * @param mixed  $value
174
+	 * @return void
175
+	 * @throws EE_Error
176
+	 * @throws ReflectionException
177
+	 */
178
+	public function set(string $property = '', $value = null)
179
+	{
180
+		if (empty($property)) {
181
+			return;
182
+		}
183
+		if (EEM_Question::instance()->has_field($property)) {
184
+			$this->_QST->set($property, $value);
185
+		}
186
+		if (EEM_Answer::instance()->has_field($property)) {
187
+			$this->_ANS->set($property, $value);
188
+		}
189
+		if (property_exists($this, $property)) {
190
+			$this->{$property} = $value;
191
+		}
192
+	}
193
+
194
+
195
+	/**
196
+	 * @param $qstn_id
197
+	 * @return void
198
+	 * @throws EE_Error
199
+	 * @throws ReflectionException
200
+	 */
201
+	private function _set_input_id($qstn_id)
202
+	{
203
+		$input_id           = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id'])
204
+			? $this->_QST_meta['input_id']
205
+			: sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
206
+		$this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
207
+			? $input_id . '-' . $qstn_id
208
+			: $input_id;
209
+	}
210
+
211
+
212
+	/**
213
+	 * @return void
214
+	 */
215
+	private function _set_input_class()
216
+	{
217
+		$this->QST_input_class = $this->_QST_meta['input_class'] ?? '';
218
+	}
219
+
220
+
221
+	/**
222
+	 * @param int|string $qstn_id
223
+	 * @return void
224
+	 * @throws EE_Error
225
+	 * @throws ReflectionException
226
+	 */
227
+	public function set_question_form_input_answer($qstn_id)
228
+	{
229
+		// check for answer in $this->form_data in case we are reprocessing a form after an error
230
+		if (
231
+			isset($this->_QST_meta['EVT_ID'])
232
+			&& isset($this->_QST_meta['att_nmbr'])
233
+			&& isset($this->_QST_meta['date'])
234
+			&& isset($this->_QST_meta['time'])
235
+			&& isset($this->_QST_meta['price_id'])
236
+		) {
237
+			$EVT_ID   = $this->_QST_meta['EVT_ID'];
238
+			$att_nmbr = $this->_QST_meta['att_nmbr'];
239
+			$date     = $this->_QST_meta['date'];
240
+			$time     = $this->_QST_meta['time'];
241
+			$price_id = $this->_QST_meta['price_id'];
242
+			if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
243
+				$answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
244
+				$this->_ANS->set('ANS_value', $answer);
245
+			}
246
+		}
247
+	}
248
+
249
+
250
+	/**
251
+	 * @param EE_Base_class $object $object
252
+	 * @param array         $input_types
253
+	 * @return array
254
+	 * @throws EE_Error
255
+	 * @throws ReflectionException
256
+	 */
257
+	public static function generate_question_form_inputs_for_object(
258
+		EE_Base_class $object,
259
+		array $input_types = []
260
+	): array {
261
+		$inputs = [];
262
+		$fields = $object->get_model()->field_settings();
263
+		foreach ($fields as $field_ID => $field) {
264
+			if ($field instanceof EE_Model_Field_Base) {
265
+				if (isset($input_types[ $field_ID ])) {
266
+					// label to display
267
+					$label = $input_types[ $field_ID ]['label'] ?? $field->get_nicename();
268
+					// get saved value for field
269
+					$value = $object->get($field_ID);
270
+					// if no saved value, then use default
271
+					$value = $value ?? $field->get_default_value();
272
+					// determine question type
273
+					$type = $input_types[ $field_ID ]['type'] ?? 'TEXT';
274
+					// input name
275
+					$input_name = isset($input_types[ $field_ID ]['input_name'])
276
+						? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
277
+						: $field_ID;
278
+					// css class for input
279
+					$class = $input_types[ $field_ID ]['class'] ?? '';
280
+					// css class for label
281
+					$label_class = $input_types[ $field_ID ]['label_class'] ?? '';
282
+					// whether to apply htmlentities to answer
283
+					$htmlentities = $input_types[ $field_ID ]['htmlentities'] ?? true;
284
+					// whether to apply htmlentities to answer
285
+					$label_b4 = $input_types[ $field_ID ]['label_b4'] ?? false;
286
+					// whether to apply htmlentities to answer
287
+					$use_desc_4_label = $input_types[ $field_ID ]['use_desc_4_label'] ?? false;
288
+					// whether input is disabled
289
+					$disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
290
+					// use a different label on mobile devices
291
+					$add_mobile_label = isset($input_types[ $field_ID ]['add_mobile_label'])
292
+						&& $input_types[ $field_ID ]['add_mobile_label'];
293
+
294
+					// create EE_Question_Form_Input object
295
+					$QFI = new EE_Question_Form_Input(
296
+						EE_Question::new_instance(
297
+							[
298
+								'QST_ID'           => 0,
299
+								'QST_display_text' => $label,
300
+								'QST_type'         => $type,
301
+							]
302
+						),
303
+						EE_Answer::new_instance(
304
+							[
305
+								'ANS_ID'    => 0,
306
+								'QST_ID'    => 0,
307
+								'REG_ID'    => 0,
308
+								'ANS_value' => $value,
309
+							]
310
+						),
311
+						[
312
+							'input_id'         => "$field_ID-{$object->ID()}",
313
+							'input_name'       => $input_name,
314
+							'input_class'      => "$field_ID $class",
315
+							'label_class'      => $label_class,
316
+							'input_prefix'     => '',
317
+							'append_qstn_id'   => false,
318
+							'htmlentities'     => $htmlentities,
319
+							'label_b4'         => $label_b4,
320
+							'use_desc_4_label' => $use_desc_4_label,
321
+							'add_mobile_label' => $add_mobile_label,
322
+						]
323
+					);
324
+					// does question type have options ?
325
+					if (
326
+						in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
327
+						&& isset($input_types[ $field_ID ]['options'])
328
+					) {
329
+						foreach ($input_types[ $field_ID ]['options'] as $option) {
330
+							$option    = stripslashes_deep($option);
331
+							$option_id = $option['id'] ?? null;
332
+							$QSO       = EE_Question_Option::new_instance(
333
+								[
334
+									'QSO_value'   => (string) $option_id,
335
+									'QSO_desc'    => $option['text'],
336
+									'QSO_deleted' => false,
337
+								]
338
+							);
339
+							// all QST (and ANS) properties can be accessed indirectly thru QFI
340
+							$QFI->add_temp_option($QSO);
341
+						}
342
+					}
343
+					// we don't want ppl manually changing primary keys cuz that would just lead to total craziness man
344
+					if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
345
+						$QFI->QST_disabled = true;
346
+					}
347
+					$inputs[ $field_ID ] = $QFI;
348
+				}
349
+			}
350
+		}
351
+		return $inputs;
352
+	}
353
+
354
+
355
+	/**
356
+	 * @param EE_Question_Option $QSO EE_Question_Option
357
+	 * @return void
358
+	 */
359
+	public function add_temp_option(EE_Question_Option $QSO)
360
+	{
361
+		$this->_QST->add_temp_option($QSO);
362
+	}
363
+
364
+
365
+	/**
366
+	 * @param boolean           $notDeletedOptionsOnly            whether to return ALL options, or only the ones which
367
+	 *                                                            have not yet been deleted
368
+	 * @param string|array|null $selected_value_to_always_include when retrieving options to an ANSWERED question,
369
+	 *                                                            we want to usually only show non-deleted options AND
370
+	 *                                                            the value that was selected for the answer, whether
371
+	 *                                                            it was trashed or not.
372
+	 * @return EE_Question_Option[]
373
+	 */
374
+	public function options(bool $notDeletedOptionsOnly = true, $selected_value_to_always_include = null): array
375
+	{
376
+		$temp_options = $this->_QST->temp_options();
377
+		return ! empty($temp_options)
378
+			? $temp_options
379
+			: $this->_QST->options(
380
+				$notDeletedOptionsOnly,
381
+				$selected_value_to_always_include
382
+			);
383
+	}
384
+
385
+
386
+	/**
387
+	 * @param mixed $key
388
+	 * @return mixed
389
+	 */
390
+	public function get_meta($key = false)
391
+	{
392
+		return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
393
+	}
394 394
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -89,7 +89,7 @@  discard block
 block discarded – undo
89 89
      */
90 90
     public function set_question_form_input_meta(array $q_meta = [])
91 91
     {
92
-        $default_q_meta  = [
92
+        $default_q_meta = [
93 93
             'att_nmbr'       => 1,
94 94
             'ticket_id'      => '',
95 95
             'date'           => '',
@@ -130,13 +130,13 @@  discard block
 block discarded – undo
130 130
      */
131 131
     private function _set_input_name($qstn_id)
132 132
     {
133
-        if (! empty($qstn_id)) {
133
+        if ( ! empty($qstn_id)) {
134 134
             $ANS_ID  = $this->get('ANS_ID');
135
-            $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
135
+            $qstn_id = ! empty($ANS_ID) ? '['.$qstn_id.']['.$ANS_ID.']' : '['.$qstn_id.']';
136 136
         }
137 137
         $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
138
-            ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
139
-            : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
138
+            ? $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'].$qstn_id
139
+            : $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'];
140 140
     }
141 141
 
142 142
 
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
             ? $this->_QST_meta['input_id']
205 205
             : sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
206 206
         $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
207
-            ? $input_id . '-' . $qstn_id
207
+            ? $input_id.'-'.$qstn_id
208 208
             : $input_id;
209 209
     }
210 210
 
@@ -239,8 +239,8 @@  discard block
 block discarded – undo
239 239
             $date     = $this->_QST_meta['date'];
240 240
             $time     = $this->_QST_meta['time'];
241 241
             $price_id = $this->_QST_meta['price_id'];
242
-            if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
243
-                $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
242
+            if (isset($this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id])) {
243
+                $answer = $this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id];
244 244
                 $this->_ANS->set('ANS_value', $answer);
245 245
             }
246 246
         }
@@ -262,34 +262,34 @@  discard block
 block discarded – undo
262 262
         $fields = $object->get_model()->field_settings();
263 263
         foreach ($fields as $field_ID => $field) {
264 264
             if ($field instanceof EE_Model_Field_Base) {
265
-                if (isset($input_types[ $field_ID ])) {
265
+                if (isset($input_types[$field_ID])) {
266 266
                     // label to display
267
-                    $label = $input_types[ $field_ID ]['label'] ?? $field->get_nicename();
267
+                    $label = $input_types[$field_ID]['label'] ?? $field->get_nicename();
268 268
                     // get saved value for field
269 269
                     $value = $object->get($field_ID);
270 270
                     // if no saved value, then use default
271 271
                     $value = $value ?? $field->get_default_value();
272 272
                     // determine question type
273
-                    $type = $input_types[ $field_ID ]['type'] ?? 'TEXT';
273
+                    $type = $input_types[$field_ID]['type'] ?? 'TEXT';
274 274
                     // input name
275
-                    $input_name = isset($input_types[ $field_ID ]['input_name'])
276
-                        ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
275
+                    $input_name = isset($input_types[$field_ID]['input_name'])
276
+                        ? $input_types[$field_ID]['input_name'].'['.$field_ID.']'
277 277
                         : $field_ID;
278 278
                     // css class for input
279
-                    $class = $input_types[ $field_ID ]['class'] ?? '';
279
+                    $class = $input_types[$field_ID]['class'] ?? '';
280 280
                     // css class for label
281
-                    $label_class = $input_types[ $field_ID ]['label_class'] ?? '';
281
+                    $label_class = $input_types[$field_ID]['label_class'] ?? '';
282 282
                     // whether to apply htmlentities to answer
283
-                    $htmlentities = $input_types[ $field_ID ]['htmlentities'] ?? true;
283
+                    $htmlentities = $input_types[$field_ID]['htmlentities'] ?? true;
284 284
                     // whether to apply htmlentities to answer
285
-                    $label_b4 = $input_types[ $field_ID ]['label_b4'] ?? false;
285
+                    $label_b4 = $input_types[$field_ID]['label_b4'] ?? false;
286 286
                     // whether to apply htmlentities to answer
287
-                    $use_desc_4_label = $input_types[ $field_ID ]['use_desc_4_label'] ?? false;
287
+                    $use_desc_4_label = $input_types[$field_ID]['use_desc_4_label'] ?? false;
288 288
                     // whether input is disabled
289
-                    $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
289
+                    $disabled = isset($input_types[$field_ID]['disabled']) && $input_types[$field_ID]['disabled'];
290 290
                     // use a different label on mobile devices
291
-                    $add_mobile_label = isset($input_types[ $field_ID ]['add_mobile_label'])
292
-                        && $input_types[ $field_ID ]['add_mobile_label'];
291
+                    $add_mobile_label = isset($input_types[$field_ID]['add_mobile_label'])
292
+                        && $input_types[$field_ID]['add_mobile_label'];
293 293
 
294 294
                     // create EE_Question_Form_Input object
295 295
                     $QFI = new EE_Question_Form_Input(
@@ -324,9 +324,9 @@  discard block
 block discarded – undo
324 324
                     // does question type have options ?
325 325
                     if (
326 326
                         in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
327
-                        && isset($input_types[ $field_ID ]['options'])
327
+                        && isset($input_types[$field_ID]['options'])
328 328
                     ) {
329
-                        foreach ($input_types[ $field_ID ]['options'] as $option) {
329
+                        foreach ($input_types[$field_ID]['options'] as $option) {
330 330
                             $option    = stripslashes_deep($option);
331 331
                             $option_id = $option['id'] ?? null;
332 332
                             $QSO       = EE_Question_Option::new_instance(
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
                     if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
345 345
                         $QFI->QST_disabled = true;
346 346
                     }
347
-                    $inputs[ $field_ID ] = $QFI;
347
+                    $inputs[$field_ID] = $QFI;
348 348
                 }
349 349
             }
350 350
         }
@@ -389,6 +389,6 @@  discard block
 block discarded – undo
389 389
      */
390 390
     public function get_meta($key = false)
391 391
     {
392
-        return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
392
+        return $key && isset($this->_QST_meta[$key]) ? $this->_QST_meta[$key] : false;
393 393
     }
394 394
 }
Please login to merge, or discard this patch.
core/EE_Cart.core.php 1 patch
Indentation   +410 added lines, -410 removed lines patch added patch discarded remove patch
@@ -16,414 +16,414 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Cart implements ResettableInterface
18 18
 {
19
-    /**
20
-     * instance of the EE_Cart object
21
-     *
22
-     * @access    private
23
-     * @var EE_Cart $_instance
24
-     */
25
-    private static $_instance;
26
-
27
-    /**
28
-     * instance of the EE_Session object
29
-     *
30
-     * @access    protected
31
-     * @var EE_Session $_session
32
-     */
33
-    protected $_session;
34
-
35
-    /**
36
-     * The total Line item which comprises all the children line-item subtotals,
37
-     * which in turn each have their line items.
38
-     * Typically, the line item structure will look like:
39
-     * grand total
40
-     * -tickets-sub-total
41
-     * --ticket1
42
-     * --ticket2
43
-     * --...
44
-     * -taxes-sub-total
45
-     * --tax1
46
-     * --tax2
47
-     *
48
-     * @var EE_Line_Item
49
-     */
50
-    private $_grand_total;
51
-
52
-
53
-    /**
54
-     * @singleton method used to instantiate class object
55
-     * @access    public
56
-     * @param EE_Line_Item $grand_total
57
-     * @param EE_Session   $session
58
-     * @return EE_Cart
59
-     * @throws EE_Error
60
-     * @throws ReflectionException
61
-     */
62
-    public static function instance(EE_Line_Item $grand_total = null, EE_Session $session = null)
63
-    {
64
-        if ($grand_total instanceof EE_Line_Item && $grand_total->is_total()) {
65
-            self::$_instance = new self($grand_total, $session);
66
-        }
67
-        // or maybe retrieve an existing one ?
68
-        if (! self::$_instance instanceof EE_Cart) {
69
-            // try getting the cart out of the session
70
-            $saved_cart = $session instanceof EE_Session ? $session->cart() : null;
71
-            self::$_instance = $saved_cart instanceof EE_Cart ? $saved_cart : new self($grand_total, $session);
72
-            unset($saved_cart);
73
-        }
74
-        // verify that cart is ok and grand total line item exists
75
-        if (! self::$_instance instanceof EE_Cart || ! self::$_instance->_grand_total instanceof EE_Line_Item) {
76
-            self::$_instance = new self($grand_total, $session);
77
-        }
78
-        self::$_instance->get_grand_total();
79
-        // once everything is all said and done, save the cart to the EE_Session
80
-        add_action('shutdown', array(self::$_instance, 'save_cart'), 90);
81
-        return self::$_instance;
82
-    }
83
-
84
-
85
-    /**
86
-     * private constructor to prevent direct creation
87
-     *
88
-     * @Constructor
89
-     * @access private
90
-     * @param EE_Line_Item $grand_total
91
-     * @param EE_Session   $session
92
-     */
93
-    private function __construct(EE_Line_Item $grand_total = null, EE_Session $session = null)
94
-    {
95
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
96
-        $this->set_session($session);
97
-        if ($grand_total instanceof EE_Line_Item && $grand_total->is_total()) {
98
-            $this->set_grand_total_line_item($grand_total);
99
-        }
100
-    }
101
-
102
-
103
-    /**
104
-     * Resets the cart completely (whereas empty_cart
105
-     *
106
-     * @param EE_Line_Item $grand_total
107
-     * @param EE_Session   $session
108
-     * @return EE_Cart
109
-     * @throws EE_Error
110
-     * @throws ReflectionException
111
-     */
112
-    public static function reset(EE_Line_Item $grand_total = null, EE_Session $session = null)
113
-    {
114
-        remove_action('shutdown', array(self::$_instance, 'save_cart'), 90);
115
-        if ($session instanceof EE_Session) {
116
-            $session->reset_cart();
117
-        }
118
-        self::$_instance = null;
119
-        return self::instance($grand_total, $session);
120
-    }
121
-
122
-
123
-    /**
124
-     * @return EE_Session
125
-     */
126
-    public function session()
127
-    {
128
-        if (! $this->_session instanceof EE_Session) {
129
-            $this->set_session();
130
-        }
131
-        return $this->_session;
132
-    }
133
-
134
-
135
-    /**
136
-     * @param EE_Session $session
137
-     */
138
-    public function set_session(EE_Session $session = null)
139
-    {
140
-        $this->_session = $session instanceof EE_Session ? $session : EE_Registry::instance()->load_core('Session');
141
-    }
142
-
143
-
144
-    /**
145
-     * Sets the cart to match the line item. Especially handy for loading an old cart where you
146
-     *  know the grand total line item on it
147
-     *
148
-     * @param EE_Line_Item $line_item
149
-     */
150
-    public function set_grand_total_line_item(EE_Line_Item $line_item)
151
-    {
152
-        $this->_grand_total = $line_item;
153
-    }
154
-
155
-
156
-    /**
157
-     * get_cart_from_reg_url_link
158
-     *
159
-     * @access public
160
-     * @param EE_Transaction $transaction
161
-     * @param EE_Session     $session
162
-     * @return EE_Cart
163
-     * @throws EE_Error
164
-     * @throws ReflectionException
165
-     */
166
-    public static function get_cart_from_txn(EE_Transaction $transaction, EE_Session $session = null)
167
-    {
168
-        $grand_total = $transaction->total_line_item();
169
-        $grand_total->get_items();
170
-        $grand_total->tax_descendants();
171
-        return EE_Cart::instance($grand_total, $session);
172
-    }
173
-
174
-
175
-    /**
176
-     * Creates the total line item, and ensures it has its 'tickets' and 'taxes' sub-items
177
-     *
178
-     * @return EE_Line_Item
179
-     * @throws EE_Error
180
-     * @throws ReflectionException
181
-     */
182
-    private function _create_grand_total()
183
-    {
184
-        $this->_grand_total = EEH_Line_Item::create_total_line_item();
185
-        return $this->_grand_total;
186
-    }
187
-
188
-
189
-    /**
190
-     * Gets all the line items of object type Ticket
191
-     *
192
-     * @access public
193
-     * @return EE_Line_Item[]
194
-     * @throws EE_Error
195
-     * @throws ReflectionException
196
-     */
197
-    public function get_tickets(): array
198
-    {
199
-        if ($this->_grand_total === null) {
200
-            return array();
201
-        }
202
-        return EEH_Line_Item::get_ticket_line_items($this->_grand_total);
203
-    }
204
-
205
-
206
-    /**
207
-     * returns the total quantity of tickets in the cart
208
-     *
209
-     * @access public
210
-     * @return int
211
-     * @throws EE_Error
212
-     * @throws ReflectionException
213
-     */
214
-    public function all_ticket_quantity_count(): int
215
-    {
216
-        $tickets = $this->get_tickets();
217
-        if (empty($tickets)) {
218
-            return 0;
219
-        }
220
-        $count = 0;
221
-        foreach ($tickets as $ticket) {
222
-            $count += $ticket->quantity();
223
-        }
224
-        return $count;
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets all the tax line items
230
-     *
231
-     * @return EE_Line_Item[]
232
-     * @throws EE_Error
233
-     * @throws ReflectionException
234
-     */
235
-    public function get_taxes()
236
-    {
237
-        return EEH_Line_Item::get_taxes_subtotal($this->_grand_total)->children();
238
-    }
239
-
240
-
241
-    /**
242
-     * Gets the total line item (which is a parent of all other line items) on this cart
243
-     *
244
-     * @return EE_Line_Item
245
-     * @throws EE_Error
246
-     * @throws ReflectionException
247
-     */
248
-    public function get_grand_total()
249
-    {
250
-        return $this->_grand_total instanceof EE_Line_Item ? $this->_grand_total : $this->_create_grand_total();
251
-    }
252
-
253
-
254
-    /**
255
-     * @process items for adding to cart
256
-     * @access  public
257
-     * @param EE_Ticket $ticket
258
-     * @param int       $qty
259
-     * @return bool TRUE on success, FALSE on fail
260
-     * @throws EE_Error
261
-     * @throws ReflectionException
262
-     */
263
-    public function add_ticket_to_cart(EE_Ticket $ticket, $qty = 1)
264
-    {
265
-        EEH_Line_Item::add_ticket_purchase($this->get_grand_total(), $ticket, $qty, false);
266
-        return $this->save_cart();
267
-    }
268
-
269
-
270
-    /**
271
-     * get_cart_total_before_tax
272
-     *
273
-     * @access public
274
-     * @return float
275
-     * @throws EE_Error
276
-     * @throws ReflectionException
277
-     */
278
-    public function get_cart_total_before_tax()
279
-    {
280
-        return $this->get_grand_total()->recalculate_pre_tax_total();
281
-    }
282
-
283
-
284
-    /**
285
-     * gets the total amount of tax paid for items in this cart
286
-     *
287
-     * @access public
288
-     * @return float
289
-     * @throws EE_Error
290
-     * @throws ReflectionException
291
-     */
292
-    public function get_applied_taxes()
293
-    {
294
-        return EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
295
-    }
296
-
297
-
298
-    /**
299
-     * Gets the total amount to be paid for the items in the cart, including taxes and other modifiers
300
-     *
301
-     * @access public
302
-     * @return float
303
-     * @throws EE_Error
304
-     * @throws ReflectionException
305
-     */
306
-    public function get_cart_grand_total()
307
-    {
308
-        EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
309
-        return $this->get_grand_total()->total();
310
-    }
311
-
312
-
313
-    /**
314
-     * Gets the total amount to be paid for the items in the cart, including taxes and other modifiers
315
-     *
316
-     * @access public
317
-     * @return float
318
-     * @throws EE_Error
319
-     * @throws ReflectionException
320
-     */
321
-    public function recalculate_all_cart_totals()
322
-    {
323
-        $pre_tax_total = $this->get_cart_total_before_tax();
324
-        $taxes_total = EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
325
-        $this->_grand_total->set_total($pre_tax_total + $taxes_total);
326
-        $this->_grand_total->save_this_and_descendants_to_txn();
327
-        return $this->get_grand_total()->total();
328
-    }
329
-
330
-
331
-    /**
332
-     * deletes an item from the cart
333
-     *
334
-     * @access public
335
-     * @param array|bool|string $line_item_codes
336
-     * @return int on success, FALSE on fail
337
-     * @throws EE_Error
338
-     * @throws ReflectionException
339
-     */
340
-    public function delete_items($line_item_codes = false)
341
-    {
342
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
343
-        return EEH_Line_Item::delete_items($this->get_grand_total(), $line_item_codes);
344
-    }
345
-
346
-
347
-    /**
348
-     * @remove ALL items from cart and zero ALL totals
349
-     * @access public
350
-     * @return bool
351
-     * @throws EE_Error
352
-     * @throws ReflectionException
353
-     */
354
-    public function empty_cart()
355
-    {
356
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
357
-        $this->_grand_total = $this->_create_grand_total();
358
-        return $this->save_cart(true);
359
-    }
360
-
361
-
362
-    /**
363
-     * @remove ALL items from cart and delete total as well
364
-     * @access public
365
-     * @return bool
366
-     * @throws EE_Error
367
-     * @throws ReflectionException
368
-     */
369
-    public function delete_cart()
370
-    {
371
-        if ($this->_grand_total instanceof EE_Line_Item) {
372
-            $deleted = EEH_Line_Item::delete_all_child_items($this->_grand_total);
373
-            if ($deleted) {
374
-                $deleted += $this->_grand_total->delete();
375
-                $this->_grand_total = null;
376
-                return true;
377
-            }
378
-        }
379
-        return false;
380
-    }
381
-
382
-
383
-    /**
384
-     * @save   cart to session
385
-     * @access public
386
-     * @param bool $apply_taxes
387
-     * @return bool TRUE on success, FALSE on fail
388
-     * @throws EE_Error
389
-     * @throws ReflectionException
390
-     */
391
-    public function save_cart($apply_taxes = true)
392
-    {
393
-        if ($apply_taxes && $this->_grand_total instanceof EE_Line_Item) {
394
-            EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
395
-            // make sure we don't cache the transaction because it can get stale
396
-            if (
397
-                $this->_grand_total->get_one_from_cache('Transaction') instanceof EE_Transaction
398
-                && $this->_grand_total->get_one_from_cache('Transaction')->ID()
399
-            ) {
400
-                $this->_grand_total->clear_cache('Transaction', null, true);
401
-            }
402
-        }
403
-        if ($this->session() instanceof EE_Session) {
404
-            return $this->session()->set_cart($this);
405
-        }
406
-        return false;
407
-    }
408
-
409
-
410
-    public function __wakeup()
411
-    {
412
-        if (! $this->_grand_total instanceof EE_Line_Item && absint($this->_grand_total) !== 0) {
413
-            // $this->_grand_total is actually just an ID, so use it to get the object from the db
414
-            $this->_grand_total = EEM_Line_Item::instance()->get_one_by_ID($this->_grand_total);
415
-        }
416
-    }
417
-
418
-
419
-    /**
420
-     * @return array
421
-     */
422
-    public function __sleep()
423
-    {
424
-        if ($this->_grand_total instanceof EE_Line_Item && $this->_grand_total->ID()) {
425
-            $this->_grand_total = $this->_grand_total->ID();
426
-        }
427
-        return array('_grand_total');
428
-    }
19
+	/**
20
+	 * instance of the EE_Cart object
21
+	 *
22
+	 * @access    private
23
+	 * @var EE_Cart $_instance
24
+	 */
25
+	private static $_instance;
26
+
27
+	/**
28
+	 * instance of the EE_Session object
29
+	 *
30
+	 * @access    protected
31
+	 * @var EE_Session $_session
32
+	 */
33
+	protected $_session;
34
+
35
+	/**
36
+	 * The total Line item which comprises all the children line-item subtotals,
37
+	 * which in turn each have their line items.
38
+	 * Typically, the line item structure will look like:
39
+	 * grand total
40
+	 * -tickets-sub-total
41
+	 * --ticket1
42
+	 * --ticket2
43
+	 * --...
44
+	 * -taxes-sub-total
45
+	 * --tax1
46
+	 * --tax2
47
+	 *
48
+	 * @var EE_Line_Item
49
+	 */
50
+	private $_grand_total;
51
+
52
+
53
+	/**
54
+	 * @singleton method used to instantiate class object
55
+	 * @access    public
56
+	 * @param EE_Line_Item $grand_total
57
+	 * @param EE_Session   $session
58
+	 * @return EE_Cart
59
+	 * @throws EE_Error
60
+	 * @throws ReflectionException
61
+	 */
62
+	public static function instance(EE_Line_Item $grand_total = null, EE_Session $session = null)
63
+	{
64
+		if ($grand_total instanceof EE_Line_Item && $grand_total->is_total()) {
65
+			self::$_instance = new self($grand_total, $session);
66
+		}
67
+		// or maybe retrieve an existing one ?
68
+		if (! self::$_instance instanceof EE_Cart) {
69
+			// try getting the cart out of the session
70
+			$saved_cart = $session instanceof EE_Session ? $session->cart() : null;
71
+			self::$_instance = $saved_cart instanceof EE_Cart ? $saved_cart : new self($grand_total, $session);
72
+			unset($saved_cart);
73
+		}
74
+		// verify that cart is ok and grand total line item exists
75
+		if (! self::$_instance instanceof EE_Cart || ! self::$_instance->_grand_total instanceof EE_Line_Item) {
76
+			self::$_instance = new self($grand_total, $session);
77
+		}
78
+		self::$_instance->get_grand_total();
79
+		// once everything is all said and done, save the cart to the EE_Session
80
+		add_action('shutdown', array(self::$_instance, 'save_cart'), 90);
81
+		return self::$_instance;
82
+	}
83
+
84
+
85
+	/**
86
+	 * private constructor to prevent direct creation
87
+	 *
88
+	 * @Constructor
89
+	 * @access private
90
+	 * @param EE_Line_Item $grand_total
91
+	 * @param EE_Session   $session
92
+	 */
93
+	private function __construct(EE_Line_Item $grand_total = null, EE_Session $session = null)
94
+	{
95
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
96
+		$this->set_session($session);
97
+		if ($grand_total instanceof EE_Line_Item && $grand_total->is_total()) {
98
+			$this->set_grand_total_line_item($grand_total);
99
+		}
100
+	}
101
+
102
+
103
+	/**
104
+	 * Resets the cart completely (whereas empty_cart
105
+	 *
106
+	 * @param EE_Line_Item $grand_total
107
+	 * @param EE_Session   $session
108
+	 * @return EE_Cart
109
+	 * @throws EE_Error
110
+	 * @throws ReflectionException
111
+	 */
112
+	public static function reset(EE_Line_Item $grand_total = null, EE_Session $session = null)
113
+	{
114
+		remove_action('shutdown', array(self::$_instance, 'save_cart'), 90);
115
+		if ($session instanceof EE_Session) {
116
+			$session->reset_cart();
117
+		}
118
+		self::$_instance = null;
119
+		return self::instance($grand_total, $session);
120
+	}
121
+
122
+
123
+	/**
124
+	 * @return EE_Session
125
+	 */
126
+	public function session()
127
+	{
128
+		if (! $this->_session instanceof EE_Session) {
129
+			$this->set_session();
130
+		}
131
+		return $this->_session;
132
+	}
133
+
134
+
135
+	/**
136
+	 * @param EE_Session $session
137
+	 */
138
+	public function set_session(EE_Session $session = null)
139
+	{
140
+		$this->_session = $session instanceof EE_Session ? $session : EE_Registry::instance()->load_core('Session');
141
+	}
142
+
143
+
144
+	/**
145
+	 * Sets the cart to match the line item. Especially handy for loading an old cart where you
146
+	 *  know the grand total line item on it
147
+	 *
148
+	 * @param EE_Line_Item $line_item
149
+	 */
150
+	public function set_grand_total_line_item(EE_Line_Item $line_item)
151
+	{
152
+		$this->_grand_total = $line_item;
153
+	}
154
+
155
+
156
+	/**
157
+	 * get_cart_from_reg_url_link
158
+	 *
159
+	 * @access public
160
+	 * @param EE_Transaction $transaction
161
+	 * @param EE_Session     $session
162
+	 * @return EE_Cart
163
+	 * @throws EE_Error
164
+	 * @throws ReflectionException
165
+	 */
166
+	public static function get_cart_from_txn(EE_Transaction $transaction, EE_Session $session = null)
167
+	{
168
+		$grand_total = $transaction->total_line_item();
169
+		$grand_total->get_items();
170
+		$grand_total->tax_descendants();
171
+		return EE_Cart::instance($grand_total, $session);
172
+	}
173
+
174
+
175
+	/**
176
+	 * Creates the total line item, and ensures it has its 'tickets' and 'taxes' sub-items
177
+	 *
178
+	 * @return EE_Line_Item
179
+	 * @throws EE_Error
180
+	 * @throws ReflectionException
181
+	 */
182
+	private function _create_grand_total()
183
+	{
184
+		$this->_grand_total = EEH_Line_Item::create_total_line_item();
185
+		return $this->_grand_total;
186
+	}
187
+
188
+
189
+	/**
190
+	 * Gets all the line items of object type Ticket
191
+	 *
192
+	 * @access public
193
+	 * @return EE_Line_Item[]
194
+	 * @throws EE_Error
195
+	 * @throws ReflectionException
196
+	 */
197
+	public function get_tickets(): array
198
+	{
199
+		if ($this->_grand_total === null) {
200
+			return array();
201
+		}
202
+		return EEH_Line_Item::get_ticket_line_items($this->_grand_total);
203
+	}
204
+
205
+
206
+	/**
207
+	 * returns the total quantity of tickets in the cart
208
+	 *
209
+	 * @access public
210
+	 * @return int
211
+	 * @throws EE_Error
212
+	 * @throws ReflectionException
213
+	 */
214
+	public function all_ticket_quantity_count(): int
215
+	{
216
+		$tickets = $this->get_tickets();
217
+		if (empty($tickets)) {
218
+			return 0;
219
+		}
220
+		$count = 0;
221
+		foreach ($tickets as $ticket) {
222
+			$count += $ticket->quantity();
223
+		}
224
+		return $count;
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets all the tax line items
230
+	 *
231
+	 * @return EE_Line_Item[]
232
+	 * @throws EE_Error
233
+	 * @throws ReflectionException
234
+	 */
235
+	public function get_taxes()
236
+	{
237
+		return EEH_Line_Item::get_taxes_subtotal($this->_grand_total)->children();
238
+	}
239
+
240
+
241
+	/**
242
+	 * Gets the total line item (which is a parent of all other line items) on this cart
243
+	 *
244
+	 * @return EE_Line_Item
245
+	 * @throws EE_Error
246
+	 * @throws ReflectionException
247
+	 */
248
+	public function get_grand_total()
249
+	{
250
+		return $this->_grand_total instanceof EE_Line_Item ? $this->_grand_total : $this->_create_grand_total();
251
+	}
252
+
253
+
254
+	/**
255
+	 * @process items for adding to cart
256
+	 * @access  public
257
+	 * @param EE_Ticket $ticket
258
+	 * @param int       $qty
259
+	 * @return bool TRUE on success, FALSE on fail
260
+	 * @throws EE_Error
261
+	 * @throws ReflectionException
262
+	 */
263
+	public function add_ticket_to_cart(EE_Ticket $ticket, $qty = 1)
264
+	{
265
+		EEH_Line_Item::add_ticket_purchase($this->get_grand_total(), $ticket, $qty, false);
266
+		return $this->save_cart();
267
+	}
268
+
269
+
270
+	/**
271
+	 * get_cart_total_before_tax
272
+	 *
273
+	 * @access public
274
+	 * @return float
275
+	 * @throws EE_Error
276
+	 * @throws ReflectionException
277
+	 */
278
+	public function get_cart_total_before_tax()
279
+	{
280
+		return $this->get_grand_total()->recalculate_pre_tax_total();
281
+	}
282
+
283
+
284
+	/**
285
+	 * gets the total amount of tax paid for items in this cart
286
+	 *
287
+	 * @access public
288
+	 * @return float
289
+	 * @throws EE_Error
290
+	 * @throws ReflectionException
291
+	 */
292
+	public function get_applied_taxes()
293
+	{
294
+		return EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
295
+	}
296
+
297
+
298
+	/**
299
+	 * Gets the total amount to be paid for the items in the cart, including taxes and other modifiers
300
+	 *
301
+	 * @access public
302
+	 * @return float
303
+	 * @throws EE_Error
304
+	 * @throws ReflectionException
305
+	 */
306
+	public function get_cart_grand_total()
307
+	{
308
+		EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
309
+		return $this->get_grand_total()->total();
310
+	}
311
+
312
+
313
+	/**
314
+	 * Gets the total amount to be paid for the items in the cart, including taxes and other modifiers
315
+	 *
316
+	 * @access public
317
+	 * @return float
318
+	 * @throws EE_Error
319
+	 * @throws ReflectionException
320
+	 */
321
+	public function recalculate_all_cart_totals()
322
+	{
323
+		$pre_tax_total = $this->get_cart_total_before_tax();
324
+		$taxes_total = EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
325
+		$this->_grand_total->set_total($pre_tax_total + $taxes_total);
326
+		$this->_grand_total->save_this_and_descendants_to_txn();
327
+		return $this->get_grand_total()->total();
328
+	}
329
+
330
+
331
+	/**
332
+	 * deletes an item from the cart
333
+	 *
334
+	 * @access public
335
+	 * @param array|bool|string $line_item_codes
336
+	 * @return int on success, FALSE on fail
337
+	 * @throws EE_Error
338
+	 * @throws ReflectionException
339
+	 */
340
+	public function delete_items($line_item_codes = false)
341
+	{
342
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
343
+		return EEH_Line_Item::delete_items($this->get_grand_total(), $line_item_codes);
344
+	}
345
+
346
+
347
+	/**
348
+	 * @remove ALL items from cart and zero ALL totals
349
+	 * @access public
350
+	 * @return bool
351
+	 * @throws EE_Error
352
+	 * @throws ReflectionException
353
+	 */
354
+	public function empty_cart()
355
+	{
356
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
357
+		$this->_grand_total = $this->_create_grand_total();
358
+		return $this->save_cart(true);
359
+	}
360
+
361
+
362
+	/**
363
+	 * @remove ALL items from cart and delete total as well
364
+	 * @access public
365
+	 * @return bool
366
+	 * @throws EE_Error
367
+	 * @throws ReflectionException
368
+	 */
369
+	public function delete_cart()
370
+	{
371
+		if ($this->_grand_total instanceof EE_Line_Item) {
372
+			$deleted = EEH_Line_Item::delete_all_child_items($this->_grand_total);
373
+			if ($deleted) {
374
+				$deleted += $this->_grand_total->delete();
375
+				$this->_grand_total = null;
376
+				return true;
377
+			}
378
+		}
379
+		return false;
380
+	}
381
+
382
+
383
+	/**
384
+	 * @save   cart to session
385
+	 * @access public
386
+	 * @param bool $apply_taxes
387
+	 * @return bool TRUE on success, FALSE on fail
388
+	 * @throws EE_Error
389
+	 * @throws ReflectionException
390
+	 */
391
+	public function save_cart($apply_taxes = true)
392
+	{
393
+		if ($apply_taxes && $this->_grand_total instanceof EE_Line_Item) {
394
+			EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
395
+			// make sure we don't cache the transaction because it can get stale
396
+			if (
397
+				$this->_grand_total->get_one_from_cache('Transaction') instanceof EE_Transaction
398
+				&& $this->_grand_total->get_one_from_cache('Transaction')->ID()
399
+			) {
400
+				$this->_grand_total->clear_cache('Transaction', null, true);
401
+			}
402
+		}
403
+		if ($this->session() instanceof EE_Session) {
404
+			return $this->session()->set_cart($this);
405
+		}
406
+		return false;
407
+	}
408
+
409
+
410
+	public function __wakeup()
411
+	{
412
+		if (! $this->_grand_total instanceof EE_Line_Item && absint($this->_grand_total) !== 0) {
413
+			// $this->_grand_total is actually just an ID, so use it to get the object from the db
414
+			$this->_grand_total = EEM_Line_Item::instance()->get_one_by_ID($this->_grand_total);
415
+		}
416
+	}
417
+
418
+
419
+	/**
420
+	 * @return array
421
+	 */
422
+	public function __sleep()
423
+	{
424
+		if ($this->_grand_total instanceof EE_Line_Item && $this->_grand_total->ID()) {
425
+			$this->_grand_total = $this->_grand_total->ID();
426
+		}
427
+		return array('_grand_total');
428
+	}
429 429
 }
Please login to merge, or discard this patch.
core/EE_Error.core.php 1 patch
Indentation   +1134 added lines, -1134 removed lines patch added patch discarded remove patch
@@ -18,245 +18,245 @@  discard block
 block discarded – undo
18 18
  */
19 19
 class EE_Error extends Exception
20 20
 {
21
-    const OPTIONS_KEY_NOTICES = 'ee_notices';
22
-
23
-    /**
24
-     *    stores details for all exception
25
-     *
26
-     * @var array
27
-     */
28
-    private static $_all_exceptions = [];
29
-
30
-    /**
31
-     *    tracks number of errors
32
-     *
33
-     * @var int
34
-     */
35
-    private static $_error_count = 0;
36
-
37
-    /**
38
-     * @var array $_espresso_notices
39
-     */
40
-    private static $_espresso_notices = ['success' => false, 'errors' => false, 'attention' => false];
41
-
42
-
43
-    /**
44
-     * @override default exception handling
45
-     * @param string         $message
46
-     * @param int            $code
47
-     * @param Exception|null $previous
48
-     */
49
-    public function __construct($message, $code = 0, Exception $previous = null)
50
-    {
51
-        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
52
-            parent::__construct($message, $code);
53
-        } else {
54
-            parent::__construct($message, $code, $previous);
55
-        }
56
-    }
57
-
58
-
59
-    /**
60
-     *    error_handler
61
-     *
62
-     * @param int  $code
63
-     * @param string $message
64
-     * @param string $file
65
-     * @param int|string $line
66
-     * @return void
67
-     */
68
-    public static function error_handler(int $code, string $message, string $file, $line)
69
-    {
70
-        $type    = EE_Error::error_type($code);
71
-        $site    = site_url();
72
-        $to      = strpos($site, 'eventespresso.com')
73
-            ? '[email protected]'
74
-            : get_option('admin_email');
75
-        $subject = "$type $message in " . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
76
-        $msg     = EE_Error::_format_error($type, $message, $file, $line);
77
-        if (function_exists('wp_mail')) {
78
-            add_filter('wp_mail_content_type', ['EE_Error', 'set_content_type']);
79
-            wp_mail($to, $subject, $msg);
80
-        }
81
-        echo '<div id="message" class="espresso-notices error"><p>';
82
-        echo wp_kses($type . ': ' . $message . '<br />' . $file . ' line ' . $line, AllowedTags::getWithFormTags());
83
-        echo '<br /></p></div>';
84
-    }
85
-
86
-
87
-    /**
88
-     * error_type
89
-     * http://www.php.net/manual/en/errorfunc.constants.php#109430
90
-     *
91
-     * @param int $code
92
-     * @return string
93
-     */
94
-    public static function error_type(int $code): string
95
-    {
96
-        switch ($code) {
97
-            case E_ERROR: // 1 //
98
-                return 'E_ERROR';
99
-            case E_WARNING: // 2 //
100
-                return 'E_WARNING';
101
-            case E_PARSE: // 4 //
102
-                return 'E_PARSE';
103
-            case E_NOTICE: // 8 //
104
-                return 'E_NOTICE';
105
-            case E_CORE_ERROR: // 16 //
106
-                return 'E_CORE_ERROR';
107
-            case E_CORE_WARNING: // 32 //
108
-                return 'E_CORE_WARNING';
109
-            case E_COMPILE_ERROR: // 64 //
110
-                return 'E_COMPILE_ERROR';
111
-            case E_COMPILE_WARNING: // 128 //
112
-                return 'E_COMPILE_WARNING';
113
-            case E_USER_ERROR: // 256 //
114
-                return 'E_USER_ERROR';
115
-            case E_USER_WARNING: // 512 //
116
-                return 'E_USER_WARNING';
117
-            case E_USER_NOTICE: // 1024 //
118
-                return 'E_USER_NOTICE';
119
-            case E_STRICT: // 2048 //
120
-                return 'E_STRICT';
121
-            case E_RECOVERABLE_ERROR: // 4096 //
122
-                return 'E_RECOVERABLE_ERROR';
123
-            case E_DEPRECATED: // 8192 //
124
-                return 'E_DEPRECATED';
125
-            case E_USER_DEPRECATED: // 16384 //
126
-                return 'E_USER_DEPRECATED';
127
-            case E_ALL: // 16384 //
128
-                return 'E_ALL';
129
-        }
130
-        return '';
131
-    }
132
-
133
-
134
-    /**
135
-     *    fatal_error_handler
136
-     *
137
-     * @return void
138
-     */
139
-    public static function fatal_error_handler()
140
-    {
141
-        $last_error = error_get_last();
142
-        if ($last_error['type'] === E_ERROR) {
143
-            EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
144
-        }
145
-    }
146
-
147
-
148
-    /**
149
-     * _format_error
150
-     *
151
-     * @param $code
152
-     * @param $message
153
-     * @param $file
154
-     * @param $line
155
-     * @return string
156
-     */
157
-    private static function _format_error($code, $message, $file, $line): string
158
-    {
159
-        $html =
160
-            "<table><thead><th>Item</th><th>Details</th></thead><tbody>";
161
-        $html .= "<tr><td><b>Code</b></td><td>$code</td></tr>";
162
-        $html .= "<tr><td><b>Error</b></td><td>$message</td></tr>";
163
-        $html .= "<tr><td><b>File</b></td><td>$file</td></tr>";
164
-        $html .= "<tr><td><b>Line</b></td><td>$line</td></tr>";
165
-        $html .= '</tbody></table>';
166
-        return $html;
167
-    }
168
-
169
-
170
-    /**
171
-     * set_content_type
172
-     *
173
-     * @param $content_type
174
-     * @return string
175
-     */
176
-    public static function set_content_type($content_type): string
177
-    {
178
-        return 'text/html';
179
-    }
180
-
181
-
182
-    /**
183
-     * @return void
184
-     * @throws EE_Error
185
-     * @throws ReflectionException
186
-     */
187
-    public function get_error()
188
-    {
189
-        if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
190
-            throw $this;
191
-        }
192
-        // get separate user and developer messages if they exist
193
-        $msg      = explode('||', $this->getMessage());
194
-        $user_msg = $msg[0];
195
-        $dev_msg  = $msg[1] ?? $msg[0];
196
-        $msg      = WP_DEBUG ? $dev_msg : $user_msg;
197
-        // add details to _all_exceptions array
198
-        $x_time                                     = time();
199
-        self::$_all_exceptions[ $x_time ]['name']   = get_class($this);
200
-        self::$_all_exceptions[ $x_time ]['file']   = $this->getFile();
201
-        self::$_all_exceptions[ $x_time ]['line']   = $this->getLine();
202
-        self::$_all_exceptions[ $x_time ]['msg']    = $msg;
203
-        self::$_all_exceptions[ $x_time ]['code']   = $this->getCode();
204
-        self::$_all_exceptions[ $x_time ]['trace']  = $this->getTrace();
205
-        self::$_all_exceptions[ $x_time ]['string'] = $this->getTraceAsString();
206
-        self::$_error_count++;
207
-        // add_action( 'shutdown', array( $this, 'display_errors' ));
208
-        $this->display_errors();
209
-    }
210
-
211
-
212
-    /**
213
-     * @param bool   $check_stored
214
-     * @param string $type_to_check
215
-     * @return bool
216
-     * @throws InvalidInterfaceException
217
-     * @throws InvalidArgumentException
218
-     * @throws InvalidDataTypeException
219
-     */
220
-    public static function has_error(bool $check_stored = false, string $type_to_check = 'errors'): bool
221
-    {
222
-        $has_error = isset(self::$_espresso_notices[ $type_to_check ])
223
-                     && ! empty(self::$_espresso_notices[ $type_to_check ]);
224
-        if ($check_stored && ! $has_error) {
225
-            $notices = EE_Error::getStoredNotices();
226
-            foreach ($notices as $type => $notice) {
227
-                if ($type === $type_to_check && $notice) {
228
-                    return true;
229
-                }
230
-            }
231
-        }
232
-        return $has_error;
233
-    }
234
-
235
-
236
-    /**
237
-     * @echo string
238
-     * @throws ReflectionException
239
-     */
240
-    public function display_errors()
241
-    {
242
-        $trace_details = '';
243
-        $output = '
21
+	const OPTIONS_KEY_NOTICES = 'ee_notices';
22
+
23
+	/**
24
+	 *    stores details for all exception
25
+	 *
26
+	 * @var array
27
+	 */
28
+	private static $_all_exceptions = [];
29
+
30
+	/**
31
+	 *    tracks number of errors
32
+	 *
33
+	 * @var int
34
+	 */
35
+	private static $_error_count = 0;
36
+
37
+	/**
38
+	 * @var array $_espresso_notices
39
+	 */
40
+	private static $_espresso_notices = ['success' => false, 'errors' => false, 'attention' => false];
41
+
42
+
43
+	/**
44
+	 * @override default exception handling
45
+	 * @param string         $message
46
+	 * @param int            $code
47
+	 * @param Exception|null $previous
48
+	 */
49
+	public function __construct($message, $code = 0, Exception $previous = null)
50
+	{
51
+		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
52
+			parent::__construct($message, $code);
53
+		} else {
54
+			parent::__construct($message, $code, $previous);
55
+		}
56
+	}
57
+
58
+
59
+	/**
60
+	 *    error_handler
61
+	 *
62
+	 * @param int  $code
63
+	 * @param string $message
64
+	 * @param string $file
65
+	 * @param int|string $line
66
+	 * @return void
67
+	 */
68
+	public static function error_handler(int $code, string $message, string $file, $line)
69
+	{
70
+		$type    = EE_Error::error_type($code);
71
+		$site    = site_url();
72
+		$to      = strpos($site, 'eventespresso.com')
73
+			? '[email protected]'
74
+			: get_option('admin_email');
75
+		$subject = "$type $message in " . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
76
+		$msg     = EE_Error::_format_error($type, $message, $file, $line);
77
+		if (function_exists('wp_mail')) {
78
+			add_filter('wp_mail_content_type', ['EE_Error', 'set_content_type']);
79
+			wp_mail($to, $subject, $msg);
80
+		}
81
+		echo '<div id="message" class="espresso-notices error"><p>';
82
+		echo wp_kses($type . ': ' . $message . '<br />' . $file . ' line ' . $line, AllowedTags::getWithFormTags());
83
+		echo '<br /></p></div>';
84
+	}
85
+
86
+
87
+	/**
88
+	 * error_type
89
+	 * http://www.php.net/manual/en/errorfunc.constants.php#109430
90
+	 *
91
+	 * @param int $code
92
+	 * @return string
93
+	 */
94
+	public static function error_type(int $code): string
95
+	{
96
+		switch ($code) {
97
+			case E_ERROR: // 1 //
98
+				return 'E_ERROR';
99
+			case E_WARNING: // 2 //
100
+				return 'E_WARNING';
101
+			case E_PARSE: // 4 //
102
+				return 'E_PARSE';
103
+			case E_NOTICE: // 8 //
104
+				return 'E_NOTICE';
105
+			case E_CORE_ERROR: // 16 //
106
+				return 'E_CORE_ERROR';
107
+			case E_CORE_WARNING: // 32 //
108
+				return 'E_CORE_WARNING';
109
+			case E_COMPILE_ERROR: // 64 //
110
+				return 'E_COMPILE_ERROR';
111
+			case E_COMPILE_WARNING: // 128 //
112
+				return 'E_COMPILE_WARNING';
113
+			case E_USER_ERROR: // 256 //
114
+				return 'E_USER_ERROR';
115
+			case E_USER_WARNING: // 512 //
116
+				return 'E_USER_WARNING';
117
+			case E_USER_NOTICE: // 1024 //
118
+				return 'E_USER_NOTICE';
119
+			case E_STRICT: // 2048 //
120
+				return 'E_STRICT';
121
+			case E_RECOVERABLE_ERROR: // 4096 //
122
+				return 'E_RECOVERABLE_ERROR';
123
+			case E_DEPRECATED: // 8192 //
124
+				return 'E_DEPRECATED';
125
+			case E_USER_DEPRECATED: // 16384 //
126
+				return 'E_USER_DEPRECATED';
127
+			case E_ALL: // 16384 //
128
+				return 'E_ALL';
129
+		}
130
+		return '';
131
+	}
132
+
133
+
134
+	/**
135
+	 *    fatal_error_handler
136
+	 *
137
+	 * @return void
138
+	 */
139
+	public static function fatal_error_handler()
140
+	{
141
+		$last_error = error_get_last();
142
+		if ($last_error['type'] === E_ERROR) {
143
+			EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
144
+		}
145
+	}
146
+
147
+
148
+	/**
149
+	 * _format_error
150
+	 *
151
+	 * @param $code
152
+	 * @param $message
153
+	 * @param $file
154
+	 * @param $line
155
+	 * @return string
156
+	 */
157
+	private static function _format_error($code, $message, $file, $line): string
158
+	{
159
+		$html =
160
+			"<table><thead><th>Item</th><th>Details</th></thead><tbody>";
161
+		$html .= "<tr><td><b>Code</b></td><td>$code</td></tr>";
162
+		$html .= "<tr><td><b>Error</b></td><td>$message</td></tr>";
163
+		$html .= "<tr><td><b>File</b></td><td>$file</td></tr>";
164
+		$html .= "<tr><td><b>Line</b></td><td>$line</td></tr>";
165
+		$html .= '</tbody></table>';
166
+		return $html;
167
+	}
168
+
169
+
170
+	/**
171
+	 * set_content_type
172
+	 *
173
+	 * @param $content_type
174
+	 * @return string
175
+	 */
176
+	public static function set_content_type($content_type): string
177
+	{
178
+		return 'text/html';
179
+	}
180
+
181
+
182
+	/**
183
+	 * @return void
184
+	 * @throws EE_Error
185
+	 * @throws ReflectionException
186
+	 */
187
+	public function get_error()
188
+	{
189
+		if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
190
+			throw $this;
191
+		}
192
+		// get separate user and developer messages if they exist
193
+		$msg      = explode('||', $this->getMessage());
194
+		$user_msg = $msg[0];
195
+		$dev_msg  = $msg[1] ?? $msg[0];
196
+		$msg      = WP_DEBUG ? $dev_msg : $user_msg;
197
+		// add details to _all_exceptions array
198
+		$x_time                                     = time();
199
+		self::$_all_exceptions[ $x_time ]['name']   = get_class($this);
200
+		self::$_all_exceptions[ $x_time ]['file']   = $this->getFile();
201
+		self::$_all_exceptions[ $x_time ]['line']   = $this->getLine();
202
+		self::$_all_exceptions[ $x_time ]['msg']    = $msg;
203
+		self::$_all_exceptions[ $x_time ]['code']   = $this->getCode();
204
+		self::$_all_exceptions[ $x_time ]['trace']  = $this->getTrace();
205
+		self::$_all_exceptions[ $x_time ]['string'] = $this->getTraceAsString();
206
+		self::$_error_count++;
207
+		// add_action( 'shutdown', array( $this, 'display_errors' ));
208
+		$this->display_errors();
209
+	}
210
+
211
+
212
+	/**
213
+	 * @param bool   $check_stored
214
+	 * @param string $type_to_check
215
+	 * @return bool
216
+	 * @throws InvalidInterfaceException
217
+	 * @throws InvalidArgumentException
218
+	 * @throws InvalidDataTypeException
219
+	 */
220
+	public static function has_error(bool $check_stored = false, string $type_to_check = 'errors'): bool
221
+	{
222
+		$has_error = isset(self::$_espresso_notices[ $type_to_check ])
223
+					 && ! empty(self::$_espresso_notices[ $type_to_check ]);
224
+		if ($check_stored && ! $has_error) {
225
+			$notices = EE_Error::getStoredNotices();
226
+			foreach ($notices as $type => $notice) {
227
+				if ($type === $type_to_check && $notice) {
228
+					return true;
229
+				}
230
+			}
231
+		}
232
+		return $has_error;
233
+	}
234
+
235
+
236
+	/**
237
+	 * @echo string
238
+	 * @throws ReflectionException
239
+	 */
240
+	public function display_errors()
241
+	{
242
+		$trace_details = '';
243
+		$output = '
244 244
         <div id="ee-error-message" class="error">';
245
-        if (! WP_DEBUG) {
246
-            $output .= '
245
+		if (! WP_DEBUG) {
246
+			$output .= '
247 247
 	        <p>';
248
-        }
249
-        // cycle thru errors
250
-        foreach (self::$_all_exceptions as $time => $ex) {
251
-            $error_code = '';
252
-            // process trace info
253
-            if (empty($ex['trace'])) {
254
-                $trace_details .= esc_html__(
255
-                    'Sorry, but no trace information was available for this exception.',
256
-                    'event_espresso'
257
-                );
258
-            } else {
259
-                $trace_details .= '
248
+		}
249
+		// cycle thru errors
250
+		foreach (self::$_all_exceptions as $time => $ex) {
251
+			$error_code = '';
252
+			// process trace info
253
+			if (empty($ex['trace'])) {
254
+				$trace_details .= esc_html__(
255
+					'Sorry, but no trace information was available for this exception.',
256
+					'event_espresso'
257
+				);
258
+			} else {
259
+				$trace_details .= '
260 260
 			<div id="ee-trace-details">
261 261
 			<table>
262 262
 				<tr>
@@ -266,43 +266,43 @@  discard block
 block discarded – undo
266 266
 					<th scope="col">Class</th>
267 267
 					<th scope="col">Method( arguments )</th>
268 268
 				</tr>';
269
-                $last_on_stack = count($ex['trace']) - 1;
270
-                // reverse array so that stack is in proper chronological order
271
-                $sorted_trace = array_reverse($ex['trace']);
272
-                foreach ($sorted_trace as $number => $trace) {
273
-                    $file     = $trace['file'] ?? '';
274
-                    $class    = $trace['class'] ?? '';
275
-                    $type     = $trace['type'] ?? '';
276
-                    $function = $trace['function'] ?? '';
277
-                    $args     = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
278
-                    $line     = $trace['line'] ?? '';
279
-                    $zebra    = ($number % 2) ? ' odd' : '';
280
-                    if (empty($file) && ! empty($class)) {
281
-                        $a    = new ReflectionClass($class);
282
-                        $file = $a->getFileName();
283
-                        if (empty($line) && ! empty($function)) {
284
-                            try {
285
-                                // if $function is a closure, this throws an exception
286
-                                $b    = new ReflectionMethod($class, $function);
287
-                                $line = $b->getStartLine();
288
-                            } catch (Exception $closure_exception) {
289
-                                $line = 'unknown';
290
-                            }
291
-                        }
292
-                    }
293
-                    if ($number === $last_on_stack) {
294
-                        $file       = $ex['file'] !== '' ? $ex['file'] : $file;
295
-                        $line       = $ex['line'] !== '' ? $ex['line'] : $line;
296
-                        $error_code = self::generate_error_code($file, $trace['function'], $line);
297
-                    }
298
-                    $number_display   = ! empty($number) ? $number : '&nbsp;';
299
-                    $line_display     = ! empty($line) ? $line : '&nbsp;';
300
-                    $file_display     = ! empty($file) ? $file : '&nbsp;';
301
-                    $class_display    = ! empty($class) ? $class : '&nbsp;';
302
-                    $type_display     = ! empty($type) ? $type : '&nbsp;';
303
-                    $function_display = ! empty($function) ? $function : '&nbsp;';
304
-                    $args_display     = ! empty($args) ? '( ' . $args . ' )' : '';
305
-                    $trace_details    .= '
269
+				$last_on_stack = count($ex['trace']) - 1;
270
+				// reverse array so that stack is in proper chronological order
271
+				$sorted_trace = array_reverse($ex['trace']);
272
+				foreach ($sorted_trace as $number => $trace) {
273
+					$file     = $trace['file'] ?? '';
274
+					$class    = $trace['class'] ?? '';
275
+					$type     = $trace['type'] ?? '';
276
+					$function = $trace['function'] ?? '';
277
+					$args     = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
278
+					$line     = $trace['line'] ?? '';
279
+					$zebra    = ($number % 2) ? ' odd' : '';
280
+					if (empty($file) && ! empty($class)) {
281
+						$a    = new ReflectionClass($class);
282
+						$file = $a->getFileName();
283
+						if (empty($line) && ! empty($function)) {
284
+							try {
285
+								// if $function is a closure, this throws an exception
286
+								$b    = new ReflectionMethod($class, $function);
287
+								$line = $b->getStartLine();
288
+							} catch (Exception $closure_exception) {
289
+								$line = 'unknown';
290
+							}
291
+						}
292
+					}
293
+					if ($number === $last_on_stack) {
294
+						$file       = $ex['file'] !== '' ? $ex['file'] : $file;
295
+						$line       = $ex['line'] !== '' ? $ex['line'] : $line;
296
+						$error_code = self::generate_error_code($file, $trace['function'], $line);
297
+					}
298
+					$number_display   = ! empty($number) ? $number : '&nbsp;';
299
+					$line_display     = ! empty($line) ? $line : '&nbsp;';
300
+					$file_display     = ! empty($file) ? $file : '&nbsp;';
301
+					$class_display    = ! empty($class) ? $class : '&nbsp;';
302
+					$type_display     = ! empty($type) ? $type : '&nbsp;';
303
+					$function_display = ! empty($function) ? $function : '&nbsp;';
304
+					$args_display     = ! empty($args) ? '( ' . $args . ' )' : '';
305
+					$trace_details    .= '
306 306
 					<tr>
307 307
 						<td class="' . $zebra . '">' . $number_display . '</td>
308 308
 						<td class="' . $zebra . '">' . $line_display . '</td>
@@ -310,645 +310,645 @@  discard block
 block discarded – undo
310 310
 						<td class="' . $zebra . '">' . $class_display . '</td>
311 311
 						<td class="' . $zebra . '">' . $type_display . $function_display . $args_display . '</td>
312 312
 					</tr>';
313
-                }
314
-                $trace_details .= '
313
+				}
314
+				$trace_details .= '
315 315
 			 </table>
316 316
 			</div>';
317
-            }
318
-            $ex['code'] = $ex['code'] ?: $error_code;
319
-            // add generic non-identifying messages for non-privileged users
320
-            if (! WP_DEBUG) {
321
-                $output .= '<span class="ee-error-user-msg-spn">'
322
-                           . trim($ex['msg'])
323
-                           . '</span> &nbsp; <sup>'
324
-                           . $ex['code']
325
-                           . '</sup><br />';
326
-            } else {
327
-                // or helpful developer messages if debugging is on
328
-                $output .= '
317
+			}
318
+			$ex['code'] = $ex['code'] ?: $error_code;
319
+			// add generic non-identifying messages for non-privileged users
320
+			if (! WP_DEBUG) {
321
+				$output .= '<span class="ee-error-user-msg-spn">'
322
+						   . trim($ex['msg'])
323
+						   . '</span> &nbsp; <sup>'
324
+						   . $ex['code']
325
+						   . '</sup><br />';
326
+			} else {
327
+				// or helpful developer messages if debugging is on
328
+				$output .= '
329 329
 		<div class="ee-error-dev-msg-dv">
330 330
 			<p class="ee-error-dev-msg-pg">
331 331
 				<strong class="ee-error-dev-msg-str">An '
332
-                           . $ex['name']
333
-                           . ' exception was thrown!</strong>  &nbsp; <span>code: '
334
-                           . $ex['code']
335
-                           . '</span><br />
332
+						   . $ex['name']
333
+						   . ' exception was thrown!</strong>  &nbsp; <span>code: '
334
+						   . $ex['code']
335
+						   . '</span><br />
336 336
 				<span class="big-text">"'
337
-                           . trim($ex['msg'])
338
-                           . '"</span><br/>
337
+						   . trim($ex['msg'])
338
+						   . '"</span><br/>
339 339
 				<a id="display-ee-error-trace-'
340
-                           . self::$_error_count
341
-                           . $time
342
-                           . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
343
-                           . self::$_error_count
344
-                           . $time
345
-                           . '">
340
+						   . self::$_error_count
341
+						   . $time
342
+						   . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
343
+						   . self::$_error_count
344
+						   . $time
345
+						   . '">
346 346
 					'
347
-                           . esc_html__('click to view backtrace and class/method details', 'event_espresso')
348
-                           . '
347
+						   . esc_html__('click to view backtrace and class/method details', 'event_espresso')
348
+						   . '
349 349
 				</a><br />
350 350
 				<span class="small-text lt-grey-text">'
351
-                           . $ex['file']
352
-                           . ' &nbsp; ( line no: '
353
-                           . $ex['line']
354
-                           . ' )</span>
351
+						   . $ex['file']
352
+						   . ' &nbsp; ( line no: '
353
+						   . $ex['line']
354
+						   . ' )</span>
355 355
 			</p>
356 356
 			<div id="ee-error-trace-'
357
-                           . self::$_error_count
358
-                           . $time
359
-                           . '-dv" class="ee-error-trace-dv" style="display: none;">
357
+						   . self::$_error_count
358
+						   . $time
359
+						   . '-dv" class="ee-error-trace-dv" style="display: none;">
360 360
 				'
361
-                           . $trace_details;
362
-                if (! empty($class)) {
363
-                    $output .= '
361
+						   . $trace_details;
362
+				if (! empty($class)) {
363
+					$output .= '
364 364
 				<div style="padding:3px; margin:0 0 1em; border:1px solid #666; background:#fff; border-radius:3px;">
365 365
 					<div style="padding:1em 2em; border:1px solid #666; background:#f9f9f9;">
366 366
 						<h3>Class Details</h3>';
367
-                    $a      = new ReflectionClass($class);
368
-                    $output .= '
367
+					$a      = new ReflectionClass($class);
368
+					$output .= '
369 369
 						<pre>' . $a . '</pre>
370 370
 					</div>
371 371
 				</div>';
372
-                }
373
-                $output .= '
372
+				}
373
+				$output .= '
374 374
 			</div>
375 375
 		</div>
376 376
 		<br />';
377
-            }
378
-            $this->write_to_error_log($time, $ex);
379
-        }
380
-        // remove last linebreak
381
-        $output = substr($output, 0, -6);
382
-        if (! WP_DEBUG) {
383
-            $output .= '
377
+			}
378
+			$this->write_to_error_log($time, $ex);
379
+		}
380
+		// remove last linebreak
381
+		$output = substr($output, 0, -6);
382
+		if (! WP_DEBUG) {
383
+			$output .= '
384 384
 	        </p>';
385
-        }
386
-        $output .= '
385
+		}
386
+		$output .= '
387 387
         </div>';
388
-        $output .= self::_print_scripts(true);
389
-        if (defined('DOING_AJAX')) {
390
-            echo wp_json_encode(['error' => $output]);
391
-            exit();
392
-        }
393
-        echo wp_kses($output, AllowedTags::getWithFormTags());
394
-        die();
395
-    }
396
-
397
-
398
-    /**
399
-     *    generate string from exception trace args
400
-     *
401
-     * @param array $arguments
402
-     * @param bool  $array
403
-     * @return string
404
-     */
405
-    private function _convert_args_to_string(array $arguments = [], bool $array = false): string
406
-    {
407
-        $arg_string = '';
408
-        if (! empty($arguments)) {
409
-            $args = [];
410
-            foreach ($arguments as $arg) {
411
-                if (! empty($arg)) {
412
-                    if (is_string($arg)) {
413
-                        $args[] = " '" . $arg . "'";
414
-                    } elseif (is_array($arg)) {
415
-                        $args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
416
-                    } elseif (is_bool($arg)) {
417
-                        $args[] = $arg ? ' TRUE' : ' FALSE';
418
-                    } elseif (is_object($arg)) {
419
-                        $args[] = ' OBJECT ' . get_class($arg);
420
-                    } elseif (is_resource($arg)) {
421
-                        $args[] = get_resource_type($arg);
422
-                    } else {
423
-                        $args[] = $arg;
424
-                    }
425
-                } else {
426
-                    $args[] = ' NULL';
427
-                }
428
-            }
429
-            $arg_string = implode(', ', $args);
430
-        }
431
-        if ($array) {
432
-            $arg_string .= ' )';
433
-        }
434
-        return $arg_string;
435
-    }
436
-
437
-
438
-    /**
439
-     *    add error message
440
-     *
441
-     * @param string $msg         the message to display to users or developers - adding a double pipe || (OR) creates
442
-     *                            separate messages for user || dev
443
-     * @param string $file        the file that the error occurred in - just use __FILE__
444
-     * @param string $func        the function/method that the error occurred in - just use __FUNCTION__
445
-     * @param int|string $line        the line number where the error occurred - just use __LINE__
446
-     * @return        void
447
-     */
448
-    public static function add_error(string $msg, string $file, string $func, $line)
449
-    {
450
-        self::_add_notice('errors', $msg, $file, $func, $line);
451
-        self::$_error_count++;
452
-    }
453
-
454
-
455
-    /**
456
-     * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
457
-     * adds an error
458
-     *
459
-     * @param string $msg
460
-     * @param string $file
461
-     * @param string $func
462
-     * @param int|string $line
463
-     * @throws EE_Error
464
-     */
465
-    public static function throw_exception_if_debugging(
466
-        string $msg = '',
467
-        string $file = '',
468
-        string $func = '',
469
-        $line = ''
470
-    ) {
471
-        if (WP_DEBUG) {
472
-            throw new EE_Error($msg);
473
-        }
474
-        EE_Error::add_error($msg, $file, $func, $line);
475
-    }
476
-
477
-
478
-    /**
479
-     *    add success message
480
-     *
481
-     * @param string $msg         the message to display to users or developers - adding a double pipe || (OR) creates
482
-     *                            separate messages for user || dev
483
-     * @param string $file        the file that the error occurred in - just use __FILE__
484
-     * @param string $func        the function/method that the error occurred in - just use __FUNCTION__
485
-     * @param int|string $line        the line number where the error occurred - just use __LINE__
486
-     * @return void
487
-     */
488
-    public static function add_success(string $msg = '', string $file = '', string $func = '', $line = '')
489
-    {
490
-        self::_add_notice('success', $msg, $file, $func, $line);
491
-    }
492
-
493
-
494
-    /**
495
-     *    add attention message
496
-     *
497
-     * @param string $msg         the message to display to users or developers - adding a double pipe || (OR) creates
498
-     *                            separate messages for user || dev
499
-     * @param string $file        the file that the error occurred in - just use __FILE__
500
-     * @param string $func        the function/method that the error occurred in - just use __FUNCTION__
501
-     * @param int|string $line        the line number where the error occurred - just use __LINE__
502
-     * @return        void
503
-     */
504
-    public static function add_attention(string $msg = '', string $file = '', string $func = '', $line = '')
505
-    {
506
-        self::_add_notice('attention', $msg, $file, $func, $line);
507
-    }
508
-
509
-
510
-    /**
511
-     * @param string $type whether the message is for a success or error notification
512
-     * @param string $msg  the message to display to users or developers
513
-     *                     - adding a double pipe || (OR) creates separate messages for user || dev
514
-     * @param string $file the file that the error occurred in - just use __FILE__
515
-     * @param string $func the function/method that the error occurred in - just use __FUNCTION__
516
-     * @param int|string $line the line number where the error occurred - just use __LINE__
517
-     * @return void
518
-     */
519
-    private static function _add_notice(
520
-        string $type = 'success',
521
-        string $msg = '',
522
-        string $file = '',
523
-        string $func = '',
524
-        $line = ''
525
-    ) {
526
-        if (empty($msg)) {
527
-            EE_Error::doing_it_wrong(
528
-                'EE_Error::add_' . $type . '()',
529
-                sprintf(
530
-                    esc_html__(
531
-                        'Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
532
-                        'event_espresso'
533
-                    ),
534
-                    $type,
535
-                    $file,
536
-                    $line
537
-                ),
538
-                EVENT_ESPRESSO_VERSION
539
-            );
540
-        }
541
-        if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
542
-            EE_Error::doing_it_wrong(
543
-                'EE_Error::add_error()',
544
-                esc_html__(
545
-                    'You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
546
-                    'event_espresso'
547
-                ),
548
-                EVENT_ESPRESSO_VERSION
549
-            );
550
-        }
551
-        // get separate user and developer messages if they exist
552
-        $msg      = explode('||', $msg);
553
-        $user_msg = $msg[0];
554
-        $dev_msg  = $msg[1] ?? $msg[0];
555
-        /**
556
-         * Do an action so other code can be triggered when a notice is created
557
-         *
558
-         * @param string $type     can be 'errors', 'attention', or 'success'
559
-         * @param string $user_msg message displayed to user when WP_DEBUG is off
560
-         * @param string $user_msg message displayed to user when WP_DEBUG is on
561
-         * @param string $file     file where error was generated
562
-         * @param string $func     function where error was generated
563
-         * @param int|string $line     line where error was generated
564
-         */
565
-        do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
566
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
567
-        // add notice if message exists
568
-        if (! empty($msg)) {
569
-            // get error code
570
-            $notice_code = EE_Error::generate_error_code($file, $func, $line);
571
-            if (WP_DEBUG && $type === 'errors') {
572
-                $msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
573
-            }
574
-
575
-            if (! is_array(self::$_espresso_notices[ $type ]) || ! array_key_exists($type, self::$_espresso_notices)) {
576
-                self::$_espresso_notices[ $type ] = [];
577
-            }
578
-
579
-            // add notice. Index by code if it's not blank
580
-            if ($notice_code) {
581
-                self::$_espresso_notices[ $type ][ $notice_code ] = $msg;
582
-            } else {
583
-                self::$_espresso_notices[ $type ][] = $msg;
584
-            }
585
-            add_action('wp_footer', ['EE_Error', 'enqueue_error_scripts'], 1);
586
-        }
587
-    }
588
-
589
-
590
-    /**
591
-     * in some case it may be necessary to overwrite the existing success messages
592
-     *
593
-     * @return        void
594
-     */
595
-    public static function overwrite_success()
596
-    {
597
-        self::$_espresso_notices['success'] = [];
598
-    }
599
-
600
-
601
-    /**
602
-     * in some case it may be necessary to overwrite the existing attention messages
603
-     *
604
-     * @return void
605
-     */
606
-    public static function overwrite_attention()
607
-    {
608
-        self::$_espresso_notices['attention'] = [];
609
-    }
610
-
611
-
612
-    /**
613
-     * in some case it may be necessary to overwrite the existing error messages
614
-     *
615
-     * @return void
616
-     */
617
-    public static function overwrite_errors()
618
-    {
619
-        self::$_espresso_notices['errors'] = [];
620
-    }
621
-
622
-
623
-    /**
624
-     * @return void
625
-     */
626
-    public static function reset_notices()
627
-    {
628
-        self::$_espresso_notices['success']   = [];
629
-        self::$_espresso_notices['attention'] = [];
630
-        self::$_espresso_notices['errors']    = [];
631
-    }
632
-
633
-
634
-    /**
635
-     * @return int
636
-     */
637
-    public static function has_notices(): int
638
-    {
639
-        $has_notices = 0;
640
-        // check for success messages
641
-        $has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])
642
-            ? 3
643
-            : $has_notices;
644
-        // check for attention messages
645
-        $has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])
646
-            ? 2
647
-            : $has_notices;
648
-        // check for error messages
649
-        return self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])
650
-            ? 1
651
-            : $has_notices;
652
-    }
653
-
654
-
655
-    /**
656
-     * This simply returns non formatted error notices as they were sent into the EE_Error object.
657
-     *
658
-     * @return array
659
-     * @since 4.9.0
660
-     */
661
-    public static function get_vanilla_notices(): array
662
-    {
663
-        return [
664
-            'success'   => self::$_espresso_notices['success'] ?? [],
665
-            'attention' => self::$_espresso_notices['attention'] ?? [],
666
-            'errors'    => self::$_espresso_notices['errors'] ?? [],
667
-        ];
668
-    }
669
-
670
-
671
-    /**
672
-     * @return array
673
-     * @throws InvalidArgumentException
674
-     * @throws InvalidDataTypeException
675
-     * @throws InvalidInterfaceException
676
-     */
677
-    public static function getStoredNotices(): array
678
-    {
679
-        if ($user_id = get_current_user_id()) {
680
-            // get notices for logged in user
681
-            $notices = get_user_option(EE_Error::OPTIONS_KEY_NOTICES, $user_id);
682
-            return is_array($notices) ? $notices : [];
683
-        }
684
-        if (EE_Session::isLoadedAndActive()) {
685
-            // get notices for user currently engaged in a session
686
-            $session_data = EE_Session::instance()->get_session_data(EE_Error::OPTIONS_KEY_NOTICES);
687
-            return is_array($session_data) ? $session_data : [];
688
-        }
689
-        // get global notices and hope they apply to the current site visitor
690
-        $notices = get_option(EE_Error::OPTIONS_KEY_NOTICES, []);
691
-        return is_array($notices) ? $notices : [];
692
-    }
693
-
694
-
695
-    /**
696
-     * @param array $notices
697
-     * @return bool
698
-     * @throws InvalidArgumentException
699
-     * @throws InvalidDataTypeException
700
-     * @throws InvalidInterfaceException
701
-     */
702
-    public static function storeNotices(array $notices): bool
703
-    {
704
-        if ($user_id = get_current_user_id()) {
705
-            // store notices for logged in user
706
-            return (bool) update_user_option(
707
-                $user_id,
708
-                EE_Error::OPTIONS_KEY_NOTICES,
709
-                $notices
710
-            );
711
-        }
712
-        if (EE_Session::isLoadedAndActive()) {
713
-            // store notices for user currently engaged in a session
714
-            return EE_Session::instance()->set_session_data(
715
-                [EE_Error::OPTIONS_KEY_NOTICES => $notices]
716
-            );
717
-        }
718
-        // store global notices and hope they apply to the same site visitor on the next request
719
-        return update_option(EE_Error::OPTIONS_KEY_NOTICES, $notices);
720
-    }
721
-
722
-
723
-    /**
724
-     * @return bool
725
-     * @throws InvalidArgumentException
726
-     * @throws InvalidDataTypeException
727
-     * @throws InvalidInterfaceException
728
-     */
729
-    public static function clearNotices(): bool
730
-    {
731
-        if ($user_id = get_current_user_id()) {
732
-            // clear notices for logged in user
733
-            return (bool) update_user_option(
734
-                $user_id,
735
-                EE_Error::OPTIONS_KEY_NOTICES,
736
-                []
737
-            );
738
-        }
739
-        if (EE_Session::isLoadedAndActive()) {
740
-            // clear notices for user currently engaged in a session
741
-            return EE_Session::instance()->reset_data([EE_Error::OPTIONS_KEY_NOTICES]);
742
-        }
743
-        // clear global notices and hope none belonged to some for some other site visitor
744
-        return update_option(EE_Error::OPTIONS_KEY_NOTICES, []);
745
-    }
746
-
747
-
748
-    /**
749
-     * saves notices to the db for retrieval on next request
750
-     *
751
-     * @return void
752
-     * @throws InvalidArgumentException
753
-     * @throws InvalidDataTypeException
754
-     * @throws InvalidInterfaceException
755
-     */
756
-    public static function stashNoticesBeforeRedirect()
757
-    {
758
-        EE_Error::get_notices(false, true);
759
-    }
760
-
761
-
762
-    /**
763
-     * compile all error or success messages into one string
764
-     *
765
-     * @param boolean $format_output            whether or not to format the messages for display in the WP admin
766
-     * @param boolean $save_to_transient        whether or not to save notices to the db for retrieval on next request
767
-     *                                          - ONLY do this just before redirecting
768
-     * @param bool $remove_empty             whether or not to unset empty messages
769
-     * @return array|string
770
-     * @throws InvalidArgumentException
771
-     * @throws InvalidDataTypeException
772
-     * @throws InvalidInterfaceException
773
-     * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
774
-     */
775
-    public static function get_notices(
776
-        bool $format_output = true,
777
-        bool $save_to_transient = false,
778
-        bool $remove_empty = true
779
-    ) {
780
-        $success_messages   = '';
781
-        $attention_messages = '';
782
-        $error_messages     = '';
783
-        /** @var RequestInterface $request */
784
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
785
-        // either save notices to the db
786
-        if ($save_to_transient || $request->requestParamIsSet('activate-selected')) {
787
-            self::$_espresso_notices = array_merge(
788
-                EE_Error::getStoredNotices(),
789
-                self::$_espresso_notices
790
-            );
791
-            EE_Error::storeNotices(self::$_espresso_notices);
792
-            return [];
793
-        }
794
-        $print_scripts = EE_Error::combineExistingAndNewNotices();
795
-        // check for success messages
796
-        if (! empty(self::$_espresso_notices['success'])) {
797
-            // combine messages
798
-            $success_messages .= implode('<br />', self::$_espresso_notices['success']);
799
-            $print_scripts    = true;
800
-        }
801
-        // check for attention messages
802
-        if (! empty(self::$_espresso_notices['attention'])) {
803
-            // combine messages
804
-            $attention_messages .= implode('<br />', self::$_espresso_notices['attention']);
805
-            $print_scripts      = true;
806
-        }
807
-        // check for error messages
808
-        if (! empty(self::$_espresso_notices['errors'])) {
809
-            $error_messages .= count(self::$_espresso_notices['errors']) > 1
810
-                ? esc_html__('The following errors have occurred:', 'event_espresso')
811
-                : esc_html__('An error has occurred:', 'event_espresso');
812
-            // combine messages
813
-            $error_messages .= '<br />' . implode('<br />', self::$_espresso_notices['errors']);
814
-            $print_scripts  = true;
815
-        }
816
-        if ($format_output) {
817
-            $notices = EE_Error::formatNoticesOutput(
818
-                $success_messages,
819
-                $attention_messages,
820
-                $error_messages
821
-            );
822
-        } else {
823
-            $notices = [
824
-                'success'   => $success_messages,
825
-                'attention' => $attention_messages,
826
-                'errors'    => $error_messages,
827
-            ];
828
-            if ($remove_empty) {
829
-                // remove empty notices
830
-                foreach ($notices as $type => $notice) {
831
-                    if (empty($notice)) {
832
-                        unset($notices[ $type ]);
833
-                    }
834
-                }
835
-            }
836
-        }
837
-        if ($print_scripts) {
838
-            self::_print_scripts();
839
-        }
840
-        return $notices;
841
-    }
842
-
843
-
844
-    /**
845
-     * @return bool
846
-     * @throws InvalidArgumentException
847
-     * @throws InvalidDataTypeException
848
-     * @throws InvalidInterfaceException
849
-     */
850
-    private static function combineExistingAndNewNotices(): bool
851
-    {
852
-        $print_scripts = false;
853
-        // grab any notices that have been previously saved
854
-        $notices = EE_Error::getStoredNotices();
855
-        if (! empty($notices)) {
856
-            foreach ($notices as $type => $notice) {
857
-                if (is_array($notice) && ! empty($notice)) {
858
-                    // make sure that existing notice type is an array
859
-                    self::$_espresso_notices[ $type ] = is_array(self::$_espresso_notices[ $type ])
860
-                                                        && ! empty(self::$_espresso_notices[ $type ])
861
-                        ? self::$_espresso_notices[ $type ]
862
-                        : [];
863
-                    // add newly created notices to existing ones
864
-                    self::$_espresso_notices[ $type ] += $notice;
865
-                    $print_scripts                    = true;
866
-                }
867
-            }
868
-            // now clear any stored notices
869
-            EE_Error::clearNotices();
870
-        }
871
-        return $print_scripts;
872
-    }
873
-
874
-
875
-    /**
876
-     * @param string $success_messages
877
-     * @param string $attention_messages
878
-     * @param string $error_messages
879
-     * @return string
880
-     */
881
-    private static function formatNoticesOutput(
882
-        string $success_messages,
883
-        string $attention_messages,
884
-        string $error_messages
885
-    ): string {
886
-        $notices = '<div id="espresso-notices">';
887
-        $close   = is_admin()
888
-            ? ''
889
-            : '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"/></a>';
890
-        if ($success_messages !== '') {
891
-            $css_id    = is_admin() ? 'ee-success-message' : 'espresso-notices-success';
892
-            $css_class = is_admin() ? 'updated fade ee-status-outline ee-status-bg--success' : 'success fade-away';
893
-            // showMessage( $success_messages );
894
-            $notices .= '<div id="' . $css_id . '" '
895
-                        . 'class="espresso-notices ' . $css_class . '" '
896
-                        . 'style="display:none;">'
897
-                        . '<p>' . $success_messages . '</p>'
898
-                        . $close
899
-                        . '</div>';
900
-        }
901
-        if ($attention_messages !== '') {
902
-            $css_id    = is_admin()  ? 'ee-attention-message' : 'espresso-notices-attention';
903
-            $css_class = is_admin()
904
-                ? 'notice notice-info ee-notices-attention ee-status-outline ee-status-bg--attention'
905
-                : 'attention fade-away';
906
-            // showMessage( $error_messages, TRUE );
907
-            $notices .= '<div id="' . $css_id . '" '
908
-                        . 'class="espresso-notices ' . $css_class . '" '
909
-                        . 'style="display:none;">'
910
-                        . '<p>' . $attention_messages . '</p>'
911
-                        . $close
912
-                        . '</div>';
913
-        }
914
-        if ($error_messages !== '') {
915
-            $css_id    = is_admin() ? 'ee-error-message' : 'espresso-notices-error';
916
-            $css_class = is_admin()
917
-                ? 'error ee-status-outline ee-status-bg--error'
918
-                : 'error fade-away';
919
-            // showMessage( $error_messages, TRUE );
920
-            $notices .= '<div id="' . $css_id . '" '
921
-                        . 'class="espresso-notices ' . $css_class . '" '
922
-                        . 'style="display:none;">'
923
-                        . '<p>' . $error_messages . '</p>'
924
-                        . $close
925
-                        . '</div>';
926
-        }
927
-        $notices .= '</div>';
928
-        return $notices;
929
-    }
930
-
931
-
932
-    /**
933
-     * _print_scripts
934
-     *
935
-     * @param bool $force_print
936
-     * @return    string
937
-     */
938
-    private static function _print_scripts(bool $force_print = false): string
939
-    {
940
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
941
-            if (wp_script_is('ee_error_js', 'registered')) {
942
-                wp_enqueue_style('espresso_default');
943
-                wp_enqueue_style('espresso_custom_css');
944
-                wp_enqueue_script('ee_error_js');
945
-            }
946
-            if (wp_script_is('ee_error_js')) {
947
-                wp_localize_script('ee_error_js', 'ee_settings', ['wp_debug' => WP_DEBUG]);
948
-                return '';
949
-            }
950
-        } else {
951
-            return '
388
+		$output .= self::_print_scripts(true);
389
+		if (defined('DOING_AJAX')) {
390
+			echo wp_json_encode(['error' => $output]);
391
+			exit();
392
+		}
393
+		echo wp_kses($output, AllowedTags::getWithFormTags());
394
+		die();
395
+	}
396
+
397
+
398
+	/**
399
+	 *    generate string from exception trace args
400
+	 *
401
+	 * @param array $arguments
402
+	 * @param bool  $array
403
+	 * @return string
404
+	 */
405
+	private function _convert_args_to_string(array $arguments = [], bool $array = false): string
406
+	{
407
+		$arg_string = '';
408
+		if (! empty($arguments)) {
409
+			$args = [];
410
+			foreach ($arguments as $arg) {
411
+				if (! empty($arg)) {
412
+					if (is_string($arg)) {
413
+						$args[] = " '" . $arg . "'";
414
+					} elseif (is_array($arg)) {
415
+						$args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
416
+					} elseif (is_bool($arg)) {
417
+						$args[] = $arg ? ' TRUE' : ' FALSE';
418
+					} elseif (is_object($arg)) {
419
+						$args[] = ' OBJECT ' . get_class($arg);
420
+					} elseif (is_resource($arg)) {
421
+						$args[] = get_resource_type($arg);
422
+					} else {
423
+						$args[] = $arg;
424
+					}
425
+				} else {
426
+					$args[] = ' NULL';
427
+				}
428
+			}
429
+			$arg_string = implode(', ', $args);
430
+		}
431
+		if ($array) {
432
+			$arg_string .= ' )';
433
+		}
434
+		return $arg_string;
435
+	}
436
+
437
+
438
+	/**
439
+	 *    add error message
440
+	 *
441
+	 * @param string $msg         the message to display to users or developers - adding a double pipe || (OR) creates
442
+	 *                            separate messages for user || dev
443
+	 * @param string $file        the file that the error occurred in - just use __FILE__
444
+	 * @param string $func        the function/method that the error occurred in - just use __FUNCTION__
445
+	 * @param int|string $line        the line number where the error occurred - just use __LINE__
446
+	 * @return        void
447
+	 */
448
+	public static function add_error(string $msg, string $file, string $func, $line)
449
+	{
450
+		self::_add_notice('errors', $msg, $file, $func, $line);
451
+		self::$_error_count++;
452
+	}
453
+
454
+
455
+	/**
456
+	 * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
457
+	 * adds an error
458
+	 *
459
+	 * @param string $msg
460
+	 * @param string $file
461
+	 * @param string $func
462
+	 * @param int|string $line
463
+	 * @throws EE_Error
464
+	 */
465
+	public static function throw_exception_if_debugging(
466
+		string $msg = '',
467
+		string $file = '',
468
+		string $func = '',
469
+		$line = ''
470
+	) {
471
+		if (WP_DEBUG) {
472
+			throw new EE_Error($msg);
473
+		}
474
+		EE_Error::add_error($msg, $file, $func, $line);
475
+	}
476
+
477
+
478
+	/**
479
+	 *    add success message
480
+	 *
481
+	 * @param string $msg         the message to display to users or developers - adding a double pipe || (OR) creates
482
+	 *                            separate messages for user || dev
483
+	 * @param string $file        the file that the error occurred in - just use __FILE__
484
+	 * @param string $func        the function/method that the error occurred in - just use __FUNCTION__
485
+	 * @param int|string $line        the line number where the error occurred - just use __LINE__
486
+	 * @return void
487
+	 */
488
+	public static function add_success(string $msg = '', string $file = '', string $func = '', $line = '')
489
+	{
490
+		self::_add_notice('success', $msg, $file, $func, $line);
491
+	}
492
+
493
+
494
+	/**
495
+	 *    add attention message
496
+	 *
497
+	 * @param string $msg         the message to display to users or developers - adding a double pipe || (OR) creates
498
+	 *                            separate messages for user || dev
499
+	 * @param string $file        the file that the error occurred in - just use __FILE__
500
+	 * @param string $func        the function/method that the error occurred in - just use __FUNCTION__
501
+	 * @param int|string $line        the line number where the error occurred - just use __LINE__
502
+	 * @return        void
503
+	 */
504
+	public static function add_attention(string $msg = '', string $file = '', string $func = '', $line = '')
505
+	{
506
+		self::_add_notice('attention', $msg, $file, $func, $line);
507
+	}
508
+
509
+
510
+	/**
511
+	 * @param string $type whether the message is for a success or error notification
512
+	 * @param string $msg  the message to display to users or developers
513
+	 *                     - adding a double pipe || (OR) creates separate messages for user || dev
514
+	 * @param string $file the file that the error occurred in - just use __FILE__
515
+	 * @param string $func the function/method that the error occurred in - just use __FUNCTION__
516
+	 * @param int|string $line the line number where the error occurred - just use __LINE__
517
+	 * @return void
518
+	 */
519
+	private static function _add_notice(
520
+		string $type = 'success',
521
+		string $msg = '',
522
+		string $file = '',
523
+		string $func = '',
524
+		$line = ''
525
+	) {
526
+		if (empty($msg)) {
527
+			EE_Error::doing_it_wrong(
528
+				'EE_Error::add_' . $type . '()',
529
+				sprintf(
530
+					esc_html__(
531
+						'Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
532
+						'event_espresso'
533
+					),
534
+					$type,
535
+					$file,
536
+					$line
537
+				),
538
+				EVENT_ESPRESSO_VERSION
539
+			);
540
+		}
541
+		if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
542
+			EE_Error::doing_it_wrong(
543
+				'EE_Error::add_error()',
544
+				esc_html__(
545
+					'You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
546
+					'event_espresso'
547
+				),
548
+				EVENT_ESPRESSO_VERSION
549
+			);
550
+		}
551
+		// get separate user and developer messages if they exist
552
+		$msg      = explode('||', $msg);
553
+		$user_msg = $msg[0];
554
+		$dev_msg  = $msg[1] ?? $msg[0];
555
+		/**
556
+		 * Do an action so other code can be triggered when a notice is created
557
+		 *
558
+		 * @param string $type     can be 'errors', 'attention', or 'success'
559
+		 * @param string $user_msg message displayed to user when WP_DEBUG is off
560
+		 * @param string $user_msg message displayed to user when WP_DEBUG is on
561
+		 * @param string $file     file where error was generated
562
+		 * @param string $func     function where error was generated
563
+		 * @param int|string $line     line where error was generated
564
+		 */
565
+		do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
566
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
567
+		// add notice if message exists
568
+		if (! empty($msg)) {
569
+			// get error code
570
+			$notice_code = EE_Error::generate_error_code($file, $func, $line);
571
+			if (WP_DEBUG && $type === 'errors') {
572
+				$msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
573
+			}
574
+
575
+			if (! is_array(self::$_espresso_notices[ $type ]) || ! array_key_exists($type, self::$_espresso_notices)) {
576
+				self::$_espresso_notices[ $type ] = [];
577
+			}
578
+
579
+			// add notice. Index by code if it's not blank
580
+			if ($notice_code) {
581
+				self::$_espresso_notices[ $type ][ $notice_code ] = $msg;
582
+			} else {
583
+				self::$_espresso_notices[ $type ][] = $msg;
584
+			}
585
+			add_action('wp_footer', ['EE_Error', 'enqueue_error_scripts'], 1);
586
+		}
587
+	}
588
+
589
+
590
+	/**
591
+	 * in some case it may be necessary to overwrite the existing success messages
592
+	 *
593
+	 * @return        void
594
+	 */
595
+	public static function overwrite_success()
596
+	{
597
+		self::$_espresso_notices['success'] = [];
598
+	}
599
+
600
+
601
+	/**
602
+	 * in some case it may be necessary to overwrite the existing attention messages
603
+	 *
604
+	 * @return void
605
+	 */
606
+	public static function overwrite_attention()
607
+	{
608
+		self::$_espresso_notices['attention'] = [];
609
+	}
610
+
611
+
612
+	/**
613
+	 * in some case it may be necessary to overwrite the existing error messages
614
+	 *
615
+	 * @return void
616
+	 */
617
+	public static function overwrite_errors()
618
+	{
619
+		self::$_espresso_notices['errors'] = [];
620
+	}
621
+
622
+
623
+	/**
624
+	 * @return void
625
+	 */
626
+	public static function reset_notices()
627
+	{
628
+		self::$_espresso_notices['success']   = [];
629
+		self::$_espresso_notices['attention'] = [];
630
+		self::$_espresso_notices['errors']    = [];
631
+	}
632
+
633
+
634
+	/**
635
+	 * @return int
636
+	 */
637
+	public static function has_notices(): int
638
+	{
639
+		$has_notices = 0;
640
+		// check for success messages
641
+		$has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])
642
+			? 3
643
+			: $has_notices;
644
+		// check for attention messages
645
+		$has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])
646
+			? 2
647
+			: $has_notices;
648
+		// check for error messages
649
+		return self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])
650
+			? 1
651
+			: $has_notices;
652
+	}
653
+
654
+
655
+	/**
656
+	 * This simply returns non formatted error notices as they were sent into the EE_Error object.
657
+	 *
658
+	 * @return array
659
+	 * @since 4.9.0
660
+	 */
661
+	public static function get_vanilla_notices(): array
662
+	{
663
+		return [
664
+			'success'   => self::$_espresso_notices['success'] ?? [],
665
+			'attention' => self::$_espresso_notices['attention'] ?? [],
666
+			'errors'    => self::$_espresso_notices['errors'] ?? [],
667
+		];
668
+	}
669
+
670
+
671
+	/**
672
+	 * @return array
673
+	 * @throws InvalidArgumentException
674
+	 * @throws InvalidDataTypeException
675
+	 * @throws InvalidInterfaceException
676
+	 */
677
+	public static function getStoredNotices(): array
678
+	{
679
+		if ($user_id = get_current_user_id()) {
680
+			// get notices for logged in user
681
+			$notices = get_user_option(EE_Error::OPTIONS_KEY_NOTICES, $user_id);
682
+			return is_array($notices) ? $notices : [];
683
+		}
684
+		if (EE_Session::isLoadedAndActive()) {
685
+			// get notices for user currently engaged in a session
686
+			$session_data = EE_Session::instance()->get_session_data(EE_Error::OPTIONS_KEY_NOTICES);
687
+			return is_array($session_data) ? $session_data : [];
688
+		}
689
+		// get global notices and hope they apply to the current site visitor
690
+		$notices = get_option(EE_Error::OPTIONS_KEY_NOTICES, []);
691
+		return is_array($notices) ? $notices : [];
692
+	}
693
+
694
+
695
+	/**
696
+	 * @param array $notices
697
+	 * @return bool
698
+	 * @throws InvalidArgumentException
699
+	 * @throws InvalidDataTypeException
700
+	 * @throws InvalidInterfaceException
701
+	 */
702
+	public static function storeNotices(array $notices): bool
703
+	{
704
+		if ($user_id = get_current_user_id()) {
705
+			// store notices for logged in user
706
+			return (bool) update_user_option(
707
+				$user_id,
708
+				EE_Error::OPTIONS_KEY_NOTICES,
709
+				$notices
710
+			);
711
+		}
712
+		if (EE_Session::isLoadedAndActive()) {
713
+			// store notices for user currently engaged in a session
714
+			return EE_Session::instance()->set_session_data(
715
+				[EE_Error::OPTIONS_KEY_NOTICES => $notices]
716
+			);
717
+		}
718
+		// store global notices and hope they apply to the same site visitor on the next request
719
+		return update_option(EE_Error::OPTIONS_KEY_NOTICES, $notices);
720
+	}
721
+
722
+
723
+	/**
724
+	 * @return bool
725
+	 * @throws InvalidArgumentException
726
+	 * @throws InvalidDataTypeException
727
+	 * @throws InvalidInterfaceException
728
+	 */
729
+	public static function clearNotices(): bool
730
+	{
731
+		if ($user_id = get_current_user_id()) {
732
+			// clear notices for logged in user
733
+			return (bool) update_user_option(
734
+				$user_id,
735
+				EE_Error::OPTIONS_KEY_NOTICES,
736
+				[]
737
+			);
738
+		}
739
+		if (EE_Session::isLoadedAndActive()) {
740
+			// clear notices for user currently engaged in a session
741
+			return EE_Session::instance()->reset_data([EE_Error::OPTIONS_KEY_NOTICES]);
742
+		}
743
+		// clear global notices and hope none belonged to some for some other site visitor
744
+		return update_option(EE_Error::OPTIONS_KEY_NOTICES, []);
745
+	}
746
+
747
+
748
+	/**
749
+	 * saves notices to the db for retrieval on next request
750
+	 *
751
+	 * @return void
752
+	 * @throws InvalidArgumentException
753
+	 * @throws InvalidDataTypeException
754
+	 * @throws InvalidInterfaceException
755
+	 */
756
+	public static function stashNoticesBeforeRedirect()
757
+	{
758
+		EE_Error::get_notices(false, true);
759
+	}
760
+
761
+
762
+	/**
763
+	 * compile all error or success messages into one string
764
+	 *
765
+	 * @param boolean $format_output            whether or not to format the messages for display in the WP admin
766
+	 * @param boolean $save_to_transient        whether or not to save notices to the db for retrieval on next request
767
+	 *                                          - ONLY do this just before redirecting
768
+	 * @param bool $remove_empty             whether or not to unset empty messages
769
+	 * @return array|string
770
+	 * @throws InvalidArgumentException
771
+	 * @throws InvalidDataTypeException
772
+	 * @throws InvalidInterfaceException
773
+	 * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
774
+	 */
775
+	public static function get_notices(
776
+		bool $format_output = true,
777
+		bool $save_to_transient = false,
778
+		bool $remove_empty = true
779
+	) {
780
+		$success_messages   = '';
781
+		$attention_messages = '';
782
+		$error_messages     = '';
783
+		/** @var RequestInterface $request */
784
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
785
+		// either save notices to the db
786
+		if ($save_to_transient || $request->requestParamIsSet('activate-selected')) {
787
+			self::$_espresso_notices = array_merge(
788
+				EE_Error::getStoredNotices(),
789
+				self::$_espresso_notices
790
+			);
791
+			EE_Error::storeNotices(self::$_espresso_notices);
792
+			return [];
793
+		}
794
+		$print_scripts = EE_Error::combineExistingAndNewNotices();
795
+		// check for success messages
796
+		if (! empty(self::$_espresso_notices['success'])) {
797
+			// combine messages
798
+			$success_messages .= implode('<br />', self::$_espresso_notices['success']);
799
+			$print_scripts    = true;
800
+		}
801
+		// check for attention messages
802
+		if (! empty(self::$_espresso_notices['attention'])) {
803
+			// combine messages
804
+			$attention_messages .= implode('<br />', self::$_espresso_notices['attention']);
805
+			$print_scripts      = true;
806
+		}
807
+		// check for error messages
808
+		if (! empty(self::$_espresso_notices['errors'])) {
809
+			$error_messages .= count(self::$_espresso_notices['errors']) > 1
810
+				? esc_html__('The following errors have occurred:', 'event_espresso')
811
+				: esc_html__('An error has occurred:', 'event_espresso');
812
+			// combine messages
813
+			$error_messages .= '<br />' . implode('<br />', self::$_espresso_notices['errors']);
814
+			$print_scripts  = true;
815
+		}
816
+		if ($format_output) {
817
+			$notices = EE_Error::formatNoticesOutput(
818
+				$success_messages,
819
+				$attention_messages,
820
+				$error_messages
821
+			);
822
+		} else {
823
+			$notices = [
824
+				'success'   => $success_messages,
825
+				'attention' => $attention_messages,
826
+				'errors'    => $error_messages,
827
+			];
828
+			if ($remove_empty) {
829
+				// remove empty notices
830
+				foreach ($notices as $type => $notice) {
831
+					if (empty($notice)) {
832
+						unset($notices[ $type ]);
833
+					}
834
+				}
835
+			}
836
+		}
837
+		if ($print_scripts) {
838
+			self::_print_scripts();
839
+		}
840
+		return $notices;
841
+	}
842
+
843
+
844
+	/**
845
+	 * @return bool
846
+	 * @throws InvalidArgumentException
847
+	 * @throws InvalidDataTypeException
848
+	 * @throws InvalidInterfaceException
849
+	 */
850
+	private static function combineExistingAndNewNotices(): bool
851
+	{
852
+		$print_scripts = false;
853
+		// grab any notices that have been previously saved
854
+		$notices = EE_Error::getStoredNotices();
855
+		if (! empty($notices)) {
856
+			foreach ($notices as $type => $notice) {
857
+				if (is_array($notice) && ! empty($notice)) {
858
+					// make sure that existing notice type is an array
859
+					self::$_espresso_notices[ $type ] = is_array(self::$_espresso_notices[ $type ])
860
+														&& ! empty(self::$_espresso_notices[ $type ])
861
+						? self::$_espresso_notices[ $type ]
862
+						: [];
863
+					// add newly created notices to existing ones
864
+					self::$_espresso_notices[ $type ] += $notice;
865
+					$print_scripts                    = true;
866
+				}
867
+			}
868
+			// now clear any stored notices
869
+			EE_Error::clearNotices();
870
+		}
871
+		return $print_scripts;
872
+	}
873
+
874
+
875
+	/**
876
+	 * @param string $success_messages
877
+	 * @param string $attention_messages
878
+	 * @param string $error_messages
879
+	 * @return string
880
+	 */
881
+	private static function formatNoticesOutput(
882
+		string $success_messages,
883
+		string $attention_messages,
884
+		string $error_messages
885
+	): string {
886
+		$notices = '<div id="espresso-notices">';
887
+		$close   = is_admin()
888
+			? ''
889
+			: '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"/></a>';
890
+		if ($success_messages !== '') {
891
+			$css_id    = is_admin() ? 'ee-success-message' : 'espresso-notices-success';
892
+			$css_class = is_admin() ? 'updated fade ee-status-outline ee-status-bg--success' : 'success fade-away';
893
+			// showMessage( $success_messages );
894
+			$notices .= '<div id="' . $css_id . '" '
895
+						. 'class="espresso-notices ' . $css_class . '" '
896
+						. 'style="display:none;">'
897
+						. '<p>' . $success_messages . '</p>'
898
+						. $close
899
+						. '</div>';
900
+		}
901
+		if ($attention_messages !== '') {
902
+			$css_id    = is_admin()  ? 'ee-attention-message' : 'espresso-notices-attention';
903
+			$css_class = is_admin()
904
+				? 'notice notice-info ee-notices-attention ee-status-outline ee-status-bg--attention'
905
+				: 'attention fade-away';
906
+			// showMessage( $error_messages, TRUE );
907
+			$notices .= '<div id="' . $css_id . '" '
908
+						. 'class="espresso-notices ' . $css_class . '" '
909
+						. 'style="display:none;">'
910
+						. '<p>' . $attention_messages . '</p>'
911
+						. $close
912
+						. '</div>';
913
+		}
914
+		if ($error_messages !== '') {
915
+			$css_id    = is_admin() ? 'ee-error-message' : 'espresso-notices-error';
916
+			$css_class = is_admin()
917
+				? 'error ee-status-outline ee-status-bg--error'
918
+				: 'error fade-away';
919
+			// showMessage( $error_messages, TRUE );
920
+			$notices .= '<div id="' . $css_id . '" '
921
+						. 'class="espresso-notices ' . $css_class . '" '
922
+						. 'style="display:none;">'
923
+						. '<p>' . $error_messages . '</p>'
924
+						. $close
925
+						. '</div>';
926
+		}
927
+		$notices .= '</div>';
928
+		return $notices;
929
+	}
930
+
931
+
932
+	/**
933
+	 * _print_scripts
934
+	 *
935
+	 * @param bool $force_print
936
+	 * @return    string
937
+	 */
938
+	private static function _print_scripts(bool $force_print = false): string
939
+	{
940
+		if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
941
+			if (wp_script_is('ee_error_js', 'registered')) {
942
+				wp_enqueue_style('espresso_default');
943
+				wp_enqueue_style('espresso_custom_css');
944
+				wp_enqueue_script('ee_error_js');
945
+			}
946
+			if (wp_script_is('ee_error_js')) {
947
+				wp_localize_script('ee_error_js', 'ee_settings', ['wp_debug' => WP_DEBUG]);
948
+				return '';
949
+			}
950
+		} else {
951
+			return '
952 952
 <script>
953 953
 /* <![CDATA[ */
954 954
 const ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
@@ -958,233 +958,233 @@  discard block
 block discarded – undo
958 958
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
959 959
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
960 960
 ';
961
-        }
962
-        return '';
963
-    }
964
-
965
-
966
-    /**
967
-     * @return void
968
-     */
969
-    public static function enqueue_error_scripts()
970
-    {
971
-        self::_print_scripts();
972
-    }
973
-
974
-
975
-    /**
976
-     * create error code from filepath, function name,
977
-     * and line number where exception or error was thrown
978
-     *
979
-     * @param string $file
980
-     * @param string $func
981
-     * @param int|string $line
982
-     * @return string
983
-     */
984
-    public static function generate_error_code(string $file = '', string $func = '', $line = ''): string
985
-    {
986
-        $file       = explode('.', basename($file));
987
-        $error_code = ! empty($file[0]) ? $file[0] : '';
988
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
989
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
990
-        return $error_code;
991
-    }
992
-
993
-
994
-    /**
995
-     * write exception details to log file
996
-     * Since 4.9.53.rc.006 this writes to the standard PHP log file, not EE's custom log file
997
-     *
998
-     * @param int   $time
999
-     * @param array $ex
1000
-     * @param bool  $clear
1001
-     * @return void
1002
-     */
1003
-    public function write_to_error_log(int $time = 0, array $ex = [], bool $clear = false)
1004
-    {
1005
-        if (empty($ex)) {
1006
-            return;
1007
-        }
1008
-        if (! $time) {
1009
-            $time = time();
1010
-        }
1011
-        $exception_log = '----------------------------------------------------------------------------------------'
1012
-                         . PHP_EOL;
1013
-        $exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
1014
-        $exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
1015
-        $exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
1016
-        $exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
1017
-        $exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
1018
-        $exception_log .= 'Stack trace: ' . PHP_EOL;
1019
-        $exception_log .= $ex['string'] . PHP_EOL;
1020
-        $exception_log .= '----------------------------------------------------------------------------------------'
1021
-                          . PHP_EOL;
1022
-        try {
1023
-            error_log($exception_log);
1024
-        } catch (Exception $e) {
1025
-            EE_Error::add_error(
1026
-                sprintf(
1027
-                    esc_html__(
1028
-                        'Event Espresso error logging could not be setup because: %s',
1029
-                        'event_espresso'
1030
-                    ),
1031
-                    $e->getMessage()
1032
-                ),
1033
-                __FILE__,
1034
-                __FUNCTION__,
1035
-                __LINE__
1036
-            );
1037
-        }
1038
-    }
1039
-
1040
-
1041
-    /**
1042
-     * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1043
-     * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1044
-     * but the code execution is done in a manner that could lead to unexpected results
1045
-     * (i.e. running to early, or too late in WP or EE loading process).
1046
-     * A good test for knowing whether to use this method is:
1047
-     * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1048
-     * Yes -> use EE_Error::add_error() or throw new EE_Error()
1049
-     * 2. If this is loaded before something else, it won't break anything,
1050
-     * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1051
-     *
1052
-     * @param string   $function     The function that was called
1053
-     * @param string   $message      A message explaining what has been done incorrectly
1054
-     * @param string   $version      The version of Event Espresso where the error was added
1055
-     * @param string   $applies_when a version string for when you want the doing_it_wrong notice to begin appearing
1056
-     *                               for a deprecated function. This allows deprecation to occur during one version,
1057
-     *                               but not have any notices appear until a later version. This allows developers
1058
-     *                               extra time to update their code before notices appear.
1059
-     * @param int|null $error_type
1060
-     * @uses   constant WP_DEBUG test if wp_debug is on or not
1061
-     */
1062
-    public static function doing_it_wrong(
1063
-        string $function,
1064
-        string $message,
1065
-        string $version,
1066
-        string $applies_when = '',
1067
-        int $error_type = null
1068
-    ) {
1069
-        if (defined('WP_DEBUG') && WP_DEBUG) {
1070
-            EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1071
-        }
1072
-    }
1073
-
1074
-
1075
-    /**
1076
-     * Like get_notices, but returns an array of all the notices of the given type.
1077
-     *
1078
-     * @return array {
1079
-     * @type array $success   all the success messages
1080
-     * @type array $errors    all the error messages
1081
-     * @type array $attention all the attention messages
1082
-     * }
1083
-     */
1084
-    public static function get_raw_notices(): array
1085
-    {
1086
-        return self::$_espresso_notices;
1087
-    }
1088
-
1089
-
1090
-    /**
1091
-     * @param string $pan_name     the name, or key of the Persistent Admin Notice to be stored
1092
-     * @param string $pan_message  the message to be stored persistently until dismissed
1093
-     * @param bool   $force_update allows one to enforce the reappearance of a persistent message.
1094
-     * @return void
1095
-     * @throws InvalidDataTypeException
1096
-     * @deprecated 4.9.27
1097
-     */
1098
-    public static function add_persistent_admin_notice(
1099
-        string $pan_name = '',
1100
-        string $pan_message = '',
1101
-        bool $force_update = false
1102
-    ) {
1103
-        new PersistentAdminNotice(
1104
-            $pan_name,
1105
-            $pan_message,
1106
-            $force_update
1107
-        );
1108
-        EE_Error::doing_it_wrong(
1109
-            __METHOD__,
1110
-            sprintf(
1111
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1112
-                '\EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
1113
-            ),
1114
-            '4.9.27'
1115
-        );
1116
-    }
1117
-
1118
-
1119
-    /**
1120
-     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
1121
-     * @param bool   $purge
1122
-     * @param bool   $return
1123
-     * @throws DomainException
1124
-     * @throws InvalidInterfaceException
1125
-     * @throws InvalidDataTypeException
1126
-     * @throws ServiceNotFoundException
1127
-     * @throws InvalidArgumentException
1128
-     * @deprecated 4.9.27
1129
-     */
1130
-    public static function dismiss_persistent_admin_notice(
1131
-        string $pan_name = '',
1132
-        bool $purge = false,
1133
-        bool $return = false
1134
-    ) {
1135
-        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
1136
-        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
1137
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1138
-        );
1139
-        $persistent_admin_notice_manager->dismissNotice($pan_name, $purge, $return);
1140
-        EE_Error::doing_it_wrong(
1141
-            __METHOD__,
1142
-            sprintf(
1143
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1144
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1145
-            ),
1146
-            '4.9.27'
1147
-        );
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * @param string $pan_name    the name, or key of the Persistent Admin Notice to be stored
1153
-     * @param string $pan_message the message to be stored persistently until dismissed
1154
-     * @param string $return_url  URL to go back to after nag notice is dismissed
1155
-     * @deprecated 4.9.27
1156
-     */
1157
-    public static function display_persistent_admin_notices(
1158
-        string $pan_name = '',
1159
-        string $pan_message = '',
1160
-        string $return_url = ''
1161
-    ) {
1162
-        EE_Error::doing_it_wrong(
1163
-            __METHOD__,
1164
-            sprintf(
1165
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1166
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1167
-            ),
1168
-            '4.9.27'
1169
-        );
1170
-    }
1171
-
1172
-
1173
-    /**
1174
-     * @param string $return_url
1175
-     * @deprecated 4.9.27
1176
-     */
1177
-    public static function get_persistent_admin_notices(string $return_url = '')
1178
-    {
1179
-        EE_Error::doing_it_wrong(
1180
-            __METHOD__,
1181
-            sprintf(
1182
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1183
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1184
-            ),
1185
-            '4.9.27'
1186
-        );
1187
-    }
961
+		}
962
+		return '';
963
+	}
964
+
965
+
966
+	/**
967
+	 * @return void
968
+	 */
969
+	public static function enqueue_error_scripts()
970
+	{
971
+		self::_print_scripts();
972
+	}
973
+
974
+
975
+	/**
976
+	 * create error code from filepath, function name,
977
+	 * and line number where exception or error was thrown
978
+	 *
979
+	 * @param string $file
980
+	 * @param string $func
981
+	 * @param int|string $line
982
+	 * @return string
983
+	 */
984
+	public static function generate_error_code(string $file = '', string $func = '', $line = ''): string
985
+	{
986
+		$file       = explode('.', basename($file));
987
+		$error_code = ! empty($file[0]) ? $file[0] : '';
988
+		$error_code .= ! empty($func) ? ' - ' . $func : '';
989
+		$error_code .= ! empty($line) ? ' - ' . $line : '';
990
+		return $error_code;
991
+	}
992
+
993
+
994
+	/**
995
+	 * write exception details to log file
996
+	 * Since 4.9.53.rc.006 this writes to the standard PHP log file, not EE's custom log file
997
+	 *
998
+	 * @param int   $time
999
+	 * @param array $ex
1000
+	 * @param bool  $clear
1001
+	 * @return void
1002
+	 */
1003
+	public function write_to_error_log(int $time = 0, array $ex = [], bool $clear = false)
1004
+	{
1005
+		if (empty($ex)) {
1006
+			return;
1007
+		}
1008
+		if (! $time) {
1009
+			$time = time();
1010
+		}
1011
+		$exception_log = '----------------------------------------------------------------------------------------'
1012
+						 . PHP_EOL;
1013
+		$exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
1014
+		$exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
1015
+		$exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
1016
+		$exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
1017
+		$exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
1018
+		$exception_log .= 'Stack trace: ' . PHP_EOL;
1019
+		$exception_log .= $ex['string'] . PHP_EOL;
1020
+		$exception_log .= '----------------------------------------------------------------------------------------'
1021
+						  . PHP_EOL;
1022
+		try {
1023
+			error_log($exception_log);
1024
+		} catch (Exception $e) {
1025
+			EE_Error::add_error(
1026
+				sprintf(
1027
+					esc_html__(
1028
+						'Event Espresso error logging could not be setup because: %s',
1029
+						'event_espresso'
1030
+					),
1031
+					$e->getMessage()
1032
+				),
1033
+				__FILE__,
1034
+				__FUNCTION__,
1035
+				__LINE__
1036
+			);
1037
+		}
1038
+	}
1039
+
1040
+
1041
+	/**
1042
+	 * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1043
+	 * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1044
+	 * but the code execution is done in a manner that could lead to unexpected results
1045
+	 * (i.e. running to early, or too late in WP or EE loading process).
1046
+	 * A good test for knowing whether to use this method is:
1047
+	 * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1048
+	 * Yes -> use EE_Error::add_error() or throw new EE_Error()
1049
+	 * 2. If this is loaded before something else, it won't break anything,
1050
+	 * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1051
+	 *
1052
+	 * @param string   $function     The function that was called
1053
+	 * @param string   $message      A message explaining what has been done incorrectly
1054
+	 * @param string   $version      The version of Event Espresso where the error was added
1055
+	 * @param string   $applies_when a version string for when you want the doing_it_wrong notice to begin appearing
1056
+	 *                               for a deprecated function. This allows deprecation to occur during one version,
1057
+	 *                               but not have any notices appear until a later version. This allows developers
1058
+	 *                               extra time to update their code before notices appear.
1059
+	 * @param int|null $error_type
1060
+	 * @uses   constant WP_DEBUG test if wp_debug is on or not
1061
+	 */
1062
+	public static function doing_it_wrong(
1063
+		string $function,
1064
+		string $message,
1065
+		string $version,
1066
+		string $applies_when = '',
1067
+		int $error_type = null
1068
+	) {
1069
+		if (defined('WP_DEBUG') && WP_DEBUG) {
1070
+			EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1071
+		}
1072
+	}
1073
+
1074
+
1075
+	/**
1076
+	 * Like get_notices, but returns an array of all the notices of the given type.
1077
+	 *
1078
+	 * @return array {
1079
+	 * @type array $success   all the success messages
1080
+	 * @type array $errors    all the error messages
1081
+	 * @type array $attention all the attention messages
1082
+	 * }
1083
+	 */
1084
+	public static function get_raw_notices(): array
1085
+	{
1086
+		return self::$_espresso_notices;
1087
+	}
1088
+
1089
+
1090
+	/**
1091
+	 * @param string $pan_name     the name, or key of the Persistent Admin Notice to be stored
1092
+	 * @param string $pan_message  the message to be stored persistently until dismissed
1093
+	 * @param bool   $force_update allows one to enforce the reappearance of a persistent message.
1094
+	 * @return void
1095
+	 * @throws InvalidDataTypeException
1096
+	 * @deprecated 4.9.27
1097
+	 */
1098
+	public static function add_persistent_admin_notice(
1099
+		string $pan_name = '',
1100
+		string $pan_message = '',
1101
+		bool $force_update = false
1102
+	) {
1103
+		new PersistentAdminNotice(
1104
+			$pan_name,
1105
+			$pan_message,
1106
+			$force_update
1107
+		);
1108
+		EE_Error::doing_it_wrong(
1109
+			__METHOD__,
1110
+			sprintf(
1111
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1112
+				'\EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
1113
+			),
1114
+			'4.9.27'
1115
+		);
1116
+	}
1117
+
1118
+
1119
+	/**
1120
+	 * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
1121
+	 * @param bool   $purge
1122
+	 * @param bool   $return
1123
+	 * @throws DomainException
1124
+	 * @throws InvalidInterfaceException
1125
+	 * @throws InvalidDataTypeException
1126
+	 * @throws ServiceNotFoundException
1127
+	 * @throws InvalidArgumentException
1128
+	 * @deprecated 4.9.27
1129
+	 */
1130
+	public static function dismiss_persistent_admin_notice(
1131
+		string $pan_name = '',
1132
+		bool $purge = false,
1133
+		bool $return = false
1134
+	) {
1135
+		/** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
1136
+		$persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
1137
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1138
+		);
1139
+		$persistent_admin_notice_manager->dismissNotice($pan_name, $purge, $return);
1140
+		EE_Error::doing_it_wrong(
1141
+			__METHOD__,
1142
+			sprintf(
1143
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1144
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1145
+			),
1146
+			'4.9.27'
1147
+		);
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * @param string $pan_name    the name, or key of the Persistent Admin Notice to be stored
1153
+	 * @param string $pan_message the message to be stored persistently until dismissed
1154
+	 * @param string $return_url  URL to go back to after nag notice is dismissed
1155
+	 * @deprecated 4.9.27
1156
+	 */
1157
+	public static function display_persistent_admin_notices(
1158
+		string $pan_name = '',
1159
+		string $pan_message = '',
1160
+		string $return_url = ''
1161
+	) {
1162
+		EE_Error::doing_it_wrong(
1163
+			__METHOD__,
1164
+			sprintf(
1165
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1166
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1167
+			),
1168
+			'4.9.27'
1169
+		);
1170
+	}
1171
+
1172
+
1173
+	/**
1174
+	 * @param string $return_url
1175
+	 * @deprecated 4.9.27
1176
+	 */
1177
+	public static function get_persistent_admin_notices(string $return_url = '')
1178
+	{
1179
+		EE_Error::doing_it_wrong(
1180
+			__METHOD__,
1181
+			sprintf(
1182
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1183
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
1184
+			),
1185
+			'4.9.27'
1186
+		);
1187
+	}
1188 1188
 }
1189 1189
 
1190 1190
 // end of Class EE_Exceptions
@@ -1197,29 +1197,29 @@  discard block
 block discarded – undo
1197 1197
  */
1198 1198
 function espresso_error_enqueue_scripts()
1199 1199
 {
1200
-    // js for error handling
1201
-    if (! wp_script_is('espresso_core', 'registered')) {
1202
-        wp_register_script(
1203
-            'espresso_core',
1204
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1205
-            ['jquery'],
1206
-            EVENT_ESPRESSO_VERSION
1207
-        );
1208
-    }
1209
-    wp_register_script(
1210
-        'ee_error_js',
1211
-        EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1212
-        ['espresso_core'],
1213
-        EVENT_ESPRESSO_VERSION
1214
-    );
1215
-    wp_localize_script('ee_error_js', 'ee_settings', ['wp_debug' => WP_DEBUG]);
1200
+	// js for error handling
1201
+	if (! wp_script_is('espresso_core', 'registered')) {
1202
+		wp_register_script(
1203
+			'espresso_core',
1204
+			EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1205
+			['jquery'],
1206
+			EVENT_ESPRESSO_VERSION
1207
+		);
1208
+	}
1209
+	wp_register_script(
1210
+		'ee_error_js',
1211
+		EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1212
+		['espresso_core'],
1213
+		EVENT_ESPRESSO_VERSION
1214
+	);
1215
+	wp_localize_script('ee_error_js', 'ee_settings', ['wp_debug' => WP_DEBUG]);
1216 1216
 }
1217 1217
 
1218 1218
 
1219 1219
 if (is_admin()) {
1220
-    add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 5);
1220
+	add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 5);
1221 1221
 } else {
1222
-    add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 5);
1222
+	add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 5);
1223 1223
 }
1224 1224
 
1225 1225
 
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1287 added lines, -1287 removed lines patch added patch discarded remove patch
@@ -16,1297 +16,1297 @@
 block discarded – undo
16 16
  */
17 17
 class Extend_Events_Admin_Page extends Events_Admin_Page
18 18
 {
19
-    /**
20
-     * Extend_Events_Admin_Page constructor.
21
-     *
22
-     * @param bool $routing
23
-     * @throws ReflectionException
24
-     */
25
-    public function __construct($routing = true)
26
-    {
27
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
31
-        }
32
-        parent::__construct($routing);
33
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
34
-    }
35
-
36
-
37
-    protected function _set_page_config()
38
-    {
39
-        parent::_set_page_config();
40
-
41
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
42
-        // is there an evt_id in the request?
43
-        $EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
44
-        $EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
45
-        $TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
46
-        $new_page_routes                                 = [
47
-            'duplicate_event'          => [
48
-                'func'       => '_duplicate_event',
49
-                'capability' => 'ee_edit_event',
50
-                'obj_id'     => $EVT_ID,
51
-                'noheader'   => true,
52
-            ],
53
-            'import_page'              => [
54
-                'func'       => '_import_page',
55
-                'capability' => 'import',
56
-            ],
57
-            'import'                   => [
58
-                'func'       => '_import_events',
59
-                'capability' => 'import',
60
-                'noheader'   => true,
61
-            ],
62
-            'import_events'            => [
63
-                'func'       => '_import_events',
64
-                'capability' => 'import',
65
-                'noheader'   => true,
66
-            ],
67
-            'export_events'            => [
68
-                'func'       => '_events_export',
69
-                'capability' => 'export',
70
-                'noheader'   => true,
71
-            ],
72
-            'export_categories'        => [
73
-                'func'       => '_categories_export',
74
-                'capability' => 'export',
75
-                'noheader'   => true,
76
-            ],
77
-            'sample_export_file'       => [
78
-                'func'       => '_sample_export_file',
79
-                'capability' => 'export',
80
-                'noheader'   => true,
81
-            ],
82
-            'update_template_settings' => [
83
-                'func'       => '_update_template_settings',
84
-                'capability' => 'manage_options',
85
-                'noheader'   => true,
86
-            ],
87
-            'ticket_list_table'        => [
88
-                'func'       => '_tickets_overview_list_table',
89
-                'capability' => 'ee_read_default_tickets',
90
-            ],
91
-        ];
92
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
93
-        $this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
94
-        // don't load these meta boxes if using the advanced editor
95
-        if (
96
-            ! $this->admin_config->useAdvancedEditor()
97
-            || ! $this->feature->allowed('use_default_ticket_manager')
98
-        ) {
99
-            $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
100
-            $this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
101
-
102
-            $legacy_editor_page_routes = [
103
-                'trash_ticket'    => [
104
-                    'func'       => '_trash_or_restore_ticket',
105
-                    'capability' => 'ee_delete_default_ticket',
106
-                    'obj_id'     => $TKT_ID,
107
-                    'noheader'   => true,
108
-                    'args'       => ['trash' => true],
109
-                ],
110
-                'trash_tickets'   => [
111
-                    'func'       => '_trash_or_restore_ticket',
112
-                    'capability' => 'ee_delete_default_tickets',
113
-                    'noheader'   => true,
114
-                    'args'       => ['trash' => true],
115
-                ],
116
-                'restore_ticket'  => [
117
-                    'func'       => '_trash_or_restore_ticket',
118
-                    'capability' => 'ee_delete_default_ticket',
119
-                    'obj_id'     => $TKT_ID,
120
-                    'noheader'   => true,
121
-                ],
122
-                'restore_tickets' => [
123
-                    'func'       => '_trash_or_restore_ticket',
124
-                    'capability' => 'ee_delete_default_tickets',
125
-                    'noheader'   => true,
126
-                ],
127
-                'delete_ticket'   => [
128
-                    'func'       => '_delete_ticket',
129
-                    'capability' => 'ee_delete_default_ticket',
130
-                    'obj_id'     => $TKT_ID,
131
-                    'noheader'   => true,
132
-                ],
133
-                'delete_tickets'  => [
134
-                    'func'       => '_delete_ticket',
135
-                    'capability' => 'ee_delete_default_tickets',
136
-                    'noheader'   => true,
137
-                ],
138
-            ];
139
-            $new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
140
-        }
141
-
142
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
143
-        // partial route/config override
144
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
145
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
146
-
147
-        // add default tickets tab and template settings nav tabs (note union at end)
148
-        $this->_page_config = [
149
-                                  'ticket_list_table' => [
150
-                                      'nav'           => [
151
-                                          'label' => esc_html__('Default Tickets', 'event_espresso'),
152
-                                          'icon'  => 'dashicons-tickets-alt',
153
-                                          'order' => 60,
154
-                                      ],
155
-                                      'list_table'    => 'Tickets_List_Table',
156
-                                      'require_nonce' => false,
157
-                                  ],
158
-                                  'template_settings' => [
159
-                                      'nav'           => [
160
-                                          'label' => esc_html__('Templates', 'event_espresso'),
161
-                                          'icon'  => 'dashicons-layout',
162
-                                          'order' => 30,
163
-                                      ],
164
-                                      'metaboxes'     => array_merge(
165
-                                          ['_publish_post_box'],
166
-                                          $this->_default_espresso_metaboxes
167
-                                      ),
168
-                                      'help_tabs'     => [
169
-                                          'general_settings_templates_help_tab' => [
170
-                                              'title'    => esc_html__('Templates', 'event_espresso'),
171
-                                              'filename' => 'general_settings_templates',
172
-                                          ],
173
-                                      ],
174
-                                      'require_nonce' => false,
175
-                                  ],
176
-                              ] + $this->_page_config;
177
-
178
-        // add filters and actions
179
-        // modifying _views
180
-        add_filter(
181
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
182
-            [$this, 'add_additional_datetime_button'],
183
-            10,
184
-            2
185
-        );
186
-        add_filter(
187
-            'FHEE_event_datetime_metabox_clone_button_template',
188
-            [$this, 'add_datetime_clone_button'],
189
-            10,
190
-            2
191
-        );
192
-        add_filter(
193
-            'FHEE_event_datetime_metabox_timezones_template',
194
-            [$this, 'datetime_timezones_template'],
195
-            10,
196
-            2
197
-        );
198
-        // filters for event list table
199
-        add_filter(
200
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
201
-            [$this, 'extra_list_table_actions'],
202
-            10,
203
-            2
204
-        );
205
-        // legend item
206
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
207
-        add_action('admin_init', [$this, 'admin_init']);
208
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
209
-        // add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 2);
210
-        DuplicateEventButton::addEventEditorPermalinkButton(8);
211
-    }
212
-
213
-
214
-    /**
215
-     * admin_init
216
-     */
217
-    public function admin_init()
218
-    {
219
-        EE_Registry::$i18n_js_strings = array_merge(
220
-            EE_Registry::$i18n_js_strings,
221
-            [
222
-                'image_confirm'          => esc_html__(
223
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
224
-                    'event_espresso'
225
-                ),
226
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
227
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
228
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
229
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
230
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
231
-            ]
232
-        );
233
-    }
234
-
235
-
236
-    /**
237
-     * Add per page screen options to the default ticket list table view.
238
-     *
239
-     * @throws InvalidArgumentException
240
-     * @throws InvalidDataTypeException
241
-     * @throws InvalidInterfaceException
242
-     */
243
-    protected function _add_screen_options_ticket_list_table()
244
-    {
245
-        $this->_per_page_screen_option();
246
-    }
247
-
248
-
249
-    /**
250
-     * @param string      $return    the current html
251
-     * @param int         $id        the post id for the page
252
-     * @param string|null $new_title What the title is
253
-     * @param string|null $new_slug  what the slug is
254
-     * @return string
255
-     * @deprecated 5.0.0.p
256
-     */
257
-    public function extra_permalink_field_buttons(
258
-        string $return,
259
-        int $id,
260
-        ?string $new_title,
261
-        ?string $new_slug
262
-    ): string {
263
-        $return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
264
-        return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
265
-    }
266
-
267
-
268
-    /**
269
-     * Set the list table views for the default ticket list table view.
270
-     */
271
-    public function _set_list_table_views_ticket_list_table()
272
-    {
273
-        $this->_views = [
274
-            'all'     => [
275
-                'slug'        => 'all',
276
-                'label'       => esc_html__('All', 'event_espresso'),
277
-                'count'       => 0,
278
-                'bulk_action' => [
279
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
280
-                ],
281
-            ],
282
-            'trashed' => [
283
-                'slug'        => 'trashed',
284
-                'label'       => esc_html__('Trash', 'event_espresso'),
285
-                'count'       => 0,
286
-                'bulk_action' => [
287
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
288
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
289
-                ],
290
-            ],
291
-        ];
292
-    }
293
-
294
-
295
-    /**
296
-     * Enqueue scripts and styles for the event editor.
297
-     */
298
-    public function load_scripts_styles_edit()
299
-    {
300
-        if (! $this->admin_config->useAdvancedEditor()) {
301
-            wp_register_script(
302
-                'ee-event-editor-heartbeat',
303
-                EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
304
-                ['ee_admin_js', 'heartbeat'],
305
-                EVENT_ESPRESSO_VERSION,
306
-                true
307
-            );
308
-            wp_enqueue_script('ee-accounting');
309
-            wp_enqueue_script('ee-event-editor-heartbeat');
310
-        }
311
-        wp_enqueue_script('event_editor_js');
312
-        wp_register_style(
313
-            'event-editor-css',
314
-            EVENTS_ASSETS_URL . 'event-editor.css',
315
-            ['ee-admin-css'],
316
-            EVENT_ESPRESSO_VERSION
317
-        );
318
-        wp_enqueue_style('event-editor-css');
319
-        // styles
320
-        wp_enqueue_style('espresso-ui-theme');
321
-    }
322
-
323
-
324
-    /**
325
-     * Sets the views for the default list table view.
326
-     *
327
-     * @throws EE_Error
328
-     * @throws ReflectionException
329
-     */
330
-    protected function _set_list_table_views_default()
331
-    {
332
-        parent::_set_list_table_views_default();
333
-        $new_views    = [
334
-            'today' => [
335
-                'slug'        => 'today',
336
-                'label'       => esc_html__('Today', 'event_espresso'),
337
-                'count'       => $this->total_events_today(),
338
-                'bulk_action' => [
339
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
340
-                ],
341
-            ],
342
-            'month' => [
343
-                'slug'        => 'month',
344
-                'label'       => esc_html__('This Month', 'event_espresso'),
345
-                'count'       => $this->total_events_this_month(),
346
-                'bulk_action' => [
347
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
348
-                ],
349
-            ],
350
-        ];
351
-        $this->_views = array_merge($this->_views, $new_views);
352
-    }
353
-
354
-
355
-    /**
356
-     * Returns the extra action links for the default list table view.
357
-     *
358
-     * @param array    $action_links
359
-     * @param EE_Event $event
360
-     * @return array
361
-     * @throws EE_Error
362
-     * @throws ReflectionException
363
-     */
364
-    public function extra_list_table_actions(array $action_links, EE_Event $event): array
365
-    {
366
-        if (
367
-        EE_Registry::instance()->CAP->current_user_can(
368
-            'ee_read_registrations',
369
-            'espresso_registrations_reports',
370
-            $event->ID()
371
-        )
372
-        ) {
373
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce(
374
-                [
375
-                    'action' => 'reports',
376
-                    'EVT_ID' => $event->ID(),
377
-                ],
378
-                REG_ADMIN_URL
379
-            );
380
-
381
-            $action_links[] = '
19
+	/**
20
+	 * Extend_Events_Admin_Page constructor.
21
+	 *
22
+	 * @param bool $routing
23
+	 * @throws ReflectionException
24
+	 */
25
+	public function __construct($routing = true)
26
+	{
27
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
31
+		}
32
+		parent::__construct($routing);
33
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
34
+	}
35
+
36
+
37
+	protected function _set_page_config()
38
+	{
39
+		parent::_set_page_config();
40
+
41
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
42
+		// is there an evt_id in the request?
43
+		$EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
44
+		$EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
45
+		$TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
46
+		$new_page_routes                                 = [
47
+			'duplicate_event'          => [
48
+				'func'       => '_duplicate_event',
49
+				'capability' => 'ee_edit_event',
50
+				'obj_id'     => $EVT_ID,
51
+				'noheader'   => true,
52
+			],
53
+			'import_page'              => [
54
+				'func'       => '_import_page',
55
+				'capability' => 'import',
56
+			],
57
+			'import'                   => [
58
+				'func'       => '_import_events',
59
+				'capability' => 'import',
60
+				'noheader'   => true,
61
+			],
62
+			'import_events'            => [
63
+				'func'       => '_import_events',
64
+				'capability' => 'import',
65
+				'noheader'   => true,
66
+			],
67
+			'export_events'            => [
68
+				'func'       => '_events_export',
69
+				'capability' => 'export',
70
+				'noheader'   => true,
71
+			],
72
+			'export_categories'        => [
73
+				'func'       => '_categories_export',
74
+				'capability' => 'export',
75
+				'noheader'   => true,
76
+			],
77
+			'sample_export_file'       => [
78
+				'func'       => '_sample_export_file',
79
+				'capability' => 'export',
80
+				'noheader'   => true,
81
+			],
82
+			'update_template_settings' => [
83
+				'func'       => '_update_template_settings',
84
+				'capability' => 'manage_options',
85
+				'noheader'   => true,
86
+			],
87
+			'ticket_list_table'        => [
88
+				'func'       => '_tickets_overview_list_table',
89
+				'capability' => 'ee_read_default_tickets',
90
+			],
91
+		];
92
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
93
+		$this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
94
+		// don't load these meta boxes if using the advanced editor
95
+		if (
96
+			! $this->admin_config->useAdvancedEditor()
97
+			|| ! $this->feature->allowed('use_default_ticket_manager')
98
+		) {
99
+			$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
100
+			$this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
101
+
102
+			$legacy_editor_page_routes = [
103
+				'trash_ticket'    => [
104
+					'func'       => '_trash_or_restore_ticket',
105
+					'capability' => 'ee_delete_default_ticket',
106
+					'obj_id'     => $TKT_ID,
107
+					'noheader'   => true,
108
+					'args'       => ['trash' => true],
109
+				],
110
+				'trash_tickets'   => [
111
+					'func'       => '_trash_or_restore_ticket',
112
+					'capability' => 'ee_delete_default_tickets',
113
+					'noheader'   => true,
114
+					'args'       => ['trash' => true],
115
+				],
116
+				'restore_ticket'  => [
117
+					'func'       => '_trash_or_restore_ticket',
118
+					'capability' => 'ee_delete_default_ticket',
119
+					'obj_id'     => $TKT_ID,
120
+					'noheader'   => true,
121
+				],
122
+				'restore_tickets' => [
123
+					'func'       => '_trash_or_restore_ticket',
124
+					'capability' => 'ee_delete_default_tickets',
125
+					'noheader'   => true,
126
+				],
127
+				'delete_ticket'   => [
128
+					'func'       => '_delete_ticket',
129
+					'capability' => 'ee_delete_default_ticket',
130
+					'obj_id'     => $TKT_ID,
131
+					'noheader'   => true,
132
+				],
133
+				'delete_tickets'  => [
134
+					'func'       => '_delete_ticket',
135
+					'capability' => 'ee_delete_default_tickets',
136
+					'noheader'   => true,
137
+				],
138
+			];
139
+			$new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
140
+		}
141
+
142
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
143
+		// partial route/config override
144
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
145
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
146
+
147
+		// add default tickets tab and template settings nav tabs (note union at end)
148
+		$this->_page_config = [
149
+								  'ticket_list_table' => [
150
+									  'nav'           => [
151
+										  'label' => esc_html__('Default Tickets', 'event_espresso'),
152
+										  'icon'  => 'dashicons-tickets-alt',
153
+										  'order' => 60,
154
+									  ],
155
+									  'list_table'    => 'Tickets_List_Table',
156
+									  'require_nonce' => false,
157
+								  ],
158
+								  'template_settings' => [
159
+									  'nav'           => [
160
+										  'label' => esc_html__('Templates', 'event_espresso'),
161
+										  'icon'  => 'dashicons-layout',
162
+										  'order' => 30,
163
+									  ],
164
+									  'metaboxes'     => array_merge(
165
+										  ['_publish_post_box'],
166
+										  $this->_default_espresso_metaboxes
167
+									  ),
168
+									  'help_tabs'     => [
169
+										  'general_settings_templates_help_tab' => [
170
+											  'title'    => esc_html__('Templates', 'event_espresso'),
171
+											  'filename' => 'general_settings_templates',
172
+										  ],
173
+									  ],
174
+									  'require_nonce' => false,
175
+								  ],
176
+							  ] + $this->_page_config;
177
+
178
+		// add filters and actions
179
+		// modifying _views
180
+		add_filter(
181
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
182
+			[$this, 'add_additional_datetime_button'],
183
+			10,
184
+			2
185
+		);
186
+		add_filter(
187
+			'FHEE_event_datetime_metabox_clone_button_template',
188
+			[$this, 'add_datetime_clone_button'],
189
+			10,
190
+			2
191
+		);
192
+		add_filter(
193
+			'FHEE_event_datetime_metabox_timezones_template',
194
+			[$this, 'datetime_timezones_template'],
195
+			10,
196
+			2
197
+		);
198
+		// filters for event list table
199
+		add_filter(
200
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
201
+			[$this, 'extra_list_table_actions'],
202
+			10,
203
+			2
204
+		);
205
+		// legend item
206
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
207
+		add_action('admin_init', [$this, 'admin_init']);
208
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
209
+		// add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 2);
210
+		DuplicateEventButton::addEventEditorPermalinkButton(8);
211
+	}
212
+
213
+
214
+	/**
215
+	 * admin_init
216
+	 */
217
+	public function admin_init()
218
+	{
219
+		EE_Registry::$i18n_js_strings = array_merge(
220
+			EE_Registry::$i18n_js_strings,
221
+			[
222
+				'image_confirm'          => esc_html__(
223
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
224
+					'event_espresso'
225
+				),
226
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
227
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
228
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
229
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
230
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
231
+			]
232
+		);
233
+	}
234
+
235
+
236
+	/**
237
+	 * Add per page screen options to the default ticket list table view.
238
+	 *
239
+	 * @throws InvalidArgumentException
240
+	 * @throws InvalidDataTypeException
241
+	 * @throws InvalidInterfaceException
242
+	 */
243
+	protected function _add_screen_options_ticket_list_table()
244
+	{
245
+		$this->_per_page_screen_option();
246
+	}
247
+
248
+
249
+	/**
250
+	 * @param string      $return    the current html
251
+	 * @param int         $id        the post id for the page
252
+	 * @param string|null $new_title What the title is
253
+	 * @param string|null $new_slug  what the slug is
254
+	 * @return string
255
+	 * @deprecated 5.0.0.p
256
+	 */
257
+	public function extra_permalink_field_buttons(
258
+		string $return,
259
+		int $id,
260
+		?string $new_title,
261
+		?string $new_slug
262
+	): string {
263
+		$return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
264
+		return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
265
+	}
266
+
267
+
268
+	/**
269
+	 * Set the list table views for the default ticket list table view.
270
+	 */
271
+	public function _set_list_table_views_ticket_list_table()
272
+	{
273
+		$this->_views = [
274
+			'all'     => [
275
+				'slug'        => 'all',
276
+				'label'       => esc_html__('All', 'event_espresso'),
277
+				'count'       => 0,
278
+				'bulk_action' => [
279
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
280
+				],
281
+			],
282
+			'trashed' => [
283
+				'slug'        => 'trashed',
284
+				'label'       => esc_html__('Trash', 'event_espresso'),
285
+				'count'       => 0,
286
+				'bulk_action' => [
287
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
288
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
289
+				],
290
+			],
291
+		];
292
+	}
293
+
294
+
295
+	/**
296
+	 * Enqueue scripts and styles for the event editor.
297
+	 */
298
+	public function load_scripts_styles_edit()
299
+	{
300
+		if (! $this->admin_config->useAdvancedEditor()) {
301
+			wp_register_script(
302
+				'ee-event-editor-heartbeat',
303
+				EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
304
+				['ee_admin_js', 'heartbeat'],
305
+				EVENT_ESPRESSO_VERSION,
306
+				true
307
+			);
308
+			wp_enqueue_script('ee-accounting');
309
+			wp_enqueue_script('ee-event-editor-heartbeat');
310
+		}
311
+		wp_enqueue_script('event_editor_js');
312
+		wp_register_style(
313
+			'event-editor-css',
314
+			EVENTS_ASSETS_URL . 'event-editor.css',
315
+			['ee-admin-css'],
316
+			EVENT_ESPRESSO_VERSION
317
+		);
318
+		wp_enqueue_style('event-editor-css');
319
+		// styles
320
+		wp_enqueue_style('espresso-ui-theme');
321
+	}
322
+
323
+
324
+	/**
325
+	 * Sets the views for the default list table view.
326
+	 *
327
+	 * @throws EE_Error
328
+	 * @throws ReflectionException
329
+	 */
330
+	protected function _set_list_table_views_default()
331
+	{
332
+		parent::_set_list_table_views_default();
333
+		$new_views    = [
334
+			'today' => [
335
+				'slug'        => 'today',
336
+				'label'       => esc_html__('Today', 'event_espresso'),
337
+				'count'       => $this->total_events_today(),
338
+				'bulk_action' => [
339
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
340
+				],
341
+			],
342
+			'month' => [
343
+				'slug'        => 'month',
344
+				'label'       => esc_html__('This Month', 'event_espresso'),
345
+				'count'       => $this->total_events_this_month(),
346
+				'bulk_action' => [
347
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
348
+				],
349
+			],
350
+		];
351
+		$this->_views = array_merge($this->_views, $new_views);
352
+	}
353
+
354
+
355
+	/**
356
+	 * Returns the extra action links for the default list table view.
357
+	 *
358
+	 * @param array    $action_links
359
+	 * @param EE_Event $event
360
+	 * @return array
361
+	 * @throws EE_Error
362
+	 * @throws ReflectionException
363
+	 */
364
+	public function extra_list_table_actions(array $action_links, EE_Event $event): array
365
+	{
366
+		if (
367
+		EE_Registry::instance()->CAP->current_user_can(
368
+			'ee_read_registrations',
369
+			'espresso_registrations_reports',
370
+			$event->ID()
371
+		)
372
+		) {
373
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce(
374
+				[
375
+					'action' => 'reports',
376
+					'EVT_ID' => $event->ID(),
377
+				],
378
+				REG_ADMIN_URL
379
+			);
380
+
381
+			$action_links[] = '
382 382
                 <a href="' . $reports_link . '"
383 383
                     aria-label="' . esc_attr__('View Report', 'event_espresso') . '"
384 384
                     class="ee-aria-tooltip button button--icon-only"
385 385
                 >
386 386
                     <span class="dashicons dashicons-chart-bar"></span>
387 387
                 </a>';
388
-        }
389
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
390
-            EE_Registry::instance()->load_helper('MSG_Template');
391
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
392
-                'see_notifications_for',
393
-                null,
394
-                ['EVT_ID' => $event->ID()]
395
-            );
396
-        }
397
-        return $action_links;
398
-    }
399
-
400
-
401
-    /**
402
-     * @param $items
403
-     * @return mixed
404
-     */
405
-    public function additional_legend_items($items)
406
-    {
407
-        if (
408
-        EE_Registry::instance()->CAP->current_user_can(
409
-            'ee_read_registrations',
410
-            'espresso_registrations_reports'
411
-        )
412
-        ) {
413
-            $items['reports'] = [
414
-                'class' => 'dashicons dashicons-chart-bar',
415
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
416
-            ];
417
-        }
418
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
419
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
420
-            // $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
421
-            // (can only use numeric offsets when treating strings as arrays)
422
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
423
-                $items['view_related_messages'] = [
424
-                    'class' => $related_for_icon['css_class'],
425
-                    'desc'  => $related_for_icon['label'],
426
-                ];
427
-            }
428
-        }
429
-        return $items;
430
-    }
431
-
432
-
433
-    /**
434
-     * This is the callback method for the duplicate event route
435
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
436
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
437
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
438
-     * After duplication the redirect is to the new event edit page.
439
-     *
440
-     * @return void
441
-     * @throws EE_Error If EE_Event is not available with given ID
442
-     * @throws ReflectionException
443
-     * @access protected
444
-     */
445
-    protected function _duplicate_event()
446
-    {
447
-        // first make sure the ID for the event is in the request.
448
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
449
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
450
-        if (! $EVT_ID) {
451
-            EE_Error::add_error(
452
-                esc_html__(
453
-                    'In order to duplicate an event an Event ID is required.  None was given.',
454
-                    'event_espresso'
455
-                ),
456
-                __FILE__,
457
-                __FUNCTION__,
458
-                __LINE__
459
-            );
460
-            $this->_redirect_after_action(false, '', '', [], true);
461
-            return;
462
-        }
463
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
464
-        $orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
465
-        if (! $orig_event instanceof EE_Event) {
466
-            throw new EE_Error(
467
-                sprintf(
468
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
469
-                    $EVT_ID
470
-                )
471
-            );
472
-        }
473
-        // k now let's clone the $orig_event before getting relations
474
-        $new_event = clone $orig_event;
475
-        // original datetimes
476
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
477
-        // other original relations
478
-        $orig_ven = $orig_event->get_many_related('Venue');
479
-        // reset the ID and modify other details to make it clear this is a dupe
480
-        $new_event->set('EVT_ID', 0);
481
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
482
-        $new_event->set('EVT_name', $new_name);
483
-        $new_event->set(
484
-            'EVT_slug',
485
-            wp_unique_post_slug(
486
-                sanitize_title($orig_event->name()),
487
-                0,
488
-                'publish',
489
-                'espresso_events',
490
-                0
491
-            )
492
-        );
493
-        $new_event->set('status', 'draft');
494
-        // duplicate discussion settings
495
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
496
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
497
-        // save the new event
498
-        $new_event->save();
499
-        // venues
500
-        foreach ($orig_ven as $ven) {
501
-            $new_event->_add_relation_to($ven, 'Venue');
502
-        }
503
-        $new_event->save();
504
-        // now we need to get the question group relations and handle that
505
-        // first primary question groups
506
-        $orig_primary_qgs = $orig_event->get_many_related(
507
-            'Question_Group',
508
-            [['Event_Question_Group.EQG_primary' => true]]
509
-        );
510
-        if (! empty($orig_primary_qgs)) {
511
-            foreach ($orig_primary_qgs as $obj) {
512
-                if ($obj instanceof EE_Question_Group) {
513
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
514
-                }
515
-            }
516
-        }
517
-        // next additional attendee question groups
518
-        $orig_additional_qgs = $orig_event->get_many_related(
519
-            'Question_Group',
520
-            [['Event_Question_Group.EQG_additional' => true]]
521
-        );
522
-        if (! empty($orig_additional_qgs)) {
523
-            foreach ($orig_additional_qgs as $obj) {
524
-                if ($obj instanceof EE_Question_Group) {
525
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
526
-                }
527
-            }
528
-        }
529
-
530
-        $new_event->save();
531
-
532
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
533
-        $cloned_tickets = [];
534
-        foreach ($orig_datetimes as $orig_dtt) {
535
-            if (! $orig_dtt instanceof EE_Datetime) {
536
-                continue;
537
-            }
538
-            $new_dtt      = clone $orig_dtt;
539
-            $orig_tickets = $orig_dtt->tickets();
540
-            // save new dtt then add to event
541
-            $new_dtt->set('DTT_ID', 0);
542
-            $new_dtt->set('DTT_sold', 0);
543
-            $new_dtt->set_reserved(0);
544
-            $new_dtt->save();
545
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
546
-            $new_event->save();
547
-            // now let's get the ticket relations setup.
548
-            foreach ((array) $orig_tickets as $orig_ticket) {
549
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
550
-                if (! $orig_ticket instanceof EE_Ticket) {
551
-                    continue;
552
-                }
553
-                // is this ticket archived?  If it is then let's skip
554
-                if ($orig_ticket->get('TKT_deleted')) {
555
-                    continue;
556
-                }
557
-                // does this original ticket already exist in the clone_tickets cache?
558
-                //  If so we'll just use the new ticket from it.
559
-                if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
560
-                    $new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
561
-                } else {
562
-                    $new_ticket = clone $orig_ticket;
563
-                    // get relations on the $orig_ticket that we need to set up.
564
-                    $orig_prices = $orig_ticket->prices();
565
-                    $new_ticket->set('TKT_ID', 0);
566
-                    $new_ticket->set('TKT_sold', 0);
567
-                    $new_ticket->set('TKT_reserved', 0);
568
-                    // make sure new ticket has ID.
569
-                    $new_ticket->save();
570
-                    // price relations on new ticket need to be setup.
571
-                    foreach ($orig_prices as $orig_price) {
572
-                        // don't clone default prices, just add a relation
573
-                        if ($orig_price->is_default()) {
574
-                            $new_ticket->_add_relation_to($orig_price, 'Price');
575
-                            $new_ticket->save();
576
-                            continue;
577
-                        }
578
-                        $new_price = clone $orig_price;
579
-                        $new_price->set('PRC_ID', 0);
580
-                        $new_price->save();
581
-                        $new_ticket->_add_relation_to($new_price, 'Price');
582
-                    }
583
-                    $new_ticket->save();
584
-
585
-                    do_action(
586
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
587
-                        $orig_ticket,
588
-                        $new_ticket,
589
-                        $orig_prices,
590
-                        $orig_event,
591
-                        $orig_dtt,
592
-                        $new_dtt
593
-                    );
594
-                    $cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
595
-                }
596
-                // k now we can add the new ticket as a relation to the new datetime
597
-                // and make sure it's added to our cached $cloned_tickets array
598
-                // for use with later datetimes that have the same ticket.
599
-                $new_dtt->_add_relation_to($new_ticket, 'Ticket');
600
-            }
601
-            $new_dtt->save();
602
-        }
603
-        // clone taxonomy information
604
-        $taxonomies_to_clone_with = apply_filters(
605
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
606
-            ['espresso_event_categories', 'espresso_event_type', 'post_tag']
607
-        );
608
-        // get terms for original event (notice)
609
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
610
-        // loop through terms and add them to new event.
611
-        foreach ($orig_terms as $term) {
612
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
613
-        }
614
-
615
-        // duplicate other core WP_Post items for this event.
616
-        // post thumbnail (feature image).
617
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
618
-        if ($feature_image_id) {
619
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
620
-        }
621
-
622
-        // duplicate page_template setting
623
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
624
-        if ($page_template) {
625
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
626
-        }
627
-
628
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
629
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
630
-        if ($new_event->ID()) {
631
-            $redirect_args = [
632
-                'post'   => $new_event->ID(),
633
-                'action' => 'edit',
634
-            ];
635
-            EE_Error::add_success(
636
-                esc_html__(
637
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
638
-                    'event_espresso'
639
-                )
640
-            );
641
-        } else {
642
-            $redirect_args = [
643
-                'action' => 'default',
644
-            ];
645
-            EE_Error::add_error(
646
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
647
-                __FILE__,
648
-                __FUNCTION__,
649
-                __LINE__
650
-            );
651
-        }
652
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
653
-    }
654
-
655
-
656
-    /**
657
-     * Generates output for the import page.
658
-     *
659
-     * @throws EE_Error
660
-     */
661
-    protected function _import_page()
662
-    {
663
-        $title = esc_html__('Import', 'event_espresso');
664
-        $intro = esc_html__(
665
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
666
-            'event_espresso'
667
-        );
668
-
669
-        $form_url = EVENTS_ADMIN_URL;
670
-        $action   = 'import_events';
671
-        $type     = 'csv';
672
-
673
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
674
-            $title,
675
-            $intro,
676
-            $form_url,
677
-            $action,
678
-            $type
679
-        );
680
-
681
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
682
-            ['action' => 'sample_export_file'],
683
-            $this->_admin_base_url
684
-        );
685
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
686
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
687
-            $this->_template_args,
688
-            true
689
-        );
690
-        $this->display_admin_page_with_sidebar();
691
-    }
692
-
693
-
694
-    /**
695
-     * _import_events
696
-     * This handles displaying the screen and running imports for importing events.
697
-     *
698
-     * @return void
699
-     * @throws EE_Error
700
-     */
701
-    protected function _import_events()
702
-    {
703
-        require_once(EE_CLASSES . 'EE_Import.class.php');
704
-        $success = EE_Import::instance()->import();
705
-        $this->_redirect_after_action(
706
-            $success,
707
-            esc_html__('Import File', 'event_espresso'),
708
-            'ran',
709
-            ['action' => 'import_page'],
710
-            true
711
-        );
712
-    }
713
-
714
-
715
-    /**
716
-     * _events_export
717
-     * Will export all (or just the given event) to a Excel compatible file.
718
-     *
719
-     * @access protected
720
-     * @return void
721
-     */
722
-    protected function _events_export()
723
-    {
724
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
725
-        $EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
726
-        $this->request->mergeRequestParams(
727
-            [
728
-                'export' => 'report',
729
-                'action' => 'all_event_data',
730
-                'EVT_ID' => $EVT_ID,
731
-            ]
732
-        );
733
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
734
-            require_once(EE_CLASSES . 'EE_Export.class.php');
735
-            $EE_Export = EE_Export::instance($this->request->requestParams());
736
-            $EE_Export->export();
737
-        }
738
-    }
739
-
740
-
741
-    /**
742
-     * handle category exports()
743
-     *
744
-     * @return void
745
-     */
746
-    protected function _categories_export()
747
-    {
748
-        $EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
749
-        $this->request->mergeRequestParams(
750
-            [
751
-                'export' => 'report',
752
-                'action' => 'categories',
753
-                'EVT_ID' => $EVT_ID,
754
-            ]
755
-        );
756
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
757
-            require_once(EE_CLASSES . 'EE_Export.class.php');
758
-            $EE_Export = EE_Export::instance($this->request->requestParams());
759
-            $EE_Export->export();
760
-        }
761
-    }
762
-
763
-
764
-    /**
765
-     * Creates a sample CSV file for importing
766
-     */
767
-    protected function _sample_export_file()
768
-    {
769
-        $EE_Export = EE_Export::instance();
770
-        if ($EE_Export instanceof EE_Export) {
771
-            $EE_Export->export();
772
-        }
773
-    }
774
-
775
-
776
-    /*************        Template Settings        *************/
777
-    /**
778
-     * Generates template settings page output
779
-     *
780
-     * @throws DomainException
781
-     * @throws EE_Error
782
-     * @throws InvalidArgumentException
783
-     * @throws InvalidDataTypeException
784
-     * @throws InvalidInterfaceException
785
-     */
786
-    protected function _template_settings()
787
-    {
788
-        $this->_template_args['values'] = $this->_yes_no_values;
789
-        /**
790
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
791
-         * from General_Settings_Admin_Page to here.
792
-         */
793
-        $this->_template_args = apply_filters(
794
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
795
-            $this->_template_args
796
-        );
797
-        $this->_set_add_edit_form_tags('update_template_settings');
798
-        $this->_set_publish_post_box_vars();
799
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
800
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
801
-            $this->_template_args,
802
-            true
803
-        );
804
-        $this->display_admin_page_with_sidebar();
805
-    }
806
-
807
-
808
-    /**
809
-     * Handler for updating template settings.
810
-     *
811
-     * @throws EE_Error
812
-     */
813
-    protected function _update_template_settings()
814
-    {
815
-        /**
816
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
817
-         * from General_Settings_Admin_Page to here.
818
-         */
819
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
820
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
821
-            EE_Registry::instance()->CFG->template_settings,
822
-            $this->request->requestParams()
823
-        );
824
-        // update custom post type slugs and detect if we need to flush rewrite rules
825
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
826
-
827
-        $event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
828
-
829
-        EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
830
-            ? EEH_URL::slugify($event_cpt_slug, 'events')
831
-            : EE_Registry::instance()->CFG->core->event_cpt_slug;
832
-
833
-        $what    = esc_html__('Template Settings', 'event_espresso');
834
-        $success = $this->_update_espresso_configuration(
835
-            $what,
836
-            EE_Registry::instance()->CFG->template_settings,
837
-            __FILE__,
838
-            __FUNCTION__,
839
-            __LINE__
840
-        );
841
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
842
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
843
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
844
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
845
-            );
846
-            $rewrite_rules->flush();
847
-        }
848
-        $this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
849
-    }
850
-
851
-
852
-    /**
853
-     * _premium_event_editor_meta_boxes
854
-     * add all metaboxes related to the event_editor
855
-     *
856
-     * @access protected
857
-     * @return void
858
-     * @throws EE_Error
859
-     * @throws ReflectionException
860
-     */
861
-    protected function _premium_event_editor_meta_boxes()
862
-    {
863
-        $this->verify_cpt_object();
864
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
865
-        if (
866
-            ! $this->admin_config->useAdvancedEditor()
867
-            || ! $this->feature->allowed('use_reg_options_meta_box')
868
-        ) {
869
-            $this->addMetaBox(
870
-                'espresso_event_editor_event_options',
871
-                esc_html__('Event Registration Options', 'event_espresso'),
872
-                [$this, 'registration_options_meta_box'],
873
-                $this->page_slug,
874
-                'side',
875
-                'core'
876
-            );
877
-        }
878
-    }
879
-
880
-
881
-    /**
882
-     * override caf metabox
883
-     *
884
-     * @return void
885
-     * @throws EE_Error
886
-     * @throws ReflectionException
887
-     */
888
-    public function registration_options_meta_box()
889
-    {
890
-        $yes_no_values = [
891
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
892
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
893
-        ];
894
-
895
-        $default_reg_status_values = EEM_Registration::reg_status_array(
896
-            [
897
-                EEM_Registration::status_id_cancelled,
898
-                EEM_Registration::status_id_declined,
899
-                EEM_Registration::status_id_incomplete,
900
-                EEM_Registration::status_id_wait_list,
901
-            ],
902
-            true
903
-        );
904
-
905
-        $template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
906
-        $template_args['_event']           = $this->_cpt_model_obj;
907
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
908
-
909
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
910
-            'default_reg_status',
911
-            $default_reg_status_values,
912
-            $this->_cpt_model_obj->default_registration_status(),
913
-            '',
914
-            'ee-input-width--reg',
915
-            false
916
-        );
917
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
918
-            'display_desc',
919
-            $yes_no_values,
920
-            $this->_cpt_model_obj->display_description()
921
-        );
922
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
923
-            'display_ticket_selector',
924
-            $yes_no_values,
925
-            $this->_cpt_model_obj->display_ticket_selector(),
926
-            '',
927
-            'ee-input-width--small',
928
-            false
929
-        );
930
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
931
-            'EVT_default_registration_status',
932
-            $default_reg_status_values,
933
-            $this->_cpt_model_obj->default_registration_status(),
934
-            '',
935
-            'ee-input-width--reg',
936
-            false
937
-        );
938
-        $template_args['additional_registration_options'] = apply_filters(
939
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
940
-            '',
941
-            $template_args,
942
-            $yes_no_values,
943
-            $default_reg_status_values
944
-        );
945
-        EEH_Template::display_template(
946
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
947
-            $template_args
948
-        );
949
-    }
950
-
951
-
952
-
953
-    /**
954
-     * wp_list_table_mods for caf
955
-     * ============================
956
-     */
957
-
958
-
959
-    /**
960
-     * espresso_event_months_dropdown
961
-     *
962
-     * @deprecatd 5.0.0.p
963
-     * @access public
964
-     * @return string                dropdown listing month/year selections for events.
965
-     * @throws EE_Error
966
-     */
967
-    public function espresso_event_months_dropdown(): string
968
-    {
969
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
970
-        // Note we need to include any other filters that are set!
971
-        return EEH_Form_Fields::generate_event_months_dropdown(
972
-            $this->request->getRequestParam('month_range'),
973
-            $this->request->getRequestParam('status'),
974
-            $this->request->getRequestParam('EVT_CAT', 0, 'int'),
975
-            $this->request->getRequestParam('active_status')
976
-        );
977
-    }
978
-
979
-
980
-    /**
981
-     * returns a list of "active" statuses on the event
982
-     *
983
-     * @deprecatd 5.0.0.p
984
-     * @param string $current_value whatever the current active status is
985
-     * @return string
986
-     */
987
-    public function active_status_dropdown(string $current_value = ''): string
988
-    {
989
-        $select_name = 'active_status';
990
-        $values      = [
991
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
992
-            'active'   => esc_html__('Active', 'event_espresso'),
993
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
994
-            'expired'  => esc_html__('Expired', 'event_espresso'),
995
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
996
-        ];
997
-
998
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value);
999
-    }
1000
-
1001
-
1002
-    /**
1003
-     * returns a list of "venues"
1004
-     *
1005
-     * @deprecatd 5.0.0.p
1006
-     * @param string $current_value whatever the current active status is
1007
-     * @return string
1008
-     * @throws EE_Error
1009
-     * @throws ReflectionException
1010
-     */
1011
-    protected function venuesDropdown(string $current_value = ''): string
1012
-    {
1013
-        $values = ['' => esc_html__('All Venues', 'event_espresso')];
1014
-        // populate the list of venues.
1015
-        $venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1016
-
1017
-        foreach ($venues as $venue) {
1018
-            $values[ $venue->ID() ] = $venue->name();
1019
-        }
1020
-
1021
-        return EEH_Form_Fields::select_input('venue', $values, $current_value);
1022
-    }
1023
-
1024
-
1025
-    /**
1026
-     * output a dropdown of the categories for the category filter on the event admin list table
1027
-     *
1028
-     * @deprecatd 5.0.0.p
1029
-     * @access  public
1030
-     * @return string html
1031
-     * @throws EE_Error
1032
-     * @throws ReflectionException
1033
-     */
1034
-    public function category_dropdown(): string
1035
-    {
1036
-        return EEH_Form_Fields::generate_event_category_dropdown(
1037
-            $this->request->getRequestParam('EVT_CAT', -1, 'int')
1038
-        );
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * get total number of events today
1044
-     *
1045
-     * @access public
1046
-     * @return int
1047
-     * @throws EE_Error
1048
-     * @throws InvalidArgumentException
1049
-     * @throws InvalidDataTypeException
1050
-     * @throws InvalidInterfaceException
1051
-     * @throws ReflectionException
1052
-     */
1053
-    public function total_events_today(): int
1054
-    {
1055
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1056
-            'DTT_EVT_start',
1057
-            date('Y-m-d') . ' 00:00:00',
1058
-            'Y-m-d H:i:s',
1059
-            'UTC'
1060
-        );
1061
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1062
-            'DTT_EVT_start',
1063
-            date('Y-m-d') . ' 23:59:59',
1064
-            'Y-m-d H:i:s',
1065
-            'UTC'
1066
-        );
1067
-        $where = [
1068
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1069
-        ];
1070
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * get total number of events this month
1076
-     *
1077
-     * @access public
1078
-     * @return int
1079
-     * @throws EE_Error
1080
-     * @throws InvalidArgumentException
1081
-     * @throws InvalidDataTypeException
1082
-     * @throws InvalidInterfaceException
1083
-     * @throws ReflectionException
1084
-     */
1085
-    public function total_events_this_month(): int
1086
-    {
1087
-        // Dates
1088
-        $this_year_r     = date('Y');
1089
-        $this_month_r    = date('m');
1090
-        $days_this_month = date('t');
1091
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1092
-            'DTT_EVT_start',
1093
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1094
-            'Y-m-d H:i:s',
1095
-            'UTC'
1096
-        );
1097
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1098
-            'DTT_EVT_start',
1099
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1100
-            'Y-m-d H:i:s',
1101
-            'UTC'
1102
-        );
1103
-        $where           = [
1104
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1105
-        ];
1106
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1107
-    }
1108
-
1109
-
1110
-    /** DEFAULT TICKETS STUFF **/
1111
-
1112
-    /**
1113
-     * Output default tickets list table view.
1114
-     *
1115
-     * @throws EE_Error
1116
-     */
1117
-    public function _tickets_overview_list_table()
1118
-    {
1119
-        if (
1120
-            $this->admin_config->useAdvancedEditor()
1121
-            && $this->feature->allowed('use_default_ticket_manager')
1122
-        ) {
1123
-            // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1124
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1125
-                EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1126
-                [],
1127
-                true
1128
-            );
1129
-            $this->display_admin_page_with_no_sidebar();
1130
-        } else {
1131
-            $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1132
-            $this->display_admin_list_table_page_with_no_sidebar();
1133
-        }
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * @param int  $per_page
1139
-     * @param bool $count
1140
-     * @param bool $trashed
1141
-     * @return EE_Soft_Delete_Base_Class[]|int
1142
-     * @throws EE_Error
1143
-     * @throws ReflectionException
1144
-     */
1145
-    public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1146
-    {
1147
-        $orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1148
-        $order   = $this->request->getRequestParam('order', 'ASC');
1149
-        switch ($orderby) {
1150
-            case 'TKT_name':
1151
-                $orderby = ['TKT_name' => $order];
1152
-                break;
1153
-            case 'TKT_price':
1154
-                $orderby = ['TKT_price' => $order];
1155
-                break;
1156
-            case 'TKT_uses':
1157
-                $orderby = ['TKT_uses' => $order];
1158
-                break;
1159
-            case 'TKT_min':
1160
-                $orderby = ['TKT_min' => $order];
1161
-                break;
1162
-            case 'TKT_max':
1163
-                $orderby = ['TKT_max' => $order];
1164
-                break;
1165
-            case 'TKT_qty':
1166
-                $orderby = ['TKT_qty' => $order];
1167
-                break;
1168
-        }
1169
-
1170
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
1171
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1172
-        $offset       = ($current_page - 1) * $per_page;
1173
-
1174
-        $where = [
1175
-            'TKT_is_default' => 1,
1176
-            'TKT_deleted'    => $trashed,
1177
-        ];
1178
-
1179
-        $search_term = $this->request->getRequestParam('s');
1180
-        if ($search_term) {
1181
-            $search_term = '%' . $search_term . '%';
1182
-            $where['OR'] = [
1183
-                'TKT_name'        => ['LIKE', $search_term],
1184
-                'TKT_description' => ['LIKE', $search_term],
1185
-            ];
1186
-        }
1187
-
1188
-        return $count
1189
-            ? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1190
-            : EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1191
-                [
1192
-                    $where,
1193
-                    'order_by' => $orderby,
1194
-                    'limit'    => [$offset, $per_page],
1195
-                    'group_by' => 'TKT_ID',
1196
-                ]
1197
-            );
1198
-    }
1199
-
1200
-
1201
-    /**
1202
-     * @param bool $trash
1203
-     * @throws EE_Error
1204
-     * @throws InvalidArgumentException
1205
-     * @throws InvalidDataTypeException
1206
-     * @throws InvalidInterfaceException
1207
-     * @throws ReflectionException
1208
-     */
1209
-    protected function _trash_or_restore_ticket(bool $trash = false)
1210
-    {
1211
-        $success = 1;
1212
-        $TKT     = EEM_Ticket::instance();
1213
-        // checkboxes?
1214
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1215
-        if (! empty($checkboxes)) {
1216
-            // if array has more than one element then success message should be plural
1217
-            $success = count($checkboxes) > 1 ? 2 : 1;
1218
-            // cycle thru the boxes
1219
-            foreach ($checkboxes as $TKT_ID => $value) {
1220
-                if ($trash) {
1221
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1222
-                        $success = 0;
1223
-                    }
1224
-                } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1225
-                    $success = 0;
1226
-                }
1227
-            }
1228
-        } else {
1229
-            // grab single id and trash
1230
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1231
-            if ($trash) {
1232
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1233
-                    $success = 0;
1234
-                }
1235
-            } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1236
-                $success = 0;
1237
-            }
1238
-        }
1239
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1240
-        $query_args  = [
1241
-            'action' => 'ticket_list_table',
1242
-            'status' => $trash ? '' : 'trashed',
1243
-        ];
1244
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * Handles trashing default ticket.
1250
-     *
1251
-     * @throws EE_Error
1252
-     * @throws ReflectionException
1253
-     */
1254
-    protected function _delete_ticket()
1255
-    {
1256
-        $success = 1;
1257
-        // checkboxes?
1258
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1259
-        if (! empty($checkboxes)) {
1260
-            // if array has more than one element then success message should be plural
1261
-            $success = count($checkboxes) > 1 ? 2 : 1;
1262
-            // cycle thru the boxes
1263
-            foreach ($checkboxes as $TKT_ID => $value) {
1264
-                // delete
1265
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1266
-                    $success = 0;
1267
-                }
1268
-            }
1269
-        } else {
1270
-            // grab single id and trash
1271
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1272
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1273
-                $success = 0;
1274
-            }
1275
-        }
1276
-        $action_desc = 'deleted';
1277
-        $query_args  = [
1278
-            'action' => 'ticket_list_table',
1279
-            'status' => 'trashed',
1280
-        ];
1281
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1282
-        if (
1283
-        EEM_Ticket::instance()->count_deleted_and_undeleted(
1284
-            [['TKT_is_default' => 1]],
1285
-            'TKT_ID',
1286
-            true
1287
-        )
1288
-        ) {
1289
-            $query_args = [];
1290
-        }
1291
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1292
-    }
1293
-
1294
-
1295
-    /**
1296
-     * @param int $TKT_ID
1297
-     * @return bool|int
1298
-     * @throws EE_Error
1299
-     * @throws ReflectionException
1300
-     */
1301
-    protected function _delete_the_ticket(int $TKT_ID)
1302
-    {
1303
-        $ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1304
-        if (! $ticket instanceof EE_Ticket) {
1305
-            return false;
1306
-        }
1307
-        $ticket->_remove_relations('Datetime');
1308
-        // delete all related prices first
1309
-        $ticket->delete_related_permanently('Price');
1310
-        return $ticket->delete_permanently();
1311
-    }
388
+		}
389
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
390
+			EE_Registry::instance()->load_helper('MSG_Template');
391
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
392
+				'see_notifications_for',
393
+				null,
394
+				['EVT_ID' => $event->ID()]
395
+			);
396
+		}
397
+		return $action_links;
398
+	}
399
+
400
+
401
+	/**
402
+	 * @param $items
403
+	 * @return mixed
404
+	 */
405
+	public function additional_legend_items($items)
406
+	{
407
+		if (
408
+		EE_Registry::instance()->CAP->current_user_can(
409
+			'ee_read_registrations',
410
+			'espresso_registrations_reports'
411
+		)
412
+		) {
413
+			$items['reports'] = [
414
+				'class' => 'dashicons dashicons-chart-bar',
415
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
416
+			];
417
+		}
418
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
419
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
420
+			// $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
421
+			// (can only use numeric offsets when treating strings as arrays)
422
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
423
+				$items['view_related_messages'] = [
424
+					'class' => $related_for_icon['css_class'],
425
+					'desc'  => $related_for_icon['label'],
426
+				];
427
+			}
428
+		}
429
+		return $items;
430
+	}
431
+
432
+
433
+	/**
434
+	 * This is the callback method for the duplicate event route
435
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
436
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
437
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
438
+	 * After duplication the redirect is to the new event edit page.
439
+	 *
440
+	 * @return void
441
+	 * @throws EE_Error If EE_Event is not available with given ID
442
+	 * @throws ReflectionException
443
+	 * @access protected
444
+	 */
445
+	protected function _duplicate_event()
446
+	{
447
+		// first make sure the ID for the event is in the request.
448
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
449
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
450
+		if (! $EVT_ID) {
451
+			EE_Error::add_error(
452
+				esc_html__(
453
+					'In order to duplicate an event an Event ID is required.  None was given.',
454
+					'event_espresso'
455
+				),
456
+				__FILE__,
457
+				__FUNCTION__,
458
+				__LINE__
459
+			);
460
+			$this->_redirect_after_action(false, '', '', [], true);
461
+			return;
462
+		}
463
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
464
+		$orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
465
+		if (! $orig_event instanceof EE_Event) {
466
+			throw new EE_Error(
467
+				sprintf(
468
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
469
+					$EVT_ID
470
+				)
471
+			);
472
+		}
473
+		// k now let's clone the $orig_event before getting relations
474
+		$new_event = clone $orig_event;
475
+		// original datetimes
476
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
477
+		// other original relations
478
+		$orig_ven = $orig_event->get_many_related('Venue');
479
+		// reset the ID and modify other details to make it clear this is a dupe
480
+		$new_event->set('EVT_ID', 0);
481
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
482
+		$new_event->set('EVT_name', $new_name);
483
+		$new_event->set(
484
+			'EVT_slug',
485
+			wp_unique_post_slug(
486
+				sanitize_title($orig_event->name()),
487
+				0,
488
+				'publish',
489
+				'espresso_events',
490
+				0
491
+			)
492
+		);
493
+		$new_event->set('status', 'draft');
494
+		// duplicate discussion settings
495
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
496
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
497
+		// save the new event
498
+		$new_event->save();
499
+		// venues
500
+		foreach ($orig_ven as $ven) {
501
+			$new_event->_add_relation_to($ven, 'Venue');
502
+		}
503
+		$new_event->save();
504
+		// now we need to get the question group relations and handle that
505
+		// first primary question groups
506
+		$orig_primary_qgs = $orig_event->get_many_related(
507
+			'Question_Group',
508
+			[['Event_Question_Group.EQG_primary' => true]]
509
+		);
510
+		if (! empty($orig_primary_qgs)) {
511
+			foreach ($orig_primary_qgs as $obj) {
512
+				if ($obj instanceof EE_Question_Group) {
513
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
514
+				}
515
+			}
516
+		}
517
+		// next additional attendee question groups
518
+		$orig_additional_qgs = $orig_event->get_many_related(
519
+			'Question_Group',
520
+			[['Event_Question_Group.EQG_additional' => true]]
521
+		);
522
+		if (! empty($orig_additional_qgs)) {
523
+			foreach ($orig_additional_qgs as $obj) {
524
+				if ($obj instanceof EE_Question_Group) {
525
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
526
+				}
527
+			}
528
+		}
529
+
530
+		$new_event->save();
531
+
532
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
533
+		$cloned_tickets = [];
534
+		foreach ($orig_datetimes as $orig_dtt) {
535
+			if (! $orig_dtt instanceof EE_Datetime) {
536
+				continue;
537
+			}
538
+			$new_dtt      = clone $orig_dtt;
539
+			$orig_tickets = $orig_dtt->tickets();
540
+			// save new dtt then add to event
541
+			$new_dtt->set('DTT_ID', 0);
542
+			$new_dtt->set('DTT_sold', 0);
543
+			$new_dtt->set_reserved(0);
544
+			$new_dtt->save();
545
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
546
+			$new_event->save();
547
+			// now let's get the ticket relations setup.
548
+			foreach ((array) $orig_tickets as $orig_ticket) {
549
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
550
+				if (! $orig_ticket instanceof EE_Ticket) {
551
+					continue;
552
+				}
553
+				// is this ticket archived?  If it is then let's skip
554
+				if ($orig_ticket->get('TKT_deleted')) {
555
+					continue;
556
+				}
557
+				// does this original ticket already exist in the clone_tickets cache?
558
+				//  If so we'll just use the new ticket from it.
559
+				if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
560
+					$new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
561
+				} else {
562
+					$new_ticket = clone $orig_ticket;
563
+					// get relations on the $orig_ticket that we need to set up.
564
+					$orig_prices = $orig_ticket->prices();
565
+					$new_ticket->set('TKT_ID', 0);
566
+					$new_ticket->set('TKT_sold', 0);
567
+					$new_ticket->set('TKT_reserved', 0);
568
+					// make sure new ticket has ID.
569
+					$new_ticket->save();
570
+					// price relations on new ticket need to be setup.
571
+					foreach ($orig_prices as $orig_price) {
572
+						// don't clone default prices, just add a relation
573
+						if ($orig_price->is_default()) {
574
+							$new_ticket->_add_relation_to($orig_price, 'Price');
575
+							$new_ticket->save();
576
+							continue;
577
+						}
578
+						$new_price = clone $orig_price;
579
+						$new_price->set('PRC_ID', 0);
580
+						$new_price->save();
581
+						$new_ticket->_add_relation_to($new_price, 'Price');
582
+					}
583
+					$new_ticket->save();
584
+
585
+					do_action(
586
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
587
+						$orig_ticket,
588
+						$new_ticket,
589
+						$orig_prices,
590
+						$orig_event,
591
+						$orig_dtt,
592
+						$new_dtt
593
+					);
594
+					$cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
595
+				}
596
+				// k now we can add the new ticket as a relation to the new datetime
597
+				// and make sure it's added to our cached $cloned_tickets array
598
+				// for use with later datetimes that have the same ticket.
599
+				$new_dtt->_add_relation_to($new_ticket, 'Ticket');
600
+			}
601
+			$new_dtt->save();
602
+		}
603
+		// clone taxonomy information
604
+		$taxonomies_to_clone_with = apply_filters(
605
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
606
+			['espresso_event_categories', 'espresso_event_type', 'post_tag']
607
+		);
608
+		// get terms for original event (notice)
609
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
610
+		// loop through terms and add them to new event.
611
+		foreach ($orig_terms as $term) {
612
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
613
+		}
614
+
615
+		// duplicate other core WP_Post items for this event.
616
+		// post thumbnail (feature image).
617
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
618
+		if ($feature_image_id) {
619
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
620
+		}
621
+
622
+		// duplicate page_template setting
623
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
624
+		if ($page_template) {
625
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
626
+		}
627
+
628
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
629
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
630
+		if ($new_event->ID()) {
631
+			$redirect_args = [
632
+				'post'   => $new_event->ID(),
633
+				'action' => 'edit',
634
+			];
635
+			EE_Error::add_success(
636
+				esc_html__(
637
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
638
+					'event_espresso'
639
+				)
640
+			);
641
+		} else {
642
+			$redirect_args = [
643
+				'action' => 'default',
644
+			];
645
+			EE_Error::add_error(
646
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
647
+				__FILE__,
648
+				__FUNCTION__,
649
+				__LINE__
650
+			);
651
+		}
652
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
653
+	}
654
+
655
+
656
+	/**
657
+	 * Generates output for the import page.
658
+	 *
659
+	 * @throws EE_Error
660
+	 */
661
+	protected function _import_page()
662
+	{
663
+		$title = esc_html__('Import', 'event_espresso');
664
+		$intro = esc_html__(
665
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
666
+			'event_espresso'
667
+		);
668
+
669
+		$form_url = EVENTS_ADMIN_URL;
670
+		$action   = 'import_events';
671
+		$type     = 'csv';
672
+
673
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
674
+			$title,
675
+			$intro,
676
+			$form_url,
677
+			$action,
678
+			$type
679
+		);
680
+
681
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
682
+			['action' => 'sample_export_file'],
683
+			$this->_admin_base_url
684
+		);
685
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
686
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
687
+			$this->_template_args,
688
+			true
689
+		);
690
+		$this->display_admin_page_with_sidebar();
691
+	}
692
+
693
+
694
+	/**
695
+	 * _import_events
696
+	 * This handles displaying the screen and running imports for importing events.
697
+	 *
698
+	 * @return void
699
+	 * @throws EE_Error
700
+	 */
701
+	protected function _import_events()
702
+	{
703
+		require_once(EE_CLASSES . 'EE_Import.class.php');
704
+		$success = EE_Import::instance()->import();
705
+		$this->_redirect_after_action(
706
+			$success,
707
+			esc_html__('Import File', 'event_espresso'),
708
+			'ran',
709
+			['action' => 'import_page'],
710
+			true
711
+		);
712
+	}
713
+
714
+
715
+	/**
716
+	 * _events_export
717
+	 * Will export all (or just the given event) to a Excel compatible file.
718
+	 *
719
+	 * @access protected
720
+	 * @return void
721
+	 */
722
+	protected function _events_export()
723
+	{
724
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
725
+		$EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
726
+		$this->request->mergeRequestParams(
727
+			[
728
+				'export' => 'report',
729
+				'action' => 'all_event_data',
730
+				'EVT_ID' => $EVT_ID,
731
+			]
732
+		);
733
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
734
+			require_once(EE_CLASSES . 'EE_Export.class.php');
735
+			$EE_Export = EE_Export::instance($this->request->requestParams());
736
+			$EE_Export->export();
737
+		}
738
+	}
739
+
740
+
741
+	/**
742
+	 * handle category exports()
743
+	 *
744
+	 * @return void
745
+	 */
746
+	protected function _categories_export()
747
+	{
748
+		$EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
749
+		$this->request->mergeRequestParams(
750
+			[
751
+				'export' => 'report',
752
+				'action' => 'categories',
753
+				'EVT_ID' => $EVT_ID,
754
+			]
755
+		);
756
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
757
+			require_once(EE_CLASSES . 'EE_Export.class.php');
758
+			$EE_Export = EE_Export::instance($this->request->requestParams());
759
+			$EE_Export->export();
760
+		}
761
+	}
762
+
763
+
764
+	/**
765
+	 * Creates a sample CSV file for importing
766
+	 */
767
+	protected function _sample_export_file()
768
+	{
769
+		$EE_Export = EE_Export::instance();
770
+		if ($EE_Export instanceof EE_Export) {
771
+			$EE_Export->export();
772
+		}
773
+	}
774
+
775
+
776
+	/*************        Template Settings        *************/
777
+	/**
778
+	 * Generates template settings page output
779
+	 *
780
+	 * @throws DomainException
781
+	 * @throws EE_Error
782
+	 * @throws InvalidArgumentException
783
+	 * @throws InvalidDataTypeException
784
+	 * @throws InvalidInterfaceException
785
+	 */
786
+	protected function _template_settings()
787
+	{
788
+		$this->_template_args['values'] = $this->_yes_no_values;
789
+		/**
790
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
791
+		 * from General_Settings_Admin_Page to here.
792
+		 */
793
+		$this->_template_args = apply_filters(
794
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
795
+			$this->_template_args
796
+		);
797
+		$this->_set_add_edit_form_tags('update_template_settings');
798
+		$this->_set_publish_post_box_vars();
799
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
800
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
801
+			$this->_template_args,
802
+			true
803
+		);
804
+		$this->display_admin_page_with_sidebar();
805
+	}
806
+
807
+
808
+	/**
809
+	 * Handler for updating template settings.
810
+	 *
811
+	 * @throws EE_Error
812
+	 */
813
+	protected function _update_template_settings()
814
+	{
815
+		/**
816
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
817
+		 * from General_Settings_Admin_Page to here.
818
+		 */
819
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
820
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
821
+			EE_Registry::instance()->CFG->template_settings,
822
+			$this->request->requestParams()
823
+		);
824
+		// update custom post type slugs and detect if we need to flush rewrite rules
825
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
826
+
827
+		$event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
828
+
829
+		EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
830
+			? EEH_URL::slugify($event_cpt_slug, 'events')
831
+			: EE_Registry::instance()->CFG->core->event_cpt_slug;
832
+
833
+		$what    = esc_html__('Template Settings', 'event_espresso');
834
+		$success = $this->_update_espresso_configuration(
835
+			$what,
836
+			EE_Registry::instance()->CFG->template_settings,
837
+			__FILE__,
838
+			__FUNCTION__,
839
+			__LINE__
840
+		);
841
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
842
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
843
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
844
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
845
+			);
846
+			$rewrite_rules->flush();
847
+		}
848
+		$this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
849
+	}
850
+
851
+
852
+	/**
853
+	 * _premium_event_editor_meta_boxes
854
+	 * add all metaboxes related to the event_editor
855
+	 *
856
+	 * @access protected
857
+	 * @return void
858
+	 * @throws EE_Error
859
+	 * @throws ReflectionException
860
+	 */
861
+	protected function _premium_event_editor_meta_boxes()
862
+	{
863
+		$this->verify_cpt_object();
864
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
865
+		if (
866
+			! $this->admin_config->useAdvancedEditor()
867
+			|| ! $this->feature->allowed('use_reg_options_meta_box')
868
+		) {
869
+			$this->addMetaBox(
870
+				'espresso_event_editor_event_options',
871
+				esc_html__('Event Registration Options', 'event_espresso'),
872
+				[$this, 'registration_options_meta_box'],
873
+				$this->page_slug,
874
+				'side',
875
+				'core'
876
+			);
877
+		}
878
+	}
879
+
880
+
881
+	/**
882
+	 * override caf metabox
883
+	 *
884
+	 * @return void
885
+	 * @throws EE_Error
886
+	 * @throws ReflectionException
887
+	 */
888
+	public function registration_options_meta_box()
889
+	{
890
+		$yes_no_values = [
891
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
892
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
893
+		];
894
+
895
+		$default_reg_status_values = EEM_Registration::reg_status_array(
896
+			[
897
+				EEM_Registration::status_id_cancelled,
898
+				EEM_Registration::status_id_declined,
899
+				EEM_Registration::status_id_incomplete,
900
+				EEM_Registration::status_id_wait_list,
901
+			],
902
+			true
903
+		);
904
+
905
+		$template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
906
+		$template_args['_event']           = $this->_cpt_model_obj;
907
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
908
+
909
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
910
+			'default_reg_status',
911
+			$default_reg_status_values,
912
+			$this->_cpt_model_obj->default_registration_status(),
913
+			'',
914
+			'ee-input-width--reg',
915
+			false
916
+		);
917
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
918
+			'display_desc',
919
+			$yes_no_values,
920
+			$this->_cpt_model_obj->display_description()
921
+		);
922
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
923
+			'display_ticket_selector',
924
+			$yes_no_values,
925
+			$this->_cpt_model_obj->display_ticket_selector(),
926
+			'',
927
+			'ee-input-width--small',
928
+			false
929
+		);
930
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
931
+			'EVT_default_registration_status',
932
+			$default_reg_status_values,
933
+			$this->_cpt_model_obj->default_registration_status(),
934
+			'',
935
+			'ee-input-width--reg',
936
+			false
937
+		);
938
+		$template_args['additional_registration_options'] = apply_filters(
939
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
940
+			'',
941
+			$template_args,
942
+			$yes_no_values,
943
+			$default_reg_status_values
944
+		);
945
+		EEH_Template::display_template(
946
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
947
+			$template_args
948
+		);
949
+	}
950
+
951
+
952
+
953
+	/**
954
+	 * wp_list_table_mods for caf
955
+	 * ============================
956
+	 */
957
+
958
+
959
+	/**
960
+	 * espresso_event_months_dropdown
961
+	 *
962
+	 * @deprecatd 5.0.0.p
963
+	 * @access public
964
+	 * @return string                dropdown listing month/year selections for events.
965
+	 * @throws EE_Error
966
+	 */
967
+	public function espresso_event_months_dropdown(): string
968
+	{
969
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
970
+		// Note we need to include any other filters that are set!
971
+		return EEH_Form_Fields::generate_event_months_dropdown(
972
+			$this->request->getRequestParam('month_range'),
973
+			$this->request->getRequestParam('status'),
974
+			$this->request->getRequestParam('EVT_CAT', 0, 'int'),
975
+			$this->request->getRequestParam('active_status')
976
+		);
977
+	}
978
+
979
+
980
+	/**
981
+	 * returns a list of "active" statuses on the event
982
+	 *
983
+	 * @deprecatd 5.0.0.p
984
+	 * @param string $current_value whatever the current active status is
985
+	 * @return string
986
+	 */
987
+	public function active_status_dropdown(string $current_value = ''): string
988
+	{
989
+		$select_name = 'active_status';
990
+		$values      = [
991
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
992
+			'active'   => esc_html__('Active', 'event_espresso'),
993
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
994
+			'expired'  => esc_html__('Expired', 'event_espresso'),
995
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
996
+		];
997
+
998
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value);
999
+	}
1000
+
1001
+
1002
+	/**
1003
+	 * returns a list of "venues"
1004
+	 *
1005
+	 * @deprecatd 5.0.0.p
1006
+	 * @param string $current_value whatever the current active status is
1007
+	 * @return string
1008
+	 * @throws EE_Error
1009
+	 * @throws ReflectionException
1010
+	 */
1011
+	protected function venuesDropdown(string $current_value = ''): string
1012
+	{
1013
+		$values = ['' => esc_html__('All Venues', 'event_espresso')];
1014
+		// populate the list of venues.
1015
+		$venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1016
+
1017
+		foreach ($venues as $venue) {
1018
+			$values[ $venue->ID() ] = $venue->name();
1019
+		}
1020
+
1021
+		return EEH_Form_Fields::select_input('venue', $values, $current_value);
1022
+	}
1023
+
1024
+
1025
+	/**
1026
+	 * output a dropdown of the categories for the category filter on the event admin list table
1027
+	 *
1028
+	 * @deprecatd 5.0.0.p
1029
+	 * @access  public
1030
+	 * @return string html
1031
+	 * @throws EE_Error
1032
+	 * @throws ReflectionException
1033
+	 */
1034
+	public function category_dropdown(): string
1035
+	{
1036
+		return EEH_Form_Fields::generate_event_category_dropdown(
1037
+			$this->request->getRequestParam('EVT_CAT', -1, 'int')
1038
+		);
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * get total number of events today
1044
+	 *
1045
+	 * @access public
1046
+	 * @return int
1047
+	 * @throws EE_Error
1048
+	 * @throws InvalidArgumentException
1049
+	 * @throws InvalidDataTypeException
1050
+	 * @throws InvalidInterfaceException
1051
+	 * @throws ReflectionException
1052
+	 */
1053
+	public function total_events_today(): int
1054
+	{
1055
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1056
+			'DTT_EVT_start',
1057
+			date('Y-m-d') . ' 00:00:00',
1058
+			'Y-m-d H:i:s',
1059
+			'UTC'
1060
+		);
1061
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1062
+			'DTT_EVT_start',
1063
+			date('Y-m-d') . ' 23:59:59',
1064
+			'Y-m-d H:i:s',
1065
+			'UTC'
1066
+		);
1067
+		$where = [
1068
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1069
+		];
1070
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * get total number of events this month
1076
+	 *
1077
+	 * @access public
1078
+	 * @return int
1079
+	 * @throws EE_Error
1080
+	 * @throws InvalidArgumentException
1081
+	 * @throws InvalidDataTypeException
1082
+	 * @throws InvalidInterfaceException
1083
+	 * @throws ReflectionException
1084
+	 */
1085
+	public function total_events_this_month(): int
1086
+	{
1087
+		// Dates
1088
+		$this_year_r     = date('Y');
1089
+		$this_month_r    = date('m');
1090
+		$days_this_month = date('t');
1091
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1092
+			'DTT_EVT_start',
1093
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1094
+			'Y-m-d H:i:s',
1095
+			'UTC'
1096
+		);
1097
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1098
+			'DTT_EVT_start',
1099
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1100
+			'Y-m-d H:i:s',
1101
+			'UTC'
1102
+		);
1103
+		$where           = [
1104
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1105
+		];
1106
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1107
+	}
1108
+
1109
+
1110
+	/** DEFAULT TICKETS STUFF **/
1111
+
1112
+	/**
1113
+	 * Output default tickets list table view.
1114
+	 *
1115
+	 * @throws EE_Error
1116
+	 */
1117
+	public function _tickets_overview_list_table()
1118
+	{
1119
+		if (
1120
+			$this->admin_config->useAdvancedEditor()
1121
+			&& $this->feature->allowed('use_default_ticket_manager')
1122
+		) {
1123
+			// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1124
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1125
+				EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1126
+				[],
1127
+				true
1128
+			);
1129
+			$this->display_admin_page_with_no_sidebar();
1130
+		} else {
1131
+			$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1132
+			$this->display_admin_list_table_page_with_no_sidebar();
1133
+		}
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * @param int  $per_page
1139
+	 * @param bool $count
1140
+	 * @param bool $trashed
1141
+	 * @return EE_Soft_Delete_Base_Class[]|int
1142
+	 * @throws EE_Error
1143
+	 * @throws ReflectionException
1144
+	 */
1145
+	public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1146
+	{
1147
+		$orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1148
+		$order   = $this->request->getRequestParam('order', 'ASC');
1149
+		switch ($orderby) {
1150
+			case 'TKT_name':
1151
+				$orderby = ['TKT_name' => $order];
1152
+				break;
1153
+			case 'TKT_price':
1154
+				$orderby = ['TKT_price' => $order];
1155
+				break;
1156
+			case 'TKT_uses':
1157
+				$orderby = ['TKT_uses' => $order];
1158
+				break;
1159
+			case 'TKT_min':
1160
+				$orderby = ['TKT_min' => $order];
1161
+				break;
1162
+			case 'TKT_max':
1163
+				$orderby = ['TKT_max' => $order];
1164
+				break;
1165
+			case 'TKT_qty':
1166
+				$orderby = ['TKT_qty' => $order];
1167
+				break;
1168
+		}
1169
+
1170
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
1171
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1172
+		$offset       = ($current_page - 1) * $per_page;
1173
+
1174
+		$where = [
1175
+			'TKT_is_default' => 1,
1176
+			'TKT_deleted'    => $trashed,
1177
+		];
1178
+
1179
+		$search_term = $this->request->getRequestParam('s');
1180
+		if ($search_term) {
1181
+			$search_term = '%' . $search_term . '%';
1182
+			$where['OR'] = [
1183
+				'TKT_name'        => ['LIKE', $search_term],
1184
+				'TKT_description' => ['LIKE', $search_term],
1185
+			];
1186
+		}
1187
+
1188
+		return $count
1189
+			? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1190
+			: EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1191
+				[
1192
+					$where,
1193
+					'order_by' => $orderby,
1194
+					'limit'    => [$offset, $per_page],
1195
+					'group_by' => 'TKT_ID',
1196
+				]
1197
+			);
1198
+	}
1199
+
1200
+
1201
+	/**
1202
+	 * @param bool $trash
1203
+	 * @throws EE_Error
1204
+	 * @throws InvalidArgumentException
1205
+	 * @throws InvalidDataTypeException
1206
+	 * @throws InvalidInterfaceException
1207
+	 * @throws ReflectionException
1208
+	 */
1209
+	protected function _trash_or_restore_ticket(bool $trash = false)
1210
+	{
1211
+		$success = 1;
1212
+		$TKT     = EEM_Ticket::instance();
1213
+		// checkboxes?
1214
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1215
+		if (! empty($checkboxes)) {
1216
+			// if array has more than one element then success message should be plural
1217
+			$success = count($checkboxes) > 1 ? 2 : 1;
1218
+			// cycle thru the boxes
1219
+			foreach ($checkboxes as $TKT_ID => $value) {
1220
+				if ($trash) {
1221
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1222
+						$success = 0;
1223
+					}
1224
+				} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1225
+					$success = 0;
1226
+				}
1227
+			}
1228
+		} else {
1229
+			// grab single id and trash
1230
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1231
+			if ($trash) {
1232
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1233
+					$success = 0;
1234
+				}
1235
+			} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1236
+				$success = 0;
1237
+			}
1238
+		}
1239
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1240
+		$query_args  = [
1241
+			'action' => 'ticket_list_table',
1242
+			'status' => $trash ? '' : 'trashed',
1243
+		];
1244
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * Handles trashing default ticket.
1250
+	 *
1251
+	 * @throws EE_Error
1252
+	 * @throws ReflectionException
1253
+	 */
1254
+	protected function _delete_ticket()
1255
+	{
1256
+		$success = 1;
1257
+		// checkboxes?
1258
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1259
+		if (! empty($checkboxes)) {
1260
+			// if array has more than one element then success message should be plural
1261
+			$success = count($checkboxes) > 1 ? 2 : 1;
1262
+			// cycle thru the boxes
1263
+			foreach ($checkboxes as $TKT_ID => $value) {
1264
+				// delete
1265
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1266
+					$success = 0;
1267
+				}
1268
+			}
1269
+		} else {
1270
+			// grab single id and trash
1271
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1272
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1273
+				$success = 0;
1274
+			}
1275
+		}
1276
+		$action_desc = 'deleted';
1277
+		$query_args  = [
1278
+			'action' => 'ticket_list_table',
1279
+			'status' => 'trashed',
1280
+		];
1281
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1282
+		if (
1283
+		EEM_Ticket::instance()->count_deleted_and_undeleted(
1284
+			[['TKT_is_default' => 1]],
1285
+			'TKT_ID',
1286
+			true
1287
+		)
1288
+		) {
1289
+			$query_args = [];
1290
+		}
1291
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1292
+	}
1293
+
1294
+
1295
+	/**
1296
+	 * @param int $TKT_ID
1297
+	 * @return bool|int
1298
+	 * @throws EE_Error
1299
+	 * @throws ReflectionException
1300
+	 */
1301
+	protected function _delete_the_ticket(int $TKT_ID)
1302
+	{
1303
+		$ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1304
+		if (! $ticket instanceof EE_Ticket) {
1305
+			return false;
1306
+		}
1307
+		$ticket->_remove_relations('Datetime');
1308
+		// delete all related prices first
1309
+		$ticket->delete_related_permanently('Price');
1310
+		return $ticket->delete_permanently();
1311
+	}
1312 1312
 }
Please login to merge, or discard this patch.
admin/extend/registrations/EE_Event_Registrations_List_Table.class.php 1 patch
Indentation   +614 added lines, -614 removed lines patch added patch discarded remove patch
@@ -17,230 +17,230 @@  discard block
 block discarded – undo
17 17
  */
18 18
 class EE_Event_Registrations_List_Table extends EE_Admin_List_Table
19 19
 {
20
-    /**
21
-     * @var Extend_Registrations_Admin_Page
22
-     */
23
-    protected EE_Admin_Page $_admin_page;
24
-
25
-    /**
26
-     * This property will hold the related Datetimes on an event IF the event id is included in the request.
27
-     */
28
-    protected DatetimesForEventCheckIn  $datetimes_for_event;
29
-
30
-    protected ?DatetimesForEventCheckIn $datetimes_for_current_row = null;
31
-
32
-    /**
33
-     * The DTT_ID if the current view has a specified datetime.
34
-     */
35
-    protected int          $datetime_id = 0;
36
-
37
-    protected ?EE_Datetime $datetime    = null;
38
-
39
-    /**
40
-     * The event ID if one is specified in the request
41
-     */
42
-    protected int       $event_id      = 0;
43
-
44
-    protected ?EE_Event $event         = null;
45
-
46
-    protected bool      $hide_expired  = false;
47
-
48
-    protected bool      $hide_upcoming = false;
49
-
50
-    protected array     $_status       = [];
51
-
52
-
53
-    /**
54
-     * EE_Event_Registrations_List_Table constructor.
55
-     *
56
-     * @param Registrations_Admin_Page $admin_page
57
-     * @throws EE_Error
58
-     * @throws ReflectionException
59
-     */
60
-    public function __construct($admin_page)
61
-    {
62
-        $this->request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
63
-        $this->resolveRequestVars();
64
-        parent::__construct($admin_page);
65
-    }
66
-
67
-
68
-    /**
69
-     * @throws EE_Error
70
-     * @throws ReflectionException
71
-     * @since 5.0.0.p
72
-     */
73
-    private function resolveRequestVars()
74
-    {
75
-        $this->event_id            = $this->request->getRequestParam('event_id', 0, DataType::INTEGER);
76
-        $this->datetimes_for_event = DatetimesForEventCheckIn::fromEventID($this->event_id);
77
-        // if we're filtering for a specific event and it only has one datetime, then grab its ID
78
-        $this->datetime    = $this->datetimes_for_event->getOneDatetimeForEvent();
79
-        $this->datetime_id = $this->datetime instanceof EE_Datetime ? $this->datetime->ID() : 0;
80
-        // else check the request, but use the above as the default (and hope they match if BOTH exist, LOLZ)
81
-        $this->datetime_id = $this->request->getRequestParam(
82
-            'DTT_ID',
83
-            $this->datetime_id,
84
-            DataType::INTEGER
85
-        );
86
-    }
87
-
88
-
89
-    /**
90
-     * @throws EE_Error
91
-     * @throws ReflectionException
92
-     */
93
-    protected function _setup_data()
94
-    {
95
-        $this->_data = $this->_view !== 'trash'
96
-            ? $this->_admin_page->get_event_attendees($this->_per_page)
97
-            : $this->_admin_page->get_event_attendees($this->_per_page, false, true);
98
-
99
-        $this->_all_data_count = $this->_view !== 'trash'
100
-            ? $this->_admin_page->get_event_attendees($this->_per_page, true)
101
-            : $this->_admin_page->get_event_attendees($this->_per_page, true, true);
102
-    }
103
-
104
-
105
-    /**
106
-     * @throws ReflectionException
107
-     * @throws EE_Error
108
-     */
109
-    protected function _set_properties()
110
-    {
111
-        $this->_wp_list_args = [
112
-            'singular' => esc_html__('registrant', 'event_espresso'),
113
-            'plural'   => esc_html__('registrants', 'event_espresso'),
114
-            'ajax'     => true,
115
-            'screen'   => $this->_admin_page->get_current_screen()->id,
116
-        ];
117
-        $columns             = [];
118
-
119
-        $this->_columns = [
120
-            '_REG_att_checked_in' => '<span class="dashicons dashicons-yes ee-icon-size-18"></span>',
121
-            'ATT_name'            => esc_html__('Registrant', 'event_espresso'),
122
-            'ATT_email'           => esc_html__('Email Address', 'event_espresso'),
123
-            'Event'               => esc_html__('Event', 'event_espresso'),
124
-            'PRC_name'            => esc_html__('TKT Option', 'event_espresso'),
125
-            '_REG_final_price'    => esc_html__('Price', 'event_espresso'),
126
-            'TXN_paid'            => esc_html__('Paid', 'event_espresso'),
127
-            'TXN_total'           => esc_html__('Total', 'event_espresso'),
128
-        ];
129
-        // Add/remove columns when an event has been selected
130
-        if (! empty($this->event_id)) {
131
-            // Render a checkbox column
132
-            $columns['cb']              = '<input type="checkbox" />';
133
-            $this->_has_checkbox_column = true;
134
-            // Remove the 'Event' column
135
-            unset($this->_columns['Event']);
136
-            $this->setBottomButtons();
137
-        }
138
-        $this->_columns        = array_merge($columns, $this->_columns);
139
-        $this->_primary_column = '_REG_att_checked_in';
140
-
141
-        $csv_report = RegistrationsCsvReportParams::getRequestParams(
142
-            $this->getReturnUrl(),
143
-            $this->_req_data,
144
-            $this->event_id,
145
-            $this->datetime_id
146
-        );
147
-        if (! empty($csv_report)) {
148
-            $this->_bottom_buttons['csv_reg_report'] = $csv_report;
149
-        }
150
-
151
-        $this->_sortable_columns = [
152
-            /**
153
-             * Allows users to change the default sort if they wish.
154
-             * Returning a falsey on this filter will result in the default sort to be by firstname rather than last name.
155
-             * Note: usual naming conventions for filters aren't followed here so that just one filter can be used to
156
-             * change the sorts on any list table involving registration contacts.  If you want to only change the filter
157
-             * for a specific list table you can use the provided reference to this object instance.
158
-             */
159
-            'ATT_name' => [
160
-                'FHEE__EE_Registrations_List_Table___set_properties__default_sort_by_registration_last_name',
161
-                true,
162
-                $this,
163
-            ]
164
-                ? ['ATT_lname' => true]
165
-                : ['ATT_fname' => true],
166
-            'Event'    => ['Event.EVT_name' => false],
167
-        ];
168
-        $this->_hidden_columns   = [];
169
-        $this->event             = EEM_Event::instance()->get_one_by_ID($this->event_id);
170
-        if ($this->event instanceof EE_Event) {
171
-            $this->datetimes_for_event = DatetimesForEventCheckIn::fromEvent($this->event);
172
-        }
173
-    }
174
-
175
-
176
-    /**
177
-     * @param EE_Registration $item
178
-     * @return string
179
-     */
180
-    protected function _get_row_class($item): string
181
-    {
182
-        $class = parent::_get_row_class($item);
183
-        if ($this->_has_checkbox_column) {
184
-            $class .= ' has-checkbox-column';
185
-        }
186
-        return $class;
187
-    }
188
-
189
-
190
-    /**
191
-     * @return array
192
-     * @throws EE_Error
193
-     * @throws ReflectionException
194
-     */
195
-    protected function _get_table_filters()
196
-    {
197
-        $filters               = [];
198
-        $this->hide_expired    = $this->request->getRequestParam('hide_expired', false, DataType::BOOL);
199
-        $this->hide_upcoming   = $this->request->getRequestParam('hide_upcoming', false, DataType::BOOL);
200
-        $hide_expired_checked  = $this->hide_expired ? 'checked' : '';
201
-        $hide_upcoming_checked = $this->hide_upcoming ? 'checked' : '';
202
-        // get datetimes for ALL active events (note possible capability restrictions)
203
-        $events          = $this->datetimes_for_event->getAllEvents();
204
-        $event_options[] = [
205
-            'id'   => 0,
206
-            'text' => esc_html__(' - select an event - ', 'event_espresso'),
207
-        ];
208
-        foreach ($events as $event) {
209
-            // any registrations for this event?
210
-            if (! $event instanceof EE_Event/* || ! $event->get_count_of_all_registrations()*/) {
211
-                continue;
212
-            }
213
-            $expired_class  = $event->is_expired() ? 'ee-expired-event' : '';
214
-            $upcoming_class = $event->is_upcoming() ? ' ee-upcoming-event' : '';
215
-
216
-            $event_options[] = [
217
-                'id'    => $event->ID(),
218
-                'text'  => apply_filters(
219
-                    'FHEE__EE_Event_Registrations___get_table_filters__event_name',
220
-                    $event->name(),
221
-                    $event
222
-                ),
223
-                'class' => $expired_class . $upcoming_class,
224
-            ];
225
-            if ($event->ID() === $this->event_id) {
226
-                $this->hide_expired    = $expired_class === '' ? $this->hide_expired : false;
227
-                $hide_expired_checked  = $expired_class === '' ? $hide_expired_checked : '';
228
-                $this->hide_upcoming   = $upcoming_class === '' ? $this->hide_upcoming : false;
229
-                $hide_upcoming_checked = $upcoming_class === '' ? $hide_upcoming_checked : '';
230
-            }
231
-        }
232
-
233
-        $select_class = $this->hide_expired ? 'ee-hide-expired-events' : '';
234
-        $select_class .= $this->hide_upcoming ? ' ee-hide-upcoming-events' : '';
235
-        $select_input = EEH_Form_Fields::select_input(
236
-            'event_id',
237
-            $event_options,
238
-            $this->event_id,
239
-            '',
240
-            $select_class
241
-        );
242
-
243
-        $filters[] = '
20
+	/**
21
+	 * @var Extend_Registrations_Admin_Page
22
+	 */
23
+	protected EE_Admin_Page $_admin_page;
24
+
25
+	/**
26
+	 * This property will hold the related Datetimes on an event IF the event id is included in the request.
27
+	 */
28
+	protected DatetimesForEventCheckIn  $datetimes_for_event;
29
+
30
+	protected ?DatetimesForEventCheckIn $datetimes_for_current_row = null;
31
+
32
+	/**
33
+	 * The DTT_ID if the current view has a specified datetime.
34
+	 */
35
+	protected int          $datetime_id = 0;
36
+
37
+	protected ?EE_Datetime $datetime    = null;
38
+
39
+	/**
40
+	 * The event ID if one is specified in the request
41
+	 */
42
+	protected int       $event_id      = 0;
43
+
44
+	protected ?EE_Event $event         = null;
45
+
46
+	protected bool      $hide_expired  = false;
47
+
48
+	protected bool      $hide_upcoming = false;
49
+
50
+	protected array     $_status       = [];
51
+
52
+
53
+	/**
54
+	 * EE_Event_Registrations_List_Table constructor.
55
+	 *
56
+	 * @param Registrations_Admin_Page $admin_page
57
+	 * @throws EE_Error
58
+	 * @throws ReflectionException
59
+	 */
60
+	public function __construct($admin_page)
61
+	{
62
+		$this->request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
63
+		$this->resolveRequestVars();
64
+		parent::__construct($admin_page);
65
+	}
66
+
67
+
68
+	/**
69
+	 * @throws EE_Error
70
+	 * @throws ReflectionException
71
+	 * @since 5.0.0.p
72
+	 */
73
+	private function resolveRequestVars()
74
+	{
75
+		$this->event_id            = $this->request->getRequestParam('event_id', 0, DataType::INTEGER);
76
+		$this->datetimes_for_event = DatetimesForEventCheckIn::fromEventID($this->event_id);
77
+		// if we're filtering for a specific event and it only has one datetime, then grab its ID
78
+		$this->datetime    = $this->datetimes_for_event->getOneDatetimeForEvent();
79
+		$this->datetime_id = $this->datetime instanceof EE_Datetime ? $this->datetime->ID() : 0;
80
+		// else check the request, but use the above as the default (and hope they match if BOTH exist, LOLZ)
81
+		$this->datetime_id = $this->request->getRequestParam(
82
+			'DTT_ID',
83
+			$this->datetime_id,
84
+			DataType::INTEGER
85
+		);
86
+	}
87
+
88
+
89
+	/**
90
+	 * @throws EE_Error
91
+	 * @throws ReflectionException
92
+	 */
93
+	protected function _setup_data()
94
+	{
95
+		$this->_data = $this->_view !== 'trash'
96
+			? $this->_admin_page->get_event_attendees($this->_per_page)
97
+			: $this->_admin_page->get_event_attendees($this->_per_page, false, true);
98
+
99
+		$this->_all_data_count = $this->_view !== 'trash'
100
+			? $this->_admin_page->get_event_attendees($this->_per_page, true)
101
+			: $this->_admin_page->get_event_attendees($this->_per_page, true, true);
102
+	}
103
+
104
+
105
+	/**
106
+	 * @throws ReflectionException
107
+	 * @throws EE_Error
108
+	 */
109
+	protected function _set_properties()
110
+	{
111
+		$this->_wp_list_args = [
112
+			'singular' => esc_html__('registrant', 'event_espresso'),
113
+			'plural'   => esc_html__('registrants', 'event_espresso'),
114
+			'ajax'     => true,
115
+			'screen'   => $this->_admin_page->get_current_screen()->id,
116
+		];
117
+		$columns             = [];
118
+
119
+		$this->_columns = [
120
+			'_REG_att_checked_in' => '<span class="dashicons dashicons-yes ee-icon-size-18"></span>',
121
+			'ATT_name'            => esc_html__('Registrant', 'event_espresso'),
122
+			'ATT_email'           => esc_html__('Email Address', 'event_espresso'),
123
+			'Event'               => esc_html__('Event', 'event_espresso'),
124
+			'PRC_name'            => esc_html__('TKT Option', 'event_espresso'),
125
+			'_REG_final_price'    => esc_html__('Price', 'event_espresso'),
126
+			'TXN_paid'            => esc_html__('Paid', 'event_espresso'),
127
+			'TXN_total'           => esc_html__('Total', 'event_espresso'),
128
+		];
129
+		// Add/remove columns when an event has been selected
130
+		if (! empty($this->event_id)) {
131
+			// Render a checkbox column
132
+			$columns['cb']              = '<input type="checkbox" />';
133
+			$this->_has_checkbox_column = true;
134
+			// Remove the 'Event' column
135
+			unset($this->_columns['Event']);
136
+			$this->setBottomButtons();
137
+		}
138
+		$this->_columns        = array_merge($columns, $this->_columns);
139
+		$this->_primary_column = '_REG_att_checked_in';
140
+
141
+		$csv_report = RegistrationsCsvReportParams::getRequestParams(
142
+			$this->getReturnUrl(),
143
+			$this->_req_data,
144
+			$this->event_id,
145
+			$this->datetime_id
146
+		);
147
+		if (! empty($csv_report)) {
148
+			$this->_bottom_buttons['csv_reg_report'] = $csv_report;
149
+		}
150
+
151
+		$this->_sortable_columns = [
152
+			/**
153
+			 * Allows users to change the default sort if they wish.
154
+			 * Returning a falsey on this filter will result in the default sort to be by firstname rather than last name.
155
+			 * Note: usual naming conventions for filters aren't followed here so that just one filter can be used to
156
+			 * change the sorts on any list table involving registration contacts.  If you want to only change the filter
157
+			 * for a specific list table you can use the provided reference to this object instance.
158
+			 */
159
+			'ATT_name' => [
160
+				'FHEE__EE_Registrations_List_Table___set_properties__default_sort_by_registration_last_name',
161
+				true,
162
+				$this,
163
+			]
164
+				? ['ATT_lname' => true]
165
+				: ['ATT_fname' => true],
166
+			'Event'    => ['Event.EVT_name' => false],
167
+		];
168
+		$this->_hidden_columns   = [];
169
+		$this->event             = EEM_Event::instance()->get_one_by_ID($this->event_id);
170
+		if ($this->event instanceof EE_Event) {
171
+			$this->datetimes_for_event = DatetimesForEventCheckIn::fromEvent($this->event);
172
+		}
173
+	}
174
+
175
+
176
+	/**
177
+	 * @param EE_Registration $item
178
+	 * @return string
179
+	 */
180
+	protected function _get_row_class($item): string
181
+	{
182
+		$class = parent::_get_row_class($item);
183
+		if ($this->_has_checkbox_column) {
184
+			$class .= ' has-checkbox-column';
185
+		}
186
+		return $class;
187
+	}
188
+
189
+
190
+	/**
191
+	 * @return array
192
+	 * @throws EE_Error
193
+	 * @throws ReflectionException
194
+	 */
195
+	protected function _get_table_filters()
196
+	{
197
+		$filters               = [];
198
+		$this->hide_expired    = $this->request->getRequestParam('hide_expired', false, DataType::BOOL);
199
+		$this->hide_upcoming   = $this->request->getRequestParam('hide_upcoming', false, DataType::BOOL);
200
+		$hide_expired_checked  = $this->hide_expired ? 'checked' : '';
201
+		$hide_upcoming_checked = $this->hide_upcoming ? 'checked' : '';
202
+		// get datetimes for ALL active events (note possible capability restrictions)
203
+		$events          = $this->datetimes_for_event->getAllEvents();
204
+		$event_options[] = [
205
+			'id'   => 0,
206
+			'text' => esc_html__(' - select an event - ', 'event_espresso'),
207
+		];
208
+		foreach ($events as $event) {
209
+			// any registrations for this event?
210
+			if (! $event instanceof EE_Event/* || ! $event->get_count_of_all_registrations()*/) {
211
+				continue;
212
+			}
213
+			$expired_class  = $event->is_expired() ? 'ee-expired-event' : '';
214
+			$upcoming_class = $event->is_upcoming() ? ' ee-upcoming-event' : '';
215
+
216
+			$event_options[] = [
217
+				'id'    => $event->ID(),
218
+				'text'  => apply_filters(
219
+					'FHEE__EE_Event_Registrations___get_table_filters__event_name',
220
+					$event->name(),
221
+					$event
222
+				),
223
+				'class' => $expired_class . $upcoming_class,
224
+			];
225
+			if ($event->ID() === $this->event_id) {
226
+				$this->hide_expired    = $expired_class === '' ? $this->hide_expired : false;
227
+				$hide_expired_checked  = $expired_class === '' ? $hide_expired_checked : '';
228
+				$this->hide_upcoming   = $upcoming_class === '' ? $this->hide_upcoming : false;
229
+				$hide_upcoming_checked = $upcoming_class === '' ? $hide_upcoming_checked : '';
230
+			}
231
+		}
232
+
233
+		$select_class = $this->hide_expired ? 'ee-hide-expired-events' : '';
234
+		$select_class .= $this->hide_upcoming ? ' ee-hide-upcoming-events' : '';
235
+		$select_input = EEH_Form_Fields::select_input(
236
+			'event_id',
237
+			$event_options,
238
+			$this->event_id,
239
+			'',
240
+			$select_class
241
+		);
242
+
243
+		$filters[] = '
244 244
         <div class="ee-event-filter__wrapper">
245 245
             <label class="ee-event-filter-main-label">
246 246
                 ' . esc_html__('Check-in Status for', 'event_espresso') . '
@@ -250,435 +250,435 @@  discard block
 block discarded – undo
250 250
                     <label for="event_id">' . esc_html__('Event', 'event_espresso') . '</label>
251 251
                     ' . $select_input . '
252 252
                 </span>';
253
-        // DTT datetimes filter
254
-        $datetimes_for_event = $this->datetimes_for_event->getAllDatetimesForEvent(
255
-            $hide_upcoming_checked === 'checked'
256
-        );
257
-        if (count($datetimes_for_event) > 1) {
258
-            $datetimes[0] = esc_html__(' - select a datetime - ', 'event_espresso');
259
-            foreach ($datetimes_for_event as $datetime) {
260
-                if ($datetime instanceof EE_Datetime) {
261
-                    $datetime_string = $datetime->name();
262
-                    $datetime_string = ! empty($datetime_string) ? $datetime_string . ': ' : '';
263
-                    $datetime_string .= $datetime->date_and_time_range();
264
-                    $datetime_string .= $datetime->is_active() ? ' ∗' : '';
265
-                    $datetime_string .= $datetime->is_expired() ? ' «' : '';
266
-                    $datetime_string .= $datetime->is_upcoming() ? ' »' : '';
267
-                    // now put it all together
268
-                    $datetimes[ $datetime->ID() ] = $datetime_string;
269
-                }
270
-            }
271
-            $filters[] = '
253
+		// DTT datetimes filter
254
+		$datetimes_for_event = $this->datetimes_for_event->getAllDatetimesForEvent(
255
+			$hide_upcoming_checked === 'checked'
256
+		);
257
+		if (count($datetimes_for_event) > 1) {
258
+			$datetimes[0] = esc_html__(' - select a datetime - ', 'event_espresso');
259
+			foreach ($datetimes_for_event as $datetime) {
260
+				if ($datetime instanceof EE_Datetime) {
261
+					$datetime_string = $datetime->name();
262
+					$datetime_string = ! empty($datetime_string) ? $datetime_string . ': ' : '';
263
+					$datetime_string .= $datetime->date_and_time_range();
264
+					$datetime_string .= $datetime->is_active() ? ' ∗' : '';
265
+					$datetime_string .= $datetime->is_expired() ? ' «' : '';
266
+					$datetime_string .= $datetime->is_upcoming() ? ' »' : '';
267
+					// now put it all together
268
+					$datetimes[ $datetime->ID() ] = $datetime_string;
269
+				}
270
+			}
271
+			$filters[] = '
272 272
                 <span class="ee-datetime-selector">
273 273
                     <label for="DTT_ID">' . esc_html__('Datetime', 'event_espresso') . '</label>
274 274
                     ' . EEH_Form_Fields::select_input(
275
-                        'DTT_ID',
276
-                        $datetimes,
277
-                        $this->datetime_id
278
-                    ) . '
275
+						'DTT_ID',
276
+						$datetimes,
277
+						$this->datetime_id
278
+					) . '
279 279
                 </span>';
280
-        }
281
-        $filters[] = '
280
+		}
281
+		$filters[] = '
282 282
                 <span class="ee-hide-upcoming-check">
283 283
                     <label for="js-ee-hide-upcoming-events">
284 284
                         <input type="checkbox" id="js-ee-hide-upcoming-events" name="hide_upcoming" '
285
-                         . $hide_upcoming_checked
286
-                         . '>
285
+						 . $hide_upcoming_checked
286
+						 . '>
287 287
                             '
288
-                         . esc_html__('Hide Upcoming Events', 'event_espresso')
289
-                         . '
288
+						 . esc_html__('Hide Upcoming Events', 'event_espresso')
289
+						 . '
290 290
                     </label>
291 291
                     <span class="ee-help-btn dashicons dashicons-editor-help ee-aria-tooltip"
292 292
                           aria-label="'
293
-                         . esc_html__(
294
-                             'Will not display events with start dates in the future (ie: have not yet begun)',
295
-                             'event_espresso'
296
-                         ) . '"
293
+						 . esc_html__(
294
+							 'Will not display events with start dates in the future (ie: have not yet begun)',
295
+							 'event_espresso'
296
+						 ) . '"
297 297
                     ></span>
298 298
                 </span>
299 299
                 <span class="ee-hide-expired-check">
300 300
                     <label for="js-ee-hide-expired-events">
301 301
                         <input type="checkbox" id="js-ee-hide-expired-events" name="hide_expired" '
302
-                         . $hide_expired_checked
303
-                         . '>
302
+						 . $hide_expired_checked
303
+						 . '>
304 304
                             ' . esc_html__('Hide Expired Events', 'event_espresso') . '
305 305
                     </label>
306 306
                     <span class="ee-help-btn dashicons dashicons-editor-help ee-aria-tooltip"
307 307
                           aria-label="'
308
-                         . esc_html__(
309
-                             'Will not display events with end dates in the past (ie: have already finished)',
310
-                             'event_espresso'
311
-                         )
312
-                         . '"
308
+						 . esc_html__(
309
+							 'Will not display events with end dates in the past (ie: have already finished)',
310
+							 'event_espresso'
311
+						 )
312
+						 . '"
313 313
                     ></span>
314 314
                 </span>
315 315
             </div>
316 316
         </div>';
317
-        return $filters;
318
-    }
319
-
320
-
321
-    /**
322
-     * @throws EE_Error
323
-     * @throws ReflectionException
324
-     */
325
-    protected function _add_view_counts()
326
-    {
327
-        $this->_views['all']['count'] = $this->_get_total_event_attendees();
328
-    }
329
-
330
-
331
-    /**
332
-     * @return int
333
-     * @throws EE_Error
334
-     * @throws ReflectionException
335
-     */
336
-    protected function _get_total_event_attendees(): int
337
-    {
338
-        $query_params = [];
339
-        if ($this->event_id) {
340
-            $query_params[0]['EVT_ID'] = $this->event_id;
341
-        }
342
-        // if DTT is included we only show for that datetime.  Otherwise we're showing for all datetimes (the event).
343
-        if ($this->datetime_id) {
344
-            $query_params[0]['Ticket.Datetime.DTT_ID'] = $this->datetime_id;
345
-        }
346
-        $status_ids_array          = apply_filters(
347
-            'FHEE__Extend_Registrations_Admin_Page__get_event_attendees__status_ids_array',
348
-            [EEM_Registration::status_id_pending_payment, EEM_Registration::status_id_approved]
349
-        );
350
-        $query_params[0]['STS_ID'] = ['IN', $status_ids_array];
351
-        return EEM_Registration::instance()->count($query_params);
352
-    }
353
-
354
-
355
-    /**
356
-     * @param EE_Registration $item
357
-     * @return string
358
-     * @throws EE_Error
359
-     * @throws ReflectionException
360
-     */
361
-    public function column_cb($item): string
362
-    {
363
-        return sprintf('<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />', $item->ID());
364
-    }
365
-
366
-
367
-    /**
368
-     * column_REG_att_checked_in
369
-     *
370
-     * @param EE_Registration $registration
371
-     * @return string
372
-     * @throws EE_Error
373
-     * @throws InvalidArgumentException
374
-     * @throws InvalidDataTypeException
375
-     * @throws InvalidInterfaceException
376
-     * @throws ReflectionException
377
-     */
378
-    public function column__REG_att_checked_in(EE_Registration $registration): string
379
-    {
380
-        // we need a local variable for the datetime for each row
381
-        // (so that we don't pollute state for the entire table)
382
-        // so let's try to get it from the registration's event
383
-        $DTT_ID = $this->datetime_id;
384
-        if (! $DTT_ID) {
385
-            $reg_ticket_datetimes = $registration->ticket()->datetimes();
386
-            if (count($reg_ticket_datetimes) === 1) {
387
-                $reg_ticket_datetime = reset($reg_ticket_datetimes);
388
-                $DTT_ID              = $reg_ticket_datetime instanceof EE_Datetime ? $reg_ticket_datetime->ID() : 0;
389
-            }
390
-        }
391
-
392
-        if (! $DTT_ID) {
393
-            $this->datetimes_for_current_row = DatetimesForEventCheckIn::fromRegistration($registration);
394
-            $datetime                        = $this->datetimes_for_current_row->getOneDatetimeForEvent($DTT_ID);
395
-            $DTT_ID                          = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
396
-        }
397
-
398
-        $checkin_status_dashicon = CheckinStatusDashicon::fromRegistrationAndDatetimeId(
399
-            $registration,
400
-            $DTT_ID
401
-        );
402
-
403
-        $aria_label     = $checkin_status_dashicon->ariaLabel();
404
-        $dashicon_class = $checkin_status_dashicon->cssClasses();
405
-        $attributes     = ' onClick="return false"';
406
-        $button_class   = 'button button--secondary button--icon-only ee-aria-tooltip ee-aria-tooltip--big-box';
407
-
408
-        if (
409
-            $DTT_ID
410
-            && EE_Registry::instance()->CAP->current_user_can(
411
-                'ee_edit_checkin',
412
-                'espresso_registrations_toggle_checkin_status',
413
-                $registration->ID()
414
-            )
415
-        ) {
416
-            // overwrite the disabled attribute with data attributes for performing checkin
417
-            $attributes   = 'data-_regid="' . $registration->ID() . '"';
418
-            $attributes   .= ' data-dttid="' . $DTT_ID . '"';
419
-            $attributes   .= ' data-nonce="' . wp_create_nonce('checkin_nonce') . '"';
420
-            $button_class .= ' clickable trigger-checkin';
421
-        }
422
-
423
-        $content = '
317
+		return $filters;
318
+	}
319
+
320
+
321
+	/**
322
+	 * @throws EE_Error
323
+	 * @throws ReflectionException
324
+	 */
325
+	protected function _add_view_counts()
326
+	{
327
+		$this->_views['all']['count'] = $this->_get_total_event_attendees();
328
+	}
329
+
330
+
331
+	/**
332
+	 * @return int
333
+	 * @throws EE_Error
334
+	 * @throws ReflectionException
335
+	 */
336
+	protected function _get_total_event_attendees(): int
337
+	{
338
+		$query_params = [];
339
+		if ($this->event_id) {
340
+			$query_params[0]['EVT_ID'] = $this->event_id;
341
+		}
342
+		// if DTT is included we only show for that datetime.  Otherwise we're showing for all datetimes (the event).
343
+		if ($this->datetime_id) {
344
+			$query_params[0]['Ticket.Datetime.DTT_ID'] = $this->datetime_id;
345
+		}
346
+		$status_ids_array          = apply_filters(
347
+			'FHEE__Extend_Registrations_Admin_Page__get_event_attendees__status_ids_array',
348
+			[EEM_Registration::status_id_pending_payment, EEM_Registration::status_id_approved]
349
+		);
350
+		$query_params[0]['STS_ID'] = ['IN', $status_ids_array];
351
+		return EEM_Registration::instance()->count($query_params);
352
+	}
353
+
354
+
355
+	/**
356
+	 * @param EE_Registration $item
357
+	 * @return string
358
+	 * @throws EE_Error
359
+	 * @throws ReflectionException
360
+	 */
361
+	public function column_cb($item): string
362
+	{
363
+		return sprintf('<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />', $item->ID());
364
+	}
365
+
366
+
367
+	/**
368
+	 * column_REG_att_checked_in
369
+	 *
370
+	 * @param EE_Registration $registration
371
+	 * @return string
372
+	 * @throws EE_Error
373
+	 * @throws InvalidArgumentException
374
+	 * @throws InvalidDataTypeException
375
+	 * @throws InvalidInterfaceException
376
+	 * @throws ReflectionException
377
+	 */
378
+	public function column__REG_att_checked_in(EE_Registration $registration): string
379
+	{
380
+		// we need a local variable for the datetime for each row
381
+		// (so that we don't pollute state for the entire table)
382
+		// so let's try to get it from the registration's event
383
+		$DTT_ID = $this->datetime_id;
384
+		if (! $DTT_ID) {
385
+			$reg_ticket_datetimes = $registration->ticket()->datetimes();
386
+			if (count($reg_ticket_datetimes) === 1) {
387
+				$reg_ticket_datetime = reset($reg_ticket_datetimes);
388
+				$DTT_ID              = $reg_ticket_datetime instanceof EE_Datetime ? $reg_ticket_datetime->ID() : 0;
389
+			}
390
+		}
391
+
392
+		if (! $DTT_ID) {
393
+			$this->datetimes_for_current_row = DatetimesForEventCheckIn::fromRegistration($registration);
394
+			$datetime                        = $this->datetimes_for_current_row->getOneDatetimeForEvent($DTT_ID);
395
+			$DTT_ID                          = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
396
+		}
397
+
398
+		$checkin_status_dashicon = CheckinStatusDashicon::fromRegistrationAndDatetimeId(
399
+			$registration,
400
+			$DTT_ID
401
+		);
402
+
403
+		$aria_label     = $checkin_status_dashicon->ariaLabel();
404
+		$dashicon_class = $checkin_status_dashicon->cssClasses();
405
+		$attributes     = ' onClick="return false"';
406
+		$button_class   = 'button button--secondary button--icon-only ee-aria-tooltip ee-aria-tooltip--big-box';
407
+
408
+		if (
409
+			$DTT_ID
410
+			&& EE_Registry::instance()->CAP->current_user_can(
411
+				'ee_edit_checkin',
412
+				'espresso_registrations_toggle_checkin_status',
413
+				$registration->ID()
414
+			)
415
+		) {
416
+			// overwrite the disabled attribute with data attributes for performing checkin
417
+			$attributes   = 'data-_regid="' . $registration->ID() . '"';
418
+			$attributes   .= ' data-dttid="' . $DTT_ID . '"';
419
+			$attributes   .= ' data-nonce="' . wp_create_nonce('checkin_nonce') . '"';
420
+			$button_class .= ' clickable trigger-checkin';
421
+		}
422
+
423
+		$content = '
424 424
         <button aria-label="' . $aria_label . '" class="' . $button_class . '" ' . $attributes . '>
425 425
             <span class="' . $dashicon_class . '" ></span>
426 426
         </button>
427 427
         <span class="show-on-mobile-view-only">' . $this->column_ATT_name($registration) . '</span>';
428
-        return $this->columnContent('_REG_att_checked_in', $content, 'center');
429
-    }
430
-
431
-
432
-    /**
433
-     * @param EE_Registration $registration
434
-     * @return string
435
-     * @throws EE_Error
436
-     * @throws ReflectionException
437
-     */
438
-    public function column_ATT_name(EE_Registration $registration): string
439
-    {
440
-        $attendee = $registration->attendee();
441
-        if (! $attendee instanceof EE_Attendee) {
442
-            return esc_html__('No contact record for this registration.', 'event_espresso');
443
-        }
444
-        // edit attendee link
445
-        $edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
446
-            ['action' => 'view_registration', '_REG_ID' => $registration->ID()],
447
-            REG_ADMIN_URL
448
-        );
449
-        $name_link    = '
428
+		return $this->columnContent('_REG_att_checked_in', $content, 'center');
429
+	}
430
+
431
+
432
+	/**
433
+	 * @param EE_Registration $registration
434
+	 * @return string
435
+	 * @throws EE_Error
436
+	 * @throws ReflectionException
437
+	 */
438
+	public function column_ATT_name(EE_Registration $registration): string
439
+	{
440
+		$attendee = $registration->attendee();
441
+		if (! $attendee instanceof EE_Attendee) {
442
+			return esc_html__('No contact record for this registration.', 'event_espresso');
443
+		}
444
+		// edit attendee link
445
+		$edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
446
+			['action' => 'view_registration', '_REG_ID' => $registration->ID()],
447
+			REG_ADMIN_URL
448
+		);
449
+		$name_link    = '
450 450
             <span class="ee-status-dot ee-status-bg--' . esc_attr($registration->status_ID()) . ' ee-aria-tooltip"
451 451
             aria-label="' . EEH_Template::pretty_status($registration->status_ID(), false, 'sentence') . '">
452 452
             </span>';
453
-        $name_link    .= EE_Registry::instance()->CAP->current_user_can(
454
-            'ee_edit_contacts',
455
-            'espresso_registrations_edit_attendee'
456
-        )
457
-            ? '<a class="ee-aria-tooltip" href="' . $edit_lnk_url . '" aria-label="' . esc_attr__(
458
-                'View Registration Details',
459
-                'event_espresso'
460
-            ) . '">'
461
-              . $registration->attendee()->full_name()
462
-              . '</a>'
463
-            : $registration->attendee()->full_name();
464
-        $name_link    .= $registration->count() === 1
465
-            ? '&nbsp;<sup><div class="dashicons dashicons-star-filled gold-icon"></div></sup>	'
466
-            : '';
467
-        // add group details
468
-        $name_link .= '&nbsp;' . sprintf(
469
-            esc_html__('(%s of %s)', 'event_espresso'),
470
-            $registration->count(),
471
-            $registration->group_size()
472
-        );
473
-        // add regcode
474
-        $link      = EE_Admin_Page::add_query_args_and_nonce(
475
-            ['action' => 'view_registration', '_REG_ID' => $registration->ID()],
476
-            REG_ADMIN_URL
477
-        );
478
-        $name_link .= '<br>';
479
-        $name_link .= EE_Registry::instance()->instance()->CAP->current_user_can(
480
-            'ee_read_registration',
481
-            'view_registration',
482
-            $registration->ID()
483
-        )
484
-            ? '<a class="ee-aria-tooltip" href="' . $link . '" aria-label="' . esc_attr__(
485
-                'View Registration Details',
486
-                'event_espresso'
487
-            ) . '">'
488
-              . $registration->reg_code()
489
-              . '</a>'
490
-            : $registration->reg_code();
491
-
492
-        $actions = [];
493
-        if (
494
-            $this->datetime_id
495
-            && EE_Registry::instance()->CAP->current_user_can(
496
-                'ee_read_checkins',
497
-                'espresso_registrations_registration_checkins'
498
-            )
499
-        ) {
500
-            $checkin_list_url = EE_Admin_Page::add_query_args_and_nonce(
501
-                ['action' => 'registration_checkins', '_REG_ID' => $registration->ID(), 'DTT_ID' => $this->datetime_id],
502
-                REG_ADMIN_URL
503
-            );
504
-            // get the timestamps for this registration's checkins, related to the selected datetime
505
-            /** @var EE_Checkin[] $checkins */
506
-            $checkins = $registration->get_many_related('Checkin', [['DTT_ID' => $this->datetime_id]]);
507
-            if (! empty($checkins)) {
508
-                // get the last timestamp
509
-                $last_checkin = end($checkins);
510
-                // get timestamp string
511
-                $timestamp_string   = $last_checkin->get_datetime('CHK_timestamp');
512
-                $actions['checkin'] = '
453
+		$name_link    .= EE_Registry::instance()->CAP->current_user_can(
454
+			'ee_edit_contacts',
455
+			'espresso_registrations_edit_attendee'
456
+		)
457
+			? '<a class="ee-aria-tooltip" href="' . $edit_lnk_url . '" aria-label="' . esc_attr__(
458
+				'View Registration Details',
459
+				'event_espresso'
460
+			) . '">'
461
+			  . $registration->attendee()->full_name()
462
+			  . '</a>'
463
+			: $registration->attendee()->full_name();
464
+		$name_link    .= $registration->count() === 1
465
+			? '&nbsp;<sup><div class="dashicons dashicons-star-filled gold-icon"></div></sup>	'
466
+			: '';
467
+		// add group details
468
+		$name_link .= '&nbsp;' . sprintf(
469
+			esc_html__('(%s of %s)', 'event_espresso'),
470
+			$registration->count(),
471
+			$registration->group_size()
472
+		);
473
+		// add regcode
474
+		$link      = EE_Admin_Page::add_query_args_and_nonce(
475
+			['action' => 'view_registration', '_REG_ID' => $registration->ID()],
476
+			REG_ADMIN_URL
477
+		);
478
+		$name_link .= '<br>';
479
+		$name_link .= EE_Registry::instance()->instance()->CAP->current_user_can(
480
+			'ee_read_registration',
481
+			'view_registration',
482
+			$registration->ID()
483
+		)
484
+			? '<a class="ee-aria-tooltip" href="' . $link . '" aria-label="' . esc_attr__(
485
+				'View Registration Details',
486
+				'event_espresso'
487
+			) . '">'
488
+			  . $registration->reg_code()
489
+			  . '</a>'
490
+			: $registration->reg_code();
491
+
492
+		$actions = [];
493
+		if (
494
+			$this->datetime_id
495
+			&& EE_Registry::instance()->CAP->current_user_can(
496
+				'ee_read_checkins',
497
+				'espresso_registrations_registration_checkins'
498
+			)
499
+		) {
500
+			$checkin_list_url = EE_Admin_Page::add_query_args_and_nonce(
501
+				['action' => 'registration_checkins', '_REG_ID' => $registration->ID(), 'DTT_ID' => $this->datetime_id],
502
+				REG_ADMIN_URL
503
+			);
504
+			// get the timestamps for this registration's checkins, related to the selected datetime
505
+			/** @var EE_Checkin[] $checkins */
506
+			$checkins = $registration->get_many_related('Checkin', [['DTT_ID' => $this->datetime_id]]);
507
+			if (! empty($checkins)) {
508
+				// get the last timestamp
509
+				$last_checkin = end($checkins);
510
+				// get timestamp string
511
+				$timestamp_string   = $last_checkin->get_datetime('CHK_timestamp');
512
+				$actions['checkin'] = '
513 513
                     <a  class="ee-aria-tooltip"
514 514
                         href="' . $checkin_list_url . '"
515 515
                         aria-label="' . esc_attr__(
516
-                            'View this registrant\'s check-ins/checkouts for the datetime',
517
-                            'event_espresso'
518
-                        ) . '"
516
+							'View this registrant\'s check-ins/checkouts for the datetime',
517
+							'event_espresso'
518
+						) . '"
519 519
                     >
520 520
                         ' . $last_checkin->getCheckInText() . ': ' . $timestamp_string . '
521 521
                     </a>';
522
-            }
523
-        }
524
-        $content = (! empty($this->datetime_id) && ! empty($checkins))
525
-            ? sprintf('%1$s %2$s', $name_link, $this->row_actions($actions, true))
526
-            : $name_link;
527
-        return $this->columnContent('ATT_name', $content);
528
-    }
529
-
530
-
531
-    /**
532
-     * @param EE_Registration $registration
533
-     * @return string
534
-     * @throws EE_Error
535
-     * @throws EE_Error
536
-     * @throws ReflectionException
537
-     */
538
-    public function column_ATT_email(EE_Registration $registration): string
539
-    {
540
-        $attendee = $registration->attendee();
541
-        $content  = $attendee instanceof EE_Attendee ? $attendee->email() : '';
542
-        return $this->columnContent('ATT_email', $content);
543
-    }
544
-
545
-
546
-    /**
547
-     * @param EE_Registration $registration
548
-     * @return string
549
-     * @throws EE_Error
550
-     * @throws ReflectionException
551
-     */
552
-    public function column_Event(EE_Registration $registration): string
553
-    {
554
-        try {
555
-            $event            = $this->event instanceof EE_Event ? $this->event : $registration->event();
556
-            $checkin_link_url = EE_Admin_Page::add_query_args_and_nonce(
557
-                ['action' => 'event_registrations', 'event_id' => $event->ID()],
558
-                REG_ADMIN_URL
559
-            );
560
-            $content          = EE_Registry::instance()->CAP->current_user_can(
561
-                'ee_read_checkins',
562
-                'espresso_registrations_registration_checkins'
563
-            ) ? '<a class="ee-aria-tooltip" href="' . $checkin_link_url . '" aria-label="'
564
-                . esc_attr__(
565
-                    'View Checkins for this Event',
566
-                    'event_espresso'
567
-                ) . '">' . $event->name() . '</a>' : $event->name();
568
-        } catch (EntityNotFoundException $e) {
569
-            $content = esc_html__('Unknown', 'event_espresso');
570
-        }
571
-        return $this->columnContent('Event', $content);
572
-    }
573
-
574
-
575
-    /**
576
-     * @param EE_Registration $registration
577
-     * @return string
578
-     * @throws EE_Error
579
-     * @throws ReflectionException
580
-     */
581
-    public function column_PRC_name(EE_Registration $registration): string
582
-    {
583
-        $content = $registration->ticket() instanceof EE_Ticket
584
-            ? $registration->ticket()->name()
585
-              . '<span class="ee-entity--id">(ID:' . $registration->ticket()->ID() . ')</span>'
586
-            : esc_html__(
587
-                "Unknown",
588
-                "event_espresso"
589
-            );
590
-        return $this->columnContent('PRC_name', $content);
591
-    }
592
-
593
-
594
-    /**
595
-     * column_REG_final_price
596
-     *
597
-     * @param EE_Registration $registration
598
-     * @return string
599
-     * @throws EE_Error
600
-     * @throws ReflectionException
601
-     */
602
-    public function column__REG_final_price(EE_Registration $registration): string
603
-    {
604
-        return $this->columnContent('_REG_final_price', $registration->pretty_final_price(), 'end');
605
-    }
606
-
607
-
608
-    /**
609
-     * column_TXN_paid
610
-     *
611
-     * @param EE_Registration $registration
612
-     * @return string
613
-     * @throws EE_Error
614
-     * @throws ReflectionException
615
-     */
616
-    public function column_TXN_paid(EE_Registration $registration): string
617
-    {
618
-        $content = '';
619
-        if ($registration->count() === 1) {
620
-            if ($registration->transaction()->paid() >= $registration->transaction()->total()) {
621
-                return '<div class="dashicons dashicons-yes green-icon"></div>';
622
-            } else {
623
-                $view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
624
-                    ['action' => 'view_transaction', 'TXN_ID' => $registration->transaction_ID()],
625
-                    TXN_ADMIN_URL
626
-                );
627
-                $content          = EE_Registry::instance()->CAP->current_user_can(
628
-                    'ee_read_transaction',
629
-                    'espresso_transactions_view_transaction'
630
-                ) ? '
522
+			}
523
+		}
524
+		$content = (! empty($this->datetime_id) && ! empty($checkins))
525
+			? sprintf('%1$s %2$s', $name_link, $this->row_actions($actions, true))
526
+			: $name_link;
527
+		return $this->columnContent('ATT_name', $content);
528
+	}
529
+
530
+
531
+	/**
532
+	 * @param EE_Registration $registration
533
+	 * @return string
534
+	 * @throws EE_Error
535
+	 * @throws EE_Error
536
+	 * @throws ReflectionException
537
+	 */
538
+	public function column_ATT_email(EE_Registration $registration): string
539
+	{
540
+		$attendee = $registration->attendee();
541
+		$content  = $attendee instanceof EE_Attendee ? $attendee->email() : '';
542
+		return $this->columnContent('ATT_email', $content);
543
+	}
544
+
545
+
546
+	/**
547
+	 * @param EE_Registration $registration
548
+	 * @return string
549
+	 * @throws EE_Error
550
+	 * @throws ReflectionException
551
+	 */
552
+	public function column_Event(EE_Registration $registration): string
553
+	{
554
+		try {
555
+			$event            = $this->event instanceof EE_Event ? $this->event : $registration->event();
556
+			$checkin_link_url = EE_Admin_Page::add_query_args_and_nonce(
557
+				['action' => 'event_registrations', 'event_id' => $event->ID()],
558
+				REG_ADMIN_URL
559
+			);
560
+			$content          = EE_Registry::instance()->CAP->current_user_can(
561
+				'ee_read_checkins',
562
+				'espresso_registrations_registration_checkins'
563
+			) ? '<a class="ee-aria-tooltip" href="' . $checkin_link_url . '" aria-label="'
564
+				. esc_attr__(
565
+					'View Checkins for this Event',
566
+					'event_espresso'
567
+				) . '">' . $event->name() . '</a>' : $event->name();
568
+		} catch (EntityNotFoundException $e) {
569
+			$content = esc_html__('Unknown', 'event_espresso');
570
+		}
571
+		return $this->columnContent('Event', $content);
572
+	}
573
+
574
+
575
+	/**
576
+	 * @param EE_Registration $registration
577
+	 * @return string
578
+	 * @throws EE_Error
579
+	 * @throws ReflectionException
580
+	 */
581
+	public function column_PRC_name(EE_Registration $registration): string
582
+	{
583
+		$content = $registration->ticket() instanceof EE_Ticket
584
+			? $registration->ticket()->name()
585
+			  . '<span class="ee-entity--id">(ID:' . $registration->ticket()->ID() . ')</span>'
586
+			: esc_html__(
587
+				"Unknown",
588
+				"event_espresso"
589
+			);
590
+		return $this->columnContent('PRC_name', $content);
591
+	}
592
+
593
+
594
+	/**
595
+	 * column_REG_final_price
596
+	 *
597
+	 * @param EE_Registration $registration
598
+	 * @return string
599
+	 * @throws EE_Error
600
+	 * @throws ReflectionException
601
+	 */
602
+	public function column__REG_final_price(EE_Registration $registration): string
603
+	{
604
+		return $this->columnContent('_REG_final_price', $registration->pretty_final_price(), 'end');
605
+	}
606
+
607
+
608
+	/**
609
+	 * column_TXN_paid
610
+	 *
611
+	 * @param EE_Registration $registration
612
+	 * @return string
613
+	 * @throws EE_Error
614
+	 * @throws ReflectionException
615
+	 */
616
+	public function column_TXN_paid(EE_Registration $registration): string
617
+	{
618
+		$content = '';
619
+		if ($registration->count() === 1) {
620
+			if ($registration->transaction()->paid() >= $registration->transaction()->total()) {
621
+				return '<div class="dashicons dashicons-yes green-icon"></div>';
622
+			} else {
623
+				$view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
624
+					['action' => 'view_transaction', 'TXN_ID' => $registration->transaction_ID()],
625
+					TXN_ADMIN_URL
626
+				);
627
+				$content          = EE_Registry::instance()->CAP->current_user_can(
628
+					'ee_read_transaction',
629
+					'espresso_transactions_view_transaction'
630
+				) ? '
631 631
 				<a class="ee-aria-tooltip ee-status-color--'
632
-                    . $registration->transaction()->status_ID()
633
-                    . '" href="'
634
-                    . $view_txn_lnk_url
635
-                    . '"  aria-label="'
636
-                    . esc_attr__('View Transaction', 'event_espresso')
637
-                    . '">
632
+					. $registration->transaction()->status_ID()
633
+					. '" href="'
634
+					. $view_txn_lnk_url
635
+					. '"  aria-label="'
636
+					. esc_attr__('View Transaction', 'event_espresso')
637
+					. '">
638 638
 						'
639
-                    . $registration->transaction()->pretty_paid()
640
-                    . '
639
+					. $registration->transaction()->pretty_paid()
640
+					. '
641 641
 					</a>
642 642
 				' : $registration->transaction()->pretty_paid();
643
-            }
644
-        }
645
-        return $this->columnContent('TXN_paid', $content, 'end');
646
-    }
647
-
648
-
649
-    /**
650
-     *        column_TXN_total
651
-     *
652
-     * @param EE_Registration $registration
653
-     * @return string
654
-     * @throws EE_Error
655
-     * @throws ReflectionException
656
-     */
657
-    public function column_TXN_total(EE_Registration $registration): string
658
-    {
659
-        $content      = '';
660
-        $txn          = $registration->transaction();
661
-        $view_txn_url = add_query_arg(['action' => 'view_transaction', 'TXN_ID' => $txn->ID()], TXN_ADMIN_URL);
662
-        if ($registration->get('REG_count') === 1) {
663
-            $line_total_obj = $txn->total_line_item();
664
-            $txn_total      = $line_total_obj instanceof EE_Line_Item
665
-                ? $line_total_obj->get_pretty('LIN_total')
666
-                : esc_html__(
667
-                    'View Transaction',
668
-                    'event_espresso'
669
-                );
670
-            $content        = EE_Registry::instance()->CAP->current_user_can(
671
-                'ee_read_transaction',
672
-                'espresso_transactions_view_transaction'
673
-            ) ? '<a class="ee-aria-tooltip" href="'
674
-                . $view_txn_url
675
-                . '" aria-label="'
676
-                . esc_attr__('View Transaction', 'event_espresso')
677
-                . '">'
678
-                . $txn_total
679
-                . '</a>'
680
-                : $txn_total;
681
-        }
682
-        return $this->columnContent('TXN_total', $content, 'end');
683
-    }
643
+			}
644
+		}
645
+		return $this->columnContent('TXN_paid', $content, 'end');
646
+	}
647
+
648
+
649
+	/**
650
+	 *        column_TXN_total
651
+	 *
652
+	 * @param EE_Registration $registration
653
+	 * @return string
654
+	 * @throws EE_Error
655
+	 * @throws ReflectionException
656
+	 */
657
+	public function column_TXN_total(EE_Registration $registration): string
658
+	{
659
+		$content      = '';
660
+		$txn          = $registration->transaction();
661
+		$view_txn_url = add_query_arg(['action' => 'view_transaction', 'TXN_ID' => $txn->ID()], TXN_ADMIN_URL);
662
+		if ($registration->get('REG_count') === 1) {
663
+			$line_total_obj = $txn->total_line_item();
664
+			$txn_total      = $line_total_obj instanceof EE_Line_Item
665
+				? $line_total_obj->get_pretty('LIN_total')
666
+				: esc_html__(
667
+					'View Transaction',
668
+					'event_espresso'
669
+				);
670
+			$content        = EE_Registry::instance()->CAP->current_user_can(
671
+				'ee_read_transaction',
672
+				'espresso_transactions_view_transaction'
673
+			) ? '<a class="ee-aria-tooltip" href="'
674
+				. $view_txn_url
675
+				. '" aria-label="'
676
+				. esc_attr__('View Transaction', 'event_espresso')
677
+				. '">'
678
+				. $txn_total
679
+				. '</a>'
680
+				: $txn_total;
681
+		}
682
+		return $this->columnContent('TXN_total', $content, 'end');
683
+	}
684 684
 }
Please login to merge, or discard this patch.